Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ff75219

Browse files
committed
Fix bugs in "restore.sql" script emitted in pg_dump tar output.
The tar output module did some very ugly and ultimately incorrect hacking on COPY commands to try to get them to work in the context of restoring a deconstructed tar archive. In particular, it would fail altogether for table names containing any upper-case characters, since it smashed the command string to lower-case before modifying it (and, just to add insult to injury, did that in a way that would fail in multibyte encodings). I don't see any particular value in being flexible about the case of the command keywords, since the string will just have been created by dumpTableData, so let's get rid of the whole case-folding thing. Also, it doesn't seem to meet the POLA for the script to restore data only in COPY mode, so add \i commands to make it have comparable behavior in --inserts mode. Noted while looking at the tar-output code in connection with Brian Weaver's patch.
1 parent 997fa75 commit ff75219

File tree

1 file changed

+35
-47
lines changed

1 file changed

+35
-47
lines changed

src/bin/pg_dump/pg_backup_tar.c

Lines changed: 35 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -647,56 +647,46 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
647647
{
648648
lclContext *ctx = (lclContext *) AH->formatData;
649649
lclTocEntry *tctx = (lclTocEntry *) te->formatData;
650-
char *tmpCopy;
651-
size_t i,
652-
pos1,
653-
pos2;
650+
int pos1;
654651

655652
if (!tctx->filename)
656653
return;
657654

655+
/*
656+
* If we're writing the special restore.sql script, emit a suitable
657+
* command to include each table's data from the corresponding file.
658+
*
659+
* In the COPY case this is a bit klugy because the regular COPY command
660+
* was already printed before we get control.
661+
*/
658662
if (ctx->isSpecialScript)
659663
{
660-
if (!te->copyStmt)
661-
return;
662-
663-
/* Abort the default COPY */
664-
ahprintf(AH, "\\.\n");
665-
666-
/* Get a copy of the COPY statement and clean it up */
667-
tmpCopy = pg_strdup(te->copyStmt);
668-
for (i = 0; i < strlen(tmpCopy); i++)
669-
tmpCopy[i] = pg_tolower((unsigned char) tmpCopy[i]);
670-
671-
/*
672-
* This is very nasty; we don't know if the archive used WITH OIDS, so
673-
* we search the string for it in a paranoid sort of way.
674-
*/
675-
if (strncmp(tmpCopy, "copy ", 5) != 0)
676-
exit_horribly(modulename,
677-
"invalid COPY statement -- could not find \"copy\" in string \"%s\"\n", tmpCopy);
678-
679-
pos1 = 5;
680-
for (pos1 = 5; pos1 < strlen(tmpCopy); pos1++)
681-
if (tmpCopy[pos1] != ' ')
682-
break;
683-
684-
if (tmpCopy[pos1] == '"')
685-
pos1 += 2;
686-
687-
pos1 += strlen(te->tag);
688-
689-
for (pos2 = pos1; pos2 < strlen(tmpCopy); pos2++)
690-
if (strncmp(&tmpCopy[pos2], "from stdin", 10) == 0)
691-
break;
664+
if (te->copyStmt)
665+
{
666+
/* Abort the COPY FROM stdin */
667+
ahprintf(AH, "\\.\n");
692668

693-
if (pos2 >= strlen(tmpCopy))
694-
exit_horribly(modulename,
695-
"invalid COPY statement -- could not find \"from stdin\" in string \"%s\" starting at position %lu\n",
696-
tmpCopy, (unsigned long) pos1);
669+
/*
670+
* The COPY statement should look like "COPY ... FROM stdin;\n",
671+
* see dumpTableData().
672+
*/
673+
pos1 = (int) strlen(te->copyStmt) - 13;
674+
if (pos1 < 6 || strncmp(te->copyStmt, "COPY ", 5) != 0 ||
675+
strcmp(te->copyStmt + pos1, " FROM stdin;\n") != 0)
676+
exit_horribly(modulename,
677+
"unexpected COPY statement syntax: \"%s\"\n",
678+
te->copyStmt);
697679

698-
ahwrite(tmpCopy, 1, pos2, AH); /* 'copy "table" [with oids]' */
699-
ahprintf(AH, " from '$$PATH$$/%s' %s", tctx->filename, &tmpCopy[pos2 + 10]);
680+
/* Emit all but the FROM part ... */
681+
ahwrite(te->copyStmt, 1, pos1, AH);
682+
/* ... and insert modified FROM */
683+
ahprintf(AH, " FROM '$$PATH$$/%s';\n\n", tctx->filename);
684+
}
685+
else
686+
{
687+
/* --inserts mode, no worries, just include the data file */
688+
ahprintf(AH, "\\i $$PATH$$/%s\n\n", tctx->filename);
689+
}
700690

701691
return;
702692
}
@@ -843,18 +833,14 @@ _CloseArchive(ArchiveHandle *AH)
843833
* if the files have been extracted.
844834
*/
845835
th = tarOpen(AH, "restore.sql", 'w');
846-
tarPrintf(AH, th, "create temporary table pgdump_restore_path(p text);\n");
836+
847837
tarPrintf(AH, th, "--\n"
848838
"-- NOTE:\n"
849839
"--\n"
850840
"-- File paths need to be edited. Search for $$PATH$$ and\n"
851841
"-- replace it with the path to the directory containing\n"
852842
"-- the extracted data files.\n"
853-
"--\n"
854-
"-- Edit the following to match the path where the\n"
855-
"-- tar archive has been extracted.\n"
856843
"--\n");
857-
tarPrintf(AH, th, "insert into pgdump_restore_path values('/tmp');\n\n");
858844

859845
AH->CustomOutPtr = _scriptOut;
860846

@@ -882,6 +868,8 @@ _CloseArchive(ArchiveHandle *AH)
882868

883869
tarClose(AH, th);
884870

871+
ctx->isSpecialScript = 0;
872+
885873
/*
886874
* EOF marker for tar files is two blocks of NULLs.
887875
*/

0 commit comments

Comments
 (0)