diff options
Diffstat (limited to 'src/backend/utils/mmgr/portalmem.c')
-rw-r--r-- | src/backend/utils/mmgr/portalmem.c | 123 |
1 files changed, 115 insertions, 8 deletions
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index 0402005a372..1bd9cc61d85 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -12,15 +12,19 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.83 2005/11/22 18:17:27 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.84 2006/01/18 06:49:27 neilc Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include "miscadmin.h" +#include "access/heapam.h" +#include "catalog/pg_type.h" #include "commands/portalcmds.h" #include "executor/executor.h" +#include "funcapi.h" +#include "miscadmin.h" +#include "utils/builtins.h" #include "utils/hsearch.h" #include "utils/memutils.h" #include "utils/portal.h" @@ -56,8 +60,8 @@ do { \ \ MemSet(key, 0, MAX_PORTALNAME_LEN); \ StrNCpy(key, NAME, MAX_PORTALNAME_LEN); \ - hentry = (PortalHashEnt*)hash_search(PortalHashTable, \ - key, HASH_FIND, NULL); \ + hentry = (PortalHashEnt *) hash_search(PortalHashTable, \ + key, HASH_FIND, NULL); \ if (hentry) \ PORTAL = hentry->portal; \ else \ @@ -70,8 +74,8 @@ do { \ \ MemSet(key, 0, MAX_PORTALNAME_LEN); \ StrNCpy(key, NAME, MAX_PORTALNAME_LEN); \ - hentry = (PortalHashEnt*)hash_search(PortalHashTable, \ - key, HASH_ENTER, &found); \ + hentry = (PortalHashEnt *) hash_search(PortalHashTable, \ + key, HASH_ENTER, &found); \ if (found) \ elog(ERROR, "duplicate portal name"); \ hentry->portal = PORTAL; \ @@ -85,8 +89,8 @@ do { \ \ MemSet(key, 0, MAX_PORTALNAME_LEN); \ StrNCpy(key, PORTAL->name, MAX_PORTALNAME_LEN); \ - hentry = (PortalHashEnt*)hash_search(PortalHashTable, \ - key, HASH_REMOVE, NULL); \ + hentry = (PortalHashEnt *) hash_search(PortalHashTable, \ + key, HASH_REMOVE, NULL); \ if (hentry == NULL) \ elog(WARNING, "trying to delete portal name that does not exist"); \ } while(0) @@ -190,12 +194,15 @@ CreatePortal(const char *name, bool allowDup, bool dupSilent) "Portal"); /* initialize portal fields that don't start off zero */ + portal->status = PORTAL_NEW; portal->cleanup = PortalCleanup; portal->createSubid = GetCurrentSubTransactionId(); portal->strategy = PORTAL_MULTI_QUERY; portal->cursorOptions = CURSOR_OPT_NO_SCROLL; portal->atStart = true; portal->atEnd = true; /* disallow fetches until query is set */ + portal->visible = true; + portal->creation_time = GetCurrentTimestamp(); /* put portal in table (sets portal->name) */ PortalHashTableInsert(portal, name); @@ -756,3 +763,103 @@ AtSubCleanup_Portals(SubTransactionId mySubid) PortalDrop(portal, false); } } + +/* Find all available cursors */ +Datum +pg_cursor(PG_FUNCTION_ARGS) +{ + FuncCallContext *funcctx; + HASH_SEQ_STATUS *hash_seq; + PortalHashEnt *hentry; + + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) + { + MemoryContext oldcontext; + TupleDesc tupdesc; + + /* create a function context for cross-call persistence */ + funcctx = SRF_FIRSTCALL_INIT(); + + /* + * switch to memory context appropriate for multiple function + * calls + */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + if (PortalHashTable) + { + hash_seq = (HASH_SEQ_STATUS *) palloc(sizeof(HASH_SEQ_STATUS)); + hash_seq_init(hash_seq, PortalHashTable); + funcctx->user_fctx = (void *) hash_seq; + } + else + funcctx->user_fctx = NULL; + + /* + * build tupdesc for result tuples. This must match the + * definition of the pg_cursors view in system_views.sql + */ + tupdesc = CreateTemplateTupleDesc(6, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_holdable", + BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_binary", + BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_scrollable", + BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "creation_time", + TIMESTAMPTZOID, -1, 0); + + funcctx->tuple_desc = BlessTupleDesc(tupdesc); + MemoryContextSwitchTo(oldcontext); + } + + /* stuff done on every call of the function */ + funcctx = SRF_PERCALL_SETUP(); + hash_seq = (HASH_SEQ_STATUS *) funcctx->user_fctx; + + /* if the hash table is uninitialized, we're done */ + if (hash_seq == NULL) + SRF_RETURN_DONE(funcctx); + + /* loop until we find a visible portal or hit the end of the list */ + while ((hentry = hash_seq_search(hash_seq)) != NULL) + { + if (hentry->portal->visible) + break; + } + + if (hentry) + { + Portal portal; + Datum result; + HeapTuple tuple; + Datum values[6]; + bool nulls[6]; + + portal = hentry->portal; + MemSet(nulls, 0, sizeof(nulls)); + + values[0] = DirectFunctionCall1(textin, CStringGetDatum(portal->name)); + if (!portal->sourceText) + nulls[1] = true; + else + values[1] = DirectFunctionCall1(textin, + CStringGetDatum(portal->sourceText)); + values[2] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_HOLD); + values[3] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_BINARY); + values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL); + values[5] = TimestampTzGetDatum(portal->creation_time); + + tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); + result = HeapTupleGetDatum(tuple); + SRF_RETURN_NEXT(funcctx, result); + } + + SRF_RETURN_DONE(funcctx); +} + |