pg_dump et al: Add --if-exists option
This option makes pg_dump, pg_dumpall and pg_restore inject an IF EXISTS clause to each DROP command they emit. (In pg_dumpall, the clause is not added to individual objects drops, but rather to the CREATE DATABASE commands, as well as CREATE ROLE and CREATE TABLESPACE.) This allows for a better user dump experience when using --clean in case some objects do not already exist. Per bug #7873 by Dave Rolsky. Author: Pavel Stěhule Reviewed-by: Jeevan Chalke, Álvaro Herrera, Josh Kupershmidt
This commit is contained in:
parent
34c6d9611d
commit
9067310cc5
|
@ -145,7 +145,8 @@ PostgreSQL documentation
|
|||
<para>
|
||||
Output commands to clean (drop)
|
||||
database objects prior to outputting the commands for creating them.
|
||||
(Restore might generate some harmless error messages, if any objects
|
||||
(Unless <option>--if-exists</> is also specified,
|
||||
restore might generate some harmless error messages, if any objects
|
||||
were not present in the destination database.)
|
||||
</para>
|
||||
|
||||
|
@ -649,6 +650,17 @@ PostgreSQL documentation
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--if-exists</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use conditional commands (i.e. add an <literal>IF EXISTS</literal>
|
||||
clause) when cleaning database objects. This option is not valid
|
||||
unless <option>--clean</> is also specified.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--disable-dollar-quoting</></term>
|
||||
<listitem>
|
||||
|
|
|
@ -300,6 +300,17 @@ PostgreSQL documentation
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--if-exists</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use conditional commands (i.e. add an <literal>IF EXISTS</literal>
|
||||
clause) to clean databases and other objects. This option is not valid
|
||||
unless <option>--clean</> is also specified.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--inserts</option></term>
|
||||
<listitem>
|
||||
|
|
|
@ -109,7 +109,8 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Clean (drop) database objects before recreating them.
|
||||
(This might generate some harmless error messages, if any objects
|
||||
(Unless <option>--if-exists</> is used,
|
||||
this might generate some harmless error messages, if any objects
|
||||
were not present in the destination database.)
|
||||
</para>
|
||||
</listitem>
|
||||
|
@ -489,6 +490,17 @@
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--if-exists</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use conditional commands (i.e. add an <literal>IF EXISTS</literal>
|
||||
clause) when cleaning database objects. This option is not valid
|
||||
unless <option>--clean</> is also specified.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--no-data-for-failed-tables</option></term>
|
||||
<listitem>
|
||||
|
|
|
@ -113,6 +113,7 @@ typedef struct _restoreOptions
|
|||
char *superuser; /* Username to use as superuser */
|
||||
char *use_role; /* Issue SET ROLE to this */
|
||||
int dropSchema;
|
||||
int if_exists;
|
||||
const char *filename;
|
||||
int dataOnly;
|
||||
int schemaOnly;
|
||||
|
|
|
@ -413,8 +413,77 @@ RestoreArchive(Archive *AHX)
|
|||
/* Select owner and schema as necessary */
|
||||
_becomeOwner(AH, te);
|
||||
_selectOutputSchema(AH, te->namespace);
|
||||
/* Drop it */
|
||||
ahprintf(AH, "%s", te->dropStmt);
|
||||
|
||||
/*
|
||||
* Now emit the DROP command, if the object has one. Note we
|
||||
* don't necessarily emit it verbatim; at this point we add an
|
||||
* appropriate IF EXISTS clause, if the user requested it.
|
||||
*/
|
||||
if (*te->dropStmt != '\0')
|
||||
{
|
||||
if (!ropt->if_exists)
|
||||
{
|
||||
/* No --if-exists? Then just use the original */
|
||||
ahprintf(AH, "%s", te->dropStmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
char buffer[40];
|
||||
char *mark;
|
||||
char *dropStmt = pg_strdup(te->dropStmt);
|
||||
char *dropStmtPtr = dropStmt;
|
||||
PQExpBuffer ftStmt = createPQExpBuffer();
|
||||
|
||||
/*
|
||||
* Need to inject IF EXISTS clause after ALTER TABLE
|
||||
* part in ALTER TABLE .. DROP statement
|
||||
*/
|
||||
if (strncmp(dropStmt, "ALTER TABLE", 11) == 0)
|
||||
{
|
||||
appendPQExpBuffer(ftStmt,
|
||||
"ALTER TABLE IF EXISTS");
|
||||
dropStmt = dropStmt + 11;
|
||||
}
|
||||
|
||||
/*
|
||||
* ALTER TABLE..ALTER COLUMN..DROP DEFAULT does not
|
||||
* support the IF EXISTS clause, and therefore we
|
||||
* simply emit the original command for such objects.
|
||||
* For other objects, we need to extract the first part
|
||||
* of the DROP which includes the object type. Most of
|
||||
* the time this matches te->desc, so search for that;
|
||||
* however for the different kinds of CONSTRAINTs, we
|
||||
* know to search for hardcoded "DROP CONSTRAINT"
|
||||
* instead.
|
||||
*/
|
||||
if (strcmp(te->desc, "DEFAULT") == 0)
|
||||
appendPQExpBuffer(ftStmt, "%s", dropStmt);
|
||||
else
|
||||
{
|
||||
if (strcmp(te->desc, "CONSTRAINT") == 0 ||
|
||||
strcmp(te->desc, "CHECK CONSTRAINT") == 0 ||
|
||||
strcmp(te->desc, "FK CONSTRAINT") == 0)
|
||||
strcpy(buffer, "DROP CONSTRAINT");
|
||||
else
|
||||
snprintf(buffer, sizeof(buffer), "DROP %s",
|
||||
te->desc);
|
||||
|
||||
mark = strstr(dropStmt, buffer);
|
||||
Assert(mark != NULL);
|
||||
|
||||
*mark = '\0';
|
||||
appendPQExpBuffer(ftStmt, "%s%s IF EXISTS%s",
|
||||
dropStmt, buffer,
|
||||
mark + strlen(buffer));
|
||||
}
|
||||
|
||||
ahprintf(AH, "%s", ftStmt->data);
|
||||
|
||||
destroyPQExpBuffer(ftStmt);
|
||||
|
||||
pg_free(dropStmtPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,6 +132,7 @@ static int binary_upgrade = 0;
|
|||
static int disable_dollar_quoting = 0;
|
||||
static int dump_inserts = 0;
|
||||
static int column_inserts = 0;
|
||||
static int if_exists = 0;
|
||||
static int no_security_labels = 0;
|
||||
static int no_synchronized_snapshots = 0;
|
||||
static int no_unlogged_table_data = 0;
|
||||
|
@ -345,6 +346,7 @@ main(int argc, char **argv)
|
|||
{"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
|
||||
{"disable-triggers", no_argument, &disable_triggers, 1},
|
||||
{"exclude-table-data", required_argument, NULL, 4},
|
||||
{"if-exists", no_argument, &if_exists, 1},
|
||||
{"inserts", no_argument, &dump_inserts, 1},
|
||||
{"lock-wait-timeout", required_argument, NULL, 2},
|
||||
{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
|
||||
|
@ -573,6 +575,9 @@ main(int argc, char **argv)
|
|||
exit_nicely(1);
|
||||
}
|
||||
|
||||
if (if_exists && !outputClean)
|
||||
exit_horribly(NULL, "option --if-exists requires -c/--clean option\n");
|
||||
|
||||
/* Identify archive format to emit */
|
||||
archiveFormat = parseArchiveFormat(format, &archiveMode);
|
||||
|
||||
|
@ -805,6 +810,7 @@ main(int argc, char **argv)
|
|||
ropt->dropSchema = outputClean;
|
||||
ropt->dataOnly = dataOnly;
|
||||
ropt->schemaOnly = schemaOnly;
|
||||
ropt->if_exists = if_exists;
|
||||
ropt->dumpSections = dumpSections;
|
||||
ropt->aclsSkip = aclsSkip;
|
||||
ropt->superuser = outputSuperuser;
|
||||
|
@ -886,6 +892,7 @@ help(const char *progname)
|
|||
printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
|
||||
printf(_(" --disable-triggers disable triggers during data-only restore\n"));
|
||||
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(_(" --no-security-labels do not dump security label assignments\n"));
|
||||
printf(_(" --no-synchronized-snapshots do not use synchronized snapshots in parallel jobs\n"));
|
||||
|
|
|
@ -73,6 +73,7 @@ static int binary_upgrade = 0;
|
|||
static int column_inserts = 0;
|
||||
static int disable_dollar_quoting = 0;
|
||||
static int disable_triggers = 0;
|
||||
static int if_exists = 0;
|
||||
static int inserts = 0;
|
||||
static int no_tablespaces = 0;
|
||||
static int use_setsessauth = 0;
|
||||
|
@ -119,6 +120,7 @@ main(int argc, char *argv[])
|
|||
{"column-inserts", no_argument, &column_inserts, 1},
|
||||
{"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
|
||||
{"disable-triggers", no_argument, &disable_triggers, 1},
|
||||
{"if-exists", no_argument, &if_exists, 1},
|
||||
{"inserts", no_argument, &inserts, 1},
|
||||
{"lock-wait-timeout", required_argument, NULL, 2},
|
||||
{"no-tablespaces", no_argument, &no_tablespaces, 1},
|
||||
|
@ -334,6 +336,13 @@ main(int argc, char *argv[])
|
|||
exit_nicely(1);
|
||||
}
|
||||
|
||||
if (if_exists && !output_clean)
|
||||
{
|
||||
fprintf(stderr, _("%s: option --if-exists requires -c/--clean option\n"),
|
||||
progname);
|
||||
exit_nicely(1);
|
||||
}
|
||||
|
||||
if (roles_only && tablespaces_only)
|
||||
{
|
||||
fprintf(stderr, _("%s: options -r/--roles-only and -t/--tablespaces-only cannot be used together\n"),
|
||||
|
@ -564,6 +573,7 @@ help(void)
|
|||
printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
|
||||
printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
|
||||
printf(_(" --disable-triggers disable triggers during data-only restore\n"));
|
||||
printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
|
||||
printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
|
||||
printf(_(" --no-security-labels do not dump security label assignments\n"));
|
||||
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
|
||||
|
@ -624,7 +634,9 @@ dropRoles(PGconn *conn)
|
|||
|
||||
rolename = PQgetvalue(res, i, i_rolname);
|
||||
|
||||
fprintf(OPF, "DROP ROLE %s;\n", fmtId(rolename));
|
||||
fprintf(OPF, "DROP ROLE %s%s;\n",
|
||||
if_exists ? "IF EXISTS " : "",
|
||||
fmtId(rolename));
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
|
@ -994,7 +1006,9 @@ dropTablespaces(PGconn *conn)
|
|||
{
|
||||
char *spcname = PQgetvalue(res, i, 0);
|
||||
|
||||
fprintf(OPF, "DROP TABLESPACE %s;\n", fmtId(spcname));
|
||||
fprintf(OPF, "DROP TABLESPACE %s%s;\n",
|
||||
if_exists ? "IF EXISTS " : "",
|
||||
fmtId(spcname));
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
|
@ -1148,7 +1162,9 @@ dropDBs(PGconn *conn)
|
|||
if (strcmp(dbname, "template1") != 0 &&
|
||||
strcmp(dbname, "postgres") != 0)
|
||||
{
|
||||
fprintf(OPF, "DROP DATABASE %s;\n", fmtId(dbname));
|
||||
fprintf(OPF, "DROP DATABASE %s%s;\n",
|
||||
if_exists ? "IF EXISTS " : "",
|
||||
fmtId(dbname));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ main(int argc, char **argv)
|
|||
Archive *AH;
|
||||
char *inputFileSpec;
|
||||
static int disable_triggers = 0;
|
||||
static int if_exists = 0;
|
||||
static int no_data_for_failed_tables = 0;
|
||||
static int outputNoTablespaces = 0;
|
||||
static int use_setsessauth = 0;
|
||||
|
@ -110,6 +111,7 @@ main(int argc, char **argv)
|
|||
* the following options don't have an equivalent short option letter
|
||||
*/
|
||||
{"disable-triggers", no_argument, &disable_triggers, 1},
|
||||
{"if-exists", no_argument, &if_exists, 1},
|
||||
{"no-data-for-failed-tables", no_argument, &no_data_for_failed_tables, 1},
|
||||
{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
|
||||
{"role", required_argument, NULL, 2},
|
||||
|
@ -336,6 +338,14 @@ main(int argc, char **argv)
|
|||
opts->use_setsessauth = use_setsessauth;
|
||||
opts->no_security_labels = no_security_labels;
|
||||
|
||||
if (if_exists && !opts->dropSchema)
|
||||
{
|
||||
fprintf(stderr, _("%s: option --if-exists requires -c/--clean option\n"),
|
||||
progname);
|
||||
exit_nicely(1);
|
||||
}
|
||||
opts->if_exists = if_exists;
|
||||
|
||||
if (opts->formatName)
|
||||
{
|
||||
switch (opts->formatName[0])
|
||||
|
@ -450,6 +460,7 @@ usage(const char *progname)
|
|||
printf(_(" -x, --no-privileges skip restoration of access privileges (grant/revoke)\n"));
|
||||
printf(_(" -1, --single-transaction restore as a single transaction\n"));
|
||||
printf(_(" --disable-triggers disable triggers during data-only restore\n"));
|
||||
printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
|
||||
printf(_(" --no-data-for-failed-tables do not restore data of tables that could not be\n"
|
||||
" created\n"));
|
||||
printf(_(" --no-security-labels do not restore security labels\n"));
|
||||
|
|
Loading…
Reference in New Issue