Commit 9d23a70d authored by Alvaro Herrera's avatar Alvaro Herrera

pg_dump: get rid of die_horribly

The old code was using exit_horribly or die_horribly other depending on
whether it had an ArchiveHandle on which to close the connection or not;
but there were places that were passing a NULL ArchiveHandle to
die_horribly, and other places that used exit_horribly while having an
AH available.  So there wasn't all that much consistency.

Improve the situation by keeping only one of the routines, and instead
of having to pass the AH down from the caller, arrange for it to be
present for an on_exit_nicely callback to operate on.

Author: Joachim Wieland
Some tweaks by me

Per a suggestion from Robert Haas, in the ongoing "parallel pg_dump"
saga.
parent b251cf31
......@@ -256,8 +256,8 @@ EndCompressorZlib(ArchiveHandle *AH, CompressorState *cs)
DeflateCompressorZlib(AH, cs, true);
if (deflateEnd(zp) != Z_OK)
die_horribly(AH, modulename,
"could not close compression stream: %s\n", zp->msg);
exit_horribly(modulename,
"could not close compression stream: %s\n", zp->msg);
free(cs->zlibOut);
free(cs->zp);
......@@ -274,8 +274,8 @@ DeflateCompressorZlib(ArchiveHandle *AH, CompressorState *cs, bool flush)
{
res = deflate(zp, flush ? Z_FINISH : Z_NO_FLUSH);
if (res == Z_STREAM_ERROR)
die_horribly(AH, modulename,
"could not compress data: %s\n", zp->msg);
exit_horribly(modulename,
"could not compress data: %s\n", zp->msg);
if ((flush && (zp->avail_out < cs->zlibOutSize))
|| (zp->avail_out == 0)
|| (zp->avail_in != 0)
......@@ -295,9 +295,9 @@ DeflateCompressorZlib(ArchiveHandle *AH, CompressorState *cs, bool flush)
size_t len = cs->zlibOutSize - zp->avail_out;
if (cs->writeF(AH, out, len) != len)
die_horribly(AH, modulename,
"could not write to output file: %s\n",
strerror(errno));
exit_horribly(modulename,
"could not write to output file: %s\n",
strerror(errno));
}
zp->next_out = (void *) out;
zp->avail_out = cs->zlibOutSize;
......@@ -318,7 +318,7 @@ WriteDataToArchiveZlib(ArchiveHandle *AH, CompressorState *cs,
/*
* we have either succeeded in writing dLen bytes or we have called
* die_horribly()
* exit_horribly()
*/
return dLen;
}
......@@ -361,8 +361,8 @@ ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF)
res = inflate(zp, 0);
if (res != Z_OK && res != Z_STREAM_END)
die_horribly(AH, modulename,
"could not uncompress data: %s\n", zp->msg);
exit_horribly(modulename,
"could not uncompress data: %s\n", zp->msg);
out[ZLIB_OUT_SIZE - zp->avail_out] = '\0';
ahwrite(out, 1, ZLIB_OUT_SIZE - zp->avail_out, AH);
......@@ -377,16 +377,16 @@ ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF)
zp->avail_out = ZLIB_OUT_SIZE;
res = inflate(zp, 0);
if (res != Z_OK && res != Z_STREAM_END)
die_horribly(AH, modulename,
"could not uncompress data: %s\n", zp->msg);
exit_horribly(modulename,
"could not uncompress data: %s\n", zp->msg);
out[ZLIB_OUT_SIZE - zp->avail_out] = '\0';
ahwrite(out, 1, ZLIB_OUT_SIZE - zp->avail_out, AH);
}
if (inflateEnd(zp) != Z_OK)
die_horribly(AH, modulename,
"could not close compression library: %s\n", zp->msg);
exit_horribly(modulename,
"could not close compression library: %s\n", zp->msg);
free(buf);
free(out);
......@@ -426,9 +426,9 @@ WriteDataToArchiveNone(ArchiveHandle *AH, CompressorState *cs,
* do a check here as well...
*/
if (cs->writeF(AH, data, dLen) != dLen)
die_horribly(AH, modulename,
"could not write to output file: %s\n",
strerror(errno));
exit_horribly(modulename,
"could not write to output file: %s\n",
strerror(errno));
return dLen;
}
......
......@@ -49,6 +49,7 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
#ifdef WIN32
static bool parallel_init_done = false;
static DWORD tls_index;
static DWORD mainThreadId;
#endif
void
......@@ -59,6 +60,7 @@ init_parallel_dump_utils(void)
{
tls_index = TlsAlloc();
parallel_init_done = true;
mainThreadId = GetCurrentThreadId();
}
#endif
}
......@@ -1320,5 +1322,9 @@ exit_nicely(int code)
while (--on_exit_nicely_index >= 0)
(*on_exit_nicely_list[on_exit_nicely_index].function)(code,
on_exit_nicely_list[on_exit_nicely_index].arg);
#ifdef WIN32
if (parallel_init_done && GetCurrentThreadId() != mainThreadId)
ExitThread(code);
#endif
exit(code);
}
......@@ -2,13 +2,13 @@
CATALOG_NAME = pg_dump
AVAIL_LANGUAGES = de es fr it ja ko pt_BR sv tr zh_CN zh_TW
GETTEXT_FILES = pg_dump.c common.c pg_backup_archiver.c pg_backup_custom.c \
pg_backup_db.c pg_backup_files.c pg_backup_null.c \
pg_backup_db.c pg_backup_null.c \
pg_backup_tar.c pg_restore.c pg_dumpall.c \
../../port/exec.c
GETTEXT_TRIGGERS = write_msg:2 die_horribly:3 exit_horribly:2 simple_prompt \
ExecuteSqlCommand:3 ahlog:3
GETTEXT_TRIGGERS = write_msg:2 exit_horribly:2 simple_prompt \
ExecuteSqlCommand:3 ahlog:3 warn_or_exit_horribly:3
GETTEXT_FLAGS = \
write_msg:2:c-format \
die_horribly:3:c-format \
exit_horribly:2:c-format \
ahlog:3:c-format
ahlog:3:c-format \
warn_or_exit_horribly:3:c-format
......@@ -61,11 +61,28 @@
#define thandle HANDLE
#endif
typedef struct ParallelStateEntry
{
#ifdef WIN32
unsigned int threadId;
#else
pid_t pid;
#endif
ArchiveHandle *AH;
} ParallelStateEntry;
typedef struct ParallelState
{
int numWorkers;
ParallelStateEntry *pse;
} ParallelState;
/* Arguments needed for a worker child */
typedef struct _restore_args
{
ArchiveHandle *AH;
TocEntry *te;
ParallelStateEntry *pse;
} RestoreArgs;
/* State for each parallel activity slot */
......@@ -75,6 +92,14 @@ typedef struct _parallel_slot
RestoreArgs *args;
} ParallelSlot;
typedef struct ShutdownInformation
{
ParallelState *pstate;
Archive *AHX;
} ShutdownInformation;
static ShutdownInformation shutdown_info;
#define NO_SLOT (-1)
#define TEXT_DUMP_HEADER "--\n-- PostgreSQL database dump\n--\n\n"
......@@ -122,10 +147,6 @@ static int _discoverArchiveFormat(ArchiveHandle *AH);
static int RestoringToDB(ArchiveHandle *AH);
static void dump_lo_buf(ArchiveHandle *AH);
static void vdie_horribly(ArchiveHandle *AH, const char *modulename,
const char *fmt, va_list ap)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0), noreturn));
static void dumpTimestamp(ArchiveHandle *AH, const char *msg, time_t tim);
static void SetOutput(ArchiveHandle *AH, const char *filename, int compression);
static OutputContext SaveOutput(ArchiveHandle *AH);
......@@ -160,6 +181,11 @@ static void inhibit_data_for_failed_table(ArchiveHandle *AH, TocEntry *te);
static ArchiveHandle *CloneArchive(ArchiveHandle *AH);
static void DeCloneArchive(ArchiveHandle *AH);
static void setProcessIdentifier(ParallelStateEntry *pse, ArchiveHandle *AH);
static void unsetProcessIdentifier(ParallelStateEntry *pse);
static ParallelStateEntry *GetMyPSEntry(ParallelState *pstate);
static void archive_close_connection(int code, void *arg);
/*
* Wrapper functions.
......@@ -208,8 +234,8 @@ CloseArchive(Archive *AHX)
res = fclose(AH->OF);
if (res != 0)
die_horribly(AH, modulename, "could not close output file: %s\n",
strerror(errno));
exit_horribly(modulename, "could not close output file: %s\n",
strerror(errno));
}
/* Public */
......@@ -234,14 +260,14 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
* connected to, not the one we will create, which is very bad...
*/
if (ropt->createDB && ropt->dropSchema)
die_horribly(AH, modulename, "-C and -c are incompatible options\n");
exit_horribly(modulename, "-C and -c are incompatible options\n");
/*
* -C is not compatible with -1, because we can't create a database inside
* a transaction block.
*/
if (ropt->createDB && ropt->single_txn)
die_horribly(AH, modulename, "-C and -1 are incompatible options\n");
exit_horribly(modulename, "-C and -1 are incompatible options\n");
/*
* If we're going to do parallel restore, there are some restrictions.
......@@ -251,11 +277,11 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
{
/* We haven't got round to making this work for all archive formats */
if (AH->ClonePtr == NULL || AH->ReopenPtr == NULL)
die_horribly(AH, modulename, "parallel restore is not supported with this archive file format\n");
exit_horribly(modulename, "parallel restore is not supported with this archive file format\n");
/* Doesn't work if the archive represents dependencies as OIDs */
if (AH->version < K_VERS_1_8)
die_horribly(AH, modulename, "parallel restore is not supported with archives made by pre-8.0 pg_dump\n");
exit_horribly(modulename, "parallel restore is not supported with archives made by pre-8.0 pg_dump\n");
/*
* It's also not gonna work if we can't reopen the input file, so
......@@ -274,7 +300,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
{
reqs = _tocEntryRequired(te, ropt, false);
if (te->hadDumper && (reqs & REQ_DATA) != 0)
die_horribly(AH, modulename, "cannot restore from compressed archive (compression not supported in this installation)\n");
exit_horribly(modulename, "cannot restore from compressed archive (compression not supported in this installation)\n");
}
}
#endif
......@@ -286,7 +312,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
{
ahlog(AH, 1, "connecting to database for restore\n");
if (AH->version < K_VERS_1_3)
die_horribly(AH, modulename, "direct database connections are not supported in pre-1.3 archives\n");
exit_horribly(modulename, "direct database connections are not supported in pre-1.3 archives\n");
/* XXX Should get this from the archive */
AHX->minRemoteVersion = 070100;
......@@ -734,7 +760,7 @@ WriteData(Archive *AHX, const void *data, size_t dLen)
ArchiveHandle *AH = (ArchiveHandle *) AHX;
if (!AH->currToc)
die_horribly(AH, modulename, "internal error -- WriteData cannot be called outside the context of a DataDumper routine\n");
exit_horribly(modulename, "internal error -- WriteData cannot be called outside the context of a DataDumper routine\n");
return (*AH->WriteDataPtr) (AH, data, dLen);
}
......@@ -886,7 +912,7 @@ StartBlob(Archive *AHX, Oid oid)
ArchiveHandle *AH = (ArchiveHandle *) AHX;
if (!AH->StartBlobPtr)
die_horribly(AH, modulename, "large-object output not supported in chosen format\n");
exit_horribly(modulename, "large-object output not supported in chosen format\n");
(*AH->StartBlobPtr) (AH, AH->currToc, oid);
......@@ -973,13 +999,13 @@ StartRestoreBlob(ArchiveHandle *AH, Oid oid, bool drop)
{
loOid = lo_create(AH->connection, oid);
if (loOid == 0 || loOid != oid)
die_horribly(AH, modulename, "could not create large object %u: %s",
oid, PQerrorMessage(AH->connection));
exit_horribly(modulename, "could not create large object %u: %s",
oid, PQerrorMessage(AH->connection));
}
AH->loFd = lo_open(AH->connection, oid, INV_WRITE);
if (AH->loFd == -1)
die_horribly(AH, modulename, "could not open large object %u: %s",
oid, PQerrorMessage(AH->connection));
exit_horribly(modulename, "could not open large object %u: %s",
oid, PQerrorMessage(AH->connection));
}
else
{
......@@ -1035,8 +1061,8 @@ SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
/* Setup the file */
fh = fopen(ropt->tocFile, PG_BINARY_R);
if (!fh)
die_horribly(AH, modulename, "could not open TOC file \"%s\": %s\n",
ropt->tocFile, strerror(errno));
exit_horribly(modulename, "could not open TOC file \"%s\": %s\n",
ropt->tocFile, strerror(errno));
incomplete_line = false;
while (fgets(buf, sizeof(buf), fh) != NULL)
......@@ -1083,8 +1109,8 @@ SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
/* Find TOC entry */
te = getTocEntryByDumpId(AH, id);
if (!te)
die_horribly(AH, modulename, "could not find entry for ID %d\n",
id);
exit_horribly(modulename, "could not find entry for ID %d\n",
id);
/* Mark it wanted */
ropt->idWanted[id - 1] = true;
......@@ -1104,8 +1130,8 @@ SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
}
if (fclose(fh) != 0)
die_horribly(AH, modulename, "could not close TOC file: %s\n",
strerror(errno));
exit_horribly(modulename, "could not close TOC file: %s\n",
strerror(errno));
}
/*
......@@ -1221,11 +1247,11 @@ SetOutput(ArchiveHandle *AH, const char *filename, int compression)
if (!AH->OF)
{
if (filename)
die_horribly(AH, modulename, "could not open output file \"%s\": %s\n",
filename, strerror(errno));
exit_horribly(modulename, "could not open output file \"%s\": %s\n",
filename, strerror(errno));
else
die_horribly(AH, modulename, "could not open output file: %s\n",
strerror(errno));
exit_horribly(modulename, "could not open output file: %s\n",
strerror(errno));
}
}
......@@ -1251,7 +1277,7 @@ RestoreOutput(ArchiveHandle *AH, OutputContext savedContext)
res = fclose(AH->OF);
if (res != 0)
die_horribly(AH, modulename, "could not close output file: %s\n",
exit_horribly(modulename, "could not close output file: %s\n",
strerror(errno));
AH->gzOut = savedContext.gzOut;
......@@ -1329,7 +1355,7 @@ dump_lo_buf(ArchiveHandle *AH)
AH->lo_buf_used),
(unsigned long) AH->lo_buf_used, (unsigned long) res);
if (res != AH->lo_buf_used)
die_horribly(AH, modulename,
exit_horribly(modulename,
"could not write to large object (result: %lu, expected: %lu)\n",
(unsigned long) res, (unsigned long) AH->lo_buf_used);
}
......@@ -1388,7 +1414,7 @@ ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
{
res = GZWRITE(ptr, size, nmemb, AH->OF);
if (res != (nmemb * size))
die_horribly(AH, modulename, "could not write to output file: %s\n", strerror(errno));
exit_horribly(modulename, "could not write to output file: %s\n", strerror(errno));
return res;
}
else if (AH->CustomOutPtr)
......@@ -1396,7 +1422,7 @@ ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
res = AH->CustomOutPtr (AH, ptr, size * nmemb);
if (res != (nmemb * size))
die_horribly(AH, modulename, "could not write to custom output routine\n");
exit_horribly(modulename, "could not write to custom output routine\n");
return res;
}
else
......@@ -1411,56 +1437,17 @@ ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
{
res = fwrite(ptr, size, nmemb, AH->OF);
if (res != nmemb)
die_horribly(AH, modulename, "could not write to output file: %s\n",
exit_horribly(modulename, "could not write to output file: %s\n",
strerror(errno));
return res;
}
}
}
/* Report a fatal error and exit(1) */
static void
vdie_horribly(ArchiveHandle *AH, const char *modulename,
const char *fmt, va_list ap)
{
vwrite_msg(modulename, fmt, ap);
if (AH)
{
if (AH->public.verbose)
write_msg(NULL, "*** aborted because of error\n");
DisconnectDatabase(&AH->public);
}
exit_nicely(1);
}
/* As above, but with variable arg list */
void
die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...)
{
va_list ap;
va_start(ap, fmt);
vdie_horribly(AH, modulename, fmt, ap);
va_end(ap);
}
/* As above, but with a complaint about a particular query. */
void
die_on_query_failure(ArchiveHandle *AH, const char *modulename,
const char *query)
{
write_msg(modulename, "query failed: %s",
PQerrorMessage(AH->connection));
die_horribly(AH, modulename, "query was: %s\n", query);
}
/* on some error, we may decide to go on... */
void
warn_or_die_horribly(ArchiveHandle *AH,
const char *modulename, const char *fmt,...)
warn_or_exit_horribly(ArchiveHandle *AH,
const char *modulename, const char *fmt,...)
{
va_list ap;
......@@ -1497,14 +1484,13 @@ warn_or_die_horribly(ArchiveHandle *AH,
AH->lastErrorTE = AH->currentTE;
va_start(ap, fmt);
vwrite_msg(modulename, fmt, ap);
va_end(ap);
if (AH->public.exit_on_error)
vdie_horribly(AH, modulename, fmt, ap);
exit_nicely(1);
else
{
vwrite_msg(modulename, fmt, ap);
AH->public.n_errors++;
}
va_end(ap);
}
#ifdef NOT_USED
......@@ -1623,7 +1609,7 @@ ReadOffset(ArchiveHandle *AH, pgoff_t * o)
break;
default:
die_horribly(AH, modulename, "unexpected data offset flag %d\n", offsetFlg);
exit_horribly(modulename, "unexpected data offset flag %d\n", offsetFlg);
}
/*
......@@ -1636,7 +1622,7 @@ ReadOffset(ArchiveHandle *AH, pgoff_t * o)
else
{
if ((*AH->ReadBytePtr) (AH) != 0)
die_horribly(AH, modulename, "file offset in dump file is too large\n");
exit_horribly(modulename, "file offset in dump file is too large\n");
}
}
......@@ -1730,7 +1716,7 @@ ReadStr(ArchiveHandle *AH)
{
buf = (char *) pg_malloc(l + 1);
if ((*AH->ReadBufPtr) (AH, (void *) buf, l) != l)
die_horribly(AH, modulename, "unexpected end of file\n");
exit_horribly(modulename, "unexpected end of file\n");
buf[l] = '\0';
}
......@@ -1773,8 +1759,8 @@ _discoverArchiveFormat(ArchiveHandle *AH)
char buf[MAXPGPATH];
if (snprintf(buf, MAXPGPATH, "%s/toc.dat", AH->fSpec) >= MAXPGPATH)
die_horribly(AH, modulename, "directory name too long: \"%s\"\n",
AH->fSpec);
exit_horribly(modulename, "directory name too long: \"%s\"\n",
AH->fSpec);
if (stat(buf, &st) == 0 && S_ISREG(st.st_mode))
{
AH->format = archDirectory;
......@@ -1783,32 +1769,32 @@ _discoverArchiveFormat(ArchiveHandle *AH)
#ifdef HAVE_LIBZ
if (snprintf(buf, MAXPGPATH, "%s/toc.dat.gz", AH->fSpec) >= MAXPGPATH)
die_horribly(AH, modulename, "directory name too long: \"%s\"\n",
AH->fSpec);
exit_horribly(modulename, "directory name too long: \"%s\"\n",
AH->fSpec);
if (stat(buf, &st) == 0 && S_ISREG(st.st_mode))
{
AH->format = archDirectory;
return AH->format;
}
#endif
die_horribly(AH, modulename, "directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)\n",
AH->fSpec);
exit_horribly(modulename, "directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)\n",
AH->fSpec);
fh = NULL; /* keep compiler quiet */
}
else
{
fh = fopen(AH->fSpec, PG_BINARY_R);
if (!fh)
die_horribly(AH, modulename, "could not open input file \"%s\": %s\n",
AH->fSpec, strerror(errno));
exit_horribly(modulename, "could not open input file \"%s\": %s\n",
AH->fSpec, strerror(errno));
}
}
else
{
fh = stdin;
if (!fh)
die_horribly(AH, modulename, "could not open input file: %s\n",
strerror(errno));
exit_horribly(modulename, "could not open input file: %s\n",
strerror(errno));
}
cnt = fread(sig, 1, 5, fh);
......@@ -1816,10 +1802,10 @@ _discoverArchiveFormat(ArchiveHandle *AH)
if (cnt != 5)
{
if (ferror(fh))
die_horribly(AH, modulename, "could not read input file: %s\n", strerror(errno));
exit_horribly(modulename, "could not read input file: %s\n", strerror(errno));
else
die_horribly(AH, modulename, "input file is too short (read %lu, expected 5)\n",
(unsigned long) cnt);
exit_horribly(modulename, "input file is too short (read %lu, expected 5)\n",
(unsigned long) cnt);
}
/* Save it, just in case we need it later */
......@@ -1880,14 +1866,14 @@ _discoverArchiveFormat(ArchiveHandle *AH)
strncmp(AH->lookahead, TEXT_DUMPALL_HEADER, strlen(TEXT_DUMPALL_HEADER)) == 0))
{
/* looks like it's probably a text format dump. so suggest they try psql */
die_horribly(AH, modulename, "input file appears to be a text format dump. Please use psql.\n");
exit_horribly(modulename, "input file appears to be a text format dump. Please use psql.\n");
}
if (AH->lookaheadLen != 512)
die_horribly(AH, modulename, "input file does not appear to be a valid archive (too short?)\n");
exit_horribly(modulename, "input file does not appear to be a valid archive (too short?)\n");
if (!isValidTarHeader(AH->lookahead))
die_horribly(AH, modulename, "input file does not appear to be a valid archive\n");
exit_horribly(modulename, "input file does not appear to be a valid archive\n");
AH->format = archTar;
}
......@@ -1907,8 +1893,8 @@ _discoverArchiveFormat(ArchiveHandle *AH)
/* Close the file */
if (wantClose)
if (fclose(fh) != 0)
die_horribly(AH, modulename, "could not close input file: %s\n",
strerror(errno));
exit_horribly(modulename, "could not close input file: %s\n",
strerror(errno));
return AH->format;
}
......@@ -2027,7 +2013,7 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
break;
default:
die_horribly(AH, modulename, "unrecognized file format \"%d\"\n", fmt);
exit_horribly(modulename, "unrecognized file format \"%d\"\n", fmt);
}
return AH;
......@@ -2149,9 +2135,9 @@ ReadToc(ArchiveHandle *AH)
/* Sanity check */
if (te->dumpId <= 0)
die_horribly(AH, modulename,
"entry ID %d out of range -- perhaps a corrupt TOC\n",
te->dumpId);
exit_horribly(modulename,
"entry ID %d out of range -- perhaps a corrupt TOC\n",
te->dumpId);
te->hadDumper = ReadInt(AH);
......@@ -2306,13 +2292,13 @@ processEncodingEntry(ArchiveHandle *AH, TocEntry *te)
*ptr2 = '\0';
encoding = pg_char_to_encoding(ptr1);
if (encoding < 0)
die_horribly(AH, modulename, "unrecognized encoding \"%s\"\n",
ptr1);
exit_horribly(modulename, "unrecognized encoding \"%s\"\n",
ptr1);
AH->public.encoding = encoding;
}
else
die_horribly(AH, modulename, "invalid ENCODING item: %s\n",
te->defn);
exit_horribly(modulename, "invalid ENCODING item: %s\n",
te->defn);
free(defn);
}
......@@ -2329,8 +2315,8 @@ processStdStringsEntry(ArchiveHandle *AH, TocEntry *te)
else if (ptr1 && strncmp(ptr1, "'off'", 5) == 0)
AH->public.std_strings = false;
else
die_horribly(AH, modulename, "invalid STDSTRINGS item: %s\n",
te->defn);
exit_horribly(modulename, "invalid STDSTRINGS item: %s\n",
te->defn);
}
static teReqs
......@@ -2537,9 +2523,9 @@ _doSetSessionAuth(ArchiveHandle *AH, const char *user)
res = PQexec(AH->connection, cmd->data);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
/* NOT warn_or_die_horribly... use -O instead to skip this. */
die_horribly(AH, modulename, "could not set session user to \"%s\": %s",
user, PQerrorMessage(AH->connection));
/* NOT warn_or_exit_horribly... use -O instead to skip this. */
exit_horribly(modulename, "could not set session user to \"%s\": %s",
user, PQerrorMessage(AH->connection));
PQclear(res);
}
......@@ -2569,9 +2555,9 @@ _doSetWithOids(ArchiveHandle *AH, const bool withOids)
res = PQexec(AH->connection, cmd->data);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
warn_or_die_horribly(AH, modulename,
"could not set default_with_oids: %s",
PQerrorMessage(AH->connection));
warn_or_exit_horribly(AH, modulename,
"could not set default_with_oids: %s",
PQerrorMessage(AH->connection));
PQclear(res);
}
......@@ -2707,9 +2693,9 @@ _selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
res = PQexec(AH->connection, qry->data);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
warn_or_die_horribly(AH, modulename,
"could not set search_path to \"%s\": %s",
schemaName, PQerrorMessage(AH->connection));
warn_or_exit_horribly(AH, modulename,
"could not set search_path to \"%s\": %s",
schemaName, PQerrorMessage(AH->connection));
PQclear(res);
}
......@@ -2768,9 +2754,9 @@ _selectTablespace(ArchiveHandle *AH, const char *tablespace)
res = PQexec(AH->connection, qry->data);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
warn_or_die_horribly(AH, modulename,
"could not set default_tablespace to %s: %s",
fmtId(want), PQerrorMessage(AH->connection));
warn_or_exit_horribly(AH, modulename,
"could not set default_tablespace to %s: %s",
fmtId(want), PQerrorMessage(AH->connection));
PQclear(res);
}
......@@ -3150,10 +3136,10 @@ ReadHead(ArchiveHandle *AH)
if (!AH->readHeader)
{
if ((*AH->ReadBufPtr) (AH, tmpMag, 5) != 5)
die_horribly(AH, modulename, "unexpected end of file\n");
exit_horribly(modulename, "unexpected end of file\n");
if (strncmp(tmpMag, "PGDMP", 5) != 0)
die_horribly(AH, modulename, "did not find magic string in file header\n");
exit_horribly(modulename, "did not find magic string in file header\n");
AH->vmaj = (*AH->ReadBytePtr) (AH);
AH->vmin = (*AH->ReadBytePtr) (AH);
......@@ -3166,13 +3152,13 @@ ReadHead(ArchiveHandle *AH)
AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0;
if (AH->version < K_VERS_1_0 || AH->version > K_VERS_MAX)
die_horribly(AH, modulename, "unsupported version (%d.%d) in file header\n",
AH->vmaj, AH->vmin);
exit_horribly(modulename, "unsupported version (%d.%d) in file header\n",
AH->vmaj, AH->vmin);
AH->intSize = (*AH->ReadBytePtr) (AH);
if (AH->intSize > 32)
die_horribly(AH, modulename, "sanity check on integer size (%lu) failed\n",
(unsigned long) AH->intSize);
exit_horribly(modulename, "sanity check on integer size (%lu) failed\n",
(unsigned long) AH->intSize);
if (AH->intSize > sizeof(int))
write_msg(modulename, "WARNING: archive was made on a machine with larger integers, some operations might fail\n");
......@@ -3185,8 +3171,8 @@ ReadHead(ArchiveHandle *AH)
fmt = (*AH->ReadBytePtr) (AH);
if (AH->format != fmt)
die_horribly(AH, modulename, "expected format (%d) differs from format found in file (%d)\n",
AH->format, fmt);
exit_horribly(modulename, "expected format (%d) differs from format found in file (%d)\n",
AH->format, fmt);
}
if (AH->version >= K_VERS_1_2)
......@@ -3290,6 +3276,66 @@ dumpTimestamp(ArchiveHandle *AH, const char *msg, time_t tim)
ahprintf(AH, "-- %s %s\n\n", msg, buf);
}
static void
setProcessIdentifier(ParallelStateEntry *pse, ArchiveHandle *AH)
{
#ifdef WIN32
pse->threadId = GetCurrentThreadId();
#else
pse->pid = getpid();
#endif
pse->AH = AH;
}
static void
unsetProcessIdentifier(ParallelStateEntry *pse)
{
#ifdef WIN32
pse->threadId = 0;
#else
pse->pid = 0;
#endif
pse->AH = NULL;
}
static ParallelStateEntry *
GetMyPSEntry(ParallelState *pstate)
{
int i;
for (i = 0; i < pstate->numWorkers; i++)
#ifdef WIN32
if (pstate->pse[i].threadId == GetCurrentThreadId())
#else
if (pstate->pse[i].pid == getpid())
#endif
return &(pstate->pse[i]);
return NULL;
}
static void
archive_close_connection(int code, void *arg)
{
ShutdownInformation *si = (ShutdownInformation *) arg;
if (si->pstate)
{
ParallelStateEntry *entry = GetMyPSEntry(si->pstate);
if (entry != NULL && entry->AH)
DisconnectDatabase(&(entry->AH->public));
}
else if (si->AHX)
DisconnectDatabase(si->AHX);
}
void
on_exit_close_archive(Archive *AHX)
{
shutdown_info.AHX = AHX;
on_exit_nicely(archive_close_connection, &shutdown_info);
}
/*
* Main engine for parallel restore.
......@@ -3316,10 +3362,17 @@ restore_toc_entries_parallel(ArchiveHandle *AH)
TocEntry *next_work_item;
thandle ret_child;
TocEntry *te;
ParallelState *pstate;
int i;
ahlog(AH, 2, "entering restore_toc_entries_parallel\n");
slots = (ParallelSlot *) pg_calloc(sizeof(ParallelSlot), n_slots);
slots = (ParallelSlot *) pg_calloc(n_slots, sizeof(ParallelSlot));
pstate = (ParallelState *) pg_malloc(sizeof(ParallelState));
pstate->pse = (ParallelStateEntry *) pg_calloc(n_slots, sizeof(ParallelStateEntry));
pstate->numWorkers = ropt->number_of_jobs;
for (i = 0; i < pstate->numWorkers; i++)
unsetProcessIdentifier(&(pstate->pse[i]));
/* Adjust dependency information */
fix_dependencies(AH);
......@@ -3375,6 +3428,12 @@ restore_toc_entries_parallel(ArchiveHandle *AH)
*/
DisconnectDatabase(&AH->public);
/*
* Set the pstate in the shutdown_info. The exit handler uses pstate if set
* and falls back to AHX otherwise.
*/
shutdown_info.pstate = pstate;
/* blow away any transient state from the old connection */
if (AH->currUser)
free(AH->currUser);
......@@ -3473,6 +3532,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH)
args = pg_malloc(sizeof(RestoreArgs));
args->AH = CloneArchive(AH);
args->te = next_work_item;
args->pse = &pstate->pse[next_slot];
/* run the step in a worker child */
child = spawn_restore(args);
......@@ -3500,13 +3560,19 @@ restore_toc_entries_parallel(ArchiveHandle *AH)
}
else
{
die_horribly(AH, modulename, "worker process crashed: status %d\n",
work_status);
exit_horribly(modulename, "worker process crashed: status %d\n",
work_status);
}
}
ahlog(AH, 1, "finished main parallel loop\n");
/*
* Remove the pstate again, so the exit handler will now fall back to
* closing AH->connection again.
*/
shutdown_info.pstate = NULL;
/*
* Now reconnect the single parent connection.
*/
......@@ -3548,23 +3614,23 @@ spawn_restore(RestoreArgs *args)
{
/* in child process */
parallel_restore(args);
die_horribly(args->AH, modulename,
"parallel_restore should not return\n");
exit_horribly(modulename,
"parallel_restore should not return\n");
}
else if (child < 0)
{
/* fork failed */
die_horribly(args->AH, modulename,
"could not create worker process: %s\n",
strerror(errno));
exit_horribly(modulename,
"could not create worker process: %s\n",
strerror(errno));
}
#else
child = (HANDLE) _beginthreadex(NULL, 0, (void *) parallel_restore,
args, 0, NULL);
if (child == 0)
die_horribly(args->AH, modulename,
"could not create worker thread: %s\n",
strerror(errno));
exit_horribly(modulename,
"could not create worker thread: %s\n",
strerror(errno));
#endif
return child;
......@@ -3806,6 +3872,8 @@ parallel_restore(RestoreArgs *args)
RestoreOptions *ropt = AH->ropt;
int retval;
setProcessIdentifier(args->pse, AH);
/*
* Close and reopen the input file so we have a private file pointer that
* doesn't stomp on anyone else's file pointer, if we're actually going to
......@@ -3836,6 +3904,7 @@ parallel_restore(RestoreArgs *args)
/* And clean up */
DisconnectDatabase((Archive *) AH);
unsetProcessIdentifier(args->pse);
/* If we reopened the file, we are done with it, so close it now */
if (te->section == SECTION_DATA)
......@@ -3881,7 +3950,7 @@ mark_work_done(ArchiveHandle *AH, TocEntry *ready_list,
}
if (te == NULL)
die_horribly(AH, modulename, "could not find slot of finished worker\n");
exit_horribly(modulename, "could not find slot of finished worker\n");
ahlog(AH, 1, "finished item %d %s %s\n",
te->dumpId, te->desc, te->tag);
......@@ -3896,8 +3965,8 @@ mark_work_done(ArchiveHandle *AH, TocEntry *ready_list,
else if (status == WORKER_IGNORED_ERRORS)
AH->public.n_errors++;
else if (status != 0)
die_horribly(AH, modulename, "worker process failed: exit code %d\n",
status);
exit_horribly(modulename, "worker process failed: exit code %d\n",
status);
reduce_dependencies(AH, te, ready_list);
}
......
......@@ -323,10 +323,9 @@ typedef struct _tocEntry
int nLockDeps; /* number of such dependencies */
} TocEntry;
extern void on_exit_close_archive(Archive *AHX);
extern void die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4), noreturn));
extern void die_on_query_failure(ArchiveHandle *AH, const char *modulename, const char *query) __attribute__((noreturn));
extern void warn_or_die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
extern void warn_or_exit_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
extern void WriteTOC(ArchiveHandle *AH);
extern void ReadTOC(ArchiveHandle *AH);
......
......@@ -146,15 +146,15 @@ InitArchiveFmt_Custom(ArchiveHandle *AH)
{
AH->FH = fopen(AH->fSpec, PG_BINARY_W);
if (!AH->FH)
die_horribly(AH, modulename, "could not open output file \"%s\": %s\n",
AH->fSpec, strerror(errno));
exit_horribly(modulename, "could not open output file \"%s\": %s\n",
AH->fSpec, strerror(errno));
}
else
{
AH->FH = stdout;
if (!AH->FH)
die_horribly(AH, modulename, "could not open output file: %s\n",
strerror(errno));
exit_horribly(modulename, "could not open output file: %s\n",
strerror(errno));
}
ctx->hasSeek = checkSeek(AH->FH);
......@@ -165,15 +165,15 @@ InitArchiveFmt_Custom(ArchiveHandle *AH)
{
AH->FH = fopen(AH->fSpec, PG_BINARY_R);
if (!AH->FH)
die_horribly(AH, modulename, "could not open input file \"%s\": %s\n",
AH->fSpec, strerror(errno));
exit_horribly(modulename, "could not open input file \"%s\": %s\n",
AH->fSpec, strerror(errno));
}
else
{
AH->FH = stdin;
if (!AH->FH)
die_horribly(AH, modulename, "could not open input file: %s\n",
strerror(errno));
exit_horribly(modulename, "could not open input file: %s\n",
strerror(errno));
}
ctx->hasSeek = checkSeek(AH->FH);
......@@ -367,7 +367,7 @@ _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
lclContext *ctx = (lclContext *) AH->formatData;
if (oid == 0)
die_horribly(AH, modulename, "invalid OID for large object\n");
exit_horribly(modulename, "invalid OID for large object\n");
WriteInt(AH, oid);
......@@ -437,9 +437,9 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
break;
default: /* Always have a default */
die_horribly(AH, modulename,
"unrecognized data block type (%d) while searching archive\n",
blkType);
exit_horribly(modulename,
"unrecognized data block type (%d) while searching archive\n",
blkType);
break;
}
_readBlockHeader(AH, &blkType, &id);
......@@ -449,8 +449,8 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
{
/* We can just seek to the place we need to be. */
if (fseeko(AH->FH, tctx->dataPos, SEEK_SET) != 0)
die_horribly(AH, modulename, "error during file seek: %s\n",
strerror(errno));
exit_horribly(modulename, "error during file seek: %s\n",
strerror(errno));
_readBlockHeader(AH, &blkType, &id);
}
......@@ -459,25 +459,25 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
if (blkType == EOF)
{
if (tctx->dataState == K_OFFSET_POS_NOT_SET)
die_horribly(AH, modulename, "could not find block ID %d in archive -- "
"possibly due to out-of-order restore request, "
"which cannot be handled due to lack of data offsets in archive\n",
te->dumpId);
exit_horribly(modulename, "could not find block ID %d in archive -- "
"possibly due to out-of-order restore request, "
"which cannot be handled due to lack of data offsets in archive\n",
te->dumpId);
else if (!ctx->hasSeek)
die_horribly(AH, modulename, "could not find block ID %d in archive -- "
"possibly due to out-of-order restore request, "
"which cannot be handled due to non-seekable input file\n",
te->dumpId);
exit_horribly(modulename, "could not find block ID %d in archive -- "
"possibly due to out-of-order restore request, "
"which cannot be handled due to non-seekable input file\n",
te->dumpId);
else /* huh, the dataPos led us to EOF? */
die_horribly(AH, modulename, "could not find block ID %d in archive -- "
"possibly corrupt archive\n",
te->dumpId);
exit_horribly(modulename, "could not find block ID %d in archive -- "
"possibly corrupt archive\n",
te->dumpId);
}
/* Are we sane? */
if (id != te->dumpId)
die_horribly(AH, modulename, "found unexpected block ID (%d) when reading data -- expected %d\n",
id, te->dumpId);
exit_horribly(modulename, "found unexpected block ID (%d) when reading data -- expected %d\n",
id, te->dumpId);
switch (blkType)
{
......@@ -490,8 +490,8 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
break;
default: /* Always have a default */
die_horribly(AH, modulename, "unrecognized data block type %d while restoring archive\n",
blkType);
exit_horribly(modulename, "unrecognized data block type %d while restoring archive\n",
blkType);
break;
}
}
......@@ -571,11 +571,11 @@ _skipData(ArchiveHandle *AH)
if (cnt != blkLen)
{
if (feof(AH->FH))
die_horribly(AH, modulename,
"could not read from input file: end of file\n");
exit_horribly(modulename,
"could not read from input file: end of file\n");
else
die_horribly(AH, modulename,
"could not read from input file: %s\n", strerror(errno));
exit_horribly(modulename,
"could not read from input file: %s\n", strerror(errno));
}
ctx->filePos += blkLen;
......@@ -604,7 +604,7 @@ _WriteByte(ArchiveHandle *AH, const int i)
if (res != EOF)
ctx->filePos += 1;
else
die_horribly(AH, modulename, "could not write byte: %s\n", strerror(errno));
exit_horribly(modulename, "could not write byte: %s\n", strerror(errno));
return res;
}
......@@ -624,7 +624,7 @@ _ReadByte(ArchiveHandle *AH)
res = getc(AH->FH);
if (res == EOF)
die_horribly(AH, modulename, "unexpected end of file\n");
exit_horribly(modulename, "unexpected end of file\n");
ctx->filePos += 1;
return res;
}
......@@ -645,7 +645,7 @@ _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
res = fwrite(buf, 1, len, AH->FH);
if (res != len)
die_horribly(AH, modulename,
exit_horribly(modulename,
"could not write to output file: %s\n", strerror(errno));
ctx->filePos += res;
......@@ -712,7 +712,7 @@ _CloseArchive(ArchiveHandle *AH)
}
if (fclose(AH->FH) != 0)
die_horribly(AH, modulename, "could not close archive file: %s\n", strerror(errno));
exit_horribly(modulename, "could not close archive file: %s\n", strerror(errno));
AH->FH = NULL;
}
......@@ -731,37 +731,37 @@ _ReopenArchive(ArchiveHandle *AH)
pgoff_t tpos;
if (AH->mode == archModeWrite)
die_horribly(AH, modulename, "can only reopen input archives\n");
exit_horribly(modulename, "can only reopen input archives\n");
/*
* These two cases are user-facing errors since they represent unsupported
* (but not invalid) use-cases. Word the error messages appropriately.
*/
if (AH->fSpec == NULL || strcmp(AH->fSpec, "") == 0)
die_horribly(AH, modulename, "parallel restore from stdin is not supported\n");
exit_horribly(modulename, "parallel restore from stdin is not supported\n");
if (!ctx->hasSeek)
die_horribly(AH, modulename, "parallel restore from non-seekable file is not supported\n");
exit_horribly(modulename, "parallel restore from non-seekable file is not supported\n");
errno = 0;
tpos = ftello(AH->FH);
if (errno)
die_horribly(AH, modulename, "could not determine seek position in archive file: %s\n",
strerror(errno));
exit_horribly(modulename, "could not determine seek position in archive file: %s\n",
strerror(errno));
#ifndef WIN32
if (fclose(AH->FH) != 0)
die_horribly(AH, modulename, "could not close archive file: %s\n",
strerror(errno));
exit_horribly(modulename, "could not close archive file: %s\n",
strerror(errno));
#endif
AH->FH = fopen(AH->fSpec, PG_BINARY_R);
if (!AH->FH)
die_horribly(AH, modulename, "could not open input file \"%s\": %s\n",
AH->fSpec, strerror(errno));
exit_horribly(modulename, "could not open input file \"%s\": %s\n",
AH->fSpec, strerror(errno));
if (fseeko(AH->FH, tpos, SEEK_SET) != 0)
die_horribly(AH, modulename, "could not set seek position in archive file: %s\n",
strerror(errno));
exit_horribly(modulename, "could not set seek position in archive file: %s\n",
strerror(errno));
}
/*
......@@ -778,7 +778,7 @@ _Clone(ArchiveHandle *AH)
/* sanity check, shouldn't happen */
if (ctx->cs != NULL)
die_horribly(AH, modulename, "compressor active\n");
exit_horribly(modulename, "compressor active\n");
/*
* Note: we do not make a local lo_buf because we expect at most one BLOBS
......@@ -840,7 +840,7 @@ _readBlockHeader(ArchiveHandle *AH, int *type, int *id)
int byt;
/*
* Note: if we are at EOF with a pre-1.3 input file, we'll die_horribly
* Note: if we are at EOF with a pre-1.3 input file, we'll exit_horribly
* inside ReadInt rather than returning EOF. It doesn't seem worth
* jumping through hoops to deal with that case better, because no such
* files are likely to exist in the wild: only some 7.1 development
......@@ -905,10 +905,10 @@ _CustomReadFunc(ArchiveHandle *AH, char **buf, size_t *buflen)
if (cnt != blkLen)
{
if (feof(AH->FH))
die_horribly(AH, modulename,
"could not read from input file: end of file\n");
exit_horribly(modulename,
"could not read from input file: end of file\n");
else
die_horribly(AH, modulename,
exit_horribly(modulename,
"could not read from input file: %s\n", strerror(errno));
}
return cnt;
......
......@@ -30,13 +30,13 @@ static PGconn *_connectDB(ArchiveHandle *AH, const char *newdbname, const char *
static void notice_processor(void *arg, const char *message);
static int
_parse_version(ArchiveHandle *AH, const char *versionString)
_parse_version(const char *versionString)
{
int v;
v = parse_version(versionString);
if (v < 0)
die_horribly(AH, modulename, "could not parse version string \"%s\"\n", versionString);
exit_horribly(modulename, "could not parse version string \"%s\"\n", versionString);
return v;
}
......@@ -48,13 +48,13 @@ _check_database_version(ArchiveHandle *AH)
const char *remoteversion_str;
int remoteversion;
myversion = _parse_version(AH, PG_VERSION);
myversion = _parse_version(PG_VERSION);
remoteversion_str = PQparameterStatus(AH->connection, "server_version");
if (!remoteversion_str)
die_horribly(AH, modulename, "could not get server_version from libpq\n");
exit_horribly(modulename, "could not get server_version from libpq\n");
remoteversion = _parse_version(AH, remoteversion_str);
remoteversion = _parse_version(remoteversion_str);
AH->public.remoteVersionStr = pg_strdup(remoteversion_str);
AH->public.remoteVersion = remoteversion;
......@@ -67,7 +67,7 @@ _check_database_version(ArchiveHandle *AH)
{
write_msg(NULL, "server version: %s; %s version: %s\n",
remoteversion_str, progname, PG_VERSION);
die_horribly(AH, NULL, "aborting because of server version mismatch\n");
exit_horribly(NULL, "aborting because of server version mismatch\n");
}
}
......@@ -145,7 +145,7 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
{
password = simple_prompt("Password: ", 100, false);
if (password == NULL)
die_horribly(AH, modulename, "out of memory\n");
exit_horribly(modulename, "out of memory\n");
}
do
......@@ -176,12 +176,12 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
free(values);
if (!newConn)
die_horribly(AH, modulename, "failed to reconnect to database\n");
exit_horribly(modulename, "failed to reconnect to database\n");
if (PQstatus(newConn) == CONNECTION_BAD)
{
if (!PQconnectionNeedsPassword(newConn))
die_horribly(AH, modulename, "could not reconnect to database: %s",
exit_horribly(modulename, "could not reconnect to database: %s",
PQerrorMessage(newConn));
PQfinish(newConn);
......@@ -197,10 +197,10 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
if (AH->promptPassword != TRI_NO)
password = simple_prompt("Password: ", 100, false);
else
die_horribly(AH, modulename, "connection needs password\n");
exit_horribly(modulename, "connection needs password\n");
if (password == NULL)
die_horribly(AH, modulename, "out of memory\n");
exit_horribly(modulename, "out of memory\n");
new_pass = true;
}
} while (new_pass);
......@@ -238,13 +238,13 @@ ConnectDatabase(Archive *AHX,
bool new_pass;
if (AH->connection)
die_horribly(AH, modulename, "already connected to a database\n");
exit_horribly(modulename, "already connected to a database\n");
if (prompt_password == TRI_YES && password == NULL)
{
password = simple_prompt("Password: ", 100, false);
if (password == NULL)
die_horribly(AH, modulename, "out of memory\n");
exit_horribly(modulename, "out of memory\n");
}
AH->promptPassword = prompt_password;
......@@ -280,7 +280,7 @@ ConnectDatabase(Archive *AHX,
free(values);
if (!AH->connection)
die_horribly(AH, modulename, "failed to connect to database\n");
exit_horribly(modulename, "failed to connect to database\n");
if (PQstatus(AH->connection) == CONNECTION_BAD &&
PQconnectionNeedsPassword(AH->connection) &&
......@@ -290,7 +290,7 @@ ConnectDatabase(Archive *AHX,
PQfinish(AH->connection);
password = simple_prompt("Password: ", 100, false);
if (password == NULL)
die_horribly(AH, modulename, "out of memory\n");
exit_horribly(modulename, "out of memory\n");
new_pass = true;
}
} while (new_pass);
......@@ -299,7 +299,7 @@ ConnectDatabase(Archive *AHX,
/* check to see that the backend connection was successfully made */
if (PQstatus(AH->connection) == CONNECTION_BAD)
die_horribly(AH, modulename, "connection to database \"%s\" failed: %s",
exit_horribly(modulename, "connection to database \"%s\" failed: %s",
PQdb(AH->connection), PQerrorMessage(AH->connection));
/* check for version mismatch */
......@@ -331,6 +331,14 @@ notice_processor(void *arg, const char *message)
write_msg(NULL, "%s", message);
}
/* Like exit_horribly(), but with a complaint about a particular query. */
static void
die_on_query_failure(ArchiveHandle *AH, const char *modulename, const char *query)
{
write_msg(modulename, "query failed: %s",
PQerrorMessage(AH->connection));
exit_horribly(modulename, "query was: %s\n", query);
}
void
ExecuteSqlStatement(Archive *AHX, const char *query)
......@@ -393,8 +401,8 @@ ExecuteSqlCommand(ArchiveHandle *AH, const char *qry, const char *desc)
errStmt[DB_MAX_ERR_STMT - 2] = '.';
errStmt[DB_MAX_ERR_STMT - 1] = '\0';
}
warn_or_die_horribly(AH, modulename, "%s: %s Command was: %s\n",
desc, PQerrorMessage(conn), errStmt);
warn_or_exit_horribly(AH, modulename, "%s: %s Command was: %s\n",
desc, PQerrorMessage(conn), errStmt);
break;
}
......@@ -495,8 +503,8 @@ ExecuteSqlCommandBuf(ArchiveHandle *AH, const char *buf, size_t bufLen)
*/
if (AH->pgCopyIn &&
PQputCopyData(AH->connection, buf, bufLen) <= 0)
die_horribly(AH, modulename, "error returned by PQputCopyData: %s",
PQerrorMessage(AH->connection));
exit_horribly(modulename, "error returned by PQputCopyData: %s",
PQerrorMessage(AH->connection));
}
else if (AH->outputKind == OUTPUT_OTHERDATA)
{
......@@ -541,14 +549,14 @@ EndDBCopyMode(ArchiveHandle *AH, TocEntry *te)
PGresult *res;
if (PQputCopyEnd(AH->connection, NULL) <= 0)
die_horribly(AH, modulename, "error returned by PQputCopyEnd: %s",
PQerrorMessage(AH->connection));
exit_horribly(modulename, "error returned by PQputCopyEnd: %s",
PQerrorMessage(AH->connection));
/* Check command status and return to normal libpq state */
res = PQgetResult(AH->connection);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
warn_or_die_horribly(AH, modulename, "COPY failed for table \"%s\": %s",
te->tag, PQerrorMessage(AH->connection));
warn_or_exit_horribly(AH, modulename, "COPY failed for table \"%s\": %s",
te->tag, PQerrorMessage(AH->connection));
PQclear(res);
AH->pgCopyIn = false;
......
......@@ -142,7 +142,7 @@ InitArchiveFmt_Directory(ArchiveHandle *AH)
*/
if (!AH->fSpec || strcmp(AH->fSpec, "") == 0)
die_horribly(AH, modulename, "no output directory specified\n");
exit_horribly(modulename, "no output directory specified\n");
ctx->directory = AH->fSpec;
......@@ -160,9 +160,9 @@ InitArchiveFmt_Directory(ArchiveHandle *AH)
tocFH = cfopen_read(fname, PG_BINARY_R);
if (tocFH == NULL)
die_horribly(AH, modulename,
"could not open input file \"%s\": %s\n",
fname, strerror(errno));
exit_horribly(modulename,
"could not open input file \"%s\": %s\n",
fname, strerror(errno));
ctx->dataFH = tocFH;
......@@ -177,7 +177,7 @@ InitArchiveFmt_Directory(ArchiveHandle *AH)
/* Nothing else in the file, so close it again... */
if (cfclose(tocFH) != 0)
die_horribly(AH, modulename, "could not close TOC file: %s\n",
exit_horribly(modulename, "could not close TOC file: %s\n",
strerror(errno));
ctx->dataFH = NULL;
}
......@@ -288,8 +288,8 @@ _StartData(ArchiveHandle *AH, TocEntry *te)
ctx->dataFH = cfopen_write(fname, PG_BINARY_W, AH->compression);
if (ctx->dataFH == NULL)
die_horribly(AH, modulename, "could not open output file \"%s\": %s\n",
fname, strerror(errno));
exit_horribly(modulename, "could not open output file \"%s\": %s\n",
fname, strerror(errno));
}
/*
......@@ -346,7 +346,7 @@ _PrintFileData(ArchiveHandle *AH, char *filename, RestoreOptions *ropt)
cfp = cfopen_read(filename, PG_BINARY_R);
if (!cfp)
die_horribly(AH, modulename, "could not open input file \"%s\": %s\n",
exit_horribly(modulename, "could not open input file \"%s\": %s\n",
filename, strerror(errno));
buf = pg_malloc(ZLIB_OUT_SIZE);
......@@ -357,7 +357,7 @@ _PrintFileData(ArchiveHandle *AH, char *filename, RestoreOptions *ropt)
free(buf);
if (cfclose(cfp) != 0)
die_horribly(AH, modulename, "could not close data file: %s\n",
exit_horribly(modulename, "could not close data file: %s\n",
strerror(errno));
}
......@@ -397,8 +397,8 @@ _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
ctx->blobsTocFH = cfopen_read(fname, PG_BINARY_R);
if (ctx->blobsTocFH == NULL)
die_horribly(AH, modulename, "could not open large object TOC file \"%s\" for input: %s\n",
fname, strerror(errno));
exit_horribly(modulename, "could not open large object TOC file \"%s\" for input: %s\n",
fname, strerror(errno));
/* Read the blobs TOC file line-by-line, and process each blob */
while ((cfgets(ctx->blobsTocFH, line, MAXPGPATH)) != NULL)
......@@ -407,8 +407,8 @@ _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
char path[MAXPGPATH];
if (sscanf(line, "%u %s\n", &oid, fname) != 2)
die_horribly(AH, modulename, "invalid line in large object TOC file: %s\n",
line);
exit_horribly(modulename, "invalid line in large object TOC file: %s\n",
line);
StartRestoreBlob(AH, oid, ropt->dropSchema);
snprintf(path, MAXPGPATH, "%s/%s", ctx->directory, fname);
......@@ -416,12 +416,12 @@ _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
EndRestoreBlob(AH, oid);
}
if (!cfeof(ctx->blobsTocFH))
die_horribly(AH, modulename, "error reading large object TOC file \"%s\"\n",
exit_horribly(modulename, "error reading large object TOC file \"%s\"\n",
fname);
if (cfclose(ctx->blobsTocFH) != 0)
die_horribly(AH, modulename, "could not close large object TOC file \"%s\": %s\n",
fname, strerror(errno));
exit_horribly(modulename, "could not close large object TOC file \"%s\": %s\n",
fname, strerror(errno));
ctx->blobsTocFH = NULL;
......@@ -441,7 +441,7 @@ _WriteByte(ArchiveHandle *AH, const int i)
lclContext *ctx = (lclContext *) AH->formatData;
if (cfwrite(&c, 1, ctx->dataFH) != 1)
die_horribly(AH, modulename, "could not write byte\n");
exit_horribly(modulename, "could not write byte\n");
return 1;
}
......@@ -460,7 +460,7 @@ _ReadByte(ArchiveHandle *AH)
res = cfgetc(ctx->dataFH);
if (res == EOF)
die_horribly(AH, modulename, "unexpected end of file\n");
exit_horribly(modulename, "unexpected end of file\n");
return res;
}
......@@ -477,7 +477,7 @@ _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
res = cfwrite(buf, len, ctx->dataFH);
if (res != len)
die_horribly(AH, modulename, "could not write to output file: %s\n",
exit_horribly(modulename, "could not write to output file: %s\n",
strerror(errno));
return res;
......@@ -524,8 +524,8 @@ _CloseArchive(ArchiveHandle *AH)
/* The TOC is always created uncompressed */
tocFH = cfopen_write(fname, PG_BINARY_W, 0);
if (tocFH == NULL)
die_horribly(AH, modulename, "could not open output file \"%s\": %s\n",
fname, strerror(errno));
exit_horribly(modulename, "could not open output file \"%s\": %s\n",
fname, strerror(errno));
ctx->dataFH = tocFH;
/*
......@@ -538,8 +538,8 @@ _CloseArchive(ArchiveHandle *AH)
AH->format = archDirectory;
WriteToc(AH);
if (cfclose(tocFH) != 0)
die_horribly(AH, modulename, "could not close TOC file: %s\n",
strerror(errno));
exit_horribly(modulename, "could not close TOC file: %s\n",
strerror(errno));
WriteDataChunks(AH);
}
AH->FH = NULL;
......@@ -568,8 +568,8 @@ _StartBlobs(ArchiveHandle *AH, TocEntry *te)
/* The blob TOC file is never compressed */
ctx->blobsTocFH = cfopen_write(fname, "ab", 0);
if (ctx->blobsTocFH == NULL)
die_horribly(AH, modulename, "could not open output file \"%s\": %s\n",
fname, strerror(errno));
exit_horribly(modulename, "could not open output file \"%s\": %s\n",
fname, strerror(errno));
}
/*
......@@ -588,7 +588,7 @@ _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
ctx->dataFH = cfopen_write(fname, PG_BINARY_W, AH->compression);
if (ctx->dataFH == NULL)
die_horribly(AH, modulename, "could not open output file \"%s\": %s\n",
exit_horribly(modulename, "could not open output file \"%s\": %s\n",
fname, strerror(errno));
}
......@@ -611,7 +611,7 @@ _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
/* register the blob in blobs.toc */
len = snprintf(buf, sizeof(buf), "%u blob_%u.dat\n", oid, oid);
if (cfwrite(buf, len, ctx->blobsTocFH) != len)
die_horribly(AH, modulename, "could not write to blobs TOC file\n");
exit_horribly(modulename, "could not write to blobs TOC file\n");
}
/*
......@@ -667,7 +667,7 @@ prependDirectory(ArchiveHandle *AH, const char *relativeFilename)
dname = ctx->directory;
if (strlen(dname) + 1 + strlen(relativeFilename) + 1 > MAXPGPATH)
die_horribly(AH, modulename, "path name too long: %s", dname);
exit_horribly(modulename, "path name too long: %s", dname);
strcpy(buf, dname);
strcat(buf, "/");
......
......@@ -74,7 +74,7 @@ InitArchiveFmt_Null(ArchiveHandle *AH)
* Now prevent reading...
*/
if (AH->mode == archModeRead)
die_horribly(AH, NULL, "this format cannot be read\n");
exit_horribly(NULL, "this format cannot be read\n");
}
/*
......@@ -149,7 +149,7 @@ _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
bool old_blob_style = (AH->version < K_VERS_1_12);
if (oid == 0)
die_horribly(AH, NULL, "invalid OID for large object\n");
exit_horribly(NULL, "invalid OID for large object\n");
/* With an old archive we must do drop and create logic here */
if (old_blob_style && AH->ropt->dropSchema)
......
......@@ -355,7 +355,7 @@ tarOpen(ArchiveHandle *AH, const char *filename, char mode)
* Couldn't find the requested file. Future: do SEEK(0) and
* retry.
*/
die_horribly(AH, modulename, "could not find file \"%s\" in archive\n", filename);
exit_horribly(modulename, "could not find file \"%s\" in archive\n", filename);
}
else
{
......@@ -369,7 +369,7 @@ tarOpen(ArchiveHandle *AH, const char *filename, char mode)
if (AH->compression == 0)
tm->nFH = ctx->tarFH;
else
die_horribly(AH, modulename, "compression is not supported by tar archive format\n");
exit_horribly(modulename, "compression is not supported by tar archive format\n");
/* tm->zFH = gzdopen(dup(fileno(ctx->tarFH)), "rb"); */
#else
tm->nFH = ctx->tarFH;
......@@ -411,7 +411,7 @@ tarOpen(ArchiveHandle *AH, const char *filename, char mode)
#endif
if (tm->tmpFH == NULL)
die_horribly(AH, modulename, "could not generate temporary file name: %s\n", strerror(errno));
exit_horribly(modulename, "could not generate temporary file name: %s\n", strerror(errno));
#ifdef HAVE_LIBZ
......@@ -420,7 +420,7 @@ tarOpen(ArchiveHandle *AH, const char *filename, char mode)
sprintf(fmode, "wb%d", AH->compression);
tm->zFH = gzdopen(dup(fileno(tm->tmpFH)), fmode);
if (tm->zFH == NULL)
die_horribly(AH, modulename, "could not open temporary file\n");
exit_horribly(modulename, "could not open temporary file\n");
}
else
tm->nFH = tm->tmpFH;
......@@ -447,7 +447,7 @@ tarClose(ArchiveHandle *AH, TAR_MEMBER *th)
*/
if (AH->compression != 0)
if (GZCLOSE(th->zFH) != 0)
die_horribly(AH, modulename, "could not close tar member\n");
exit_horribly(modulename, "could not close tar member\n");
if (th->mode == 'w')
_tarAddFile(AH, th); /* This will close the temp file */
......@@ -547,7 +547,7 @@ _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
res = fread(&((char *) buf)[used], 1, len, th->nFH);
}
else
die_horribly(AH, modulename, "internal error -- neither th nor fh specified in tarReadRaw()\n");
exit_horribly(modulename, "internal error -- neither th nor fh specified in tarReadRaw()\n");
}
ctx->tarFHpos += res + used;
......@@ -584,8 +584,8 @@ tarWrite(const void *buf, size_t len, TAR_MEMBER *th)
res = fwrite(buf, 1, len, th->nFH);
if (res != len)
die_horribly(th->AH, modulename,
"could not write to output file: %s\n", strerror(errno));
exit_horribly(modulename,
"could not write to output file: %s\n", strerror(errno));
th->pos += res;
return res;
......@@ -672,8 +672,8 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
* we search the string for it in a paranoid sort of way.
*/
if (strncmp(tmpCopy, "copy ", 5) != 0)
die_horribly(AH, modulename,
"invalid COPY statement -- could not find \"copy\" in string \"%s\"\n", tmpCopy);
exit_horribly(modulename,
"invalid COPY statement -- could not find \"copy\" in string \"%s\"\n", tmpCopy);
pos1 = 5;
for (pos1 = 5; pos1 < strlen(tmpCopy); pos1++)
......@@ -690,9 +690,9 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
break;
if (pos2 >= strlen(tmpCopy))
die_horribly(AH, modulename,
"invalid COPY statement -- could not find \"from stdin\" in string \"%s\" starting at position %lu\n",
tmpCopy, (unsigned long) pos1);
exit_horribly(modulename,
"invalid COPY statement -- could not find \"from stdin\" in string \"%s\" starting at position %lu\n",
tmpCopy, (unsigned long) pos1);
ahwrite(tmpCopy, 1, pos2, AH); /* 'copy "table" [with oids]' */
ahprintf(AH, " from '$$PATH$$/%s' %s", tctx->filename, &tmpCopy[pos2 + 10]);
......@@ -784,7 +784,7 @@ _ReadByte(ArchiveHandle *AH)
res = tarRead(&c, 1, ctx->FH);
if (res != 1)
die_horribly(AH, modulename, "unexpected end of file\n");
exit_horribly(modulename, "unexpected end of file\n");
ctx->filePos += 1;
return c;
}
......@@ -878,7 +878,7 @@ _CloseArchive(ArchiveHandle *AH)
for (i = 0; i < 512; i++)
{
if (fputc(0, ctx->tarFH) == EOF)
die_horribly(AH, modulename,
exit_horribly(modulename,
"could not write null block at end of tar archive\n");
}
}
......@@ -934,7 +934,7 @@ _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
char *sfx;
if (oid == 0)
die_horribly(AH, modulename, "invalid OID for large object (%u)\n", oid);
exit_horribly(modulename, "invalid OID for large object (%u)\n", oid);
if (AH->compression != 0)
sfx = ".gz";
......@@ -1077,7 +1077,7 @@ _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
* because pgoff_t can't exceed the compared maximum on their platform.
*/
if (th->fileLen > MAX_TAR_MEMBER_FILELEN)
die_horribly(AH, modulename, "archive member too large for tar format\n");
exit_horribly(modulename, "archive member too large for tar format\n");
_tarWriteHeader(th);
......@@ -1085,15 +1085,15 @@ _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
{
res = fwrite(buf, 1, cnt, th->tarFH);
if (res != cnt)
die_horribly(AH, modulename,
"could not write to output file: %s\n",
strerror(errno));
exit_horribly(modulename,
"could not write to output file: %s\n",
strerror(errno));
len += res;
}
if (fclose(tmp) != 0) /* This *should* delete it... */
die_horribly(AH, modulename, "could not close temporary file: %s\n",
strerror(errno));
exit_horribly(modulename, "could not close temporary file: %s\n",
strerror(errno));
if (len != th->fileLen)
{
......@@ -1102,15 +1102,15 @@ _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
snprintf(buf1, sizeof(buf1), INT64_FORMAT, (int64) len);
snprintf(buf2, sizeof(buf2), INT64_FORMAT, (int64) th->fileLen);
die_horribly(AH, modulename, "actual file length (%s) does not match expected (%s)\n",
buf1, buf2);
exit_horribly(modulename, "actual file length (%s) does not match expected (%s)\n",
buf1, buf2);
}
pad = ((len + 511) & ~511) - len;
for (i = 0; i < pad; i++)
{
if (fputc('\0', th->tarFH) == EOF)
die_horribly(AH, modulename, "could not output padding at end of tar member\n");
exit_horribly(modulename, "could not output padding at end of tar member\n");
}
ctx->tarFHpos += len + pad;
......@@ -1159,7 +1159,7 @@ _tarPositionTo(ArchiveHandle *AH, const char *filename)
if (!_tarGetHeader(AH, th))
{
if (filename)
die_horribly(AH, modulename, "could not find header for file \"%s\" in tar archive\n", filename);
exit_horribly(modulename, "could not find header for file \"%s\" in tar archive\n", filename);
else
{
/*
......@@ -1177,9 +1177,9 @@ _tarPositionTo(ArchiveHandle *AH, const char *filename)
id = atoi(th->targetFile);
if ((TocIDRequired(AH, id, AH->ropt) & REQ_DATA) != 0)
die_horribly(AH, modulename, "restoring data out of order is not supported in this archive format: "
"\"%s\" is required, but comes before \"%s\" in the archive file.\n",
th->targetFile, filename);
exit_horribly(modulename, "restoring data out of order is not supported in this archive format: "
"\"%s\" is required, but comes before \"%s\" in the archive file.\n",
th->targetFile, filename);
/* Header doesn't match, so read to next header */
len = ((th->fileLen + 511) & ~511); /* Padded length */
......@@ -1189,7 +1189,7 @@ _tarPositionTo(ArchiveHandle *AH, const char *filename)
_tarReadRaw(AH, &header[0], 512, NULL, ctx->tarFH);
if (!_tarGetHeader(AH, th))
die_horribly(AH, modulename, "could not find header for file \"%s\" in tar archive\n", filename);
exit_horribly(modulename, "could not find header for file \"%s\" in tar archive\n", filename);
}
ctx->tarNextMember = ctx->tarFHpos + ((th->fileLen + 511) & ~511);
......@@ -1222,7 +1222,7 @@ _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
snprintf(buf1, sizeof(buf1), INT64_FORMAT, (int64) ftello(ctx->tarFH));
snprintf(buf2, sizeof(buf2), INT64_FORMAT, (int64) ftello(ctx->tarFHpos));
die_horribly(AH, modulename,
exit_horribly(modulename,
"mismatch in actual vs. predicted file position (%s vs. %s)\n",
buf1, buf2);
}
......@@ -1237,11 +1237,11 @@ _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
return 0;
if (len != 512)
die_horribly(AH, modulename,
ngettext("incomplete tar header found (%lu byte)\n",
"incomplete tar header found (%lu bytes)\n",
len),
(unsigned long) len);
exit_horribly(modulename,
ngettext("incomplete tar header found (%lu byte)\n",
"incomplete tar header found (%lu bytes)\n",
len),
(unsigned long) len);
/* Calc checksum */
chk = _tarChecksum(h);
......@@ -1285,10 +1285,10 @@ _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
char buf[100];
snprintf(buf, sizeof(buf), INT64_FORMAT, (int64) ftello(ctx->tarFH));
die_horribly(AH, modulename,
"corrupt tar header found in %s "
"(expected %d, computed %d) file position %s\n",
tag, sum, chk, buf);
exit_horribly(modulename,
"corrupt tar header found in %s "
"(expected %d, computed %d) file position %s\n",
tag, sum, chk, buf);
}
th->targetFile = pg_strdup(tag);
......@@ -1379,5 +1379,5 @@ _tarWriteHeader(TAR_MEMBER *th)
}
if (fwrite(h, 1, 512, th->tarFH) != 512)
die_horribly(th->AH, modulename, "could not write to output file: %s\n", strerror(errno));
exit_horribly(modulename, "could not write to output file: %s\n", strerror(errno));
}
......@@ -144,7 +144,6 @@ static int serializable_deferrable = 0;
static void help(const char *progname);
static void pgdump_cleanup_at_exit(int code, void *arg);
static void setup_connection(Archive *AH, const char *dumpencoding,
char *use_role);
static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
......@@ -575,7 +574,9 @@ main(int argc, char **argv)
/* Open the output file */
fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode);
on_exit_nicely(pgdump_cleanup_at_exit, fout);
/* Register the cleanup hook */
on_exit_close_archive(fout);
if (fout == NULL)
exit_horribly(NULL, "could not open output file \"%s\" for writing\n", filename);
......@@ -836,14 +837,6 @@ help(const char *progname)
printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
}
static void
pgdump_cleanup_at_exit(int code, void *arg)
{
Archive *AH = (Archive *) arg;
DisconnectDatabase(AH);
}
static void
setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
{
......
......@@ -379,6 +379,13 @@ main(int argc, char **argv)
AH = OpenArchive(inputFileSpec, opts->format);
/*
* We don't have a connection yet but that doesn't matter. The connection
* is initialized to NULL and if we terminate through exit_nicely() while
* it's still NULL, the cleanup function will just be a no-op.
*/
on_exit_close_archive(AH);
/* Let the archiver know how noisy to be */
AH->verbose = opts->verbose;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment