]> granicus.if.org Git - postgresql/commitdiff
pg_dump failed to handle backslashes embedded in function definitions
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 4 Jan 2001 01:23:47 +0000 (01:23 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 4 Jan 2001 01:23:47 +0000 (01:23 +0000)
(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.

src/bin/pg_dump/pg_dump.c

index 588f90df5497275f5ade3e8f078e17ce472af265..43c91e3e4ed3f89472d04ec6b2b66a279f461f3a 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.183 2000/12/03 20:45:37 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.184 2001/01/04 01:23:47 tgl Exp $
  *
  * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
  *
@@ -138,7 +138,7 @@ static void dumpTriggers(Archive *fout, const char *tablename,
                         TableInfo *tblinfo, int numTables);
 static void dumpRules(Archive *fout, const char *tablename,
                  TableInfo *tblinfo, int numTables);
-static char *checkForQuote(const char *s);
+static void formatStringLiteral(PQExpBuffer buf, const char *str);
 static void clearTableInfo(TableInfo *, int);
 static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
                        TypeInfo *tinfo, int numTypes);
@@ -434,7 +434,6 @@ dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
        PQExpBuffer q = createPQExpBuffer();
        int                     tuple;
        int                     field;
-       const char *expsrc;
 
        appendPQExpBuffer(q, "SELECT * FROM %s", fmtId(classname, force_quotes));
        res = PQexec(g_conn, q->data);
@@ -492,32 +491,10 @@ dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
                                        /*
                                         * All other types are printed as string literals,
                                         * with appropriate escaping of special characters.
-                                        * Quote mark ' goes to '' per SQL standard, other
-                                        * stuff goes to \ sequences.
                                         */
-                                       archputc('\'', fout);
-                                       expsrc = PQgetvalue(res, tuple, field);
-                                       while (*expsrc)
-                                       {
-                                               char            ch = *expsrc++;
-
-                                               if (ch == '\\' || ch == '\'')
-                                               {
-                                                       archputc(ch, fout);                     /* double these */
-                                                       archputc(ch, fout);
-                                               }
-                                               else if (ch < '\040')
-                                               {
-                                                       /* generate octal escape for control chars */
-                                                       archputc('\\', fout);
-                                                       archputc(((ch >> 6) & 3) + '0', fout);
-                                                       archputc(((ch >> 3) & 7) + '0', fout);
-                                                       archputc((ch & 7) + '0', fout);
-                                               }
-                                               else
-                                                       archputc(ch, fout);
-                                       }
-                                       archputc('\'', fout);
+                                       resetPQExpBuffer(q);
+                                       formatStringLiteral(q, PQgetvalue(res, tuple, field));
+                                       archprintf(fout, "%s", q->data);
                                        break;
                        }
                }
@@ -527,6 +504,41 @@ dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
        return 1;
 }
 
+/*
+ * Convert a string value to an SQL string literal,
+ * with appropriate escaping of special characters.
+ * Quote mark ' goes to '' per SQL standard, other
+ * stuff goes to \ sequences.
+ * The literal is appended to the given PQExpBuffer.
+ */
+static void
+formatStringLiteral(PQExpBuffer buf, const char *str)
+{
+       appendPQExpBufferChar(buf, '\'');
+       while (*str)
+       {
+               char    ch = *str++;
+
+               if (ch == '\\' || ch == '\'')
+               {
+                       appendPQExpBufferChar(buf, ch); /* double these */
+                       appendPQExpBufferChar(buf, ch);
+               }
+               else if ((unsigned char) ch < (unsigned char) ' ' &&
+                                ch != '\n' && ch != '\t')
+               {
+                       /* generate octal escape for control chars other than whitespace */
+                       appendPQExpBufferChar(buf, '\\');
+                       appendPQExpBufferChar(buf, ((ch >> 6) & 3) + '0');
+                       appendPQExpBufferChar(buf, ((ch >> 3) & 7) + '0');
+                       appendPQExpBufferChar(buf, (ch & 7) + '0');
+               }
+               else
+                       appendPQExpBufferChar(buf, ch);
+       }
+       appendPQExpBufferChar(buf, '\'');
+}
+
 /*
  * DumpClasses -
  *       dump the contents of all the classes.
@@ -1067,7 +1079,8 @@ dumpDatabase(Archive *AH)
 
        /* Get the dba */
        appendPQExpBuffer(dbQry, "select (select usename from pg_user where datdba = usesysid) as dba from pg_database"
-                                                       " where datname = '%s'", PQdb(g_conn));
+                                                       " where datname = ");
+       formatStringLiteral(dbQry, PQdb(g_conn));
 
        res = PQexec(g_conn, dbQry->data);
        if (!res ||
@@ -1826,7 +1839,7 @@ getFuncs(int *numFuncs)
                finfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
                finfo[i].proname = strdup(PQgetvalue(res, i, i_proname));
 
-               finfo[i].prosrc = checkForQuote(PQgetvalue(res, i, i_prosrc));
+               finfo[i].prosrc = strdup(PQgetvalue(res, i, i_prosrc));
                finfo[i].probin = strdup(PQgetvalue(res, i, i_probin));
 
                finfo[i].prorettype = strdup(PQgetvalue(res, i, i_prorettype));
@@ -1955,7 +1968,9 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
                        PGresult   *res2;
 
                        resetPQExpBuffer(query);
-                       appendPQExpBuffer(query, "SELECT pg_get_viewdef('%s') as viewdef ", tblinfo[i].relname);
+                       appendPQExpBuffer(query, "SELECT pg_get_viewdef(");
+                       formatStringLiteral(query, tblinfo[i].relname);
+                       appendPQExpBuffer(query, ") as viewdef");
                        res2 = PQexec(g_conn, query->data);
                        if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
                        {
@@ -2753,8 +2768,9 @@ dumpComment(Archive *fout, const char *target, const char *oid)
        {
                i_description = PQfnumber(res, "description");
                resetPQExpBuffer(query);
-               appendPQExpBuffer(query, "COMMENT ON %s IS '%s';\n",
-                                                       target, checkForQuote(PQgetvalue(res, 0, i_description)));
+               appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
+               formatStringLiteral(query, PQgetvalue(res, 0, i_description));
+               appendPQExpBuffer(query, ";\n");
 
                ArchiveEntry(fout, oid, target, "COMMENT", NULL, query->data, "" /*Del*/,
                                           "" /* Copy */, "" /*Owner*/, NULL, NULL);    
@@ -2788,8 +2804,8 @@ dumpDBComment(Archive *fout)
        /*** Build query to find comment ***/
 
        query = createPQExpBuffer();
-       appendPQExpBuffer(query, "SELECT oid FROM pg_database WHERE datname = '%s'",
-                                         PQdb(g_conn));
+       appendPQExpBuffer(query, "SELECT oid FROM pg_database WHERE datname = ");
+       formatStringLiteral(query, PQdb(g_conn));
 
        /*** Execute query ***/
 
@@ -2864,25 +2880,28 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
                resetPQExpBuffer(q);
                appendPQExpBuffer(q,
                                                  "CREATE TYPE %s "
-                          "( internallength = %s, externallength = %s, input = %s, "
-                                 "output = %s, send = %s, receive = %s, default = '%s'",
+                                                 "( internallength = %s, externallength = %s,",
                                                  fmtId(tinfo[i].typname, force_quotes),
                                                  tinfo[i].typlen,
-                                                 tinfo[i].typprtlen,
-                                                 tinfo[i].typinput,
-                                                 tinfo[i].typoutput,
-                                                 tinfo[i].typsend,
-                                                 tinfo[i].typreceive,
-                                                 tinfo[i].typdefault);
+                                                 tinfo[i].typprtlen);
+               /* cannot combine these because fmtId uses static result area */
+               appendPQExpBuffer(q, " input = %s,",
+                                                 fmtId(tinfo[i].typinput, force_quotes));
+               appendPQExpBuffer(q, " output = %s,",
+                                                 fmtId(tinfo[i].typoutput, force_quotes));
+               appendPQExpBuffer(q, " send = %s,",
+                                                 fmtId(tinfo[i].typsend, force_quotes));
+               appendPQExpBuffer(q, " receive = %s, default = ",
+                                                 fmtId(tinfo[i].typreceive, force_quotes));
+               formatStringLiteral(q, tinfo[i].typdefault);
 
                if (tinfo[i].isArray)
                {
                        char       *elemType;
 
                        elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem, zeroAsOpaque);
-
-                       appendPQExpBuffer(q, ", element = %s, delimiter = '%s'",
-                                                         elemType, tinfo[i].typdelim);
+                       appendPQExpBuffer(q, ", element = %s, delimiter = ", elemType);
+                       formatStringLiteral(q, tinfo[i].typdelim);
                }
                if (tinfo[i].passedbyvalue)
                        appendPQExpBuffer(q, ",passedbyvalue);\n");
@@ -2971,24 +2990,25 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
 
                dumpOneFunc(fout, finfo, fidx, tinfo, numTypes);
 
-               lanname = checkForQuote(PQgetvalue(res, i, i_lanname));
-               lancompiler = checkForQuote(PQgetvalue(res, i, i_lancompiler));
+               lanname = PQgetvalue(res, i, i_lanname);
+               lancompiler = PQgetvalue(res, i, i_lancompiler);
 
-               appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE '%s';\n", lanname);
+               appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE ");
+               formatStringLiteral(delqry, lanname);
+               appendPQExpBuffer(delqry, ";\n");
 
-               appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE '%s' "
-                               "HANDLER %s LANCOMPILER '%s';\n",
-                               (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ? "TRUSTED " : "",
-                               lanname,
-                               fmtId(finfo[fidx].proname, force_quotes),
-                               lancompiler);
+               appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE ",
+                                                 (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ?
+                                                 "TRUSTED " : "");
+               formatStringLiteral(defqry, lanname);
+               appendPQExpBuffer(defqry, " HANDLER %s LANCOMPILER ",
+                                                 fmtId(finfo[fidx].proname, force_quotes));
+               formatStringLiteral(defqry, lancompiler);
+               appendPQExpBuffer(defqry, ";\n");
 
                ArchiveEntry(fout, PQgetvalue(res, i, i_oid), lanname, "PROCEDURAL LANGUAGE",
                            NULL, defqry->data, delqry->data, "", "", NULL, NULL);
 
-               free(lanname);
-               free(lancompiler);
-
                resetPQExpBuffer(defqry);
                resetPQExpBuffer(delqry);
        }
@@ -3071,15 +3091,21 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
         */
        if (strcmp(finfo[i].probin, "-") != 0)
        {
+               appendPQExpBuffer(asPart, "AS ");
+               formatStringLiteral(asPart, finfo[i].probin);
                if (strcmp(finfo[i].prosrc, "-") != 0)
-                       appendPQExpBuffer(asPart, "AS '%s', '%s'", finfo[i].probin, finfo[i].prosrc);
-               else
-                       appendPQExpBuffer(asPart, "AS '%s'", finfo[i].probin);
+               {
+                       appendPQExpBuffer(asPart, ", ");
+                       formatStringLiteral(asPart, finfo[i].prosrc);
+               }
        }
        else
        {
                if (strcmp(finfo[i].prosrc, "-") != 0)
-                       appendPQExpBuffer(asPart, "AS '%s'", finfo[i].prosrc);
+               {
+                       appendPQExpBuffer(asPart, "AS ");
+                       formatStringLiteral(asPart, finfo[i].prosrc);
+               }
        }
 
        strcpy(func_lang, PQgetvalue(res, 0, i_lanname));
@@ -3107,10 +3133,11 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
 
        resetPQExpBuffer(q);
        appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data );
-       appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE '%s'",
-                                         (finfo[i].retset) ? " SETOF " : "",
+       appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE ",
+                                         (finfo[i].retset) ? "SETOF " : "",
                                          findTypeByOid(tinfo, numTypes, finfo[i].prorettype, zeroAsOpaque),
-                                         asPart->data, func_lang);
+                                         asPart->data);
+       formatStringLiteral(q, func_lang);
 
        if (finfo[i].iscachable || finfo[i].isstrict) /* OR in new attrs here */
        {
@@ -3286,8 +3313,10 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
                                                  findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype, zeroAsOpaque + useBaseTypeName));
 
                if (agginfo[i].agginitval)
-                       appendPQExpBuffer(details, ", INITCOND = '%s'",
-                                                         agginfo[i].agginitval);
+               {
+                       appendPQExpBuffer(details, ", INITCOND = ");
+                       formatStringLiteral(details, agginfo[i].agginitval);
+               }
 
                if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
                        appendPQExpBuffer(details, ", FINALFUNC = %s",
@@ -3970,7 +3999,8 @@ findLastBuiltinOid(const char* dbname)
        PQExpBuffer query = createPQExpBuffer();
 
        resetPQExpBuffer(query);
-       appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = '%s'", dbname);
+       appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
+       formatStringLiteral(query, dbname);
 
        res = PQexec(g_conn, query->data);
        if (res == NULL ||
@@ -3999,41 +4029,6 @@ findLastBuiltinOid(const char* dbname)
 }
 
 
-/*
- * checkForQuote:
- *       checks a string for quote characters and quotes them
- */
-static char *
-checkForQuote(const char *s)
-{
-       char       *r;
-       char            c;
-       char       *result;
-
-       int                     j = 0;
-
-       r = malloc(strlen(s) * 3 + 1);          /* definitely long enough */
-
-       while ((c = *s) != '\0')
-       {
-
-               if (c == '\'')
-               {
-                       r[j++] = '\'';          /* quote the single quotes */
-               }
-               r[j++] = c;
-               s++;
-       }
-       r[j] = '\0';
-
-       result = strdup(r);
-       free(r);
-
-       return result;
-
-}
-
-
 static void
 dumpSequence(Archive *fout, TableInfo tbinfo)
 {
@@ -4113,8 +4108,9 @@ dumpSequence(Archive *fout, TableInfo tbinfo)
 
 
        resetPQExpBuffer(query);
-       appendPQExpBuffer(query, "SELECT setval ('%s', %d, '%c');\n", 
-                                               fmtId(tbinfo.relname, force_quotes), last, called);
+       appendPQExpBuffer(query, "SELECT setval (");
+       formatStringLiteral(query, fmtId(tbinfo.relname, force_quotes));
+       appendPQExpBuffer(query, ", %d, '%c');\n", last, called);
 
        ArchiveEntry(fout, tbinfo.oid, fmtId(tbinfo.relname, force_quotes), "SEQUENCE SET", NULL,
                                        query->data, "" /* Del */, "", "", NULL, NULL);
@@ -4191,12 +4187,13 @@ dumpRules(Archive *fout, const char *tablename,
                                                  "   (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
                                                  "   pg_rewrite.oid, pg_rewrite.rulename "
                                                  "FROM pg_rewrite, pg_class, pg_rules "
-                                                 "WHERE pg_class.relname = '%s' "
+                                                 "WHERE pg_class.relname = ");
+               formatStringLiteral(query, tblinfo[t].relname);
+               appendPQExpBuffer(query,
                                                  "    AND pg_rewrite.ev_class = pg_class.oid "
                                                  "    AND pg_rules.tablename = pg_class.relname "
                                                  "    AND pg_rules.rulename = pg_rewrite.rulename "
-                                                 "ORDER BY pg_rewrite.oid",
-                                                 tblinfo[t].relname);
+                                                 "ORDER BY pg_rewrite.oid");
                res = PQexec(g_conn, query->data);
                if (!res ||
                        PQresultStatus(res) != PGRES_TUPLES_OK)