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 + -
显示快捷键?