On Thu, Jan 26, 2006 at 10:17:05PM -0500, Tom Lane wrote:
> David Fetter <[EMAIL PROTECTED]> writes:
> > I have seed database scripts quasi-generated from pg_dump which
> > include COPY statements, but the data is hard to edit (especially
> > cut & paste operations) when the COPY delimiter is some
> > non-visible character like \t.
> 
> This seems like an awfully weak use-case for adding to pg_dump's
> already overly complicated feature set.

Those who don't use it will never see it.

> The difficulty of parsing COPY output is not simplified by making
> the delimiter variable --- more likely the reverse.

It's fairly straight-forward.

> Furthermore, it's quite unclear why you'd use pg_dump at all to
> generate a data file that you intend to feed to some other program.

In my case, it's about being copy/paste friendly.

> Seems to me that "psql -c 'COPY ...'" is a more likely front-end for
> such a process.

Actually, it's not.  I'm attaching my preliminary patch, as I see I
haven't explained it well enough.

Cheers,
D
-- 
David Fetter [EMAIL PROTECTED] http://fetter.org/
phone: +1 415 235 3778

Remember to vote!
? pg_dump_copy.diff
Index: doc/src/sgml/ref/pg_dump.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/pg_dump.sgml,v
retrieving revision 1.81
diff -c -r1.81 pg_dump.sgml
*** doc/src/sgml/ref/pg_dump.sgml       1 Nov 2005 21:09:50 -0000       1.81
--- doc/src/sgml/ref/pg_dump.sgml       27 Jan 2006 02:22:41 -0000
***************
*** 163,168 ****
--- 163,188 ----
       </varlistentry>
  
       <varlistentry>
+       <term><option>--copy-delimiter=<replaceable 
class="parameter">delimiter</replaceable></option></term>
+       <listitem>
+        <para>
+         Use <replaceable class="parameter">delimiter</replaceable>
+         instead of the default tab character in <command>COPY</command> 
statements. 
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term><option>--copy-null=<replaceable 
class="parameter">string_for_nulls</replaceable></option></term>
+       <listitem>
+        <para>
+         Use  <replaceable class="parameter">string_for_nulls</replaceable> 
instead of the
+         default \N in <command>COPY</command> statements.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
        <term><option>-d</option></term>
        <term><option>--inserts</option></term>
        <listitem>
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.427
diff -c -r1.427 pg_dump.c
*** src/bin/pg_dump/pg_dump.c   21 Jan 2006 02:16:20 -0000      1.427
--- src/bin/pg_dump/pg_dump.c   27 Jan 2006 02:22:48 -0000
***************
*** 111,116 ****
--- 111,121 ----
  /* flag to turn on/off dollar quoting */
  static int    disable_dollar_quoting = 0;
  
+ /* Things used when caller invokes COPY options. */
+ const char *copy_delimiter_default = "\t";
+ const char *copy_delimiter = "\t";
+ const char *copy_null_default = "\\N";
+ const char *copy_null = "\\N";
  
  static void help(const char *progname);
  static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
***************
*** 246,251 ****
--- 251,265 ----
                {"disable-triggers", no_argument, &disable_triggers, 1},
                {"use-set-session-authorization", no_argument, 
&use_setsessauth, 1},
  
+               /*
+                * The following options don't have an equivalent short option
+                * letter, and are not available as -X long-name.  Use the
+                * long form instead.
+                */
+ 
+               {"copy-delimiter", required_argument, NULL, 2},
+               {"copy-null", required_argument, NULL, 3},
+ 
                {NULL, 0, NULL, 0}
        };
        int                     optindex;
***************
*** 414,419 ****
--- 428,453 ----
                                break;
                                /* This covers the long options equivalent to 
-X xxx. */
  
+                       case 2:
+                               copy_delimiter = strdup(optarg);
+                               if (strlen(copy_delimiter) != 1)
+                               {
+                                       fprintf(stderr, _("In %s, 
copy-delimiter must be exactly one byte long, not %d\n"),
+                                                               progname, 
strlen(copy_delimiter));
+                                       exit(1);
+                               }
+                               if ( (*copy_delimiter == '\r') || 
(*copy_delimiter == '\n') )
+                               {
+                                       fprintf(stderr, _("In %s, 
copy-delimiter may not be \\r or \\n.\n"),
+                                                               progname);
+                                       exit(1);
+                               }
+                               break;
+ 
+                       case 3:
+                               copy_null = strdup(optarg);
+                               break;
+ 
                        case 0:
                                break;
  
***************
*** 816,836 ****
                column_list = fmtCopyColumnList(tbinfo);
        else
                column_list = "";               /* can't select columns in COPY 
*/
  
-       if (oids && hasoids)
-       {
-               appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
-                                                 
fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
-                                                                               
 classname),
-                                                 column_list);
-       }
-       else
-       {
-               appendPQExpBuffer(q, "COPY %s %s TO stdout;",
-                                                 
fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
-                                                                               
 classname),
-                                                 column_list);
-       }
        res = PQexec(g_conn, q->data);
        check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
  
--- 850,869 ----
                column_list = fmtCopyColumnList(tbinfo);
        else
                column_list = "";               /* can't select columns in COPY 
*/
+       appendPQExpBuffer(q, "COPY %s %s %sTO stdout",
+                                        
fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, classname),
+                                        column_list,
+                                        /* dump OIDs if requested */
+                                        (oids && hasoids) ?  "WITH OIDS " : ""
+       );
+       /* Add a DELIMITER if copy_delimiter is not the default */
+       if (strcmp(copy_delimiter, copy_delimiter_default) != 0)
+               appendPQExpBuffer(q, " DELIMITER AS '%s'", copy_delimiter);
+       /* Add a NULL AS stanza if copy_null is not the default */
+       if (strcmp(copy_null,copy_null_default) != 0)
+               appendPQExpBuffer(q, " NULL AS '%s'", copy_null);
+       appendPQExpBuffer(q, ";");
  
        res = PQexec(g_conn, q->data);
        check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
  
***************
*** 1085,1093 ****
                /* must use 2 steps here 'cause fmtId is nonreentrant */
                appendPQExpBuffer(copyBuf, "COPY %s ",
                                                  fmtId(tbinfo->dobj.name));
!               appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
!                                                 fmtCopyColumnList(tbinfo),
!                                         (tdinfo->oids && tbinfo->hasoids) ? 
"WITH OIDS " : "");
                copyStmt = copyBuf->data;
        }
        else
--- 1118,1135 ----
                /* must use 2 steps here 'cause fmtId is nonreentrant */
                appendPQExpBuffer(copyBuf, "COPY %s ",
                                                  fmtId(tbinfo->dobj.name));
!               appendPQExpBuffer(copyBuf, "%s %sFROM stdin",
!                                               fmtCopyColumnList(tbinfo),
!                                               (tdinfo->oids && 
tbinfo->hasoids) ? "WITH OIDS " : ""
!               );
!               /* Add DELIMITER AS stanza if not the default */
!               if (strcmp(copy_delimiter, copy_delimiter_default) != 0)
!                       appendPQExpBuffer(copyBuf, " DELIMITER AS '%s'", 
copy_delimiter);
!               /* Add NULL AS stanza if not the default */
!               if (strcmp(copy_null, copy_null_default) != 0)
!                       appendPQExpBuffer(copyBuf, " NULL AS '%s'", copy_null);
!               appendPQExpBuffer(copyBuf, ";\n");
! 
                copyStmt = copyBuf->data;
        }
        else
---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings

Reply via email to