diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-05-06 20:26:28 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-05-06 20:26:28 +0000 |
commit | 79913910d4b518a42c893b6dd459656798ffa591 (patch) | |
tree | f0cd5c25dff8d026b9d8d4736717a4d38c278134 /src/backend/executor | |
parent | 299fbb4b379003557f79d2732a85ece168d04ec4 (diff) |
Restructure command destination handling so that we pass around
DestReceiver pointers instead of just CommandDest values. The DestReceiver
is made at the point where the destination is selected, rather than
deep inside the executor. This cleans up the original kluge implementation
of tstoreReceiver.c, and makes it easy to support retrieving results
from utility statements inside portals. Thus, you can now do fun things
like Bind and Execute a FETCH or EXPLAIN command, and it'll all work
as expected (e.g., you can Describe the portal, or use Execute's count
parameter to suspend the output partway through). Implementation involves
stuffing the utility command's output into a Tuplestore, which would be
kind of annoying for huge output sets, but should be quite acceptable
for typical uses of utility commands.
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execMain.c | 35 | ||||
-rw-r--r-- | src/backend/executor/execTuples.c | 64 | ||||
-rw-r--r-- | src/backend/executor/functions.c | 4 | ||||
-rw-r--r-- | src/backend/executor/spi.c | 50 | ||||
-rw-r--r-- | src/backend/executor/tstoreReceiver.c | 60 |
5 files changed, 125 insertions, 88 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 719c9456562..3d1b950e210 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.207 2003/05/06 00:20:31 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.208 2003/05/06 20:26:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -72,9 +72,9 @@ static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate, CmdType operation, long numberTuples, ScanDirection direction, - DestReceiver *destfunc); + DestReceiver *dest); static void ExecSelect(TupleTableSlot *slot, - DestReceiver *destfunc, + DestReceiver *dest, EState *estate); static void ExecInsert(TupleTableSlot *slot, ItemPointer tupleid, EState *estate); @@ -188,8 +188,7 @@ ExecutorRun(QueryDesc *queryDesc, { EState *estate; CmdType operation; - CommandDest dest; - DestReceiver *destfunc; + DestReceiver *dest; TupleTableSlot *result; MemoryContext oldcontext; @@ -218,11 +217,10 @@ ExecutorRun(QueryDesc *queryDesc, estate->es_processed = 0; estate->es_lastoid = InvalidOid; - destfunc = DestToFunction(dest); - (*destfunc->setup) (destfunc, operation, - queryDesc->portalName, - queryDesc->tupDesc, - queryDesc->planstate->plan->targetlist); + (*dest->startup) (dest, operation, + queryDesc->portalName, + queryDesc->tupDesc, + queryDesc->planstate->plan->targetlist); /* * run plan @@ -235,12 +233,12 @@ ExecutorRun(QueryDesc *queryDesc, operation, count, direction, - destfunc); + dest); /* * shutdown receiver */ - (*destfunc->cleanup) (destfunc); + (*dest->shutdown) (dest); MemoryContextSwitchTo(oldcontext); @@ -962,7 +960,7 @@ ExecutePlan(EState *estate, CmdType operation, long numberTuples, ScanDirection direction, - DestReceiver *destfunc) + DestReceiver *dest) { JunkFilter *junkfilter; TupleTableSlot *slot; @@ -1162,8 +1160,7 @@ lnext: ; { case CMD_SELECT: ExecSelect(slot, /* slot containing tuple */ - destfunc, /* destination's tuple-receiver - * obj */ + dest, /* destination's tuple-receiver obj */ estate); result = slot; break; @@ -1237,7 +1234,7 @@ lnext: ; */ static void ExecSelect(TupleTableSlot *slot, - DestReceiver *destfunc, + DestReceiver *dest, EState *estate) { HeapTuple tuple; @@ -1251,6 +1248,8 @@ ExecSelect(TupleTableSlot *slot, /* * insert the tuple into the "into relation" + * + * XXX this probably ought to be replaced by a separate destination */ if (estate->es_into_relation_descriptor != NULL) { @@ -1260,9 +1259,9 @@ ExecSelect(TupleTableSlot *slot, } /* - * send the tuple to the front end (or the screen) + * send the tuple to the destination */ - (*destfunc->receiveTuple) (tuple, attrtype, destfunc); + (*dest->receiveTuple) (tuple, attrtype, dest); IncrRetrieved(); (estate->es_processed)++; } diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index c81dd33d36a..2e040f78903 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.64 2003/05/06 00:20:31 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.65 2003/05/06 20:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -591,6 +591,49 @@ ExecTypeFromTL(List *targetList, bool hasoid) return typeInfo; } +/* ---------------------------------------------------------------- + * ExecCleanTypeFromTL + * + * Same as above, but resjunk columns are omitted from the result. + * ---------------------------------------------------------------- + */ +TupleDesc +ExecCleanTypeFromTL(List *targetList, bool hasoid) +{ + TupleDesc typeInfo; + List *tlitem; + int len; + int cleanresno; + + /* + * allocate a new typeInfo + */ + len = ExecCleanTargetListLength(targetList); + typeInfo = CreateTemplateTupleDesc(len, hasoid); + + /* + * scan list, generate type info for each entry + */ + cleanresno = 1; + foreach(tlitem, targetList) + { + TargetEntry *tle = lfirst(tlitem); + Resdom *resdom = tle->resdom; + + if (resdom->resjunk) + continue; + TupleDescInitEntry(typeInfo, + cleanresno++, + resdom->resname, + resdom->restype, + resdom->restypmod, + 0, + false); + } + + return typeInfo; +} + /* * TupleDescGetSlot - Initialize a slot based on the supplied tupledesc */ @@ -713,17 +756,17 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) * Table Function capability. Currently used by EXPLAIN and SHOW ALL */ TupOutputState * -begin_tup_output_tupdesc(CommandDest dest, TupleDesc tupdesc) +begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc) { TupOutputState *tstate; tstate = (TupOutputState *) palloc(sizeof(TupOutputState)); tstate->metadata = TupleDescGetAttInMetadata(tupdesc); - tstate->destfunc = DestToFunction(dest); + tstate->dest = dest; - (*tstate->destfunc->setup) (tstate->destfunc, (int) CMD_SELECT, - NULL, tupdesc, NIL); + (*tstate->dest->startup) (tstate->dest, (int) CMD_SELECT, + NULL, tupdesc, NIL); return tstate; } @@ -741,9 +784,9 @@ do_tup_output(TupOutputState *tstate, char **values) HeapTuple tuple = BuildTupleFromCStrings(tstate->metadata, values); /* send the tuple to the receiver */ - (*tstate->destfunc->receiveTuple) (tuple, - tstate->metadata->tupdesc, - tstate->destfunc); + (*tstate->dest->receiveTuple) (tuple, + tstate->metadata->tupdesc, + tstate->dest); /* clean up */ heap_freetuple(tuple); } @@ -766,7 +809,7 @@ do_text_output_multiline(TupOutputState *tstate, char *text) if (eol) *eol++ = '\0'; else - eol = text +strlen(text); + eol = text + strlen(text); do_tup_output(tstate, &text); text = eol; @@ -776,7 +819,8 @@ do_text_output_multiline(TupOutputState *tstate, char *text) void end_tup_output(TupOutputState *tstate) { - (*tstate->destfunc->cleanup) (tstate->destfunc); + (*tstate->dest->shutdown) (tstate->dest); + /* note that destroying the dest is not ours to do */ /* XXX worth cleaning up the attinmetadata? */ pfree(tstate); } diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index ba41828be34..e89e5f32d64 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.63 2003/05/06 00:20:31 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.64 2003/05/06 20:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -245,7 +245,7 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache) { Assert(es->qd == NULL); es->qd = CreateQueryDesc(es->query, es->plan, - None, NULL, + None_Receiver, NULL, fcache->paramLI, false); /* Utility commands don't need Executor. */ diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 74299ddf3ea..c3b3ec3530a 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.95 2003/05/06 00:20:31 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.96 2003/05/06 20:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -38,7 +38,7 @@ static int _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, int tcount); static void _SPI_cursor_operation(Portal portal, bool forward, int count, - CommandDest dest); + DestReceiver *dest); static _SPI_plan *_SPI_copy_plan(_SPI_plan *plan, int location); @@ -841,7 +841,8 @@ SPI_cursor_find(const char *name) void SPI_cursor_fetch(Portal portal, bool forward, int count) { - _SPI_cursor_operation(portal, forward, count, SPI); + _SPI_cursor_operation(portal, forward, count, CreateDestReceiver(SPI)); + /* we know that the SPI receiver doesn't need a destroy call */ } @@ -853,7 +854,7 @@ SPI_cursor_fetch(Portal portal, bool forward, int count) void SPI_cursor_move(Portal portal, bool forward, int count) { - _SPI_cursor_operation(portal, forward, count, None); + _SPI_cursor_operation(portal, forward, count, None_Receiver); } @@ -874,13 +875,13 @@ SPI_cursor_close(Portal portal) /* =================== private functions =================== */ /* - * spi_dest_setup + * spi_dest_startup * Initialize to receive tuples from Executor into SPITupleTable * of current SPI procedure */ void -spi_dest_setup(DestReceiver *self, int operation, - const char *portalName, TupleDesc typeinfo, List *targetlist) +spi_dest_startup(DestReceiver *self, int operation, + const char *portalName, TupleDesc typeinfo, List *targetlist) { SPITupleTable *tuptable; MemoryContext oldcxt; @@ -891,12 +892,12 @@ spi_dest_setup(DestReceiver *self, int operation, * _SPI_connected */ if (_SPI_curid != _SPI_connected || _SPI_connected < 0) - elog(FATAL, "SPI: improper call to spi_dest_setup"); + elog(FATAL, "SPI: improper call to spi_dest_startup"); if (_SPI_current != &(_SPI_stack[_SPI_curid])) - elog(FATAL, "SPI: stack corrupted in spi_dest_setup"); + elog(FATAL, "SPI: stack corrupted in spi_dest_startup"); if (_SPI_current->tuptable != NULL) - elog(FATAL, "SPI: improper call to spi_dest_setup"); + elog(FATAL, "SPI: improper call to spi_dest_startup"); oldcxt = _SPI_procmem(); /* switch to procedure memory context */ @@ -1029,10 +1030,12 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan) Query *queryTree = (Query *) lfirst(query_list_item); Plan *planTree; QueryDesc *qdesc; + DestReceiver *dest; planTree = pg_plan_query(queryTree); plan_list = lappend(plan_list, planTree); + dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None); if (queryTree->commandType == CMD_UTILITY) { if (IsA(queryTree->utilityStmt, CopyStmt)) @@ -1051,14 +1054,13 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan) res = SPI_OK_UTILITY; if (plan == NULL) { - ProcessUtility(queryTree->utilityStmt, None, NULL); + ProcessUtility(queryTree->utilityStmt, dest, NULL); CommandCounterIncrement(); } } else if (plan == NULL) { - qdesc = CreateQueryDesc(queryTree, planTree, - queryTree->canSetTag ? SPI : None, + qdesc = CreateQueryDesc(queryTree, planTree, dest, NULL, NULL, false); res = _SPI_pquery(qdesc, true, queryTree->canSetTag ? tcount : 0); @@ -1068,8 +1070,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan) } else { - qdesc = CreateQueryDesc(queryTree, planTree, - queryTree->canSetTag ? SPI : None, + qdesc = CreateQueryDesc(queryTree, planTree, dest, NULL, NULL, false); res = _SPI_pquery(qdesc, false, 0); if (res < 0) @@ -1144,20 +1145,21 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, Query *queryTree = (Query *) lfirst(query_list_item); Plan *planTree; QueryDesc *qdesc; + DestReceiver *dest; planTree = lfirst(plan_list); plan_list = lnext(plan_list); + dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None); if (queryTree->commandType == CMD_UTILITY) { - ProcessUtility(queryTree->utilityStmt, None, NULL); + ProcessUtility(queryTree->utilityStmt, dest, NULL); res = SPI_OK_UTILITY; CommandCounterIncrement(); } else { - qdesc = CreateQueryDesc(queryTree, planTree, - queryTree->canSetTag ? SPI : None, + qdesc = CreateQueryDesc(queryTree, planTree, dest, NULL, paramLI, false); res = _SPI_pquery(qdesc, true, queryTree->canSetTag ? tcount : 0); @@ -1185,7 +1187,7 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount) if (queryDesc->parsetree->into != NULL) /* select into table */ { res = SPI_OK_SELINTO; - queryDesc->dest = None; /* don't output results anywhere */ + queryDesc->dest = None_Receiver; /* don't output results */ } break; case CMD_INSERT: @@ -1216,13 +1218,13 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount) _SPI_current->processed = queryDesc->estate->es_processed; save_lastoid = queryDesc->estate->es_lastoid; - if (operation == CMD_SELECT && queryDesc->dest == SPI) + if (operation == CMD_SELECT && queryDesc->dest->mydest == SPI) { if (_SPI_checktuples()) elog(FATAL, "SPI_select: # of processed tuples check failed"); } - if (queryDesc->dest == SPI) + if (queryDesc->dest->mydest == SPI) { SPI_processed = _SPI_current->processed; SPI_lastoid = save_lastoid; @@ -1253,7 +1255,7 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount) */ static void _SPI_cursor_operation(Portal portal, bool forward, int count, - CommandDest dest) + DestReceiver *dest) { /* Check that the portal is valid */ if (!PortalIsValid(portal)) @@ -1275,7 +1277,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count, (long) count, dest); - if (dest == SPI && _SPI_checktuples()) + if (dest->mydest == SPI && _SPI_checktuples()) elog(FATAL, "SPI_fetch: # of processed tuples check failed"); /* Put the result into place for access by caller */ @@ -1343,7 +1345,7 @@ _SPI_checktuples(void) SPITupleTable *tuptable = _SPI_current->tuptable; bool failed = false; - if (tuptable == NULL) /* spi_dest_setup was not called */ + if (tuptable == NULL) /* spi_dest_startup was not called */ failed = true; else if (processed != (tuptable->alloced - tuptable->free)) failed = true; diff --git a/src/backend/executor/tstoreReceiver.c b/src/backend/executor/tstoreReceiver.c index 05b0c1f2397..bcab8154a32 100644 --- a/src/backend/executor/tstoreReceiver.c +++ b/src/backend/executor/tstoreReceiver.c @@ -1,6 +1,6 @@ /*------------------------------------------------------------------------- * - * tstore_receiver.c + * tstoreReceiver.c * an implementation of DestReceiver that stores the result tuples in * a Tuplestore * @@ -9,7 +9,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/tstoreReceiver.c,v 1.4 2003/05/06 00:20:31 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/tstoreReceiver.c,v 1.5 2003/05/06 20:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,8 +17,7 @@ #include "postgres.h" #include "executor/tstoreReceiver.h" -#include "utils/memutils.h" -#include "utils/portal.h" + typedef struct { @@ -30,32 +29,13 @@ typedef struct /* * Prepare to receive tuples from executor. - * - * XXX: As currently implemented, this routine is a hack: there should - * be no tie between this code and the portal system. Instead, the - * receiver function that is part of DestFunction should be passed a - * QueryDesc, so that the call site of ExecutorRun can "sub-class" - * QueryDesc and pass in any necessary addition information (in this - * case, the Tuplestore to use). */ static void -tstoreSetupReceiver(DestReceiver *self, int operation, - const char *portalname, - TupleDesc typeinfo, List *targetlist) +tstoreStartupReceiver(DestReceiver *self, int operation, + const char *portalname, + TupleDesc typeinfo, List *targetlist) { - TStoreState *myState = (TStoreState *) self; - - /* Should only be called within a suitably-prepped portal */ - if (CurrentPortal == NULL || - CurrentPortal->holdStore == NULL) - elog(ERROR, "Tuplestore destination used in wrong context"); - - /* Debug check: make sure portal's result tuple desc is correct */ - Assert(CurrentPortal->tupDesc != NULL); - Assert(equalTupleDescs(CurrentPortal->tupDesc, typeinfo)); - - myState->tstore = CurrentPortal->holdStore; - myState->cxt = CurrentPortal->holdContext; + /* do nothing */ } /* @@ -73,28 +53,40 @@ tstoreReceiveTuple(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) } /* - * Clean up + * Clean up at end of an executor run */ static void -tstoreCleanupReceiver(DestReceiver *self) +tstoreShutdownReceiver(DestReceiver *self) { /* do nothing */ } /* + * Destroy receiver when done with it + */ +static void +tstoreDestroyReceiver(DestReceiver *self) +{ + pfree(self); +} + +/* * Initially create a DestReceiver object. */ DestReceiver * -tstoreReceiverCreateDR(void) +CreateTuplestoreDestReceiver(Tuplestorestate *tStore, + MemoryContext tContext) { TStoreState *self = (TStoreState *) palloc(sizeof(TStoreState)); self->pub.receiveTuple = tstoreReceiveTuple; - self->pub.setup = tstoreSetupReceiver; - self->pub.cleanup = tstoreCleanupReceiver; + self->pub.startup = tstoreStartupReceiver; + self->pub.shutdown = tstoreShutdownReceiver; + self->pub.destroy = tstoreDestroyReceiver; + self->pub.mydest = Tuplestore; - self->tstore = NULL; - self->cxt = NULL; + self->tstore = tStore; + self->cxt = tContext; return (DestReceiver *) self; } |