portalmem.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 960 行 · 第 1/2 页
C
960 行
/* * Pre-commit processing for portals. * * Any holdable cursors created in this transaction need to be converted to * materialized form, since we are going to close down the executor and * release locks. Other portals are not touched yet. * * Returns TRUE if any holdable cursors were processed, FALSE if not. */boolCommitHoldablePortals(void){ bool result = false; HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; /* Is it a holdable portal created in the current xact? */ if ((portal->cursorOptions & CURSOR_OPT_HOLD) && portal->createSubid != InvalidSubTransactionId && portal->status == PORTAL_READY) { /* * We are exiting the transaction that created a holdable cursor. * Instead of dropping the portal, prepare it for access by later * transactions. * * Note that PersistHoldablePortal() must release all resources * used by the portal that are local to the creating transaction. */ PortalCreateHoldStore(portal); PersistHoldablePortal(portal); /* drop cached plan reference, if any */ if (portal->cplan) PortalReleaseCachedPlan(portal); /* * Any resources belonging to the portal will be released in the * upcoming transaction-wide cleanup; the portal will no longer * have its own resources. */ portal->resowner = NULL; /* * Having successfully exported the holdable cursor, mark it as * not belonging to this transaction. */ portal->createSubid = InvalidSubTransactionId; result = true; } } return result;}/* * Pre-prepare processing for portals. * * Currently we refuse PREPARE if the transaction created any holdable * cursors, since it's quite unclear what to do with one. However, this * has the same API as CommitHoldablePortals and is invoked in the same * way by xact.c, so that we can easily do something reasonable if anyone * comes up with something reasonable to do. * * Returns TRUE if any holdable cursors were processed, FALSE if not. */boolPrepareHoldablePortals(void){ bool result = false; HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; /* Is it a holdable portal created in the current xact? */ if ((portal->cursorOptions & CURSOR_OPT_HOLD) && portal->createSubid != InvalidSubTransactionId && portal->status == PORTAL_READY) { /* * We are exiting the transaction that created a holdable cursor. * Can't do PREPARE. */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot PREPARE a transaction that has created a cursor WITH HOLD"))); } } return result;}/* * Pre-commit processing for portals. * * Remove all non-holdable portals created in this transaction. * Portals remaining from prior transactions should be left untouched. */voidAtCommit_Portals(void){ HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; /* * Do not touch active portals --- this can only happen in the case of * a multi-transaction utility command, such as VACUUM. * * Note however that any resource owner attached to such a portal is * still going to go away, so don't leave a dangling pointer. */ if (portal->status == PORTAL_ACTIVE) { portal->resowner = NULL; continue; } /* * Do nothing to cursors held over from a previous transaction * (including holdable ones just frozen by CommitHoldablePortals). */ if (portal->createSubid == InvalidSubTransactionId) continue; /* Zap all non-holdable portals */ PortalDrop(portal, true); /* Restart the iteration in case that led to other drops */ /* XXX is this really necessary? */ hash_seq_term(&status); hash_seq_init(&status, PortalHashTable); }}/* * Abort processing for portals. * * At this point we reset "active" status and run the cleanup hook if * present, but we can't release the portal's memory until the cleanup call. * * The reason we need to reset active is so that we can replace the unnamed * portal, else we'll fail to execute ROLLBACK when it arrives. */voidAtAbort_Portals(void){ HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; if (portal->status == PORTAL_ACTIVE) portal->status = PORTAL_FAILED; /* * Do nothing else to cursors held over from a previous transaction. */ if (portal->createSubid == InvalidSubTransactionId) continue; /* let portalcmds.c clean up the state it knows about */ if (PointerIsValid(portal->cleanup)) { (*portal->cleanup) (portal); portal->cleanup = NULL; } /* drop cached plan reference, if any */ if (portal->cplan) PortalReleaseCachedPlan(portal); /* * Any resources belonging to the portal will be released in the * upcoming transaction-wide cleanup; they will be gone before we run * PortalDrop. */ portal->resowner = NULL; /* * Although we can't delete the portal data structure proper, we can * release any memory in subsidiary contexts, such as executor state. * The cleanup hook was the last thing that might have needed data * there. */ MemoryContextDeleteChildren(PortalGetHeapMemory(portal)); }}/* * Post-abort cleanup for portals. * * Delete all portals not held over from prior transactions. */voidAtCleanup_Portals(void){ HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; /* Do nothing to cursors held over from a previous transaction */ if (portal->createSubid == InvalidSubTransactionId) { Assert(portal->status != PORTAL_ACTIVE); Assert(portal->resowner == NULL); continue; } /* Else zap it. */ PortalDrop(portal, false); }}/* * Pre-subcommit processing for portals. * * Reassign the portals created in the current subtransaction to the parent * subtransaction. */voidAtSubCommit_Portals(SubTransactionId mySubid, SubTransactionId parentSubid, ResourceOwner parentXactOwner){ HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; if (portal->createSubid == mySubid) { portal->createSubid = parentSubid; if (portal->resowner) ResourceOwnerNewParent(portal->resowner, parentXactOwner); } }}/* * Subtransaction abort handling for portals. * * Deactivate portals created during the failed subtransaction. * Note that per AtSubCommit_Portals, this will catch portals created * in descendants of the subtransaction too. * * We don't destroy any portals here; that's done in AtSubCleanup_Portals. */voidAtSubAbort_Portals(SubTransactionId mySubid, SubTransactionId parentSubid, ResourceOwner parentXactOwner){ HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; if (portal->createSubid != mySubid) continue; /* * Force any active portals of my own transaction into FAILED state. * This is mostly to ensure that a portal running a FETCH will go * FAILED if the underlying cursor fails. (Note we do NOT want to do * this to upper-level portals, since they may be able to continue.) * * This is only needed to dodge the sanity check in PortalDrop. */ if (portal->status == PORTAL_ACTIVE) portal->status = PORTAL_FAILED; /* * If the portal is READY then allow it to survive into the parent * transaction; otherwise shut it down. * * Currently, we can't actually support that because the portal's * query might refer to objects created or changed in the failed * subtransaction, leading to crashes if execution is resumed. So, * even READY portals are deleted. It would be nice to detect whether * the query actually depends on any such object, instead. */#ifdef NOT_USED if (portal->status == PORTAL_READY) { portal->createSubid = parentSubid; if (portal->resowner) ResourceOwnerNewParent(portal->resowner, parentXactOwner); } else#endif { /* let portalcmds.c clean up the state it knows about */ if (PointerIsValid(portal->cleanup)) { (*portal->cleanup) (portal); portal->cleanup = NULL; } /* drop cached plan reference, if any */ if (portal->cplan) PortalReleaseCachedPlan(portal); /* * Any resources belonging to the portal will be released in the * upcoming transaction-wide cleanup; they will be gone before we * run PortalDrop. */ portal->resowner = NULL; /* * Although we can't delete the portal data structure proper, we * can release any memory in subsidiary contexts, such as executor * state. The cleanup hook was the last thing that might have * needed data there. */ MemoryContextDeleteChildren(PortalGetHeapMemory(portal)); } }}/* * Post-subabort cleanup for portals. * * Drop all portals created in the failed subtransaction (but note that * we will not drop any that were reassigned to the parent above). */voidAtSubCleanup_Portals(SubTransactionId mySubid){ HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; if (portal->createSubid != mySubid) continue; /* Zap it. */ PortalDrop(portal, false); }}/* Find all available cursors */Datumpg_cursor(PG_FUNCTION_ARGS){ ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupdesc; Tuplestorestate *tupstore; MemoryContext per_query_ctx; MemoryContext oldcontext; HASH_SEQ_STATUS hash_seq; PortalHashEnt *hentry; /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); if (!(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("materialize mode required, but it is not " \ "allowed in this context"))); /* need to build tuplestore in query context */ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; oldcontext = MemoryContextSwitchTo(per_query_ctx); /* * 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); /* * We put all the tuples into a tuplestore in one scan of the hashtable. * This avoids any issue of the hashtable possibly changing between calls. */ tupstore = tuplestore_begin_heap(true, false, work_mem); hash_seq_init(&hash_seq, PortalHashTable); while ((hentry = hash_seq_search(&hash_seq)) != NULL) { Portal portal = hentry->portal; HeapTuple tuple; Datum values[6]; bool nulls[6]; /* report only "visible" entries */ if (!portal->visible) continue; /* generate junk in short-term context */ MemoryContextSwitchTo(oldcontext); 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(tupdesc, values, nulls); /* switch to appropriate context while storing the tuple */ MemoryContextSwitchTo(per_query_ctx); tuplestore_puttuple(tupstore, tuple); } /* clean up and return the tuplestore */ tuplestore_donestoring(tupstore); MemoryContextSwitchTo(oldcontext); rsinfo->returnMode = SFRM_Materialize; rsinfo->setResult = tupstore; rsinfo->setDesc = tupdesc; return (Datum) 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?