diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/copy.c | 49 | ||||
-rw-r--r-- | src/backend/commands/portalcmds.c | 157 | ||||
-rw-r--r-- | src/backend/commands/vacuum.c | 109 |
3 files changed, 194 insertions, 121 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 4a05b40eea8..8307e9b47d2 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -8,13 +8,12 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.227 2004/06/16 01:26:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.228 2004/07/31 00:45:31 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include <errno.h> #include <unistd.h> #include <sys/stat.h> #include <netinet/in.h> @@ -130,6 +129,9 @@ static StringInfoData line_buf; static bool line_buf_converted; /* non-export function prototypes */ +static void DoCopyTo(Relation rel, List *attnumlist, bool binary, bool oids, + char *delim, char *null_print, bool csv_mode, char *quote, + char *escape, List *force_quote_atts, bool fe_copy); static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, char *delim, char *null_print, bool csv_mode, char *quote, char *escape, List *force_quote_atts); @@ -688,6 +690,7 @@ DoCopy(const CopyStmt *stmt) ListCell *option; List *attnamelist = stmt->attlist; List *attnumlist; + bool fe_copy = false; bool binary = false; bool oids = false; bool csv_mode = false; @@ -1062,7 +1065,7 @@ DoCopy(const CopyStmt *stmt) if (pipe) { if (whereToSendOutput == Remote) - SendCopyBegin(binary, list_length(attnumlist)); + fe_copy = true; else copy_file = stdout; } @@ -1099,8 +1102,9 @@ DoCopy(const CopyStmt *stmt) errmsg("\"%s\" is a directory", filename))); } } - CopyTo(rel, attnumlist, binary, oids, delim, null_print, csv_mode, - quote, escape, force_quote_atts); + + DoCopyTo(rel, attnumlist, binary, oids, delim, null_print, csv_mode, + quote, escape, force_quote_atts, fe_copy); } if (!pipe) @@ -1112,8 +1116,6 @@ DoCopy(const CopyStmt *stmt) errmsg("could not write to file \"%s\": %m", filename))); } - else if (whereToSendOutput == Remote && !is_from) - SendCopyEnd(binary); pfree(attribute_buf.data); pfree(line_buf.data); @@ -1128,6 +1130,39 @@ DoCopy(const CopyStmt *stmt) /* + * This intermediate routine just exists to localize the effects of setjmp + * so we don't need to plaster a lot of variables with "volatile". + */ +static void +DoCopyTo(Relation rel, List *attnumlist, bool binary, bool oids, + char *delim, char *null_print, bool csv_mode, char *quote, + char *escape, List *force_quote_atts, bool fe_copy) +{ + PG_TRY(); + { + if (fe_copy) + SendCopyBegin(binary, list_length(attnumlist)); + + CopyTo(rel, attnumlist, binary, oids, delim, null_print, csv_mode, + quote, escape, force_quote_atts); + + if (fe_copy) + SendCopyEnd(binary); + } + PG_CATCH(); + { + /* + * Make sure we turn off old-style COPY OUT mode upon error. + * It is okay to do this in all cases, since it does nothing + * if the mode is not on. + */ + pq_endcopyout(true); + PG_RE_THROW(); + } + PG_END_TRY(); +} + +/* * Copy from relation TO file. */ static void diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c index b176a6c0c7b..509d9e0dfa1 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.29 2004/07/17 03:28:47 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.30 2004/07/31 00:45:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -259,8 +259,18 @@ PortalCleanup(Portal portal) /* We must make the portal's resource owner current */ saveResourceOwner = CurrentResourceOwner; - CurrentResourceOwner = portal->resowner; - ExecutorEnd(queryDesc); + PG_TRY(); + { + CurrentResourceOwner = portal->resowner; + ExecutorEnd(queryDesc); + } + PG_CATCH(); + { + /* Ensure CurrentResourceOwner is restored on error */ + CurrentResourceOwner = saveResourceOwner; + PG_RE_THROW(); + } + PG_END_TRY(); CurrentResourceOwner = saveResourceOwner; } } @@ -317,86 +327,95 @@ PersistHoldablePortal(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; + PG_TRY(); + { + ActivePortal = portal; + CurrentResourceOwner = portal->resowner; + PortalContext = PortalGetHeapMemory(portal); + QueryContext = portal->queryContext; + + MemoryContextSwitchTo(PortalContext); + + /* + * Rewind the executor: we need to store the entire result set in the + * tuplestore, so that subsequent backward FETCHs can be processed. + */ + ExecutorRewind(queryDesc); + + /* Change the destination to output to the tuplestore */ + queryDesc->dest = CreateDestReceiver(Tuplestore, portal); + + /* Fetch the result set into the tuplestore */ + ExecutorRun(queryDesc, ForwardScanDirection, 0L); + + (*queryDesc->dest->rDestroy) (queryDesc->dest); + queryDesc->dest = NULL; + + /* + * Now shut down the inner executor. + */ + portal->queryDesc = NULL; /* prevent double shutdown */ + ExecutorEnd(queryDesc); + + /* + * Reset the position in the result set: ideally, this could be + * implemented by just skipping straight to the tuple # that we need + * to be at, but the tuplestore API doesn't support that. So we start + * at the beginning of the tuplestore and iterate through it until we + * reach where we need to be. FIXME someday? + */ + MemoryContextSwitchTo(portal->holdContext); + + if (!portal->atEnd) + { + long store_pos; - MemoryContextSwitchTo(PortalContext); + if (portal->posOverflow) /* oops, cannot trust portalPos */ + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("could not reposition held cursor"))); - /* - * Rewind the executor: we need to store the entire result set in the - * tuplestore, so that subsequent backward FETCHs can be processed. - */ - ExecutorRewind(queryDesc); + tuplestore_rescan(portal->holdStore); - /* Change the destination to output to the tuplestore */ - queryDesc->dest = CreateDestReceiver(Tuplestore, portal); + for (store_pos = 0; store_pos < portal->portalPos; store_pos++) + { + HeapTuple tup; + bool should_free; - /* Fetch the result set into the tuplestore */ - ExecutorRun(queryDesc, ForwardScanDirection, 0L); + tup = tuplestore_gettuple(portal->holdStore, true, + &should_free); - (*queryDesc->dest->rDestroy) (queryDesc->dest); - queryDesc->dest = NULL; + if (tup == NULL) + elog(ERROR, "unexpected end of tuple stream"); - /* - * Now shut down the inner executor. - */ - portal->queryDesc = NULL; /* prevent double shutdown */ - ExecutorEnd(queryDesc); - - /* - * Reset the position in the result set: ideally, this could be - * implemented by just skipping straight to the tuple # that we need - * to be at, but the tuplestore API doesn't support that. So we start - * at the beginning of the tuplestore and iterate through it until we - * reach where we need to be. FIXME someday? - */ - MemoryContextSwitchTo(portal->holdContext); - - if (!portal->atEnd) + if (should_free) + pfree(tup); + } + } + } + PG_CATCH(); { - long store_pos; - - if (portal->posOverflow) /* oops, cannot trust portalPos */ - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("could not reposition held cursor"))); - - tuplestore_rescan(portal->holdStore); - - for (store_pos = 0; store_pos < portal->portalPos; store_pos++) - { - HeapTuple tup; - bool should_free; - - tup = tuplestore_gettuple(portal->holdStore, true, - &should_free); + /* Uncaught error while executing portal: mark it dead */ + portal->status = PORTAL_FAILED; - if (tup == NULL) - elog(ERROR, "unexpected end of tuple stream"); + /* Restore global vars and propagate error */ + ActivePortal = saveActivePortal; + CurrentResourceOwner = saveResourceOwner; + PortalContext = savePortalContext; + QueryContext = saveQueryContext; - if (should_free) - pfree(tup); - } + PG_RE_THROW(); } + PG_END_TRY(); MemoryContextSwitchTo(oldcxt); - /* - * We can now release any subsidiary memory of the portal's heap - * context; we'll never use it again. The executor already dropped - * its context, but this will clean up anything that glommed onto the - * portal's heap via PortalContext. - */ - MemoryContextDeleteChildren(PortalGetHeapMemory(portal)); - /* Mark portal not active */ portal->status = PORTAL_READY; @@ -404,4 +423,12 @@ PersistHoldablePortal(Portal portal) CurrentResourceOwner = saveResourceOwner; PortalContext = savePortalContext; QueryContext = saveQueryContext; + + /* + * We can now release any subsidiary memory of the portal's heap + * context; we'll never use it again. The executor already dropped + * its context, but this will clean up anything that glommed onto the + * portal's heap via PortalContext. + */ + MemoryContextDeleteChildren(PortalGetHeapMemory(portal)); } diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index dfc03ea461a..23d7996cf53 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.284 2004/07/21 22:31:21 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.285 2004/07/31 00:45:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -228,14 +228,13 @@ void vacuum(VacuumStmt *vacstmt) { const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE"; - MemoryContext anl_context = NULL; TransactionId initialOldestXmin = InvalidTransactionId; TransactionId initialFreezeLimit = InvalidTransactionId; - bool all_rels, + volatile MemoryContext anl_context = NULL; + volatile bool all_rels, in_outer_xact, use_own_xacts; List *relations; - ListCell *cur; if (vacstmt->verbose) elevel = INFO; @@ -267,10 +266,6 @@ vacuum(VacuumStmt *vacstmt) in_outer_xact = IsInTransactionChain((void *) vacstmt); } - /* Turn vacuum cost accounting on or off */ - VacuumCostActive = (VacuumCostNaptime > 0); - VacuumCostBalance = 0; - /* * Send info about dead objects to the statistics collector */ @@ -377,57 +372,76 @@ vacuum(VacuumStmt *vacstmt) CommitTransactionCommand(); } - /* - * Loop to process each selected relation. - */ - foreach(cur, relations) + /* Turn vacuum cost accounting on or off */ + PG_TRY(); { - Oid relid = lfirst_oid(cur); + ListCell *cur; - if (vacstmt->vacuum) - { - if (!vacuum_rel(relid, vacstmt, RELKIND_RELATION)) - all_rels = false; /* forget about updating dbstats */ - } - if (vacstmt->analyze) + VacuumCostActive = (VacuumCostNaptime > 0); + VacuumCostBalance = 0; + + /* + * Loop to process each selected relation. + */ + foreach(cur, relations) { - MemoryContext old_context = NULL; + Oid relid = lfirst_oid(cur); - /* - * If using separate xacts, start one for analyze. Otherwise, - * we can use the outer transaction, but we still need to call - * analyze_rel in a memory context that will be cleaned up on - * return (else we leak memory while processing multiple - * tables). - */ - if (use_own_xacts) + if (vacstmt->vacuum) { - StartTransactionCommand(); - SetQuerySnapshot(); /* might be needed for functions - * in indexes */ + if (!vacuum_rel(relid, vacstmt, RELKIND_RELATION)) + all_rels = false; /* forget about updating dbstats */ } - else - old_context = MemoryContextSwitchTo(anl_context); + if (vacstmt->analyze) + { + MemoryContext old_context = NULL; - /* - * Tell the buffer replacement strategy that vacuum is - * causing the IO - */ - StrategyHintVacuum(true); + /* + * If using separate xacts, start one for analyze. Otherwise, + * we can use the outer transaction, but we still need to call + * analyze_rel in a memory context that will be cleaned up on + * return (else we leak memory while processing multiple + * tables). + */ + if (use_own_xacts) + { + StartTransactionCommand(); + SetQuerySnapshot(); /* might be needed for functions + * in indexes */ + } + else + old_context = MemoryContextSwitchTo(anl_context); + + /* + * Tell the buffer replacement strategy that vacuum is + * causing the IO + */ + StrategyHintVacuum(true); - analyze_rel(relid, vacstmt); + analyze_rel(relid, vacstmt); - StrategyHintVacuum(false); + StrategyHintVacuum(false); - if (use_own_xacts) - CommitTransactionCommand(); - else - { - MemoryContextSwitchTo(old_context); - MemoryContextResetAndDeleteChildren(anl_context); + if (use_own_xacts) + CommitTransactionCommand(); + else + { + MemoryContextSwitchTo(old_context); + MemoryContextResetAndDeleteChildren(anl_context); + } } } } + PG_CATCH(); + { + /* Make sure cost accounting is turned off after error */ + VacuumCostActive = false; + PG_RE_THROW(); + } + PG_END_TRY(); + + /* Turn off vacuum cost accounting */ + VacuumCostActive = false; /* * Finish up processing. @@ -475,9 +489,6 @@ vacuum(VacuumStmt *vacstmt) if (anl_context) MemoryContextDelete(anl_context); - - /* Turn off vacuum cost accounting */ - VacuumCostActive = false; } /* |