no_es_result_relation_info.patch
text/x-patch
Filename: no_es_result_relation_info.patch
Type: text/x-patch
Part: 0
Message:
Re: Writeable CTE patch
Patch
Format: context
| File | + | − |
|---|---|---|
| src/backend/commands/copy.c | 2 | 2 |
| src/backend/commands/tablecmds.c | 0 | 2 |
| src/backend/commands/vacuum.c | 4 | 3 |
| src/backend/executor/execJunk.c | 3 | 1 |
| src/backend/executor/execMain.c | 30 | 83 |
| src/backend/executor/execScan.c | 13 | 13 |
| src/backend/executor/execUtils.c | 10 | 15 |
| src/backend/executor/nodeModifyTable.c | 69 | 77 |
| src/include/executor/executor.h | 2 | 2 |
| src/include/nodes/execnodes.h | 1 | 4 |
Index: src/backend/commands/copy.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/copy.c,v
retrieving revision 1.318
diff -c -r1.318 copy.c
*** src/backend/commands/copy.c 20 Nov 2009 20:38:10 -0000 1.318
--- src/backend/commands/copy.c 27 Nov 2009 17:21:55 -0000
***************
*** 1811,1817 ****
estate->es_result_relations = resultRelInfo;
estate->es_num_result_relations = 1;
- estate->es_result_relation_info = resultRelInfo;
/* Set up a tuple slot too */
slot = ExecInitExtraTupleSlot(estate);
--- 1811,1816 ----
***************
*** 2165,2171 ****
heap_insert(cstate->rel, tuple, mycid, hi_options, bistate);
if (resultRelInfo->ri_NumIndices > 0)
! recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
estate, false);
/* AFTER ROW INSERT Triggers */
--- 2164,2171 ----
heap_insert(cstate->rel, tuple, mycid, hi_options, bistate);
if (resultRelInfo->ri_NumIndices > 0)
! recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
! slot, &(tuple->t_self),
estate, false);
/* AFTER ROW INSERT Triggers */
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.306
diff -c -r1.306 tablecmds.c
*** src/backend/commands/tablecmds.c 20 Nov 2009 20:38:10 -0000 1.306
--- src/backend/commands/tablecmds.c 27 Nov 2009 17:21:55 -0000
***************
*** 941,947 ****
resultRelInfo = resultRelInfos;
foreach(cell, rels)
{
- estate->es_result_relation_info = resultRelInfo;
ExecBSTruncateTriggers(estate, resultRelInfo);
resultRelInfo++;
}
--- 941,946 ----
***************
*** 1009,1015 ****
resultRelInfo = resultRelInfos;
foreach(cell, rels)
{
- estate->es_result_relation_info = resultRelInfo;
ExecASTruncateTriggers(estate, resultRelInfo);
resultRelInfo++;
}
--- 1008,1013 ----
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.396
diff -c -r1.396 vacuum.c
*** src/backend/commands/vacuum.c 16 Nov 2009 21:32:06 -0000 1.396
--- src/backend/commands/vacuum.c 27 Nov 2009 17:21:55 -0000
***************
*** 181,187 ****
ec->estate->es_result_relations = ec->resultRelInfo;
ec->estate->es_num_result_relations = 1;
- ec->estate->es_result_relation_info = ec->resultRelInfo;
/* Set up a tuple slot too */
ec->slot = MakeSingleTupleTableSlot(tupdesc);
--- 181,186 ----
***************
*** 3099,3105 ****
if (ec->resultRelInfo->ri_NumIndices > 0)
{
ExecStoreTuple(&newtup, ec->slot, InvalidBuffer, false);
! ExecInsertIndexTuples(ec->slot, &(newtup.t_self), ec->estate, true);
ResetPerTupleExprContext(ec->estate);
}
}
--- 3098,3105 ----
if (ec->resultRelInfo->ri_NumIndices > 0)
{
ExecStoreTuple(&newtup, ec->slot, InvalidBuffer, false);
! ExecInsertIndexTuples(ec->resultRelInfo, ec->slot, &(newtup.t_self),
! ec->estate, true);
ResetPerTupleExprContext(ec->estate);
}
}
***************
*** 3225,3231 ****
if (ec->resultRelInfo->ri_NumIndices > 0)
{
ExecStoreTuple(&newtup, ec->slot, InvalidBuffer, false);
! ExecInsertIndexTuples(ec->slot, &(newtup.t_self), ec->estate, true);
ResetPerTupleExprContext(ec->estate);
}
}
--- 3225,3232 ----
if (ec->resultRelInfo->ri_NumIndices > 0)
{
ExecStoreTuple(&newtup, ec->slot, InvalidBuffer, false);
! ExecInsertIndexTuples(ec->resultRelInfo, ec->slot, &(newtup.t_self),
! ec->estate, true);
ResetPerTupleExprContext(ec->estate);
}
}
Index: src/backend/executor/execJunk.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/execJunk.c,v
retrieving revision 1.59
diff -c -r1.59 execJunk.c
*** src/backend/executor/execJunk.c 10 Oct 2009 01:43:45 -0000 1.59
--- src/backend/executor/execJunk.c 27 Nov 2009 17:21:56 -0000
***************
*** 34,40 ****
* called 'resjunk'. If the value of this field is true then the
* corresponding attribute is a "junk" attribute.
*
! * When we initialize a plan we call ExecInitJunkFilter to create a filter.
*
* We then execute the plan, treating the resjunk attributes like any others.
*
--- 34,42 ----
* called 'resjunk'. If the value of this field is true then the
* corresponding attribute is a "junk" attribute.
*
! * When we initialize a plan we call ExecInitJunkFilter to create a filter,
! * if one is needed. (We need one either if there are junk attributes,
! * or if we have to add or remove an OID column from the result rowtype.)
*
* We then execute the plan, treating the resjunk attributes like any others.
*
Index: src/backend/executor/execMain.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/execMain.c,v
retrieving revision 1.335
diff -c -r1.335 execMain.c
*** src/backend/executor/execMain.c 20 Nov 2009 20:38:10 -0000 1.335
--- src/backend/executor/execMain.c 27 Nov 2009 17:21:56 -0000
***************
*** 339,345 ****
/*
* Close the SELECT INTO relation if any
*/
! if (estate->es_select_into)
CloseIntoRel(queryDesc);
/* do away with our snapshots */
--- 339,345 ----
/*
* Close the SELECT INTO relation if any
*/
! if (queryDesc->dest && queryDesc->dest->mydest == DestIntoRel)
CloseIntoRel(queryDesc);
/* do away with our snapshots */
***************
*** 624,629 ****
--- 624,630 ----
EState *estate = queryDesc->estate;
PlanState *planstate;
TupleDesc tupType;
+ bool select_into;
ListCell *l;
int i;
***************
*** 671,678 ****
}
estate->es_result_relations = resultRelInfos;
estate->es_num_result_relations = numResultRelations;
- /* es_result_relation_info is NULL except when within ModifyTable */
- estate->es_result_relation_info = NULL;
}
else
{
--- 672,677 ----
***************
*** 681,687 ****
*/
estate->es_result_relations = NULL;
estate->es_num_result_relations = 0;
- estate->es_result_relation_info = NULL;
}
/*
--- 680,685 ----
***************
*** 736,751 ****
}
/*
! * Detect whether we're doing SELECT INTO. If so, set the es_into_oids
! * flag appropriately so that the plan tree will be initialized with the
! * correct tuple descriptors. (Other SELECT INTO stuff comes later.)
*/
! estate->es_select_into = false;
! if (operation == CMD_SELECT && plannedstmt->intoClause != NULL)
! {
! estate->es_select_into = true;
! estate->es_into_oids = interpretOidsOption(plannedstmt->intoClause->options);
! }
/*
* Initialize the executor's tuple table to empty.
--- 734,742 ----
}
/*
! * Detect whether we're doing SELECT INTO.
*/
! select_into = (operation == CMD_SELECT && plannedstmt->intoClause != NULL);
/*
* Initialize the executor's tuple table to empty.
***************
*** 804,825 ****
tupType = ExecGetResultType(planstate);
/*
! * Initialize the junk filter if needed. SELECT queries need a
! * filter if there are any junk attrs in the top-level tlist.
*/
if (operation == CMD_SELECT)
{
bool junk_filter_needed = false;
! ListCell *tlist;
! foreach(tlist, plan->targetlist)
{
! TargetEntry *tle = (TargetEntry *) lfirst(tlist);
! if (tle->resjunk)
{
! junk_filter_needed = true;
! break;
}
}
--- 795,832 ----
tupType = ExecGetResultType(planstate);
/*
! * Initialize the junk filter if needed. SELECT queries need a filter
! * if there are any junk attrs in the top-level tlist, or if we're doing
! * SELECT INTO and the result type doesn't match the required hasOids
! * status.
*/
if (operation == CMD_SELECT)
{
bool junk_filter_needed = false;
! bool junk_filter_hasoid = false;
! if (select_into)
{
! /* output hasoid state must match the expected rel option */
! junk_filter_hasoid =
! interpretOidsOption(plannedstmt->intoClause->options);
! if (tupType->tdhasoid != junk_filter_hasoid)
! junk_filter_needed = true;
! }
! if (!junk_filter_needed)
! {
! ListCell *tlist;
!
! foreach(tlist, plan->targetlist)
{
! TargetEntry *tle = (TargetEntry *) lfirst(tlist);
!
! if (tle->resjunk)
! {
! junk_filter_needed = true;
! break;
! }
}
}
***************
*** 828,834 ****
JunkFilter *j;
j = ExecInitJunkFilter(planstate->plan->targetlist,
! tupType->tdhasoid,
ExecInitExtraTupleSlot(estate));
estate->es_junkFilter = j;
--- 835,841 ----
JunkFilter *j;
j = ExecInitJunkFilter(planstate->plan->targetlist,
! junk_filter_hasoid,
ExecInitExtraTupleSlot(estate));
estate->es_junkFilter = j;
***************
*** 847,853 ****
*
* If EXPLAIN, skip creating the "into" relation.
*/
! if (estate->es_select_into && !(eflags & EXEC_FLAG_EXPLAIN_ONLY))
OpenIntoRel(queryDesc);
}
--- 854,860 ----
*
* If EXPLAIN, skip creating the "into" relation.
*/
! if (select_into && !(eflags & EXEC_FLAG_EXPLAIN_ONLY))
OpenIntoRel(queryDesc);
}
***************
*** 1010,1072 ****
return rInfo;
}
- /*
- * ExecContextForcesOids
- *
- * This is pretty grotty: when doing INSERT, UPDATE, or SELECT INTO,
- * we need to ensure that result tuples have space for an OID iff they are
- * going to be stored into a relation that has OIDs. In other contexts
- * we are free to choose whether to leave space for OIDs in result tuples
- * (we generally don't want to, but we do if a physical-tlist optimization
- * is possible). This routine checks the plan context and returns TRUE if the
- * choice is forced, FALSE if the choice is not forced. In the TRUE case,
- * *hasoids is set to the required value.
- *
- * One reason this is ugly is that all plan nodes in the plan tree will emit
- * tuples with space for an OID, though we really only need the topmost node
- * to do so. However, node types like Sort don't project new tuples but just
- * return their inputs, and in those cases the requirement propagates down
- * to the input node. Eventually we might make this code smart enough to
- * recognize how far down the requirement really goes, but for now we just
- * make all plan nodes do the same thing if the top level forces the choice.
- *
- * We assume that if we are generating tuples for INSERT or UPDATE,
- * estate->es_result_relation_info is already set up to describe the target
- * relation. Note that in an UPDATE that spans an inheritance tree, some of
- * the target relations may have OIDs and some not. We have to make the
- * decisions on a per-relation basis as we initialize each of the subplans of
- * the ModifyTable node, so ModifyTable has to set es_result_relation_info
- * while initializing each subplan.
- *
- * SELECT INTO is even uglier, because we don't have the INTO relation's
- * descriptor available when this code runs; we have to look aside at a
- * flag set by InitPlan().
- */
- bool
- ExecContextForcesOids(PlanState *planstate, bool *hasoids)
- {
- ResultRelInfo *ri = planstate->state->es_result_relation_info;
-
- if (ri != NULL)
- {
- Relation rel = ri->ri_RelationDesc;
-
- if (rel != NULL)
- {
- *hasoids = rel->rd_rel->relhasoids;
- return true;
- }
- }
-
- if (planstate->state->es_select_into)
- {
- *hasoids = planstate->state->es_into_oids;
- return true;
- }
-
- return false;
- }
-
/* ----------------------------------------------------------------
* ExecEndPlan
*
--- 1017,1022 ----
***************
*** 1887,1898 ****
estate->es_output_cid = parentestate->es_output_cid;
estate->es_result_relations = parentestate->es_result_relations;
estate->es_num_result_relations = parentestate->es_num_result_relations;
- estate->es_result_relation_info = parentestate->es_result_relation_info;
/* es_trig_target_relations must NOT be copied */
estate->es_rowMarks = parentestate->es_rowMarks;
estate->es_instrument = parentestate->es_instrument;
- estate->es_select_into = parentestate->es_select_into;
- estate->es_into_oids = parentestate->es_into_oids;
/*
* The external param list is simply shared from parent. The internal
--- 1837,1845 ----
Index: src/backend/executor/execScan.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/execScan.c,v
retrieving revision 1.47
diff -c -r1.47 execScan.c
*** src/backend/executor/execScan.c 26 Oct 2009 02:26:29 -0000 1.47
--- src/backend/executor/execScan.c 27 Nov 2009 17:21:56 -0000
***************
*** 23,29 ****
#include "utils/memutils.h"
! static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc);
/*
--- 23,30 ----
#include "utils/memutils.h"
! static bool tlist_matches_tupdesc(List *tlist, Index varno, TupleDesc tupdesc,
! bool resulthasoid);
/*
***************
*** 235,263 ****
* the scan node, because the planner will preferentially generate a matching
* tlist.
*
! * ExecAssignScanType must have been called already.
*/
void
ExecAssignScanProjectionInfo(ScanState *node)
{
Scan *scan = (Scan *) node->ps.plan;
! if (tlist_matches_tupdesc(&node->ps,
! scan->plan.targetlist,
scan->scanrelid,
! node->ss_ScanTupleSlot->tts_tupleDescriptor))
node->ps.ps_ProjInfo = NULL;
else
! ExecAssignProjectionInfo(&node->ps,
! node->ss_ScanTupleSlot->tts_tupleDescriptor);
}
static bool
! tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc)
{
int numattrs = tupdesc->natts;
int attrno;
- bool hasoid;
ListCell *tlist_item = list_head(tlist);
/* Check the tlist attributes */
--- 236,265 ----
* the scan node, because the planner will preferentially generate a matching
* tlist.
*
! * ExecAssignScanType and ExecAssignResultType must have been called already.
*/
void
ExecAssignScanProjectionInfo(ScanState *node)
{
Scan *scan = (Scan *) node->ps.plan;
+ TupleDesc scandesc = node->ss_ScanTupleSlot->tts_tupleDescriptor;
+ TupleDesc resultdesc = node->ps.ps_ResultTupleSlot->tts_tupleDescriptor;
! if (tlist_matches_tupdesc(scan->plan.targetlist,
scan->scanrelid,
! scandesc,
! resultdesc->tdhasoid))
node->ps.ps_ProjInfo = NULL;
else
! ExecAssignProjectionInfo(&node->ps, scandesc);
}
static bool
! tlist_matches_tupdesc(List *tlist, Index varno, TupleDesc tupdesc,
! bool resulthasoid)
{
int numattrs = tupdesc->natts;
int attrno;
ListCell *tlist_item = list_head(tlist);
/* Check the tlist attributes */
***************
*** 301,311 ****
return false; /* tlist too long */
/*
! * If the plan context requires a particular hasoid setting, then that has
! * to match, too.
*/
! if (ExecContextForcesOids(ps, &hasoid) &&
! hasoid != tupdesc->tdhasoid)
return false;
return true;
--- 303,311 ----
return false; /* tlist too long */
/*
! * The hasOids state has to match the output rowtype, too.
*/
! if (tupdesc->tdhasoid != resulthasoid)
return false;
return true;
Index: src/backend/executor/execUtils.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/execUtils.c,v
retrieving revision 1.166
diff -c -r1.166 execUtils.c
*** src/backend/executor/execUtils.c 20 Nov 2009 20:38:10 -0000 1.166
--- src/backend/executor/execUtils.c 27 Nov 2009 17:21:56 -0000
***************
*** 113,119 ****
estate->es_result_relations = NULL;
estate->es_num_result_relations = 0;
- estate->es_result_relation_info = NULL;
estate->es_trig_target_relations = NIL;
estate->es_trig_tuple_slot = NULL;
--- 113,118 ----
***************
*** 132,139 ****
estate->es_lastoid = InvalidOid;
estate->es_instrument = false;
- estate->es_select_into = false;
- estate->es_into_oids = false;
estate->es_exprcontexts = NIL;
--- 131,136 ----
***************
*** 440,454 ****
bool hasoid;
TupleDesc tupDesc;
! if (ExecContextForcesOids(planstate, &hasoid))
! {
! /* context forces OID choice; hasoid is now set correctly */
! }
! else
! {
! /* given free choice, don't leave space for OIDs in result tuples */
! hasoid = false;
! }
/*
* ExecTypeFromTL needs the parse-time representation of the tlist, not a
--- 437,450 ----
bool hasoid;
TupleDesc tupDesc;
! /*
! * If the plan is a scan node on a relation that has OIDs, it would be
! * desirable to allow OIDs in the output rowtype, so that a physical
! * tlist optimization is possible. It would require some refactoring
! * to make that knowledge available here, however, so for the moment
! * just set hasoid = false always.
! */
! hasoid = false;
/*
* ExecTypeFromTL needs the parse-time representation of the tlist, not a
***************
*** 969,981 ****
* ----------------------------------------------------------------
*/
List *
! ExecInsertIndexTuples(TupleTableSlot *slot,
ItemPointer tupleid,
EState *estate,
bool is_vacuum_full)
{
List *result = NIL;
- ResultRelInfo *resultRelInfo;
int i;
int numIndices;
RelationPtr relationDescs;
--- 965,977 ----
* ----------------------------------------------------------------
*/
List *
! ExecInsertIndexTuples(ResultRelInfo *resultRelInfo,
! TupleTableSlot *slot,
ItemPointer tupleid,
EState *estate,
bool is_vacuum_full)
{
List *result = NIL;
int i;
int numIndices;
RelationPtr relationDescs;
***************
*** 988,994 ****
/*
* Get information from the result relation info structure.
*/
- resultRelInfo = estate->es_result_relation_info;
numIndices = resultRelInfo->ri_NumIndices;
relationDescs = resultRelInfo->ri_IndexRelationDescs;
indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
--- 984,989 ----
Index: src/backend/executor/nodeModifyTable.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/nodeModifyTable.c,v
retrieving revision 1.3
diff -c -r1.3 nodeModifyTable.c
*** src/backend/executor/nodeModifyTable.c 20 Nov 2009 20:38:10 -0000 1.3
--- src/backend/executor/nodeModifyTable.c 27 Nov 2009 17:21:56 -0000
***************
*** 158,169 ****
* ----------------------------------------------------------------
*/
static TupleTableSlot *
! ExecInsert(TupleTableSlot *slot,
TupleTableSlot *planSlot,
EState *estate)
{
HeapTuple tuple;
- ResultRelInfo *resultRelInfo;
Relation resultRelationDesc;
Oid newId;
List *recheckIndexes = NIL;
--- 158,169 ----
* ----------------------------------------------------------------
*/
static TupleTableSlot *
! ExecInsert(ResultRelInfo *resultRelInfo,
! TupleTableSlot *slot,
TupleTableSlot *planSlot,
EState *estate)
{
HeapTuple tuple;
Relation resultRelationDesc;
Oid newId;
List *recheckIndexes = NIL;
***************
*** 177,183 ****
/*
* get information on the (current) result relation
*/
- resultRelInfo = estate->es_result_relation_info;
resultRelationDesc = resultRelInfo->ri_RelationDesc;
/*
--- 177,182 ----
***************
*** 248,254 ****
* insert index entries for tuple
*/
if (resultRelInfo->ri_NumIndices > 0)
! recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
estate, false);
/* AFTER ROW INSERT Triggers */
--- 247,254 ----
* insert index entries for tuple
*/
if (resultRelInfo->ri_NumIndices > 0)
! recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
! slot, &(tuple->t_self),
estate, false);
/* AFTER ROW INSERT Triggers */
***************
*** 272,283 ****
* ----------------------------------------------------------------
*/
static TupleTableSlot *
! ExecDelete(ItemPointer tupleid,
TupleTableSlot *planSlot,
EPQState *epqstate,
EState *estate)
{
- ResultRelInfo *resultRelInfo;
Relation resultRelationDesc;
HTSU_Result result;
ItemPointerData update_ctid;
--- 272,283 ----
* ----------------------------------------------------------------
*/
static TupleTableSlot *
! ExecDelete(ResultRelInfo *resultRelInfo,
! ItemPointer tupleid,
TupleTableSlot *planSlot,
EPQState *epqstate,
EState *estate)
{
Relation resultRelationDesc;
HTSU_Result result;
ItemPointerData update_ctid;
***************
*** 286,292 ****
/*
* get information on the (current) result relation
*/
- resultRelInfo = estate->es_result_relation_info;
resultRelationDesc = resultRelInfo->ri_RelationDesc;
/* BEFORE ROW DELETE Triggers */
--- 286,291 ----
***************
*** 415,428 ****
* ----------------------------------------------------------------
*/
static TupleTableSlot *
! ExecUpdate(ItemPointer tupleid,
TupleTableSlot *slot,
TupleTableSlot *planSlot,
EPQState *epqstate,
EState *estate)
{
HeapTuple tuple;
- ResultRelInfo *resultRelInfo;
Relation resultRelationDesc;
HTSU_Result result;
ItemPointerData update_ctid;
--- 414,427 ----
* ----------------------------------------------------------------
*/
static TupleTableSlot *
! ExecUpdate(ResultRelInfo *resultRelInfo,
! ItemPointer tupleid,
TupleTableSlot *slot,
TupleTableSlot *planSlot,
EPQState *epqstate,
EState *estate)
{
HeapTuple tuple;
Relation resultRelationDesc;
HTSU_Result result;
ItemPointerData update_ctid;
***************
*** 444,450 ****
/*
* get information on the (current) result relation
*/
- resultRelInfo = estate->es_result_relation_info;
resultRelationDesc = resultRelInfo->ri_RelationDesc;
/* BEFORE ROW UPDATE Triggers */
--- 443,448 ----
***************
*** 563,569 ****
* If it's a HOT update, we mustn't insert new index entries.
*/
if (resultRelInfo->ri_NumIndices > 0 && !HeapTupleIsHeapOnly(tuple))
! recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
estate, false);
/* AFTER ROW UPDATE Triggers */
--- 561,568 ----
* If it's a HOT update, we mustn't insert new index entries.
*/
if (resultRelInfo->ri_NumIndices > 0 && !HeapTupleIsHeapOnly(tuple))
! recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
! slot, &(tuple->t_self),
estate, false);
/* AFTER ROW UPDATE Triggers */
***************
*** 645,650 ****
--- 644,650 ----
EState *estate = node->ps.state;
CmdType operation = node->operation;
PlanState *subplanstate;
+ ResultRelInfo *resultRelInfo;
JunkFilter *junkfilter;
TupleTableSlot *slot;
TupleTableSlot *planSlot;
***************
*** 660,676 ****
node->fireBSTriggers = false;
}
- /*
- * es_result_relation_info must point to the currently active result
- * relation. (Note we assume that ModifyTable nodes can't be nested.)
- * We want it to be NULL whenever we're not within ModifyTable, though.
- */
- estate->es_result_relation_info =
- estate->es_result_relations + node->mt_whichplan;
-
/* Preload local variables */
subplanstate = node->mt_plans[node->mt_whichplan];
! junkfilter = estate->es_result_relation_info->ri_junkFilter;
/*
* Fetch rows from subplan(s), and execute the required table modification
--- 660,669 ----
node->fireBSTriggers = false;
}
/* Preload local variables */
subplanstate = node->mt_plans[node->mt_whichplan];
! resultRelInfo = estate->es_result_relations + node->mt_whichplan;
! junkfilter = resultRelInfo->ri_junkFilter;
/*
* Fetch rows from subplan(s), and execute the required table modification
***************
*** 686,694 ****
node->mt_whichplan++;
if (node->mt_whichplan < node->mt_nplans)
{
- estate->es_result_relation_info++;
subplanstate = node->mt_plans[node->mt_whichplan];
! junkfilter = estate->es_result_relation_info->ri_junkFilter;
EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan);
continue;
}
--- 679,687 ----
node->mt_whichplan++;
if (node->mt_whichplan < node->mt_nplans)
{
subplanstate = node->mt_plans[node->mt_whichplan];
! resultRelInfo = estate->es_result_relations + node->mt_whichplan;
! junkfilter = resultRelInfo->ri_junkFilter;
EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan);
continue;
}
***************
*** 730,743 ****
switch (operation)
{
case CMD_INSERT:
! slot = ExecInsert(slot, planSlot, estate);
break;
case CMD_UPDATE:
! slot = ExecUpdate(tupleid, slot, planSlot,
&node->mt_epqstate, estate);
break;
case CMD_DELETE:
! slot = ExecDelete(tupleid, planSlot,
&node->mt_epqstate, estate);
break;
default:
--- 723,739 ----
switch (operation)
{
case CMD_INSERT:
! slot = ExecInsert(resultRelInfo,
! slot, planSlot, estate);
break;
case CMD_UPDATE:
! slot = ExecUpdate(resultRelInfo,
! tupleid, slot, planSlot,
&node->mt_epqstate, estate);
break;
case CMD_DELETE:
! slot = ExecDelete(resultRelInfo,
! tupleid, planSlot,
&node->mt_epqstate, estate);
break;
default:
***************
*** 750,764 ****
* the work on next call.
*/
if (slot)
- {
- estate->es_result_relation_info = NULL;
return slot;
- }
}
- /* Reset es_result_relation_info before exiting */
- estate->es_result_relation_info = NULL;
-
/*
* We're done, but fire AFTER STATEMENT triggers before exiting.
*/
--- 746,754 ----
***************
*** 813,832 ****
/*
* call ExecInitNode on each of the plans to be executed and save the
! * results into the array "mt_plans". Note we *must* set
! * estate->es_result_relation_info correctly while we initialize each
! * sub-plan; ExecContextForcesOids depends on that!
*/
- estate->es_result_relation_info = estate->es_result_relations;
i = 0;
foreach(l, node->plans)
{
subplan = (Plan *) lfirst(l);
mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
- estate->es_result_relation_info++;
i++;
}
- estate->es_result_relation_info = NULL;
/* select first subplan */
mtstate->mt_whichplan = 0;
--- 803,817 ----
/*
* call ExecInitNode on each of the plans to be executed and save the
! * results into the array "mt_plans".
*/
i = 0;
foreach(l, node->plans)
{
subplan = (Plan *) lfirst(l);
mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
i++;
}
/* select first subplan */
mtstate->mt_whichplan = 0;
***************
*** 921,951 ****
/*
* Initialize the junk filter(s) if needed. INSERT queries need a filter
! * if there are any junk attrs in the tlist. UPDATE and DELETE
! * always need a filter, since there's always a junk 'ctid' attribute
! * present --- no need to look first.
*
* If there are multiple result relations, each one needs its own junk
! * filter. Note multiple rels are only possible for UPDATE/DELETE, so we
! * can't be fooled by some needing a filter and some not.
*
* This section of code is also a convenient place to verify that the
* output of an INSERT or UPDATE matches the target table(s).
*/
{
bool junk_filter_needed = false;
switch (operation)
{
case CMD_INSERT:
! foreach(l, subplan->targetlist)
{
! TargetEntry *tle = (TargetEntry *) lfirst(l);
!
! if (tle->resjunk)
{
! junk_filter_needed = true;
! break;
}
}
break;
--- 906,958 ----
/*
* Initialize the junk filter(s) if needed. INSERT queries need a filter
! * if there are any junk attrs in the tlist, or if we have to add or
! * remove an OID column. UPDATE and DELETE always need a filter, since
! * there's always a junk 'ctid' attribute present --- no need to look
! * first. (For DELETE, we won't actually use the filter to filter tuples,
! * but we still need it for extracting the ctid attribute.)
*
* If there are multiple result relations, each one needs its own junk
! * filter.
*
* This section of code is also a convenient place to verify that the
* output of an INSERT or UPDATE matches the target table(s).
*/
+ resultRelInfo = estate->es_result_relations;
+ for (i = 0; i < nplans; i++)
{
bool junk_filter_needed = false;
+ bool junk_filter_hasoid = false;
+
+ subplan = mtstate->mt_plans[i]->plan;
+
+ if (operation == CMD_INSERT || operation == CMD_UPDATE)
+ {
+ TupleDesc tupType;
+
+ ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
+ subplan->targetlist);
+ /* output hasoid state must match the rel */
+ junk_filter_hasoid = resultRelInfo->ri_RelationDesc->rd_att->tdhasoid;
+ tupType = ExecGetResultType(mtstate->mt_plans[i]);
+ if (tupType->tdhasoid != junk_filter_hasoid)
+ junk_filter_needed = true;
+ }
switch (operation)
{
case CMD_INSERT:
! if (!junk_filter_needed)
{
! foreach(l, subplan->targetlist)
{
! TargetEntry *tle = (TargetEntry *) lfirst(l);
!
! if (tle->resjunk)
! {
! junk_filter_needed = true;
! break;
! }
}
}
break;
***************
*** 960,997 ****
if (junk_filter_needed)
{
! resultRelInfo = estate->es_result_relations;
! for (i = 0; i < nplans; i++)
! {
! JunkFilter *j;
!
! subplan = mtstate->mt_plans[i]->plan;
! if (operation == CMD_INSERT || operation == CMD_UPDATE)
! ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
! subplan->targetlist);
!
! j = ExecInitJunkFilter(subplan->targetlist,
! resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
! ExecInitExtraTupleSlot(estate));
! if (operation == CMD_UPDATE || operation == CMD_DELETE)
! {
! /* For UPDATE/DELETE, find the ctid junk attr now */
! j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
! if (!AttributeNumberIsValid(j->jf_junkAttNo))
! elog(ERROR, "could not find junk ctid column");
! }
!
! resultRelInfo->ri_junkFilter = j;
! resultRelInfo++;
}
}
! else
! {
! if (operation == CMD_INSERT)
! ExecCheckPlanOutput(estate->es_result_relations->ri_RelationDesc,
! subplan->targetlist);
! }
}
/*
--- 967,989 ----
if (junk_filter_needed)
{
! JunkFilter *j;
! j = ExecInitJunkFilter(subplan->targetlist,
! junk_filter_hasoid,
! ExecInitExtraTupleSlot(estate));
! if (operation == CMD_UPDATE || operation == CMD_DELETE)
! {
! /* For UPDATE/DELETE, find the ctid junk attr now */
! j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
! if (!AttributeNumberIsValid(j->jf_junkAttNo))
! elog(ERROR, "could not find junk ctid column");
}
+
+ resultRelInfo->ri_junkFilter = j;
}
!
! resultRelInfo++;
}
/*
Index: src/include/executor/executor.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/executor/executor.h,v
retrieving revision 1.163
diff -c -r1.163 executor.h
*** src/include/executor/executor.h 26 Oct 2009 02:26:41 -0000 1.163
--- src/include/executor/executor.h 27 Nov 2009 17:21:56 -0000
***************
*** 163,169 ****
CmdType operation,
bool doInstrument);
extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);
- extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
extern void ExecConstraints(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate);
extern TupleTableSlot *EvalPlanQual(EState *estate, EPQState *epqstate,
--- 163,168 ----
***************
*** 319,325 ****
extern void ExecOpenIndices(ResultRelInfo *resultRelInfo);
extern void ExecCloseIndices(ResultRelInfo *resultRelInfo);
! extern List *ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,
EState *estate, bool is_vacuum_full);
extern void RegisterExprContextCallback(ExprContext *econtext,
--- 318,325 ----
extern void ExecOpenIndices(ResultRelInfo *resultRelInfo);
extern void ExecCloseIndices(ResultRelInfo *resultRelInfo);
! extern List *ExecInsertIndexTuples(ResultRelInfo *resultRelInfo,
! TupleTableSlot *slot, ItemPointer tupleid,
EState *estate, bool is_vacuum_full);
extern void RegisterExprContextCallback(ExprContext *econtext,
Index: src/include/nodes/execnodes.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/nodes/execnodes.h,v
retrieving revision 1.212
diff -c -r1.212 execnodes.h
*** src/include/nodes/execnodes.h 20 Nov 2009 20:38:11 -0000 1.212
--- src/include/nodes/execnodes.h 27 Nov 2009 17:21:56 -0000
***************
*** 340,349 ****
/* If query can insert/delete tuples, the command ID to mark them with */
CommandId es_output_cid;
! /* Info about target table for insert/update/delete queries: */
ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
int es_num_result_relations; /* length of array */
- ResultRelInfo *es_result_relation_info; /* currently active array elt */
/* Stuff used for firing triggers: */
List *es_trig_target_relations; /* trigger-only ResultRelInfos */
--- 340,348 ----
/* If query can insert/delete tuples, the command ID to mark them with */
CommandId es_output_cid;
! /* Info about target tables for insert/update/delete queries: */
ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
int es_num_result_relations; /* length of array */
/* Stuff used for firing triggers: */
List *es_trig_target_relations; /* trigger-only ResultRelInfos */
***************
*** 365,372 ****
Oid es_lastoid; /* last oid processed (by INSERT) */
bool es_instrument; /* true requests runtime instrumentation */
- bool es_select_into; /* true if doing SELECT INTO */
- bool es_into_oids; /* true to generate OIDs in SELECT INTO */
List *es_exprcontexts; /* List of ExprContexts within EState */
--- 364,369 ----