mirror of
https://github.com/postgres/postgres.git
synced 2025-07-08 11:42:09 +03:00
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:
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* 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 "miscadmin.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "optimizer/planmain.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
#include "parser/parse_relation.h"
|
||||
#include "rewrite/rewriteHandler.h"
|
||||
@ -803,6 +802,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||
slot = ExecAllocTableSlot(tupleTable);
|
||||
ExecSetSlotDescriptor(slot, tupDesc, false);
|
||||
|
||||
econtext = GetPerTupleExprContext(estate);
|
||||
|
||||
/*
|
||||
* Pick up the required catalog information for each attribute in the
|
||||
* 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)
|
||||
{
|
||||
fix_opfuncids(defexpr);
|
||||
defexprs[num_defaults] = ExecInitExpr((Expr *) defexpr, NULL);
|
||||
defexprs[num_defaults] = ExecPrepareExpr((Expr *) defexpr,
|
||||
estate);
|
||||
defmap[num_defaults] = i;
|
||||
num_defaults++;
|
||||
}
|
||||
@ -873,8 +874,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||
/* check whether any constraints actually found */
|
||||
if (node != (Node *) prm)
|
||||
{
|
||||
fix_opfuncids(node);
|
||||
constraintexprs[i] = ExecInitExpr((Expr *) node, NULL);
|
||||
constraintexprs[i] = ExecPrepareExpr((Expr *) node,
|
||||
estate);
|
||||
hasConstraints = true;
|
||||
}
|
||||
}
|
||||
@ -934,8 +935,6 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||
copy_lineno = 0;
|
||||
fe_eof = false;
|
||||
|
||||
econtext = GetPerTupleExprContext(estate);
|
||||
|
||||
/* Make room for a PARAM_EXEC value for domain constraint checks */
|
||||
if (hasConstraints)
|
||||
econtext->ecxt_param_exec_vals = (ParamExecData *)
|
||||
@ -953,9 +952,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||
/* Reset the per-tuple exprcontext */
|
||||
ResetPerTupleExprContext(estate);
|
||||
|
||||
/* Switch to and reset per-tuple memory context, too */
|
||||
/* Switch into its memory context */
|
||||
MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
||||
MemoryContextReset(CurrentMemoryContext);
|
||||
|
||||
/* Initialize all values for row to NULL */
|
||||
MemSet(values, 0, num_phys_attrs * sizeof(Datum));
|
||||
@ -1268,6 +1266,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||
ExecDropTupleTable(tupleTable, true);
|
||||
|
||||
ExecCloseIndices(resultRelInfo);
|
||||
|
||||
FreeExecutorState(estate);
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* 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);
|
||||
|
||||
ExecutorEnd(queryDesc);
|
||||
FreeQueryDesc(queryDesc);
|
||||
|
||||
CommandCounterIncrement();
|
||||
|
||||
totaltime += elapsed_time(&starttime);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* 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 "miscadmin.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/planmain.h"
|
||||
#include "optimizer/prep.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
@ -163,7 +162,6 @@ DefineIndex(RangeVar *heapRelation,
|
||||
if (predicate)
|
||||
{
|
||||
cnfPred = canonicalize_qual((Expr *) copyObject(predicate), true);
|
||||
fix_opfuncids((Node *) cnfPred);
|
||||
CheckPredicate(cnfPred, rangetable, relationId);
|
||||
}
|
||||
|
||||
@ -173,8 +171,7 @@ DefineIndex(RangeVar *heapRelation,
|
||||
*/
|
||||
indexInfo = makeNode(IndexInfo);
|
||||
indexInfo->ii_Predicate = cnfPred;
|
||||
indexInfo->ii_PredicateState = (List *)
|
||||
ExecInitExpr((Expr *) cnfPred, NULL);
|
||||
indexInfo->ii_PredicateState = NIL;
|
||||
indexInfo->ii_FuncOid = InvalidOid;
|
||||
indexInfo->ii_Unique = unique;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
PortalCleanup(Portal portal)
|
||||
{
|
||||
MemoryContext oldcontext;
|
||||
|
||||
/*
|
||||
* sanity checks
|
||||
*/
|
||||
AssertArg(PortalIsValid(portal));
|
||||
AssertArg(portal->cleanup == PortalCleanup);
|
||||
|
||||
/*
|
||||
* set proper portal-executor context before calling ExecMain.
|
||||
*/
|
||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||
|
||||
/*
|
||||
* tell the executor to shutdown the query
|
||||
*/
|
||||
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
|
||||
*
|
||||
* 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 "executor/executor.h"
|
||||
#include "utils/guc.h"
|
||||
#include "optimizer/planmain.h"
|
||||
#include "optimizer/planner.h"
|
||||
#include "rewrite/rewriteHandler.h"
|
||||
#include "tcop/pquery.h"
|
||||
@ -50,7 +49,6 @@ static void InitQueryHashTable(void);
|
||||
static void StoreQuery(const char *stmt_name, List *query_list,
|
||||
List *plan_list, List *argtype_list);
|
||||
static QueryHashEntry *FetchQuery(const char *plan_name);
|
||||
static void RunQuery(QueryDesc *qdesc);
|
||||
|
||||
|
||||
/*
|
||||
@ -96,33 +94,37 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
|
||||
*query_list,
|
||||
*plan_list;
|
||||
ParamListInfo paramLI = NULL;
|
||||
EState *estate;
|
||||
|
||||
/* Look it up in the hash table */
|
||||
entry = FetchQuery(stmt->name);
|
||||
|
||||
/* Make working copies the executor can safely scribble on */
|
||||
query_list = (List *) copyObject(entry->query_list);
|
||||
plan_list = (List *) copyObject(entry->plan_list);
|
||||
query_list = entry->query_list;
|
||||
plan_list = entry->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 */
|
||||
if (entry->argtype_list != NIL)
|
||||
{
|
||||
int nargs = length(entry->argtype_list);
|
||||
int i = 0;
|
||||
List *exprstates;
|
||||
ExprContext *econtext = MakeExprContext(NULL, CurrentMemoryContext);
|
||||
|
||||
/* Parser should have caught this error, but check */
|
||||
if (nargs != length(stmt->params))
|
||||
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)
|
||||
{
|
||||
@ -130,7 +132,7 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
|
||||
bool isNull;
|
||||
|
||||
paramLI[i].value = ExecEvalExprSwitchContext(n,
|
||||
econtext,
|
||||
GetPerTupleExprContext(estate),
|
||||
&isNull,
|
||||
NULL);
|
||||
paramLI[i].kind = PARAM_NUM;
|
||||
@ -173,7 +175,13 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
|
||||
qdesc->dest = None;
|
||||
}
|
||||
|
||||
RunQuery(qdesc);
|
||||
ExecutorStart(qdesc);
|
||||
|
||||
ExecutorRun(qdesc, ForwardScanDirection, 0L);
|
||||
|
||||
ExecutorEnd(qdesc);
|
||||
|
||||
FreeQueryDesc(qdesc);
|
||||
|
||||
if (log_executor_stats)
|
||||
ShowUsage("EXECUTOR STATISTICS");
|
||||
@ -188,7 +196,9 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* specified plan from storage.
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* 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 "optimizer/clauses.h"
|
||||
#include "optimizer/plancat.h"
|
||||
#include "optimizer/planmain.h"
|
||||
#include "optimizer/prep.h"
|
||||
#include "parser/gramparse.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
@ -2713,6 +2712,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
|
||||
ParseState *pstate;
|
||||
bool successful = true;
|
||||
HeapScanDesc scan;
|
||||
EState *estate;
|
||||
ExprContext *econtext;
|
||||
TupleTableSlot *slot;
|
||||
HeapTuple tuple;
|
||||
@ -2723,9 +2723,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
|
||||
|
||||
/*
|
||||
* We need to make a parse state and range
|
||||
* table to allow us to transformExpr and
|
||||
* fix_opfuncids to get a version of the
|
||||
* expression we can pass to ExecQual
|
||||
* table to allow us to do transformExpr()
|
||||
*/
|
||||
pstate = make_parsestate(NULL);
|
||||
rte = addRangeTableEntryForRelation(pstate,
|
||||
@ -2765,19 +2763,22 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
|
||||
*/
|
||||
expr = eval_const_expressions(expr);
|
||||
|
||||
/* And fix the opfuncids */
|
||||
fix_opfuncids(expr);
|
||||
/* Needs to be in implicit-ANDs form for ExecQual */
|
||||
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 */
|
||||
qualstate = (List *) ExecInitExpr((Expr *) qual, NULL);
|
||||
qualstate = (List *) ExecPrepareExpr((Expr *) qual, estate);
|
||||
|
||||
/* Make tuple slot to hold tuples */
|
||||
slot = MakeTupleTableSlot();
|
||||
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.
|
||||
@ -2797,8 +2798,8 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
|
||||
|
||||
heap_endscan(scan);
|
||||
|
||||
FreeExprContext(econtext);
|
||||
pfree(slot);
|
||||
FreeExecutorState(estate);
|
||||
|
||||
if (!successful)
|
||||
elog(ERROR, "AlterTableAddConstraint: rejected due to CHECK constraint %s",
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
* The "DefineFoo" routines take the parse tree and pick out the
|
||||
@ -47,7 +47,6 @@
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/nodes.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/planmain.h"
|
||||
#include "optimizer/var.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
#include "parser/parse_expr.h"
|
||||
@ -1242,6 +1241,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
|
||||
List *rels;
|
||||
List *rt;
|
||||
Form_pg_type typTup;
|
||||
EState *estate;
|
||||
ExprContext *econtext;
|
||||
char *ccbin;
|
||||
Expr *expr;
|
||||
@ -1338,11 +1338,13 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
|
||||
* the constraint is being added to.
|
||||
*/
|
||||
expr = (Expr *) stringToNode(ccbin);
|
||||
fix_opfuncids((Node *) expr);
|
||||
exprstate = ExecInitExpr(expr, NULL);
|
||||
|
||||
/* Make an expression context for ExecEvalExpr */
|
||||
econtext = MakeExprContext(NULL, CurrentMemoryContext);
|
||||
/* Need an EState to run ExecEvalExpr */
|
||||
estate = CreateExecutorState();
|
||||
econtext = GetPerTupleExprContext(estate);
|
||||
|
||||
/* build execution state for expr */
|
||||
exprstate = ExecPrepareExpr(expr, estate);
|
||||
|
||||
rels = get_rels_with_domain(domainoid);
|
||||
|
||||
@ -1377,7 +1379,9 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
|
||||
econtext->domainValue_datum = d;
|
||||
econtext->domainValue_isNull = isNull;
|
||||
|
||||
conResult = ExecEvalExpr(exprstate, econtext, &isNull, NULL);
|
||||
conResult = ExecEvalExprSwitchContext(exprstate,
|
||||
econtext,
|
||||
&isNull, NULL);
|
||||
|
||||
if (!isNull && !DatumGetBool(conResult))
|
||||
elog(ERROR, "AlterDomainAddConstraint: Domain %s constraint %s failed",
|
||||
@ -1393,7 +1397,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
|
||||
heap_close(testrel, NoLock);
|
||||
}
|
||||
|
||||
FreeExprContext(econtext);
|
||||
FreeExecutorState(estate);
|
||||
|
||||
/* Clean up */
|
||||
heap_close(rel, NoLock);
|
||||
|
@ -13,7 +13,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
* executor's index-entry-making machinery.
|
||||
*/
|
||||
estate = CreateExecutorState();
|
||||
|
||||
resultRelInfo = makeNode(ResultRelInfo);
|
||||
resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
|
||||
resultRelInfo->ri_RelationDesc = onerel;
|
||||
@ -1444,7 +1446,6 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
|
||||
ExecOpenIndices(resultRelInfo);
|
||||
|
||||
estate = CreateExecutorState();
|
||||
estate->es_result_relations = resultRelInfo;
|
||||
estate->es_num_result_relations = 1;
|
||||
estate->es_result_relation_info = resultRelInfo;
|
||||
@ -2484,6 +2485,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
ExecDropTupleTable(tupleTable, true);
|
||||
|
||||
ExecCloseIndices(resultRelInfo);
|
||||
|
||||
FreeExecutorState(estate);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user