Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit522650a

Browse files
committed
Fix pg_restore's direct-to-database mode for INSERT-style table data.
In commit6545a90, I removed the mini SQLlexer that was in pg_backup_db.c, thinking that it had no real purposebeyond separating COPY data from SQL commands, which purpose had beenobsoleted by long-ago fixes in pg_dump's archive file format.Unfortunately this was in error: that code was also used to identifycommand boundaries in INSERT-style table data, which is run together as asingle string in the archive file for better compressibility. As a result,direct-to-database restores from archive files made with --inserts or--column-inserts fail in our latest releases, as reported by Dick Visser.To fix, restore the mini SQL lexer, but simplify it by adjusting thecalling logic so that it's only required to cope with INSERT-style tabledata, not arbitrary SQL commands. This allows us to not have to deal withSQL comments, E'' strings, or dollar-quoted strings, none of which haveever been emitted by dumpTableData_insert.Also, fix the lexer to cope with standard-conforming strings, which was theactual bug that the previous patch was meant to solve.Back-patch to all supported branches. The previous patch went back to 8.2,which unfortunately means that the EOL release of 8.2 contains this bug,but I don't think we're doing another 8.2 release just because of that.
1 parentf9f0484 commit522650a

File tree

4 files changed

+135
-11
lines changed

4 files changed

+135
-11
lines changed

‎src/bin/pg_dump/pg_backup_archiver.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -617,20 +617,20 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te,
617617
if (te->copyStmt&&strlen(te->copyStmt)>0)
618618
{
619619
ahprintf(AH,"%s",te->copyStmt);
620-
AH->writingCopyData=true;
620+
AH->outputKind=OUTPUT_COPYDATA;
621621
}
622+
else
623+
AH->outputKind=OUTPUT_OTHERDATA;
622624

623625
(*AH->PrintTocDataPtr) (AH,te,ropt);
624626

625627
/*
626628
* Terminate COPY if needed.
627629
*/
628-
if (AH->writingCopyData)
629-
{
630-
if (RestoringToDB(AH))
631-
EndDBCopyMode(AH,te);
632-
AH->writingCopyData= false;
633-
}
630+
if (AH->outputKind==OUTPUT_COPYDATA&&
631+
RestoringToDB(AH))
632+
EndDBCopyMode(AH,te);
633+
AH->outputKind=OUTPUT_SQLCMDS;
634634

635635
/* close out the transaction started above */
636636
if (is_parallel&&te->created)
@@ -2006,6 +2006,8 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
20062006
AH->mode=mode;
20072007
AH->compression=compression;
20082008

2009+
memset(&(AH->sqlparse),0,sizeof(AH->sqlparse));
2010+
20092011
/* Open stdout with no compression for AH output handle */
20102012
AH->gzOut=0;
20112013
AH->OF=stdout;
@@ -4209,7 +4211,8 @@ CloneArchive(ArchiveHandle *AH)
42094211
die_horribly(AH,modulename,"out of memory\n");
42104212
memcpy(clone,AH,sizeof(ArchiveHandle));
42114213

4212-
/* Handle format-independent fields ... none at the moment */
4214+
/* Handle format-independent fields */
4215+
memset(&(clone->sqlparse),0,sizeof(clone->sqlparse));
42134216

42144217
/* The clone will have its own connection, so disregard connection state */
42154218
clone->connection=NULL;
@@ -4242,7 +4245,9 @@ DeCloneArchive(ArchiveHandle *AH)
42424245
/* Clear format-specific state */
42434246
(AH->DeClonePtr) (AH);
42444247

4245-
/* Clear state allocated by CloneArchive ... none at the moment */
4248+
/* Clear state allocated by CloneArchive */
4249+
if (AH->sqlparse.curCmd)
4250+
destroyPQExpBuffer(AH->sqlparse.curCmd);
42464251

42474252
/* Clear any connection-local state */
42484253
if (AH->currUser)

‎src/bin/pg_dump/pg_backup_archiver.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,20 @@ typedef void (*DeClonePtr) (struct _archiveHandle * AH);
132132

133133
typedefsize_t (*CustomOutPtr) (struct_archiveHandle*AH,constvoid*buf,size_tlen);
134134

135+
typedefenum
136+
{
137+
SQL_SCAN=0,/* normal */
138+
SQL_IN_SINGLE_QUOTE,/* '...' literal */
139+
SQL_IN_DOUBLE_QUOTE/* "..." identifier */
140+
}sqlparseState;
141+
142+
typedefstruct
143+
{
144+
sqlparseStatestate;/* see above */
145+
boolbackSlash;/* next char is backslash quoted? */
146+
PQExpBuffercurCmd;/* incomplete line (NULL if not created) */
147+
}sqlparseInfo;
148+
135149
typedefenum
136150
{
137151
STAGE_NONE=0,
@@ -140,6 +154,13 @@ typedef enum
140154
STAGE_FINALIZING
141155
}ArchiverStage;
142156

157+
typedefenum
158+
{
159+
OUTPUT_SQLCMDS=0,/* emitting general SQL commands */
160+
OUTPUT_COPYDATA,/* writing COPY data */
161+
OUTPUT_OTHERDATA/* writing data as INSERT commands */
162+
}ArchiverOutput;
163+
143164
typedefenum
144165
{
145166
REQ_SCHEMA=1,
@@ -167,6 +188,8 @@ typedef struct _archiveHandle
167188
* Added V1.7 */
168189
ArchiveFormatformat;/* Archive format */
169190

191+
sqlparseInfosqlparse;/* state for parsing INSERT data */
192+
170193
time_tcreateDate;/* Date archive created */
171194

172195
/*
@@ -217,7 +240,7 @@ typedef struct _archiveHandle
217240
PGconn*connection;
218241
intconnectToDB;/* Flag to indicate if direct DB connection is
219242
* required */
220-
boolwritingCopyData;/*True when we are sending COPY data */
243+
ArchiverOutputoutputKind;/*Flag for what we're currently writing */
221244
boolpgCopyIn;/* Currently in libpq 'COPY IN' mode. */
222245

223246
intloFd;/* BLOB fd */

‎src/bin/pg_dump/pg_backup_db.c

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,15 +369,93 @@ ExecuteSqlCommand(ArchiveHandle *AH, const char *qry, const char *desc)
369369
}
370370

371371

372+
/*
373+
* Process non-COPY table data (that is, INSERT commands).
374+
*
375+
* The commands have been run together as one long string for compressibility,
376+
* and we are receiving them in bufferloads with arbitrary boundaries, so we
377+
* have to locate command boundaries and save partial commands across calls.
378+
* All state must be kept in AH->sqlparse, not in local variables of this
379+
* routine. We assume that AH->sqlparse was filled with zeroes when created.
380+
*
381+
* We have to lex the data to the extent of identifying literals and quoted
382+
* identifiers, so that we can recognize statement-terminating semicolons.
383+
* We assume that INSERT data will not contain SQL comments, E'' literals,
384+
* or dollar-quoted strings, so this is much simpler than a full SQL lexer.
385+
*/
386+
staticvoid
387+
ExecuteInsertCommands(ArchiveHandle*AH,constchar*buf,size_tbufLen)
388+
{
389+
constchar*qry=buf;
390+
constchar*eos=buf+bufLen;
391+
392+
/* initialize command buffer if first time through */
393+
if (AH->sqlparse.curCmd==NULL)
394+
AH->sqlparse.curCmd=createPQExpBuffer();
395+
396+
for (;qry<eos;qry++)
397+
{
398+
charch=*qry;
399+
400+
/* For neatness, we skip any newlines between commands */
401+
if (!(ch=='\n'&&AH->sqlparse.curCmd->len==0))
402+
appendPQExpBufferChar(AH->sqlparse.curCmd,ch);
403+
404+
switch (AH->sqlparse.state)
405+
{
406+
caseSQL_SCAN:/* Default state == 0, set in _allocAH */
407+
if (ch==';')
408+
{
409+
/*
410+
* We've found the end of a statement. Send it and reset
411+
* the buffer.
412+
*/
413+
ExecuteSqlCommand(AH,AH->sqlparse.curCmd->data,
414+
"could not execute query");
415+
resetPQExpBuffer(AH->sqlparse.curCmd);
416+
}
417+
elseif (ch=='\'')
418+
{
419+
AH->sqlparse.state=SQL_IN_SINGLE_QUOTE;
420+
AH->sqlparse.backSlash= false;
421+
}
422+
elseif (ch=='"')
423+
{
424+
AH->sqlparse.state=SQL_IN_DOUBLE_QUOTE;
425+
}
426+
break;
427+
428+
caseSQL_IN_SINGLE_QUOTE:
429+
/* We needn't handle '' specially */
430+
if (ch=='\''&& !AH->sqlparse.backSlash)
431+
AH->sqlparse.state=SQL_SCAN;
432+
elseif (ch=='\\'&& !AH->public.std_strings)
433+
AH->sqlparse.backSlash= !AH->sqlparse.backSlash;
434+
else
435+
AH->sqlparse.backSlash= false;
436+
break;
437+
438+
caseSQL_IN_DOUBLE_QUOTE:
439+
/* We needn't handle "" specially */
440+
if (ch=='"')
441+
AH->sqlparse.state=SQL_SCAN;
442+
break;
443+
}
444+
}
445+
}
446+
447+
372448
/*
373449
* Implement ahwrite() for direct-to-DB restore
374450
*/
375451
int
376452
ExecuteSqlCommandBuf(ArchiveHandle*AH,constchar*buf,size_tbufLen)
377453
{
378-
if (AH->writingCopyData)
454+
if (AH->outputKind==OUTPUT_COPYDATA)
379455
{
380456
/*
457+
* COPY data.
458+
*
381459
* We drop the data on the floor if libpq has failed to enter COPY
382460
* mode; this allows us to behave reasonably when trying to continue
383461
* after an error in a COPY command.
@@ -387,9 +465,19 @@ ExecuteSqlCommandBuf(ArchiveHandle *AH, const char *buf, size_t bufLen)
387465
die_horribly(AH,modulename,"error returned by PQputCopyData: %s",
388466
PQerrorMessage(AH->connection));
389467
}
468+
elseif (AH->outputKind==OUTPUT_OTHERDATA)
469+
{
470+
/*
471+
* Table data expressed as INSERT commands.
472+
*/
473+
ExecuteInsertCommands(AH,buf,bufLen);
474+
}
390475
else
391476
{
392477
/*
478+
* General SQL commands; we assume that commands will not be split
479+
* across calls.
480+
*
393481
* In most cases the data passed to us will be a null-terminated
394482
* string, but if it's not, we have to add a trailing null.
395483
*/

‎src/bin/pg_dump/pg_dump.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,14 @@ dumpTableData_copy(Archive *fout, void *dcontext)
13521352
return1;
13531353
}
13541354

1355+
/*
1356+
* Dump table data using INSERT commands.
1357+
*
1358+
* Caution: when we restore from an archive file direct to database, the
1359+
* INSERT commands emitted by this function have to be parsed by
1360+
* pg_backup_db.c's ExecuteInsertCommands(), which will not handle comments,
1361+
* E'' strings, or dollar-quoted strings. So don't emit anything like that.
1362+
*/
13551363
staticint
13561364
dumpTableData_insert(Archive*fout,void*dcontext)
13571365
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp