Skip to content

Commit 8daf82e

Browse files
committed
Fix pg_restore's direct-to-database mode for standard_conforming_strings.
pg_backup_db.c contained a mini SQL lexer with which it tried to identify boundaries between SQL commands, but that code was not designed to cope with standard_conforming_strings, and would get the wrong answer if a backslash immediately precedes a closing single quote in such a string, as per report from Julian Mehnle. The bug only affects direct-to-database restores from archive files made with standard_conforming_strings = on. Rather than complicating the code some more to try to fix that, let's just rip it all out. The only reason it was needed was to cope with COPY data embedded into ordinary archive entries, which was a layout that was used only for about the first three weeks of the archive format's existence, and never in any production release of pg_dump. Instead, just rely on the archive file layout to tell us whether we're printing COPY data or not. This bug represents a data corruption hazard in all releases in which standard_conforming_strings can be turned on, ie 8.2 and later, so back-patch to all supported branches.
1 parent c4222d3 commit 8daf82e

File tree

4 files changed

+65
-378
lines changed

4 files changed

+65
-378
lines changed

src/bin/pg_dump/pg_backup_archiver.c

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ static TocEntry *getTocEntryByDumpId(ArchiveHandle *AH, DumpId id);
6464
static void _moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te);
6565
static int _discoverArchiveFormat(ArchiveHandle *AH);
6666

67+
static int RestoringToDB(ArchiveHandle *AH);
6768
static void dump_lo_buf(ArchiveHandle *AH);
6869
static void _write_msg(const char *modulename, const char *fmt, va_list ap);
6970
static void _die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt, va_list ap);
@@ -364,14 +365,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
364365
te->tag);
365366

366367
/*
367-
* If we have a copy statement, use it. As of V1.3,
368-
* these are separate to allow easy import from
369-
* withing a database connection. Pre 1.3 archives can
370-
* not use DB connections and are sent to output only.
371-
*
372-
* For V1.3+, the table data MUST have a copy
373-
* statement so that we can go into appropriate mode
374-
* with libpq.
368+
* If we have a copy statement, use it.
375369
*/
376370
if (te->copyStmt && strlen(te->copyStmt) > 0)
377371
{
@@ -381,7 +375,15 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
381375

382376
(*AH->PrintTocDataPtr) (AH, te, ropt);
383377

384-
AH->writingCopyData = false;
378+
/*
379+
* Terminate COPY if needed.
380+
*/
381+
if (AH->writingCopyData)
382+
{
383+
if (RestoringToDB(AH))
384+
EndDBCopyMode(AH, te);
385+
AH->writingCopyData = false;
386+
}
385387

386388
_enableTriggersIfNecessary(AH, te, ropt);
387389
}
@@ -1006,17 +1008,13 @@ ahprintf(ArchiveHandle *AH, const char *fmt,...)
10061008
{
10071009
char *p = NULL;
10081010
va_list ap;
1009-
int bSize = strlen(fmt) + 256; /* Should be enough */
1011+
int bSize = strlen(fmt) + 256; /* Usually enough */
10101012
int cnt = -1;
10111013

10121014
/*
10131015
* This is paranoid: deal with the possibility that vsnprintf is willing
1014-
* to ignore trailing null
1015-
*/
1016-
1017-
/*
1018-
* or returns > 0 even if string does not fit. It may be the case that it
1019-
* returns cnt = bufsize
1016+
* to ignore trailing null or returns > 0 even if string does not fit.
1017+
* It may be the case that it returns cnt = bufsize.
10201018
*/
10211019
while (cnt < 0 || cnt >= (bSize - 1))
10221020
{
@@ -1096,7 +1094,7 @@ dump_lo_buf(ArchiveHandle *AH)
10961094

10971095

10981096
/*
1099-
* Write buffer to the output file (usually stdout). This is user for
1097+
* Write buffer to the output file (usually stdout). This is used for
11001098
* outputting 'restore' scripts etc. It is even possible for an archive
11011099
* format to create a custom output routine to 'fake' a restore if it
11021100
* wants to generate a script (see TAR output).
@@ -1148,7 +1146,7 @@ ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
11481146
* connected then send it to the DB.
11491147
*/
11501148
if (RestoringToDB(AH))
1151-
return ExecuteSqlCommandBuf(AH, (void *) ptr, size * nmemb); /* Always 1, currently */
1149+
return ExecuteSqlCommandBuf(AH, (const char *) ptr, size * nmemb);
11521150
else
11531151
{
11541152
res = fwrite((void *) ptr, size, nmemb, AH->OF);
@@ -1693,9 +1691,6 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
16931691
AH->mode = mode;
16941692
AH->compression = compression;
16951693

1696-
AH->pgCopyBuf = createPQExpBuffer();
1697-
AH->sqlBuf = createPQExpBuffer();
1698-
16991694
/* Open stdout with no compression for AH output handle */
17001695
AH->gzOut = 0;
17011696
AH->OF = stdout;

src/bin/pg_dump/pg_backup_archiver.h

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -134,28 +134,6 @@ typedef struct _outputContext
134134
int gzOut;
135135
} OutputContext;
136136

137-
typedef enum
138-
{
139-
SQL_SCAN = 0, /* normal */
140-
SQL_IN_SQL_COMMENT, /* -- comment */
141-
SQL_IN_EXT_COMMENT, /* slash-star comment */
142-
SQL_IN_SINGLE_QUOTE, /* '...' literal */
143-
SQL_IN_E_QUOTE, /* E'...' literal */
144-
SQL_IN_DOUBLE_QUOTE, /* "..." identifier */
145-
SQL_IN_DOLLAR_TAG, /* possible dollar-quote starting tag */
146-
SQL_IN_DOLLAR_QUOTE /* body of dollar quote */
147-
} sqlparseState;
148-
149-
typedef struct
150-
{
151-
sqlparseState state; /* see above */
152-
char lastChar; /* preceding char, or '\0' initially */
153-
bool backSlash; /* next char is backslash quoted? */
154-
int braceDepth; /* parenthesis nesting depth */
155-
PQExpBuffer tagBuf; /* dollar quote tag (NULL if not created) */
156-
int minTagEndPos; /* first possible end position of $-quote */
157-
} sqlparseInfo;
158-
159137
typedef enum
160138
{
161139
STAGE_NONE = 0,
@@ -191,9 +169,6 @@ typedef struct _archiveHandle
191169
* Added V1.7 */
192170
ArchiveFormat format; /* Archive format */
193171

194-
sqlparseInfo sqlparse;
195-
PQExpBuffer sqlBuf;
196-
197172
time_t createDate; /* Date archive created */
198173

199174
/*
@@ -241,8 +216,6 @@ typedef struct _archiveHandle
241216
* required */
242217
bool writingCopyData; /* True when we are sending COPY data */
243218
bool pgCopyIn; /* Currently in libpq 'COPY IN' mode. */
244-
PQExpBuffer pgCopyBuf; /* Left-over data from incomplete lines in
245-
* COPY IN */
246219

247220
int loFd; /* BLOB fd */
248221
int writingBlob; /* Flag */

0 commit comments

Comments
 (0)