aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/tablecmds.c57
-rw-r--r--src/backend/executor/execMain.c5
-rw-r--r--src/backend/executor/execQual.c244
-rw-r--r--src/backend/executor/execScan.c12
-rw-r--r--src/backend/executor/execUtils.c43
-rw-r--r--src/backend/executor/nodeAgg.c4
-rw-r--r--src/backend/executor/nodeGroup.c4
-rw-r--r--src/backend/executor/nodeHashjoin.c4
-rw-r--r--src/backend/executor/nodeMergejoin.c4
-rw-r--r--src/backend/executor/nodeNestloop.c4
-rw-r--r--src/backend/executor/nodeResult.c4
-rw-r--r--src/backend/executor/nodeSubplan.c8
-rw-r--r--src/include/executor/executor.h8
13 files changed, 311 insertions, 90 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 0aaf47a19dc..7e347b27f0e 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.206.2.1 2007/01/25 04:17:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.206.2.2 2007/02/02 00:07:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1950,22 +1950,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
@@ -2915,6 +2940,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);
}
@@ -2946,6 +2977,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);
}
@@ -3745,6 +3782,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/execMain.c b/src/backend/executor/execMain.c
index 1d6284c357c..804ba96aacc 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.280.2.1 2006/12/26 21:37:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.280.2.2 2007/02/02 00:07:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -770,7 +770,8 @@ InitPlan(QueryDesc *queryDesc, int eflags)
rliststate = (List *) ExecInitExpr((Expr *) rlist, planstate);
resultRelInfo->ri_projectReturning =
- ExecBuildProjectionInfo(rliststate, econtext, slot);
+ ExecBuildProjectionInfo(rliststate, econtext, slot,
+ resultRelInfo->ri_RelationDesc->rd_att);
resultRelInfo++;
}
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 1dbef5f15c9..ab375a3ea36 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.199 2006/11/17 16:46:27 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.199.2.1 2007/02/02 00:07:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -63,6 +63,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,
@@ -422,6 +424,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
@@ -436,7 +442,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
@@ -463,35 +469,170 @@ 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)));
+ }
+
+ 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);
}
@@ -499,10 +640,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
@@ -510,7 +647,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;
@@ -519,16 +656,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;
@@ -544,9 +671,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)
{
@@ -555,9 +679,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);
}
@@ -2985,12 +3106,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);
@@ -3008,6 +3131,28 @@ ExecEvalFieldSelect(FieldSelectState *fstate,
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
@@ -3019,7 +3164,7 @@ ExecEvalFieldSelect(FieldSelectState *fstate,
tmptup.t_data = tuple;
result = heap_getattr(&tmptup,
- fselect->fieldnum,
+ fieldnum,
tupDesc,
isNull);
return result;
@@ -3206,15 +3351,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 e83e2b827c1..66936050030 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.38.2.1 2007/01/24 01:25:51 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.38.2.2 2007/02/02 00:07:27 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 7f34d9471d8..909d9b198d0 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.140.2.1 2006/12/26 21:37:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.140.2.2 2007/02/02 00:07:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -578,12 +578,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;
@@ -598,14 +605,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) ||
@@ -614,6 +624,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;
@@ -689,15 +715,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 44609bb40b7..2c276b33c96 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.146 2006/10/04 00:29:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.146.2.1 2007/02/02 00:07:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1243,7 +1243,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
* 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 a64b5b5b19d..f094a8ab28f 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.65 2006/07/14 14:52:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.65.2.1 2007/02/02 00:07:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -205,7 +205,7 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
* 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 14fd016e5a5..a664e6e0a8a 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.85 2006/10/04 00:29:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.85.2.1 2007/02/02 00:07:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -431,7 +431,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
* 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 8a9f6fe2300..9b809ff2b5d 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.82 2006/10/04 00:29:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.82.2.1 2007/02/02 00:07:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1607,7 +1607,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
* 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 1c0a696f533..014f7bb795d 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.43 2006/10/04 00:29:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.43.2.1 2007/02/02 00:07:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -349,7 +349,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
* 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 2deef985f4d..a0c18cf3658 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.34.2.1 2006/12/26 19:26:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeResult.c,v 1.34.2.2 2007/02/02 00:07:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -235,7 +235,7 @@ ExecInitResult(Result *node, EState *estate, int eflags)
* 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 5d945e9a464..9b751b7c305 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.80.2.1 2006/12/26 21:37:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.80.2.2 2007/02/02 00:07:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -862,14 +862,16 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
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);
}
}
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 22d4b0e2660..60e3150c999 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.130.2.1 2006/12/26 21:37:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.130.2.2 2007/02/02 00:07:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -257,8 +257,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, TupleDesc tupDesc);