diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index 27d6ffd508..35355b8b9b 100644 --- a/src/backend/access/common/printtup.c +++ b/src/backend/access/common/printtup.c @@ -2,14 +2,14 @@ * * printtup.c * Routines to print out tuples to the destination (both frontend - * clients and interactive backends are supported here). + * clients and standalone backends are supported here). * * * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.69 2003/05/06 00:20:31 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.70 2003/05/06 20:26:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,11 +22,13 @@ #include "utils/lsyscache.h" -static void printtup_setup(DestReceiver *self, int operation, +static void printtup_startup(DestReceiver *self, int operation, const char *portalName, TupleDesc typeinfo, List *targetlist); static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self); static void printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self); -static void printtup_cleanup(DestReceiver *self); +static void printtup_shutdown(DestReceiver *self); +static void printtup_destroy(DestReceiver *self); + /* ---------------------------------------------------------------- * printtup / debugtup support @@ -59,13 +61,41 @@ typedef struct * ---------------- */ DestReceiver * -printtup_create_DR(bool isBinary, bool sendDescrip) +printtup_create_DR(CommandDest dest) { DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup)); + bool isBinary; + bool sendDescrip; + + switch (dest) + { + case Remote: + isBinary = false; + sendDescrip = true; + break; + case RemoteInternal: + isBinary = true; + sendDescrip = true; + break; + case RemoteExecute: + isBinary = false; + sendDescrip = false; /* no T message for Execute */ + break; + case RemoteExecuteInternal: + isBinary = true; + sendDescrip = false; /* no T message for Execute */ + break; + + default: + elog(ERROR, "printtup_create_DR: unsupported dest"); + return NULL; + } self->pub.receiveTuple = isBinary ? printtup_internal : printtup; - self->pub.setup = printtup_setup; - self->pub.cleanup = printtup_cleanup; + self->pub.startup = printtup_startup; + self->pub.shutdown = printtup_shutdown; + self->pub.destroy = printtup_destroy; + self->pub.mydest = dest; self->sendDescrip = sendDescrip; @@ -77,8 +107,8 @@ printtup_create_DR(bool isBinary, bool sendDescrip) } static void -printtup_setup(DestReceiver *self, int operation, - const char *portalName, TupleDesc typeinfo, List *targetlist) +printtup_startup(DestReceiver *self, int operation, + const char *portalName, TupleDesc typeinfo, List *targetlist) { DR_printtup *myState = (DR_printtup *) self; @@ -288,17 +318,28 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) } /* ---------------- - * printtup_cleanup + * printtup_shutdown * ---------------- */ static void -printtup_cleanup(DestReceiver *self) +printtup_shutdown(DestReceiver *self) { DR_printtup *myState = (DR_printtup *) self; if (myState->myinfo) pfree(myState->myinfo); - pfree(myState); + myState->myinfo = NULL; + myState->attrinfo = NULL; +} + +/* ---------------- + * printtup_destroy + * ---------------- + */ +static void +printtup_destroy(DestReceiver *self) +{ + pfree(self); } /* ---------------- @@ -340,12 +381,12 @@ showatts(const char *name, TupleDesc tupleDesc) } /* ---------------- - * debugSetup - prepare to print tuples for an interactive backend + * debugStartup - prepare to print tuples for an interactive backend * ---------------- */ void -debugSetup(DestReceiver *self, int operation, - const char *portalName, TupleDesc typeinfo, List *targetlist) +debugStartup(DestReceiver *self, int operation, + const char *portalName, TupleDesc typeinfo, List *targetlist) { /* * show the return type of the tuples diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 2504d69fd0..28a6e0378c 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994-5, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.107 2003/05/06 00:20:31 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.108 2003/05/06 20:26:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -67,21 +67,15 @@ static Node *make_ors_ands_explicit(List *orclauses); * execute an EXPLAIN command */ void -ExplainQuery(ExplainStmt *stmt, CommandDest dest) +ExplainQuery(ExplainStmt *stmt, DestReceiver *dest) { Query *query = stmt->query; TupOutputState *tstate; - TupleDesc tupdesc; List *rewritten; List *l; - /* need a tuple descriptor representing a single TEXT column */ - tupdesc = CreateTemplateTupleDesc(1, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN", - TEXTOID, -1, 0, false); - /* prepare for projection of tuples */ - tstate = begin_tup_output_tupdesc(dest, tupdesc); + tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt)); if (query->commandType == CMD_UTILITY) { @@ -119,6 +113,22 @@ ExplainQuery(ExplainStmt *stmt, CommandDest dest) end_tup_output(tstate); } +/* + * ExplainResultDesc - + * construct the result tupledesc for an EXPLAIN + */ +TupleDesc +ExplainResultDesc(ExplainStmt *stmt) +{ + TupleDesc tupdesc; + + /* need a tuple descriptor representing a single TEXT column */ + tupdesc = CreateTemplateTupleDesc(1, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN", + TEXTOID, -1, 0, false); + return tupdesc; +} + /* * ExplainOneQuery - * print out the execution plan for one query @@ -169,7 +179,7 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate) plan = planner(query, isCursor, cursorOptions); /* Create a QueryDesc requesting no output */ - queryDesc = CreateQueryDesc(query, plan, None, NULL, NULL, + queryDesc = CreateQueryDesc(query, plan, None_Receiver, NULL, NULL, stmt->analyze); ExplainOnePlan(queryDesc, stmt, tstate); diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c index 82058ff5d1..1c51a1bb89 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.14 2003/05/05 00:44:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.15 2003/05/06 20:26:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,9 +23,9 @@ #include -#include "miscadmin.h" #include "commands/portalcmds.h" #include "executor/executor.h" +#include "executor/tstoreReceiver.h" #include "optimizer/planner.h" #include "rewrite/rewriteHandler.h" #include "tcop/pquery.h" @@ -37,7 +37,7 @@ * Execute SQL DECLARE CURSOR command. */ void -PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest) +PerformCursorOpen(DeclareCursorStmt *stmt) { List *rewritten; Query *query; @@ -142,9 +142,10 @@ PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest) */ void PerformPortalFetch(FetchStmt *stmt, - CommandDest dest, + DestReceiver *dest, char *completionTag) { + DestReceiver *mydest = dest; Portal portal; long nprocessed; @@ -168,7 +169,7 @@ PerformPortalFetch(FetchStmt *stmt, } /* - * Adjust dest if needed. MOVE wants dest = None. + * Adjust dest if needed. MOVE wants destination None. * * If fetching from a binary cursor and the requested destination is * Remote, change it to RemoteInternal. Note we do NOT change if the @@ -176,21 +177,26 @@ PerformPortalFetch(FetchStmt *stmt, * specification wins out over the cursor's type. */ if (stmt->ismove) - dest = None; - else if (dest == Remote && (portal->cursorOptions & CURSOR_OPT_BINARY)) - dest = RemoteInternal; + mydest = CreateDestReceiver(None); + else if (dest->mydest == Remote && + (portal->cursorOptions & CURSOR_OPT_BINARY)) + mydest = CreateDestReceiver(RemoteInternal); /* Do it */ nprocessed = PortalRunFetch(portal, stmt->direction, stmt->howMany, - dest); + mydest); /* Return command status if wanted */ if (completionTag) snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld", stmt->ismove ? "MOVE" : "FETCH", nprocessed); + + /* Clean up if we created a local destination */ + if (mydest != dest) + (mydest->destroy) (mydest); } /* @@ -243,21 +249,6 @@ PortalCleanup(Portal portal, bool isError) AssertArg(PortalIsValid(portal)); AssertArg(portal->cleanup == PortalCleanup); - /* - * Delete tuplestore if present. (Note: portalmem.c is responsible - * for removing holdContext.) We should do this even under error - * conditions; since the tuplestore would have been using cross- - * transaction storage, its temp files need to be explicitly deleted. - */ - if (portal->holdStore) - { - MemoryContext oldcontext; - - oldcontext = MemoryContextSwitchTo(portal->holdContext); - tuplestore_end(portal->holdStore); - MemoryContextSwitchTo(oldcontext); - portal->holdStore = NULL; - } /* * Shut down executor, if still running. We skip this during error * abort, since other mechanisms will take care of releasing executor @@ -284,7 +275,6 @@ void PersistHoldablePortal(Portal portal) { QueryDesc *queryDesc = PortalGetQueryDesc(portal); - Portal saveCurrentPortal; MemoryContext savePortalContext; MemoryContext saveQueryContext; MemoryContext oldcxt; @@ -294,26 +284,22 @@ PersistHoldablePortal(Portal portal) * inside the transaction that originally created it. */ Assert(portal->createXact == GetCurrentTransactionId()); - Assert(portal->holdStore == NULL); Assert(queryDesc != NULL); Assert(portal->portalReady); Assert(!portal->portalDone); /* - * This context is used to store the tuple set. - * Caller must have created it already. + * Caller must have created the tuplestore already. */ Assert(portal->holdContext != NULL); - oldcxt = MemoryContextSwitchTo(portal->holdContext); - - /* XXX: Should SortMem be used for this? */ - portal->holdStore = tuplestore_begin_heap(true, true, SortMem); + Assert(portal->holdStore != NULL); /* - * Before closing down the executor, we must copy the tupdesc, since - * it was created in executor memory. Note we are copying it into - * the holdContext. + * Before closing down the executor, we must copy the tupdesc into + * long-term memory, since it was created in executor memory. */ + oldcxt = MemoryContextSwitchTo(portal->holdContext); + portal->tupDesc = CreateTupleDescCopy(portal->tupDesc); MemoryContextSwitchTo(oldcxt); @@ -326,10 +312,8 @@ PersistHoldablePortal(Portal portal) portal->portalActive = true; /* - * Set global portal and context pointers. + * Set global portal context pointers. */ - saveCurrentPortal = CurrentPortal; - CurrentPortal = portal; savePortalContext = PortalContext; PortalContext = PortalGetHeapMemory(portal); saveQueryContext = QueryContext; @@ -344,12 +328,16 @@ PersistHoldablePortal(Portal portal) */ ExecutorRewind(queryDesc); - /* Set the destination to output to the tuplestore */ - queryDesc->dest = Tuplestore; + /* Change the destination to output to the tuplestore */ + queryDesc->dest = CreateTuplestoreDestReceiver(portal->holdStore, + portal->holdContext); /* Fetch the result set into the tuplestore */ ExecutorRun(queryDesc, ForwardScanDirection, 0L); + (*queryDesc->dest->destroy) (queryDesc->dest); + queryDesc->dest = NULL; + /* * Now shut down the inner executor. */ @@ -359,7 +347,6 @@ PersistHoldablePortal(Portal portal) /* Mark portal not active */ portal->portalActive = false; - CurrentPortal = saveCurrentPortal; PortalContext = savePortalContext; QueryContext = saveQueryContext; diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index 3f8beac53c..c317494f6f 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -10,7 +10,7 @@ * Copyright (c) 2002-2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.15 2003/05/05 00:44:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.16 2003/05/06 20:26:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -102,7 +102,7 @@ PrepareQuery(PrepareStmt *stmt) * Implements the 'EXECUTE' utility statement. */ void -ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest) +ExecuteQuery(ExecuteStmt *stmt, DestReceiver *dest) { PreparedStatement *entry; char *query_string; @@ -180,7 +180,7 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest) */ PortalStart(portal, paramLI); - (void) PortalRun(portal, FETCH_ALL, outputDest, outputDest, NULL); + (void) PortalRun(portal, FETCH_ALL, dest, dest, NULL); PortalDrop(portal, false); @@ -488,19 +488,21 @@ ExplainExecuteQuery(ExplainStmt *stmt, TupOutputState *tstate) { QueryDesc *qdesc; - /* Create a QueryDesc requesting no output */ - qdesc = CreateQueryDesc(query, plan, None, NULL, - paramLI, stmt->analyze); - if (execstmt->into) { - if (qdesc->operation != CMD_SELECT) + if (query->commandType != CMD_SELECT) elog(ERROR, "INTO clause specified for non-SELECT query"); + /* Copy the query so we can modify it */ + query = copyObject(query); + query->into = execstmt->into; - qdesc->dest = None; } + /* Create a QueryDesc requesting no output */ + qdesc = CreateQueryDesc(query, plan, None_Receiver, NULL, + paramLI, stmt->analyze); + ExplainOnePlan(qdesc, stmt, tstate); } diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index 4e2224e189..282fb19a85 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.8 2003/04/29 22:13:08 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.9 2003/05/06 20:26:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -133,7 +133,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) /* schemas should contain only utility stmts */ Assert(querytree->commandType == CMD_UTILITY); /* do this step */ - ProcessUtility(querytree->utilityStmt, None, NULL); + ProcessUtility(querytree->utilityStmt, None_Receiver, NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); } diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 719c945656..3d1b950e21 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 c81dd33d36..2e040f7890 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 ba41828be3..e89e5f32d6 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 74299ddf3e..c3b3ec3530 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 05b0c1f239..bcab8154a3 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; } diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c index 54b5ef75c1..bce77603f5 100644 --- a/src/backend/tcop/dest.c +++ b/src/backend/tcop/dest.c @@ -8,14 +8,14 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.56 2003/05/06 00:20:33 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.57 2003/05/06 20:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ /* * INTERFACE ROUTINES * BeginCommand - initialize the destination at start of command - * DestToFunction - identify per-tuple processing routines + * CreateDestReceiver - create tuple receiver object for destination * EndCommand - clean up the destination at end of command * NullCommand - tell dest that an empty query string was recognized * ReadyForQuery - tell dest that we are ready for a new query @@ -30,7 +30,6 @@ #include "access/printtup.h" #include "access/xact.h" -#include "executor/tstoreReceiver.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" @@ -45,14 +44,15 @@ donothingReceive(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) } static void -donothingSetup(DestReceiver *self, int operation, - const char *portalName, TupleDesc typeinfo, List *targetlist) +donothingStartup(DestReceiver *self, int operation, + const char *portalName, TupleDesc typeinfo, List *targetlist) { } static void donothingCleanup(DestReceiver *self) { + /* this is used for both shutdown and destroy methods */ } /* ---------------- @@ -60,17 +60,24 @@ donothingCleanup(DestReceiver *self) * ---------------- */ static DestReceiver donothingDR = { - donothingReceive, donothingSetup, donothingCleanup + donothingReceive, donothingStartup, donothingCleanup, donothingCleanup, + None }; static DestReceiver debugtupDR = { - debugtup, debugSetup, donothingCleanup + debugtup, debugStartup, donothingCleanup, donothingCleanup, + Debug }; static DestReceiver spi_printtupDR = { - spi_printtup, spi_dest_setup, donothingCleanup + spi_printtup, spi_dest_startup, donothingCleanup, donothingCleanup, + SPI }; +/* Globally available receiver for None */ +DestReceiver *None_Receiver = &donothingDR; + + /* ---------------- * BeginCommand - initialize the destination at start of command * ---------------- @@ -82,26 +89,19 @@ BeginCommand(const char *commandTag, CommandDest dest) } /* ---------------- - * DestToFunction - return appropriate receiver function set for dest + * CreateDestReceiver - return appropriate receiver function set for dest * ---------------- */ DestReceiver * -DestToFunction(CommandDest dest) +CreateDestReceiver(CommandDest dest) { switch (dest) { case Remote: - return printtup_create_DR(false, true); - case RemoteInternal: - return printtup_create_DR(true, true); - case RemoteExecute: - /* like Remote, but suppress output of T message */ - return printtup_create_DR(false, false); - case RemoteExecuteInternal: - return printtup_create_DR(true, false); + return printtup_create_DR(dest); case None: return &donothingDR; @@ -113,7 +113,12 @@ DestToFunction(CommandDest dest) return &spi_printtupDR; case Tuplestore: - return tstoreReceiverCreateDR(); + /* + * This is disallowed, you must use tstoreReceiver.c's + * specialized function to create a Tuplestore DestReceiver + */ + elog(ERROR, "CreateDestReceiver: cannot handle Tuplestore"); + break; } /* should never get here */ diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 0ec7fcf71d..a7dd5cb904 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.335 2003/05/06 05:15:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.336 2003/05/06 20:26:27 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -656,6 +656,8 @@ pg_plan_queries(List *querytrees, bool needSnapshot) static void exec_simple_query(const char *query_string) { + CommandDest dest = whereToSendOutput; + DestReceiver *receiver; MemoryContext oldcontext; List *parsetree_list, *parsetree_item; @@ -682,6 +684,12 @@ exec_simple_query(const char *query_string) if (save_log_statement_stats) ResetUsage(); + /* + * Create destination receiver object --- we can reuse it for all + * queries in the string. Note it is created in MessageContext. + */ + receiver = CreateDestReceiver(dest); + /* * Start up a transaction command. All queries generated by the * query_string will be in this same command block, *unless* we find a @@ -745,7 +753,7 @@ exec_simple_query(const char *query_string) set_ps_display(commandTag); - BeginCommand(commandTag, whereToSendOutput); + BeginCommand(commandTag, dest); /* * If we are in an aborted transaction, reject all commands except @@ -819,8 +827,8 @@ exec_simple_query(const char *query_string) (void) PortalRun(portal, FETCH_ALL, - whereToSendOutput, - whereToSendOutput, + receiver, + receiver, completionTag); PortalDrop(portal, false); @@ -868,14 +876,16 @@ exec_simple_query(const char *query_string) * (But a command aborted by error will not send an EndCommand * report at all.) */ - EndCommand(completionTag, whereToSendOutput); + EndCommand(completionTag, dest); } /* end loop over parsetrees */ /* * If there were no parsetrees, return EmptyQueryResponse message. */ if (!parsetree_list) - NullCommand(whereToSendOutput); + NullCommand(dest); + + (*receiver->destroy) (receiver); QueryContext = NULL; @@ -1282,6 +1292,7 @@ static void exec_execute_message(const char *portal_name, int is_binary, long max_rows) { CommandDest dest; + DestReceiver *receiver; Portal portal; bool is_trans_stmt = false; bool is_trans_exit = false; @@ -1363,15 +1374,19 @@ exec_execute_message(const char *portal_name, int is_binary, long max_rows) /* * Okay to run the portal. */ + receiver = CreateDestReceiver(dest); + if (max_rows <= 0) max_rows = FETCH_ALL; completed = PortalRun(portal, max_rows, - dest, - dest, + receiver, + receiver, completionTag); + (*receiver->destroy) (receiver); + if (completed) { if (is_trans_stmt) @@ -2344,7 +2359,7 @@ PostgresMain(int argc, char *argv[], const char *username) if (!IsUnderPostmaster) { puts("\nPOSTGRES backend interactive interface "); - puts("$Revision: 1.335 $ $Date: 2003/05/06 05:15:45 $\n"); + puts("$Revision: 1.336 $ $Date: 2003/05/06 20:26:27 $\n"); } /* @@ -2412,7 +2427,6 @@ PostgresMain(int argc, char *argv[], const char *username) */ MemoryContextSwitchTo(TopMemoryContext); MemoryContextResetAndDeleteChildren(ErrorContext); - CurrentPortal = NULL; PortalContext = NULL; QueryContext = NULL; diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index 280f269c8f..0cb7865a9f 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -8,13 +8,14 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.61 2003/05/06 00:20:33 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.62 2003/05/06 20:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "executor/executor.h" +#include "executor/tstoreReceiver.h" #include "miscadmin.h" #include "tcop/tcopprot.h" #include "tcop/pquery.h" @@ -24,18 +25,18 @@ static uint32 RunFromStore(Portal portal, ScanDirection direction, long count, - CommandDest dest); + DestReceiver *dest); static long PortalRunSelect(Portal portal, bool forward, long count, - CommandDest dest); + DestReceiver *dest); static void PortalRunUtility(Portal portal, Query *query, - CommandDest dest, char *completionTag); + DestReceiver *dest, char *completionTag); static void PortalRunMulti(Portal portal, - CommandDest dest, CommandDest altdest, + DestReceiver *dest, DestReceiver *altdest, char *completionTag); static long DoPortalRunFetch(Portal portal, FetchDirection fdirection, long count, - CommandDest dest); + DestReceiver *dest); static void DoPortalRewind(Portal portal); @@ -45,7 +46,7 @@ static void DoPortalRewind(Portal portal); QueryDesc * CreateQueryDesc(Query *parsetree, Plan *plantree, - CommandDest dest, + DestReceiver *dest, const char *portalName, ParamListInfo params, bool doInstrument) @@ -103,7 +104,7 @@ ProcessQuery(Query *parsetree, Plan *plan, ParamListInfo params, const char *portalName, - CommandDest dest, + DestReceiver *dest, char *completionTag) { int operation = parsetree->commandType; @@ -123,7 +124,7 @@ ProcessQuery(Query *parsetree, * special-cases this case. (Perhaps would be cleaner to have * an additional destination type?) */ - dest = None; + dest = None_Receiver; } } @@ -185,6 +186,39 @@ ProcessQuery(Query *parsetree, FreeQueryDesc(queryDesc); } +/* + * ChoosePortalStrategy + * Select portal execution strategy given the intended query list. + * + * See the comments in portal.h. + */ +PortalStrategy +ChoosePortalStrategy(List *parseTrees) +{ + PortalStrategy strategy; + + strategy = PORTAL_MULTI_QUERY; /* default assumption */ + + if (length(parseTrees) == 1) + { + Query *query = (Query *) lfirst(parseTrees); + + if (query->commandType == CMD_SELECT && + query->canSetTag && + query->into == NULL) + { + strategy = PORTAL_ONE_SELECT; + } + else if (query->commandType == CMD_UTILITY && + query->canSetTag && + query->utilityStmt != NULL) + { + if (UtilityReturnsTuples(query->utilityStmt)) + strategy = PORTAL_UTIL_SELECT; + } + } + return strategy; +} /* * PortalStart @@ -202,7 +236,6 @@ void PortalStart(Portal portal, ParamListInfo params) { MemoryContext oldContext; - Query *query = NULL; QueryDesc *queryDesc; AssertArg(PortalIsValid(portal)); @@ -215,23 +248,9 @@ PortalStart(Portal portal, ParamListInfo params) portal->portalParams = params; /* - * Determine the portal execution strategy (see comments in portal.h) + * Determine the portal execution strategy */ - portal->strategy = PORTAL_MULTI_QUERY; /* default assumption */ - if (length(portal->parseTrees) == 1) - { - query = (Query *) lfirst(portal->parseTrees); - if (query->commandType == CMD_SELECT && - query->canSetTag && - query->into == NULL) - portal->strategy = PORTAL_ONE_SELECT; - else if (query->commandType == CMD_UTILITY && - query->canSetTag && - query->utilityStmt != NULL) - { - /* XXX check for things that can be PORTAL_UTIL_SELECT */ - } - } + portal->strategy = ChoosePortalStrategy(portal->parseTrees); /* * Fire her up according to the strategy @@ -247,9 +266,9 @@ PortalStart(Portal portal, ParamListInfo params) * Create QueryDesc in portal's context; for the moment, set * the destination to None. */ - queryDesc = CreateQueryDesc(query, + queryDesc = CreateQueryDesc((Query *) lfirst(portal->parseTrees), (Plan *) lfirst(portal->planTrees), - None, + None_Receiver, portal->name, params, false); @@ -261,6 +280,9 @@ PortalStart(Portal portal, ParamListInfo params) * This tells PortalCleanup to shut down the executor */ portal->queryDesc = queryDesc; + /* + * Remember tuple descriptor + */ portal->tupDesc = queryDesc->tupDesc; /* * Reset cursor position data to "start of query" @@ -272,10 +294,19 @@ PortalStart(Portal portal, ParamListInfo params) break; case PORTAL_UTIL_SELECT: - /* XXX implement later */ - /* XXX query snapshot here? no, RunUtility will do it */ - /* xxx what about Params? */ - portal->tupDesc = NULL; + /* + * We don't set query snapshot here, because PortalRunUtility + * will take care of it. + */ + portal->tupDesc = + UtilityTupleDescriptor(((Query *) lfirst(portal->parseTrees))->utilityStmt); + /* + * Reset cursor position data to "start of query" + */ + portal->atStart = true; + portal->atEnd = false; /* allow fetches */ + portal->portalPos = 0; + portal->posOverflow = false; break; case PORTAL_MULTI_QUERY: @@ -310,11 +341,11 @@ PortalStart(Portal portal, ParamListInfo params) * suspended due to exhaustion of the count parameter. */ bool -PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest, +PortalRun(Portal portal, long count, + DestReceiver *dest, DestReceiver *altdest, char *completionTag) { bool result; - Portal saveCurrentPortal; MemoryContext savePortalContext; MemoryContext saveQueryContext; MemoryContext oldContext; @@ -336,10 +367,8 @@ PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest, portal->portalActive = true; /* - * Set global portal and context pointers. + * Set global portal context pointers. */ - saveCurrentPortal = CurrentPortal; - CurrentPortal = portal; savePortalContext = PortalContext; PortalContext = PortalGetHeapMemory(portal); saveQueryContext = QueryContext; @@ -367,8 +396,14 @@ PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest, */ if (!portal->portalUtilReady) { + DestReceiver *treceiver; + + PortalCreateHoldStore(portal); + treceiver = CreateTuplestoreDestReceiver(portal->holdStore, + portal->holdContext); PortalRunUtility(portal, lfirst(portal->parseTrees), - Tuplestore, NULL); + treceiver, NULL); + (*treceiver->destroy) (treceiver); portal->portalUtilReady = true; } /* @@ -404,7 +439,6 @@ PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest, /* Mark portal not active */ portal->portalActive = false; - CurrentPortal = saveCurrentPortal; PortalContext = savePortalContext; QueryContext = saveQueryContext; @@ -431,7 +465,7 @@ long PortalRunSelect(Portal portal, bool forward, long count, - CommandDest dest) + DestReceiver *dest) { QueryDesc *queryDesc; ScanDirection direction; @@ -568,21 +602,18 @@ PortalRunSelect(Portal portal, */ static uint32 RunFromStore(Portal portal, ScanDirection direction, long count, - CommandDest dest) + DestReceiver *dest) { - DestReceiver *destfunc; List *targetlist; long current_tuple_count = 0; - destfunc = DestToFunction(dest); - if (portal->strategy == PORTAL_ONE_SELECT) targetlist = ((Plan *) lfirst(portal->planTrees))->targetlist; else targetlist = NIL; - (*destfunc->setup) (destfunc, CMD_SELECT, portal->name, portal->tupDesc, - targetlist); + (*dest->startup) (dest, CMD_SELECT, portal->name, portal->tupDesc, + targetlist); if (direction == NoMovementScanDirection) { @@ -608,7 +639,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count, if (tup == NULL) break; - (*destfunc->receiveTuple) (tup, portal->tupDesc, destfunc); + (*dest->receiveTuple) (tup, portal->tupDesc, dest); if (should_free) pfree(tup); @@ -624,7 +655,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count, } } - (*destfunc->cleanup) (destfunc); + (*dest->shutdown) (dest); return (uint32) current_tuple_count; } @@ -635,7 +666,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count, */ static void PortalRunUtility(Portal portal, Query *query, - CommandDest dest, char *completionTag) + DestReceiver *dest, char *completionTag) { Node *utilityStmt = query->utilityStmt; @@ -690,7 +721,7 @@ PortalRunUtility(Portal portal, Query *query, */ static void PortalRunMulti(Portal portal, - CommandDest dest, CommandDest altdest, + DestReceiver *dest, DestReceiver *altdest, char *completionTag) { List *plantree_list = portal->planTrees; @@ -807,10 +838,9 @@ long PortalRunFetch(Portal portal, FetchDirection fdirection, long count, - CommandDest dest) + DestReceiver *dest) { long result; - Portal saveCurrentPortal; MemoryContext savePortalContext; MemoryContext saveQueryContext; MemoryContext oldContext; @@ -828,10 +858,8 @@ PortalRunFetch(Portal portal, portal->portalActive = true; /* - * Set global portal and context pointers. + * Set global portal context pointers. */ - saveCurrentPortal = CurrentPortal; - CurrentPortal = portal; savePortalContext = PortalContext; PortalContext = PortalGetHeapMemory(portal); saveQueryContext = QueryContext; @@ -856,7 +884,6 @@ PortalRunFetch(Portal portal, /* Mark portal not active */ portal->portalActive = false; - CurrentPortal = saveCurrentPortal; PortalContext = savePortalContext; QueryContext = saveQueryContext; @@ -873,7 +900,7 @@ static long DoPortalRunFetch(Portal portal, FetchDirection fdirection, long count, - CommandDest dest) + DestReceiver *dest) { bool forward; @@ -912,7 +939,8 @@ DoPortalRunFetch(Portal portal, { DoPortalRewind(portal); if (count > 1) - PortalRunSelect(portal, true, count-1, None); + PortalRunSelect(portal, true, count-1, + None_Receiver); } else { @@ -921,9 +949,11 @@ DoPortalRunFetch(Portal portal, if (portal->atEnd) pos++; /* need one extra fetch if off end */ if (count <= pos) - PortalRunSelect(portal, false, pos-count+1, None); + PortalRunSelect(portal, false, pos-count+1, + None_Receiver); else if (count > pos+1) - PortalRunSelect(portal, true, count-pos-1, None); + PortalRunSelect(portal, true, count-pos-1, + None_Receiver); } return PortalRunSelect(portal, true, 1L, dest); } @@ -936,9 +966,9 @@ DoPortalRunFetch(Portal portal, * (Is it worth considering case where count > half of size * of query? We could rewind once we know the size ...) */ - PortalRunSelect(portal, true, FETCH_ALL, None); + PortalRunSelect(portal, true, FETCH_ALL, None_Receiver); if (count < -1) - PortalRunSelect(portal, false, -count-1, None); + PortalRunSelect(portal, false, -count-1, None_Receiver); return PortalRunSelect(portal, false, 1L, dest); } else /* count == 0 */ @@ -955,7 +985,7 @@ DoPortalRunFetch(Portal portal, * Definition: advance count-1 rows, return next row (if any). */ if (count > 1) - PortalRunSelect(portal, true, count-1, None); + PortalRunSelect(portal, true, count-1, None_Receiver); return PortalRunSelect(portal, true, 1L, dest); } else if (count < 0) @@ -965,7 +995,7 @@ DoPortalRunFetch(Portal portal, * (if any). */ if (count < -1) - PortalRunSelect(portal, false, -count-1, None); + PortalRunSelect(portal, false, -count-1, None_Receiver); return PortalRunSelect(portal, false, 1L, dest); } else /* count == 0 */ @@ -995,7 +1025,7 @@ DoPortalRunFetch(Portal portal, /* Are we sitting on a row? */ on_row = (!portal->atStart && !portal->atEnd); - if (dest == None) + if (dest->mydest == None) { /* MOVE 0 returns 0/1 based on if FETCH 0 would return a row */ return on_row ? 1L : 0L; @@ -1011,7 +1041,7 @@ DoPortalRunFetch(Portal portal, */ if (on_row) { - PortalRunSelect(portal, false, 1L, None); + PortalRunSelect(portal, false, 1L, None_Receiver); /* Set up to fetch one row forward */ count = 1; forward = true; @@ -1022,7 +1052,7 @@ DoPortalRunFetch(Portal portal, /* * Optimize MOVE BACKWARD ALL into a Rewind. */ - if (!forward && count == FETCH_ALL && dest == None) + if (!forward && count == FETCH_ALL && dest->mydest == None) { long result = portal->portalPos; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index a0431f350c..5fce0d5e75 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.198 2003/05/02 20:54:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.199 2003/05/06 20:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -47,6 +47,7 @@ #include "parser/parse_type.h" #include "rewrite/rewriteDefine.h" #include "rewrite/rewriteRemove.h" +#include "tcop/pquery.h" #include "tcop/utility.h" #include "utils/acl.h" #include "utils/guc.h" @@ -244,7 +245,7 @@ check_xact_readonly(Node *parsetree) */ void ProcessUtility(Node *parsetree, - CommandDest dest, + DestReceiver *dest, char *completionTag) { check_xact_readonly(parsetree); @@ -310,7 +311,7 @@ ProcessUtility(Node *parsetree, * Portal (cursor) manipulation */ case T_DeclareCursorStmt: - PerformCursorOpen((DeclareCursorStmt *) parsetree, dest); + PerformCursorOpen((DeclareCursorStmt *) parsetree); break; case T_ClosePortalStmt: @@ -880,7 +881,7 @@ ProcessUtility(Node *parsetree, { VariableShowStmt *n = (VariableShowStmt *) parsetree; - GetPGVariable(n->name); + GetPGVariable(n->name, dest); } break; @@ -1028,6 +1029,137 @@ ProcessUtility(Node *parsetree, } } +/* + * UtilityReturnsTuples + * Return "true" if this utility statement will send output to the + * destination. + * + * Generally, there should be a case here for each case in ProcessUtility + * where "dest" is passed on. + */ +bool +UtilityReturnsTuples(Node *parsetree) +{ + switch (nodeTag(parsetree)) + { + case T_FetchStmt: + { + FetchStmt *stmt = (FetchStmt *) parsetree; + Portal portal; + + if (stmt->ismove) + return false; + portal = GetPortalByName(stmt->portalname); + if (!PortalIsValid(portal)) + return false; /* not our business to raise error */ + /* + * Note: if portal contains multiple statements then it's + * possible some of them will return tuples, but we don't + * handle that case here. + */ + return portal->tupDesc ? true : false; + } + + case T_ExecuteStmt: + { + ExecuteStmt *stmt = (ExecuteStmt *) parsetree; + PreparedStatement *entry; + + if (stmt->into) + return false; + entry = FetchPreparedStatement(stmt->name, false); + if (!entry) + return false; /* not our business to raise error */ + switch (ChoosePortalStrategy(entry->query_list)) + { + case PORTAL_ONE_SELECT: + return true; + case PORTAL_UTIL_SELECT: + return true; + case PORTAL_MULTI_QUERY: + /* can't figure it out, per note above */ + break; + } + return false; + } + + case T_ExplainStmt: + return true; + + case T_VariableShowStmt: + return true; + + default: + return false; + } +} + +/* + * UtilityTupleDescriptor + * Fetch the actual output tuple descriptor for a utility statement + * for which UtilityReturnsTuples() previously returned "true". + * + * The returned descriptor is created in (or copied into) the current memory + * context. + */ +TupleDesc +UtilityTupleDescriptor(Node *parsetree) +{ + switch (nodeTag(parsetree)) + { + case T_FetchStmt: + { + FetchStmt *stmt = (FetchStmt *) parsetree; + Portal portal; + + if (stmt->ismove) + return NULL; + portal = GetPortalByName(stmt->portalname); + if (!PortalIsValid(portal)) + return NULL; /* not our business to raise error */ + return CreateTupleDescCopy(portal->tupDesc); + } + + case T_ExecuteStmt: + { + ExecuteStmt *stmt = (ExecuteStmt *) parsetree; + PreparedStatement *entry; + Query *query; + + if (stmt->into) + return NULL; + entry = FetchPreparedStatement(stmt->name, false); + if (!entry) + return NULL; /* not our business to raise error */ + switch (ChoosePortalStrategy(entry->query_list)) + { + case PORTAL_ONE_SELECT: + query = (Query *) lfirst(entry->query_list); + return ExecCleanTypeFromTL(query->targetList, false); + case PORTAL_UTIL_SELECT: + query = (Query *) lfirst(entry->query_list); + return UtilityTupleDescriptor(query->utilityStmt); + case PORTAL_MULTI_QUERY: + break; + } + return NULL; + } + + case T_ExplainStmt: + return ExplainResultDesc((ExplainStmt *) parsetree); + + case T_VariableShowStmt: + { + VariableShowStmt *n = (VariableShowStmt *) parsetree; + + return GetPGVariableResultDesc(n->name); + } + + default: + return NULL; + } +} + /* * CreateCommandTag diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 77cf062685..a5651ff7f0 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.122 2003/05/02 22:02:47 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.123 2003/05/06 20:26:27 tgl Exp $ * *-------------------------------------------------------------------- */ @@ -2438,12 +2438,41 @@ set_config_by_name(PG_FUNCTION_ARGS) * SHOW command */ void -GetPGVariable(const char *name) +GetPGVariable(const char *name, DestReceiver *dest) { if (strcasecmp(name, "all") == 0) - ShowAllGUCConfig(); + ShowAllGUCConfig(dest); else - ShowGUCConfigOption(name); + ShowGUCConfigOption(name, dest); +} + +TupleDesc +GetPGVariableResultDesc(const char *name) +{ + TupleDesc tupdesc; + + if (strcasecmp(name, "all") == 0) + { + /* need a tuple descriptor representing two TEXT columns */ + tupdesc = CreateTemplateTupleDesc(2, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", + TEXTOID, -1, 0, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting", + TEXTOID, -1, 0, false); + } + else + { + const char *varname; + + /* Get the canonical spelling of name */ + (void) GetConfigOptionByName(name, &varname); + + /* need a tuple descriptor representing a single TEXT column */ + tupdesc = CreateTemplateTupleDesc(1, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, (char *) varname, + TEXTOID, -1, 0, false); + } + return tupdesc; } /* @@ -2468,11 +2497,10 @@ ResetPGVariable(const char *name) * SHOW command */ void -ShowGUCConfigOption(const char *name) +ShowGUCConfigOption(const char *name, DestReceiver *dest) { TupOutputState *tstate; TupleDesc tupdesc; - CommandDest dest = whereToSendOutput; const char *varname; char *value; @@ -2497,12 +2525,11 @@ ShowGUCConfigOption(const char *name) * SHOW ALL command */ void -ShowAllGUCConfig(void) +ShowAllGUCConfig(DestReceiver *dest) { int i; TupOutputState *tstate; TupleDesc tupdesc; - CommandDest dest = whereToSendOutput; char *values[2]; /* need a tuple descriptor representing two TEXT columns */ diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index 2fb62f4aba..fc42c0b52c 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -12,12 +12,13 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.57 2003/05/05 00:44:56 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.58 2003/05/06 20:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include "miscadmin.h" #include "commands/portalcmds.h" #include "executor/executor.h" #include "utils/hsearch.h" @@ -36,9 +37,6 @@ * ---------------- */ -Portal CurrentPortal = NULL; /* globally visible pointer */ - - #define MAX_PORTALNAME_LEN NAMEDATALEN typedef struct portalhashent @@ -251,6 +249,38 @@ PortalDefineQuery(Portal portal, portal->queryContext = queryContext; } +/* + * PortalCreateHoldStore + * Create the tuplestore for a portal. + */ +void +PortalCreateHoldStore(Portal portal) +{ + MemoryContext oldcxt; + + Assert(portal->holdContext == NULL); + Assert(portal->holdStore == NULL); + + /* + * Create the memory context that is used for storage of the tuple set. + * Note this is NOT a child of the portal's heap memory. + */ + portal->holdContext = + AllocSetContextCreate(PortalMemory, + "PortalHeapMemory", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + + /* Create the tuple store, selecting cross-transaction temp files. */ + oldcxt = MemoryContextSwitchTo(portal->holdContext); + + /* XXX: Should SortMem be used for this? */ + portal->holdStore = tuplestore_begin_heap(true, true, SortMem); + + MemoryContextSwitchTo(oldcxt); +} + /* * PortalDrop * Destroy the portal. @@ -279,6 +309,21 @@ PortalDrop(Portal portal, bool isError) if (PointerIsValid(portal->cleanup)) (*portal->cleanup) (portal, isError); + /* + * Delete tuplestore if present. We should do this even under error + * conditions; since the tuplestore would have been using cross- + * transaction storage, its temp files need to be explicitly deleted. + */ + if (portal->holdStore) + { + MemoryContext oldcontext; + + oldcontext = MemoryContextSwitchTo(portal->holdContext); + tuplestore_end(portal->holdStore); + MemoryContextSwitchTo(oldcontext); + portal->holdStore = NULL; + } + /* delete tuplestore storage, if any */ if (portal->holdContext) MemoryContextDelete(portal->holdContext); @@ -360,27 +405,12 @@ AtCommit_Portals(void) * We are exiting the transaction that created a holdable * cursor. Instead of dropping the portal, prepare it for * access by later transactions. - */ - - /* - * Create the memory context that is used for storage of - * the held cursor's tuple set. Note this is NOT a child - * of the portal's heap memory. - */ - portal->holdContext = - AllocSetContextCreate(PortalMemory, - "PortalHeapMemory", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); - - /* - * Transfer data into the held tuplestore. * * Note that PersistHoldablePortal() must release all * resources used by the portal that are local to the creating * transaction. */ + PortalCreateHoldStore(portal); PersistHoldablePortal(portal); } else diff --git a/src/include/access/printtup.h b/src/include/access/printtup.h index c4c92fb1bb..9d10fe4607 100644 --- a/src/include/access/printtup.h +++ b/src/include/access/printtup.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: printtup.h,v 1.25 2003/05/06 00:20:33 tgl Exp $ + * $Id: printtup.h,v 1.26 2003/05/06 20:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,19 +16,19 @@ #include "tcop/dest.h" -extern DestReceiver *printtup_create_DR(bool isBinary, bool sendDescrip); +extern DestReceiver *printtup_create_DR(CommandDest dest); extern void SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist); -extern void debugSetup(DestReceiver *self, int operation, +extern void debugStartup(DestReceiver *self, int operation, const char *portalName, TupleDesc typeinfo, List *targetlist); extern void debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self); /* XXX these are really in executor/spi.c */ -extern void spi_dest_setup(DestReceiver *self, int operation, +extern void spi_dest_startup(DestReceiver *self, int operation, const char *portalName, TupleDesc typeinfo, List *targetlist); -extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc, +extern void spi_printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self); #endif /* PRINTTUP_H */ diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h index 040740490b..69b2268920 100644 --- a/src/include/commands/explain.h +++ b/src/include/commands/explain.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * - * $Id: explain.h,v 1.18 2003/02/02 23:46:38 tgl Exp $ + * $Id: explain.h,v 1.19 2003/05/06 20:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -18,7 +18,10 @@ #include "tcop/dest.h" -extern void ExplainQuery(ExplainStmt *stmt, CommandDest dest); +extern void ExplainQuery(ExplainStmt *stmt, DestReceiver *dest); + +extern TupleDesc ExplainResultDesc(ExplainStmt *stmt); + extern void ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt, TupOutputState *tstate); diff --git a/src/include/commands/portalcmds.h b/src/include/commands/portalcmds.h index f89ac36fa5..ce874df667 100644 --- a/src/include/commands/portalcmds.h +++ b/src/include/commands/portalcmds.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: portalcmds.h,v 1.9 2003/05/05 00:44:56 tgl Exp $ + * $Id: portalcmds.h,v 1.10 2003/05/06 20:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,9 +17,9 @@ #include "utils/portal.h" -extern void PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest); +extern void PerformCursorOpen(DeclareCursorStmt *stmt); -extern void PerformPortalFetch(FetchStmt *stmt, CommandDest dest, +extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest, char *completionTag); extern void PerformPortalClose(const char *name); diff --git a/src/include/commands/prepare.h b/src/include/commands/prepare.h index 5d24c579a4..2438077624 100644 --- a/src/include/commands/prepare.h +++ b/src/include/commands/prepare.h @@ -6,7 +6,7 @@ * * Copyright (c) 2002-2003, PostgreSQL Global Development Group * - * $Id: prepare.h,v 1.4 2003/05/05 00:44:56 tgl Exp $ + * $Id: prepare.h,v 1.5 2003/05/06 20:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -42,7 +42,7 @@ typedef struct /* Utility statements PREPARE, EXECUTE, DEALLOCATE, EXPLAIN EXECUTE */ extern void PrepareQuery(PrepareStmt *stmt); -extern void ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest); +extern void ExecuteQuery(ExecuteStmt *stmt, DestReceiver *dest); extern void DeallocateQuery(DeallocateStmt *stmt); extern void ExplainExecuteQuery(ExplainStmt *stmt, TupOutputState *tstate); diff --git a/src/include/executor/execdesc.h b/src/include/executor/execdesc.h index 27148bb1d8..9c54ed1d64 100644 --- a/src/include/executor/execdesc.h +++ b/src/include/executor/execdesc.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: execdesc.h,v 1.22 2002/12/15 16:17:54 tgl Exp $ + * $Id: execdesc.h,v 1.23 2003/05/06 20:26:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -33,7 +33,7 @@ typedef struct QueryDesc CmdType operation; /* CMD_SELECT, CMD_UPDATE, etc. */ Query *parsetree; /* rewritten parsetree */ Plan *plantree; /* planner's output */ - CommandDest dest; /* the destination output of the execution */ + DestReceiver *dest; /* the destination for tuple output */ const char *portalName; /* name of portal, or NULL */ ParamListInfo params; /* param values being passed in */ bool doInstrument; /* TRUE requests runtime instrumentation */ @@ -46,7 +46,7 @@ typedef struct QueryDesc /* in pquery.c */ extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree, - CommandDest dest, const char *portalName, + DestReceiver *dest, const char *portalName, ParamListInfo params, bool doInstrument); diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 302bc2681c..707b8c9fa6 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: executor.h,v 1.93 2003/05/06 00:20:33 tgl Exp $ + * $Id: executor.h,v 1.94 2003/05/06 20:26:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -161,16 +161,18 @@ extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate); extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate, TupleDesc tupType); extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid); +extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid); extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg); typedef struct TupOutputState { /* use "struct" here to allow forward reference */ struct AttInMetadata *metadata; - DestReceiver *destfunc; + DestReceiver *dest; } TupOutputState; -extern TupOutputState *begin_tup_output_tupdesc(CommandDest dest, TupleDesc tupdesc); +extern TupOutputState *begin_tup_output_tupdesc(DestReceiver *dest, + TupleDesc tupdesc); extern void do_tup_output(TupOutputState *tstate, char **values); extern void do_text_output_multiline(TupOutputState *tstate, char *text); extern void end_tup_output(TupOutputState *tstate); diff --git a/src/include/executor/tstoreReceiver.h b/src/include/executor/tstoreReceiver.h index e5fb7a9509..e7d9497ffe 100644 --- a/src/include/executor/tstoreReceiver.h +++ b/src/include/executor/tstoreReceiver.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: tstoreReceiver.h,v 1.1 2003/03/27 16:55:11 momjian Exp $ + * $Id: tstoreReceiver.h,v 1.2 2003/05/06 20:26:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,7 +16,10 @@ #define TSTORE_RECEIVER_H #include "tcop/dest.h" +#include "utils/tuplestore.h" -extern DestReceiver *tstoreReceiverCreateDR(void); + +extern DestReceiver *CreateTuplestoreDestReceiver(Tuplestorestate *tStore, + MemoryContext tContext); #endif /* TSTORE_RECEIVER_H */ diff --git a/src/include/tcop/dest.h b/src/include/tcop/dest.h index be2338b7f3..d2162e9976 100644 --- a/src/include/tcop/dest.h +++ b/src/include/tcop/dest.h @@ -21,30 +21,40 @@ * dest.c defines three functions that implement destination management: * * BeginCommand: initialize the destination at start of command. - * DestToFunction: return a pointer to a struct of destination-specific + * CreateDestReceiver: return a pointer to a struct of destination-specific * receiver functions. * EndCommand: clean up the destination at end of command. * * BeginCommand/EndCommand are executed once per received SQL query. * - * DestToFunction, and the receiver functions it links to, are executed - * each time we run the executor to produce tuples, which may occur - * multiple times per received query (eg, due to additional queries produced - * by rewrite rules). + * CreateDestReceiver returns a receiver object appropriate to the specified + * destination. The executor, as well as utility statements that can return + * tuples, are passed the resulting DestReceiver* pointer. Each executor run + * or utility execution calls the receiver's startup method, then the + * receiveTuple method (zero or more times), then the shutdown method. + * The same receiver object may be re-used multiple times; eventually it is + * destroyed by calling its destroy method. * - * The DestReceiver object returned by DestToFunction may be a statically - * allocated object (for destination types that require no local state) - * or can be a palloc'd object that has DestReceiver as its first field - * and contains additional fields (see printtup.c for an example). These - * additional fields are then accessible to the DestReceiver functions - * by casting the DestReceiver* pointer passed to them. - * The palloc'd object is pfree'd by the DestReceiver's cleanup function. + * The DestReceiver object returned by CreateDestReceiver may be a statically + * allocated object (for destination types that require no local state), + * in which case destroy is a no-op. Alternatively it can be a palloc'd + * object that has DestReceiver as its first field and contains additional + * fields (see printtup.c for an example). These additional fields are then + * accessible to the DestReceiver functions by casting the DestReceiver* + * pointer passed to them. The palloc'd object is pfree'd by the destroy + * method. Note that the caller of CreateDestReceiver should take care to + * do so in a memory context that is long-lived enough for the receiver + * object not to disappear while still needed. + * + * Special provision: None_Receiver is a permanently available receiver + * object for the None destination. This avoids useless creation/destroy + * calls in portal and cursor manipulations. * * * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: dest.h,v 1.36 2003/05/06 00:20:33 tgl Exp $ + * $Id: dest.h,v 1.37 2003/05/06 20:26:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -63,7 +73,7 @@ * destination. Someday this will probably need to be improved. * * Note: only the values None, Debug, Remote are legal for the global - * variable whereToSendOutput. The other values may be selected + * variable whereToSendOutput. The other values may be used * as the destination for individual commands. * ---------------- */ @@ -84,6 +94,11 @@ typedef enum * DestReceiver is a base type for destination-specific local state. * In the simplest cases, there is no state info, just the function * pointers that the executor must call. + * + * Note: the receiveTuple routine must be passed a TupleDesc identical to the + * one given to the startup routine. The reason for passing it again is just + * that some destinations would otherwise need dynamic state merely to + * remember the tupledesc pointer. * ---------------- */ typedef struct _DestReceiver DestReceiver; @@ -93,19 +108,25 @@ struct _DestReceiver /* Called for each tuple to be output: */ void (*receiveTuple) (HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self); - /* Initialization and teardown: */ - void (*setup) (DestReceiver *self, int operation, - const char *portalName, - TupleDesc typeinfo, - List *targetlist); - void (*cleanup) (DestReceiver *self); + /* Per-executor-run initialization and shutdown: */ + void (*startup) (DestReceiver *self, int operation, + const char *portalName, + TupleDesc typeinfo, + List *targetlist); + void (*shutdown) (DestReceiver *self); + /* Destroy the receiver object itself (if dynamically allocated) */ + void (*destroy) (DestReceiver *self); + /* CommandDest code for this receiver */ + CommandDest mydest; /* Private fields might appear beyond this point... */ }; +extern DestReceiver *None_Receiver; /* permanent receiver for None */ + /* The primary destination management functions */ extern void BeginCommand(const char *commandTag, CommandDest dest); -extern DestReceiver *DestToFunction(CommandDest dest); +extern DestReceiver *CreateDestReceiver(CommandDest dest); extern void EndCommand(const char *commandTag, CommandDest dest); /* Additional functions that go with destination management, more or less. */ diff --git a/src/include/tcop/pquery.h b/src/include/tcop/pquery.h index bf3344d2bd..d9d6a6221d 100644 --- a/src/include/tcop/pquery.h +++ b/src/include/tcop/pquery.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pquery.h,v 1.25 2003/05/02 20:54:36 tgl Exp $ + * $Id: pquery.h,v 1.26 2003/05/06 20:26:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,18 +21,20 @@ extern void ProcessQuery(Query *parsetree, Plan *plan, ParamListInfo params, const char *portalName, - CommandDest dest, + DestReceiver *dest, char *completionTag); +extern PortalStrategy ChoosePortalStrategy(List *parseTrees); + extern void PortalStart(Portal portal, ParamListInfo params); extern bool PortalRun(Portal portal, long count, - CommandDest dest, CommandDest altdest, + DestReceiver *dest, DestReceiver *altdest, char *completionTag); extern long PortalRunFetch(Portal portal, FetchDirection fdirection, long count, - CommandDest dest); + DestReceiver *dest); #endif /* PQUERY_H */ diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h index 96c0dc43c5..38edd4346a 100644 --- a/src/include/tcop/utility.h +++ b/src/include/tcop/utility.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: utility.h,v 1.17 2003/05/02 20:54:36 tgl Exp $ + * $Id: utility.h,v 1.18 2003/05/06 20:26:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,9 +16,13 @@ #include "executor/execdesc.h" -extern void ProcessUtility(Node *parsetree, CommandDest dest, +extern void ProcessUtility(Node *parsetree, DestReceiver *dest, char *completionTag); +extern bool UtilityReturnsTuples(Node *parsetree); + +extern TupleDesc UtilityTupleDescriptor(Node *parsetree); + extern const char *CreateCommandTag(Node *parsetree); #endif /* UTILITY_H */ diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 359adaabcf..c9b4b93ce5 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -7,13 +7,14 @@ * Copyright 2000-2003 by PostgreSQL Global Development Group * Written by Peter Eisentraut . * - * $Id: guc.h,v 1.30 2003/05/02 22:02:47 momjian Exp $ + * $Id: guc.h,v 1.31 2003/05/06 20:26:28 tgl Exp $ *-------------------------------------------------------------------- */ #ifndef GUC_H #define GUC_H #include "nodes/pg_list.h" +#include "tcop/dest.h" #include "utils/array.h" @@ -119,14 +120,15 @@ extern void ParseLongOption(const char *string, char **name, char **value); extern bool set_config_option(const char *name, const char *value, GucContext context, GucSource source, bool isLocal, bool DoIt); -extern void ShowGUCConfigOption(const char *name); -extern void ShowAllGUCConfig(void); +extern void ShowGUCConfigOption(const char *name, DestReceiver *dest); +extern void ShowAllGUCConfig(DestReceiver *dest); extern char *GetConfigOptionByName(const char *name, const char **varname); extern char *GetConfigOptionByNum(int varnum, const char **varname, bool *noshow); extern int GetNumConfigOptions(void); extern void SetPGVariable(const char *name, List *args, bool is_local); -extern void GetPGVariable(const char *name); +extern void GetPGVariable(const char *name, DestReceiver *dest); +extern TupleDesc GetPGVariableResultDesc(const char *name); extern void ResetPGVariable(const char *name); extern char *flatten_set_variable_args(const char *name, List *args); diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h index 2353ba01d4..e2617f321e 100644 --- a/src/include/utils/portal.h +++ b/src/include/utils/portal.h @@ -39,7 +39,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: portal.h,v 1.42 2003/05/02 20:54:36 tgl Exp $ + * $Id: portal.h,v 1.43 2003/05/06 20:26:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -156,10 +156,6 @@ typedef struct PortalData #define PortalGetHeapMemory(portal) ((portal)->heap) -/* Currently executing Portal, if any */ -extern DLLIMPORT Portal CurrentPortal; - - /* Prototypes for functions in utils/mmgr/portalmem.c */ extern void EnablePortalManager(void); extern void AtCommit_Portals(void); @@ -176,5 +172,6 @@ extern void PortalDefineQuery(Portal portal, List *parseTrees, List *planTrees, MemoryContext queryContext); +extern void PortalCreateHoldStore(Portal portal); #endif /* PORTAL_H */