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

Commit6680d19

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 parent8c7f64b commit6680d19

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
@@ -2200,14 +2200,39 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
22002200
/*
22012201
* Variables that are marked GUC_LIST_QUOTE were already fully
22022202
* quoted by flatten_set_variable_args() before they were put
2203-
* into the proconfig array; we mustn't re-quote them or we'll
2204-
* make a mess. Variables that are not so marked should just
2205-
* be emitted as simple string literals. If the variable is
2206-
* not known to guc.c, we'll do the latter; this makes it
2207-
* unsafe to use GUC_LIST_QUOTE for extension variables.
2203+
* into the proconfig array. However, because the quoting
2204+
* rules used there aren't exactly like SQL's, we have to
2205+
* break the list value apart and then quote the elements as
2206+
* string literals. (The elements may be double-quoted as-is,
2207+
* but we can't just feed them to the SQL parser; it would do
2208+
* the wrong thing with elements that are zero-length or
2209+
* longer than NAMEDATALEN.)
2210+
*
2211+
* Variables that are not so marked should just be emitted as
2212+
* simple string literals. If the variable is not known to
2213+
* guc.c, we'll do that; this makes it unsafe to use
2214+
* GUC_LIST_QUOTE for extension variables.
22082215
*/
22092216
if (GetConfigOptionFlags(configitem, true)&GUC_LIST_QUOTE)
2210-
appendStringInfoString(&buf,pos);
2217+
{
2218+
List*namelist;
2219+
ListCell*lc;
2220+
2221+
/* Parse string into list of identifiers */
2222+
if (!SplitGUCList(pos,',',&namelist))
2223+
{
2224+
/* this shouldn't fail really */
2225+
elog(ERROR,"invalid list syntax in proconfig item");
2226+
}
2227+
foreach(lc,namelist)
2228+
{
2229+
char*curname= (char*)lfirst(lc);
2230+
2231+
simple_quote_literal(&buf,curname);
2232+
if (lnext(lc))
2233+
appendStringInfoString(&buf,", ");
2234+
}
2235+
}
22112236
else
22122237
simple_quote_literal(&buf,pos);
22132238
appendStringInfoChar(&buf,'\n');

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

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

33413341

3342+
/*
3343+
* SplitGUCList --- parse a string containing identifiers or file names
3344+
*
3345+
* This is used to split the value of a GUC_LIST_QUOTE GUC variable, without
3346+
* presuming whether the elements will be taken as identifiers or file names.
3347+
* We assume the input has already been through flatten_set_variable_args(),
3348+
* so that we need never downcase (if appropriate, that was done already).
3349+
* Nor do we ever truncate, since we don't know the correct max length.
3350+
* We disallow embedded whitespace for simplicity (it shouldn't matter,
3351+
* because any embedded whitespace should have led to double-quoting).
3352+
* Otherwise the API is identical to SplitIdentifierString.
3353+
*
3354+
* XXX it's annoying to have so many copies of this string-splitting logic.
3355+
* However, it's not clear that having one function with a bunch of option
3356+
* flags would be much better.
3357+
*
3358+
* XXX there is a version of this function in src/bin/pg_dump/dumputils.c.
3359+
* Be sure to update that if you have to change this.
3360+
*
3361+
* Inputs:
3362+
*rawstring: the input string; must be overwritable!On return, it's
3363+
* been modified to contain the separated identifiers.
3364+
*separator: the separator punctuation expected between identifiers
3365+
* (typically '.' or ','). Whitespace may also appear around
3366+
* identifiers.
3367+
* Outputs:
3368+
*namelist: filled with a palloc'd list of pointers to identifiers within
3369+
* rawstring. Caller should list_free() this even on error return.
3370+
*
3371+
* Returns true if okay, false if there is a syntax error in the string.
3372+
*/
3373+
bool
3374+
SplitGUCList(char*rawstring,charseparator,
3375+
List**namelist)
3376+
{
3377+
char*nextp=rawstring;
3378+
booldone= false;
3379+
3380+
*namelist=NIL;
3381+
3382+
while (scanner_isspace(*nextp))
3383+
nextp++;/* skip leading whitespace */
3384+
3385+
if (*nextp=='\0')
3386+
return true;/* allow empty string */
3387+
3388+
/* At the top of the loop, we are at start of a new identifier. */
3389+
do
3390+
{
3391+
char*curname;
3392+
char*endp;
3393+
3394+
if (*nextp=='"')
3395+
{
3396+
/* Quoted name --- collapse quote-quote pairs */
3397+
curname=nextp+1;
3398+
for (;;)
3399+
{
3400+
endp=strchr(nextp+1,'"');
3401+
if (endp==NULL)
3402+
return false;/* mismatched quotes */
3403+
if (endp[1]!='"')
3404+
break;/* found end of quoted name */
3405+
/* Collapse adjacent quotes into one quote, and look again */
3406+
memmove(endp,endp+1,strlen(endp));
3407+
nextp=endp;
3408+
}
3409+
/* endp now points at the terminating quote */
3410+
nextp=endp+1;
3411+
}
3412+
else
3413+
{
3414+
/* Unquoted name --- extends to separator or whitespace */
3415+
curname=nextp;
3416+
while (*nextp&&*nextp!=separator&&
3417+
!scanner_isspace(*nextp))
3418+
nextp++;
3419+
endp=nextp;
3420+
if (curname==nextp)
3421+
return false;/* empty unquoted name not allowed */
3422+
}
3423+
3424+
while (scanner_isspace(*nextp))
3425+
nextp++;/* skip trailing whitespace */
3426+
3427+
if (*nextp==separator)
3428+
{
3429+
nextp++;
3430+
while (scanner_isspace(*nextp))
3431+
nextp++;/* skip leading whitespace for next */
3432+
/* we expect another name, so done remains false */
3433+
}
3434+
elseif (*nextp=='\0')
3435+
done= true;
3436+
else
3437+
return false;/* invalid syntax */
3438+
3439+
/* Now safe to overwrite separator with a null */
3440+
*endp='\0';
3441+
3442+
/*
3443+
* Finished isolating current name --- add it to list
3444+
*/
3445+
*namelist=lappend(*namelist,curname);
3446+
3447+
/* Loop back if we didn't reach end of string */
3448+
}while (!done);
3449+
3450+
return true;
3451+
}
3452+
3453+
33423454
/*****************************************************************************
33433455
*Comparison Functions used for bytea
33443456
*

‎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

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

‎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
@@ -11801,14 +11801,36 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
1180111801
/*
1180211802
* Variables that are marked GUC_LIST_QUOTE were already fully quoted
1180311803
* by flatten_set_variable_args() before they were put into the
11804-
* proconfig array; we mustn't re-quote them or we'll make a mess.
11804+
* proconfig array. However, because the quoting rules used there
11805+
* aren't exactly like SQL's, we have to break the list value apart
11806+
* and then quote the elements as string literals. (The elements may
11807+
* be double-quoted as-is, but we can't just feed them to the SQL
11808+
* parser; it would do the wrong thing with elements that are
11809+
* zero-length or longer than NAMEDATALEN.)
11810+
*
1180511811
* Variables that are not so marked should just be emitted as simple
1180611812
* string literals. If the variable is not known to
11807-
* variable_is_guc_list_quote(), we'll dothe latter; this makes it
11808-
*unsafeto use GUC_LIST_QUOTE for extension variables.
11813+
* variable_is_guc_list_quote(), we'll dothat; this makes it unsafe
11814+
* to use GUC_LIST_QUOTE for extension variables.
1180911815
*/
1181011816
if (variable_is_guc_list_quote(configitem))
11811-
appendPQExpBufferStr(q, pos);
11817+
{
11818+
char **namelist;
11819+
char **nameptr;
11820+
11821+
/* Parse string into list of identifiers */
11822+
/* this shouldn't fail really */
11823+
if (SplitGUCList(pos, ',', &namelist))
11824+
{
11825+
for (nameptr = namelist; *nameptr; nameptr++)
11826+
{
11827+
if (nameptr != namelist)
11828+
appendPQExpBufferStr(q, ", ");
11829+
appendStringLiteralAH(q, *nameptr, fout);
11830+
}
11831+
}
11832+
pg_free(namelist);
11833+
}
1181211834
else
1181311835
appendStringLiteralAH(q, pos, fout);
1181411836
}

‎src/bin/pg_dump/pg_dumpall.c

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,14 +1721,35 @@ makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
17211721
/*
17221722
* Variables that are marked GUC_LIST_QUOTE were already fully quoted by
17231723
* flatten_set_variable_args() before they were put into the setconfig
1724-
* array; we mustn't re-quote them or we'll make a mess. Variables that
1725-
* are not so marked should just be emitted as simple string literals. If
1726-
* the variable is not known to variable_is_guc_list_quote(), we'll do the
1727-
* latter; this makes it unsafe to use GUC_LIST_QUOTE for extension
1728-
* variables.
1724+
* array. However, because the quoting rules used there aren't exactly
1725+
* like SQL's, we have to break the list value apart and then quote the
1726+
* elements as string literals. (The elements may be double-quoted as-is,
1727+
* but we can't just feed them to the SQL parser; it would do the wrong
1728+
* thing with elements that are zero-length or longer than NAMEDATALEN.)
1729+
*
1730+
* Variables that are not so marked should just be emitted as simple
1731+
* string literals. If the variable is not known to
1732+
* variable_is_guc_list_quote(), we'll do that; this makes it unsafe to
1733+
* use GUC_LIST_QUOTE for extension variables.
17291734
*/
17301735
if (variable_is_guc_list_quote(mine))
1731-
appendPQExpBufferStr(buf,pos+1);
1736+
{
1737+
char**namelist;
1738+
char**nameptr;
1739+
1740+
/* Parse string into list of identifiers */
1741+
/* this shouldn't fail really */
1742+
if (SplitGUCList(pos+1,',',&namelist))
1743+
{
1744+
for (nameptr=namelist;*nameptr;nameptr++)
1745+
{
1746+
if (nameptr!=namelist)
1747+
appendPQExpBufferStr(buf,", ");
1748+
appendStringLiteralConn(buf,*nameptr,conn);
1749+
}
1750+
}
1751+
pg_free(namelist);
1752+
}
17321753
else
17331754
appendStringLiteralConn(buf,pos+1,conn);
17341755
appendPQExpBufferStr(buf,";\n");

‎src/include/utils/builtins.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,8 @@ extern bool SplitIdentifierString(char *rawstring, char separator,
860860
List**namelist);
861861
externboolSplitDirectoriesString(char*rawstring,charseparator,
862862
List**namelist);
863+
externboolSplitGUCList(char*rawstring,charseparator,
864+
List**namelist);
863865
externDatumreplace_text(PG_FUNCTION_ARGS);
864866
externtext*replace_text_regexp(text*src_text,void*regexp,
865867
text*replace_text,boolglob);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp