Greetings, I have developed a fairly simple patch to the pg_dump utility. It is against version 8.3.1 source code.
I have added a new parameter, -w/--where=EXPR This lets you specify an expression that will be used in a WHERE clause when the data is dumped. I have implemented and tested that it works when generating either COPY statements (the default), or INSERT statements (-d and -D). These two modes of operation have two different sections of code that select the data to be dumped. Though this change could arguably be removed, when a -w/--where expression is specified, it is also indicated in the comments of the dump output so one viewing the dump can see that it was not necessarily all of the data. When -w/--where is not specified, the dump output is just as if this patch had not been applied. I've also updated the pg_dump.sgml file to add a description of this new flag. The code changes should also conform to the existing code style within pg_dump. The patch should be applied from the root of the source tree with a -p1 option to the patch command. Please give any feedback if the patch needs improvement Thanks for a great DB!
diff -cr postgresql-8.3.1.orig/doc/src/sgml/ref/pg_dump.sgml postgresql-8.3.1/doc/src/sgml/ref/pg_dump.sgml *** postgresql-8.3.1.orig/doc/src/sgml/ref/pg_dump.sgml 2008-05-31 17:48:38.000000000 -0500 --- postgresql-8.3.1/doc/src/sgml/ref/pg_dump.sgml 2008-06-01 00:23:32.000000000 -0500 *************** *** 535,540 **** --- 535,562 ---- </varlistentry> <varlistentry> + <term><option>-w <replaceable class="parameter">expression</replaceable></option></term> + <term><option>--where=<replaceable class="parameter">expression</replaceable></option></term> + <listitem> + <para> + Dump only table data for which the given <command>WHERE</command> + clause expression is true. The given expression is used for all + tables that will be dumped. Therefore, an error will occur if the + expression refers to columns that do not exist in the table being + dumped. + </para> + + <note> + <para> + When giving the expression at the shell prompt, it must be correctly + quoted and escaped since otherwise it may be received as multiple + arguments to <application>pg_dump</application>. + </para> + </note> + </listitem> + </varlistentry> + + <varlistentry> <term><option>-x</></term> <term><option>--no-privileges</></term> <term><option>--no-acl</></term> diff -cr postgresql-8.3.1.orig/src/bin/pg_dump/pg_dump.c postgresql-8.3.1/src/bin/pg_dump/pg_dump.c *** postgresql-8.3.1.orig/src/bin/pg_dump/pg_dump.c 2008-05-31 17:48:25.000000000 -0500 --- postgresql-8.3.1/src/bin/pg_dump/pg_dump.c 2008-06-01 00:33:30.000000000 -0500 *************** *** 76,81 **** --- 76,82 ---- bool attrNames; /* put attr names into insert strings */ bool schemaOnly; bool dataOnly; + char *whereClauseExpr; bool aclsSkip; /* subquery used to convert user ID (eg, datdba) to user name */ *************** *** 191,197 **** static void dumpEncoding(Archive *AH); static void dumpStdStrings(Archive *AH); static const char *getAttrName(int attrnum, TableInfo *tblInfo); ! static const char *fmtCopyColumnList(const TableInfo *ti); static void do_sql_command(PGconn *conn, const char *query); static void check_sql_result(PGresult *res, PGconn *conn, const char *query, ExecStatusType expected); --- 192,198 ---- static void dumpEncoding(Archive *AH); static void dumpStdStrings(Archive *AH); static const char *getAttrName(int attrnum, TableInfo *tblInfo); ! static const char *fmtCopyColumnList(const TableInfo *ti, bool addParens); static void do_sql_command(PGconn *conn, const char *query); static void check_sql_result(PGresult *res, PGconn *conn, const char *query, ExecStatusType expected); *************** *** 231,236 **** --- 232,238 ---- static struct option long_options[] = { {"data-only", no_argument, NULL, 'a'}, + {"where", no_argument, NULL, 'w'}, {"blobs", no_argument, NULL, 'b'}, {"clean", no_argument, NULL, 'c'}, {"create", no_argument, NULL, 'C'}, *************** *** 281,286 **** --- 283,289 ---- strcpy(g_opaque_type, "opaque"); dataOnly = schemaOnly = dumpInserts = attrNames = false; + whereClauseExpr = NULL; progname = get_progname(argv[0]); *************** *** 302,308 **** } } ! while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:N:oOp:RsS:t:T:U:vWxX:Z:", long_options, &optindex)) != -1) { switch (c) --- 305,311 ---- } } ! while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:N:oOp:RsS:t:T:U:vw:WxX:Z:", long_options, &optindex)) != -1) { switch (c) *************** *** 403,408 **** --- 406,415 ---- g_verbose = true; break; + case 'w': /* where clause expression */ + whereClauseExpr = strdup(optarg); + break; + case 'W': force_password = true; break; *************** *** 462,467 **** --- 469,480 ---- exit(1); } + if (whereClauseExpr && schemaOnly) + { + write_msg(NULL, "options -w/--where and -s/--schema-only cannot be used together\n"); + exit(1); + } + if (dataOnly && outputClean) { write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n"); *************** *** 765,770 **** --- 778,786 ---- " plain text format\n")); printf(_(" -t, --table=TABLE dump the named table(s) only\n")); printf(_(" -T, --exclude-table=TABLE do NOT dump the named table(s)\n")); + printf(_(" -w, --where=EXPR specify a WHERE clause expression when dumping any\n" + " table data. NOTE: Be sure to quote the entire \n" + " expression from the shell.\n")); printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n")); printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n")); printf(_(" --disable-triggers disable triggers during data-only restore\n")); *************** *** 1016,1022 **** PGresult *res; int ret; char *copybuf; - const char *column_list; if (g_verbose) write_msg(NULL, "dumping contents of table %s\n", classname); --- 1032,1037 ---- *************** *** 1029,1059 **** */ selectSourceSchema(tbinfo->dobj.namespace->dobj.name); ! /* ! * If possible, specify the column list explicitly so that we have no ! * possibility of retrieving data in the wrong column order. (The default ! * column ordering of COPY will not be what we want in certain corner ! * cases involving ADD COLUMN and inheritance.) ! */ ! if (g_fout->remoteVersion >= 70300) ! 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); PQclear(res); --- 1044,1087 ---- */ selectSourceSchema(tbinfo->dobj.namespace->dobj.name); ! appendPQExpBuffer(q, "COPY"); ! if (whereClauseExpr) { ! appendPQExpBuffer(q, " (SELECT %s FROM %s WHERE %s)", ! fmtCopyColumnList(tbinfo, false), fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, classname), ! whereClauseExpr); } else { ! const char *column_list; ! /* ! * If possible, specify the column list explicitly so that we have no ! * possibility of retrieving data in the wrong column order. (The default ! * column ordering of COPY will not be what we want in certain corner ! * cases involving ADD COLUMN and inheritance.) ! */ ! if (g_fout->remoteVersion >= 70300) ! column_list = fmtCopyColumnList(tbinfo, true); ! else ! column_list = ""; /* can't select columns in COPY */ ! ! appendPQExpBuffer(q, " %s %s", fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, classname), column_list); } + + if (oids && hasoids) + { + appendPQExpBuffer(q, " WITH OIDS TO stdout;"); + } + else + { + appendPQExpBuffer(q, " TO stdout;"); + } res = PQexec(g_conn, q->data); check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT); PQclear(res); *************** *** 1172,1177 **** --- 1200,1210 ---- classname)); } + if (whereClauseExpr) + { + appendPQExpBuffer(q, " WHERE %s", whereClauseExpr); + } + res = PQexec(g_conn, q->data); check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK); *************** *** 1298,1303 **** --- 1331,1337 ---- PQExpBuffer copyBuf = createPQExpBuffer(); DataDumperPtr dumpFn; char *copyStmt; + char *desc; if (!dumpInserts) { *************** *** 1307,1313 **** 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; } --- 1341,1347 ---- appendPQExpBuffer(copyBuf, "COPY %s ", fmtId(tbinfo->dobj.name)); appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n", ! fmtCopyColumnList(tbinfo, true), (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : ""); copyStmt = copyBuf->data; } *************** *** 1318,1332 **** copyStmt = NULL; } ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId, tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name, NULL, tbinfo->rolname, false, ! "TABLE DATA", "", "", copyStmt, tdinfo->dobj.dependencies, tdinfo->dobj.nDeps, dumpFn, tdinfo); destroyPQExpBuffer(copyBuf); } --- 1352,1387 ---- copyStmt = NULL; } + if (whereClauseExpr) + { + int l; + desc = malloc(64 + strlen(whereClauseExpr)); + sprintf(desc, "TABLE DATA (WHERE %s)", whereClauseExpr); + + /* don't allow \n or \r in what will be part of a comment in the output */ + l = strlen(desc); + for(l=l-1; l>=0; l--) + { + if (desc[l] == '\n' || desc[l] == '\r') + desc[l] = ' '; + } + } + else + { + desc = strdup("TABLE DATA"); + } + ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId, tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name, NULL, tbinfo->rolname, false, ! desc, "", "", copyStmt, tdinfo->dobj.dependencies, tdinfo->dobj.nDeps, dumpFn, tdinfo); + free(desc); + destroyPQExpBuffer(copyBuf); } *************** *** 10227,10233 **** * "", not an invalid "()" column list. */ static const char * ! fmtCopyColumnList(const TableInfo *ti) { static PQExpBuffer q = NULL; int numatts = ti->numatts; --- 10282,10288 ---- * "", not an invalid "()" column list. */ static const char * ! fmtCopyColumnList(const TableInfo *ti, bool addParens) { static PQExpBuffer q = NULL; int numatts = ti->numatts; *************** *** 10241,10247 **** else q = createPQExpBuffer(); ! appendPQExpBuffer(q, "("); needComma = false; for (i = 0; i < numatts; i++) { --- 10296,10303 ---- else q = createPQExpBuffer(); ! if (addParens) ! appendPQExpBuffer(q, "("); needComma = false; for (i = 0; i < numatts; i++) { *************** *** 10256,10262 **** if (!needComma) return ""; /* no undropped columns */ ! appendPQExpBuffer(q, ")"); return q->data; } --- 10312,10319 ---- if (!needComma) return ""; /* no undropped columns */ ! if (addParens) ! appendPQExpBuffer(q, ")"); return q->data; }
-- Sent via pgsql-patches mailing list (pgsql-patches@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-patches