Skip to content

Commit ea608bf

Browse files
committed
pg_dump failed to handle backslashes embedded in function definitions
(and most other places where it needed to output a string literal, too, except for data INSERT statements). Per bug report from Easter, 12/1/00.
1 parent 60500d5 commit ea608bf

File tree

1 file changed

+105
-108
lines changed

1 file changed

+105
-108
lines changed

src/bin/pg_dump/pg_dump.c

Lines changed: 105 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*
2323
*
2424
* IDENTIFICATION
25-
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.183 2000/12/03 20:45:37 tgl Exp $
25+
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.184 2001/01/04 01:23:47 tgl Exp $
2626
*
2727
* Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
2828
*
@@ -138,7 +138,7 @@ static void dumpTriggers(Archive *fout, const char *tablename,
138138
TableInfo *tblinfo, int numTables);
139139
static void dumpRules(Archive *fout, const char *tablename,
140140
TableInfo *tblinfo, int numTables);
141-
static char *checkForQuote(const char *s);
141+
static void formatStringLiteral(PQExpBuffer buf, const char *str);
142142
static void clearTableInfo(TableInfo *, int);
143143
static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
144144
TypeInfo *tinfo, int numTypes);
@@ -434,7 +434,6 @@ dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
434434
PQExpBuffer q = createPQExpBuffer();
435435
int tuple;
436436
int field;
437-
const char *expsrc;
438437

439438
appendPQExpBuffer(q, "SELECT * FROM %s", fmtId(classname, force_quotes));
440439
res = PQexec(g_conn, q->data);
@@ -492,32 +491,10 @@ dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
492491
/*
493492
* All other types are printed as string literals,
494493
* with appropriate escaping of special characters.
495-
* Quote mark ' goes to '' per SQL standard, other
496-
* stuff goes to \ sequences.
497494
*/
498-
archputc('\'', fout);
499-
expsrc = PQgetvalue(res, tuple, field);
500-
while (*expsrc)
501-
{
502-
char ch = *expsrc++;
503-
504-
if (ch == '\\' || ch == '\'')
505-
{
506-
archputc(ch, fout); /* double these */
507-
archputc(ch, fout);
508-
}
509-
else if (ch < '\040')
510-
{
511-
/* generate octal escape for control chars */
512-
archputc('\\', fout);
513-
archputc(((ch >> 6) & 3) + '0', fout);
514-
archputc(((ch >> 3) & 7) + '0', fout);
515-
archputc((ch & 7) + '0', fout);
516-
}
517-
else
518-
archputc(ch, fout);
519-
}
520-
archputc('\'', fout);
495+
resetPQExpBuffer(q);
496+
formatStringLiteral(q, PQgetvalue(res, tuple, field));
497+
archprintf(fout, "%s", q->data);
521498
break;
522499
}
523500
}
@@ -527,6 +504,41 @@ dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
527504
return 1;
528505
}
529506

507+
/*
508+
* Convert a string value to an SQL string literal,
509+
* with appropriate escaping of special characters.
510+
* Quote mark ' goes to '' per SQL standard, other
511+
* stuff goes to \ sequences.
512+
* The literal is appended to the given PQExpBuffer.
513+
*/
514+
static void
515+
formatStringLiteral(PQExpBuffer buf, const char *str)
516+
{
517+
appendPQExpBufferChar(buf, '\'');
518+
while (*str)
519+
{
520+
char ch = *str++;
521+
522+
if (ch == '\\' || ch == '\'')
523+
{
524+
appendPQExpBufferChar(buf, ch); /* double these */
525+
appendPQExpBufferChar(buf, ch);
526+
}
527+
else if ((unsigned char) ch < (unsigned char) ' ' &&
528+
ch != '\n' && ch != '\t')
529+
{
530+
/* generate octal escape for control chars other than whitespace */
531+
appendPQExpBufferChar(buf, '\\');
532+
appendPQExpBufferChar(buf, ((ch >> 6) & 3) + '0');
533+
appendPQExpBufferChar(buf, ((ch >> 3) & 7) + '0');
534+
appendPQExpBufferChar(buf, (ch & 7) + '0');
535+
}
536+
else
537+
appendPQExpBufferChar(buf, ch);
538+
}
539+
appendPQExpBufferChar(buf, '\'');
540+
}
541+
530542
/*
531543
* DumpClasses -
532544
* dump the contents of all the classes.
@@ -1067,7 +1079,8 @@ dumpDatabase(Archive *AH)
10671079

10681080
/* Get the dba */
10691081
appendPQExpBuffer(dbQry, "select (select usename from pg_user where datdba = usesysid) as dba from pg_database"
1070-
" where datname = '%s'", PQdb(g_conn));
1082+
" where datname = ");
1083+
formatStringLiteral(dbQry, PQdb(g_conn));
10711084

10721085
res = PQexec(g_conn, dbQry->data);
10731086
if (!res ||
@@ -1826,7 +1839,7 @@ getFuncs(int *numFuncs)
18261839
finfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
18271840
finfo[i].proname = strdup(PQgetvalue(res, i, i_proname));
18281841

1829-
finfo[i].prosrc = checkForQuote(PQgetvalue(res, i, i_prosrc));
1842+
finfo[i].prosrc = strdup(PQgetvalue(res, i, i_prosrc));
18301843
finfo[i].probin = strdup(PQgetvalue(res, i, i_probin));
18311844

18321845
finfo[i].prorettype = strdup(PQgetvalue(res, i, i_prorettype));
@@ -1955,7 +1968,9 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
19551968
PGresult *res2;
19561969

19571970
resetPQExpBuffer(query);
1958-
appendPQExpBuffer(query, "SELECT pg_get_viewdef('%s') as viewdef ", tblinfo[i].relname);
1971+
appendPQExpBuffer(query, "SELECT pg_get_viewdef(");
1972+
formatStringLiteral(query, tblinfo[i].relname);
1973+
appendPQExpBuffer(query, ") as viewdef");
19591974
res2 = PQexec(g_conn, query->data);
19601975
if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
19611976
{
@@ -2753,8 +2768,9 @@ dumpComment(Archive *fout, const char *target, const char *oid)
27532768
{
27542769
i_description = PQfnumber(res, "description");
27552770
resetPQExpBuffer(query);
2756-
appendPQExpBuffer(query, "COMMENT ON %s IS '%s';\n",
2757-
target, checkForQuote(PQgetvalue(res, 0, i_description)));
2771+
appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
2772+
formatStringLiteral(query, PQgetvalue(res, 0, i_description));
2773+
appendPQExpBuffer(query, ";\n");
27582774

27592775
ArchiveEntry(fout, oid, target, "COMMENT", NULL, query->data, "" /*Del*/,
27602776
"" /* Copy */, "" /*Owner*/, NULL, NULL);
@@ -2788,8 +2804,8 @@ dumpDBComment(Archive *fout)
27882804
/*** Build query to find comment ***/
27892805

27902806
query = createPQExpBuffer();
2791-
appendPQExpBuffer(query, "SELECT oid FROM pg_database WHERE datname = '%s'",
2792-
PQdb(g_conn));
2807+
appendPQExpBuffer(query, "SELECT oid FROM pg_database WHERE datname = ");
2808+
formatStringLiteral(query, PQdb(g_conn));
27932809

27942810
/*** Execute query ***/
27952811

@@ -2864,25 +2880,28 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
28642880
resetPQExpBuffer(q);
28652881
appendPQExpBuffer(q,
28662882
"CREATE TYPE %s "
2867-
"( internallength = %s, externallength = %s, input = %s, "
2868-
"output = %s, send = %s, receive = %s, default = '%s'",
2883+
"( internallength = %s, externallength = %s,",
28692884
fmtId(tinfo[i].typname, force_quotes),
28702885
tinfo[i].typlen,
2871-
tinfo[i].typprtlen,
2872-
tinfo[i].typinput,
2873-
tinfo[i].typoutput,
2874-
tinfo[i].typsend,
2875-
tinfo[i].typreceive,
2876-
tinfo[i].typdefault);
2886+
tinfo[i].typprtlen);
2887+
/* cannot combine these because fmtId uses static result area */
2888+
appendPQExpBuffer(q, " input = %s,",
2889+
fmtId(tinfo[i].typinput, force_quotes));
2890+
appendPQExpBuffer(q, " output = %s,",
2891+
fmtId(tinfo[i].typoutput, force_quotes));
2892+
appendPQExpBuffer(q, " send = %s,",
2893+
fmtId(tinfo[i].typsend, force_quotes));
2894+
appendPQExpBuffer(q, " receive = %s, default = ",
2895+
fmtId(tinfo[i].typreceive, force_quotes));
2896+
formatStringLiteral(q, tinfo[i].typdefault);
28772897

28782898
if (tinfo[i].isArray)
28792899
{
28802900
char *elemType;
28812901

28822902
elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem, zeroAsOpaque);
2883-
2884-
appendPQExpBuffer(q, ", element = %s, delimiter = '%s'",
2885-
elemType, tinfo[i].typdelim);
2903+
appendPQExpBuffer(q, ", element = %s, delimiter = ", elemType);
2904+
formatStringLiteral(q, tinfo[i].typdelim);
28862905
}
28872906
if (tinfo[i].passedbyvalue)
28882907
appendPQExpBuffer(q, ",passedbyvalue);\n");
@@ -2971,24 +2990,25 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
29712990

29722991
dumpOneFunc(fout, finfo, fidx, tinfo, numTypes);
29732992

2974-
lanname = checkForQuote(PQgetvalue(res, i, i_lanname));
2975-
lancompiler = checkForQuote(PQgetvalue(res, i, i_lancompiler));
2993+
lanname = PQgetvalue(res, i, i_lanname);
2994+
lancompiler = PQgetvalue(res, i, i_lancompiler);
29762995

2977-
appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE '%s';\n", lanname);
2996+
appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE ");
2997+
formatStringLiteral(delqry, lanname);
2998+
appendPQExpBuffer(delqry, ";\n");
29782999

2979-
appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE '%s' "
2980-
"HANDLER %s LANCOMPILER '%s';\n",
2981-
(PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ? "TRUSTED " : "",
2982-
lanname,
2983-
fmtId(finfo[fidx].proname, force_quotes),
2984-
lancompiler);
3000+
appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE ",
3001+
(PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ?
3002+
"TRUSTED " : "");
3003+
formatStringLiteral(defqry, lanname);
3004+
appendPQExpBuffer(defqry, " HANDLER %s LANCOMPILER ",
3005+
fmtId(finfo[fidx].proname, force_quotes));
3006+
formatStringLiteral(defqry, lancompiler);
3007+
appendPQExpBuffer(defqry, ";\n");
29853008

29863009
ArchiveEntry(fout, PQgetvalue(res, i, i_oid), lanname, "PROCEDURAL LANGUAGE",
29873010
NULL, defqry->data, delqry->data, "", "", NULL, NULL);
29883011

2989-
free(lanname);
2990-
free(lancompiler);
2991-
29923012
resetPQExpBuffer(defqry);
29933013
resetPQExpBuffer(delqry);
29943014
}
@@ -3071,15 +3091,21 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
30713091
*/
30723092
if (strcmp(finfo[i].probin, "-") != 0)
30733093
{
3094+
appendPQExpBuffer(asPart, "AS ");
3095+
formatStringLiteral(asPart, finfo[i].probin);
30743096
if (strcmp(finfo[i].prosrc, "-") != 0)
3075-
appendPQExpBuffer(asPart, "AS '%s', '%s'", finfo[i].probin, finfo[i].prosrc);
3076-
else
3077-
appendPQExpBuffer(asPart, "AS '%s'", finfo[i].probin);
3097+
{
3098+
appendPQExpBuffer(asPart, ", ");
3099+
formatStringLiteral(asPart, finfo[i].prosrc);
3100+
}
30783101
}
30793102
else
30803103
{
30813104
if (strcmp(finfo[i].prosrc, "-") != 0)
3082-
appendPQExpBuffer(asPart, "AS '%s'", finfo[i].prosrc);
3105+
{
3106+
appendPQExpBuffer(asPart, "AS ");
3107+
formatStringLiteral(asPart, finfo[i].prosrc);
3108+
}
30833109
}
30843110

30853111
strcpy(func_lang, PQgetvalue(res, 0, i_lanname));
@@ -3107,10 +3133,11 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
31073133

31083134
resetPQExpBuffer(q);
31093135
appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data );
3110-
appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE '%s'",
3111-
(finfo[i].retset) ? " SETOF " : "",
3136+
appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE ",
3137+
(finfo[i].retset) ? "SETOF " : "",
31123138
findTypeByOid(tinfo, numTypes, finfo[i].prorettype, zeroAsOpaque),
3113-
asPart->data, func_lang);
3139+
asPart->data);
3140+
formatStringLiteral(q, func_lang);
31143141

31153142
if (finfo[i].iscachable || finfo[i].isstrict) /* OR in new attrs here */
31163143
{
@@ -3286,8 +3313,10 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
32863313
findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype, zeroAsOpaque + useBaseTypeName));
32873314

32883315
if (agginfo[i].agginitval)
3289-
appendPQExpBuffer(details, ", INITCOND = '%s'",
3290-
agginfo[i].agginitval);
3316+
{
3317+
appendPQExpBuffer(details, ", INITCOND = ");
3318+
formatStringLiteral(details, agginfo[i].agginitval);
3319+
}
32913320

32923321
if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
32933322
appendPQExpBuffer(details, ", FINALFUNC = %s",
@@ -3970,7 +3999,8 @@ findLastBuiltinOid(const char* dbname)
39703999
PQExpBuffer query = createPQExpBuffer();
39714000

39724001
resetPQExpBuffer(query);
3973-
appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = '%s'", dbname);
4002+
appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
4003+
formatStringLiteral(query, dbname);
39744004

39754005
res = PQexec(g_conn, query->data);
39764006
if (res == NULL ||
@@ -3999,41 +4029,6 @@ findLastBuiltinOid(const char* dbname)
39994029
}
40004030

40014031

4002-
/*
4003-
* checkForQuote:
4004-
* checks a string for quote characters and quotes them
4005-
*/
4006-
static char *
4007-
checkForQuote(const char *s)
4008-
{
4009-
char *r;
4010-
char c;
4011-
char *result;
4012-
4013-
int j = 0;
4014-
4015-
r = malloc(strlen(s) * 3 + 1); /* definitely long enough */
4016-
4017-
while ((c = *s) != '\0')
4018-
{
4019-
4020-
if (c == '\'')
4021-
{
4022-
r[j++] = '\''; /* quote the single quotes */
4023-
}
4024-
r[j++] = c;
4025-
s++;
4026-
}
4027-
r[j] = '\0';
4028-
4029-
result = strdup(r);
4030-
free(r);
4031-
4032-
return result;
4033-
4034-
}
4035-
4036-
40374032
static void
40384033
dumpSequence(Archive *fout, TableInfo tbinfo)
40394034
{
@@ -4113,8 +4108,9 @@ dumpSequence(Archive *fout, TableInfo tbinfo)
41134108

41144109

41154110
resetPQExpBuffer(query);
4116-
appendPQExpBuffer(query, "SELECT setval ('%s', %d, '%c');\n",
4117-
fmtId(tbinfo.relname, force_quotes), last, called);
4111+
appendPQExpBuffer(query, "SELECT setval (");
4112+
formatStringLiteral(query, fmtId(tbinfo.relname, force_quotes));
4113+
appendPQExpBuffer(query, ", %d, '%c');\n", last, called);
41184114

41194115
ArchiveEntry(fout, tbinfo.oid, fmtId(tbinfo.relname, force_quotes), "SEQUENCE SET", NULL,
41204116
query->data, "" /* Del */, "", "", NULL, NULL);
@@ -4191,12 +4187,13 @@ dumpRules(Archive *fout, const char *tablename,
41914187
" (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
41924188
" pg_rewrite.oid, pg_rewrite.rulename "
41934189
"FROM pg_rewrite, pg_class, pg_rules "
4194-
"WHERE pg_class.relname = '%s' "
4190+
"WHERE pg_class.relname = ");
4191+
formatStringLiteral(query, tblinfo[t].relname);
4192+
appendPQExpBuffer(query,
41954193
" AND pg_rewrite.ev_class = pg_class.oid "
41964194
" AND pg_rules.tablename = pg_class.relname "
41974195
" AND pg_rules.rulename = pg_rewrite.rulename "
4198-
"ORDER BY pg_rewrite.oid",
4199-
tblinfo[t].relname);
4196+
"ORDER BY pg_rewrite.oid");
42004197
res = PQexec(g_conn, query->data);
42014198
if (!res ||
42024199
PQresultStatus(res) != PGRES_TUPLES_OK)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy