Skip to content

Commit 76f7ad1

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 4810fd1 commit 76f7ad1

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
@@ -63,6 +63,7 @@ static TocEntry *getTocEntryByDumpId(ArchiveHandle *AH, DumpId id);
6363
static void _moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te);
6464
static int _discoverArchiveFormat(ArchiveHandle *AH);
6565

66+
static int RestoringToDB(ArchiveHandle *AH);
6667
static void dump_lo_buf(ArchiveHandle *AH);
6768
static void _write_msg(const char *modulename, const char *fmt, va_list ap);
6869
static void _die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt, va_list ap);
@@ -379,14 +380,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
379380
te->tag);
380381

381382
/*
382-
* If we have a copy statement, use it. As of V1.3,
383-
* these are separate to allow easy import from
384-
* withing a database connection. Pre 1.3 archives can
385-
* not use DB connections and are sent to output only.
386-
*
387-
* For V1.3+, the table data MUST have a copy
388-
* statement so that we can go into appropriate mode
389-
* with libpq.
383+
* If we have a copy statement, use it.
390384
*/
391385
if (te->copyStmt && strlen(te->copyStmt) > 0)
392386
{
@@ -396,7 +390,15 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
396390

397391
(*AH->PrintTocDataPtr) (AH, te, ropt);
398392

399-
AH->writingCopyData = false;
393+
/*
394+
* Terminate COPY if needed.
395+
*/
396+
if (AH->writingCopyData)
397+
{
398+
if (RestoringToDB(AH))
399+
EndDBCopyMode(AH, te);
400+
AH->writingCopyData = false;
401+
}
400402

401403
_enableTriggersIfNecessary(AH, te, ropt);
402404
}
@@ -1038,17 +1040,13 @@ ahprintf(ArchiveHandle *AH, const char *fmt,...)
10381040
{
10391041
char *p = NULL;
10401042
va_list ap;
1041-
int bSize = strlen(fmt) + 256; /* Should be enough */
1043+
int bSize = strlen(fmt) + 256; /* Usually enough */
10421044
int cnt = -1;
10431045

10441046
/*
10451047
* This is paranoid: deal with the possibility that vsnprintf is willing
1046-
* to ignore trailing null
1047-
*/
1048-
1049-
/*
1050-
* or returns > 0 even if string does not fit. It may be the case that it
1051-
* returns cnt = bufsize
1048+
* to ignore trailing null or returns > 0 even if string does not fit.
1049+
* It may be the case that it returns cnt = bufsize.
10521050
*/
10531051
while (cnt < 0 || cnt >= (bSize - 1))
10541052
{
@@ -1128,7 +1126,7 @@ dump_lo_buf(ArchiveHandle *AH)
11281126

11291127

11301128
/*
1131-
* Write buffer to the output file (usually stdout). This is user for
1129+
* Write buffer to the output file (usually stdout). This is used for
11321130
* outputting 'restore' scripts etc. It is even possible for an archive
11331131
* format to create a custom output routine to 'fake' a restore if it
11341132
* wants to generate a script (see TAR output).
@@ -1180,7 +1178,7 @@ ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
11801178
* connected then send it to the DB.
11811179
*/
11821180
if (RestoringToDB(AH))
1183-
return ExecuteSqlCommandBuf(AH, (void *) ptr, size * nmemb); /* Always 1, currently */
1181+
return ExecuteSqlCommandBuf(AH, (const char *) ptr, size * nmemb);
11841182
else
11851183
{
11861184
res = fwrite((void *) ptr, size, nmemb, AH->OF);
@@ -1730,9 +1728,6 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
17301728
AH->mode = mode;
17311729
AH->compression = compression;
17321730

1733-
AH->pgCopyBuf = createPQExpBuffer();
1734-
AH->sqlBuf = createPQExpBuffer();
1735-
17361731
/* Open stdout with no compression for AH output handle */
17371732
AH->gzOut = 0;
17381733
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
@@ -128,28 +128,6 @@ typedef struct _outputContext
128128
int gzOut;
129129
} OutputContext;
130130

131-
typedef enum
132-
{
133-
SQL_SCAN = 0, /* normal */
134-
SQL_IN_SQL_COMMENT, /* -- comment */
135-
SQL_IN_EXT_COMMENT, /* slash-star comment */
136-
SQL_IN_SINGLE_QUOTE, /* '...' literal */
137-
SQL_IN_E_QUOTE, /* E'...' literal */
138-
SQL_IN_DOUBLE_QUOTE, /* "..." identifier */
139-
SQL_IN_DOLLAR_TAG, /* possible dollar-quote starting tag */
140-
SQL_IN_DOLLAR_QUOTE /* body of dollar quote */
141-
} sqlparseState;
142-
143-
typedef struct
144-
{
145-
sqlparseState state; /* see above */
146-
char lastChar; /* preceding char, or '\0' initially */
147-
bool backSlash; /* next char is backslash quoted? */
148-
int braceDepth; /* parenthesis nesting depth */
149-
PQExpBuffer tagBuf; /* dollar quote tag (NULL if not created) */
150-
int minTagEndPos; /* first possible end position of $-quote */
151-
} sqlparseInfo;
152-
153131
typedef enum
154132
{
155133
STAGE_NONE = 0,
@@ -185,9 +163,6 @@ typedef struct _archiveHandle
185163
* Added V1.7 */
186164
ArchiveFormat format; /* Archive format */
187165

188-
sqlparseInfo sqlparse;
189-
PQExpBuffer sqlBuf;
190-
191166
time_t createDate; /* Date archive created */
192167

193168
/*
@@ -235,8 +210,6 @@ typedef struct _archiveHandle
235210
* required */
236211
bool writingCopyData; /* True when we are sending COPY data */
237212
bool pgCopyIn; /* Currently in libpq 'COPY IN' mode. */
238-
PQExpBuffer pgCopyBuf; /* Left-over data from incomplete lines in
239-
* COPY IN */
240213

241214
int loFd; /* BLOB fd */
242215
int writingBlob; /* Flag */

0 commit comments

Comments
 (0)