Revise executor APIs so that all per-query state structure is built in
a per-query memory context created by CreateExecutorState --- and destroyed by FreeExecutorState. This provides a final solution to the longstanding problem of memory leaked by various ExecEndNode calls.
This commit is contained in:
parent
90b3a0b6fd
commit
5bab36e9f6
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.146 2002/12/13 19:45:45 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.147 2002/12/15 16:17:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1143,8 +1143,7 @@ index_register(Oid heap,
|
||||||
/* predicate will likely be null, but may as well copy it */
|
/* predicate will likely be null, but may as well copy it */
|
||||||
newind->il_info->ii_Predicate = (List *)
|
newind->il_info->ii_Predicate = (List *)
|
||||||
copyObject(indexInfo->ii_Predicate);
|
copyObject(indexInfo->ii_Predicate);
|
||||||
newind->il_info->ii_PredicateState = (List *)
|
newind->il_info->ii_PredicateState = NIL;
|
||||||
ExecInitExpr((Expr *) newind->il_info->ii_Predicate, NULL);
|
|
||||||
|
|
||||||
newind->il_next = ILHead;
|
newind->il_next = ILHead;
|
||||||
ILHead = newind;
|
ILHead = newind;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.207 2002/12/13 19:45:47 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.208 2002/12/15 16:17:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
|
@ -41,7 +41,6 @@
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
#include "optimizer/planmain.h"
|
|
||||||
#include "optimizer/prep.h"
|
#include "optimizer/prep.h"
|
||||||
#include "parser/parse_func.h"
|
#include "parser/parse_func.h"
|
||||||
#include "storage/sinval.h"
|
#include "storage/sinval.h"
|
||||||
|
@ -912,7 +911,6 @@ BuildIndexInfo(Form_pg_index indexStruct)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If partial index, convert predicate into expression nodetree
|
* If partial index, convert predicate into expression nodetree
|
||||||
* and prepare an execution state nodetree for it
|
|
||||||
*/
|
*/
|
||||||
if (VARSIZE(&indexStruct->indpred) > VARHDRSZ)
|
if (VARSIZE(&indexStruct->indpred) > VARHDRSZ)
|
||||||
{
|
{
|
||||||
|
@ -921,9 +919,7 @@ BuildIndexInfo(Form_pg_index indexStruct)
|
||||||
predString = DatumGetCString(DirectFunctionCall1(textout,
|
predString = DatumGetCString(DirectFunctionCall1(textout,
|
||||||
PointerGetDatum(&indexStruct->indpred)));
|
PointerGetDatum(&indexStruct->indpred)));
|
||||||
ii->ii_Predicate = stringToNode(predString);
|
ii->ii_Predicate = stringToNode(predString);
|
||||||
fix_opfuncids((Node *) ii->ii_Predicate);
|
ii->ii_PredicateState = NIL;
|
||||||
ii->ii_PredicateState = (List *)
|
|
||||||
ExecInitExpr((Expr *) ii->ii_Predicate, NULL);
|
|
||||||
pfree(predString);
|
pfree(predString);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1489,9 +1485,10 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||||
Datum attdata[INDEX_MAX_KEYS];
|
Datum attdata[INDEX_MAX_KEYS];
|
||||||
char nulls[INDEX_MAX_KEYS];
|
char nulls[INDEX_MAX_KEYS];
|
||||||
double reltuples;
|
double reltuples;
|
||||||
List *predicate = indexInfo->ii_PredicateState;
|
List *predicate;
|
||||||
TupleTable tupleTable;
|
TupleTable tupleTable;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
|
EState *estate;
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
Snapshot snapshot;
|
Snapshot snapshot;
|
||||||
TransactionId OldestXmin;
|
TransactionId OldestXmin;
|
||||||
|
@ -1503,28 +1500,42 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||||
|
|
||||||
heapDescriptor = RelationGetDescr(heapRelation);
|
heapDescriptor = RelationGetDescr(heapRelation);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need an EState for evaluation of functional-index functions
|
||||||
|
* and partial-index predicates.
|
||||||
|
*/
|
||||||
|
estate = CreateExecutorState();
|
||||||
|
econtext = GetPerTupleExprContext(estate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a predicate (partial) index, we will need to evaluate
|
* If this is a predicate (partial) index, we will need to evaluate
|
||||||
* the predicate using ExecQual, which requires the current tuple to
|
* the predicate using ExecQual, which requires the current tuple to
|
||||||
* be in a slot of a TupleTable. In addition, ExecQual must have an
|
* be in a slot of a TupleTable.
|
||||||
* ExprContext referring to that slot. Here, we initialize dummy
|
|
||||||
* TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
|
|
||||||
*
|
|
||||||
* We construct the ExprContext anyway since we need a per-tuple
|
|
||||||
* temporary memory context for function evaluation -- tgl July 00
|
|
||||||
*/
|
*/
|
||||||
if (predicate != NIL)
|
if (indexInfo->ii_Predicate != NIL)
|
||||||
{
|
{
|
||||||
tupleTable = ExecCreateTupleTable(1);
|
tupleTable = ExecCreateTupleTable(1);
|
||||||
slot = ExecAllocTableSlot(tupleTable);
|
slot = ExecAllocTableSlot(tupleTable);
|
||||||
ExecSetSlotDescriptor(slot, heapDescriptor, false);
|
ExecSetSlotDescriptor(slot, heapDescriptor, false);
|
||||||
|
|
||||||
|
/* Arrange for econtext's scan tuple to be the tuple under test */
|
||||||
|
econtext->ecxt_scantuple = slot;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up execution state for predicate. Note: we mustn't attempt to
|
||||||
|
* cache this in the indexInfo, since we're building it in a transient
|
||||||
|
* EState.
|
||||||
|
*/
|
||||||
|
predicate = (List *)
|
||||||
|
ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
|
||||||
|
estate);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tupleTable = NULL;
|
tupleTable = NULL;
|
||||||
slot = NULL;
|
slot = NULL;
|
||||||
|
predicate = NIL;
|
||||||
}
|
}
|
||||||
econtext = MakeExprContext(slot, TransactionCommandContext);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ok, begin our scan of the base relation. We use SnapshotAny
|
* Ok, begin our scan of the base relation. We use SnapshotAny
|
||||||
|
@ -1687,9 +1698,10 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||||
|
|
||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
|
|
||||||
if (predicate != NIL)
|
if (tupleTable)
|
||||||
ExecDropTupleTable(tupleTable, true);
|
ExecDropTupleTable(tupleTable, true);
|
||||||
FreeExprContext(econtext);
|
|
||||||
|
FreeExecutorState(estate);
|
||||||
|
|
||||||
return reltuples;
|
return reltuples;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.186 2002/12/13 19:45:48 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.187 2002/12/15 16:17:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -35,7 +35,6 @@
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "optimizer/planmain.h"
|
|
||||||
#include "parser/parse_coerce.h"
|
#include "parser/parse_coerce.h"
|
||||||
#include "parser/parse_relation.h"
|
#include "parser/parse_relation.h"
|
||||||
#include "rewrite/rewriteHandler.h"
|
#include "rewrite/rewriteHandler.h"
|
||||||
|
@ -803,6 +802,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||||
slot = ExecAllocTableSlot(tupleTable);
|
slot = ExecAllocTableSlot(tupleTable);
|
||||||
ExecSetSlotDescriptor(slot, tupDesc, false);
|
ExecSetSlotDescriptor(slot, tupDesc, false);
|
||||||
|
|
||||||
|
econtext = GetPerTupleExprContext(estate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pick up the required catalog information for each attribute in the
|
* Pick up the required catalog information for each attribute in the
|
||||||
* relation, including the input function, the element type (to pass
|
* relation, including the input function, the element type (to pass
|
||||||
|
@ -841,8 +842,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||||
|
|
||||||
if (defexpr != NULL)
|
if (defexpr != NULL)
|
||||||
{
|
{
|
||||||
fix_opfuncids(defexpr);
|
defexprs[num_defaults] = ExecPrepareExpr((Expr *) defexpr,
|
||||||
defexprs[num_defaults] = ExecInitExpr((Expr *) defexpr, NULL);
|
estate);
|
||||||
defmap[num_defaults] = i;
|
defmap[num_defaults] = i;
|
||||||
num_defaults++;
|
num_defaults++;
|
||||||
}
|
}
|
||||||
|
@ -873,8 +874,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||||
/* check whether any constraints actually found */
|
/* check whether any constraints actually found */
|
||||||
if (node != (Node *) prm)
|
if (node != (Node *) prm)
|
||||||
{
|
{
|
||||||
fix_opfuncids(node);
|
constraintexprs[i] = ExecPrepareExpr((Expr *) node,
|
||||||
constraintexprs[i] = ExecInitExpr((Expr *) node, NULL);
|
estate);
|
||||||
hasConstraints = true;
|
hasConstraints = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -934,8 +935,6 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||||
copy_lineno = 0;
|
copy_lineno = 0;
|
||||||
fe_eof = false;
|
fe_eof = false;
|
||||||
|
|
||||||
econtext = GetPerTupleExprContext(estate);
|
|
||||||
|
|
||||||
/* Make room for a PARAM_EXEC value for domain constraint checks */
|
/* Make room for a PARAM_EXEC value for domain constraint checks */
|
||||||
if (hasConstraints)
|
if (hasConstraints)
|
||||||
econtext->ecxt_param_exec_vals = (ParamExecData *)
|
econtext->ecxt_param_exec_vals = (ParamExecData *)
|
||||||
|
@ -953,9 +952,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||||
/* Reset the per-tuple exprcontext */
|
/* Reset the per-tuple exprcontext */
|
||||||
ResetPerTupleExprContext(estate);
|
ResetPerTupleExprContext(estate);
|
||||||
|
|
||||||
/* Switch to and reset per-tuple memory context, too */
|
/* Switch into its memory context */
|
||||||
MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
||||||
MemoryContextReset(CurrentMemoryContext);
|
|
||||||
|
|
||||||
/* Initialize all values for row to NULL */
|
/* Initialize all values for row to NULL */
|
||||||
MemSet(values, 0, num_phys_attrs * sizeof(Datum));
|
MemSet(values, 0, num_phys_attrs * sizeof(Datum));
|
||||||
|
@ -1268,6 +1266,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||||
ExecDropTupleTable(tupleTable, true);
|
ExecDropTupleTable(tupleTable, true);
|
||||||
|
|
||||||
ExecCloseIndices(resultRelInfo);
|
ExecCloseIndices(resultRelInfo);
|
||||||
|
|
||||||
|
FreeExecutorState(estate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994-5, Regents of the University of California
|
* Portions Copyright (c) 1994-5, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.98 2002/12/14 00:17:50 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.99 2002/12/15 16:17:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -206,6 +206,8 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
|
||||||
gettimeofday(&starttime, NULL);
|
gettimeofday(&starttime, NULL);
|
||||||
|
|
||||||
ExecutorEnd(queryDesc);
|
ExecutorEnd(queryDesc);
|
||||||
|
FreeQueryDesc(queryDesc);
|
||||||
|
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
|
||||||
totaltime += elapsed_time(&starttime);
|
totaltime += elapsed_time(&starttime);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.94 2002/12/13 19:45:50 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.95 2002/12/15 16:17:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -27,7 +27,6 @@
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
#include "optimizer/planmain.h"
|
|
||||||
#include "optimizer/prep.h"
|
#include "optimizer/prep.h"
|
||||||
#include "parser/parsetree.h"
|
#include "parser/parsetree.h"
|
||||||
#include "parser/parse_coerce.h"
|
#include "parser/parse_coerce.h"
|
||||||
|
@ -163,7 +162,6 @@ DefineIndex(RangeVar *heapRelation,
|
||||||
if (predicate)
|
if (predicate)
|
||||||
{
|
{
|
||||||
cnfPred = canonicalize_qual((Expr *) copyObject(predicate), true);
|
cnfPred = canonicalize_qual((Expr *) copyObject(predicate), true);
|
||||||
fix_opfuncids((Node *) cnfPred);
|
|
||||||
CheckPredicate(cnfPred, rangetable, relationId);
|
CheckPredicate(cnfPred, rangetable, relationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,8 +171,7 @@ DefineIndex(RangeVar *heapRelation,
|
||||||
*/
|
*/
|
||||||
indexInfo = makeNode(IndexInfo);
|
indexInfo = makeNode(IndexInfo);
|
||||||
indexInfo->ii_Predicate = cnfPred;
|
indexInfo->ii_Predicate = cnfPred;
|
||||||
indexInfo->ii_PredicateState = (List *)
|
indexInfo->ii_PredicateState = NIL;
|
||||||
ExecInitExpr((Expr *) cnfPred, NULL);
|
|
||||||
indexInfo->ii_FuncOid = InvalidOid;
|
indexInfo->ii_FuncOid = InvalidOid;
|
||||||
indexInfo->ii_Unique = unique;
|
indexInfo->ii_Unique = unique;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.5 2002/12/05 15:50:30 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.6 2002/12/15 16:17:42 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -31,28 +31,22 @@
|
||||||
void
|
void
|
||||||
PortalCleanup(Portal portal)
|
PortalCleanup(Portal portal)
|
||||||
{
|
{
|
||||||
MemoryContext oldcontext;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
*/
|
*/
|
||||||
AssertArg(PortalIsValid(portal));
|
AssertArg(PortalIsValid(portal));
|
||||||
AssertArg(portal->cleanup == PortalCleanup);
|
AssertArg(portal->cleanup == PortalCleanup);
|
||||||
|
|
||||||
/*
|
|
||||||
* set proper portal-executor context before calling ExecMain.
|
|
||||||
*/
|
|
||||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tell the executor to shutdown the query
|
* tell the executor to shutdown the query
|
||||||
*/
|
*/
|
||||||
ExecutorEnd(PortalGetQueryDesc(portal));
|
ExecutorEnd(PortalGetQueryDesc(portal));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* switch back to previous context
|
* This should be unnecessary since the querydesc should be in the
|
||||||
|
* portal's memory context, but do it anyway for symmetry.
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(oldcontext);
|
FreeQueryDesc(PortalGetQueryDesc(portal));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Copyright (c) 2002, PostgreSQL Global Development Group
|
* Copyright (c) 2002, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.10 2002/12/13 19:45:51 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.11 2002/12/15 16:17:42 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -15,7 +15,6 @@
|
||||||
#include "commands/prepare.h"
|
#include "commands/prepare.h"
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "optimizer/planmain.h"
|
|
||||||
#include "optimizer/planner.h"
|
#include "optimizer/planner.h"
|
||||||
#include "rewrite/rewriteHandler.h"
|
#include "rewrite/rewriteHandler.h"
|
||||||
#include "tcop/pquery.h"
|
#include "tcop/pquery.h"
|
||||||
|
@ -50,7 +49,6 @@ static void InitQueryHashTable(void);
|
||||||
static void StoreQuery(const char *stmt_name, List *query_list,
|
static void StoreQuery(const char *stmt_name, List *query_list,
|
||||||
List *plan_list, List *argtype_list);
|
List *plan_list, List *argtype_list);
|
||||||
static QueryHashEntry *FetchQuery(const char *plan_name);
|
static QueryHashEntry *FetchQuery(const char *plan_name);
|
||||||
static void RunQuery(QueryDesc *qdesc);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -96,33 +94,37 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
|
||||||
*query_list,
|
*query_list,
|
||||||
*plan_list;
|
*plan_list;
|
||||||
ParamListInfo paramLI = NULL;
|
ParamListInfo paramLI = NULL;
|
||||||
|
EState *estate;
|
||||||
|
|
||||||
/* Look it up in the hash table */
|
/* Look it up in the hash table */
|
||||||
entry = FetchQuery(stmt->name);
|
entry = FetchQuery(stmt->name);
|
||||||
|
|
||||||
/* Make working copies the executor can safely scribble on */
|
query_list = entry->query_list;
|
||||||
query_list = (List *) copyObject(entry->query_list);
|
plan_list = entry->plan_list;
|
||||||
plan_list = (List *) copyObject(entry->plan_list);
|
|
||||||
|
|
||||||
Assert(length(query_list) == length(plan_list));
|
Assert(length(query_list) == length(plan_list));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need an EState to evaluate parameters; must not delete it till end
|
||||||
|
* of query, in case parameters are pass-by-reference.
|
||||||
|
*/
|
||||||
|
estate = CreateExecutorState();
|
||||||
|
|
||||||
/* Evaluate parameters, if any */
|
/* Evaluate parameters, if any */
|
||||||
if (entry->argtype_list != NIL)
|
if (entry->argtype_list != NIL)
|
||||||
{
|
{
|
||||||
int nargs = length(entry->argtype_list);
|
int nargs = length(entry->argtype_list);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
List *exprstates;
|
List *exprstates;
|
||||||
ExprContext *econtext = MakeExprContext(NULL, CurrentMemoryContext);
|
|
||||||
|
|
||||||
/* Parser should have caught this error, but check */
|
/* Parser should have caught this error, but check */
|
||||||
if (nargs != length(stmt->params))
|
if (nargs != length(stmt->params))
|
||||||
elog(ERROR, "ExecuteQuery: wrong number of arguments");
|
elog(ERROR, "ExecuteQuery: wrong number of arguments");
|
||||||
|
|
||||||
fix_opfuncids((Node *) stmt->params);
|
exprstates = (List *) ExecPrepareExpr((Expr *) stmt->params, estate);
|
||||||
|
|
||||||
exprstates = (List *) ExecInitExpr((Expr *) stmt->params, NULL);
|
paramLI = (ParamListInfo)
|
||||||
|
palloc0((nargs + 1) * sizeof(ParamListInfoData));
|
||||||
paramLI = (ParamListInfo) palloc0((nargs + 1) * sizeof(ParamListInfoData));
|
|
||||||
|
|
||||||
foreach(l, exprstates)
|
foreach(l, exprstates)
|
||||||
{
|
{
|
||||||
|
@ -130,7 +132,7 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
|
||||||
bool isNull;
|
bool isNull;
|
||||||
|
|
||||||
paramLI[i].value = ExecEvalExprSwitchContext(n,
|
paramLI[i].value = ExecEvalExprSwitchContext(n,
|
||||||
econtext,
|
GetPerTupleExprContext(estate),
|
||||||
&isNull,
|
&isNull,
|
||||||
NULL);
|
NULL);
|
||||||
paramLI[i].kind = PARAM_NUM;
|
paramLI[i].kind = PARAM_NUM;
|
||||||
|
@ -173,7 +175,13 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
|
||||||
qdesc->dest = None;
|
qdesc->dest = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
RunQuery(qdesc);
|
ExecutorStart(qdesc);
|
||||||
|
|
||||||
|
ExecutorRun(qdesc, ForwardScanDirection, 0L);
|
||||||
|
|
||||||
|
ExecutorEnd(qdesc);
|
||||||
|
|
||||||
|
FreeQueryDesc(qdesc);
|
||||||
|
|
||||||
if (log_executor_stats)
|
if (log_executor_stats)
|
||||||
ShowUsage("EXECUTOR STATISTICS");
|
ShowUsage("EXECUTOR STATISTICS");
|
||||||
|
@ -188,7 +196,9 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No need to pfree memory, MemoryContext will be reset */
|
FreeExecutorState(estate);
|
||||||
|
|
||||||
|
/* No need to pfree other memory, MemoryContext will be reset */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -333,17 +343,6 @@ FetchQueryParams(const char *plan_name)
|
||||||
return entry->argtype_list;
|
return entry->argtype_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Actually execute a prepared query.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
RunQuery(QueryDesc *qdesc)
|
|
||||||
{
|
|
||||||
ExecutorStart(qdesc);
|
|
||||||
ExecutorRun(qdesc, ForwardScanDirection, 0L);
|
|
||||||
ExecutorEnd(qdesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implements the 'DEALLOCATE' utility statement: deletes the
|
* Implements the 'DEALLOCATE' utility statement: deletes the
|
||||||
* specified plan from storage.
|
* specified plan from storage.
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.60 2002/12/13 19:45:51 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.61 2002/12/15 16:17:42 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -37,7 +37,6 @@
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
#include "optimizer/plancat.h"
|
#include "optimizer/plancat.h"
|
||||||
#include "optimizer/planmain.h"
|
|
||||||
#include "optimizer/prep.h"
|
#include "optimizer/prep.h"
|
||||||
#include "parser/gramparse.h"
|
#include "parser/gramparse.h"
|
||||||
#include "parser/parse_coerce.h"
|
#include "parser/parse_coerce.h"
|
||||||
|
@ -2713,6 +2712,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
|
||||||
ParseState *pstate;
|
ParseState *pstate;
|
||||||
bool successful = true;
|
bool successful = true;
|
||||||
HeapScanDesc scan;
|
HeapScanDesc scan;
|
||||||
|
EState *estate;
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
|
@ -2723,9 +2723,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to make a parse state and range
|
* We need to make a parse state and range
|
||||||
* table to allow us to transformExpr and
|
* table to allow us to do transformExpr()
|
||||||
* fix_opfuncids to get a version of the
|
|
||||||
* expression we can pass to ExecQual
|
|
||||||
*/
|
*/
|
||||||
pstate = make_parsestate(NULL);
|
pstate = make_parsestate(NULL);
|
||||||
rte = addRangeTableEntryForRelation(pstate,
|
rte = addRangeTableEntryForRelation(pstate,
|
||||||
|
@ -2765,19 +2763,22 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
|
||||||
*/
|
*/
|
||||||
expr = eval_const_expressions(expr);
|
expr = eval_const_expressions(expr);
|
||||||
|
|
||||||
/* And fix the opfuncids */
|
/* Needs to be in implicit-ANDs form for ExecQual */
|
||||||
fix_opfuncids(expr);
|
qual = make_ands_implicit((Expr *) expr);
|
||||||
|
|
||||||
qual = makeList1(expr);
|
/* Need an EState to run ExecQual */
|
||||||
|
estate = CreateExecutorState();
|
||||||
|
econtext = GetPerTupleExprContext(estate);
|
||||||
|
|
||||||
/* build execution state for qual */
|
/* build execution state for qual */
|
||||||
qualstate = (List *) ExecInitExpr((Expr *) qual, NULL);
|
qualstate = (List *) ExecPrepareExpr((Expr *) qual, estate);
|
||||||
|
|
||||||
/* Make tuple slot to hold tuples */
|
/* Make tuple slot to hold tuples */
|
||||||
slot = MakeTupleTableSlot();
|
slot = MakeTupleTableSlot();
|
||||||
ExecSetSlotDescriptor(slot, RelationGetDescr(rel), false);
|
ExecSetSlotDescriptor(slot, RelationGetDescr(rel), false);
|
||||||
/* Make an expression context for ExecQual */
|
|
||||||
econtext = MakeExprContext(slot, CurrentMemoryContext);
|
/* Arrange for econtext's scan tuple to be the tuple under test */
|
||||||
|
econtext->ecxt_scantuple = slot;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan through the rows now, checking the expression at each row.
|
* Scan through the rows now, checking the expression at each row.
|
||||||
|
@ -2797,8 +2798,8 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
|
||||||
|
|
||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
|
|
||||||
FreeExprContext(econtext);
|
|
||||||
pfree(slot);
|
pfree(slot);
|
||||||
|
FreeExecutorState(estate);
|
||||||
|
|
||||||
if (!successful)
|
if (!successful)
|
||||||
elog(ERROR, "AlterTableAddConstraint: rejected due to CHECK constraint %s",
|
elog(ERROR, "AlterTableAddConstraint: rejected due to CHECK constraint %s",
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.24 2002/12/13 19:45:52 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.25 2002/12/15 16:17:43 tgl Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* The "DefineFoo" routines take the parse tree and pick out the
|
* The "DefineFoo" routines take the parse tree and pick out the
|
||||||
|
@ -47,7 +47,6 @@
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "nodes/nodes.h"
|
#include "nodes/nodes.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
#include "optimizer/planmain.h"
|
|
||||||
#include "optimizer/var.h"
|
#include "optimizer/var.h"
|
||||||
#include "parser/parse_coerce.h"
|
#include "parser/parse_coerce.h"
|
||||||
#include "parser/parse_expr.h"
|
#include "parser/parse_expr.h"
|
||||||
|
@ -1242,6 +1241,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
|
||||||
List *rels;
|
List *rels;
|
||||||
List *rt;
|
List *rt;
|
||||||
Form_pg_type typTup;
|
Form_pg_type typTup;
|
||||||
|
EState *estate;
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
char *ccbin;
|
char *ccbin;
|
||||||
Expr *expr;
|
Expr *expr;
|
||||||
|
@ -1338,11 +1338,13 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
|
||||||
* the constraint is being added to.
|
* the constraint is being added to.
|
||||||
*/
|
*/
|
||||||
expr = (Expr *) stringToNode(ccbin);
|
expr = (Expr *) stringToNode(ccbin);
|
||||||
fix_opfuncids((Node *) expr);
|
|
||||||
exprstate = ExecInitExpr(expr, NULL);
|
|
||||||
|
|
||||||
/* Make an expression context for ExecEvalExpr */
|
/* Need an EState to run ExecEvalExpr */
|
||||||
econtext = MakeExprContext(NULL, CurrentMemoryContext);
|
estate = CreateExecutorState();
|
||||||
|
econtext = GetPerTupleExprContext(estate);
|
||||||
|
|
||||||
|
/* build execution state for expr */
|
||||||
|
exprstate = ExecPrepareExpr(expr, estate);
|
||||||
|
|
||||||
rels = get_rels_with_domain(domainoid);
|
rels = get_rels_with_domain(domainoid);
|
||||||
|
|
||||||
|
@ -1377,7 +1379,9 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
|
||||||
econtext->domainValue_datum = d;
|
econtext->domainValue_datum = d;
|
||||||
econtext->domainValue_isNull = isNull;
|
econtext->domainValue_isNull = isNull;
|
||||||
|
|
||||||
conResult = ExecEvalExpr(exprstate, econtext, &isNull, NULL);
|
conResult = ExecEvalExprSwitchContext(exprstate,
|
||||||
|
econtext,
|
||||||
|
&isNull, NULL);
|
||||||
|
|
||||||
if (!isNull && !DatumGetBool(conResult))
|
if (!isNull && !DatumGetBool(conResult))
|
||||||
elog(ERROR, "AlterDomainAddConstraint: Domain %s constraint %s failed",
|
elog(ERROR, "AlterDomainAddConstraint: Domain %s constraint %s failed",
|
||||||
|
@ -1393,7 +1397,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
|
||||||
heap_close(testrel, NoLock);
|
heap_close(testrel, NoLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeExprContext(econtext);
|
FreeExecutorState(estate);
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.244 2002/10/31 19:25:29 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.245 2002/12/15 16:17:44 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1437,6 +1437,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||||
* We need a ResultRelInfo and an EState so we can use the regular
|
* We need a ResultRelInfo and an EState so we can use the regular
|
||||||
* executor's index-entry-making machinery.
|
* executor's index-entry-making machinery.
|
||||||
*/
|
*/
|
||||||
|
estate = CreateExecutorState();
|
||||||
|
|
||||||
resultRelInfo = makeNode(ResultRelInfo);
|
resultRelInfo = makeNode(ResultRelInfo);
|
||||||
resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
|
resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
|
||||||
resultRelInfo->ri_RelationDesc = onerel;
|
resultRelInfo->ri_RelationDesc = onerel;
|
||||||
|
@ -1444,7 +1446,6 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||||
|
|
||||||
ExecOpenIndices(resultRelInfo);
|
ExecOpenIndices(resultRelInfo);
|
||||||
|
|
||||||
estate = CreateExecutorState();
|
|
||||||
estate->es_result_relations = resultRelInfo;
|
estate->es_result_relations = resultRelInfo;
|
||||||
estate->es_num_result_relations = 1;
|
estate->es_num_result_relations = 1;
|
||||||
estate->es_result_relation_info = resultRelInfo;
|
estate->es_result_relation_info = resultRelInfo;
|
||||||
|
@ -2484,6 +2485,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||||
ExecDropTupleTable(tupleTable, true);
|
ExecDropTupleTable(tupleTable, true);
|
||||||
|
|
||||||
ExecCloseIndices(resultRelInfo);
|
ExecCloseIndices(resultRelInfo);
|
||||||
|
|
||||||
|
FreeExecutorState(estate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.2 2002/12/05 15:50:30 tgl Exp $
|
$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.3 2002/12/15 16:17:45 tgl Exp $
|
||||||
|
|
||||||
The Postgres Executor
|
The Postgres Executor
|
||||||
---------------------
|
---------------------
|
||||||
|
@ -60,6 +60,83 @@ ExprState nodes. (Actually, there are also List nodes, which are used as
|
||||||
"glue" in all four kinds of tree.)
|
"glue" in all four kinds of tree.)
|
||||||
|
|
||||||
|
|
||||||
|
Memory Management
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
A "per query" memory context is created during CreateExecutorState();
|
||||||
|
all storage allocated during an executor invocation is allocated in that
|
||||||
|
context or a child context. This allows easy reclamation of storage
|
||||||
|
during executor shutdown --- rather than messing with retail pfree's and
|
||||||
|
probable storage leaks, we just destroy the memory context.
|
||||||
|
|
||||||
|
In particular, the plan state trees and expression state trees described
|
||||||
|
in the previous section are allocated in the per-query memory context.
|
||||||
|
|
||||||
|
To avoid intra-query memory leaks, most processing while a query runs
|
||||||
|
is done in "per tuple" memory contexts, which are so-called because they
|
||||||
|
are typically reset to empty once per tuple. Per-tuple contexts are usually
|
||||||
|
associated with ExprContexts, and commonly each PlanState node has its own
|
||||||
|
ExprContext to evaluate its qual and targetlist expressions in.
|
||||||
|
|
||||||
|
|
||||||
|
Query Processing Control Flow
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
This is a sketch of control flow for full query processing:
|
||||||
|
|
||||||
|
CreateQueryDesc
|
||||||
|
|
||||||
|
ExecutorStart
|
||||||
|
CreateExecutorState
|
||||||
|
creates per-query context
|
||||||
|
switch to per-query context to run ExecInitNode
|
||||||
|
ExecInitNode --- recursively scans plan tree
|
||||||
|
CreateExprContext
|
||||||
|
creates per-tuple context
|
||||||
|
ExecInitExpr
|
||||||
|
|
||||||
|
ExecutorRun
|
||||||
|
ExecProcNode --- recursively called in per-query context
|
||||||
|
ExecEvalExpr --- called in per-tuple context
|
||||||
|
ResetExprContext --- to free memory
|
||||||
|
|
||||||
|
ExecutorEnd
|
||||||
|
ExecEndNode --- recursively releases resources
|
||||||
|
FreeExecutorState
|
||||||
|
frees per-query context and child contexts
|
||||||
|
|
||||||
|
FreeQueryDesc
|
||||||
|
|
||||||
|
Per above comments, it's not really critical for ExecEndNode to free any
|
||||||
|
memory; it'll all go away in FreeExecutorState anyway. However, we do need to
|
||||||
|
be careful to close relations, drop buffer pins, etc, so we do need to scan
|
||||||
|
the plan state tree to find these sorts of resources.
|
||||||
|
|
||||||
|
|
||||||
|
The executor can also be used to evaluate simple expressions without any Plan
|
||||||
|
tree ("simple" meaning "no aggregates and no sub-selects", though such might
|
||||||
|
be hidden inside function calls). This case has a flow of control like
|
||||||
|
|
||||||
|
CreateExecutorState
|
||||||
|
creates per-query context
|
||||||
|
|
||||||
|
CreateExprContext -- or use GetPerTupleExprContext(estate)
|
||||||
|
creates per-tuple context
|
||||||
|
|
||||||
|
ExecPrepareExpr
|
||||||
|
switch to per-query context to run ExecInitExpr
|
||||||
|
ExecInitExpr
|
||||||
|
|
||||||
|
Repeatedly do:
|
||||||
|
ExecEvalExprSwitchContext
|
||||||
|
ExecEvalExpr --- called in per-tuple context
|
||||||
|
ResetExprContext --- to free memory
|
||||||
|
|
||||||
|
FreeExecutorState
|
||||||
|
frees per-query context, as well as ExprContext
|
||||||
|
(a separate FreeExprContext call is not necessary)
|
||||||
|
|
||||||
|
|
||||||
EvalPlanQual (READ COMMITTED update checking)
|
EvalPlanQual (READ COMMITTED update checking)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.192 2002/12/13 19:45:52 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.193 2002/12/15 16:17:45 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -40,7 +40,6 @@
|
||||||
#include "executor/execdebug.h"
|
#include "executor/execdebug.h"
|
||||||
#include "executor/execdefs.h"
|
#include "executor/execdefs.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "optimizer/planmain.h"
|
|
||||||
#include "optimizer/var.h"
|
#include "optimizer/var.h"
|
||||||
#include "parser/parsetree.h"
|
#include "parser/parsetree.h"
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
|
@ -53,7 +52,6 @@ static void initResultRelInfo(ResultRelInfo *resultRelInfo,
|
||||||
Index resultRelationIndex,
|
Index resultRelationIndex,
|
||||||
List *rangeTable,
|
List *rangeTable,
|
||||||
CmdType operation);
|
CmdType operation);
|
||||||
static void EndPlan(PlanState *planstate, EState *estate);
|
|
||||||
static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
|
static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
|
||||||
CmdType operation,
|
CmdType operation,
|
||||||
long numberTuples,
|
long numberTuples,
|
||||||
|
@ -86,27 +84,31 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
|
||||||
* field of the QueryDesc is filled in to describe the tuples that will be
|
* field of the QueryDesc is filled in to describe the tuples that will be
|
||||||
* returned, and the internal fields (estate and planstate) are set up.
|
* returned, and the internal fields (estate and planstate) are set up.
|
||||||
*
|
*
|
||||||
* XXX this will change soon:
|
* NB: the CurrentMemoryContext when this is called will become the parent
|
||||||
* NB: the CurrentMemoryContext when this is called must be the context
|
* of the per-query context used for this Executor invocation.
|
||||||
* to be used as the per-query context for the query plan. ExecutorRun()
|
|
||||||
* and ExecutorEnd() must be called in this same memory context.
|
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecutorStart(QueryDesc *queryDesc)
|
ExecutorStart(QueryDesc *queryDesc)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/* sanity checks: queryDesc must not be started already */
|
/* sanity checks: queryDesc must not be started already */
|
||||||
Assert(queryDesc != NULL);
|
Assert(queryDesc != NULL);
|
||||||
Assert(queryDesc->estate == NULL);
|
Assert(queryDesc->estate == NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build EState, fill with parameters from queryDesc
|
* Build EState, switch into per-query memory context for startup.
|
||||||
*/
|
*/
|
||||||
estate = CreateExecutorState();
|
estate = CreateExecutorState();
|
||||||
queryDesc->estate = estate;
|
queryDesc->estate = estate;
|
||||||
|
|
||||||
|
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill in parameters, if any, from queryDesc
|
||||||
|
*/
|
||||||
estate->es_param_list_info = queryDesc->params;
|
estate->es_param_list_info = queryDesc->params;
|
||||||
|
|
||||||
if (queryDesc->plantree->nParamExec > 0)
|
if (queryDesc->plantree->nParamExec > 0)
|
||||||
|
@ -128,6 +130,8 @@ ExecutorStart(QueryDesc *queryDesc)
|
||||||
* Initialize the plan state tree
|
* Initialize the plan state tree
|
||||||
*/
|
*/
|
||||||
InitPlan(queryDesc);
|
InitPlan(queryDesc);
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
|
@ -152,23 +156,30 @@ TupleTableSlot *
|
||||||
ExecutorRun(QueryDesc *queryDesc,
|
ExecutorRun(QueryDesc *queryDesc,
|
||||||
ScanDirection direction, long count)
|
ScanDirection direction, long count)
|
||||||
{
|
{
|
||||||
CmdType operation;
|
|
||||||
EState *estate;
|
EState *estate;
|
||||||
|
CmdType operation;
|
||||||
CommandDest dest;
|
CommandDest dest;
|
||||||
DestReceiver *destfunc;
|
DestReceiver *destfunc;
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
|
/* sanity checks */
|
||||||
|
Assert(queryDesc != NULL);
|
||||||
|
|
||||||
|
estate = queryDesc->estate;
|
||||||
|
|
||||||
|
Assert(estate != NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sanity checks
|
* Switch into per-query memory context
|
||||||
*/
|
*/
|
||||||
Assert(queryDesc != NULL);
|
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* extract information from the query descriptor and the query
|
* extract information from the query descriptor and the query
|
||||||
* feature.
|
* feature.
|
||||||
*/
|
*/
|
||||||
operation = queryDesc->operation;
|
operation = queryDesc->operation;
|
||||||
estate = queryDesc->estate;
|
|
||||||
dest = queryDesc->dest;
|
dest = queryDesc->dest;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -199,6 +210,8 @@ ExecutorRun(QueryDesc *queryDesc,
|
||||||
*/
|
*/
|
||||||
(*destfunc->cleanup) (destfunc);
|
(*destfunc->cleanup) (destfunc);
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,72 +226,37 @@ void
|
||||||
ExecutorEnd(QueryDesc *queryDesc)
|
ExecutorEnd(QueryDesc *queryDesc)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/* sanity checks */
|
/* sanity checks */
|
||||||
Assert(queryDesc != NULL);
|
Assert(queryDesc != NULL);
|
||||||
|
|
||||||
estate = queryDesc->estate;
|
estate = queryDesc->estate;
|
||||||
|
|
||||||
EndPlan(queryDesc->planstate, estate);
|
Assert(estate != NULL);
|
||||||
|
|
||||||
if (estate->es_snapshot != NULL)
|
|
||||||
{
|
|
||||||
if (estate->es_snapshot->xcnt > 0)
|
|
||||||
pfree(estate->es_snapshot->xip);
|
|
||||||
pfree(estate->es_snapshot);
|
|
||||||
estate->es_snapshot = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (estate->es_param_exec_vals != NULL)
|
|
||||||
{
|
|
||||||
pfree(estate->es_param_exec_vals);
|
|
||||||
estate->es_param_exec_vals = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CreateExecutorState
|
|
||||||
*/
|
|
||||||
EState *
|
|
||||||
CreateExecutorState(void)
|
|
||||||
{
|
|
||||||
EState *state;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create a new executor state
|
* Switch into per-query memory context to run ExecEndPlan
|
||||||
*/
|
*/
|
||||||
state = makeNode(EState);
|
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
|
||||||
|
|
||||||
|
ExecEndPlan(queryDesc->planstate, estate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize the Executor State structure
|
* Must switch out of context before destroying it
|
||||||
*/
|
*/
|
||||||
state->es_direction = ForwardScanDirection;
|
MemoryContextSwitchTo(oldcontext);
|
||||||
state->es_range_table = NIL;
|
|
||||||
|
|
||||||
state->es_result_relations = NULL;
|
|
||||||
state->es_num_result_relations = 0;
|
|
||||||
state->es_result_relation_info = NULL;
|
|
||||||
|
|
||||||
state->es_junkFilter = NULL;
|
|
||||||
|
|
||||||
state->es_into_relation_descriptor = NULL;
|
|
||||||
|
|
||||||
state->es_param_list_info = NULL;
|
|
||||||
state->es_param_exec_vals = NULL;
|
|
||||||
|
|
||||||
state->es_tupleTable = NULL;
|
|
||||||
|
|
||||||
state->es_query_cxt = CurrentMemoryContext;
|
|
||||||
|
|
||||||
state->es_instrument = false;
|
|
||||||
|
|
||||||
state->es_per_tuple_exprcontext = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* return the executor state structure
|
* Release EState and per-query memory context. This should release
|
||||||
|
* everything the executor has allocated.
|
||||||
*/
|
*/
|
||||||
return state;
|
FreeExecutorState(estate);
|
||||||
|
|
||||||
|
/* Reset queryDesc fields that no longer point to anything */
|
||||||
|
queryDesc->tupDesc = NULL;
|
||||||
|
queryDesc->estate = NULL;
|
||||||
|
queryDesc->planstate = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -794,13 +772,13 @@ initResultRelInfo(ResultRelInfo *resultRelInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* EndPlan
|
* ExecEndPlan
|
||||||
*
|
*
|
||||||
* Cleans up the query plan -- closes files and frees up storage
|
* Cleans up the query plan -- closes files and frees up storage
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
EndPlan(PlanState *planstate, EState *estate)
|
ExecEndPlan(PlanState *planstate, EState *estate)
|
||||||
{
|
{
|
||||||
ResultRelInfo *resultRelInfo;
|
ResultRelInfo *resultRelInfo;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1542,9 +1520,8 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
|
||||||
for (i = 0; i < ncheck; i++)
|
for (i = 0; i < ncheck; i++)
|
||||||
{
|
{
|
||||||
qual = (List *) stringToNode(check[i].ccbin);
|
qual = (List *) stringToNode(check[i].ccbin);
|
||||||
fix_opfuncids((Node *) qual);
|
|
||||||
resultRelInfo->ri_ConstraintExprs[i] = (List *)
|
resultRelInfo->ri_ConstraintExprs[i] = (List *)
|
||||||
ExecInitExpr((Expr *) qual, NULL);
|
ExecPrepareExpr((Expr *) qual, estate);
|
||||||
}
|
}
|
||||||
MemoryContextSwitchTo(oldContext);
|
MemoryContextSwitchTo(oldContext);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.120 2002/12/14 00:17:50 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.121 2002/12/15 16:17:45 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -40,6 +40,7 @@
|
||||||
#include "executor/functions.h"
|
#include "executor/functions.h"
|
||||||
#include "executor/nodeSubplan.h"
|
#include "executor/nodeSubplan.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "optimizer/planmain.h"
|
||||||
#include "parser/parse_expr.h"
|
#include "parser/parse_expr.h"
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
|
@ -1896,9 +1897,11 @@ ExecEvalExprSwitchContext(ExprState *expression,
|
||||||
* cleanup work can register a shutdown callback in the ExprContext.
|
* cleanup work can register a shutdown callback in the ExprContext.
|
||||||
*
|
*
|
||||||
* 'node' is the root of the expression tree to examine
|
* 'node' is the root of the expression tree to examine
|
||||||
* 'parent' is the PlanState node that owns the expression,
|
* 'parent' is the PlanState node that owns the expression.
|
||||||
* or NULL if we are preparing an expression that is not associated
|
*
|
||||||
* with a plan. (If so, it can't have aggs or subplans.)
|
* 'parent' may be NULL if we are preparing an expression that is not
|
||||||
|
* associated with a plan tree. (If so, it can't have aggs or subplans.)
|
||||||
|
* This case should usually come through ExecPrepareExpr, not directly here.
|
||||||
*/
|
*/
|
||||||
ExprState *
|
ExprState *
|
||||||
ExecInitExpr(Expr *node, PlanState *parent)
|
ExecInitExpr(Expr *node, PlanState *parent)
|
||||||
|
@ -2017,6 +2020,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
|
||||||
* parent->subPlan. The subplans will be initialized later.
|
* parent->subPlan. The subplans will be initialized later.
|
||||||
*/
|
*/
|
||||||
parent->subPlan = lcons(sstate, parent->subPlan);
|
parent->subPlan = lcons(sstate, parent->subPlan);
|
||||||
|
sstate->sub_estate = NULL;
|
||||||
sstate->planstate = NULL;
|
sstate->planstate = NULL;
|
||||||
|
|
||||||
sstate->oper = (List *)
|
sstate->oper = (List *)
|
||||||
|
@ -2149,6 +2153,7 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
|
||||||
elog(ERROR, "ExecInitExpr: SubPlan not expected here");
|
elog(ERROR, "ExecInitExpr: SubPlan not expected here");
|
||||||
|
|
||||||
/* The subplan's state will be initialized later */
|
/* The subplan's state will be initialized later */
|
||||||
|
sstate->sub_estate = NULL;
|
||||||
sstate->planstate = NULL;
|
sstate->planstate = NULL;
|
||||||
|
|
||||||
sstate->oper = (List *) ExecInitExpr((Expr *) node->oper, parent);
|
sstate->oper = (List *) ExecInitExpr((Expr *) node->oper, parent);
|
||||||
|
@ -2159,6 +2164,33 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
|
||||||
return sstate;
|
return sstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ExecPrepareExpr --- initialize for expression execution outside a normal
|
||||||
|
* Plan tree context.
|
||||||
|
*
|
||||||
|
* This differs from ExecInitExpr in that we don't assume the caller is
|
||||||
|
* already running in the EState's per-query context. Also, we apply
|
||||||
|
* fix_opfuncids() to the passed expression tree to be sure it is ready
|
||||||
|
* to run. (In ordinary Plan trees the planner will have fixed opfuncids,
|
||||||
|
* but callers outside the executor will not have done this.)
|
||||||
|
*/
|
||||||
|
ExprState *
|
||||||
|
ExecPrepareExpr(Expr *node, EState *estate)
|
||||||
|
{
|
||||||
|
ExprState *result;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
|
fix_opfuncids((Node *) node);
|
||||||
|
|
||||||
|
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
|
||||||
|
|
||||||
|
result = ExecInitExpr(node, NULL);
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecQual / ExecTargetList / ExecProject
|
* ExecQual / ExecTargetList / ExecProject
|
||||||
|
|
|
@ -8,13 +8,20 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.92 2002/12/13 19:45:52 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.93 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
|
* CreateExecutorState Create/delete executor working state
|
||||||
|
* FreeExecutorState
|
||||||
|
* CreateExprContext
|
||||||
|
* FreeExprContext
|
||||||
|
*
|
||||||
* ExecAssignExprContext Common code for plan node init routines.
|
* ExecAssignExprContext Common code for plan node init routines.
|
||||||
|
* ExecAssignResultType
|
||||||
|
* etc
|
||||||
*
|
*
|
||||||
* ExecOpenIndices \
|
* ExecOpenIndices \
|
||||||
* ExecCloseIndices | referenced by InitPlan, EndPlan,
|
* ExecCloseIndices | referenced by InitPlan, EndPlan,
|
||||||
|
@ -26,7 +33,6 @@
|
||||||
* NOTES
|
* NOTES
|
||||||
* This file has traditionally been the place to stick misc.
|
* This file has traditionally been the place to stick misc.
|
||||||
* executor support stuff that doesn't really go anyplace else.
|
* executor support stuff that doesn't really go anyplace else.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -64,6 +70,7 @@ extern int NIndexTupleProcessed; /* have to be defined in the
|
||||||
|
|
||||||
static void ShutdownExprContext(ExprContext *econtext);
|
static void ShutdownExprContext(ExprContext *econtext);
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* statistic functions
|
* statistic functions
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
|
@ -124,136 +131,263 @@ DisplayTupleCount(FILE *statfp)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* miscellaneous node-init support functions
|
* Executor state and memory management functions
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* ExecAssignExprContext
|
* CreateExecutorState
|
||||||
*
|
*
|
||||||
* This initializes the ExprContext field. It is only necessary
|
* Create and initialize an EState node, which is the root of
|
||||||
* to do this for nodes which use ExecQual or ExecProject
|
* working storage for an entire Executor invocation.
|
||||||
* because those routines depend on econtext. Other nodes that
|
|
||||||
* don't have to evaluate expressions don't need to do this.
|
|
||||||
*
|
*
|
||||||
* Note: we assume CurrentMemoryContext is the correct per-query context.
|
* Principally, this creates the per-query memory context that will be
|
||||||
* This should be true during plan node initialization.
|
* used to hold all working data that lives till the end of the query.
|
||||||
|
* Note that the per-query context will become a child of the caller's
|
||||||
|
* CurrentMemoryContext.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
EState *
|
||||||
|
CreateExecutorState(void)
|
||||||
|
{
|
||||||
|
EState *estate;
|
||||||
|
MemoryContext qcontext;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the per-query context for this Executor run.
|
||||||
|
*/
|
||||||
|
qcontext = AllocSetContextCreate(CurrentMemoryContext,
|
||||||
|
"ExecutorState",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make the EState node within the per-query context. This way,
|
||||||
|
* we don't need a separate pfree() operation for it at shutdown.
|
||||||
|
*/
|
||||||
|
oldcontext = MemoryContextSwitchTo(qcontext);
|
||||||
|
|
||||||
|
estate = makeNode(EState);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize all fields of the Executor State structure
|
||||||
|
*/
|
||||||
|
estate->es_direction = ForwardScanDirection;
|
||||||
|
estate->es_snapshot = SnapshotNow;
|
||||||
|
estate->es_range_table = NIL;
|
||||||
|
|
||||||
|
estate->es_result_relations = NULL;
|
||||||
|
estate->es_num_result_relations = 0;
|
||||||
|
estate->es_result_relation_info = NULL;
|
||||||
|
|
||||||
|
estate->es_junkFilter = NULL;
|
||||||
|
estate->es_into_relation_descriptor = NULL;
|
||||||
|
|
||||||
|
estate->es_param_list_info = NULL;
|
||||||
|
estate->es_param_exec_vals = NULL;
|
||||||
|
|
||||||
|
estate->es_query_cxt = qcontext;
|
||||||
|
|
||||||
|
estate->es_tupleTable = NULL;
|
||||||
|
|
||||||
|
estate->es_processed = 0;
|
||||||
|
estate->es_lastoid = InvalidOid;
|
||||||
|
estate->es_rowMark = NIL;
|
||||||
|
|
||||||
|
estate->es_instrument = false;
|
||||||
|
|
||||||
|
estate->es_exprcontexts = NIL;
|
||||||
|
|
||||||
|
estate->es_per_tuple_exprcontext = NULL;
|
||||||
|
|
||||||
|
estate->es_origPlan = NULL;
|
||||||
|
estate->es_evalPlanQual = NULL;
|
||||||
|
estate->es_evTupleNull = NULL;
|
||||||
|
estate->es_evTuple = NULL;
|
||||||
|
estate->es_useEvalPlan = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the executor state structure
|
||||||
|
*/
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
|
return estate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* FreeExecutorState
|
||||||
|
*
|
||||||
|
* Release an EState along with all remaining working storage.
|
||||||
|
*
|
||||||
|
* Note: this is not responsible for releasing non-memory resources,
|
||||||
|
* such as open relations or buffer pins. But it will shut down any
|
||||||
|
* still-active ExprContexts within the EState. That is sufficient
|
||||||
|
* cleanup for situations where the EState has only been used for expression
|
||||||
|
* evaluation, and not to run a complete Plan.
|
||||||
|
*
|
||||||
|
* This can be called in any memory context ... so long as it's not one
|
||||||
|
* of the ones to be freed.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecAssignExprContext(EState *estate, PlanState *planstate)
|
FreeExecutorState(EState *estate)
|
||||||
{
|
{
|
||||||
ExprContext *econtext = makeNode(ExprContext);
|
/*
|
||||||
|
* Shut down and free any remaining ExprContexts. We do this
|
||||||
|
* explicitly to ensure that any remaining shutdown callbacks get
|
||||||
|
* called (since they might need to release resources that aren't
|
||||||
|
* simply memory within the per-query memory context).
|
||||||
|
*/
|
||||||
|
while (estate->es_exprcontexts)
|
||||||
|
{
|
||||||
|
FreeExprContext((ExprContext *) lfirst(estate->es_exprcontexts));
|
||||||
|
/* FreeExprContext removed the list link for us */
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Free the per-query memory context, thereby releasing all working
|
||||||
|
* memory, including the EState node itself.
|
||||||
|
*/
|
||||||
|
MemoryContextDelete(estate->es_query_cxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* CreateExprContext
|
||||||
|
*
|
||||||
|
* Create a context for expression evaluation within an EState.
|
||||||
|
*
|
||||||
|
* An executor run may require multiple ExprContexts (we usually make one
|
||||||
|
* for each Plan node, and a separate one for per-output-tuple processing
|
||||||
|
* such as constraint checking). Each ExprContext has its own "per-tuple"
|
||||||
|
* memory context.
|
||||||
|
*
|
||||||
|
* Note we make no assumption about the caller's memory context.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
ExprContext *
|
||||||
|
CreateExprContext(EState *estate)
|
||||||
|
{
|
||||||
|
ExprContext *econtext;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
|
/* Create the ExprContext node within the per-query memory context */
|
||||||
|
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
|
||||||
|
|
||||||
|
econtext = makeNode(ExprContext);
|
||||||
|
|
||||||
|
/* Initialize fields of ExprContext */
|
||||||
econtext->ecxt_scantuple = NULL;
|
econtext->ecxt_scantuple = NULL;
|
||||||
econtext->ecxt_innertuple = NULL;
|
econtext->ecxt_innertuple = NULL;
|
||||||
econtext->ecxt_outertuple = NULL;
|
econtext->ecxt_outertuple = NULL;
|
||||||
econtext->ecxt_per_query_memory = CurrentMemoryContext;
|
|
||||||
|
econtext->ecxt_per_query_memory = estate->es_query_cxt;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create working memory for expression evaluation in this context.
|
* Create working memory for expression evaluation in this context.
|
||||||
*/
|
*/
|
||||||
econtext->ecxt_per_tuple_memory =
|
econtext->ecxt_per_tuple_memory =
|
||||||
AllocSetContextCreate(CurrentMemoryContext,
|
AllocSetContextCreate(estate->es_query_cxt,
|
||||||
"PlanExprContext",
|
"ExprContext",
|
||||||
ALLOCSET_DEFAULT_MINSIZE,
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
ALLOCSET_DEFAULT_INITSIZE,
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
|
econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
|
||||||
econtext->ecxt_param_list_info = estate->es_param_list_info;
|
econtext->ecxt_param_list_info = estate->es_param_list_info;
|
||||||
|
|
||||||
econtext->ecxt_aggvalues = NULL;
|
econtext->ecxt_aggvalues = NULL;
|
||||||
econtext->ecxt_aggnulls = NULL;
|
econtext->ecxt_aggnulls = NULL;
|
||||||
|
|
||||||
|
econtext->domainValue_datum = (Datum) 0;
|
||||||
|
econtext->domainValue_isNull = true;
|
||||||
|
|
||||||
|
econtext->ecxt_estate = estate;
|
||||||
|
|
||||||
econtext->ecxt_callbacks = NULL;
|
econtext->ecxt_callbacks = NULL;
|
||||||
|
|
||||||
planstate->ps_ExprContext = econtext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* MakeExprContext
|
|
||||||
*
|
|
||||||
* Build an expression context for use outside normal plan-node cases.
|
|
||||||
* A fake scan-tuple slot can be supplied (pass NULL if not needed).
|
|
||||||
* A memory context sufficiently long-lived to use as fcache context
|
|
||||||
* must be supplied as well.
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
ExprContext *
|
|
||||||
MakeExprContext(TupleTableSlot *slot,
|
|
||||||
MemoryContext queryContext)
|
|
||||||
{
|
|
||||||
ExprContext *econtext = makeNode(ExprContext);
|
|
||||||
|
|
||||||
econtext->ecxt_scantuple = slot;
|
|
||||||
econtext->ecxt_innertuple = NULL;
|
|
||||||
econtext->ecxt_outertuple = NULL;
|
|
||||||
econtext->ecxt_per_query_memory = queryContext;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We make the temporary context a child of current working context,
|
* Link the ExprContext into the EState to ensure it is shut down
|
||||||
* not of the specified queryContext. This seems reasonable but I'm
|
* when the EState is freed. Because we use lcons(), shutdowns will
|
||||||
* not totally sure about it...
|
* occur in reverse order of creation, which may not be essential
|
||||||
*
|
* but can't hurt.
|
||||||
* Expression contexts made via this routine typically don't live long
|
|
||||||
* enough to get reset, so specify a minsize of 0. That avoids
|
|
||||||
* alloc'ing any memory in the common case where expr eval doesn't use
|
|
||||||
* any.
|
|
||||||
*/
|
*/
|
||||||
econtext->ecxt_per_tuple_memory =
|
estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);
|
||||||
AllocSetContextCreate(CurrentMemoryContext,
|
|
||||||
"TempExprContext",
|
MemoryContextSwitchTo(oldcontext);
|
||||||
0,
|
|
||||||
ALLOCSET_DEFAULT_INITSIZE,
|
|
||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
|
||||||
econtext->ecxt_param_exec_vals = NULL;
|
|
||||||
econtext->ecxt_param_list_info = NULL;
|
|
||||||
econtext->ecxt_aggvalues = NULL;
|
|
||||||
econtext->ecxt_aggnulls = NULL;
|
|
||||||
econtext->ecxt_callbacks = NULL;
|
|
||||||
|
|
||||||
return econtext;
|
return econtext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* ----------------
|
||||||
* Free an ExprContext made by MakeExprContext, including the temporary
|
* FreeExprContext
|
||||||
* context used for expression evaluation. Note this will cause any
|
*
|
||||||
* pass-by-reference expression result to go away!
|
* Free an expression context, including calling any remaining
|
||||||
|
* shutdown callbacks.
|
||||||
|
*
|
||||||
|
* Since we free the temporary context used for expression evaluation,
|
||||||
|
* any previously computed pass-by-reference expression result will go away!
|
||||||
|
*
|
||||||
|
* Note we make no assumption about the caller's memory context.
|
||||||
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
FreeExprContext(ExprContext *econtext)
|
FreeExprContext(ExprContext *econtext)
|
||||||
{
|
{
|
||||||
|
EState *estate;
|
||||||
|
|
||||||
/* Call any registered callbacks */
|
/* Call any registered callbacks */
|
||||||
ShutdownExprContext(econtext);
|
ShutdownExprContext(econtext);
|
||||||
/* And clean up the memory used */
|
/* And clean up the memory used */
|
||||||
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
|
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
|
||||||
|
/* Unlink self from owning EState */
|
||||||
|
estate = econtext->ecxt_estate;
|
||||||
|
estate->es_exprcontexts = lremove(econtext, estate->es_exprcontexts);
|
||||||
|
/* And delete the ExprContext node */
|
||||||
pfree(econtext);
|
pfree(econtext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build a per-output-tuple ExprContext for an EState.
|
* Build a per-output-tuple ExprContext for an EState.
|
||||||
*
|
*
|
||||||
* This is normally invoked via GetPerTupleExprContext() macro.
|
* This is normally invoked via GetPerTupleExprContext() macro,
|
||||||
|
* not directly.
|
||||||
*/
|
*/
|
||||||
ExprContext *
|
ExprContext *
|
||||||
MakePerTupleExprContext(EState *estate)
|
MakePerTupleExprContext(EState *estate)
|
||||||
{
|
{
|
||||||
if (estate->es_per_tuple_exprcontext == NULL)
|
if (estate->es_per_tuple_exprcontext == NULL)
|
||||||
{
|
estate->es_per_tuple_exprcontext = CreateExprContext(estate);
|
||||||
MemoryContext oldContext;
|
|
||||||
|
|
||||||
oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
|
|
||||||
estate->es_per_tuple_exprcontext =
|
|
||||||
MakeExprContext(NULL, estate->es_query_cxt);
|
|
||||||
MemoryContextSwitchTo(oldContext);
|
|
||||||
}
|
|
||||||
return estate->es_per_tuple_exprcontext;
|
return estate->es_per_tuple_exprcontext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* Result slot tuple type and ProjectionInfo support
|
* miscellaneous node-init support functions
|
||||||
|
*
|
||||||
|
* Note: all of these are expected to be called with CurrentMemoryContext
|
||||||
|
* equal to the per-query memory context.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* ExecAssignExprContext
|
||||||
|
*
|
||||||
|
* This initializes the ps_ExprContext field. It is only necessary
|
||||||
|
* to do this for nodes which use ExecQual or ExecProject
|
||||||
|
* because those routines require an econtext. Other nodes that
|
||||||
|
* don't have to evaluate expressions don't need to do this.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ExecAssignExprContext(EState *estate, PlanState *planstate)
|
||||||
|
{
|
||||||
|
planstate->ps_ExprContext = CreateExprContext(estate);
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* ExecAssignResultType
|
* ExecAssignResultType
|
||||||
* ----------------
|
* ----------------
|
||||||
|
@ -367,35 +501,13 @@ ExecAssignProjectionInfo(PlanState *planstate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* ExecFreeProjectionInfo
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ExecFreeProjectionInfo(PlanState *planstate)
|
|
||||||
{
|
|
||||||
ProjectionInfo *projInfo;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get projection info. if NULL then this node has none so we just
|
|
||||||
* return.
|
|
||||||
*/
|
|
||||||
projInfo = planstate->ps_ProjInfo;
|
|
||||||
if (projInfo == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* clean up memory used.
|
|
||||||
*/
|
|
||||||
if (projInfo->pi_tupValue != NULL)
|
|
||||||
pfree(projInfo->pi_tupValue);
|
|
||||||
|
|
||||||
pfree(projInfo);
|
|
||||||
planstate->ps_ProjInfo = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* ExecFreeExprContext
|
* ExecFreeExprContext
|
||||||
|
*
|
||||||
|
* A plan node's ExprContext should be freed explicitly during ExecEndNode
|
||||||
|
* because there may be shutdown callbacks to call. (Other resources made
|
||||||
|
* by the above routines, such as projection info, don't need to be freed
|
||||||
|
* explicitly because they're just memory in the per-query memory context.)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
@ -411,16 +523,8 @@ ExecFreeExprContext(PlanState *planstate)
|
||||||
if (econtext == NULL)
|
if (econtext == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
FreeExprContext(econtext);
|
||||||
* clean up any registered callbacks
|
|
||||||
*/
|
|
||||||
ShutdownExprContext(econtext);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* clean up memory used.
|
|
||||||
*/
|
|
||||||
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
|
|
||||||
pfree(econtext);
|
|
||||||
planstate->ps_ExprContext = NULL;
|
planstate->ps_ExprContext = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,7 +716,8 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX should free indexInfo array here too.
|
* XXX should free indexInfo array here too? Currently we assume that
|
||||||
|
* such stuff will be cleaned up automatically in FreeExecutorState.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -674,16 +779,31 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
|
||||||
for (i = 0; i < numIndices; i++)
|
for (i = 0; i < numIndices; i++)
|
||||||
{
|
{
|
||||||
IndexInfo *indexInfo;
|
IndexInfo *indexInfo;
|
||||||
List *predicate;
|
|
||||||
InsertIndexResult result;
|
InsertIndexResult result;
|
||||||
|
|
||||||
if (relationDescs[i] == NULL)
|
if (relationDescs[i] == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
indexInfo = indexInfoArray[i];
|
indexInfo = indexInfoArray[i];
|
||||||
predicate = indexInfo->ii_PredicateState;
|
|
||||||
if (predicate != NIL)
|
/* Check for partial index */
|
||||||
|
if (indexInfo->ii_Predicate != NIL)
|
||||||
{
|
{
|
||||||
|
List *predicate;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If predicate state not set up yet, create it (in the
|
||||||
|
* estate's per-query context)
|
||||||
|
*/
|
||||||
|
predicate = indexInfo->ii_PredicateState;
|
||||||
|
if (predicate == NIL)
|
||||||
|
{
|
||||||
|
predicate = (List *)
|
||||||
|
ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
|
||||||
|
estate);
|
||||||
|
indexInfo->ii_PredicateState = predicate;
|
||||||
|
}
|
||||||
|
|
||||||
/* Skip this index-update if the predicate isn't satisfied */
|
/* Skip this index-update if the predicate isn't satisfied */
|
||||||
if (!ExecQual(predicate, econtext, false))
|
if (!ExecQual(predicate, econtext, false))
|
||||||
continue;
|
continue;
|
||||||
|
@ -811,6 +931,17 @@ static void
|
||||||
ShutdownExprContext(ExprContext *econtext)
|
ShutdownExprContext(ExprContext *econtext)
|
||||||
{
|
{
|
||||||
ExprContext_CB *ecxt_callback;
|
ExprContext_CB *ecxt_callback;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
|
/* Fast path in normal case where there's nothing to do. */
|
||||||
|
if (econtext->ecxt_callbacks == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call the callbacks in econtext's per-tuple context. This ensures
|
||||||
|
* that any memory they might leak will get cleaned up.
|
||||||
|
*/
|
||||||
|
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call each callback function in reverse registration order.
|
* Call each callback function in reverse registration order.
|
||||||
|
@ -821,4 +952,6 @@ ShutdownExprContext(ExprContext *econtext)
|
||||||
(*ecxt_callback->function) (ecxt_callback->arg);
|
(*ecxt_callback->function) (ecxt_callback->arg);
|
||||||
pfree(ecxt_callback);
|
pfree(ecxt_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.61 2002/12/05 15:50:32 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.62 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -284,7 +284,8 @@ postquel_end(execution_state *es)
|
||||||
if (es->qd->operation != CMD_UTILITY)
|
if (es->qd->operation != CMD_UTILITY)
|
||||||
ExecutorEnd(es->qd);
|
ExecutorEnd(es->qd);
|
||||||
|
|
||||||
pfree(es->qd);
|
FreeQueryDesc(es->qd);
|
||||||
|
|
||||||
es->qd = NULL;
|
es->qd = NULL;
|
||||||
|
|
||||||
es->status = F_EXEC_DONE;
|
es->status = F_EXEC_DONE;
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.100 2002/12/13 19:45:52 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.101 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1392,8 +1392,6 @@ ExecEndAgg(AggState *node)
|
||||||
tuplesort_end(peraggstate->sortstate);
|
tuplesort_end(peraggstate->sortstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecFreeProjectionInfo(&node->ss.ps);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free both the expr contexts.
|
* Free both the expr contexts.
|
||||||
*/
|
*/
|
||||||
|
@ -1401,18 +1399,13 @@ ExecEndAgg(AggState *node)
|
||||||
node->ss.ps.ps_ExprContext = node->tmpcontext;
|
node->ss.ps.ps_ExprContext = node->tmpcontext;
|
||||||
ExecFreeExprContext(&node->ss.ps);
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
|
|
||||||
|
/* clean up tuple table */
|
||||||
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||||
|
|
||||||
MemoryContextDelete(node->aggcontext);
|
MemoryContextDelete(node->aggcontext);
|
||||||
|
|
||||||
outerPlan = outerPlanState(node);
|
outerPlan = outerPlanState(node);
|
||||||
ExecEndNode(outerPlan);
|
ExecEndNode(outerPlan);
|
||||||
|
|
||||||
/* clean up tuple table */
|
|
||||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
|
||||||
if (node->grp_firstTuple != NULL)
|
|
||||||
{
|
|
||||||
heap_freetuple(node->grp_firstTuple);
|
|
||||||
node->grp_firstTuple = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.15 2002/12/13 19:45:52 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.16 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -273,9 +273,8 @@ void
|
||||||
ExecEndFunctionScan(FunctionScanState *node)
|
ExecEndFunctionScan(FunctionScanState *node)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* Free the exprcontext
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&node->ss.ps);
|
|
||||||
ExecFreeExprContext(&node->ss.ps);
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* locate group boundaries.
|
* locate group boundaries.
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.52 2002/12/13 19:45:52 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.53 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -218,19 +218,13 @@ ExecEndGroup(GroupState *node)
|
||||||
{
|
{
|
||||||
PlanState *outerPlan;
|
PlanState *outerPlan;
|
||||||
|
|
||||||
ExecFreeProjectionInfo(&node->ss.ps);
|
|
||||||
ExecFreeExprContext(&node->ss.ps);
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
|
|
||||||
outerPlan = outerPlanState(node);
|
|
||||||
ExecEndNode(outerPlan);
|
|
||||||
|
|
||||||
/* clean up tuple table */
|
/* clean up tuple table */
|
||||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||||
if (node->grp_firstTuple != NULL)
|
|
||||||
{
|
outerPlan = outerPlanState(node);
|
||||||
heap_freetuple(node->grp_firstTuple);
|
ExecEndNode(outerPlan);
|
||||||
node->grp_firstTuple = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.70 2002/12/13 19:45:52 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.71 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -179,10 +179,8 @@ ExecEndHash(HashState *node)
|
||||||
PlanState *outerPlan;
|
PlanState *outerPlan;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free projection info. no need to free result type info because
|
* free exprcontext
|
||||||
* that came from the outer plan...
|
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&node->ps);
|
|
||||||
ExecFreeExprContext(&node->ps);
|
ExecFreeExprContext(&node->ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.44 2002/12/13 19:45:52 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.45 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -456,17 +456,10 @@ ExecEndHashJoin(HashJoinState *node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* Free the exprcontext
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&node->js.ps);
|
|
||||||
ExecFreeExprContext(&node->js.ps);
|
ExecFreeExprContext(&node->js.ps);
|
||||||
|
|
||||||
/*
|
|
||||||
* clean up subtrees
|
|
||||||
*/
|
|
||||||
ExecEndNode(outerPlanState(node));
|
|
||||||
ExecEndNode(innerPlanState(node));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
*/
|
*/
|
||||||
|
@ -474,6 +467,11 @@ ExecEndHashJoin(HashJoinState *node)
|
||||||
ExecClearTuple(node->hj_OuterTupleSlot);
|
ExecClearTuple(node->hj_OuterTupleSlot);
|
||||||
ExecClearTuple(node->hj_HashTupleSlot);
|
ExecClearTuple(node->hj_HashTupleSlot);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clean up subtrees
|
||||||
|
*/
|
||||||
|
ExecEndNode(outerPlanState(node));
|
||||||
|
ExecEndNode(innerPlanState(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.74 2002/12/13 19:45:52 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.75 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -399,44 +399,38 @@ ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecEndIndexScan
|
* ExecEndIndexScan
|
||||||
*
|
|
||||||
* old comments
|
|
||||||
* Releases any storage allocated through C routines.
|
|
||||||
* Returns nothing.
|
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndIndexScan(IndexScanState *node)
|
ExecEndIndexScan(IndexScanState *node)
|
||||||
{
|
{
|
||||||
ExprState ***runtimeKeyInfo;
|
|
||||||
ScanKey *scanKeys;
|
|
||||||
int *numScanKeys;
|
|
||||||
int numIndices;
|
int numIndices;
|
||||||
Relation relation;
|
|
||||||
RelationPtr indexRelationDescs;
|
RelationPtr indexRelationDescs;
|
||||||
IndexScanDescPtr indexScanDescs;
|
IndexScanDescPtr indexScanDescs;
|
||||||
|
Relation relation;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
runtimeKeyInfo = node->iss_RuntimeKeyInfo;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* extract information from the node
|
* extract information from the node
|
||||||
*/
|
*/
|
||||||
numIndices = node->iss_NumIndices;
|
numIndices = node->iss_NumIndices;
|
||||||
scanKeys = node->iss_ScanKeys;
|
|
||||||
numScanKeys = node->iss_NumScanKeys;
|
|
||||||
indexRelationDescs = node->iss_RelationDescs;
|
indexRelationDescs = node->iss_RelationDescs;
|
||||||
indexScanDescs = node->iss_ScanDescs;
|
indexScanDescs = node->iss_ScanDescs;
|
||||||
relation = node->ss.ss_currentRelation;
|
relation = node->ss.ss_currentRelation;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* Free the exprcontext(s)
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&node->ss.ps);
|
|
||||||
ExecFreeExprContext(&node->ss.ps);
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
if (node->iss_RuntimeContext)
|
if (node->iss_RuntimeContext)
|
||||||
FreeExprContext(node->iss_RuntimeContext);
|
FreeExprContext(node->iss_RuntimeContext);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clear out tuple table slots
|
||||||
|
*/
|
||||||
|
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||||
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close the index relations
|
* close the index relations
|
||||||
*/
|
*/
|
||||||
|
@ -458,36 +452,6 @@ ExecEndIndexScan(IndexScanState *node)
|
||||||
* locking, however.)
|
* locking, however.)
|
||||||
*/
|
*/
|
||||||
heap_close(relation, NoLock);
|
heap_close(relation, NoLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* free the scan keys used in scanning the indices
|
|
||||||
*/
|
|
||||||
for (i = 0; i < numIndices; i++)
|
|
||||||
{
|
|
||||||
if (scanKeys[i] != NULL)
|
|
||||||
pfree(scanKeys[i]);
|
|
||||||
}
|
|
||||||
pfree(scanKeys);
|
|
||||||
pfree(numScanKeys);
|
|
||||||
|
|
||||||
if (runtimeKeyInfo)
|
|
||||||
{
|
|
||||||
for (i = 0; i < numIndices; i++)
|
|
||||||
{
|
|
||||||
if (runtimeKeyInfo[i] != NULL)
|
|
||||||
pfree(runtimeKeyInfo[i]);
|
|
||||||
}
|
|
||||||
pfree(runtimeKeyInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* clear out tuple table slots
|
|
||||||
*/
|
|
||||||
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
|
||||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
|
||||||
pfree(node->iss_RelationDescs);
|
|
||||||
pfree(node->iss_ScanDescs);
|
|
||||||
pfree(node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.13 2002/12/13 19:45:54 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.14 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -349,10 +349,10 @@ ExecEndLimit(LimitState *node)
|
||||||
{
|
{
|
||||||
ExecFreeExprContext(&node->ps);
|
ExecFreeExprContext(&node->ps);
|
||||||
|
|
||||||
ExecEndNode(outerPlanState(node));
|
|
||||||
|
|
||||||
/* clean up tuple table */
|
/* clean up tuple table */
|
||||||
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||||
|
|
||||||
|
ExecEndNode(outerPlanState(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.39 2002/12/05 15:50:33 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.40 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -196,17 +196,17 @@ ExecEndMaterial(MaterialState *node)
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||||
|
|
||||||
/*
|
|
||||||
* shut down the subplan
|
|
||||||
*/
|
|
||||||
ExecEndNode(outerPlanState(node));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release tuplestore resources
|
* Release tuplestore resources
|
||||||
*/
|
*/
|
||||||
if (node->tuplestorestate != NULL)
|
if (node->tuplestorestate != NULL)
|
||||||
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
|
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
|
||||||
node->tuplestorestate = NULL;
|
node->tuplestorestate = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* shut down the subplan
|
||||||
|
*/
|
||||||
|
ExecEndNode(outerPlanState(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.54 2002/12/13 19:45:54 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.55 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1551,23 +1551,22 @@ ExecEndMergeJoin(MergeJoinState *node)
|
||||||
"ending node processing");
|
"ending node processing");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* Free the exprcontext
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&node->js.ps);
|
|
||||||
ExecFreeExprContext(&node->js.ps);
|
ExecFreeExprContext(&node->js.ps);
|
||||||
|
|
||||||
/*
|
|
||||||
* shut down the subplans
|
|
||||||
*/
|
|
||||||
ExecEndNode(innerPlanState(node));
|
|
||||||
ExecEndNode(outerPlanState(node));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
|
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
|
||||||
ExecClearTuple(node->mj_MarkedTupleSlot);
|
ExecClearTuple(node->mj_MarkedTupleSlot);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* shut down the subplans
|
||||||
|
*/
|
||||||
|
ExecEndNode(innerPlanState(node));
|
||||||
|
ExecEndNode(outerPlanState(node));
|
||||||
|
|
||||||
MJ1_printf("ExecEndMergeJoin: %s\n",
|
MJ1_printf("ExecEndMergeJoin: %s\n",
|
||||||
"node processing ended");
|
"node processing ended");
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.28 2002/12/13 19:45:55 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.29 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -364,22 +364,21 @@ ExecEndNestLoop(NestLoopState *node)
|
||||||
"ending node processing");
|
"ending node processing");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info
|
* Free the exprcontext
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&node->js.ps);
|
|
||||||
ExecFreeExprContext(&node->js.ps);
|
ExecFreeExprContext(&node->js.ps);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clean out the tuple table
|
||||||
|
*/
|
||||||
|
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close down subplans
|
* close down subplans
|
||||||
*/
|
*/
|
||||||
ExecEndNode(outerPlanState(node));
|
ExecEndNode(outerPlanState(node));
|
||||||
ExecEndNode(innerPlanState(node));
|
ExecEndNode(innerPlanState(node));
|
||||||
|
|
||||||
/*
|
|
||||||
* clean out the tuple table
|
|
||||||
*/
|
|
||||||
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
|
|
||||||
|
|
||||||
NL1_printf("ExecEndNestLoop: %s\n",
|
NL1_printf("ExecEndNestLoop: %s\n",
|
||||||
"node processing ended");
|
"node processing ended");
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.23 2002/12/13 19:45:55 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.24 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -248,9 +248,8 @@ void
|
||||||
ExecEndResult(ResultState *node)
|
ExecEndResult(ResultState *node)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Free the projection info
|
* Free the exprcontext
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&node->ps);
|
|
||||||
ExecFreeExprContext(&node->ps);
|
ExecFreeExprContext(&node->ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.40 2002/12/13 19:45:55 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.41 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -264,22 +264,21 @@ ExecEndSeqScan(SeqScanState *node)
|
||||||
scanDesc = node->ss_currentScanDesc;
|
scanDesc = node->ss_currentScanDesc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* Free the exprcontext
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&node->ps);
|
|
||||||
ExecFreeExprContext(&node->ps);
|
ExecFreeExprContext(&node->ps);
|
||||||
|
|
||||||
/*
|
|
||||||
* close heap scan
|
|
||||||
*/
|
|
||||||
heap_endscan(scanDesc);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||||
ExecClearTuple(node->ss_ScanTupleSlot);
|
ExecClearTuple(node->ss_ScanTupleSlot);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* close heap scan
|
||||||
|
*/
|
||||||
|
heap_endscan(scanDesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close the heap relation.
|
* close the heap relation.
|
||||||
*
|
*
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.7 2002/12/05 15:50:33 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.8 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -301,9 +301,9 @@ ExecEndSetOp(SetOpState *node)
|
||||||
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||||
node->ps.ps_OuterTupleSlot = NULL;
|
node->ps.ps_OuterTupleSlot = NULL;
|
||||||
|
|
||||||
ExecEndNode(outerPlanState(node));
|
|
||||||
|
|
||||||
MemoryContextDelete(node->tempContext);
|
MemoryContextDelete(node->tempContext);
|
||||||
|
|
||||||
|
ExecEndNode(outerPlanState(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.41 2002/12/05 15:50:33 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.42 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -284,11 +284,6 @@ ExecEndSort(SortState *node)
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||||
|
|
||||||
/*
|
|
||||||
* shut down the subplan
|
|
||||||
*/
|
|
||||||
ExecEndNode(outerPlanState(node));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release tuplesort resources
|
* Release tuplesort resources
|
||||||
*/
|
*/
|
||||||
|
@ -296,6 +291,11 @@ ExecEndSort(SortState *node)
|
||||||
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
|
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
|
||||||
node->tuplesortstate = NULL;
|
node->tuplesortstate = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* shut down the subplan
|
||||||
|
*/
|
||||||
|
ExecEndNode(outerPlanState(node));
|
||||||
|
|
||||||
SO1_printf("ExecEndSort: %s\n",
|
SO1_printf("ExecEndSort: %s\n",
|
||||||
"sort node shutdown");
|
"sort node shutdown");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.38 2002/12/14 00:17:50 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.39 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -47,9 +47,10 @@ ExecSubPlan(SubPlanState *node,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We are probably in a short-lived expression-evaluation context.
|
* We are probably in a short-lived expression-evaluation context.
|
||||||
* Switch to longer-lived per-query context.
|
* Switch to the child plan's per-query context for manipulating its
|
||||||
|
* chgParam, calling ExecProcNode on it, etc.
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
|
oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
|
||||||
|
|
||||||
if (subplan->setParam != NIL)
|
if (subplan->setParam != NIL)
|
||||||
elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
|
elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
|
||||||
|
@ -132,10 +133,13 @@ ExecSubPlan(SubPlanState *node,
|
||||||
* ExecProcNode() call. node->curTuple keeps track of the
|
* ExecProcNode() call. node->curTuple keeps track of the
|
||||||
* copied tuple for eventual freeing.
|
* copied tuple for eventual freeing.
|
||||||
*/
|
*/
|
||||||
|
MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
|
||||||
tup = heap_copytuple(tup);
|
tup = heap_copytuple(tup);
|
||||||
if (node->curTuple)
|
if (node->curTuple)
|
||||||
heap_freetuple(node->curTuple);
|
heap_freetuple(node->curTuple);
|
||||||
node->curTuple = tup;
|
node->curTuple = tup;
|
||||||
|
MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
|
||||||
|
|
||||||
result = heap_getattr(tup, col, tdesc, isNull);
|
result = heap_getattr(tup, col, tdesc, isNull);
|
||||||
/* keep scanning subplan to make sure there's only one tuple */
|
/* keep scanning subplan to make sure there's only one tuple */
|
||||||
continue;
|
continue;
|
||||||
|
@ -295,6 +299,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
|
||||||
{
|
{
|
||||||
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
|
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
|
||||||
EState *sp_estate;
|
EState *sp_estate;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do access checking on the rangetable entries in the subquery.
|
* Do access checking on the rangetable entries in the subquery.
|
||||||
|
@ -303,15 +308,23 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
|
||||||
ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
|
ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize state
|
* initialize my state
|
||||||
*/
|
*/
|
||||||
node->needShutdown = false;
|
node->needShutdown = false;
|
||||||
node->curTuple = NULL;
|
node->curTuple = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create an EState for the subplan
|
* create an EState for the subplan
|
||||||
|
*
|
||||||
|
* The subquery needs its own EState because it has its own rangetable.
|
||||||
|
* It shares our Param ID space, however. XXX if rangetable access were
|
||||||
|
* done differently, the subquery could share our EState, which would
|
||||||
|
* eliminate some thrashing about in this module...
|
||||||
*/
|
*/
|
||||||
sp_estate = CreateExecutorState();
|
sp_estate = CreateExecutorState();
|
||||||
|
node->sub_estate = sp_estate;
|
||||||
|
|
||||||
|
oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
|
||||||
|
|
||||||
sp_estate->es_range_table = subplan->rtable;
|
sp_estate->es_range_table = subplan->rtable;
|
||||||
sp_estate->es_param_list_info = estate->es_param_list_info;
|
sp_estate->es_param_list_info = estate->es_param_list_info;
|
||||||
|
@ -322,12 +335,14 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
|
||||||
sp_estate->es_instrument = estate->es_instrument;
|
sp_estate->es_instrument = estate->es_instrument;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start up the subplan
|
* Start up the subplan (this is a very cut-down form of InitPlan())
|
||||||
*/
|
*/
|
||||||
node->planstate = ExecInitNode(subplan->plan, sp_estate);
|
node->planstate = ExecInitNode(subplan->plan, sp_estate);
|
||||||
|
|
||||||
node->needShutdown = true; /* now we need to shutdown the subplan */
|
node->needShutdown = true; /* now we need to shutdown the subplan */
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this plan is un-correlated or undirect correlated one and want
|
* If this plan is un-correlated or undirect correlated one and want
|
||||||
* to set params for parent plan then prepare parameters.
|
* to set params for parent plan then prepare parameters.
|
||||||
|
@ -376,10 +391,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We are probably in a short-lived expression-evaluation context.
|
* Must switch to child query's per-query memory context.
|
||||||
* Switch to longer-lived per-query context.
|
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
|
oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
|
||||||
|
|
||||||
if (subLinkType == ANY_SUBLINK ||
|
if (subLinkType == ANY_SUBLINK ||
|
||||||
subLinkType == ALL_SUBLINK)
|
subLinkType == ALL_SUBLINK)
|
||||||
|
@ -415,15 +429,18 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
|
||||||
found = true;
|
found = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to copy the subplan's tuple in case any of the params
|
* We need to copy the subplan's tuple into our own context,
|
||||||
* are pass-by-ref type --- the pointers stored in the param
|
* in case any of the params are pass-by-ref type --- the pointers
|
||||||
* structs will point at this copied tuple! node->curTuple keeps
|
* stored in the param structs will point at this copied tuple!
|
||||||
* track of the copied tuple for eventual freeing.
|
* node->curTuple keeps track of the copied tuple for eventual
|
||||||
|
* freeing.
|
||||||
*/
|
*/
|
||||||
|
MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
|
||||||
tup = heap_copytuple(tup);
|
tup = heap_copytuple(tup);
|
||||||
if (node->curTuple)
|
if (node->curTuple)
|
||||||
heap_freetuple(node->curTuple);
|
heap_freetuple(node->curTuple);
|
||||||
node->curTuple = tup;
|
node->curTuple = tup;
|
||||||
|
MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
|
||||||
|
|
||||||
foreach(lst, subplan->setParam)
|
foreach(lst, subplan->setParam)
|
||||||
{
|
{
|
||||||
|
@ -460,7 +477,10 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
|
||||||
|
|
||||||
if (planstate->plan->extParam == NULL) /* un-correlated ... */
|
if (planstate->plan->extParam == NULL) /* un-correlated ... */
|
||||||
{
|
{
|
||||||
ExecEndNode(planstate);
|
ExecEndPlan(planstate, node->sub_estate);
|
||||||
|
/* mustn't free context while still in it... */
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
FreeExecutorState(node->sub_estate);
|
||||||
node->needShutdown = false;
|
node->needShutdown = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,7 +496,12 @@ ExecEndSubPlan(SubPlanState *node)
|
||||||
{
|
{
|
||||||
if (node->needShutdown)
|
if (node->needShutdown)
|
||||||
{
|
{
|
||||||
ExecEndNode(node->planstate);
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
|
oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
|
||||||
|
ExecEndPlan(node->planstate, node->sub_estate);
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
FreeExecutorState(node->sub_estate);
|
||||||
node->needShutdown = false;
|
node->needShutdown = false;
|
||||||
}
|
}
|
||||||
if (node->curTuple)
|
if (node->curTuple)
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.15 2002/12/13 19:45:55 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.16 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -53,6 +53,7 @@ SubqueryNext(SubqueryScanState *node)
|
||||||
EState *estate;
|
EState *estate;
|
||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get information from the estate and scan state
|
* get information from the estate and scan state
|
||||||
|
@ -66,12 +67,17 @@ SubqueryNext(SubqueryScanState *node)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get the next tuple from the sub-query
|
* Get the next tuple from the sub-query. We have to be careful to
|
||||||
|
* run it in its appropriate memory context.
|
||||||
*/
|
*/
|
||||||
node->sss_SubEState->es_direction = direction;
|
node->sss_SubEState->es_direction = direction;
|
||||||
|
|
||||||
|
oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
|
||||||
|
|
||||||
slot = ExecProcNode(node->subplan);
|
slot = ExecProcNode(node->subplan);
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
node->ss.ss_ScanTupleSlot = slot;
|
node->ss.ss_ScanTupleSlot = slot;
|
||||||
|
|
||||||
return slot;
|
return slot;
|
||||||
|
@ -106,6 +112,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
|
||||||
SubqueryScanState *subquerystate;
|
SubqueryScanState *subquerystate;
|
||||||
RangeTblEntry *rte;
|
RangeTblEntry *rte;
|
||||||
EState *sp_estate;
|
EState *sp_estate;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SubqueryScan should not have any "normal" children.
|
* SubqueryScan should not have any "normal" children.
|
||||||
|
@ -152,9 +159,17 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
|
||||||
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
|
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
|
||||||
Assert(rte->rtekind == RTE_SUBQUERY);
|
Assert(rte->rtekind == RTE_SUBQUERY);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The subquery needs its own EState because it has its own rangetable.
|
||||||
|
* It shares our Param ID space, however. XXX if rangetable access were
|
||||||
|
* done differently, the subquery could share our EState, which would
|
||||||
|
* eliminate some thrashing about in this module...
|
||||||
|
*/
|
||||||
sp_estate = CreateExecutorState();
|
sp_estate = CreateExecutorState();
|
||||||
subquerystate->sss_SubEState = sp_estate;
|
subquerystate->sss_SubEState = sp_estate;
|
||||||
|
|
||||||
|
oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
|
||||||
|
|
||||||
sp_estate->es_range_table = rte->subquery->rtable;
|
sp_estate->es_range_table = rte->subquery->rtable;
|
||||||
sp_estate->es_param_list_info = estate->es_param_list_info;
|
sp_estate->es_param_list_info = estate->es_param_list_info;
|
||||||
sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
|
sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
|
||||||
|
@ -163,8 +178,13 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
|
||||||
sp_estate->es_snapshot = estate->es_snapshot;
|
sp_estate->es_snapshot = estate->es_snapshot;
|
||||||
sp_estate->es_instrument = estate->es_instrument;
|
sp_estate->es_instrument = estate->es_instrument;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start up the subplan (this is a very cut-down form of InitPlan())
|
||||||
|
*/
|
||||||
subquerystate->subplan = ExecInitNode(node->subplan, sp_estate);
|
subquerystate->subplan = ExecInitNode(node->subplan, sp_estate);
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
subquerystate->ss.ss_ScanTupleSlot = NULL;
|
subquerystate->ss.ss_ScanTupleSlot = NULL;
|
||||||
subquerystate->ss.ps.ps_TupFromTlist = false;
|
subquerystate->ss.ps.ps_TupFromTlist = false;
|
||||||
|
|
||||||
|
@ -197,10 +217,11 @@ ExecCountSlotsSubqueryScan(SubqueryScan *node)
|
||||||
void
|
void
|
||||||
ExecEndSubqueryScan(SubqueryScanState *node)
|
ExecEndSubqueryScan(SubqueryScanState *node)
|
||||||
{
|
{
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* Free the exprcontext
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&node->ss.ps);
|
|
||||||
ExecFreeExprContext(&node->ss.ps);
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -211,15 +232,13 @@ ExecEndSubqueryScan(SubqueryScanState *node)
|
||||||
/*
|
/*
|
||||||
* close down subquery
|
* close down subquery
|
||||||
*/
|
*/
|
||||||
ExecEndNode(node->subplan);
|
oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
|
||||||
|
|
||||||
/*
|
ExecEndPlan(node->subplan, node->sss_SubEState);
|
||||||
* clean up subquery's tuple table
|
|
||||||
*/
|
|
||||||
node->ss.ss_ScanTupleSlot = NULL;
|
|
||||||
ExecDropTupleTable(node->sss_SubEState->es_tupleTable, true);
|
|
||||||
|
|
||||||
/* XXX we seem to be leaking the sub-EState... */
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
|
FreeExecutorState(node->sss_SubEState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
|
@ -232,12 +251,17 @@ void
|
||||||
ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
|
ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
estate = node->ss.ps.state;
|
estate = node->ss.ps.state;
|
||||||
|
|
||||||
|
oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ExecReScan doesn't know about my subplan, so I have to do
|
* ExecReScan doesn't know about my subplan, so I have to do
|
||||||
* changed-parameter signaling myself.
|
* changed-parameter signaling myself. This is just as well,
|
||||||
|
* because the subplan has its own memory context in which its
|
||||||
|
* chgParam lists live.
|
||||||
*/
|
*/
|
||||||
if (node->ss.ps.chgParam != NULL)
|
if (node->ss.ps.chgParam != NULL)
|
||||||
SetChangedParamList(node->subplan, node->ss.ps.chgParam);
|
SetChangedParamList(node->subplan, node->ss.ps.chgParam);
|
||||||
|
@ -249,5 +273,7 @@ ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
|
||||||
if (node->subplan->chgParam == NULL)
|
if (node->subplan->chgParam == NULL)
|
||||||
ExecReScan(node->subplan, NULL);
|
ExecReScan(node->subplan, NULL);
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
node->ss.ss_ScanTupleSlot = NULL;
|
node->ss.ss_ScanTupleSlot = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.29 2002/12/13 19:45:56 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.30 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -278,19 +278,8 @@ void
|
||||||
ExecEndTidScan(TidScanState *node)
|
ExecEndTidScan(TidScanState *node)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* extract information from the node
|
* Free the exprcontext
|
||||||
*/
|
*/
|
||||||
if (node && node->tss_TidList)
|
|
||||||
pfree(node->tss_TidList);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Free the projection info and the scan attribute info
|
|
||||||
*
|
|
||||||
* Note: we don't ExecFreeResultType(scanstate) because the rule manager
|
|
||||||
* depends on the tupType returned by ExecMain(). So for now, this is
|
|
||||||
* freed at end-transaction time. -cim 6/2/91
|
|
||||||
*/
|
|
||||||
ExecFreeProjectionInfo(&node->ss.ps);
|
|
||||||
ExecFreeExprContext(&node->ss.ps);
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.35 2002/12/05 15:50:34 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.36 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -194,15 +194,10 @@ ExecEndUnique(UniqueState *node)
|
||||||
{
|
{
|
||||||
/* clean up tuple table */
|
/* clean up tuple table */
|
||||||
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||||
if (node->priorTuple != NULL)
|
|
||||||
{
|
|
||||||
heap_freetuple(node->priorTuple);
|
|
||||||
node->priorTuple = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExecEndNode(outerPlanState(node));
|
|
||||||
|
|
||||||
MemoryContextDelete(node->tempContext);
|
MemoryContextDelete(node->tempContext);
|
||||||
|
|
||||||
|
ExecEndNode(outerPlanState(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.79 2002/12/05 15:50:34 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.80 2002/12/15 16:17:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1287,23 +1287,23 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
|
||||||
elog(FATAL, "SPI_select: # of processed tuples check failed");
|
elog(FATAL, "SPI_select: # of processed tuples check failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutorEnd(queryDesc);
|
|
||||||
|
|
||||||
#ifdef SPI_EXECUTOR_STATS
|
|
||||||
if (ShowExecutorStats)
|
|
||||||
ShowUsage("SPI EXECUTOR STATS");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (dest == SPI)
|
if (dest == SPI)
|
||||||
{
|
{
|
||||||
SPI_processed = _SPI_current->processed;
|
SPI_processed = _SPI_current->processed;
|
||||||
SPI_lastoid = save_lastoid;
|
SPI_lastoid = save_lastoid;
|
||||||
SPI_tuptable = _SPI_current->tuptable;
|
SPI_tuptable = _SPI_current->tuptable;
|
||||||
}
|
}
|
||||||
queryDesc->dest = dest;
|
|
||||||
|
ExecutorEnd(queryDesc);
|
||||||
|
|
||||||
|
FreeQueryDesc(queryDesc);
|
||||||
|
|
||||||
|
#ifdef SPI_EXECUTOR_STATS
|
||||||
|
if (ShowExecutorStats)
|
||||||
|
ShowUsage("SPI EXECUTOR STATS");
|
||||||
|
#endif
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.128 2002/12/13 19:45:56 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.129 2002/12/15 16:17:49 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1132,7 +1132,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
ScanKeyData entry[1];
|
ScanKeyData entry[1];
|
||||||
Form_pg_amop aform;
|
Form_pg_amop aform;
|
||||||
ExprContext *econtext;
|
EState *estate;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/* First try the equal() test */
|
/* First try the equal() test */
|
||||||
if (equal((Node *) predicate, clause))
|
if (equal((Node *) predicate, clause))
|
||||||
|
@ -1267,20 +1268,33 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 5. Evaluate the test
|
* 5. Evaluate the test. For this we need an EState.
|
||||||
*/
|
*/
|
||||||
|
estate = CreateExecutorState();
|
||||||
|
|
||||||
|
/* We can use the estate's working context to avoid memory leaks. */
|
||||||
|
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
|
||||||
|
|
||||||
|
/* Build expression tree */
|
||||||
test_expr = make_opclause(test_op,
|
test_expr = make_opclause(test_op,
|
||||||
BOOLOID,
|
BOOLOID,
|
||||||
false,
|
false,
|
||||||
(Expr *) clause_const,
|
(Expr *) clause_const,
|
||||||
(Expr *) pred_const);
|
(Expr *) pred_const);
|
||||||
set_opfuncid((OpExpr *) test_expr);
|
|
||||||
test_exprstate = ExecInitExpr(test_expr, NULL);
|
|
||||||
|
|
||||||
econtext = MakeExprContext(NULL, CurrentMemoryContext);
|
/* Prepare it for execution */
|
||||||
test_result = ExecEvalExprSwitchContext(test_exprstate, econtext,
|
test_exprstate = ExecPrepareExpr(test_expr, estate);
|
||||||
|
|
||||||
|
/* And execute it. */
|
||||||
|
test_result = ExecEvalExprSwitchContext(test_exprstate,
|
||||||
|
GetPerTupleExprContext(estate),
|
||||||
&isNull, NULL);
|
&isNull, NULL);
|
||||||
FreeExprContext(econtext);
|
|
||||||
|
/* Get back to outer memory context */
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
|
/* Release all the junk we just created */
|
||||||
|
FreeExecutorState(estate);
|
||||||
|
|
||||||
if (isNull)
|
if (isNull)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.119 2002/12/14 00:17:59 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.120 2002/12/15 16:17:50 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
|
@ -1684,7 +1684,8 @@ evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
|
||||||
bool has_null_input = false;
|
bool has_null_input = false;
|
||||||
FuncExpr *newexpr;
|
FuncExpr *newexpr;
|
||||||
ExprState *newexprstate;
|
ExprState *newexprstate;
|
||||||
ExprContext *econtext;
|
EState *estate;
|
||||||
|
MemoryContext oldcontext;
|
||||||
Datum const_val;
|
Datum const_val;
|
||||||
bool const_is_null;
|
bool const_is_null;
|
||||||
List *arg;
|
List *arg;
|
||||||
|
@ -1729,7 +1730,14 @@ evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
|
||||||
*
|
*
|
||||||
* We use the executor's routine ExecEvalExpr() to avoid duplication of
|
* We use the executor's routine ExecEvalExpr() to avoid duplication of
|
||||||
* code and ensure we get the same result as the executor would get.
|
* code and ensure we get the same result as the executor would get.
|
||||||
*
|
* To use the executor, we need an EState.
|
||||||
|
*/
|
||||||
|
estate = CreateExecutorState();
|
||||||
|
|
||||||
|
/* We can use the estate's working context to avoid memory leaks. */
|
||||||
|
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
|
||||||
|
|
||||||
|
/*
|
||||||
* Build a new FuncExpr node containing the already-simplified arguments.
|
* Build a new FuncExpr node containing the already-simplified arguments.
|
||||||
*/
|
*/
|
||||||
newexpr = makeNode(FuncExpr);
|
newexpr = makeNode(FuncExpr);
|
||||||
|
@ -1739,27 +1747,35 @@ evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
|
||||||
newexpr->funcformat = COERCE_EXPLICIT_CALL; /* doesn't matter */
|
newexpr->funcformat = COERCE_EXPLICIT_CALL; /* doesn't matter */
|
||||||
newexpr->args = args;
|
newexpr->args = args;
|
||||||
|
|
||||||
/* Get info needed about result datatype */
|
/*
|
||||||
get_typlenbyval(result_typeid, &resultTypLen, &resultTypByVal);
|
* Prepare it for execution.
|
||||||
|
*/
|
||||||
|
newexprstate = ExecPrepareExpr((Expr *) newexpr, estate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It is OK to use a dummy econtext because none of the
|
* And evaluate it.
|
||||||
|
*
|
||||||
|
* It is OK to use a default econtext because none of the
|
||||||
* ExecEvalExpr() code used in this situation will use econtext. That
|
* ExecEvalExpr() code used in this situation will use econtext. That
|
||||||
* might seem fortuitous, but it's not so unreasonable --- a constant
|
* might seem fortuitous, but it's not so unreasonable --- a constant
|
||||||
* expression does not depend on context, by definition, n'est ce pas?
|
* expression does not depend on context, by definition, n'est ce pas?
|
||||||
*/
|
*/
|
||||||
econtext = MakeExprContext(NULL, CurrentMemoryContext);
|
const_val = ExecEvalExprSwitchContext(newexprstate,
|
||||||
|
GetPerTupleExprContext(estate),
|
||||||
newexprstate = ExecInitExpr((Expr *) newexpr, NULL);
|
|
||||||
|
|
||||||
const_val = ExecEvalExprSwitchContext(newexprstate, econtext,
|
|
||||||
&const_is_null, NULL);
|
&const_is_null, NULL);
|
||||||
|
|
||||||
|
/* Get info needed about result datatype */
|
||||||
|
get_typlenbyval(result_typeid, &resultTypLen, &resultTypByVal);
|
||||||
|
|
||||||
|
/* Get back to outer memory context */
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
/* Must copy result out of sub-context used by expression eval */
|
/* Must copy result out of sub-context used by expression eval */
|
||||||
if (!const_is_null)
|
if (!const_is_null)
|
||||||
const_val = datumCopy(const_val, resultTypByVal, resultTypLen);
|
const_val = datumCopy(const_val, resultTypByVal, resultTypLen);
|
||||||
|
|
||||||
FreeExprContext(econtext);
|
/* Release all the junk we just created */
|
||||||
|
FreeExecutorState(estate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make the constant result node.
|
* Make the constant result node.
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.57 2002/12/05 15:50:35 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.58 2002/12/15 16:17:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -52,6 +52,18 @@ CreateQueryDesc(Query *parsetree,
|
||||||
return qd;
|
return qd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FreeQueryDesc
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
FreeQueryDesc(QueryDesc *qdesc)
|
||||||
|
{
|
||||||
|
/* Can't be a live query */
|
||||||
|
Assert(qdesc->estate == NULL);
|
||||||
|
/* Only the QueryDesc itself need be freed */
|
||||||
|
pfree(qdesc);
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* PreparePortal
|
* PreparePortal
|
||||||
* ----------------
|
* ----------------
|
||||||
|
@ -152,9 +164,8 @@ ProcessQuery(Query *parsetree,
|
||||||
* QueryDesc */
|
* QueryDesc */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We stay in portal's memory context for now, so that query desc,
|
* We stay in portal's memory context for now, so that query desc
|
||||||
* exec state, and plan startup info are also allocated in the portal
|
* is also allocated in the portal context.
|
||||||
* context.
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,4 +242,6 @@ ProcessQuery(Query *parsetree,
|
||||||
* Now, we close down all the scans and free allocated resources.
|
* Now, we close down all the scans and free allocated resources.
|
||||||
*/
|
*/
|
||||||
ExecutorEnd(queryDesc);
|
ExecutorEnd(queryDesc);
|
||||||
|
|
||||||
|
FreeQueryDesc(queryDesc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: execdesc.h,v 1.21 2002/12/05 15:50:36 tgl Exp $
|
* $Id: execdesc.h,v 1.22 2002/12/15 16:17:54 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -50,4 +50,6 @@ extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
|
||||||
ParamListInfo params,
|
ParamListInfo params,
|
||||||
bool doInstrument);
|
bool doInstrument);
|
||||||
|
|
||||||
|
extern void FreeQueryDesc(QueryDesc *qdesc);
|
||||||
|
|
||||||
#endif /* EXECDESC_H */
|
#endif /* EXECDESC_H */
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: executor.h,v 1.83 2002/12/14 00:17:59 tgl Exp $
|
* $Id: executor.h,v 1.84 2002/12/15 16:17:54 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -54,8 +54,8 @@ extern void ExecutorStart(QueryDesc *queryDesc);
|
||||||
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
|
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
|
||||||
ScanDirection direction, long count);
|
ScanDirection direction, long count);
|
||||||
extern void ExecutorEnd(QueryDesc *queryDesc);
|
extern void ExecutorEnd(QueryDesc *queryDesc);
|
||||||
extern EState *CreateExecutorState(void);
|
|
||||||
extern void ExecCheckRTPerms(List *rangeTable, CmdType operation);
|
extern void ExecCheckRTPerms(List *rangeTable, CmdType operation);
|
||||||
|
extern void ExecEndPlan(PlanState *planstate, EState *estate);
|
||||||
extern void ExecConstraints(const char *caller, ResultRelInfo *resultRelInfo,
|
extern void ExecConstraints(const char *caller, ResultRelInfo *resultRelInfo,
|
||||||
TupleTableSlot *slot, EState *estate);
|
TupleTableSlot *slot, EState *estate);
|
||||||
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
|
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
|
||||||
|
@ -93,6 +93,7 @@ extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econt
|
||||||
bool *isNull, ExprDoneCond *isDone);
|
bool *isNull, ExprDoneCond *isDone);
|
||||||
extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
|
extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
|
||||||
extern SubPlanState *ExecInitExprInitPlan(SubPlan *node, PlanState *parent);
|
extern SubPlanState *ExecInitExprInitPlan(SubPlan *node, PlanState *parent);
|
||||||
|
extern ExprState *ExecPrepareExpr(Expr *node, EState *estate);
|
||||||
extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
|
extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
|
||||||
extern int ExecTargetListLength(List *targetlist);
|
extern int ExecTargetListLength(List *targetlist);
|
||||||
extern int ExecCleanTargetListLength(List *targetlist);
|
extern int ExecCleanTargetListLength(List *targetlist);
|
||||||
|
@ -157,23 +158,9 @@ extern void end_tup_output(TupOutputState *tstate);
|
||||||
/*
|
/*
|
||||||
* prototypes from functions in execUtils.c
|
* prototypes from functions in execUtils.c
|
||||||
*/
|
*/
|
||||||
extern void ResetTupleCount(void);
|
extern EState *CreateExecutorState(void);
|
||||||
extern void ExecAssignExprContext(EState *estate, PlanState *planstate);
|
extern void FreeExecutorState(EState *estate);
|
||||||
extern void ExecAssignResultType(PlanState *planstate,
|
extern ExprContext *CreateExprContext(EState *estate);
|
||||||
TupleDesc tupDesc, bool shouldFree);
|
|
||||||
extern void ExecAssignResultTypeFromOuterPlan(PlanState *planstate);
|
|
||||||
extern void ExecAssignResultTypeFromTL(PlanState *planstate);
|
|
||||||
extern TupleDesc ExecGetResultType(PlanState *planstate);
|
|
||||||
extern void ExecAssignProjectionInfo(PlanState *planstate);
|
|
||||||
extern void ExecFreeProjectionInfo(PlanState *planstate);
|
|
||||||
extern void ExecFreeExprContext(PlanState *planstate);
|
|
||||||
extern TupleDesc ExecGetScanType(ScanState *scanstate);
|
|
||||||
extern void ExecAssignScanType(ScanState *scanstate,
|
|
||||||
TupleDesc tupDesc, bool shouldFree);
|
|
||||||
extern void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate);
|
|
||||||
|
|
||||||
extern ExprContext *MakeExprContext(TupleTableSlot *slot,
|
|
||||||
MemoryContext queryContext);
|
|
||||||
extern void FreeExprContext(ExprContext *econtext);
|
extern void FreeExprContext(ExprContext *econtext);
|
||||||
|
|
||||||
#define ResetExprContext(econtext) \
|
#define ResetExprContext(econtext) \
|
||||||
|
@ -197,6 +184,19 @@ extern ExprContext *MakePerTupleExprContext(EState *estate);
|
||||||
ResetExprContext((estate)->es_per_tuple_exprcontext); \
|
ResetExprContext((estate)->es_per_tuple_exprcontext); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
extern void ExecAssignExprContext(EState *estate, PlanState *planstate);
|
||||||
|
extern void ExecAssignResultType(PlanState *planstate,
|
||||||
|
TupleDesc tupDesc, bool shouldFree);
|
||||||
|
extern void ExecAssignResultTypeFromOuterPlan(PlanState *planstate);
|
||||||
|
extern void ExecAssignResultTypeFromTL(PlanState *planstate);
|
||||||
|
extern TupleDesc ExecGetResultType(PlanState *planstate);
|
||||||
|
extern void ExecAssignProjectionInfo(PlanState *planstate);
|
||||||
|
extern void ExecFreeExprContext(PlanState *planstate);
|
||||||
|
extern TupleDesc ExecGetScanType(ScanState *scanstate);
|
||||||
|
extern void ExecAssignScanType(ScanState *scanstate,
|
||||||
|
TupleDesc tupDesc, bool shouldFree);
|
||||||
|
extern void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate);
|
||||||
|
|
||||||
extern void ExecOpenIndices(ResultRelInfo *resultRelInfo);
|
extern void ExecOpenIndices(ResultRelInfo *resultRelInfo);
|
||||||
extern void ExecCloseIndices(ResultRelInfo *resultRelInfo);
|
extern void ExecCloseIndices(ResultRelInfo *resultRelInfo);
|
||||||
extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,
|
extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: execnodes.h,v 1.85 2002/12/14 00:17:59 tgl Exp $
|
* $Id: execnodes.h,v 1.86 2002/12/15 16:17:56 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -81,14 +81,14 @@ typedef struct ExprContext_CB
|
||||||
* context.
|
* context.
|
||||||
*
|
*
|
||||||
* There are two memory contexts associated with an ExprContext:
|
* There are two memory contexts associated with an ExprContext:
|
||||||
* * ecxt_per_query_memory is a relatively long-lived context (such as
|
* * ecxt_per_query_memory is a query-lifespan context, typically the same
|
||||||
* TransactionCommandContext); typically it's the same context the
|
* context the ExprContext node itself is allocated in. This context
|
||||||
* ExprContext node itself is allocated in. This context can be
|
* can be used for purposes such as storing function call cache info.
|
||||||
* used for purposes such as storing function call cache info.
|
|
||||||
* * ecxt_per_tuple_memory is a short-term context for expression results.
|
* * ecxt_per_tuple_memory is a short-term context for expression results.
|
||||||
* As the name suggests, it will typically be reset once per tuple,
|
* As the name suggests, it will typically be reset once per tuple,
|
||||||
* before we begin to evaluate expressions for that tuple. Each
|
* before we begin to evaluate expressions for that tuple. Each
|
||||||
* ExprContext normally has its very own per-tuple memory context.
|
* ExprContext normally has its very own per-tuple memory context.
|
||||||
|
*
|
||||||
* CurrentMemoryContext should be set to ecxt_per_tuple_memory before
|
* CurrentMemoryContext should be set to ecxt_per_tuple_memory before
|
||||||
* calling ExecEvalExpr() --- see ExecEvalExprSwitchContext().
|
* calling ExecEvalExpr() --- see ExecEvalExprSwitchContext().
|
||||||
* ----------------
|
* ----------------
|
||||||
|
@ -118,6 +118,9 @@ typedef struct ExprContext
|
||||||
Datum domainValue_datum;
|
Datum domainValue_datum;
|
||||||
bool domainValue_isNull;
|
bool domainValue_isNull;
|
||||||
|
|
||||||
|
/* Link to containing EState */
|
||||||
|
struct EState *ecxt_estate;
|
||||||
|
|
||||||
/* Functions to call back when ExprContext is shut down */
|
/* Functions to call back when ExprContext is shut down */
|
||||||
ExprContext_CB *ecxt_callbacks;
|
ExprContext_CB *ecxt_callbacks;
|
||||||
} ExprContext;
|
} ExprContext;
|
||||||
|
@ -277,45 +280,43 @@ typedef struct ResultRelInfo
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* EState information
|
* EState information
|
||||||
*
|
*
|
||||||
* direction direction of the scan
|
* Master working state for an Executor invocation
|
||||||
*
|
|
||||||
* snapshot time qual to use
|
|
||||||
*
|
|
||||||
* range_table array of scan relation information
|
|
||||||
*
|
|
||||||
* result_relation information for insert/update/delete queries
|
|
||||||
*
|
|
||||||
* into_relation_descriptor relation being retrieved "into"
|
|
||||||
*
|
|
||||||
* param_list_info information about Param values
|
|
||||||
*
|
|
||||||
* tupleTable this is a pointer to an array
|
|
||||||
* of pointers to tuples used by
|
|
||||||
* the executor at any given moment.
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
typedef struct EState
|
typedef struct EState
|
||||||
{
|
{
|
||||||
NodeTag type;
|
NodeTag type;
|
||||||
ScanDirection es_direction;
|
|
||||||
Snapshot es_snapshot;
|
/* Basic state for all query types: */
|
||||||
List *es_range_table;
|
ScanDirection es_direction; /* current scan direction */
|
||||||
|
Snapshot es_snapshot; /* time qual to use */
|
||||||
|
List *es_range_table; /* List of RangeTableEntrys */
|
||||||
|
|
||||||
|
/* Info about target table for insert/update/delete queries: */
|
||||||
ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
|
ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
|
||||||
int es_num_result_relations; /* length of array */
|
int es_num_result_relations; /* length of array */
|
||||||
ResultRelInfo *es_result_relation_info; /* currently active array
|
ResultRelInfo *es_result_relation_info; /* currently active array
|
||||||
* elt */
|
* elt */
|
||||||
JunkFilter *es_junkFilter; /* currently active junk filter */
|
JunkFilter *es_junkFilter; /* currently active junk filter */
|
||||||
Relation es_into_relation_descriptor;
|
Relation es_into_relation_descriptor; /* for SELECT INTO */
|
||||||
|
|
||||||
|
/* Parameter info: */
|
||||||
ParamListInfo es_param_list_info; /* values of external params */
|
ParamListInfo es_param_list_info; /* values of external params */
|
||||||
ParamExecData *es_param_exec_vals; /* values of internal params */
|
ParamExecData *es_param_exec_vals; /* values of internal params */
|
||||||
TupleTable es_tupleTable;
|
|
||||||
|
/* Other working state: */
|
||||||
|
MemoryContext es_query_cxt; /* per-query context in which EState lives */
|
||||||
|
|
||||||
|
TupleTable es_tupleTable; /* Array of TupleTableSlots */
|
||||||
|
|
||||||
uint32 es_processed; /* # of tuples processed */
|
uint32 es_processed; /* # of tuples processed */
|
||||||
Oid es_lastoid; /* last oid processed (by INSERT) */
|
Oid es_lastoid; /* last oid processed (by INSERT) */
|
||||||
List *es_rowMark; /* not good place, but there is no other */
|
List *es_rowMark; /* not good place, but there is no other */
|
||||||
MemoryContext es_query_cxt; /* per-query context in which EState lives */
|
|
||||||
|
|
||||||
bool es_instrument; /* true requests runtime instrumentation */
|
bool es_instrument; /* true requests runtime instrumentation */
|
||||||
|
|
||||||
|
List *es_exprcontexts; /* List of ExprContexts within EState */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this ExprContext is for per-output-tuple operations, such as
|
* this ExprContext is for per-output-tuple operations, such as
|
||||||
* constraint checks and index-value computations. It will be reset
|
* constraint checks and index-value computations. It will be reset
|
||||||
|
@ -457,6 +458,7 @@ typedef struct BoolExprState
|
||||||
typedef struct SubPlanState
|
typedef struct SubPlanState
|
||||||
{
|
{
|
||||||
ExprState xprstate;
|
ExprState xprstate;
|
||||||
|
EState *sub_estate; /* subselect plan has its own EState */
|
||||||
struct PlanState *planstate; /* subselect plan's state tree */
|
struct PlanState *planstate; /* subselect plan's state tree */
|
||||||
bool needShutdown; /* TRUE = need to shutdown subplan */
|
bool needShutdown; /* TRUE = need to shutdown subplan */
|
||||||
HeapTuple curTuple; /* copy of most recent tuple from subplan */
|
HeapTuple curTuple; /* copy of most recent tuple from subplan */
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.74 2002/12/13 19:46:01 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.75 2002/12/15 16:17:58 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
|
@ -3227,7 +3227,6 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
|
||||||
bool *isNull,
|
bool *isNull,
|
||||||
Oid *rettype)
|
Oid *rettype)
|
||||||
{
|
{
|
||||||
_SPI_plan *spi_plan = (_SPI_plan *) expr->plan;
|
|
||||||
Datum retval;
|
Datum retval;
|
||||||
PLpgSQL_var *var;
|
PLpgSQL_var *var;
|
||||||
PLpgSQL_rec *rec;
|
PLpgSQL_rec *rec;
|
||||||
|
@ -3242,14 +3241,11 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
|
||||||
ParamListInfo paramLI;
|
ParamListInfo paramLI;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a simple expression context to hold the arguments.
|
* Create an expression context to hold the arguments and the result
|
||||||
*
|
* of this expression evaluation. This must be a child of the EState
|
||||||
* NOTE: we pass the SPI plan's context as the query-lifetime context for
|
* we created in the SPI plan's context.
|
||||||
* function cache nodes and suchlike allocations. This is appropriate
|
|
||||||
* because that's where the expression tree itself is, and the
|
|
||||||
* function cache nodes must live as long as it does.
|
|
||||||
*/
|
*/
|
||||||
econtext = MakeExprContext(NULL, spi_plan->plancxt);
|
econtext = CreateExprContext(expr->plan_simple_estate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Param list can live in econtext's temporary memory context.
|
* Param list can live in econtext's temporary memory context.
|
||||||
|
@ -3691,13 +3687,20 @@ exec_simple_check_plan(PLpgSQL_expr * expr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Yes - this is a simple expression. Prepare to execute it, and
|
* Yes - this is a simple expression. Prepare to execute it.
|
||||||
* stash away the result type. Put the expression state tree in the
|
* We need an EState and an expression state tree, which we'll put
|
||||||
* plan context so it will have appropriate lifespan.
|
* into the plan context so they will have appropriate lifespan.
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(spi_plan->plancxt);
|
oldcontext = MemoryContextSwitchTo(spi_plan->plancxt);
|
||||||
expr->plan_simple_expr = ExecInitExpr(tle->expr, NULL);
|
|
||||||
|
expr->plan_simple_estate = CreateExecutorState();
|
||||||
|
|
||||||
|
expr->plan_simple_expr = ExecPrepareExpr(tle->expr,
|
||||||
|
expr->plan_simple_estate);
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
|
/* Also stash away the expression result type */
|
||||||
expr->plan_simple_type = exprType((Node *) tle->expr);
|
expr->plan_simple_type = exprType((Node *) tle->expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.30 2002/12/13 19:46:01 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.31 2002/12/15 16:17:59 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
|
@ -166,6 +166,7 @@ typedef struct
|
||||||
char *query;
|
char *query;
|
||||||
void *plan;
|
void *plan;
|
||||||
ExprState *plan_simple_expr;
|
ExprState *plan_simple_expr;
|
||||||
|
EState *plan_simple_estate;
|
||||||
Oid plan_simple_type;
|
Oid plan_simple_type;
|
||||||
Oid *plan_argtypes;
|
Oid *plan_argtypes;
|
||||||
int nparams;
|
int nparams;
|
||||||
|
|
Loading…
Reference in New Issue