dollar quoting and pg_dump - Mailing list pgsql-patches

From Andrew Dunstan
Subject dollar quoting and pg_dump
Date
Msg-id 406095A2.7060205@dunslane.net
Whole thread Raw
Responses Re: dollar quoting and pg_dump
List pgsql-patches

Here's my attempt, as discussed earlier today. As always, comments
welcome.  I did provide (and use) a fallback mechanism after all, for
the case of a function with a non-empty probin. A few examples from a
dump of the regression db:

--
-- Name: tg_hub_adjustslots(character, integer, integer); Type:
FUNCTION; Schema
: public; Owner: andrew
--

CREATE FUNCTION tg_hub_adjustslots(character, integer, integer) RETURNS
integer
    AS $_$
declare
    hname   alias for $1;
    oldnslots   alias for $2;
    newnslots   alias for $3;
begin
    if newnslots = oldnslots then
        return 0;
    end if;
    if newnslots < oldnslots then
        delete from HSlot where hubname = hname and slotno > newnslots;
    return 0;
    end if;
    for i in oldnslots + 1 .. newnslots loop
        insert into HSlot (slotname, hubname, slotno, slotlink)
        values ('HS.dummy', hname, i, '');
    end loop;
    return 0;
end;
$_$
    LANGUAGE plpgsql;

--
-- Name: ttdummy(); Type: FUNCTION; Schema: public; Owner: andrew
--

CREATE FUNCTION ttdummy() RETURNS "trigger"
    AS '/home/andrew/pgwork/tip/pgsql/src/test/regress/regress.so',
'ttdummy'
    LANGUAGE c;


--
-- Name: user_relns(); Type: FUNCTION; Schema: public; Owner: andrew
--

CREATE FUNCTION user_relns() RETURNS SETOF name
    AS $$select relname
       from pg_class c, pg_namespace n
       where relnamespace = n.oid and
             (nspname !~ 'pg_.*' and nspname <> 'information_schema') and
             relkind <> 'i' $$
    LANGUAGE sql;



cheers

andrew


Index: doc/src/sgml/ref/pg_dump.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/ref/pg_dump.sgml,v
retrieving revision 1.68
diff -c -r1.68 pg_dump.sgml
*** doc/src/sgml/ref/pg_dump.sgml    1 Dec 2003 22:07:58 -0000    1.68
--- doc/src/sgml/ref/pg_dump.sgml    23 Mar 2004 19:30:59 -0000
***************
*** 461,466 ****
--- 461,477 ----
       </varlistentry>

       <varlistentry>
+       <term><option>-X disable-dollar-quoting</></term>
+       <term><option>--disable-dollar-quoting</></term>
+       <listitem>
+        <para>
+         This option disables the use of dollar quoting for function bodies,
+         and forces them to be quoted using SQL standard strings.
+        </para>
+      </listitem>
+     </varlistentry>
+
+      <varlistentry>
        <term><option>-Z <replaceable class="parameter">0..9</replaceable></option></term>
        <term><option>--compress=<replaceable class="parameter">0..9</replaceable></option></term>
        <listitem>
Index: src/bin/pg_dump/dumputils.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/bin/pg_dump/dumputils.c,v
retrieving revision 1.11
diff -c -r1.11 dumputils.c
*** src/bin/pg_dump/dumputils.c    7 Jan 2004 00:44:21 -0000    1.11
--- src/bin/pg_dump/dumputils.c    23 Mar 2004 19:30:59 -0000
***************
*** 143,148 ****
--- 143,205 ----


  /*
+  * Convert a string value to a dollar quoted literal and append it to
+  * the given buffer. If the dqprefix parameter is not NULL then the
+  * dollar quote delimiter will begin with that (after the opening $).
+  *
+  * No escaping is done at all on str, in compliance with the rules
+  * for parsing dollar quoted strings.
+  */
+ void
+ appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
+ {
+     static char suffixes[] = "_XXXXXXXX";
+     int nextchar = 0;
+     PQExpBuffer delimBuf = createPQExpBuffer();
+
+     /* start with $ + dqprefix if not NULL */
+     appendPQExpBufferChar(delimBuf, '$');
+     if (dqprefix)
+         appendPQExpBuffer(delimBuf, dqprefix);
+
+     /*
+      * make sure we have a delimiter which (without the trailing $)
+      * is not preent in the string being quoted. We don't check with the
+      * trailing $ so that a string ending in $foo is not quoted with
+      * $foo$.
+      */
+     while (strstr(str, delimBuf->data) != NULL)
+     {
+         appendPQExpBufferChar(delimBuf, suffixes[nextchar++]);
+         nextchar %= sizeof(suffixes)-1;
+     }
+
+     /* add trailing $ */
+     appendPQExpBufferChar(delimBuf, '$');
+
+     /* quote it and we are all done */
+     appendPQExpBuffer(buf,"%s%s%s",delimBuf->data,str,delimBuf->data);
+     destroyPQExpBuffer(delimBuf);
+
+ }
+
+ /*
+  * use dollar quoting if the string to be quoted contains ' or \,
+  * otherwise use standard quoting.
+  */
+
+
+ void appendStringLiteralDQFallback(PQExpBuffer buf, const char *str,
+                 bool escapeAll, const char *dqprefix)
+ {
+     if (strchr(str,'\'') == NULL && strchr(str,'\\') == NULL)
+         appendStringLiteral(buf,str,escapeAll);
+     else
+         appendStringLiteralDQ(buf,str,dqprefix);
+ }
+
+
+ /*
   * Convert backend's version string into a number.
   */
  int
Index: src/bin/pg_dump/dumputils.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/bin/pg_dump/dumputils.h,v
retrieving revision 1.10
diff -c -r1.10 dumputils.h
*** src/bin/pg_dump/dumputils.h    7 Jan 2004 00:44:21 -0000    1.10
--- src/bin/pg_dump/dumputils.h    23 Mar 2004 19:30:59 -0000
***************
*** 21,26 ****
--- 21,30 ----
  extern const char *fmtId(const char *identifier);
  extern void appendStringLiteral(PQExpBuffer buf, const char *str,
                      bool escapeAll);
+ extern void appendStringLiteralDQ(PQExpBuffer buf, const char *str,
+                 const char *dqprefix);
+ extern void appendStringLiteralDQFallback(PQExpBuffer buf, const char *str,
+                 bool escapeAll, const char *dqprefix);
  extern int    parse_version(const char *versionString);
  extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
  extern bool buildACLCommands(const char *name, const char *type,
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.368
diff -c -r1.368 pg_dump.c
*** src/bin/pg_dump/pg_dump.c    20 Mar 2004 20:09:45 -0000    1.368
--- src/bin/pg_dump/pg_dump.c    23 Mar 2004 19:31:02 -0000
***************
*** 107,112 ****
--- 107,115 ----
  static NamespaceInfo *g_namespaces;
  static int    g_numNamespaces;

+ /* flag to turn on/off dollar quoting */
+ static int     disable_dollar_quoting = 0;
+

  static void help(const char *progname);
  static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
***************
*** 233,238 ****
--- 236,242 ----
           */
          {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
          {"disable-triggers", no_argument, &disable_triggers, 1},
+         {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},

          {NULL, 0, NULL, 0}
      };
***************
*** 389,394 ****
--- 393,400 ----
                      /* no-op, still allowed for compatibility */ ;
                  else if (strcmp(optarg, "disable-triggers") == 0)
                      disable_triggers = 1;
+                 else if (strcmp(optarg,"disable-dollar-quoting") == 0)
+                     disable_dollar_quoting = true;
                  else
                  {
                      fprintf(stderr,
***************
*** 681,686 ****
--- 687,694 ----
      printf(_("  -x, --no-privileges      do not dump privileges (grant/revoke)\n"));
      printf(_("  -X disable-triggers, --disable-triggers\n"
               "                           disable triggers during data-only restore\n"));
+     printf(_("  -X disable-dollar-quoting, --disable-dollar-quoting\n"
+              "                           disable dollar quoting, use SQL standard quoting\n"));

      printf(_("\nConnection options:\n"));
      printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
***************
*** 5076,5082 ****
          if (strcmp(prosrc, "-") != 0)
          {
              appendPQExpBuffer(asPart, ", ");
!             appendStringLiteral(asPart, prosrc, false);
          }
      }
      else
--- 5084,5097 ----
          if (strcmp(prosrc, "-") != 0)
          {
              appendPQExpBuffer(asPart, ", ");
!             /*
!              * where we have bin, use dollar quoting if allowed
!              * conditionally on src
!              */
!             if (disable_dollar_quoting)
!                 appendStringLiteral(asPart, prosrc, false);
!             else
!                 appendStringLiteralDQFallback(asPart, prosrc, false, NULL);
          }
      }
      else
***************
*** 5084,5090 ****
          if (strcmp(prosrc, "-") != 0)
          {
              appendPQExpBuffer(asPart, "AS ");
!             appendStringLiteral(asPart, prosrc, false);
          }
      }

--- 5099,5109 ----
          if (strcmp(prosrc, "-") != 0)
          {
              appendPQExpBuffer(asPart, "AS ");
!             /* with no bin, dollar quote src unconditionally if allowed */
!             if (disable_dollar_quoting)
!                 appendStringLiteral(asPart, prosrc, false);
!             else
!                 appendStringLiteralDQ(asPart, prosrc, NULL);
          }
      }


pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Fix for dumoing WITH/WITHOUT oids
Next
From: "Magnus Hagander"
Date:
Subject: Small comment fix in s_lock.c