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

Commit31b29b1

Browse files
committed
Further fixes for quoted-list GUC values in pg_dump and ruleutils.c.
Commits7428699 et al turn out to be a couple bricks shy of a load.We were dumping the stored values of GUC_LIST_QUOTE variables as theyappear in proconfig or setconfig catalog columns. However, although thatquoting rule looks a lot like SQL-identifier double quotes, there are twocritical differences: empty strings ("") are legal, and depending on whichvariable you're considering, values longer than NAMEDATALEN might be validtoo. So the current technique fails altogether on empty-string listentries (as reported by Steven Winfield in bug #15248) and it also riskstruncating file pathnames during dump/reload of GUC values that are listsof pathnames.To fix, split the stored value without any downcasing or truncation,and then emit each element as a SQL string literal.This is a tad annoying, because we now have three copies of thecomma-separated-string splitting logic in varlena.c as well as a fourthone in dumputils.c. (Not to mention the randomly-different-from-thosesplitting logic in libpq...) I looked at unifying these, but it wouldbe rather a mess unless we're willing to tweak the API definitions ofSplitIdentifierString, SplitDirectoriesString, or both. That might beworth doing in future; but it seems pretty unsafe for a back-patchedbug fix, so for now accept the duplication.Back-patch to all supported branches, as the previous fix was.Discussion:https://postgr.es/m/7585.1529435872@sss.pgh.pa.us
1 parent2c4d0f3 commit31b29b1

File tree

9 files changed

+326
-30
lines changed

9 files changed

+326
-30
lines changed

‎src/backend/utils/adt/ruleutils.c

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2571,14 +2571,39 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
25712571
/*
25722572
* Variables that are marked GUC_LIST_QUOTE were already fully
25732573
* quoted by flatten_set_variable_args() before they were put
2574-
* into the proconfig array; we mustn't re-quote them or we'll
2575-
* make a mess. Variables that are not so marked should just
2576-
* be emitted as simple string literals. If the variable is
2577-
* not known to guc.c, we'll do the latter; this makes it
2578-
* unsafe to use GUC_LIST_QUOTE for extension variables.
2574+
* into the proconfig array. However, because the quoting
2575+
* rules used there aren't exactly like SQL's, we have to
2576+
* break the list value apart and then quote the elements as
2577+
* string literals. (The elements may be double-quoted as-is,
2578+
* but we can't just feed them to the SQL parser; it would do
2579+
* the wrong thing with elements that are zero-length or
2580+
* longer than NAMEDATALEN.)
2581+
*
2582+
* Variables that are not so marked should just be emitted as
2583+
* simple string literals. If the variable is not known to
2584+
* guc.c, we'll do that; this makes it unsafe to use
2585+
* GUC_LIST_QUOTE for extension variables.
25792586
*/
25802587
if (GetConfigOptionFlags(configitem, true)&GUC_LIST_QUOTE)
2581-
appendStringInfoString(&buf,pos);
2588+
{
2589+
List*namelist;
2590+
ListCell*lc;
2591+
2592+
/* Parse string into list of identifiers */
2593+
if (!SplitGUCList(pos,',',&namelist))
2594+
{
2595+
/* this shouldn't fail really */
2596+
elog(ERROR,"invalid list syntax in proconfig item");
2597+
}
2598+
foreach(lc,namelist)
2599+
{
2600+
char*curname= (char*)lfirst(lc);
2601+
2602+
simple_quote_literal(&buf,curname);
2603+
if (lnext(lc))
2604+
appendStringInfoString(&buf,", ");
2605+
}
2606+
}
25822607
else
25832608
simple_quote_literal(&buf,pos);
25842609
appendStringInfoChar(&buf,'\n');

‎src/backend/utils/adt/varlena.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3477,6 +3477,118 @@ SplitDirectoriesString(char *rawstring, char separator,
34773477
}
34783478

34793479

3480+
/*
3481+
* SplitGUCList --- parse a string containing identifiers or file names
3482+
*
3483+
* This is used to split the value of a GUC_LIST_QUOTE GUC variable, without
3484+
* presuming whether the elements will be taken as identifiers or file names.
3485+
* We assume the input has already been through flatten_set_variable_args(),
3486+
* so that we need never downcase (if appropriate, that was done already).
3487+
* Nor do we ever truncate, since we don't know the correct max length.
3488+
* We disallow embedded whitespace for simplicity (it shouldn't matter,
3489+
* because any embedded whitespace should have led to double-quoting).
3490+
* Otherwise the API is identical to SplitIdentifierString.
3491+
*
3492+
* XXX it's annoying to have so many copies of this string-splitting logic.
3493+
* However, it's not clear that having one function with a bunch of option
3494+
* flags would be much better.
3495+
*
3496+
* XXX there is a version of this function in src/bin/pg_dump/dumputils.c.
3497+
* Be sure to update that if you have to change this.
3498+
*
3499+
* Inputs:
3500+
*rawstring: the input string; must be overwritable!On return, it's
3501+
* been modified to contain the separated identifiers.
3502+
*separator: the separator punctuation expected between identifiers
3503+
* (typically '.' or ','). Whitespace may also appear around
3504+
* identifiers.
3505+
* Outputs:
3506+
*namelist: filled with a palloc'd list of pointers to identifiers within
3507+
* rawstring. Caller should list_free() this even on error return.
3508+
*
3509+
* Returns true if okay, false if there is a syntax error in the string.
3510+
*/
3511+
bool
3512+
SplitGUCList(char*rawstring,charseparator,
3513+
List**namelist)
3514+
{
3515+
char*nextp=rawstring;
3516+
booldone= false;
3517+
3518+
*namelist=NIL;
3519+
3520+
while (scanner_isspace(*nextp))
3521+
nextp++;/* skip leading whitespace */
3522+
3523+
if (*nextp=='\0')
3524+
return true;/* allow empty string */
3525+
3526+
/* At the top of the loop, we are at start of a new identifier. */
3527+
do
3528+
{
3529+
char*curname;
3530+
char*endp;
3531+
3532+
if (*nextp=='"')
3533+
{
3534+
/* Quoted name --- collapse quote-quote pairs */
3535+
curname=nextp+1;
3536+
for (;;)
3537+
{
3538+
endp=strchr(nextp+1,'"');
3539+
if (endp==NULL)
3540+
return false;/* mismatched quotes */
3541+
if (endp[1]!='"')
3542+
break;/* found end of quoted name */
3543+
/* Collapse adjacent quotes into one quote, and look again */
3544+
memmove(endp,endp+1,strlen(endp));
3545+
nextp=endp;
3546+
}
3547+
/* endp now points at the terminating quote */
3548+
nextp=endp+1;
3549+
}
3550+
else
3551+
{
3552+
/* Unquoted name --- extends to separator or whitespace */
3553+
curname=nextp;
3554+
while (*nextp&&*nextp!=separator&&
3555+
!scanner_isspace(*nextp))
3556+
nextp++;
3557+
endp=nextp;
3558+
if (curname==nextp)
3559+
return false;/* empty unquoted name not allowed */
3560+
}
3561+
3562+
while (scanner_isspace(*nextp))
3563+
nextp++;/* skip trailing whitespace */
3564+
3565+
if (*nextp==separator)
3566+
{
3567+
nextp++;
3568+
while (scanner_isspace(*nextp))
3569+
nextp++;/* skip leading whitespace for next */
3570+
/* we expect another name, so done remains false */
3571+
}
3572+
elseif (*nextp=='\0')
3573+
done= true;
3574+
else
3575+
return false;/* invalid syntax */
3576+
3577+
/* Now safe to overwrite separator with a null */
3578+
*endp='\0';
3579+
3580+
/*
3581+
* Finished isolating current name --- add it to list
3582+
*/
3583+
*namelist=lappend(*namelist,curname);
3584+
3585+
/* Loop back if we didn't reach end of string */
3586+
}while (!done);
3587+
3588+
return true;
3589+
}
3590+
3591+
34803592
/*****************************************************************************
34813593
*Comparison Functions used for bytea
34823594
*

‎src/bin/pg_dump/dumputils.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
*/
1515
#include"postgres_fe.h"
1616

17+
#include<ctype.h>
18+
1719
#include"dumputils.h"
1820
#include"fe_utils/string_utils.h"
1921

@@ -869,3 +871,112 @@ variable_is_guc_list_quote(const char *name)
869871
else
870872
return false;
871873
}
874+
875+
/*
876+
* SplitGUCList --- parse a string containing identifiers or file names
877+
*
878+
* This is used to split the value of a GUC_LIST_QUOTE GUC variable, without
879+
* presuming whether the elements will be taken as identifiers or file names.
880+
* See comparable code in src/backend/utils/adt/varlena.c.
881+
*
882+
* Inputs:
883+
*rawstring: the input string; must be overwritable!On return, it's
884+
* been modified to contain the separated identifiers.
885+
*separator: the separator punctuation expected between identifiers
886+
* (typically '.' or ','). Whitespace may also appear around
887+
* identifiers.
888+
* Outputs:
889+
*namelist: receives a malloc'd, null-terminated array of pointers to
890+
* identifiers within rawstring. Caller should free this
891+
* even on error return.
892+
*
893+
* Returns true if okay, false if there is a syntax error in the string.
894+
*/
895+
bool
896+
SplitGUCList(char*rawstring,charseparator,
897+
char***namelist)
898+
{
899+
char*nextp=rawstring;
900+
booldone= false;
901+
char**nextptr;
902+
903+
/*
904+
* Since we disallow empty identifiers, this is a conservative
905+
* overestimate of the number of pointers we could need. Allow one for
906+
* list terminator.
907+
*/
908+
*namelist=nextptr= (char**)
909+
pg_malloc((strlen(rawstring) /2+2)*sizeof(char*));
910+
*nextptr=NULL;
911+
912+
while (isspace((unsignedchar)*nextp))
913+
nextp++;/* skip leading whitespace */
914+
915+
if (*nextp=='\0')
916+
return true;/* allow empty string */
917+
918+
/* At the top of the loop, we are at start of a new identifier. */
919+
do
920+
{
921+
char*curname;
922+
char*endp;
923+
924+
if (*nextp=='"')
925+
{
926+
/* Quoted name --- collapse quote-quote pairs */
927+
curname=nextp+1;
928+
for (;;)
929+
{
930+
endp=strchr(nextp+1,'"');
931+
if (endp==NULL)
932+
return false;/* mismatched quotes */
933+
if (endp[1]!='"')
934+
break;/* found end of quoted name */
935+
/* Collapse adjacent quotes into one quote, and look again */
936+
memmove(endp,endp+1,strlen(endp));
937+
nextp=endp;
938+
}
939+
/* endp now points at the terminating quote */
940+
nextp=endp+1;
941+
}
942+
else
943+
{
944+
/* Unquoted name --- extends to separator or whitespace */
945+
curname=nextp;
946+
while (*nextp&&*nextp!=separator&&
947+
!isspace((unsignedchar)*nextp))
948+
nextp++;
949+
endp=nextp;
950+
if (curname==nextp)
951+
return false;/* empty unquoted name not allowed */
952+
}
953+
954+
while (isspace((unsignedchar)*nextp))
955+
nextp++;/* skip trailing whitespace */
956+
957+
if (*nextp==separator)
958+
{
959+
nextp++;
960+
while (isspace((unsignedchar)*nextp))
961+
nextp++;/* skip leading whitespace for next */
962+
/* we expect another name, so done remains false */
963+
}
964+
elseif (*nextp=='\0')
965+
done= true;
966+
else
967+
return false;/* invalid syntax */
968+
969+
/* Now safe to overwrite separator with a null */
970+
*endp='\0';
971+
972+
/*
973+
* Finished isolating current name --- add it to output array
974+
*/
975+
*nextptr++=curname;
976+
977+
/* Loop back if we didn't reach end of string */
978+
}while (!done);
979+
980+
*nextptr=NULL;
981+
return true;
982+
}

‎src/bin/pg_dump/dumputils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,7 @@ extern void buildACLQueries(PQExpBuffer acl_subquery, PQExpBuffer racl_subquery,
5858

5959
externboolvariable_is_guc_list_quote(constchar*name);
6060

61+
externboolSplitGUCList(char*rawstring,charseparator,
62+
char***namelist);
63+
6164
#endif/* DUMPUTILS_H */

‎src/bin/pg_dump/pg_dump.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11482,14 +11482,36 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
1148211482
/*
1148311483
* Variables that are marked GUC_LIST_QUOTE were already fully quoted
1148411484
* by flatten_set_variable_args() before they were put into the
11485-
* proconfig array; we mustn't re-quote them or we'll make a mess.
11485+
* proconfig array. However, because the quoting rules used there
11486+
* aren't exactly like SQL's, we have to break the list value apart
11487+
* and then quote the elements as string literals. (The elements may
11488+
* be double-quoted as-is, but we can't just feed them to the SQL
11489+
* parser; it would do the wrong thing with elements that are
11490+
* zero-length or longer than NAMEDATALEN.)
11491+
*
1148611492
* Variables that are not so marked should just be emitted as simple
1148711493
* string literals. If the variable is not known to
11488-
* variable_is_guc_list_quote(), we'll dothe latter; this makes it
11489-
*unsafeto use GUC_LIST_QUOTE for extension variables.
11494+
* variable_is_guc_list_quote(), we'll dothat; this makes it unsafe
11495+
* to use GUC_LIST_QUOTE for extension variables.
1149011496
*/
1149111497
if (variable_is_guc_list_quote(configitem))
11492-
appendPQExpBufferStr(q, pos);
11498+
{
11499+
char **namelist;
11500+
char **nameptr;
11501+
11502+
/* Parse string into list of identifiers */
11503+
/* this shouldn't fail really */
11504+
if (SplitGUCList(pos, ',', &namelist))
11505+
{
11506+
for (nameptr = namelist; *nameptr; nameptr++)
11507+
{
11508+
if (nameptr != namelist)
11509+
appendPQExpBufferStr(q, ", ");
11510+
appendStringLiteralAH(q, *nameptr, fout);
11511+
}
11512+
}
11513+
pg_free(namelist);
11514+
}
1149311515
else
1149411516
appendStringLiteralAH(q, pos, fout);
1149511517
}

‎src/bin/pg_dump/pg_dumpall.c

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,14 +1708,35 @@ makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
17081708
/*
17091709
* Variables that are marked GUC_LIST_QUOTE were already fully quoted by
17101710
* flatten_set_variable_args() before they were put into the setconfig
1711-
* array; we mustn't re-quote them or we'll make a mess. Variables that
1712-
* are not so marked should just be emitted as simple string literals. If
1713-
* the variable is not known to variable_is_guc_list_quote(), we'll do the
1714-
* latter; this makes it unsafe to use GUC_LIST_QUOTE for extension
1715-
* variables.
1711+
* array. However, because the quoting rules used there aren't exactly
1712+
* like SQL's, we have to break the list value apart and then quote the
1713+
* elements as string literals. (The elements may be double-quoted as-is,
1714+
* but we can't just feed them to the SQL parser; it would do the wrong
1715+
* thing with elements that are zero-length or longer than NAMEDATALEN.)
1716+
*
1717+
* Variables that are not so marked should just be emitted as simple
1718+
* string literals. If the variable is not known to
1719+
* variable_is_guc_list_quote(), we'll do that; this makes it unsafe to
1720+
* use GUC_LIST_QUOTE for extension variables.
17161721
*/
17171722
if (variable_is_guc_list_quote(mine))
1718-
appendPQExpBufferStr(buf,pos+1);
1723+
{
1724+
char**namelist;
1725+
char**nameptr;
1726+
1727+
/* Parse string into list of identifiers */
1728+
/* this shouldn't fail really */
1729+
if (SplitGUCList(pos+1,',',&namelist))
1730+
{
1731+
for (nameptr=namelist;*nameptr;nameptr++)
1732+
{
1733+
if (nameptr!=namelist)
1734+
appendPQExpBufferStr(buf,", ");
1735+
appendStringLiteralConn(buf,*nameptr,conn);
1736+
}
1737+
}
1738+
pg_free(namelist);
1739+
}
17191740
else
17201741
appendStringLiteralConn(buf,pos+1,conn);
17211742
appendPQExpBufferStr(buf,";\n");

‎src/include/utils/varlena.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ extern bool SplitIdentifierString(char *rawstring, char separator,
3131
List**namelist);
3232
externboolSplitDirectoriesString(char*rawstring,charseparator,
3333
List**namelist);
34+
externboolSplitGUCList(char*rawstring,charseparator,
35+
List**namelist);
3436
externtext*replace_text_regexp(text*src_text,void*regexp,
3537
text*replace_text,boolglob);
3638

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp