#include "dumputils.h"
#include <ctype.h>
-#include <errno.h>
#include <unistd.h>
+#ifdef WIN32
+#include <io.h>
+#endif
+
#include "pqexpbuffer.h"
#include "libpq/libpq-fs.h"
-typedef enum _teReqs_
-{
- REQ_SCHEMA = 1,
- REQ_DATA = 2,
- REQ_ALL = REQ_SCHEMA + REQ_DATA
-} teReqs;
-
const char *progname;
+
static char *modulename = gettext_noop("archiver");
static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
const int compression, ArchiveMode mode);
-static void _getObjectDescription(PQExpBuffer buf, TocEntry *te);
+static void _getObjectDescription(PQExpBuffer buf, TocEntry *te,
+ ArchiveHandle *AH);
static void _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass);
static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
-static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool acl_pass);
+static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls);
static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
static TocEntry *getTocEntryByDumpId(ArchiveHandle *AH, DumpId id);
static int _canRestoreBlobs(ArchiveHandle *AH);
static int _restoringToDB(ArchiveHandle *AH);
+static void dumpTimestamp(ArchiveHandle *AH, const char *msg, time_t tim);
+
/*
* Wrapper functions.
RestoreArchive(Archive *AHX, RestoreOptions *ropt)
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
- TocEntry *te = AH->toc->next;
+ TocEntry *te;
teReqs reqs;
OutputContext sav;
- int impliedDataOnly;
bool defnDumped;
AH->ropt = ropt;
*/
if (!ropt->dataOnly)
{
- te = AH->toc->next;
- impliedDataOnly = 1;
- while (te != AH->toc)
+ int impliedDataOnly = 1;
+
+ for (te = AH->toc->next; te != AH->toc; te = te->next)
{
- reqs = _tocEntryRequired(te, ropt, false);
+ reqs = _tocEntryRequired(te, ropt, true);
if ((reqs & REQ_SCHEMA) != 0)
{ /* It's schema, and it's wanted */
impliedDataOnly = 0;
break;
}
- te = te->next;
}
if (impliedDataOnly)
{
ahprintf(AH, "--\n-- PostgreSQL database dump\n--\n\n");
+ if (AH->public.verbose)
+ dumpTimestamp(AH, "Started on", AH->createDate);
+
/*
* Establish important parameter values right away.
*/
*/
if (ropt->dropSchema)
{
- te = AH->toc->prev;
- AH->currentTE = te;
-
- while (te != AH->toc)
+ for (te = AH->toc->prev; te != AH->toc; te = te->prev)
{
- reqs = _tocEntryRequired(te, ropt, false);
+ AH->currentTE = te;
+
+ reqs = _tocEntryRequired(te, ropt, false /* needn't drop ACLs */);
if (((reqs & REQ_SCHEMA) != 0) && te->dropStmt)
{
/* We want the schema */
/* Drop it */
ahprintf(AH, "%s", te->dropStmt);
}
- te = te->prev;
}
}
/*
- * Now process each TOC entry
+ * Now process each non-ACL TOC entry
*/
- te = AH->toc->next;
- while (te != AH->toc)
+ for (te = AH->toc->next; te != AH->toc; te = te->next)
{
AH->currentTE = te;
* mode with libpq.
*/
if (te->copyStmt && strlen(te->copyStmt) > 0)
- ahprintf(AH, te->copyStmt);
+ ahprintf(AH, "%s", te->copyStmt);
(*AH->PrintTocDataPtr) (AH, te, ropt);
_printTocEntry(AH, te, ropt, false, false);
}
}
- te = te->next;
} /* end loop over TOC entries */
/*
* Scan TOC again to output ownership commands and ACLs
*/
- te = AH->toc->next;
- while (te != AH->toc)
+ for (te = AH->toc->next; te != AH->toc; te = te->next)
{
AH->currentTE = te;
te->desc, te->tag);
_printTocEntry(AH, te, ropt, false, true);
}
-
- te = te->next;
}
+ if (AH->public.verbose)
+ dumpTimestamp(AH, "Completed on", time(NULL));
+
+ ahprintf(AH, "--\n-- PostgreSQL database dump complete\n--\n\n");
+
/*
* Clean up & we're done.
*/
AH->blobConnection = NULL;
}
}
-
- ahprintf(AH, "--\n-- PostgreSQL database dump complete\n--\n\n");
}
/*
while (te != AH->toc)
{
- if (_tocEntryRequired(te, ropt, false) != 0)
+ if (_tocEntryRequired(te, ropt, true) != 0)
ahprintf(AH, "%d; %u %u %s %s %s %s\n", te->dumpId,
te->catalogId.tableoid, te->catalogId.oid,
te->desc, te->namespace ? te->namespace : "-",
if (!fh)
die_horribly(AH, modulename, "could not open TOC file\n");
- while (fgets(buf, 1024, fh) != NULL)
+ while (fgets(buf, sizeof(buf), fh) != NULL)
{
- /* Find a comment */
+ /* Truncate line at comment, if any */
cmnt = strchr(buf, ';');
- if (cmnt == buf)
- continue;
-
- /* End string at comment */
if (cmnt != NULL)
cmnt[0] = '\0';
- /* Skip if all spaces */
- if (strspn(buf, " \t") == strlen(buf))
+ /* Ignore if all blank */
+ if (strspn(buf, " \t\r") == strlen(buf))
continue;
- /* Get an ID */
+ /* Get an ID, check it's valid and not already seen */
id = strtol(buf, &endptr, 10);
- if (endptr == buf || id <= 0 || id > AH->maxDumpId)
+ if (endptr == buf || id <= 0 || id > AH->maxDumpId ||
+ ropt->idWanted[id - 1])
{
write_msg(modulename, "WARNING: line ignored: %s\n", buf);
continue;
}
if (AH->currentTE != NULL && AH->currentTE != AH->lastErrorTE)
{
- write_msg(modulename, "Error from TOC entry %d; %u %u %s %s %s\n", AH->currentTE->dumpId,
+ write_msg(modulename, "Error from TOC entry %d; %u %u %s %s %s\n",
+ AH->currentTE->dumpId,
AH->currentTE->catalogId.tableoid, AH->currentTE->catalogId.oid,
AH->currentTE->desc, AH->currentTE->tag, AH->currentTE->owner);
}
return NULL;
}
-int
+teReqs
TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt)
{
TocEntry *te = getTocEntryByDumpId(AH, id);
if (!te)
return 0;
- return _tocEntryRequired(te, ropt, false);
+ return _tocEntryRequired(te, ropt, true);
}
size_t
AH->gzOut = 0;
AH->OF = stdout;
+ /*
+ * On Windows, we need to use binary mode to read/write non-text archive
+ * formats. Force stdin/stdout into binary mode if that is what
+ * we are using.
+ */
+#ifdef WIN32
+ if (fmt != archNull &&
+ (AH->fSpec == NULL || strcmp(AH->fSpec, "") == 0))
+ {
+ if (mode == archModeWrite)
+ setmode(fileno(stdout), O_BINARY);
+ else
+ setmode(fileno(stdin), O_BINARY);
+ }
+#endif
+
#if 0
write_msg(modulename, "archive format is %d\n", fmt);
#endif
switch (AH->format)
{
-
case archCustom:
InitArchiveFmt_Custom(AH);
break;
}
static teReqs
-_tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool acl_pass)
+_tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
{
- teReqs res = 3; /* Schema = 1, Data = 2, Both = 3 */
+ teReqs res = REQ_ALL;
/* ENCODING objects are dumped specially, so always reject here */
if (strcmp(te->desc, "ENCODING") == 0)
return 0;
/* If it's an ACL, maybe ignore it */
- if ((!acl_pass || ropt->aclsSkip) && strcmp(te->desc, "ACL") == 0)
+ if ((!include_acls || ropt->aclsSkip) && strcmp(te->desc, "ACL") == 0)
return 0;
if (!ropt->create && strcmp(te->desc, "DATABASE") == 0)
appendPQExpBuffer(qry, "\\connect %s\n\n",
dbname ? fmtId(dbname) : "-");
-
- ahprintf(AH, qry->data);
-
+ ahprintf(AH, "%s", qry->data);
destroyPQExpBuffer(qry);
}
* information used is all that's available in older dump files.
*/
static void
-_getObjectDescription(PQExpBuffer buf, TocEntry *te)
+_getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
{
const char *type = te->desc;
strcmp(type, "TABLE") == 0 ||
strcmp(type, "TYPE") == 0)
{
- appendPQExpBuffer(buf, "%s %s", type, fmtId(te->namespace));
- appendPQExpBuffer(buf, ".%s", fmtId(te->tag));
+ appendPQExpBuffer(buf, "%s ", type);
+ if (te->namespace && te->namespace[0]) /* is null pre-7.3 */
+ appendPQExpBuffer(buf, "%s.", fmtId(te->namespace));
+ /*
+ * Pre-7.3 pg_dump would sometimes (not always) put
+ * a fmtId'd name into te->tag for an index.
+ * This check is heuristic, so make its scope as
+ * narrow as possible.
+ */
+ if (AH->version < K_VERS_1_7 &&
+ te->tag[0] == '"' &&
+ te->tag[strlen(te->tag)-1] == '"' &&
+ strcmp(type, "INDEX") == 0)
+ appendPQExpBuffer(buf, "%s", te->tag);
+ else
+ appendPQExpBuffer(buf, "%s", fmtId(te->tag));
return;
}
PQExpBuffer temp = createPQExpBuffer();
appendPQExpBuffer(temp, "ALTER ");
- _getObjectDescription(temp, te);
+ _getObjectDescription(temp, te, AH);
appendPQExpBuffer(temp, " OWNER TO %s;", fmtId(te->owner));
ahprintf(AH, "%s\n\n", temp->data);
destroyPQExpBuffer(temp);
else
return true;
}
+
+
+/*
+ * dumpTimestamp
+ */
+static void
+dumpTimestamp(ArchiveHandle *AH, const char *msg, time_t tim)
+{
+ char buf[256];
+
+ if (strftime(buf, 256, "%Y-%m-%d %H:%M:%S %Z", localtime(&tim)) != 0)
+ ahprintf(AH, "-- %s %s\n\n", msg, buf);
+}