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

Commit1b5e014

Browse files
committed
This patch allows pg_restore to recognize $-quotes in SQL queries. It
will treat any unquoted string that starts with a $ and has no precedingidentifier chars as a potential $-quote tag, it then makes sure that thetag chars are valid. If so, it processes the $-quote.Philip Warner
1 parentfcc5b95 commit1b5e014

File tree

2 files changed

+201
-72
lines changed

2 files changed

+201
-72
lines changed

‎src/bin/pg_dump/pg_backup_archiver.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
*
1818
*
1919
* IDENTIFICATION
20-
*$PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.58 2004/04/22 02:39:10 momjian Exp $
20+
*$PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.59 2004/08/20 16:07:15 momjian Exp $
2121
*
2222
*-------------------------------------------------------------------------
2323
*/
@@ -137,7 +137,9 @@ typedef enum
137137
SQL_SCAN=0,
138138
SQL_IN_SQL_COMMENT,
139139
SQL_IN_EXT_COMMENT,
140-
SQL_IN_QUOTE
140+
SQL_IN_QUOTE,
141+
SQL_IN_DOLLARTAG,
142+
SQL_IN_DOLLARQUOTE
141143
}sqlparseState;
142144

143145
typedefstruct
@@ -147,6 +149,7 @@ typedef struct
147149
charlastChar;
148150
charquoteChar;
149151
intbraceDepth;
152+
PQExpBuffertagBuf;
150153
}sqlparseInfo;
151154

152155
typedefstruct_archiveHandle

‎src/bin/pg_dump/pg_backup_db.c

Lines changed: 196 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*Implements the basic DB functions used by the archiver.
66
*
77
* IDENTIFICATION
8-
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.53 2004/04/22 02:39:10 momjian Exp $
8+
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.54 2004/08/20 16:07:15 momjian Exp $
99
*
1010
*-------------------------------------------------------------------------
1111
*/
@@ -37,6 +37,8 @@ static void notice_processor(void *arg, const char *message);
3737
staticchar*_sendSQLLine(ArchiveHandle*AH,char*qry,char*eos);
3838
staticchar*_sendCopyLine(ArchiveHandle*AH,char*qry,char*eos);
3939

40+
staticint_isIdentChar(charc);
41+
staticint_isDQChar(charc,intatStart);
4042

4143
staticint
4244
_parse_version(ArchiveHandle*AH,constchar*versionString)
@@ -416,6 +418,9 @@ static char *
416418
_sendSQLLine(ArchiveHandle*AH,char*qry,char*eos)
417419
{
418420
intpos=0;/* Current position */
421+
char*sqlPtr;
422+
intconsumed;
423+
intstartDT=0;
419424

420425
/*
421426
* The following is a mini state machine to assess the end of an SQL
@@ -433,88 +438,174 @@ _sendSQLLine(ArchiveHandle *AH, char *qry, char *eos)
433438
appendPQExpBufferChar(AH->sqlBuf,qry[pos]);
434439
/* fprintf(stderr, " %c",qry[pos]); */
435440

436-
switch (AH->sqlparse.state)
441+
/* Loop until character consumed */
442+
do
437443
{
444+
/* If a character needs to be scanned in a different state,
445+
* consumed can be set to 0 to avoid advancing. Care must
446+
* be taken to ensure internal state is not damaged.
447+
*/
448+
consumed=1;
438449

439-
caseSQL_SCAN:/* Default state == 0, set in _allocAH */
440-
if (qry[pos]==';'&&AH->sqlparse.braceDepth==0)
450+
switch (AH->sqlparse.state)
441451
{
442-
/* Send It & reset the buffer */
443-
444-
/*
445-
* fprintf(stderr, " sending: '%s'\n\n",
446-
* AH->sqlBuf->data);
452+
453+
caseSQL_SCAN:/* Default state == 0, set in _allocAH */
454+
if (qry[pos]==';'&&AH->sqlparse.braceDepth==0)
455+
{
456+
/* We've got the end of a statement.
457+
* Send It & reset the buffer.
458+
*/
459+
460+
/*
461+
* fprintf(stderr, " sending: '%s'\n\n",
462+
* AH->sqlBuf->data);
463+
*/
464+
ExecuteSqlCommand(AH,AH->sqlBuf,"could not execute query", false);
465+
resetPQExpBuffer(AH->sqlBuf);
466+
AH->sqlparse.lastChar='\0';
467+
468+
/*
469+
* Remove any following newlines - so that embedded
470+
* COPY commands don't get a starting newline.
471+
*/
472+
pos++;
473+
for (;pos< (eos-qry)&&qry[pos]=='\n';pos++);
474+
475+
/* We've got our line, so exit */
476+
returnqry+pos;
477+
}
478+
else
479+
{
480+
/*
481+
* Look for normal boring quote chars, or dollar-quotes. We make
482+
* the assumption that $-quotes will not have an ident character
483+
* before them in all pg_dump output.
484+
*/
485+
if (qry[pos]=='"'
486+
||qry[pos]=='\''
487+
|| (qry[pos]=='$'&&_isIdentChar(AH->sqlparse.lastChar)==0 )
488+
)
489+
{
490+
/* fprintf(stderr,"[startquote]\n"); */
491+
AH->sqlparse.state=SQL_IN_QUOTE;
492+
AH->sqlparse.quoteChar=qry[pos];
493+
AH->sqlparse.backSlash=0;
494+
if (qry[pos]=='$')
495+
{
496+
/* override the state */
497+
AH->sqlparse.state=SQL_IN_DOLLARTAG;
498+
/* Used for checking first char of tag */
499+
startDT=1;
500+
/* We store the tag for later comparison. */
501+
AH->sqlparse.tagBuf=createPQExpBuffer();
502+
/* Get leading $ */
503+
appendPQExpBufferChar(AH->sqlparse.tagBuf,qry[pos]);
504+
}
505+
}
506+
elseif (qry[pos]=='-'&&AH->sqlparse.lastChar=='-')
507+
AH->sqlparse.state=SQL_IN_SQL_COMMENT;
508+
elseif (qry[pos]=='*'&&AH->sqlparse.lastChar=='/')
509+
AH->sqlparse.state=SQL_IN_EXT_COMMENT;
510+
elseif (qry[pos]=='(')
511+
AH->sqlparse.braceDepth++;
512+
elseif (qry[pos]==')')
513+
AH->sqlparse.braceDepth--;
514+
515+
AH->sqlparse.lastChar=qry[pos];
516+
}
517+
break;
518+
519+
caseSQL_IN_DOLLARTAG:
520+
521+
/* Like a quote, we look for a closing char *but* we only
522+
* allow a very limited set of contained chars, and no escape chars.
523+
* If invalid chars are found, we abort tag processing.
447524
*/
448-
ExecuteSqlCommand(AH,AH->sqlBuf,"could not execute query", false);
449-
resetPQExpBuffer(AH->sqlBuf);
450-
AH->sqlparse.lastChar='\0';
525+
526+
if (qry[pos]=='$')
527+
{
528+
/* fprintf(stderr,"[endquote]\n"); */
529+
/* Get trailing $ */
530+
appendPQExpBufferChar(AH->sqlparse.tagBuf,qry[pos]);
531+
AH->sqlparse.state=SQL_IN_DOLLARQUOTE;
532+
}
533+
else
534+
{
535+
if (_isDQChar(qry[pos],startDT) )
536+
{
537+
/* Valid, so add */
538+
appendPQExpBufferChar(AH->sqlparse.tagBuf,qry[pos]);
539+
}
540+
else
541+
{
542+
/* Jump back to 'scan' state, we're not really in a tag,
543+
* and valid tag chars do not include the various chars
544+
* we look for in this state machine, so it's safe to just
545+
* jump from this state back to SCAN. We set consumed = 0
546+
* so that this char gets rescanned in new state.
547+
*/
548+
destroyPQExpBuffer(AH->sqlparse.tagBuf);
549+
AH->sqlparse.state=SQL_SCAN;
550+
consumed=0;
551+
}
552+
}
553+
startDT=0;
554+
break;
555+
451556

557+
caseSQL_IN_DOLLARQUOTE:
452558
/*
453-
*Remove any following newlines - so that embedded
454-
*COPY commands don't get a starting newline.
559+
*Comparing the entire string backwards each time is NOT efficient,
560+
*but dollar quotes in pg_dump are small and the code is a lot simpler.
455561
*/
456-
pos++;
457-
for (;pos< (eos-qry)&&qry[pos]=='\n';pos++);
458-
459-
/* We've got our line, so exit */
460-
returnqry+pos;
461-
}
462-
else
463-
{
464-
if (qry[pos]=='"'||qry[pos]=='\'')
562+
sqlPtr=AH->sqlBuf->data+AH->sqlBuf->len-AH->sqlparse.tagBuf->len;
563+
564+
if (strncmp(AH->sqlparse.tagBuf->data,sqlPtr,AH->sqlparse.tagBuf->len)==0) {
565+
/* End of $-quote */
566+
AH->sqlparse.state=SQL_SCAN;
567+
destroyPQExpBuffer(AH->sqlparse.tagBuf);
568+
}
569+
break;
570+
571+
caseSQL_IN_SQL_COMMENT:
572+
if (qry[pos]=='\n')
573+
AH->sqlparse.state=SQL_SCAN;
574+
break;
575+
576+
caseSQL_IN_EXT_COMMENT:
577+
if (AH->sqlparse.lastChar=='*'&&qry[pos]=='/')
578+
AH->sqlparse.state=SQL_SCAN;
579+
break;
580+
581+
caseSQL_IN_QUOTE:
582+
583+
if (!AH->sqlparse.backSlash&&AH->sqlparse.quoteChar==qry[pos])
465584
{
466-
/* fprintf(stderr,"[startquote]\n"); */
467-
AH->sqlparse.state=SQL_IN_QUOTE;
468-
AH->sqlparse.quoteChar=qry[pos];
469-
AH->sqlparse.backSlash=0;
585+
/* fprintf(stderr,"[endquote]\n"); */
586+
AH->sqlparse.state=SQL_SCAN;
470587
}
471-
elseif (qry[pos]=='-'&&AH->sqlparse.lastChar=='-')
472-
AH->sqlparse.state=SQL_IN_SQL_COMMENT;
473-
elseif (qry[pos]=='*'&&AH->sqlparse.lastChar=='/')
474-
AH->sqlparse.state=SQL_IN_EXT_COMMENT;
475-
elseif (qry[pos]=='(')
476-
AH->sqlparse.braceDepth++;
477-
elseif (qry[pos]==')')
478-
AH->sqlparse.braceDepth--;
479-
480-
AH->sqlparse.lastChar=qry[pos];
481-
}
482-
break;
483-
484-
caseSQL_IN_SQL_COMMENT:
485-
if (qry[pos]=='\n')
486-
AH->sqlparse.state=SQL_SCAN;
487-
break;
488-
489-
caseSQL_IN_EXT_COMMENT:
490-
if (AH->sqlparse.lastChar=='*'&&qry[pos]=='/')
491-
AH->sqlparse.state=SQL_SCAN;
492-
break;
493-
494-
caseSQL_IN_QUOTE:
495-
if (!AH->sqlparse.backSlash&&AH->sqlparse.quoteChar==qry[pos])
496-
{
497-
/* fprintf(stderr,"[endquote]\n"); */
498-
AH->sqlparse.state=SQL_SCAN;
499-
}
500-
else
501-
{
502-
503-
if (qry[pos]=='\\')
588+
else
504589
{
505-
if (AH->sqlparse.lastChar=='\\')
506-
AH->sqlparse.backSlash= !AH->sqlparse.backSlash;
590+
591+
if (qry[pos]=='\\')
592+
{
593+
if (AH->sqlparse.lastChar=='\\')
594+
AH->sqlparse.backSlash= !AH->sqlparse.backSlash;
595+
else
596+
AH->sqlparse.backSlash=1;
597+
}
507598
else
508-
AH->sqlparse.backSlash=1;
599+
AH->sqlparse.backSlash=0;
509600
}
510-
else
511-
AH->sqlparse.backSlash=0;
512-
}
513-
break;
601+
break;
602+
603+
}
514604

515-
}
516-
AH->sqlparse.lastChar=qry[pos];
517-
/* fprintf(stderr, "\n"); */
605+
}while (consumed==0);
606+
607+
AH->sqlparse.lastChar=qry[pos];
608+
/* fprintf(stderr, "\n"); */
518609
}
519610

520611
/*
@@ -759,3 +850,38 @@ CommitTransactionXref(ArchiveHandle *AH)
759850

760851
destroyPQExpBuffer(qry);
761852
}
853+
854+
staticint_isIdentChar(charc)
855+
{
856+
if ((c >='a'&&c <='z')
857+
||(c >='A'&&c <='Z')
858+
||(c >='0'&&c <='9')
859+
||(c=='_')
860+
||(c=='$')
861+
||(c >='\200'&&c <='\377')
862+
)
863+
{
864+
return1;
865+
}
866+
else
867+
{
868+
return0;
869+
}
870+
}
871+
872+
staticint_isDQChar(charc,intatStart)
873+
{
874+
if ((c >='a'&&c <='z')
875+
||(c >='A'&&c <='Z')
876+
||(c=='_')
877+
||(atStart==0&&c >='0'&&c <='9')
878+
||(c >='\200'&&c <='\377')
879+
)
880+
{
881+
return1;
882+
}
883+
else
884+
{
885+
return0;
886+
}
887+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp