mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
Restructure error handling as recently discussed. It is now really
possible to trap an error inside a function rather than letting it propagate out to PostgresMain. You still have to use AbortCurrentTransaction to clean up, but at least the error handling itself will cooperate.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.426 2004/07/28 22:05:46 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.427 2004/07/31 00:45:36 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* this is the "main" module of the postgres backend and
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#if HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
@@ -77,12 +76,6 @@ const char *debug_query_string; /* for pgmonitor and
|
||||
/* Note: whereToSendOutput is initialized for the bootstrap/standalone case */
|
||||
CommandDest whereToSendOutput = Debug;
|
||||
|
||||
/* note: these declarations had better match tcopprot.h */
|
||||
sigjmp_buf Warn_restart;
|
||||
|
||||
bool Warn_restart_ready = false;
|
||||
bool InError = false;
|
||||
|
||||
/* flag for logging end of session */
|
||||
bool Log_disconnections = false;
|
||||
|
||||
@@ -1876,7 +1869,7 @@ quickdie(SIGNAL_ARGS)
|
||||
|
||||
/*
|
||||
* Ideally this should be ereport(FATAL), but then we'd not get
|
||||
* control back (perhaps could fix by doing local sigsetjmp?)
|
||||
* control back...
|
||||
*/
|
||||
ereport(WARNING,
|
||||
(errcode(ERRCODE_CRASH_SHUTDOWN),
|
||||
@@ -1962,10 +1955,9 @@ StatementCancelHandler(SIGNAL_ARGS)
|
||||
int save_errno = errno;
|
||||
|
||||
/*
|
||||
* Don't joggle the elbow of proc_exit, nor an already-in-progress
|
||||
* abort
|
||||
* Don't joggle the elbow of proc_exit
|
||||
*/
|
||||
if (!proc_exit_inprogress && !InError)
|
||||
if (!proc_exit_inprogress)
|
||||
{
|
||||
InterruptPending = true;
|
||||
QueryCancelPending = true;
|
||||
@@ -2148,7 +2140,6 @@ usage(const char *progname)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* PostgresMain
|
||||
* postgres main loop -- all backends, interactive or otherwise start here
|
||||
@@ -2175,6 +2166,7 @@ PostgresMain(int argc, char *argv[], const char *username)
|
||||
int firstchar;
|
||||
char stack_base;
|
||||
StringInfoData input_message;
|
||||
sigjmp_buf local_sigjmp_buf;
|
||||
volatile bool send_rfq = true;
|
||||
|
||||
/*
|
||||
@@ -2772,50 +2764,61 @@ PostgresMain(int argc, char *argv[], const char *username)
|
||||
*
|
||||
* If an exception is encountered, processing resumes here so we abort
|
||||
* the current transaction and start a new one.
|
||||
*
|
||||
* You might wonder why this isn't coded as an infinite loop around
|
||||
* a PG_TRY construct. The reason is that this is the bottom of the
|
||||
* exception stack, and so with PG_TRY there would be no exception
|
||||
* handler in force at all during the CATCH part. By leaving the
|
||||
* outermost setjmp always active, we have at least some chance of
|
||||
* recovering from an error during error recovery. (If we get into
|
||||
* an infinite loop thereby, it will soon be stopped by overflow of
|
||||
* elog.c's internal state stack.)
|
||||
*/
|
||||
|
||||
if (sigsetjmp(Warn_restart, 1) != 0)
|
||||
if (sigsetjmp(local_sigjmp_buf, 1) != 0)
|
||||
{
|
||||
/*
|
||||
* NOTE: if you are tempted to add more code in this if-block,
|
||||
* consider the probability that it should be in
|
||||
* AbortTransaction() instead.
|
||||
*
|
||||
* Make sure we're not interrupted while cleaning up. Also forget
|
||||
* any pending QueryCancel request, since we're aborting anyway.
|
||||
* Force InterruptHoldoffCount to a known state in case we
|
||||
* ereport'd from inside a holdoff section.
|
||||
* consider the high probability that it should be in
|
||||
* AbortTransaction() instead. The only stuff done directly here
|
||||
* should be stuff that is guaranteed to apply *only* for outer-level
|
||||
* error recovery, such as adjusting the FE/BE protocol status.
|
||||
*/
|
||||
|
||||
/* Since not using PG_TRY, must reset error stack by hand */
|
||||
error_context_stack = NULL;
|
||||
|
||||
/* Prevent interrupts while cleaning up */
|
||||
HOLD_INTERRUPTS();
|
||||
|
||||
/*
|
||||
* Forget any pending QueryCancel request, since we're returning
|
||||
* to the idle loop anyway, and cancel the statement timer if running.
|
||||
*/
|
||||
ImmediateInterruptOK = false;
|
||||
QueryCancelPending = false;
|
||||
InterruptHoldoffCount = 1;
|
||||
CritSectionCount = 0; /* should be unnecessary, but... */
|
||||
disable_sig_alarm(true);
|
||||
QueryCancelPending = false; /* again in case timeout occurred */
|
||||
|
||||
/*
|
||||
* Turn off these interrupts too. This is only needed here and not
|
||||
* in other exception-catching places since these interrupts are
|
||||
* only enabled while we wait for client input.
|
||||
*/
|
||||
DisableNotifyInterrupt();
|
||||
DisableCatchupInterrupt();
|
||||
|
||||
/* Report the error to the client and/or server log */
|
||||
EmitErrorReport();
|
||||
|
||||
/*
|
||||
* Make sure debug_query_string gets reset before we possibly clobber
|
||||
* the storage it points at.
|
||||
*/
|
||||
debug_query_string = NULL;
|
||||
|
||||
/*
|
||||
* If there's an active portal, mark it as failed
|
||||
* Abort the current transaction in order to recover.
|
||||
*/
|
||||
if (ActivePortal)
|
||||
ActivePortal->status = PORTAL_FAILED;
|
||||
|
||||
/*
|
||||
* Make sure we are in a valid memory context during recovery.
|
||||
*
|
||||
* We use ErrorContext in hopes that it will have some free space
|
||||
* even if we're otherwise up against it...
|
||||
*/
|
||||
MemoryContextSwitchTo(ErrorContext);
|
||||
|
||||
/* Make sure we are using a sane ResourceOwner, too */
|
||||
CurrentResourceOwner = CurTransactionResourceOwner;
|
||||
|
||||
/* Do the recovery */
|
||||
ereport(DEBUG2,
|
||||
(errmsg_internal("AbortCurrentTransaction")));
|
||||
AbortCurrentTransaction();
|
||||
|
||||
/*
|
||||
@@ -2823,23 +2826,9 @@ PostgresMain(int argc, char *argv[], const char *username)
|
||||
* for next time.
|
||||
*/
|
||||
MemoryContextSwitchTo(TopMemoryContext);
|
||||
MemoryContextResetAndDeleteChildren(ErrorContext);
|
||||
ActivePortal = NULL;
|
||||
PortalContext = NULL;
|
||||
FlushErrorState();
|
||||
QueryContext = NULL;
|
||||
|
||||
/*
|
||||
* Clear flag to indicate that we got out of error recovery mode
|
||||
* successfully. (Flag was set in elog.c before longjmp().)
|
||||
*/
|
||||
InError = false;
|
||||
xact_started = false;
|
||||
|
||||
/*
|
||||
* Clear flag that causes accounting for cost based vacuum.
|
||||
*/
|
||||
VacuumCostActive = false;
|
||||
|
||||
/*
|
||||
* If we were handling an extended-query-protocol message,
|
||||
* initiate skip till next Sync. This also causes us not to issue
|
||||
@@ -2848,13 +2837,15 @@ PostgresMain(int argc, char *argv[], const char *username)
|
||||
if (doing_extended_query_message)
|
||||
ignore_till_sync = true;
|
||||
|
||||
/*
|
||||
* Exit interrupt holdoff section we implicitly established above.
|
||||
*/
|
||||
/* We don't have a transaction command open anymore */
|
||||
xact_started = false;
|
||||
|
||||
/* Now we can allow interrupts again */
|
||||
RESUME_INTERRUPTS();
|
||||
}
|
||||
|
||||
Warn_restart_ready = true; /* we can now handle ereport(ERROR) */
|
||||
/* We can now handle ereport(ERROR) */
|
||||
PG_exception_stack = &local_sigjmp_buf;
|
||||
|
||||
PG_SETMASK(&UnBlockSig);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.81 2004/07/17 03:29:00 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.82 2004/07/31 00:45:36 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -246,94 +246,110 @@ PortalStart(Portal portal, ParamListInfo params)
|
||||
AssertState(portal->status == PORTAL_NEW); /* else extra PortalStart */
|
||||
|
||||
/*
|
||||
* Set global portal context pointers. (Should we set QueryContext?)
|
||||
* Set up global portal context pointers. (Should we set QueryContext?)
|
||||
*/
|
||||
saveActivePortal = ActivePortal;
|
||||
ActivePortal = portal;
|
||||
saveResourceOwner = CurrentResourceOwner;
|
||||
CurrentResourceOwner = portal->resowner;
|
||||
savePortalContext = PortalContext;
|
||||
PortalContext = PortalGetHeapMemory(portal);
|
||||
|
||||
oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||
|
||||
/* Must remember portal param list, if any */
|
||||
portal->portalParams = params;
|
||||
|
||||
/*
|
||||
* Determine the portal execution strategy
|
||||
*/
|
||||
portal->strategy = ChoosePortalStrategy(portal->parseTrees);
|
||||
|
||||
/*
|
||||
* Fire her up according to the strategy
|
||||
*/
|
||||
switch (portal->strategy)
|
||||
PG_TRY();
|
||||
{
|
||||
case PORTAL_ONE_SELECT:
|
||||
ActivePortal = portal;
|
||||
CurrentResourceOwner = portal->resowner;
|
||||
PortalContext = PortalGetHeapMemory(portal);
|
||||
|
||||
/*
|
||||
* Must set query snapshot before starting executor.
|
||||
*/
|
||||
SetQuerySnapshot();
|
||||
oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||
|
||||
/*
|
||||
* Create QueryDesc in portal's context; for the moment, set
|
||||
* the destination to None.
|
||||
*/
|
||||
queryDesc = CreateQueryDesc((Query *) linitial(portal->parseTrees),
|
||||
(Plan *) linitial(portal->planTrees),
|
||||
None_Receiver,
|
||||
params,
|
||||
false);
|
||||
/* Must remember portal param list, if any */
|
||||
portal->portalParams = params;
|
||||
|
||||
/*
|
||||
* Call ExecStart to prepare the plan for execution
|
||||
*/
|
||||
ExecutorStart(queryDesc, false, false);
|
||||
/*
|
||||
* Determine the portal execution strategy
|
||||
*/
|
||||
portal->strategy = ChoosePortalStrategy(portal->parseTrees);
|
||||
|
||||
/*
|
||||
* This tells PortalCleanup to shut down the executor
|
||||
*/
|
||||
portal->queryDesc = queryDesc;
|
||||
/*
|
||||
* Fire her up according to the strategy
|
||||
*/
|
||||
switch (portal->strategy)
|
||||
{
|
||||
case PORTAL_ONE_SELECT:
|
||||
|
||||
/*
|
||||
* Remember tuple descriptor (computed by ExecutorStart)
|
||||
*/
|
||||
portal->tupDesc = queryDesc->tupDesc;
|
||||
/*
|
||||
* Must set query snapshot before starting executor.
|
||||
*/
|
||||
SetQuerySnapshot();
|
||||
|
||||
/*
|
||||
* Reset cursor position data to "start of query"
|
||||
*/
|
||||
portal->atStart = true;
|
||||
portal->atEnd = false; /* allow fetches */
|
||||
portal->portalPos = 0;
|
||||
portal->posOverflow = false;
|
||||
break;
|
||||
/*
|
||||
* Create QueryDesc in portal's context; for the moment, set
|
||||
* the destination to None.
|
||||
*/
|
||||
queryDesc = CreateQueryDesc((Query *) linitial(portal->parseTrees),
|
||||
(Plan *) linitial(portal->planTrees),
|
||||
None_Receiver,
|
||||
params,
|
||||
false);
|
||||
|
||||
case PORTAL_UTIL_SELECT:
|
||||
/*
|
||||
* Call ExecStart to prepare the plan for execution
|
||||
*/
|
||||
ExecutorStart(queryDesc, false, false);
|
||||
|
||||
/*
|
||||
* We don't set query snapshot here, because PortalRunUtility
|
||||
* will take care of it.
|
||||
*/
|
||||
portal->tupDesc =
|
||||
UtilityTupleDescriptor(((Query *) linitial(portal->parseTrees))->utilityStmt);
|
||||
/*
|
||||
* This tells PortalCleanup to shut down the executor
|
||||
*/
|
||||
portal->queryDesc = queryDesc;
|
||||
|
||||
/*
|
||||
* Reset cursor position data to "start of query"
|
||||
*/
|
||||
portal->atStart = true;
|
||||
portal->atEnd = false; /* allow fetches */
|
||||
portal->portalPos = 0;
|
||||
portal->posOverflow = false;
|
||||
break;
|
||||
/*
|
||||
* Remember tuple descriptor (computed by ExecutorStart)
|
||||
*/
|
||||
portal->tupDesc = queryDesc->tupDesc;
|
||||
|
||||
case PORTAL_MULTI_QUERY:
|
||||
/* Need do nothing now */
|
||||
portal->tupDesc = NULL;
|
||||
break;
|
||||
/*
|
||||
* 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_UTIL_SELECT:
|
||||
|
||||
/*
|
||||
* We don't set query snapshot here, because PortalRunUtility
|
||||
* will take care of it.
|
||||
*/
|
||||
portal->tupDesc =
|
||||
UtilityTupleDescriptor(((Query *) linitial(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:
|
||||
/* Need do nothing now */
|
||||
portal->tupDesc = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
/* Uncaught error while executing portal: mark it dead */
|
||||
portal->status = PORTAL_FAILED;
|
||||
|
||||
/* Restore global vars and propagate error */
|
||||
ActivePortal = saveActivePortal;
|
||||
CurrentResourceOwner = saveResourceOwner;
|
||||
PortalContext = savePortalContext;
|
||||
|
||||
PG_RE_THROW();
|
||||
}
|
||||
PG_END_TRY();
|
||||
|
||||
MemoryContextSwitchTo(oldContext);
|
||||
|
||||
@@ -449,91 +465,108 @@ PortalRun(Portal portal, long count,
|
||||
portal->status = PORTAL_ACTIVE;
|
||||
|
||||
/*
|
||||
* Set global portal context pointers.
|
||||
* Set up global portal context pointers.
|
||||
*/
|
||||
saveActivePortal = ActivePortal;
|
||||
ActivePortal = portal;
|
||||
saveResourceOwner = CurrentResourceOwner;
|
||||
CurrentResourceOwner = portal->resowner;
|
||||
savePortalContext = PortalContext;
|
||||
PortalContext = PortalGetHeapMemory(portal);
|
||||
saveQueryContext = QueryContext;
|
||||
QueryContext = portal->queryContext;
|
||||
|
||||
oldContext = MemoryContextSwitchTo(PortalContext);
|
||||
|
||||
switch (portal->strategy)
|
||||
PG_TRY();
|
||||
{
|
||||
case PORTAL_ONE_SELECT:
|
||||
(void) PortalRunSelect(portal, true, count, dest);
|
||||
/* we know the query is supposed to set the tag */
|
||||
if (completionTag && portal->commandTag)
|
||||
strcpy(completionTag, portal->commandTag);
|
||||
ActivePortal = portal;
|
||||
CurrentResourceOwner = portal->resowner;
|
||||
PortalContext = PortalGetHeapMemory(portal);
|
||||
QueryContext = portal->queryContext;
|
||||
|
||||
/* Mark portal not active */
|
||||
portal->status = PORTAL_READY;
|
||||
oldContext = MemoryContextSwitchTo(PortalContext);
|
||||
|
||||
/*
|
||||
* Since it's a forward fetch, say DONE iff atEnd is now true.
|
||||
*/
|
||||
result = portal->atEnd;
|
||||
break;
|
||||
switch (portal->strategy)
|
||||
{
|
||||
case PORTAL_ONE_SELECT:
|
||||
(void) PortalRunSelect(portal, true, count, dest);
|
||||
/* we know the query is supposed to set the tag */
|
||||
if (completionTag && portal->commandTag)
|
||||
strcpy(completionTag, portal->commandTag);
|
||||
|
||||
case PORTAL_UTIL_SELECT:
|
||||
/* Mark portal not active */
|
||||
portal->status = PORTAL_READY;
|
||||
|
||||
/*
|
||||
* If we have not yet run the utility statement, do so,
|
||||
* storing its results in the portal's tuplestore.
|
||||
*/
|
||||
if (!portal->portalUtilReady)
|
||||
{
|
||||
DestReceiver *treceiver;
|
||||
/*
|
||||
* Since it's a forward fetch, say DONE iff atEnd is now true.
|
||||
*/
|
||||
result = portal->atEnd;
|
||||
break;
|
||||
|
||||
PortalCreateHoldStore(portal);
|
||||
treceiver = CreateDestReceiver(Tuplestore, portal);
|
||||
PortalRunUtility(portal, linitial(portal->parseTrees),
|
||||
treceiver, NULL);
|
||||
(*treceiver->rDestroy) (treceiver);
|
||||
portal->portalUtilReady = true;
|
||||
}
|
||||
case PORTAL_UTIL_SELECT:
|
||||
|
||||
/*
|
||||
* Now fetch desired portion of results.
|
||||
*/
|
||||
(void) PortalRunSelect(portal, true, count, dest);
|
||||
/*
|
||||
* If we have not yet run the utility statement, do so,
|
||||
* storing its results in the portal's tuplestore.
|
||||
*/
|
||||
if (!portal->portalUtilReady)
|
||||
{
|
||||
DestReceiver *treceiver;
|
||||
|
||||
/*
|
||||
* We know the query is supposed to set the tag; we assume
|
||||
* only the default tag is needed.
|
||||
*/
|
||||
if (completionTag && portal->commandTag)
|
||||
strcpy(completionTag, portal->commandTag);
|
||||
PortalCreateHoldStore(portal);
|
||||
treceiver = CreateDestReceiver(Tuplestore, portal);
|
||||
PortalRunUtility(portal, linitial(portal->parseTrees),
|
||||
treceiver, NULL);
|
||||
(*treceiver->rDestroy) (treceiver);
|
||||
portal->portalUtilReady = true;
|
||||
}
|
||||
|
||||
/* Mark portal not active */
|
||||
portal->status = PORTAL_READY;
|
||||
/*
|
||||
* Now fetch desired portion of results.
|
||||
*/
|
||||
(void) PortalRunSelect(portal, true, count, dest);
|
||||
|
||||
/*
|
||||
* Since it's a forward fetch, say DONE iff atEnd is now true.
|
||||
*/
|
||||
result = portal->atEnd;
|
||||
break;
|
||||
/*
|
||||
* We know the query is supposed to set the tag; we assume
|
||||
* only the default tag is needed.
|
||||
*/
|
||||
if (completionTag && portal->commandTag)
|
||||
strcpy(completionTag, portal->commandTag);
|
||||
|
||||
case PORTAL_MULTI_QUERY:
|
||||
PortalRunMulti(portal, dest, altdest, completionTag);
|
||||
/* Mark portal not active */
|
||||
portal->status = PORTAL_READY;
|
||||
|
||||
/* Prevent portal's commands from being re-executed */
|
||||
portal->status = PORTAL_DONE;
|
||||
/*
|
||||
* Since it's a forward fetch, say DONE iff atEnd is now true.
|
||||
*/
|
||||
result = portal->atEnd;
|
||||
break;
|
||||
|
||||
/* Always complete at end of RunMulti */
|
||||
result = true;
|
||||
break;
|
||||
case PORTAL_MULTI_QUERY:
|
||||
PortalRunMulti(portal, dest, altdest, completionTag);
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized portal strategy: %d",
|
||||
(int) portal->strategy);
|
||||
result = false; /* keep compiler quiet */
|
||||
break;
|
||||
/* Prevent portal's commands from being re-executed */
|
||||
portal->status = PORTAL_DONE;
|
||||
|
||||
/* Always complete at end of RunMulti */
|
||||
result = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized portal strategy: %d",
|
||||
(int) portal->strategy);
|
||||
result = false; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
/* Uncaught error while executing portal: mark it dead */
|
||||
portal->status = PORTAL_FAILED;
|
||||
|
||||
/* Restore global vars and propagate error */
|
||||
ActivePortal = saveActivePortal;
|
||||
CurrentResourceOwner = saveResourceOwner;
|
||||
PortalContext = savePortalContext;
|
||||
QueryContext = saveQueryContext;
|
||||
|
||||
PG_RE_THROW();
|
||||
}
|
||||
PG_END_TRY();
|
||||
|
||||
MemoryContextSwitchTo(oldContext);
|
||||
|
||||
@@ -970,30 +1003,47 @@ PortalRunFetch(Portal portal,
|
||||
portal->status = PORTAL_ACTIVE;
|
||||
|
||||
/*
|
||||
* Set global portal context pointers.
|
||||
* Set up global portal context pointers.
|
||||
*/
|
||||
saveActivePortal = ActivePortal;
|
||||
ActivePortal = portal;
|
||||
saveResourceOwner = CurrentResourceOwner;
|
||||
CurrentResourceOwner = portal->resowner;
|
||||
savePortalContext = PortalContext;
|
||||
PortalContext = PortalGetHeapMemory(portal);
|
||||
saveQueryContext = QueryContext;
|
||||
QueryContext = portal->queryContext;
|
||||
|
||||
oldContext = MemoryContextSwitchTo(PortalContext);
|
||||
|
||||
switch (portal->strategy)
|
||||
PG_TRY();
|
||||
{
|
||||
case PORTAL_ONE_SELECT:
|
||||
result = DoPortalRunFetch(portal, fdirection, count, dest);
|
||||
break;
|
||||
ActivePortal = portal;
|
||||
CurrentResourceOwner = portal->resowner;
|
||||
PortalContext = PortalGetHeapMemory(portal);
|
||||
QueryContext = portal->queryContext;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unsupported portal strategy");
|
||||
result = 0; /* keep compiler quiet */
|
||||
break;
|
||||
oldContext = MemoryContextSwitchTo(PortalContext);
|
||||
|
||||
switch (portal->strategy)
|
||||
{
|
||||
case PORTAL_ONE_SELECT:
|
||||
result = DoPortalRunFetch(portal, fdirection, count, dest);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unsupported portal strategy");
|
||||
result = 0; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
/* Uncaught error while executing portal: mark it dead */
|
||||
portal->status = PORTAL_FAILED;
|
||||
|
||||
/* Restore global vars and propagate error */
|
||||
ActivePortal = saveActivePortal;
|
||||
CurrentResourceOwner = saveResourceOwner;
|
||||
PortalContext = savePortalContext;
|
||||
QueryContext = saveQueryContext;
|
||||
|
||||
PG_RE_THROW();
|
||||
}
|
||||
PG_END_TRY();
|
||||
|
||||
MemoryContextSwitchTo(oldContext);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user