Commit 5413eef8 authored by Tom Lane's avatar Tom Lane

Repair failure to check that a table is still compatible with a previously

made query plan.  Use of ALTER COLUMN TYPE creates a hazard for cached
query plans: they could contain Vars that claim a column has a different
type than it now has.  Fix this by checking during plan startup that Vars
at relation scan level match the current relation tuple descriptor.  Since
at that point we already have at least AccessShareLock, we can be sure the
column type will not change underneath us later in the query.  However,
since a backend's locks do not conflict against itself, there is still a
hole for an attacker to exploit: he could try to execute ALTER COLUMN TYPE
while a query is in progress in the current backend.  Seal that hole by
rejecting ALTER TABLE whenever the target relation is already open in
the current backend.

This is a significant security hole: not only can one trivially crash the
backend, but with appropriate misuse of pass-by-reference datatypes it is
possible to read out arbitrary locations in the server process's memory,
which could allow retrieving database content the user should not be able
to see.  Our thanks to Jeff Trout for the initial report.

Security: CVE-2007-0556
parent f8eb75b6
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1964,22 +1964,47 @@ update_ri_trigger_args(Oid relid, ...@@ -1964,22 +1964,47 @@ update_ri_trigger_args(Oid relid,
void void
AlterTable(AlterTableStmt *stmt) AlterTable(AlterTableStmt *stmt)
{ {
ATController(relation_openrv(stmt->relation, AccessExclusiveLock), Relation rel = relation_openrv(stmt->relation, AccessExclusiveLock);
stmt->cmds, int expected_refcnt;
interpretInhOption(stmt->relation->inhOpt));
/*
* 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 * AlterTableInternal
* *
* ALTER TABLE with target specified by OID * 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 void
AlterTableInternal(Oid relid, List *cmds, bool recurse) AlterTableInternal(Oid relid, List *cmds, bool recurse)
{ {
ATController(relation_open(relid, AccessExclusiveLock), Relation rel = relation_open(relid, AccessExclusiveLock);
cmds,
recurse); ATController(rel, cmds, recurse);
} }
static void static void
...@@ -2929,6 +2954,12 @@ ATSimpleRecursion(List **wqueue, Relation rel, ...@@ -2929,6 +2954,12 @@ ATSimpleRecursion(List **wqueue, Relation rel,
if (childrelid == relid) if (childrelid == relid)
continue; continue;
childrel = relation_open(childrelid, AccessExclusiveLock); 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); ATPrepCmd(wqueue, childrel, cmd, false, true);
relation_close(childrel, NoLock); relation_close(childrel, NoLock);
} }
...@@ -2960,6 +2991,12 @@ ATOneLevelRecursion(List **wqueue, Relation rel, ...@@ -2960,6 +2991,12 @@ ATOneLevelRecursion(List **wqueue, Relation rel,
Relation childrel; Relation childrel;
childrel = relation_open(childrelid, AccessExclusiveLock); 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); ATPrepCmd(wqueue, childrel, cmd, true, true);
relation_close(childrel, NoLock); relation_close(childrel, NoLock);
} }
...@@ -3765,6 +3802,12 @@ ATExecDropColumn(Relation rel, const char *colName, ...@@ -3765,6 +3802,12 @@ ATExecDropColumn(Relation rel, const char *colName,
Form_pg_attribute childatt; Form_pg_attribute childatt;
childrel = heap_open(childrelid, AccessExclusiveLock); 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); tuple = SearchSysCacheCopyAttName(childrelid, colName);
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -804,7 +804,8 @@ InitPlan(QueryDesc *queryDesc, int eflags) ...@@ -804,7 +804,8 @@ InitPlan(QueryDesc *queryDesc, int eflags)
rliststate = (List *) ExecInitExpr((Expr *) rlist, planstate); rliststate = (List *) ExecInitExpr((Expr *) rlist, planstate);
resultRelInfo->ri_projectReturning = resultRelInfo->ri_projectReturning =
ExecBuildProjectionInfo(rliststate, econtext, slot); ExecBuildProjectionInfo(rliststate, econtext, slot,
resultRelInfo->ri_RelationDesc->rd_att);
resultRelInfo++; resultRelInfo++;
} }
......
This diff is collapsed.
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -187,7 +187,8 @@ ExecAssignScanProjectionInfo(ScanState *node) ...@@ -187,7 +187,8 @@ ExecAssignScanProjectionInfo(ScanState *node)
node->ss_ScanTupleSlot->tts_tupleDescriptor)) node->ss_ScanTupleSlot->tts_tupleDescriptor))
node->ps.ps_ProjInfo = NULL; node->ps.ps_ProjInfo = NULL;
else else
ExecAssignProjectionInfo(&node->ps); ExecAssignProjectionInfo(&node->ps,
node->ss_ScanTupleSlot->tts_tupleDescriptor);
} }
static bool static bool
...@@ -209,6 +210,7 @@ tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc ...@@ -209,6 +210,7 @@ tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc
var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr; var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
if (!var || !IsA(var, Var)) if (!var || !IsA(var, Var))
return false; /* tlist item not a Var */ return false; /* tlist item not a Var */
/* if these Asserts fail, planner messed up */
Assert(var->varno == varno); Assert(var->varno == varno);
Assert(var->varlevelsup == 0); Assert(var->varlevelsup == 0);
if (var->varattno != attrno) if (var->varattno != attrno)
...@@ -225,8 +227,10 @@ tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc ...@@ -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, * projection steps just to convert from specific typmod to typmod -1,
* which is pretty silly. * which is pretty silly.
*/ */
Assert(var->vartype == att_tup->atttypid); if (var->vartype != att_tup->atttypid ||
Assert(var->vartypmod == att_tup->atttypmod || var->vartypmod == -1); (var->vartypmod != att_tup->atttypmod &&
var->vartypmod != -1))
return false; /* type mismatch */
tlist_item = lnext(tlist_item); tlist_item = lnext(tlist_item);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -578,12 +578,19 @@ ExecGetResultType(PlanState *planstate) ...@@ -578,12 +578,19 @@ ExecGetResultType(PlanState *planstate)
* econtext, and storing the result into the tuple slot. (Caller must have * econtext, and storing the result into the tuple slot. (Caller must have
* ensured that tuple slot has a descriptor matching the tlist!) Note that * 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. * 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 * ProjectionInfo *
ExecBuildProjectionInfo(List *targetList, ExecBuildProjectionInfo(List *targetList,
ExprContext *econtext, ExprContext *econtext,
TupleTableSlot *slot) TupleTableSlot *slot,
TupleDesc inputDesc)
{ {
ProjectionInfo *projInfo = makeNode(ProjectionInfo); ProjectionInfo *projInfo = makeNode(ProjectionInfo);
int len; int len;
...@@ -598,14 +605,17 @@ ExecBuildProjectionInfo(List *targetList, ...@@ -598,14 +605,17 @@ ExecBuildProjectionInfo(List *targetList,
/* /*
* Determine whether the target list consists entirely of simple Var * Determine whether the target list consists entirely of simple Var
* references (ie, references to non-system attributes). If so, we can * references (ie, references to non-system attributes) that match the
* use the simpler ExecVariableList instead of ExecTargetList. * 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; isVarList = true;
foreach(tl, targetList) foreach(tl, targetList)
{ {
GenericExprState *gstate = (GenericExprState *) lfirst(tl); GenericExprState *gstate = (GenericExprState *) lfirst(tl);
Var *variable = (Var *) gstate->arg->expr; Var *variable = (Var *) gstate->arg->expr;
Form_pg_attribute attr;
if (variable == NULL || if (variable == NULL ||
!IsA(variable, Var) || !IsA(variable, Var) ||
...@@ -614,6 +624,22 @@ ExecBuildProjectionInfo(List *targetList, ...@@ -614,6 +624,22 @@ ExecBuildProjectionInfo(List *targetList,
isVarList = false; isVarList = false;
break; 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; projInfo->pi_isVarList = isVarList;
...@@ -689,15 +715,20 @@ ExecBuildProjectionInfo(List *targetList, ...@@ -689,15 +715,20 @@ ExecBuildProjectionInfo(List *targetList,
* ExecAssignProjectionInfo * ExecAssignProjectionInfo
* *
* forms the projection information from the node's targetlist * 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 void
ExecAssignProjectionInfo(PlanState *planstate) ExecAssignProjectionInfo(PlanState *planstate,
TupleDesc inputDesc)
{ {
planstate->ps_ProjInfo = planstate->ps_ProjInfo =
ExecBuildProjectionInfo(planstate->targetlist, ExecBuildProjectionInfo(planstate->targetlist,
planstate->ps_ExprContext, planstate->ps_ExprContext,
planstate->ps_ResultTupleSlot); planstate->ps_ResultTupleSlot,
inputDesc);
} }
......
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1243,7 +1243,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) ...@@ -1243,7 +1243,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
* Initialize result tuple type and projection info. * Initialize result tuple type and projection info.
*/ */
ExecAssignResultTypeFromTL(&aggstate->ss.ps); ExecAssignResultTypeFromTL(&aggstate->ss.ps);
ExecAssignProjectionInfo(&aggstate->ss.ps); ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
/* /*
* get the count of aggregates in targetlist and quals * get the count of aggregates in targetlist and quals
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* locate group boundaries. * locate group boundaries.
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -205,7 +205,7 @@ ExecInitGroup(Group *node, EState *estate, int eflags) ...@@ -205,7 +205,7 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
* Initialize result tuple type and projection info. * Initialize result tuple type and projection info.
*/ */
ExecAssignResultTypeFromTL(&grpstate->ss.ps); ExecAssignResultTypeFromTL(&grpstate->ss.ps);
ExecAssignProjectionInfo(&grpstate->ss.ps); ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
/* /*
* Precompute fmgr lookup data for inner loop * Precompute fmgr lookup data for inner loop
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -431,7 +431,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) ...@@ -431,7 +431,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
* initialize tuple type and projection info * initialize tuple type and projection info
*/ */
ExecAssignResultTypeFromTL(&hjstate->js.ps); ExecAssignResultTypeFromTL(&hjstate->js.ps);
ExecAssignProjectionInfo(&hjstate->js.ps); ExecAssignProjectionInfo(&hjstate->js.ps, NULL);
ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot, ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot,
ExecGetResultType(outerPlanState(hjstate))); ExecGetResultType(outerPlanState(hjstate)));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1493,7 +1493,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) ...@@ -1493,7 +1493,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
* initialize tuple type and projection info * initialize tuple type and projection info
*/ */
ExecAssignResultTypeFromTL(&mergestate->js.ps); ExecAssignResultTypeFromTL(&mergestate->js.ps);
ExecAssignProjectionInfo(&mergestate->js.ps); ExecAssignProjectionInfo(&mergestate->js.ps, NULL);
/* /*
* preprocess the merge clauses * preprocess the merge clauses
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -349,7 +349,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags) ...@@ -349,7 +349,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
* initialize tuple type and projection info * initialize tuple type and projection info
*/ */
ExecAssignResultTypeFromTL(&nlstate->js.ps); ExecAssignResultTypeFromTL(&nlstate->js.ps);
ExecAssignProjectionInfo(&nlstate->js.ps); ExecAssignProjectionInfo(&nlstate->js.ps, NULL);
/* /*
* finally, wipe the current outer tuple clean. * finally, wipe the current outer tuple clean.
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -235,7 +235,7 @@ ExecInitResult(Result *node, EState *estate, int eflags) ...@@ -235,7 +235,7 @@ ExecInitResult(Result *node, EState *estate, int eflags)
* initialize tuple type and projection info * initialize tuple type and projection info
*/ */
ExecAssignResultTypeFromTL(&resstate->ps); ExecAssignResultTypeFromTL(&resstate->ps);
ExecAssignProjectionInfo(&resstate->ps); ExecAssignProjectionInfo(&resstate->ps, NULL);
return resstate; return resstate;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -865,14 +865,16 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags) ...@@ -865,14 +865,16 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
ExecSetSlotDescriptor(slot, tupDesc); ExecSetSlotDescriptor(slot, tupDesc);
node->projLeft = ExecBuildProjectionInfo(lefttlist, node->projLeft = ExecBuildProjectionInfo(lefttlist,
NULL, NULL,
slot); slot,
NULL);
tupDesc = ExecTypeFromTL(rightptlist, false); tupDesc = ExecTypeFromTL(rightptlist, false);
slot = ExecAllocTableSlot(tupTable); slot = ExecAllocTableSlot(tupTable);
ExecSetSlotDescriptor(slot, tupDesc); ExecSetSlotDescriptor(slot, tupDesc);
node->projRight = ExecBuildProjectionInfo(righttlist, node->projRight = ExecBuildProjectionInfo(righttlist,
node->innerecontext, node->innerecontext,
slot); slot,
NULL);
} }
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -257,8 +257,10 @@ extern void ExecAssignResultTypeFromTL(PlanState *planstate); ...@@ -257,8 +257,10 @@ extern void ExecAssignResultTypeFromTL(PlanState *planstate);
extern TupleDesc ExecGetResultType(PlanState *planstate); extern TupleDesc ExecGetResultType(PlanState *planstate);
extern ProjectionInfo *ExecBuildProjectionInfo(List *targetList, extern ProjectionInfo *ExecBuildProjectionInfo(List *targetList,
ExprContext *econtext, ExprContext *econtext,
TupleTableSlot *slot); TupleTableSlot *slot,
extern void ExecAssignProjectionInfo(PlanState *planstate); TupleDesc inputDesc);
extern void ExecAssignProjectionInfo(PlanState *planstate,
TupleDesc inputDesc);
extern void ExecFreeExprContext(PlanState *planstate); extern void ExecFreeExprContext(PlanState *planstate);
extern TupleDesc ExecGetScanType(ScanState *scanstate); extern TupleDesc ExecGetScanType(ScanState *scanstate);
extern void ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc); extern void ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment