diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/Makefile | 8 | ||||
-rw-r--r-- | src/backend/executor/execAmi.c | 15 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 14 | ||||
-rw-r--r-- | src/backend/executor/execProcnode.c | 27 | ||||
-rw-r--r-- | src/backend/executor/execQual.c | 3 | ||||
-rw-r--r-- | src/backend/executor/execUtils.c | 102 | ||||
-rw-r--r-- | src/backend/executor/functions.c | 51 | ||||
-rw-r--r-- | src/backend/executor/nodeFunctionscan.c | 469 | ||||
-rw-r--r-- | src/backend/executor/nodeSubqueryscan.c | 4 |
9 files changed, 673 insertions, 20 deletions
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile index 363ea342e9f..0a66e1be03e 100644 --- a/src/backend/executor/Makefile +++ b/src/backend/executor/Makefile @@ -4,7 +4,7 @@ # Makefile for executor # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.17 2001/09/18 01:59:06 tgl Exp $ +# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.18 2002/05/12 20:10:02 tgl Exp $ # #------------------------------------------------------------------------- @@ -16,9 +16,9 @@ OBJS = execAmi.o execFlatten.o execJunk.o execMain.o \ execProcnode.o execQual.o execScan.o execTuples.o \ execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o nodeHash.o \ nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \ - nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSetOp.o nodeSort.o \ - nodeUnique.o nodeLimit.o nodeGroup.o nodeSubplan.o \ - nodeSubqueryscan.o nodeTidscan.o spi.o + nodeNestloop.o nodeFunctionscan.o nodeResult.o nodeSeqscan.o \ + nodeSetOp.o nodeSort.o nodeUnique.o nodeLimit.o nodeGroup.o \ + nodeSubplan.o nodeSubqueryscan.o nodeTidscan.o spi.o all: SUBSYS.o diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index 119c89b1c27..d2fe9da9ada 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: execAmi.c,v 1.62 2002/03/02 21:39:24 momjian Exp $ + * $Id: execAmi.c,v 1.63 2002/05/12 20:10:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,6 +35,7 @@ #include "executor/nodeSort.h" #include "executor/nodeSubplan.h" #include "executor/nodeSubqueryscan.h" +#include "executor/nodeFunctionscan.h" #include "executor/nodeUnique.h" @@ -100,6 +101,10 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent) ExecSubqueryReScan((SubqueryScan *) node, exprCtxt, parent); break; + case T_FunctionScan: + ExecFunctionReScan((FunctionScan *) node, exprCtxt, parent); + break; + case T_Material: ExecMaterialReScan((Material *) node, exprCtxt, parent); break; @@ -187,6 +192,10 @@ ExecMarkPos(Plan *node) ExecIndexMarkPos((IndexScan *) node); break; + case T_FunctionScan: + ExecFunctionMarkPos((FunctionScan *) node); + break; + case T_Material: ExecMaterialMarkPos((Material *) node); break; @@ -229,6 +238,10 @@ ExecRestrPos(Plan *node) ExecIndexRestrPos((IndexScan *) node); break; + case T_FunctionScan: + ExecFunctionRestrPos((FunctionScan *) node); + break; + case T_Material: ExecMaterialRestrPos((Material *) node); break; diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 68fcb325a63..a2c43bc0359 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -27,7 +27,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.160 2002/04/27 21:24:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.161 2002/05/12 20:10:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -311,7 +311,7 @@ ExecCheckPlanPerms(Plan *plan, List *rangeTable, CmdType operation) /* Recursively check the subquery */ rte = rt_fetch(scan->scan.scanrelid, rangeTable); - Assert(rte->subquery != NULL); + Assert(rte->rtekind == RTE_SUBQUERY); ExecCheckQueryPerms(operation, rte->subquery, scan->subplan); break; } @@ -362,10 +362,12 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation) Oid userid; AclResult aclcheck_result; - /* - * If it's a subquery RTE, ignore it --- it will be checked when - * ExecCheckPlanPerms finds the SubqueryScan node for it. - */ + /* + * Only plain-relation RTEs need to be checked here. Subquery RTEs + * will be checked when ExecCheckPlanPerms finds the SubqueryScan node, + * and function RTEs are checked by init_fcache when the function is + * prepared for execution. Join and special RTEs need no checks. + */ if (rte->rtekind != RTE_RELATION) return; diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index 5cbd2ea5622..c0f005f1e67 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -12,7 +12,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.28 2001/10/25 05:49:27 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.29 2002/05/12 20:10:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -96,6 +96,7 @@ #include "executor/nodeSort.h" #include "executor/nodeSubplan.h" #include "executor/nodeSubqueryscan.h" +#include "executor/nodeFunctionscan.h" #include "executor/nodeUnique.h" #include "miscadmin.h" #include "tcop/tcopprot.h" @@ -168,6 +169,11 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent) parent); break; + case T_FunctionScan: + result = ExecInitFunctionScan((FunctionScan *) node, estate, + parent); + break; + /* * join nodes */ @@ -297,6 +303,10 @@ ExecProcNode(Plan *node, Plan *parent) result = ExecSubqueryScan((SubqueryScan *) node); break; + case T_FunctionScan: + result = ExecFunctionScan((FunctionScan *) node); + break; + /* * join nodes */ @@ -392,6 +402,9 @@ ExecCountSlotsNode(Plan *node) case T_SubqueryScan: return ExecCountSlotsSubqueryScan((SubqueryScan *) node); + case T_FunctionScan: + return ExecCountSlotsFunctionScan((FunctionScan *) node); + /* * join nodes */ @@ -503,6 +516,10 @@ ExecEndNode(Plan *node, Plan *parent) ExecEndSubqueryScan((SubqueryScan *) node); break; + case T_FunctionScan: + ExecEndFunctionScan((FunctionScan *) node); + break; + /* * join nodes */ @@ -640,6 +657,14 @@ ExecGetTupType(Plan *node) } break; + case T_FunctionScan: + { + CommonScanState *scanstate = ((FunctionScan *) node)->scan.scanstate; + + slot = scanstate->cstate.cs_ResultTupleSlot; + } + break; + case T_Material: { MaterialState *matstate = ((Material *) node)->matstate; diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 5cc1bbaa718..bebb664f299 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.91 2002/04/27 03:45:03 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.92 2002/05/12 20:10:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -700,6 +700,7 @@ ExecMakeFunctionResult(FunctionCachePtr fcache, { fcinfo.resultinfo = (Node *) &rsinfo; rsinfo.type = T_ReturnSetInfo; + rsinfo.econtext = econtext; } /* diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 9b03401e444..a6b5048326b 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.80 2002/04/12 20:38:26 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.81 2002/05/12 20:10:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,6 +20,9 @@ * ExecCloseIndices | referenced by InitPlan, EndPlan, * ExecInsertIndexTuples / ExecAppend, ExecReplace * + * RegisterExprContextCallback Register function shutdown callback + * UnregisterExprContextCallback Deregister function shutdown callback + * * NOTES * This file has traditionally been the place to stick misc. * executor support stuff that doesn't really go anyplace else. @@ -58,6 +61,9 @@ extern int NIndexTupleProcessed; /* have to be defined in the * access method level so that the * cinterface.a will link ok. */ + +static void ShutdownExprContext(ExprContext *econtext); + /* ---------------------------------------------------------------- * statistic functions * ---------------------------------------------------------------- @@ -120,8 +126,6 @@ DisplayTupleCount(FILE *statfp) /* ---------------------------------------------------------------- * miscellaneous node-init support functions - * - * ExecAssignExprContext - assigns the node's expression context * ---------------------------------------------------------------- */ @@ -160,6 +164,7 @@ ExecAssignExprContext(EState *estate, CommonState *commonstate) econtext->ecxt_param_list_info = estate->es_param_list_info; econtext->ecxt_aggvalues = NULL; econtext->ecxt_aggnulls = NULL; + econtext->ecxt_callbacks = NULL; commonstate->cs_ExprContext = econtext; } @@ -204,6 +209,7 @@ MakeExprContext(TupleTableSlot *slot, econtext->ecxt_param_list_info = NULL; econtext->ecxt_aggvalues = NULL; econtext->ecxt_aggnulls = NULL; + econtext->ecxt_callbacks = NULL; return econtext; } @@ -216,6 +222,9 @@ MakeExprContext(TupleTableSlot *slot, void FreeExprContext(ExprContext *econtext) { + /* Call any registered callbacks */ + ShutdownExprContext(econtext); + /* And clean up the memory used */ MemoryContextDelete(econtext->ecxt_per_tuple_memory); pfree(econtext); } @@ -370,6 +379,11 @@ ExecFreeExprContext(CommonState *commonstate) return; /* + * clean up any registered callbacks + */ + ShutdownExprContext(econtext); + + /* * clean up memory used. */ MemoryContextDelete(econtext->ecxt_per_tuple_memory); @@ -689,3 +703,85 @@ SetChangedParamList(Plan *node, List *newchg) node->chgParam = lappendi(node->chgParam, paramId); } } + +/* + * Register a shutdown callback in an ExprContext. + * + * Shutdown callbacks will be called (in reverse order of registration) + * when the ExprContext is deleted or rescanned. This provides a hook + * for functions called in the context to do any cleanup needed --- it's + * particularly useful for functions returning sets. Note that the + * callback will *not* be called in the event that execution is aborted + * by an error. + */ +void +RegisterExprContextCallback(ExprContext *econtext, + ExprContextCallbackFunction function, + Datum arg) +{ + ExprContext_CB *ecxt_callback; + + /* Save the info in appropriate memory context */ + ecxt_callback = (ExprContext_CB *) + MemoryContextAlloc(econtext->ecxt_per_query_memory, + sizeof(ExprContext_CB)); + + ecxt_callback->function = function; + ecxt_callback->arg = arg; + + /* link to front of list for appropriate execution order */ + ecxt_callback->next = econtext->ecxt_callbacks; + econtext->ecxt_callbacks = ecxt_callback; +} + +/* + * Deregister a shutdown callback in an ExprContext. + * + * Any list entries matching the function and arg will be removed. + * This can be used if it's no longer necessary to call the callback. + */ +void +UnregisterExprContextCallback(ExprContext *econtext, + ExprContextCallbackFunction function, + Datum arg) +{ + ExprContext_CB **prev_callback; + ExprContext_CB *ecxt_callback; + + prev_callback = &econtext->ecxt_callbacks; + + while ((ecxt_callback = *prev_callback) != NULL) + { + if (ecxt_callback->function == function && ecxt_callback->arg == arg) + { + *prev_callback = ecxt_callback->next; + pfree(ecxt_callback); + } + else + { + prev_callback = &ecxt_callback->next; + } + } +} + +/* + * Call all the shutdown callbacks registered in an ExprContext. + * + * The callback list is emptied (important in case this is only a rescan + * reset, and not deletion of the ExprContext). + */ +static void +ShutdownExprContext(ExprContext *econtext) +{ + ExprContext_CB *ecxt_callback; + + /* + * Call each callback function in reverse registration order. + */ + while ((ecxt_callback = econtext->ecxt_callbacks) != NULL) + { + econtext->ecxt_callbacks = ecxt_callback->next; + (*ecxt_callback->function) (ecxt_callback->arg); + pfree(ecxt_callback); + } +} diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 885d93a2aff..938f7e17f93 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.49 2002/02/27 19:34:51 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.50 2002/05/12 20:10:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,7 +28,7 @@ /* - * We have an execution_state record for each query in the function. + * We have an execution_state record for each query in a function. */ typedef enum { @@ -56,6 +56,7 @@ typedef struct int typlen; /* length of the return type */ bool typbyval; /* true if return type is pass by value */ bool returnsTuple; /* true if return type is a tuple */ + bool shutdown_reg; /* true if registered shutdown callback */ TupleTableSlot *funcSlot; /* if one result we need to copy it before * we end execution of the function and @@ -79,6 +80,7 @@ static void postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo); static Datum postquel_execute(execution_state *es, FunctionCallInfo fcinfo, SQLFunctionCachePtr fcache); +static void ShutdownSQLFunction(Datum arg); static execution_state * @@ -546,6 +548,15 @@ fmgr_sql(PG_FUNCTION_ARGS) elog(ERROR, "Set-valued function called in context that cannot accept a set"); fcinfo->isnull = true; result = (Datum) 0; + + /* Deregister shutdown callback, if we made one */ + if (fcache->shutdown_reg) + { + UnregisterExprContextCallback(rsi->econtext, + ShutdownSQLFunction, + PointerGetDatum(fcache)); + fcache->shutdown_reg = false; + } } MemoryContextSwitchTo(oldcontext); @@ -570,9 +581,45 @@ fmgr_sql(PG_FUNCTION_ARGS) rsi->isDone = ExprMultipleResult; else elog(ERROR, "Set-valued function called in context that cannot accept a set"); + + /* + * Ensure we will get shut down cleanly if the exprcontext is + * not run to completion. + */ + if (!fcache->shutdown_reg) + { + RegisterExprContextCallback(rsi->econtext, + ShutdownSQLFunction, + PointerGetDatum(fcache)); + fcache->shutdown_reg = true; + } } MemoryContextSwitchTo(oldcontext); return result; } + +/* + * callback function in case a function-returning-set needs to be shut down + * before it has been run to completion + */ +static void +ShutdownSQLFunction(Datum arg) +{ + SQLFunctionCachePtr fcache = (SQLFunctionCachePtr) DatumGetPointer(arg); + execution_state *es = fcache->func_state; + + while (es != NULL) + { + /* Shut down anything still running */ + if (es->status == F_EXEC_RUN) + postquel_end(es); + /* Reset states to START in case we're called again */ + es->status = F_EXEC_START; + es = es->next; + } + + /* execUtils will deregister the callback... */ + fcache->shutdown_reg = false; +} diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c new file mode 100644 index 00000000000..7b6d466a812 --- /dev/null +++ b/src/backend/executor/nodeFunctionscan.c @@ -0,0 +1,469 @@ +/*------------------------------------------------------------------------- + * + * nodeFunctionscan.c + * Support routines for scanning RangeFunctions (functions in rangetable). + * + * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.1 2002/05/12 20:10:02 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +/* + * INTERFACE ROUTINES + * ExecFunctionScan scans a function. + * ExecFunctionNext retrieve next tuple in sequential order. + * ExecInitFunctionScan creates and initializes a functionscan node. + * ExecEndFunctionScan releases any storage allocated. + * ExecFunctionReScan rescans the function + */ +#include "postgres.h" + +#include "miscadmin.h" +#include "access/heapam.h" +#include "catalog/pg_type.h" +#include "executor/execdebug.h" +#include "executor/execdefs.h" +#include "executor/execdesc.h" +#include "executor/nodeFunctionscan.h" +#include "parser/parsetree.h" +#include "parser/parse_expr.h" +#include "parser/parse_type.h" +#include "storage/lmgr.h" +#include "tcop/pquery.h" +#include "utils/lsyscache.h" +#include "utils/syscache.h" +#include "utils/tuplestore.h" + +static TupleTableSlot *FunctionNext(FunctionScan *node); +static TupleTableSlot *function_getonetuple(TupleTableSlot *slot, + Node *expr, + ExprContext *econtext, + TupleDesc tupdesc, + bool returnsTuple, + bool *isNull, + ExprDoneCond *isDone); +static FunctionMode get_functionmode(Node *expr); + +/* ---------------------------------------------------------------- + * Scan Support + * ---------------------------------------------------------------- + */ +/* ---------------------------------------------------------------- + * FunctionNext + * + * This is a workhorse for ExecFunctionScan + * ---------------------------------------------------------------- + */ +static TupleTableSlot * +FunctionNext(FunctionScan *node) +{ + TupleTableSlot *slot; + Node *expr; + ExprContext *econtext; + TupleDesc tupdesc; + EState *estate; + ScanDirection direction; + Tuplestorestate *tuplestorestate; + FunctionScanState *scanstate; + bool should_free; + HeapTuple heapTuple; + + /* + * get information from the estate and scan state + */ + scanstate = (FunctionScanState *) node->scan.scanstate; + estate = node->scan.plan.state; + direction = estate->es_direction; + econtext = scanstate->csstate.cstate.cs_ExprContext; + + tuplestorestate = scanstate->tuplestorestate; + tupdesc = scanstate->tupdesc; + expr = scanstate->funcexpr; + + /* + * If first time through, read all tuples from function and pass them to + * tuplestore.c. Subsequent calls just fetch tuples from tuplestore. + */ + if (tuplestorestate == NULL) + { + /* + * Initialize tuplestore module. + */ + tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */ + SortMem); + + scanstate->tuplestorestate = (void *) tuplestorestate; + + /* + * Compute all the function tuples and pass to tuplestore. + */ + for (;;) + { + bool isNull; + ExprDoneCond isDone; + + isNull = false; + isDone = ExprSingleResult; + slot = function_getonetuple(scanstate->csstate.css_ScanTupleSlot, + expr, econtext, tupdesc, + scanstate->returnsTuple, + &isNull, &isDone); + if (TupIsNull(slot)) + break; + + tuplestore_puttuple(tuplestorestate, (void *) slot->val); + ExecClearTuple(slot); + + if (isDone != ExprMultipleResult) + break; + } + + /* + * Complete the store. + */ + tuplestore_donestoring(tuplestorestate); + } + + /* + * Get the next tuple from tuplestore. Return NULL if no more tuples. + */ + slot = scanstate->csstate.css_ScanTupleSlot; + heapTuple = tuplestore_getheaptuple(tuplestorestate, + ScanDirectionIsForward(direction), + &should_free); + + return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free); +} + +/* ---------------------------------------------------------------- + * ExecFunctionScan(node) + * + * Scans the Function sequentially and returns the next qualifying + * tuple. + * It calls the ExecScan() routine and passes it the access method + * which retrieve tuples sequentially. + * + */ + +TupleTableSlot * +ExecFunctionScan(FunctionScan *node) +{ + /* + * use FunctionNext as access method + */ + return ExecScan(&node->scan, (ExecScanAccessMtd) FunctionNext); +} + +/* ---------------------------------------------------------------- + * ExecInitFunctionScan + * ---------------------------------------------------------------- + */ +bool +ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent) +{ + FunctionScanState *scanstate; + RangeTblEntry *rte; + Oid funcrettype; + Oid funcrelid; + TupleDesc tupdesc; + + /* + * FunctionScan should not have any children. + */ + Assert(outerPlan((Plan *) node) == NULL); + Assert(innerPlan((Plan *) node) == NULL); + + /* + * assign the node's execution state + */ + node->scan.plan.state = estate; + + /* + * create new ScanState for node + */ + scanstate = makeNode(FunctionScanState); + node->scan.scanstate = &scanstate->csstate; + + /* + * Miscellaneous initialization + * + * create expression context for node + */ + ExecAssignExprContext(estate, &scanstate->csstate.cstate); + +#define FUNCTIONSCAN_NSLOTS 2 + + /* + * tuple table initialization + */ + ExecInitResultTupleSlot(estate, &scanstate->csstate.cstate); + ExecInitScanTupleSlot(estate, &scanstate->csstate); + + /* + * get info about function + */ + rte = rt_fetch(node->scan.scanrelid, estate->es_range_table); + Assert(rte->rtekind == RTE_FUNCTION); + funcrettype = exprType(rte->funcexpr); + funcrelid = typeidTypeRelid(funcrettype); + + /* + * Build a suitable tupledesc representing the output rows + */ + if (OidIsValid(funcrelid)) + { + /* + * Composite data type, i.e. a table's row type + * Same as ordinary relation RTE + */ + Relation rel; + + rel = relation_open(funcrelid, AccessShareLock); + tupdesc = CreateTupleDescCopy(RelationGetDescr(rel)); + relation_close(rel, AccessShareLock); + scanstate->returnsTuple = true; + } + else + { + /* + * Must be a base data type, i.e. scalar + */ + char *attname = strVal(lfirst(rte->eref->colnames)); + + tupdesc = CreateTemplateTupleDesc(1); + TupleDescInitEntry(tupdesc, + (AttrNumber) 1, + attname, + funcrettype, + -1, + 0, + false); + scanstate->returnsTuple = false; + } + scanstate->tupdesc = tupdesc; + ExecSetSlotDescriptor(scanstate->csstate.css_ScanTupleSlot, + tupdesc, false); + + /* + * Other node-specific setup + */ + scanstate->tuplestorestate = NULL; + scanstate->funcexpr = rte->funcexpr; + + scanstate->functionmode = get_functionmode(rte->funcexpr); + + scanstate->csstate.cstate.cs_TupFromTlist = false; + + /* + * initialize tuple type + */ + ExecAssignResultTypeFromTL((Plan *) node, &scanstate->csstate.cstate); + ExecAssignProjectionInfo((Plan *) node, &scanstate->csstate.cstate); + + return TRUE; +} + +int +ExecCountSlotsFunctionScan(FunctionScan *node) +{ + return ExecCountSlotsNode(outerPlan(node)) + + ExecCountSlotsNode(innerPlan(node)) + + FUNCTIONSCAN_NSLOTS; +} + +/* ---------------------------------------------------------------- + * ExecEndFunctionScan + * + * frees any storage allocated through C routines. + * ---------------------------------------------------------------- + */ +void +ExecEndFunctionScan(FunctionScan *node) +{ + FunctionScanState *scanstate; + EState *estate; + + /* + * get information from node + */ + scanstate = (FunctionScanState *) node->scan.scanstate; + estate = node->scan.plan.state; + + /* + * 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(&scanstate->csstate.cstate); + ExecFreeExprContext(&scanstate->csstate.cstate); + + /* + * clean out the tuple table + */ + ExecClearTuple(scanstate->csstate.cstate.cs_ResultTupleSlot); + ExecClearTuple(scanstate->csstate.css_ScanTupleSlot); + + /* + * Release tuplestore resources + */ + if (scanstate->tuplestorestate != NULL) + tuplestore_end((Tuplestorestate *) scanstate->tuplestorestate); + scanstate->tuplestorestate = NULL; +} + +/* ---------------------------------------------------------------- + * ExecFunctionMarkPos + * + * Calls tuplestore to save the current position in the stored file. + * ---------------------------------------------------------------- + */ +void +ExecFunctionMarkPos(FunctionScan *node) +{ + FunctionScanState *scanstate; + + scanstate = (FunctionScanState *) node->scan.scanstate; + + /* + * if we haven't materialized yet, just return. + */ + if (!scanstate->tuplestorestate) + return; + + tuplestore_markpos((Tuplestorestate *) scanstate->tuplestorestate); +} + +/* ---------------------------------------------------------------- + * ExecFunctionRestrPos + * + * Calls tuplestore to restore the last saved file position. + * ---------------------------------------------------------------- + */ +void +ExecFunctionRestrPos(FunctionScan *node) +{ + FunctionScanState *scanstate; + + scanstate = (FunctionScanState *) node->scan.scanstate; + + /* + * if we haven't materialized yet, just return. + */ + if (!scanstate->tuplestorestate) + return; + + tuplestore_restorepos((Tuplestorestate *) scanstate->tuplestorestate); +} + +/* ---------------------------------------------------------------- + * ExecFunctionReScan + * + * Rescans the relation. + * ---------------------------------------------------------------- + */ +void +ExecFunctionReScan(FunctionScan *node, ExprContext *exprCtxt, Plan *parent) +{ + FunctionScanState *scanstate; + + /* + * get information from node + */ + scanstate = (FunctionScanState *) node->scan.scanstate; + + ExecClearTuple(scanstate->csstate.cstate.cs_ResultTupleSlot); + + /* + * If we haven't materialized yet, just return. + */ + if (!scanstate->tuplestorestate) + return; + + /* + * Here we have a choice whether to drop the tuplestore (and recompute + * the function outputs) or just rescan it. This should depend on + * whether the function expression contains parameters and/or is + * marked volatile. FIXME soon. + */ + if (node->scan.plan.chgParam != NULL) + { + tuplestore_end((Tuplestorestate *) scanstate->tuplestorestate); + scanstate->tuplestorestate = NULL; + } + else + tuplestore_rescan((Tuplestorestate *) scanstate->tuplestorestate); +} + +/* + * Run the underlying function to get the next tuple + */ +static TupleTableSlot * +function_getonetuple(TupleTableSlot *slot, + Node *expr, + ExprContext *econtext, + TupleDesc tupdesc, + bool returnsTuple, + bool *isNull, + ExprDoneCond *isDone) +{ + HeapTuple tuple; + Datum retDatum; + char nullflag; + + /* + * get the next Datum from the function + */ + retDatum = ExecEvalExprSwitchContext(expr, econtext, isNull, isDone); + + /* + * check to see if we're really done + */ + if (*isDone == ExprEndResult) + slot = NULL; + else + { + if (returnsTuple) + { + /* + * Composite data type, i.e. a table's row type + * function returns pointer to tts?? + */ + slot = (TupleTableSlot *) retDatum; + } + else + { + /* + * Must be a base data type, i.e. scalar + * turn it into a tuple + */ + nullflag = *isNull ? 'n' : ' '; + tuple = heap_formtuple(tupdesc, &retDatum, &nullflag); + + /* + * save the tuple in the scan tuple slot and return the slot. + */ + slot = ExecStoreTuple(tuple, /* tuple to store */ + slot, /* slot to store in */ + InvalidBuffer, /* buffer associated with + * this tuple */ + true); /* pfree this pointer */ + } + } + + return slot; +} + +static FunctionMode +get_functionmode(Node *expr) +{ + /* + * for the moment, hardwire this + */ + return PM_REPEATEDCALL; +} diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c index edd4640ba41..12f659847c6 100644 --- a/src/backend/executor/nodeSubqueryscan.c +++ b/src/backend/executor/nodeSubqueryscan.c @@ -12,7 +12,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.11 2001/10/25 05:49:29 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.12 2002/05/12 20:10:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -146,7 +146,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent) * This should agree with ExecInitSubPlan */ rte = rt_fetch(node->scan.scanrelid, estate->es_range_table); - Assert(rte->subquery != NULL); + Assert(rte->rtekind == RTE_SUBQUERY); sp_estate = CreateExecutorState(); subquerystate->sss_SubEState = sp_estate; |