diff options
-rw-r--r-- | src/backend/commands/tablecmds.c | 57 | ||||
-rw-r--r-- | src/backend/executor/execQual.c | 242 | ||||
-rw-r--r-- | src/backend/executor/execScan.c | 12 | ||||
-rw-r--r-- | src/backend/executor/execUtils.c | 43 | ||||
-rw-r--r-- | src/backend/executor/nodeAgg.c | 4 | ||||
-rw-r--r-- | src/backend/executor/nodeGroup.c | 4 | ||||
-rw-r--r-- | src/backend/executor/nodeHashjoin.c | 4 | ||||
-rw-r--r-- | src/backend/executor/nodeMergejoin.c | 4 | ||||
-rw-r--r-- | src/backend/executor/nodeNestloop.c | 4 | ||||
-rw-r--r-- | src/backend/executor/nodeResult.c | 4 | ||||
-rw-r--r-- | src/backend/executor/nodeSubplan.c | 8 | ||||
-rw-r--r-- | src/include/executor/executor.h | 8 |
12 files changed, 306 insertions, 88 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index e8e2f4e3608..04a3dc632a5 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.174.2.3 2006/07/10 22:10:47 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.174.2.4 2007/02/02 00:07:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1799,22 +1799,47 @@ update_ri_trigger_args(Oid relid, void AlterTable(AlterTableStmt *stmt) { - ATController(relation_openrv(stmt->relation, AccessExclusiveLock), - stmt->cmds, - interpretInhOption(stmt->relation->inhOpt)); + Relation rel = relation_openrv(stmt->relation, AccessExclusiveLock); + int expected_refcnt; + + /* + * Disallow ALTER TABLE when the current backend has any open reference + * to it besides the one we just got (such as an open cursor or active + * plan); our AccessExclusiveLock doesn't protect us against stomping on + * our own foot, only other people's feet! + * + * Note: the only case known to cause serious trouble is ALTER COLUMN TYPE, + * and some changes are obviously pretty benign, so this could possibly + * be relaxed to only error out for certain types of alterations. But + * the use-case for allowing any of these things is not obvious, so we + * won't work hard at it for now. + */ + expected_refcnt = rel->rd_isnailed ? 2 : 1; + if (rel->rd_refcnt != expected_refcnt) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_IN_USE), + errmsg("relation \"%s\" is being used by active queries in this session", + RelationGetRelationName(rel)))); + + ATController(rel, stmt->cmds, interpretInhOption(stmt->relation->inhOpt)); } /* * AlterTableInternal * * ALTER TABLE with target specified by OID + * + * We do not reject if the relation is already open, because it's quite + * likely that one or more layers of caller have it open. That means it + * is unsafe to use this entry point for alterations that could break + * existing query plans. */ void AlterTableInternal(Oid relid, List *cmds, bool recurse) { - ATController(relation_open(relid, AccessExclusiveLock), - cmds, - recurse); + Relation rel = relation_open(relid, AccessExclusiveLock); + + ATController(rel, cmds, recurse); } static void @@ -2719,6 +2744,12 @@ ATSimpleRecursion(List **wqueue, Relation rel, if (childrelid == relid) continue; childrel = relation_open(childrelid, AccessExclusiveLock); + /* check for child relation in use in this session */ + if (childrel->rd_refcnt != 1) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_IN_USE), + errmsg("relation \"%s\" is being used by active queries in this session", + RelationGetRelationName(childrel)))); ATPrepCmd(wqueue, childrel, cmd, false, true); relation_close(childrel, NoLock); } @@ -2750,6 +2781,12 @@ ATOneLevelRecursion(List **wqueue, Relation rel, Relation childrel; childrel = relation_open(childrelid, AccessExclusiveLock); + /* check for child relation in use in this session */ + if (childrel->rd_refcnt != 1) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_IN_USE), + errmsg("relation \"%s\" is being used by active queries in this session", + RelationGetRelationName(childrel)))); ATPrepCmd(wqueue, childrel, cmd, true, true); relation_close(childrel, NoLock); } @@ -3571,6 +3608,12 @@ ATExecDropColumn(Relation rel, const char *colName, Form_pg_attribute childatt; childrel = heap_open(childrelid, AccessExclusiveLock); + /* check for child relation in use in this session */ + if (childrel->rd_refcnt != 1) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_IN_USE), + errmsg("relation \"%s\" is being used by active queries in this session", + RelationGetRelationName(childrel)))); tuple = SearchSysCacheCopyAttName(childrelid, colName); if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index e21aba888f1..e063814aad9 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.183.2.4 2006/11/06 18:21:38 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.183.2.5 2007/02/02 00:07:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -64,6 +64,8 @@ static Datum ExecEvalAggref(AggrefExprState *aggref, bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalVar(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); +static Datum ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext, @@ -434,6 +436,10 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, * * Returns a Datum whose value is the value of a range * variable with respect to given expression context. + * + * Note: ExecEvalVar is executed only the first time through in a given plan; + * it changes the ExprState's function pointer to pass control directly to + * ExecEvalScalarVar or ExecEvalWholeRowVar after making one-time checks. * ---------------------------------------------------------------- */ static Datum @@ -448,7 +454,7 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext, *isDone = ExprSingleResult; /* - * Get the slot and attribute number we want + * Get the input slot and attribute number we want * * The asserts check that references to system attributes only appear at * the level of a relation scan; at higher levels, system attributes must @@ -475,35 +481,168 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext, break; } -#ifdef USE_ASSERT_CHECKING - - /* - * Some checks that are only applied for user attribute numbers (bogus - * system attnums will be caught inside slot_getattr). - */ - if (attnum > 0) + if (attnum != InvalidAttrNumber) { - TupleDesc tuple_type = slot->tts_tupleDescriptor; - /* - * This assert checks that the attnum is valid. + * Scalar variable case. + * + * If it's a user attribute, check validity (bogus system attnums will + * be caught inside slot_getattr). What we have to check for here + * is the possibility of an attribute having been changed in type + * since the plan tree was created. Ideally the plan would get + * invalidated and not re-used, but until that day arrives, we need + * defenses. Fortunately it's sufficient to check once on the first + * time through. + * + * Note: we allow a reference to a dropped attribute. slot_getattr + * will force a NULL result in such cases. + * + * Note: we check typmod, but allow the case that the Var has + * unspecified typmod while the column has a specific typmod. */ - Assert(attnum <= tuple_type->natts); + if (attnum > 0) + { + TupleDesc slot_tupdesc = slot->tts_tupleDescriptor; + Form_pg_attribute attr; + + if (attnum > slot_tupdesc->natts) /* should never happen */ + elog(ERROR, "attribute number %d exceeds number of columns %d", + attnum, slot_tupdesc->natts); + + attr = slot_tupdesc->attrs[attnum - 1]; + /* can't check type if dropped, since atttypid is probably 0 */ + if (!attr->attisdropped) + { + if (variable->vartype != attr->atttypid || + (variable->vartypmod != attr->atttypmod && + variable->vartypmod != -1)) + ereport(ERROR, + (errmsg("attribute %d has wrong type", attnum), + errdetail("Table has type %s, but query expects %s.", + format_type_be(attr->atttypid), + format_type_be(variable->vartype)))); + } + } + + /* Skip the checking on future executions of node */ + exprstate->evalfunc = ExecEvalScalarVar; + + /* Fetch the value from the slot */ + return slot_getattr(slot, attnum, isNull); + } + else + { /* - * This assert checks that the datatype the plan expects to get (as - * told by our "variable" argument) is in fact the datatype of the - * attribute being fetched (as seen in the current context, identified - * by our "econtext" argument). Otherwise crashes are likely. + * Whole-row variable. * - * Note that we can't check dropped columns, since their atttypid has - * been zeroed. + * If it's a RECORD Var, we'll use the slot's type ID info. It's + * likely that the slot's type is also RECORD; if so, make sure it's + * been "blessed", so that the Datum can be interpreted later. + * + * If the Var identifies a named composite type, we must check that + * the actual tuple type is compatible with it. */ - Assert(variable->vartype == tuple_type->attrs[attnum - 1]->atttypid || - tuple_type->attrs[attnum - 1]->attisdropped); + TupleDesc slot_tupdesc = slot->tts_tupleDescriptor; + + if (variable->vartype == RECORDOID) + { + if (slot_tupdesc->tdtypeid == RECORDOID && + slot_tupdesc->tdtypmod < 0) + assign_record_type_typmod(slot_tupdesc); + } + else + { + TupleDesc var_tupdesc; + int i; + + /* + * We really only care about number of attributes and data type. + * Also, we can ignore type mismatch on columns that are dropped + * in the destination type, so long as the physical storage + * matches. This is helpful in some cases involving out-of-date + * cached plans. + */ + var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1); + + if (var_tupdesc->natts != slot_tupdesc->natts) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("table row type and query-specified row type do not match"), + errdetail("Table row contains %d attributes, but query expects %d.", + slot_tupdesc->natts, var_tupdesc->natts))); + + for (i = 0; i < var_tupdesc->natts; i++) + { + Form_pg_attribute vattr = var_tupdesc->attrs[i]; + Form_pg_attribute sattr = slot_tupdesc->attrs[i]; + + if (vattr->atttypid == sattr->atttypid) + continue; /* no worries */ + if (!vattr->attisdropped) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("table row type and query-specified row type do not match"), + errdetail("Table has type %s at ordinal position %d, but query expects %s.", + format_type_be(sattr->atttypid), + i + 1, + format_type_be(vattr->atttypid)))); + + if (vattr->attlen != sattr->attlen || + vattr->attalign != sattr->attalign) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("table row type and query-specified row type do not match"), + errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.", + i + 1))); + } + } + + /* Skip the checking on future executions of node */ + exprstate->evalfunc = ExecEvalWholeRowVar; + + /* Fetch the value */ + return ExecEvalWholeRowVar(exprstate, econtext, isNull, isDone); + } +} + +/* ---------------------------------------------------------------- + * ExecEvalScalarVar + * + * Returns a Datum for a scalar variable. + * ---------------------------------------------------------------- + */ +static Datum +ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone) +{ + Var *variable = (Var *) exprstate->expr; + TupleTableSlot *slot; + AttrNumber attnum; + + if (isDone) + *isDone = ExprSingleResult; + + /* Get the input slot and attribute number we want */ + switch (variable->varno) + { + case INNER: /* get the tuple from the inner node */ + slot = econtext->ecxt_innertuple; + break; + + case OUTER: /* get the tuple from the outer node */ + slot = econtext->ecxt_outertuple; + break; + + default: /* get the tuple from the relation being + * scanned */ + slot = econtext->ecxt_scantuple; + break; } -#endif /* USE_ASSERT_CHECKING */ + attnum = variable->varattno; + + /* Fetch the value from the slot */ return slot_getattr(slot, attnum, isNull); } @@ -511,10 +650,6 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext, * ExecEvalWholeRowVar * * Returns a Datum for a whole-row variable. - * - * This could be folded into ExecEvalVar, but we make it a separate - * routine so as not to slow down ExecEvalVar with tests for this - * uncommon case. * ---------------------------------------------------------------- */ static Datum @@ -522,7 +657,7 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone) { Var *variable = (Var *) exprstate->expr; - TupleTableSlot *slot; + TupleTableSlot *slot = econtext->ecxt_scantuple; HeapTuple tuple; TupleDesc tupleDesc; HeapTupleHeader dtuple; @@ -531,16 +666,6 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext, *isDone = ExprSingleResult; *isNull = false; - Assert(variable->varattno == InvalidAttrNumber); - - /* - * Whole-row Vars can only appear at the level of a relation scan, never - * in a join. - */ - Assert(variable->varno != INNER); - Assert(variable->varno != OUTER); - slot = econtext->ecxt_scantuple; - tuple = ExecFetchSlotTuple(slot); tupleDesc = slot->tts_tupleDescriptor; @@ -556,9 +681,6 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext, /* * If the Var identifies a named composite type, label the tuple with that * type; otherwise use what is in the tupleDesc. - * - * It's likely that the slot's tupleDesc is a record type; if so, make - * sure it's been "blessed", so that the Datum can be interpreted later. */ if (variable->vartype != RECORDOID) { @@ -567,9 +689,6 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext, } else { - if (tupleDesc->tdtypeid == RECORDOID && - tupleDesc->tdtypmod < 0) - assign_record_type_typmod(tupleDesc); HeapTupleHeaderSetTypeId(dtuple, tupleDesc->tdtypeid); HeapTupleHeaderSetTypMod(dtuple, tupleDesc->tdtypmod); } @@ -2700,12 +2819,14 @@ ExecEvalFieldSelect(FieldSelectState *fstate, ExprDoneCond *isDone) { FieldSelect *fselect = (FieldSelect *) fstate->xprstate.expr; + AttrNumber fieldnum = fselect->fieldnum; Datum result; Datum tupDatum; HeapTupleHeader tuple; Oid tupType; int32 tupTypmod; TupleDesc tupDesc; + Form_pg_attribute attr; HeapTupleData tmptup; tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull, isDone); @@ -2737,6 +2858,28 @@ ExecEvalFieldSelect(FieldSelectState *fstate, MemoryContextSwitchTo(oldcontext); } + /* Check for dropped column, and force a NULL result if so */ + if (fieldnum <= 0 || + fieldnum > tupDesc->natts) /* should never happen */ + elog(ERROR, "attribute number %d exceeds number of columns %d", + fieldnum, tupDesc->natts); + attr = tupDesc->attrs[fieldnum - 1]; + if (attr->attisdropped) + { + *isNull = true; + return (Datum) 0; + } + + /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */ + if (fselect->resulttype != attr->atttypid || + (fselect->resulttypmod != attr->atttypmod && + fselect->resulttypmod != -1)) + ereport(ERROR, + (errmsg("attribute %d has wrong type", fieldnum), + errdetail("Table has type %s, but query expects %s.", + format_type_be(attr->atttypid), + format_type_be(fselect->resulttype)))); + /* * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set all * the fields in the struct just in case user tries to inspect system @@ -2748,7 +2891,7 @@ ExecEvalFieldSelect(FieldSelectState *fstate, tmptup.t_data = tuple; result = heap_getattr(&tmptup, - fselect->fieldnum, + fieldnum, tupDesc, isNull); return result; @@ -2948,15 +3091,8 @@ ExecInitExpr(Expr *node, PlanState *parent) switch (nodeTag(node)) { case T_Var: - { - Var *var = (Var *) node; - - state = (ExprState *) makeNode(ExprState); - if (var->varattno != InvalidAttrNumber) - state->evalfunc = ExecEvalVar; - else - state->evalfunc = ExecEvalWholeRowVar; - } + state = (ExprState *) makeNode(ExprState); + state->evalfunc = ExecEvalVar; break; case T_Const: state = (ExprState *) makeNode(ExprState); diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index 45ef7c3ef82..1154b785447 100644 --- a/src/backend/executor/execScan.c +++ b/src/backend/executor/execScan.c @@ -12,7 +12,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.37.2.1 2007/01/24 01:25:56 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.37.2.2 2007/02/02 00:07:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -187,7 +187,8 @@ ExecAssignScanProjectionInfo(ScanState *node) node->ss_ScanTupleSlot->tts_tupleDescriptor)) node->ps.ps_ProjInfo = NULL; else - ExecAssignProjectionInfo(&node->ps); + ExecAssignProjectionInfo(&node->ps, + node->ss_ScanTupleSlot->tts_tupleDescriptor); } static bool @@ -209,6 +210,7 @@ tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr; if (!var || !IsA(var, Var)) return false; /* tlist item not a Var */ + /* if these Asserts fail, planner messed up */ Assert(var->varno == varno); Assert(var->varlevelsup == 0); if (var->varattno != attrno) @@ -225,8 +227,10 @@ tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc * projection steps just to convert from specific typmod to typmod -1, * which is pretty silly. */ - Assert(var->vartype == att_tup->atttypid); - Assert(var->vartypmod == att_tup->atttypmod || var->vartypmod == -1); + if (var->vartype != att_tup->atttypid || + (var->vartypmod != att_tup->atttypmod && + var->vartypmod != -1)) + return false; /* type mismatch */ tlist_item = lnext(tlist_item); } diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 5983249bba2..a2d3543ced0 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.126.2.3 2005/11/23 20:28:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.126.2.4 2007/02/02 00:07:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -483,12 +483,19 @@ ExecGetResultType(PlanState *planstate) * econtext, and storing the result into the tuple slot. (Caller must have * ensured that tuple slot has a descriptor matching the tlist!) Note that * the given tlist should be a list of ExprState nodes, not Expr nodes. + * + * inputDesc can be NULL, but if it is not, we check to see whether simple + * Vars in the tlist match the descriptor. It is important to provide + * inputDesc for relation-scan plan nodes, as a cross check that the relation + * hasn't been changed since the plan was made. At higher levels of a plan, + * there is no need to recheck. * ---------------- */ ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, - TupleTableSlot *slot) + TupleTableSlot *slot, + TupleDesc inputDesc) { ProjectionInfo *projInfo = makeNode(ProjectionInfo); int len; @@ -503,14 +510,17 @@ ExecBuildProjectionInfo(List *targetList, /* * Determine whether the target list consists entirely of simple Var - * references (ie, references to non-system attributes). If so, we can - * use the simpler ExecVariableList instead of ExecTargetList. + * references (ie, references to non-system attributes) that match the + * input. If so, we can use the simpler ExecVariableList instead of + * ExecTargetList. (Note: if there is a type mismatch then ExecEvalVar + * will probably throw an error at runtime, but we leave that to it.) */ isVarList = true; foreach(tl, targetList) { GenericExprState *gstate = (GenericExprState *) lfirst(tl); Var *variable = (Var *) gstate->arg->expr; + Form_pg_attribute attr; if (variable == NULL || !IsA(variable, Var) || @@ -519,6 +529,22 @@ ExecBuildProjectionInfo(List *targetList, isVarList = false; break; } + if (!inputDesc) + continue; /* can't check type, assume OK */ + if (variable->varattno > inputDesc->natts) + { + isVarList = false; + break; + } + attr = inputDesc->attrs[variable->varattno - 1]; + if (attr->attisdropped || + variable->vartype != attr->atttypid || + (variable->vartypmod != attr->atttypmod && + variable->vartypmod != -1)) + { + isVarList = false; + break; + } } projInfo->pi_isVarList = isVarList; @@ -594,15 +620,20 @@ ExecBuildProjectionInfo(List *targetList, * ExecAssignProjectionInfo * * forms the projection information from the node's targetlist + * + * Notes for inputDesc are same as for ExecBuildProjectionInfo: supply it + * for a relation-scan node, can pass NULL for upper-level nodes * ---------------- */ void -ExecAssignProjectionInfo(PlanState *planstate) +ExecAssignProjectionInfo(PlanState *planstate, + TupleDesc inputDesc) { planstate->ps_ProjInfo = ExecBuildProjectionInfo(planstate->targetlist, planstate->ps_ExprContext, - planstate->ps_ResultTupleSlot); + planstate->ps_ResultTupleSlot, + inputDesc); } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 014219a1051..c5c9aed7e78 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -61,7 +61,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.135.2.1 2005/11/22 18:23:09 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.135.2.2 2007/02/02 00:07:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1120,7 +1120,7 @@ ExecInitAgg(Agg *node, EState *estate) * Initialize result tuple type and projection info. */ ExecAssignResultTypeFromTL(&aggstate->ss.ps); - ExecAssignProjectionInfo(&aggstate->ss.ps); + ExecAssignProjectionInfo(&aggstate->ss.ps, NULL); /* * get the count of aggregates in targetlist and quals diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c index 91a08add4d9..0a691b61231 100644 --- a/src/backend/executor/nodeGroup.c +++ b/src/backend/executor/nodeGroup.c @@ -15,7 +15,7 @@ * locate group boundaries. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.62 2005/10/15 02:49:17 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.62.2.1 2007/02/02 00:07:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -203,7 +203,7 @@ ExecInitGroup(Group *node, EState *estate) * Initialize result tuple type and projection info. */ ExecAssignResultTypeFromTL(&grpstate->ss.ps); - ExecAssignProjectionInfo(&grpstate->ss.ps); + ExecAssignProjectionInfo(&grpstate->ss.ps, NULL); /* * Precompute fmgr lookup data for inner loop diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 4b82c7fcea8..22a13288661 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.75.2.3 2005/11/28 23:46:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.75.2.4 2007/02/02 00:07:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -426,7 +426,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate) * initialize tuple type and projection info */ ExecAssignResultTypeFromTL(&hjstate->js.ps); - ExecAssignProjectionInfo(&hjstate->js.ps); + ExecAssignProjectionInfo(&hjstate->js.ps, NULL); ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot, ExecGetResultType(outerPlanState(hjstate)), diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index dfa3c2e29af..41b1e15a6a2 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.75.2.2 2006/03/17 19:38:20 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.75.2.3 2007/02/02 00:07:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1606,7 +1606,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate) * initialize tuple type and projection info */ ExecAssignResultTypeFromTL(&mergestate->js.ps); - ExecAssignProjectionInfo(&mergestate->js.ps); + ExecAssignProjectionInfo(&mergestate->js.ps, NULL); /* * preprocess the merge clauses diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index 24f3621bb99..16bf1b7934f 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.39.2.1 2005/11/22 18:23:09 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.39.2.2 2007/02/02 00:07:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -339,7 +339,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate) * initialize tuple type and projection info */ ExecAssignResultTypeFromTL(&nlstate->js.ps); - ExecAssignProjectionInfo(&nlstate->js.ps); + ExecAssignProjectionInfo(&nlstate->js.ps, NULL); /* * finally, wipe the current outer tuple clean. diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c index 952745783b3..6f29d745079 100644 --- a/src/backend/executor/nodeResult.c +++ b/src/backend/executor/nodeResult.c @@ -38,7 +38,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeResult.c,v 1.32.2.1 2006/12/26 19:27:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeResult.c,v 1.32.2.2 2007/02/02 00:07:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -231,7 +231,7 @@ ExecInitResult(Result *node, EState *estate) * initialize tuple type and projection info */ ExecAssignResultTypeFromTL(&resstate->ps); - ExecAssignProjectionInfo(&resstate->ps); + ExecAssignProjectionInfo(&resstate->ps, NULL); return resstate; } diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 061ca12eda4..6ee5e13a1dc 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.70.2.1 2005/11/22 18:23:09 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.70.2.2 2007/02/02 00:07:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -882,14 +882,16 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) ExecSetSlotDescriptor(slot, tupDesc, true); node->projLeft = ExecBuildProjectionInfo(lefttlist, NULL, - slot); + slot, + NULL); tupDesc = ExecTypeFromTL(rightptlist, false); slot = ExecAllocTableSlot(tupTable); ExecSetSlotDescriptor(slot, tupDesc, true); node->projRight = ExecBuildProjectionInfo(righttlist, node->innerecontext, - slot); + slot, + NULL); } } diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 7e14801184d..8beaf7706f7 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.120.2.2 2006/01/12 21:49:07 tgl Exp $ + * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.120.2.3 2007/02/02 00:07:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -222,8 +222,10 @@ extern void ExecAssignResultTypeFromTL(PlanState *planstate); extern TupleDesc ExecGetResultType(PlanState *planstate); extern ProjectionInfo *ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, - TupleTableSlot *slot); -extern void ExecAssignProjectionInfo(PlanState *planstate); + TupleTableSlot *slot, + TupleDesc inputDesc); +extern void ExecAssignProjectionInfo(PlanState *planstate, + TupleDesc inputDesc); extern void ExecFreeExprContext(PlanState *planstate); extern TupleDesc ExecGetScanType(ScanState *scanstate); extern void ExecAssignScanType(ScanState *scanstate, |