diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 8808a03f1a..8a3be15a05 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.121 2001/02/14 21:35:00 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.122 2001/02/27 22:07:34 tgl Exp $ * * NOTES * The PerformAddAttribute() code, like most of the relation @@ -107,8 +107,8 @@ PerformPortalFetch(char *name, CommandDest dest) { Portal portal; - int feature; QueryDesc *queryDesc; + EState *estate; MemoryContext oldcontext; /* ---------------- @@ -140,19 +140,14 @@ PerformPortalFetch(char *name, oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); /* ---------------- - * setup "feature" to tell the executor which direction to go in. - * ---------------- - */ - if (forward) - feature = EXEC_FOR; - else - feature = EXEC_BACK; - - /* ---------------- - * tell the destination to prepare to receive some tuples + * tell the destination to prepare to receive some tuples. + * + * If we've been asked for a MOVE, make a temporary QueryDesc + * with the appropriate dummy destination. * ---------------- */ queryDesc = PortalGetQueryDesc(portal); + estate = PortalGetState(portal); if (dest == None) /* MOVE */ { @@ -165,7 +160,7 @@ PerformPortalFetch(char *name, BeginCommand(name, queryDesc->operation, - portal->attinfo, /* QueryDescGetTypeInfo(queryDesc) */ + PortalGetTupleDesc(portal), false, /* portal fetches don't end up in * relations */ false, /* this is a portal fetch, not a "retrieve @@ -174,18 +169,45 @@ PerformPortalFetch(char *name, dest); /* ---------------- - * execute the portal fetch operation + * Determine which direction to go in, and check to see if we're already + * at the end of the available tuples in that direction. If so, do + * nothing. (This check exists because not all plan node types are + * robust about being called again if they've already returned NULL + * once.) If it's OK to do the fetch, call the executor. Then, + * update the atStart/atEnd state depending on the number of tuples + * that were retrieved. * ---------------- */ - ExecutorRun(queryDesc, PortalGetState(portal), feature, (long) count); + if (forward) + { + if (! portal->atEnd) + { + ExecutorRun(queryDesc, estate, EXEC_FOR, (long) count); + if (estate->es_processed > 0) + portal->atStart = false; /* OK to back up now */ + if (count <= 0 || (int) estate->es_processed < count) + portal->atEnd = true; /* we retrieved 'em all */ + } + } + else + { + if (! portal->atStart) + { + ExecutorRun(queryDesc, estate, EXEC_BACK, (long) count); + if (estate->es_processed > 0) + portal->atEnd = false; /* OK to go forward now */ + if (count <= 0 || (int) estate->es_processed < count) + portal->atStart = true; /* we retrieved 'em all */ + } + } + /* ---------------- + * Clean up and switch back to old context. + * ---------------- + */ if (dest == None) /* MOVE */ pfree(queryDesc); - /* ---------------- - * Switch back to old context. - * ---------------- - */ MemoryContextSwitchTo(oldcontext); /* ---------------- diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index 3481bc675e..b36b9f6510 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.41 2001/01/24 19:43:09 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.42 2001/02/27 22:07:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -248,7 +248,7 @@ ProcessQuery(Query *parsetree, * ---------------- */ if (isRetrieveIntoRelation) - queryDesc->dest = (int) None; + queryDesc->dest = None; /* ---------------- * create a default executor state. diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index 08db60a492..63d3ed363c 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -8,44 +8,26 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.39 2001/01/24 19:43:17 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.40 2001/02/27 22:07:34 tgl Exp $ * *------------------------------------------------------------------------- */ /* * NOTES - * Do not confuse "Portal" with "PortalEntry" (or "PortalBuffer"). - * When a PQexec() routine is run, the resulting tuples - * find their way into a "PortalEntry". The contents of the resulting - * "PortalEntry" can then be inspected by other PQxxx functions. + * A "Portal" is a structure used to keep track of cursor queries. * - * A "Portal" is a structure used to keep track of queries of the - * form: - * retrieve portal FOO ( blah... ) where blah... - * - * When the backend sees a "retrieve portal" query, it allocates - * a "PortalD" structure, plans the query and then stores the query + * When the backend sees a "declare cursor" query, it allocates a + * "PortalData" structure, plans the query and then stores the query * in the portal without executing it. Later, when the backend * sees a - * fetch 1 into FOO - * + * fetch 1 from FOO * the system looks up the portal named "FOO" in the portal table, * gets the planned query and then calls the executor with a feature of * '(EXEC_FOR 1). The executor then runs the query and returns a single * tuple. The problem is that we have to hold onto the state of the - * portal query until we see a "close p". This means we have to be + * portal query until we see a "close". This means we have to be * careful about memory management. * - * Having said all that, here is what a PortalD currently looks like: - * - * struct PortalD { - * char* name; - * classObj(MemoryContext) heap; - * List queryDesc; - * EState state; - * void (*cleanup) ARGS((Portal portal)); - * }; - * * I hope this makes things clearer to whoever reads this -cim 2/22/91 */ @@ -188,43 +170,13 @@ PortalSetQuery(Portal portal, AssertArg(IsA((Node *) state, EState)); portal->queryDesc = queryDesc; - portal->state = state; portal->attinfo = attinfo; + portal->state = state; + portal->atStart = true; /* Allow fetch forward only */ + portal->atEnd = false; portal->cleanup = cleanup; } -/* - * PortalGetQueryDesc - * Returns query attached to portal. - * - * Exceptions: - * BadState if called when disabled. - * BadArg if portal is invalid. - */ -QueryDesc * -PortalGetQueryDesc(Portal portal) -{ - AssertArg(PortalIsValid(portal)); - - return portal->queryDesc; -} - -/* - * PortalGetState - * Returns state attached to portal. - * - * Exceptions: - * BadState if called when disabled. - * BadArg if portal is invalid. - */ -EState * -PortalGetState(Portal portal) -{ - AssertArg(PortalIsValid(portal)); - - return portal->state; -} - /* * CreatePortal * Returns a new portal given a name. @@ -265,7 +217,8 @@ CreatePortal(char *name) portal->queryDesc = NULL; portal->attinfo = NULL; portal->state = NULL; - + portal->atStart = true; /* disallow fetches until query is set */ + portal->atEnd = true; portal->cleanup = NULL; /* put portal in table */ @@ -315,13 +268,3 @@ AtEOXact_portals(void) { HashTableWalk(PortalHashTable, (HashtFunc) PortalDrop, 0); } - -/* - * PortalGetHeapMemory - * Returns heap memory context for a given portal. - */ -MemoryContext -PortalGetHeapMemory(Portal portal) -{ - return portal->heap; -} diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h index 9c09e8eaef..27ef1bf433 100644 --- a/src/include/utils/portal.h +++ b/src/include/utils/portal.h @@ -7,19 +7,14 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: portal.h,v 1.25 2001/01/24 19:43:28 momjian Exp $ + * $Id: portal.h,v 1.26 2001/02/27 22:07:34 tgl Exp $ * *------------------------------------------------------------------------- */ /* * Note: * A portal is an abstraction which represents the execution state of - * a running query (or a fixed sequence of queries). - * - * Note: - * now that PQ calls can be made from within a backend, a portal - * may also be used to keep track of the tuples resulting - * from the execution of a query. In this case, entryIndex + * a running query (specifically, a CURSOR). */ #ifndef PORTAL_H #define PORTAL_H @@ -28,17 +23,19 @@ #include "nodes/memnodes.h" -typedef struct PortalD *Portal; +typedef struct PortalData *Portal; -typedef struct PortalD +typedef struct PortalData { char *name; /* Portal's name */ MemoryContext heap; /* subsidiary memory */ QueryDesc *queryDesc; /* Info about query associated with portal */ TupleDesc attinfo; - EState *state; + EState *state; /* Execution state of query */ + bool atStart; /* T => fetch backwards is not allowed */ + bool atEnd; /* T => fetch forwards is not allowed */ void (*cleanup) (Portal); /* Cleanup routine (optional) */ -} PortalD; +} PortalData; /* * PortalIsValid @@ -46,6 +43,21 @@ typedef struct PortalD */ #define PortalIsValid(p) PointerIsValid(p) +/* + * Access macros for Portal ... use these in preference to field access. + */ +#define PortalGetQueryDesc(portal) ((portal)->queryDesc) +#define PortalGetTupleDesc(portal) ((portal)->attinfo) +#define PortalGetState(portal) ((portal)->state) +#define PortalGetHeapMemory(portal) ((portal)->heap) + +/* + * estimate of the maximum number of open portals a user would have, + * used in initially sizing the PortalHashTable in EnablePortalManager() + */ +#define PORTALS_PER_USER 10 + + extern void EnablePortalManager(void); extern void AtEOXact_portals(void); extern Portal CreatePortal(char *name); @@ -54,14 +66,6 @@ extern Portal GetPortalByName(char *name); extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc, TupleDesc attinfo, EState *state, void (*cleanup) (Portal portal)); -extern QueryDesc *PortalGetQueryDesc(Portal portal); -extern EState *PortalGetState(Portal portal); -extern MemoryContext PortalGetHeapMemory(Portal portal); - -/* estimate of the maximum number of open portals a user would have, - * used in initially sizing the PortalHashTable in EnablePortalManager() - */ -#define PORTALS_PER_USER 10 #endif /* PORTAL_H */