On Tue, Jan 22, 2019 at 3:35 PM David Rowley <[email protected]>
wrote:
> On Sat, 19 Jan 2019 at 01:01, Surafel Temesgen <[email protected]>
> wrote:
> > if you specified --inserts option you already specified the number of
> rows per statement which is 1 .
> > if more than one rows per statement needed it must be specified using
> --rows-per-insert
> > and specifying one row per statement using --inserts option at the same
> time specify
> > different number of rows per statement with --rows-per-insert option
> seems conflicting to me.
>
> So you're saying an INSERT, where you insert multiple rows in a single
> statement is not an insert? That logic surprises me. --inserts makes
> pg_dump use INSERTs rather than COPY. --rows-per-inserts still uses
> INSERTs. I'd love to know why you think there's some conflict with
> that.
>
> By your logic, you could say --column-inserts and --inserts should
> also conflict, but they don't. --column-inserts happens to be coded to
> imply --inserts. I really suggest we follow the lead from that. Doing
> it this way reduces the complexity of the code where we build the
> INSERT statement. Remember that a patch that is overly complex has
> much less chance of making it. I'd really suggest you keep this as
> simple as possible.
>
>
okay i understand it now .Fabien also comment about it uptread i
misunderstand it as
using separate new option.
It also seems perfectly logical to me to default --rows-per-insert to
> 1 so that when --inserts is specified we do 1 row per INSERT. If the
> user changes that value to something higher then nothing special needs
> to happen as the function building the INSERT statement will always be
> paying attention to whatever the --rows-per-insert value is set to.
> That simplifies the logic meaning you don't need to check if --inserts
> was specified.
>
>
okay .thank you for explaining. i attach a patch corrected as such
diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml
index 9e0bb93f08..4195fb81a2 100644
--- a/doc/src/sgml/ref/pg_dump.sgml
+++ b/doc/src/sgml/ref/pg_dump.sgml
@@ -775,6 +775,16 @@ PostgreSQL documentation
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--rows-per-insert</option></term>
+ <listitem>
+ <para>
+ When using <option>--rows-per-insert</option>, this allows the maximum number
+ of rows per <command>INSERT</command> statement to be specified.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--load-via-partition-root</option></term>
<listitem>
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index 4a2e122e2d..73a243ecb0 100644
--- a/src/bin/pg_dump/pg_backup.h
+++ b/src/bin/pg_dump/pg_backup.h
@@ -72,6 +72,7 @@ typedef struct _restoreOptions
int dropSchema;
int disable_dollar_quoting;
int dump_inserts;
+ int dump_inserts_multiple;
int column_inserts;
int if_exists;
int no_comments; /* Skip comments */
@@ -144,6 +145,7 @@ typedef struct _dumpOptions
/* flags for various command-line long options */
int disable_dollar_quoting;
int dump_inserts;
+ int dump_inserts_multiple;
int column_inserts;
int if_exists;
int no_comments;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 2b1a94733b..e23f5cc70f 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -313,6 +313,7 @@ main(int argc, char **argv)
int plainText = 0;
ArchiveFormat archiveFormat = archUnknown;
ArchiveMode archiveMode;
+ char *p;
static DumpOptions dopt;
@@ -359,6 +360,7 @@ main(int argc, char **argv)
{"exclude-table-data", required_argument, NULL, 4},
{"if-exists", no_argument, &dopt.if_exists, 1},
{"inserts", no_argument, &dopt.dump_inserts, 1},
+ {"rows-per-insert", required_argument, NULL, 8},
{"lock-wait-timeout", required_argument, NULL, 2},
{"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
{"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
@@ -557,6 +559,27 @@ main(int argc, char **argv)
dosync = false;
break;
+ case 8: /* inserts row number */
+ errno = 0;
+ dopt.dump_inserts_multiple = strtol(optarg, &p, 10);
+ if (p == optarg || *p != '\0')
+ {
+ write_msg(NULL, "argument of --rows-per-insert must be a number\n");
+ exit_nicely(1);
+ }
+ if (errno == ERANGE)
+ {
+ write_msg(NULL, "argument of --rows-per-insert exceeds integer range.\n");
+ exit_nicely(1);
+ }
+ if (dopt.dump_inserts_multiple <= 0)
+ {
+ write_msg(NULL, "argument of --rows-per-insert must be positive number\n");
+ exit_nicely(1);
+ }
+
+ break;
+
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit_nicely(1);
@@ -584,6 +607,9 @@ main(int argc, char **argv)
if (dopt.column_inserts)
dopt.dump_inserts = 1;
+ if (dopt.dump_inserts && !dopt.dump_inserts_multiple)
+ dopt.dump_inserts_multiple = 1;
+
/*
* Binary upgrade mode implies dumping sequence data even in schema-only
* mode. This is not exposed as a separate option, but kept separate
@@ -607,8 +633,9 @@ main(int argc, char **argv)
if (dopt.if_exists && !dopt.outputClean)
exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
- if (dopt.do_nothing && !(dopt.dump_inserts || dopt.column_inserts))
- exit_horribly(NULL, "option --on-conflict-do-nothing requires option --inserts or --column-inserts\n");
+ if (dopt.do_nothing && !(dopt.dump_inserts || dopt.column_inserts ||
+ dopt.dump_inserts_multiple))
+ exit_horribly(NULL, "option --on-conflict-do-nothing requires option --inserts , --rows-per-insert or --column-inserts\n");
/* Identify archive format to emit */
archiveFormat = parseArchiveFormat(format, &archiveMode);
@@ -877,6 +904,7 @@ main(int argc, char **argv)
ropt->use_setsessauth = dopt.use_setsessauth;
ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
ropt->dump_inserts = dopt.dump_inserts;
+ ropt->dump_inserts_multiple = dopt.dump_inserts_multiple;
ropt->no_comments = dopt.no_comments;
ropt->no_publications = dopt.no_publications;
ropt->no_security_labels = dopt.no_security_labels;
@@ -967,6 +995,7 @@ help(const char *progname)
printf(_(" --exclude-table-data=TABLE do NOT dump data for the named table(s)\n"));
printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
+ printf(_(" --rows-per-insert number of row per INSERT command\n"));
printf(_(" --load-via-partition-root load partitions via the root table\n"));
printf(_(" --no-comments do not dump comments\n"));
printf(_(" --no-publications do not dump publications\n"));
@@ -1886,6 +1915,8 @@ dumpTableData_insert(Archive *fout, void *dcontext)
int tuple;
int nfields;
int field;
+ int number_of_row = 1;
+ int end_of_statement = 0;
appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
"SELECT * FROM ONLY %s",
@@ -1900,67 +1931,86 @@ dumpTableData_insert(Archive *fout, void *dcontext)
res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
PGRES_TUPLES_OK);
nfields = PQnfields(res);
+
+ /*
+ * First time through, we build as much of the INSERT statement as
+ * possible in "insertStmt", which we can then just print for each
+ * line. If the table happens to have zero columns then this will
+ * be a complete statement, otherwise it will end in "VALUES(" and
+ * be ready to have the row's column values appended.
+ */
+ if (insertStmt == NULL)
+ {
+ TableInfo *targettab;
+
+ insertStmt = createPQExpBuffer();
+
+ /*
+ * When load-via-partition-root is set, get the root table
+ * name for the partition table, so that we can reload data
+ * through the root table.
+ */
+ if (dopt->load_via_partition_root && tbinfo->ispartition)
+ targettab = getRootTableInfo(tbinfo);
+ else
+ targettab = tbinfo;
+
+ appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
+ fmtQualifiedDumpable(targettab));
+
+ /* corner case for zero-column table */
+ if (nfields == 0)
+ {
+ appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
+ }
+ else
+ {
+ /* append the list of column names if required */
+ if (dopt->column_inserts)
+ {
+ appendPQExpBufferChar(insertStmt, '(');
+ for (field = 0; field < nfields; field++)
+ {
+ if (field > 0)
+ appendPQExpBufferStr(insertStmt, ", ");
+ appendPQExpBufferStr(insertStmt,
+ fmtId(PQfname(res, field)));
+ }
+ appendPQExpBufferStr(insertStmt, ") ");
+ }
+
+ if (tbinfo->needs_override)
+ appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
+
+ appendPQExpBufferStr(insertStmt, "VALUES ");
+ }
+ }
+
for (tuple = 0; tuple < PQntuples(res); tuple++)
{
+
/*
- * First time through, we build as much of the INSERT statement as
- * possible in "insertStmt", which we can then just print for each
- * line. If the table happens to have zero columns then this will
- * be a complete statement, otherwise it will end in "VALUES(" and
- * be ready to have the row's column values appended.
+ * If it is zero-column table then we've written all we need to.
+ * We're unable to do multi-inserts for this case due to lack of a
+ * valid syntax, so continue to use single row statements
*/
- if (insertStmt == NULL)
- {
- TableInfo *targettab;
-
- insertStmt = createPQExpBuffer();
-
- /*
- * When load-via-partition-root is set, get the root table
- * name for the partition table, so that we can reload data
- * through the root table.
- */
- if (dopt->load_via_partition_root && tbinfo->ispartition)
- targettab = getRootTableInfo(tbinfo);
- else
- targettab = tbinfo;
-
- appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
- fmtQualifiedDumpable(targettab));
-
- /* corner case for zero-column table */
- if (nfields == 0)
- {
- appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
- }
- else
- {
- /* append the list of column names if required */
- if (dopt->column_inserts)
- {
- appendPQExpBufferChar(insertStmt, '(');
- for (field = 0; field < nfields; field++)
- {
- if (field > 0)
- appendPQExpBufferStr(insertStmt, ", ");
- appendPQExpBufferStr(insertStmt,
- fmtId(PQfname(res, field)));
- }
- appendPQExpBufferStr(insertStmt, ") ");
- }
-
- if (tbinfo->needs_override)
- appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
-
- appendPQExpBufferStr(insertStmt, "VALUES (");
- }
- }
-
- archputs(insertStmt->data, fout);
-
- /* if it is zero-column table then we're done */
if (nfields == 0)
+ {
+ archputs(insertStmt->data, fout);
continue;
+ }
+
+ if (number_of_row == 1 || end_of_statement)
+ {
+ archputs(insertStmt->data, fout);
+ archputs("(", fout);
+ end_of_statement = 0;
+ }
+
+ if (number_of_row > 1)
+ {
+ archputs(", ( ", fout);
+ }
for (field = 0; field < nfields; field++)
{
@@ -2027,12 +2077,44 @@ dumpTableData_insert(Archive *fout, void *dcontext)
}
}
+ if (dopt->dump_inserts_multiple == 1)
+ {
if (!dopt->do_nothing)
archputs(");\n", fout);
else
archputs(") ON CONFLICT DO NOTHING;\n", fout);
+ }
+
+ if (dopt->dump_inserts_multiple !=1)
+ {
+ if (number_of_row == dopt->dump_inserts_multiple)
+ {
+ number_of_row = 1;
+ end_of_statement = 1;
+ if (!dopt->do_nothing)
+ archputs(");\n", fout);
+ else
+ archputs(") ON CONFLICT DO NOTHING;\n", fout);
+ }
+ else
+ {
+ archputs(")\n", fout);
+ number_of_row++;
+ }
+ }
}
+ /*
+ * If number of tuples returned is less than specified rows count
+ * we close the statment after last row.
+ */
+ if (number_of_row > 1 && PQntuples(res) == 0)
+ {
+ if (!dopt->do_nothing)
+ archputs(";\n", fout);
+ else
+ archputs(" ON CONFLICT DO NOTHING;\n", fout);
+ }
if (PQntuples(res) <= 0)
{
PQclear(res);
@@ -2091,7 +2173,7 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo)
char *copyStmt;
const char *copyFrom;
- if (!dopt->dump_inserts)
+ if (!dopt->dump_inserts && !dopt->dump_inserts_multiple)
{
/* Dump/restore using COPY */
dumpFn = dumpTableData_copy;
diff --git a/src/bin/pg_dump/t/001_basic.pl b/src/bin/pg_dump/t/001_basic.pl
index a875d540b8..ebd83922dd 100644
--- a/src/bin/pg_dump/t/001_basic.pl
+++ b/src/bin/pg_dump/t/001_basic.pl
@@ -118,8 +118,8 @@ command_fails_like(
command_fails_like(
[ 'pg_dump', '--on-conflict-do-nothing' ],
- qr/\Qpg_dump: option --on-conflict-do-nothing requires option --inserts or --column-inserts\E/,
- 'pg_dump: option --on-conflict-do-nothing requires option --inserts or --column-inserts');
+ qr/\Qpg_dump: option --on-conflict-do-nothing requires option --inserts , --rows-per-insert or --column-inserts\E/,
+ 'pg_dump: option --on-conflict-do-nothing requires option --inserts , --rows-per-insert or --column-inserts');
# pg_dumpall command-line argument checks
command_fails_like(