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 6 Mar 2006 07:32:05 -0000 *************** *** 163,168 **** --- 163,208 ---- + + + + Use delimiter + instead of the default tab character in COPY statements. + + + + + + + + + Use string_for_nulls instead of the + default \N in COPY statements. + + + + + + + + + Use delimiter + instead of the default tab character in COPY statements. + + + + + + + + + Use string_for_nulls instead of the + default \N in COPY statements. + + + + + Index: src/bin/pg_dump/pg_dump.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v retrieving revision 1.433 diff -c -r1.433 pg_dump.c *** src/bin/pg_dump/pg_dump.c 5 Mar 2006 15:58:50 -0000 1.433 --- src/bin/pg_dump/pg_dump.c 6 Mar 2006 07:32:12 -0000 *************** *** 114,119 **** --- 114,125 ---- /* flag to turn on/off dollar quoting */ static int disable_dollar_quoting = 0; + /* Things used when caller invokes COPY options. */ + #define ARG_COPY_DELIMITER 2 + #define ARG_COPY_NULL 3 + char *copy_delimiter = "\t"; + char *copy_null; + static void help(const char *progname); static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid); *************** *** 181,186 **** --- 187,193 ---- ExecStatusType expected); + int main(int argc, char **argv) { *************** *** 211,217 **** char *outputSuperuser = NULL; RestoreOptions *ropt; ! static struct option long_options[] = { {"data-only", no_argument, NULL, 'a'}, {"blobs", no_argument, NULL, 'b'}, --- 218,224 ---- char *outputSuperuser = NULL; RestoreOptions *ropt; ! static struct option long_options[] = { {"data-only", no_argument, NULL, 'a'}, {"blobs", no_argument, NULL, 'b'}, *************** *** 249,254 **** --- 256,269 ---- {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1}, {"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. Just use + * the long form. + */ + {"copy-delimiter", required_argument, NULL, ARG_COPY_DELIMITER}, + {"copy-null", required_argument, NULL, ARG_COPY_NULL}, {NULL, 0, NULL, 0} }; *************** *** 418,423 **** --- 433,460 ---- break; /* This covers the long options equivalent to -X xxx. */ + case ARG_COPY_DELIMITER: + if ( strlen(optarg) != 1) + { + fprintf(stderr, _("In %s, copy-delimiter must be exactly one byte long, not %d.\n"), + progname, strlen(optarg)); + exit(1); + } + if (*optarg == '\r' || *optarg == '\n' || + *optarg == '\\') + { + fprintf(stderr, _("In %s, copy-delimiter may not be any of \\r, \\n or \\.\n"), + progname); + exit(1); + } + copy_delimiter = optarg; + break; + + case ARG_COPY_NULL: + copy_null = malloc(2*strlen(optarg)+1); + PQescapeString(copy_null, optarg, 2*strlen(optarg)+1); + break; + case 0: break; *************** *** 427,432 **** --- 464,479 ---- } } + if (copy_null == NULL) + copy_null = malloc(3); + strcpy(copy_null, "\\N"); + + if (strstr(copy_null, copy_delimiter)) + { + fprintf(stderr, _("In %s, the NULL AS string cannot contain the COPY delimiter.\n"), progname); + exit(1); + } + if (optind < (argc - 1)) { fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), *************** *** 702,707 **** --- 749,756 ---- " use SESSION AUTHORIZATION commands instead of\n" " OWNER TO commands\n")); + printf(_(" --copy-delimiter string to use as column DELIMITER in COPY statements\n")); + printf(_(" --copy-null string to use for NULLs in COPY statements\n")); printf(_("\nConnection options:\n")); printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); printf(_(" -p, --port=PORT database server port number\n")); *************** *** 844,849 **** --- 893,904 ---- int ret; char *copybuf; const char *column_list; + char *local_copy_delimiter; + char *local_copy_null; + local_copy_delimiter = malloc(2*strlen(copy_delimiter)+1); + PQescapeString (local_copy_delimiter, copy_delimiter, 2*strlen(copy_delimiter)+1); + local_copy_null = malloc(2*strlen(copy_null)+1); + PQescapeString (local_copy_null, copy_null, 2*strlen(copy_null)+1); if (g_verbose) write_msg(NULL, "dumping contents of table %s\n", classname); *************** *** 867,886 **** 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); PQclear(res); --- 922,938 ---- else column_list = ""; /* can't select columns in COPY */ ! /* ! * Explicitly set the DELIMITER and NULL strings in the COPY ! * statement. ! */ ! appendPQExpBuffer(q, "COPY %s %s TO stdout %sDELIMITER AS '%s' NULL AS '%s';", ! fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, ! classname), ! column_list, ! (oids && hasoids) ? "WITH OIDS " : "", ! local_copy_delimiter, ! local_copy_null); res = PQexec(g_conn, q->data); check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT); PQclear(res); *************** *** 1117,1122 **** --- 1169,1180 ---- PQExpBuffer copyBuf = createPQExpBuffer(); DataDumperPtr dumpFn; char *copyStmt; + char *local_copy_delimiter; + char *local_copy_null; + local_copy_delimiter = malloc(2*strlen(copy_delimiter)+1); + PQescapeString (local_copy_delimiter, copy_delimiter, 2*strlen(copy_delimiter)+1); + local_copy_null = malloc(2*strlen(copy_null)+1); + PQescapeString (local_copy_null, copy_null, 2*strlen(copy_null)+1); if (!dumpInserts) { *************** *** 1125,1133 **** /* 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 --- 1183,1193 ---- /* must use 2 steps here 'cause fmtId is nonreentrant */ appendPQExpBuffer(copyBuf, "COPY %s ", fmtId(tbinfo->dobj.name)); ! appendPQExpBuffer(copyBuf, "%s FROM stdin %sDELIMITER AS '%s' NULL AS '%s';\n", ! fmtCopyColumnList(tbinfo), ! (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "", ! local_copy_delimiter, ! local_copy_null); copyStmt = copyBuf->data; } else