diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-12-05 15:50:39 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-12-05 15:50:39 +0000 |
commit | 1fd0c59e25063e664f8a5cee6f723470c5979544 (patch) | |
tree | d7c1ba5ee25323021a65d0e419299162a9db9c19 /src/backend/executor/functions.c | |
parent | 0f3b83edfaf65b6105b455f601c11af6e12170ca (diff) | |
download | postgresql-1fd0c59e25063e664f8a5cee6f723470c5979544.tar.gz postgresql-1fd0c59e25063e664f8a5cee6f723470c5979544.zip |
Phase 1 of read-only-plans project: cause executor state nodes to point
to plan nodes, not vice-versa. All executor state nodes now inherit from
struct PlanState. Copying of plan trees has been simplified by not
storing a list of SubPlans in Plan nodes (eliminating duplicate links).
The executor still needs such a list, but it can build it during
ExecutorStart since it has to scan the plan tree anyway.
No initdb forced since no stored-on-disk structures changed, but you
will need a full recompile because of node-numbering changes.
Diffstat (limited to 'src/backend/executor/functions.c')
-rw-r--r-- | src/backend/executor/functions.c | 147 |
1 files changed, 71 insertions, 76 deletions
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 71166d9096c..328aea5f079 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.60 2002/11/13 00:39:47 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.61 2002/12/05 15:50:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,7 +28,9 @@ /* - * We have an execution_state record for each query in a function. + * We have an execution_state record for each query in a function. Each + * record contains a querytree and plantree for its query. If the query + * is currently in F_EXEC_RUN state then there's a QueryDesc too. */ typedef enum { @@ -37,10 +39,11 @@ typedef enum typedef struct local_es { - QueryDesc *qd; - EState *estate; struct local_es *next; ExecStatus status; + Query *query; + Plan *plan; + QueryDesc *qd; /* null unless status == RUN */ } execution_state; #define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *) NULL) @@ -62,6 +65,8 @@ typedef struct * we end execution of the function and * free stuff */ + ParamListInfo paramLI; /* Param list representing current args */ + /* head of linked list of execution_state records */ execution_state *func_state; } SQLFunctionCache; @@ -73,10 +78,11 @@ typedef SQLFunctionCache *SQLFunctionCachePtr; static execution_state *init_execution_state(char *src, Oid *argOidVect, int nargs); static void init_sql_fcache(FmgrInfo *finfo); -static void postquel_start(execution_state *es); +static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache); static TupleTableSlot *postquel_getnext(execution_state *es); static void postquel_end(execution_state *es); -static void postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo); +static void postquel_sub_params(SQLFunctionCachePtr fcache, + FunctionCallInfo fcinfo); static Datum postquel_execute(execution_state *es, FunctionCallInfo fcinfo, SQLFunctionCachePtr fcache); @@ -101,7 +107,6 @@ init_execution_state(char *src, Oid *argOidVect, int nargs) Query *queryTree = lfirst(qtl_item); Plan *planTree; execution_state *newes; - EState *estate; planTree = pg_plan_query(queryTree); @@ -113,29 +118,9 @@ init_execution_state(char *src, Oid *argOidVect, int nargs) newes->next = NULL; newes->status = F_EXEC_START; - newes->qd = CreateQueryDesc(queryTree, planTree, None, NULL); - newes->estate = estate = CreateExecutorState(); - - if (nargs > 0) - { - int i; - ParamListInfo paramLI; - - paramLI = (ParamListInfo) palloc0((nargs + 1) * sizeof(ParamListInfoData)); - - estate->es_param_list_info = paramLI; - - for (i = 0; i < nargs; paramLI++, i++) - { - paramLI->kind = PARAM_NUM; - paramLI->id = i + 1; - paramLI->isnull = false; - paramLI->value = (Datum) NULL; - } - paramLI->kind = PARAM_INVALID; - } - else - estate->es_param_list_info = (ParamListInfo) NULL; + newes->query = queryTree; + newes->plan = planTree; + newes->qd = NULL; preves = newes; } @@ -219,6 +204,10 @@ init_sql_fcache(FmgrInfo *finfo) else fcache->funcSlot = NULL; + /* + * Parse and plan the queries. We need the argument info to pass + * to the parser. + */ nargs = procedureStruct->pronargs; if (nargs > 0) @@ -252,15 +241,18 @@ init_sql_fcache(FmgrInfo *finfo) static void -postquel_start(execution_state *es) +postquel_start(execution_state *es, SQLFunctionCachePtr fcache) { - /* - * Do nothing for utility commands. (create, destroy...) DZ - - * 30-8-1996 - */ - if (es->qd->operation == CMD_UTILITY) - return; - ExecutorStart(es->qd, es->estate); + Assert(es->qd == NULL); + es->qd = CreateQueryDesc(es->query, es->plan, + None, NULL, + fcache->paramLI, false); + + /* Utility commands don't need Executor. */ + if (es->qd->operation != CMD_UTILITY) + ExecutorStart(es->qd); + + es->status = F_EXEC_RUN; } static TupleTableSlot * @@ -282,40 +274,52 @@ postquel_getnext(execution_state *es) /* If it's not the last command, just run it to completion */ count = (LAST_POSTQUEL_COMMAND(es)) ? 1L : 0L; - return ExecutorRun(es->qd, es->estate, ForwardScanDirection, count); + return ExecutorRun(es->qd, ForwardScanDirection, count); } static void postquel_end(execution_state *es) { - /* - * Do nothing for utility commands. (create, destroy...) DZ - - * 30-8-1996 - */ - if (es->qd->operation == CMD_UTILITY) - return; - ExecutorEnd(es->qd, es->estate); + /* Utility commands don't need Executor. */ + if (es->qd->operation != CMD_UTILITY) + ExecutorEnd(es->qd); + + pfree(es->qd); + es->qd = NULL; + + es->status = F_EXEC_DONE; } +/* Build ParamListInfo array representing current arguments */ static void -postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo) +postquel_sub_params(SQLFunctionCachePtr fcache, + FunctionCallInfo fcinfo) { - EState *estate; ParamListInfo paramLI; + int nargs = fcinfo->nargs; - estate = es->estate; - paramLI = estate->es_param_list_info; - - while (paramLI->kind != PARAM_INVALID) + if (nargs > 0) { - if (paramLI->kind == PARAM_NUM) + int i; + + paramLI = (ParamListInfo) palloc0((nargs + 1) * sizeof(ParamListInfoData)); + + for (i = 0; i < nargs; i++) { - Assert(paramLI->id <= fcinfo->nargs); - paramLI->value = fcinfo->arg[paramLI->id - 1]; - paramLI->isnull = fcinfo->argnull[paramLI->id - 1]; + paramLI[i].kind = PARAM_NUM; + paramLI[i].id = i + 1; + paramLI[i].value = fcinfo->arg[i]; + paramLI[i].isnull = fcinfo->argnull[i]; } - paramLI++; + paramLI[nargs].kind = PARAM_INVALID; } + else + paramLI = (ParamListInfo) NULL; + + if (fcache->paramLI) + pfree(fcache->paramLI); + + fcache->paramLI = paramLI; } static TupleTableSlot * @@ -359,27 +363,14 @@ postquel_execute(execution_state *es, TupleTableSlot *slot; Datum value; - /* - * It's more right place to do it (before - * postquel_start->ExecutorStart). Now - * ExecutorStart->ExecInitIndexScan->ExecEvalParam works ok. (But - * note: I HOPE we can do it here). - vadim 01/22/97 - */ - if (fcinfo->nargs > 0) - postquel_sub_params(es, fcinfo); - if (es->status == F_EXEC_START) - { - postquel_start(es); - es->status = F_EXEC_RUN; - } + postquel_start(es, fcache); slot = postquel_getnext(es); if (TupIsNull(slot)) { postquel_end(es); - es->status = F_EXEC_DONE; fcinfo->isnull = true; /* @@ -438,10 +429,7 @@ postquel_execute(execution_state *es, * execution now. */ if (!fcinfo->flinfo->fn_retset) - { postquel_end(es); - es->status = F_EXEC_DONE; - } return value; } @@ -471,7 +459,7 @@ fmgr_sql(PG_FUNCTION_ARGS) oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); /* - * Initialize fcache and execution state if first time through. + * Initialize fcache (build plans) if first time through. */ fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra; if (fcache == NULL) @@ -482,6 +470,13 @@ fmgr_sql(PG_FUNCTION_ARGS) es = fcache->func_state; /* + * Convert params to appropriate format if starting a fresh execution. + * (If continuing execution, we can re-use prior params.) + */ + if (es && es->status == F_EXEC_START) + postquel_sub_params(fcache, fcinfo); + + /* * Find first unfinished query in function. */ while (es && es->status == F_EXEC_DONE) @@ -506,7 +501,7 @@ fmgr_sql(PG_FUNCTION_ARGS) if (es == (execution_state *) NULL) { /* - * Reset the execution states to start over again + * Reset the execution states to start over again on next call. */ es = fcache->func_state; while (es) |