*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.212 2007/01/25 04:35:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.213 2007/02/02 00:07:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
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
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);
}
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);
}
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 */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.285 2007/01/25 04:35:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.286 2007/02/02 00:07:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
rliststate = (List *) ExecInitExpr((Expr *) rlist, planstate);
resultRelInfo->ri_projectReturning =
- ExecBuildProjectionInfo(rliststate, econtext, slot);
+ ExecBuildProjectionInfo(rliststate, econtext, slot,
+ resultRelInfo->ri_RelationDesc->rd_att);
resultRelInfo++;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.210 2007/02/01 19:10:26 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.211 2007/02/02 00:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
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,
*
* 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
*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
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)));
+ }
+
+ ReleaseTupleDesc(var_tupdesc);
+ }
+
+ /* Skip the checking on future executions of node */
+ exprstate->evalfunc = ExecEvalWholeRowVar;
+
+ /* Fetch the value */
+ return ExecEvalWholeRowVar(exprstate, econtext, isNull, isDone);
}
-#endif /* USE_ASSERT_CHECKING */
+}
+/* ----------------------------------------------------------------
+ * 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;
+ }
+
+ attnum = variable->varattno;
+
+ /* Fetch the value from the slot */
return slot_getattr(slot, attnum, isNull);
}
* 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
bool *isNull, ExprDoneCond *isDone)
{
Var *variable = (Var *) exprstate->expr;
- TupleTableSlot *slot;
+ TupleTableSlot *slot = econtext->ecxt_scantuple;
HeapTuple tuple;
TupleDesc tupleDesc;
HeapTupleHeader dtuple;
*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;
/*
* 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)
{
}
else
{
- if (tupleDesc->tdtypeid == RECORDOID &&
- tupleDesc->tdtypmod < 0)
- assign_record_type_typmod(tupleDesc);
HeapTupleHeaderSetTypeId(dtuple, tupleDesc->tdtypeid);
HeapTupleHeaderSetTypMod(dtuple, tupleDesc->tdtypmod);
}
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);
tupDesc = get_cached_rowtype(tupType, tupTypmod,
&fstate->argdesc, econtext);
+ /* 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
tmptup.t_data = tuple;
result = heap_getattr(&tmptup,
- fselect->fieldnum,
+ fieldnum,
tupDesc,
isNull);
return result;
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);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.40 2007/01/24 01:25:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.41 2007/02/02 00:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
node->ss_ScanTupleSlot->tts_tupleDescriptor))
node->ps.ps_ProjInfo = NULL;
else
- ExecAssignProjectionInfo(&node->ps);
+ ExecAssignProjectionInfo(&node->ps,
+ node->ss_ScanTupleSlot->tts_tupleDescriptor);
}
static bool
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)
* 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);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.142 2007/01/05 22:19:27 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.143 2007/02/02 00:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* 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;
/*
* 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) ||
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;
* 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);
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.149 2007/01/10 18:06:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.150 2007/02/02 00:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* 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
* locate group boundaries.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.67 2007/01/10 18:06:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.68 2007/02/02 00:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* 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
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.88 2007/01/30 01:33:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.89 2007/02/02 00:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* 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)));
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.86 2007/01/11 17:19:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.87 2007/02/02 00:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* initialize tuple type and projection info
*/
ExecAssignResultTypeFromTL(&mergestate->js.ps);
- ExecAssignProjectionInfo(&mergestate->js.ps);
+ ExecAssignProjectionInfo(&mergestate->js.ps, NULL);
/*
* preprocess the merge clauses
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.44 2007/01/05 22:19:28 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.45 2007/02/02 00:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* 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.
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeResult.c,v 1.36 2007/01/05 22:19:28 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeResult.c,v 1.37 2007/02/02 00:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* initialize tuple type and projection info
*/
ExecAssignResultTypeFromTL(&resstate->ps);
- ExecAssignProjectionInfo(&resstate->ps);
+ ExecAssignProjectionInfo(&resstate->ps, NULL);
return resstate;
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.83 2007/01/30 01:33:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.84 2007/02/02 00:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
ExecSetSlotDescriptor(slot, tupDesc);
node->projLeft = ExecBuildProjectionInfo(lefttlist,
NULL,
- slot);
+ slot,
+ NULL);
tupDesc = ExecTypeFromTL(rightptlist, false);
slot = ExecAllocTableSlot(tupTable);
ExecSetSlotDescriptor(slot, tupDesc);
node->projRight = ExecBuildProjectionInfo(righttlist,
node->innerecontext,
- slot);
+ slot,
+ NULL);
}
}
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.134 2007/01/10 18:06:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.135 2007/02/02 00:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
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, TupleDesc tupDesc);