Commit 9f0ae0c8 authored by Tom Lane's avatar Tom Lane

First pass at schema-fying pg_dump/pg_restore. Much to do still,

but the basic capability seems to work.
parent 1011fb65
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/pg_dump.sgml,v 1.44 2002/04/21 19:02:39 thomas Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/pg_dump.sgml,v 1.45 2002/05/10 22:36:26 tgl Exp $
PostgreSQL documentation
-->
......@@ -407,10 +407,11 @@ PostgreSQL documentation
<term><option>--superuser=<replaceable class="parameter">username</replaceable></option></term>
<listitem>
<para>
The scripts or archives created by <command>pg_dump</command>
need to have superuser access in certain cases, such as when
disabling triggers or setting ownership of schema elements.
This option specifies the user name to use for those cases.
Specify the superuser user name to use when disabling triggers.
This is only relevant if <option>--disable-triggers</> is used.
(Usually, it's better to specify
<option>--use-set-session-authorization</>, and then start the
resulting script as superuser.)
</para>
</listitem>
</varlistentry>
......@@ -481,6 +482,36 @@ PostgreSQL documentation
</listitem>
</varlistentry>
<varlistentry>
<term><option>-X disable-triggers</></term>
<term><option>--disable-triggers</></term>
<listitem>
<para>
This option is only relevant when creating a data-only dump.
It instructs <command>pg_dump</command> to include commands
to temporarily disable triggers on the target tables while
the data is reloaded. Use this if you have referential
integrity checks or other triggers on the tables that you
do not want to invoke during data reload.
</para>
<para>
Presently, the commands emitted for <option>--disable-triggers</>
must be done as superuser. So, you should also specify
a superuser name with <option>-S</>, or preferably specify
<option>--use-set-session-authorization</> and then be careful to
start the resulting script as a superuser. If you give neither
option, the entire script must be run as superuser.
</para>
<para>
This option is only meaningful for the plain-text format. For
the other formats, you may specify the option when you
call <command>pg_restore</command>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-Z <replaceable class="parameter">0..9</replaceable></option></term>
<term><option>--compress=<replaceable class="parameter">0..9</replaceable></option></term>
......
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/pg_restore.sgml,v 1.24 2002/04/21 19:02:39 thomas Exp $ -->
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/pg_restore.sgml,v 1.25 2002/05/10 22:36:26 tgl Exp $ -->
<refentry id="APP-PGRESTORE">
<docinfo>
......@@ -336,8 +336,8 @@
<term><option>--superuser=<replaceable class="parameter">username</replaceable></option></term>
<listitem>
<para>
Specify the superuser user name to use when disabling triggers and/or setting ownership of schema elements.
By default, <COMMAND>pg_restore</COMMAND> will use the current user name if it is a superuser.
Specify the superuser user name to use when disabling triggers.
This is only relevant if <option>--disable-triggers</> is used.
</para>
</listitem>
</varlistentry>
......@@ -402,6 +402,29 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>-X disable-triggers</></term>
<term><option>--disable-triggers</></term>
<listitem>
<para>
This option is only relevant when performing a data-only restore.
It instructs <command>pg_restore</command> to execute commands
to temporarily disable triggers on the target tables while
the data is reloaded. Use this if you have referential
integrity checks or other triggers on the tables that you
do not want to invoke during data reload.
</para>
<para>
Presently, the commands emitted for <option>--disable-triggers</>
must be done as superuser. So, you should also specify
a superuser name with <option>-S</>, or preferably specify
<option>--use-set-session-authorization</> and run
<command>pg_restore</command> as a superuser.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
......
This diff is collapsed.
......@@ -15,27 +15,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup.h,v 1.18 2002/02/11 00:18:20 tgl Exp $
*
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
*
* Initial version.
*
*
* Modifications - 28-Jul-2000 - pjw@rhyme.com.au (1.45)
*
* Added --create, --no-owner, --superuser, --no-reconnect (pg_dump & pg_restore)
* Added code to dump 'Create Schema' statement (pg_dump)
* Don't bother to disable/enable triggers if we don't have a superuser (pg_restore)
* Cleaned up code for reconnecting to database.
* Force a reconnect as superuser before enabling/disabling triggers.
*
* Modifications - 31-Jul-2000 - pjw@rhyme.com.au (1.46, 1.47)
* Added & Removed --throttle (pg_dump)
* Fixed minor bug in language dumping code: expbuffres were not being reset.
* Fixed version number initialization in _allocAH (pg_backup_archiver.c)
* Added second connection when restoring BLOBs to allow temp. table to survive
* (db reconnection causes temp tables to be lost).
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup.h,v 1.19 2002/05/10 22:36:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -87,6 +67,7 @@ typedef struct _restoreOptions
* cirsumstances */
int use_setsessauth;/* use SET SESSSION AUTHORIZATION instead
* of \connect */
int disable_triggers;/* disable triggers during data-only restore */
char *superuser; /* Username to use as superuser */
int dataOnly;
int dropSchema;
......@@ -152,9 +133,11 @@ PGconn *ConnectDatabase(Archive *AH,
/* Called to add a TOC entry */
extern void ArchiveEntry(Archive *AH, const char *oid, const char *name,
const char *desc, const char *((*deps)[]), const char *defn,
const char *dropStmt, const char *copyStmt, const char *owner,
extern void ArchiveEntry(Archive *AHX, const char *oid, const char *name,
const char *namespace, const char *owner,
const char *desc, const char *((*deps)[]),
const char *defn, const char *dropStmt,
const char *copyStmt,
DataDumperPtr dumpFn, void *dumpArg);
/* Called to write *data* to the archive */
......
This diff is collapsed.
......@@ -17,17 +17,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.42 2002/04/24 02:21:04 momjian Exp $
*
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
* - Initial version.
*
* Modifications - 15-Sep-2000 - pjw@rhyme.com.au
* - Added braceDepth to sqlparseInfo to handle braces in rule definitions.
*
* Modifications - 31-Mar-2001 - pjw@rhyme.com.au (1.50)
* - Make dependencies work on ArchiveEntry calls so that UDTs will
* dump in correct order.
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.43 2002/05/10 22:36:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -68,8 +58,8 @@ typedef z_stream *z_streamp;
#include "libpq-fe.h"
#define K_VERS_MAJOR 1
#define K_VERS_MINOR 5
#define K_VERS_REV 7
#define K_VERS_MINOR 6
#define K_VERS_REV 0
/* Data block types */
#define BLK_DATA 1
......@@ -82,7 +72,8 @@ typedef z_stream *z_streamp;
#define K_VERS_1_3 (( (1 * 256 + 3) * 256 + 0) * 256 + 0) /* BLOBs */
#define K_VERS_1_4 (( (1 * 256 + 4) * 256 + 0) * 256 + 0) /* Date & name in header */
#define K_VERS_1_5 (( (1 * 256 + 5) * 256 + 0) * 256 + 0) /* Handle dependencies */
#define K_VERS_MAX (( (1 * 256 + 5) * 256 + 255) * 256 + 0)
#define K_VERS_1_6 (( (1 * 256 + 6) * 256 + 0) * 256 + 0) /* Schema field in TOCs */
#define K_VERS_MAX (( (1 * 256 + 6) * 256 + 255) * 256 + 0)
/* No of BLOBs to restore in 1 TX */
#define BLOB_BATCH_SIZE 100
......@@ -235,6 +226,7 @@ typedef struct _archiveHandle
int tocCount; /* Number of TOC entries */
struct _tocEntry *currToc; /* Used when dumping data */
char *currUser; /* Restore: current username in script */
char *currSchema; /* Restore: current schema in script */
int compression; /* Compression requested on open */
ArchiveMode mode; /* File mode - r or w */
void *formatData; /* Header data specific to file format */
......@@ -254,11 +246,12 @@ typedef struct _tocEntry
int hadDumper; /* Archiver was passed a dumper routine
* (used in restore) */
char *name;
char *namespace; /* null or empty string if not in a schema */
char *owner;
char *desc;
char *defn;
char *dropStmt;
char *copyStmt;
char *owner;
char *oid; /* Oid of source of entry */
Oid oidVal; /* Value of above */
const char *((*depOid)[]);
......@@ -314,9 +307,6 @@ extern OutputContext SetOutput(ArchiveHandle *AH, char *filename, int compressio
extern void ResetOutput(ArchiveHandle *AH, OutputContext savedContext);
extern int RestoringToDB(ArchiveHandle *AH);
extern int ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser);
extern int UserIsSuperuser(ArchiveHandle *AH, char *user);
extern char *ConnectedUser(ArchiveHandle *AH);
extern int ConnectedUserIsSuperuser(ArchiveHandle *AH);
int ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH);
int ahprintf(ArchiveHandle *AH, const char *fmt,...) __attribute__((format(printf, 2, 3)));
......
......@@ -5,25 +5,7 @@
* Implements the basic DB functions used by the archiver.
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.31 2002/01/18 19:17:05 momjian Exp $
*
* NOTES
*
* Modifications - 04-Jan-2001 - pjw@rhyme.com.au
*
* - Check results of PQ routines more carefully.
*
* Modifications - 19-Mar-2001 - pjw@rhyme.com.au
*
* - Avoid forcing table name to lower case in FixupBlobXrefs!
*
*
* Modifications - 18-Jan-2002 - pjw@rhyme.com.au
*
* - Split ExecuteSqlCommandBuf into 3 routines for (slightly) improved
* clarity. Modify loop to cater for COPY commands buried in the SQL
* command buffer (prev version assumed COPY command was executed
* in prior call). This was to fix the buf in the 'set max oid' code.
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.32 2002/05/10 22:36:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -219,57 +201,6 @@ _check_database_version(ArchiveHandle *AH, bool ignoreVersion)
}
}
/*
* Check if a given user is a superuser.
*/
int
UserIsSuperuser(ArchiveHandle *AH, char *user)
{
PQExpBuffer qry = createPQExpBuffer();
PGresult *res;
int i_usesuper;
int ntups;
int isSuper;
/* Get the superuser setting */
appendPQExpBuffer(qry, "select usesuper from pg_user where usename = '%s'", user);
res = PQexec(AH->connection, qry->data);
if (!res)
die_horribly(AH, modulename, "null result checking superuser status of %s\n", user);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
die_horribly(AH, modulename, "could not check superuser status of %s: %s",
user, PQerrorMessage(AH->connection));
ntups = PQntuples(res);
if (ntups == 0)
isSuper = 0;
else
{
i_usesuper = PQfnumber(res, "usesuper");
isSuper = (strcmp(PQgetvalue(res, 0, i_usesuper), "t") == 0);
}
PQclear(res);
destroyPQExpBuffer(qry);
return isSuper;
}
int
ConnectedUserIsSuperuser(ArchiveHandle *AH)
{
return UserIsSuperuser(AH, PQuser(AH->connection));
}
char *
ConnectedUser(ArchiveHandle *AH)
{
return PQuser(AH->connection);
}
/*
* Reconnect to the server. If dbname is not NULL, use that database,
* else the one associated with the archive handle. If username is
......@@ -310,6 +241,11 @@ ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username)
AH->username = strdup(newusername);
/* XXX Why don't we update AH->dbname? */
/* don't assume we still know the output schema */
if (AH->currSchema)
free(AH->currSchema);
AH->currSchema = strdup("");
return 1;
}
......@@ -481,13 +417,6 @@ ConnectDatabase(Archive *AHX,
PQsetNoticeProcessor(AH->connection, notice_processor, NULL);
/*
* AH->currUser = PQuser(AH->connection);
*
* Removed because it prevented an initial \connect when dumping to SQL
* in pg_dump.
*/
return AH->connection;
}
......@@ -775,8 +704,9 @@ ExecuteSqlCommandBuf(ArchiveHandle *AH, void *qryv, int bufLen)
}
void
FixupBlobRefs(ArchiveHandle *AH, char *tablename)
FixupBlobRefs(ArchiveHandle *AH, TocEntry *te)
{
PQExpBuffer tblName;
PQExpBuffer tblQry;
PGresult *res,
*uRes;
......@@ -784,44 +714,55 @@ FixupBlobRefs(ArchiveHandle *AH, char *tablename)
n;
char *attr;
if (strcmp(tablename, BLOB_XREF_TABLE) == 0)
if (strcmp(te->name, BLOB_XREF_TABLE) == 0)
return;
tblName = createPQExpBuffer();
tblQry = createPQExpBuffer();
appendPQExpBuffer(tblQry, "SELECT a.attname FROM pg_class c, pg_attribute a, pg_type t "
" WHERE a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid "
" AND t.typname in ('oid', 'lo') AND c.relname = '%s';", tablename);
if (te->namespace && strlen(te->namespace) > 0)
appendPQExpBuffer(tblName, "%s.",
fmtId(te->namespace, false));
appendPQExpBuffer(tblName, "%s",
fmtId(te->name, false));
appendPQExpBuffer(tblQry,
"SELECT a.attname FROM "
"pg_catalog.pg_attribute a, pg_catalog.pg_type t "
"WHERE a.attnum > 0 AND a.attrelid = '%s'::regclass "
"AND a.atttypid = t.oid AND t.typname in ('oid', 'lo')",
tblName->data);
res = PQexec(AH->blobConnection, tblQry->data);
if (!res)
die_horribly(AH, modulename, "could not find oid columns of table \"%s\": %s",
tablename, PQerrorMessage(AH->connection));
te->name, PQerrorMessage(AH->connection));
if ((n = PQntuples(res)) == 0)
{
/* nothing to do */
ahlog(AH, 1, "no OID type columns in table %s\n", tablename);
ahlog(AH, 1, "no OID type columns in table %s\n", te->name);
}
for (i = 0; i < n; i++)
{
attr = PQgetvalue(res, i, 0);
ahlog(AH, 1, "fixing large object cross-references for %s.%s\n", tablename, attr);
ahlog(AH, 1, "fixing large object cross-references for %s.%s\n",
te->name, attr);
resetPQExpBuffer(tblQry);
/*
* We should use coalesce here (rather than 'exists'), but it
* seems to be broken in 7.0.2 (weird optimizer strategy)
*/
appendPQExpBuffer(tblQry, "UPDATE \"%s\" SET \"%s\" = ", tablename, attr);
appendPQExpBuffer(tblQry, " (SELECT x.newOid FROM \"%s\" x WHERE x.oldOid = \"%s\".\"%s\")",
BLOB_XREF_TABLE, tablename, attr);
appendPQExpBuffer(tblQry, " where exists"
"(select * from %s x where x.oldOid = \"%s\".\"%s\");",
BLOB_XREF_TABLE, tablename, attr);
/* Can't use fmtId twice in one call... */
appendPQExpBuffer(tblQry,
"UPDATE %s SET %s = %s.newOid",
tblName->data, fmtId(attr, false),
BLOB_XREF_TABLE);
appendPQExpBuffer(tblQry,
" FROM %s WHERE %s.oldOid = %s.%s",
BLOB_XREF_TABLE,
BLOB_XREF_TABLE,
tblName->data, fmtId(attr, false));
ahlog(AH, 10, "SQL: %s\n", tblQry->data);
......@@ -829,17 +770,18 @@ FixupBlobRefs(ArchiveHandle *AH, char *tablename)
if (!uRes)
die_horribly(AH, modulename,
"could not update column \"%s\" of table \"%s\": %s",
attr, tablename, PQerrorMessage(AH->blobConnection));
attr, te->name, PQerrorMessage(AH->blobConnection));
if (PQresultStatus(uRes) != PGRES_COMMAND_OK)
die_horribly(AH, modulename,
"error while updating column \"%s\" of table \"%s\": %s",
attr, tablename, PQerrorMessage(AH->blobConnection));
attr, te->name, PQerrorMessage(AH->blobConnection));
PQclear(uRes);
}
PQclear(res);
destroyPQExpBuffer(tblName);
destroyPQExpBuffer(tblQry);
}
......
......@@ -2,12 +2,12 @@
* Definitions for pg_backup_db.c
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.h,v 1.5 2001/06/27 21:21:37 petere Exp $
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.h,v 1.6 2002/05/10 22:36:26 tgl Exp $
*/
#define BLOB_XREF_TABLE "dump_blob_xref" /* MUST be lower case */
#define BLOB_XREF_TABLE "pg_dump_blob_xref" /* MUST be lower case */
extern void FixupBlobRefs(ArchiveHandle *AH, char *tablename);
extern void FixupBlobRefs(ArchiveHandle *AH, TocEntry *te);
extern int ExecuteSqlCommand(ArchiveHandle *AH, PQExpBuffer qry, char *desc, bool use_blob);
extern int ExecuteSqlCommandBuf(ArchiveHandle *AH, void *qry, int bufLen);
......
......@@ -3,7 +3,7 @@
* pg_backup_null.c
*
* Implementation of an archive that is never saved; it is used by
* pg_dump to output output a plain text SQL script instead of save
* pg_dump to output a plain text SQL script instead of save
* a real archive.
*
* See the headers to pg_restore for more details.
......@@ -17,7 +17,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_null.c,v 1.8 2002/04/24 02:21:04 momjian Exp $
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_null.c,v 1.9 2002/05/10 22:36:26 tgl Exp $
*
* Modifications - 09-Jul-2000 - pjw@rhyme.com.au
*
......
......@@ -16,7 +16,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.21 2002/04/24 02:21:04 momjian Exp $
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.22 2002/05/10 22:36:26 tgl Exp $
*
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
*
......@@ -835,7 +835,7 @@ _CloseArchive(ArchiveHandle *AH)
ropt = NewRestoreOptions();
ropt->dropSchema = 1;
ropt->compression = 0;
ropt->superuser = PQuser(AH->connection);
ropt->superuser = NULL;
ropt->suppressDumpWarnings = true;
savVerbose = AH->public.verbose;
......
This diff is collapsed.
This diff is collapsed.
......@@ -34,22 +34,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_restore.c,v 1.33 2002/01/18 19:17:05 momjian Exp $
*
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
*
* Initial version. Command processing taken from original pg_dump.
*
* Modifications - 28-Jul-2000 - pjw@rhyme.com.au (1.45)
*
* Added --create, --no-owner, --superuser, --no-reconnect (pg_dump & pg_restore)
* Added code to dump 'Create Schema' statement (pg_dump)
* Don't bother to disable/enable triggers if we don't have a superuser (pg_restore)
* Cleaned up code for reconnecting to database.
* Force a reconnect as superuser before enabling/disabling triggers.
*
* Modifications - 6-Mar-2001 - pjw@rhyme.com.au
* Change -U option to -L to allow -U to specify username in future.
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_restore.c,v 1.34 2002/05/10 22:36:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -94,6 +79,7 @@ main(int argc, char **argv)
extern int optind;
extern char *optarg;
static int use_setsessauth = 0;
static int disable_triggers = 0;
#ifdef HAVE_GETOPT_LONG
struct option cmdopts[] = {
......@@ -130,6 +116,8 @@ main(int argc, char **argv)
* letter, but are available as '-X long-name'
*/
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
{"disable-triggers", no_argument, &disable_triggers, 1},
{NULL, 0, NULL, 0}
};
#endif /* HAVE_GETOPT_LONG */
......@@ -281,6 +269,8 @@ main(int argc, char **argv)
case 'X':
if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
else if (strcmp(optarg, "disable-triggers") == 0)
disable_triggers = 1;
else
{
fprintf(stderr,
......@@ -309,6 +299,7 @@ main(int argc, char **argv)
fileSpec = NULL;
opts->use_setsessauth = use_setsessauth;
opts->disable_triggers = disable_triggers;
if (opts->formatName)
{
......@@ -416,6 +407,8 @@ usage(const char *progname)
" -X use-set-session-authorization, --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead\n"
" of reconnecting, if possible\n"
" -X disable-triggers, --disable-triggers\n"
" disable triggers during data-only restore\n"
));
#else /* not HAVE_GETOPT_LONG */
......@@ -452,6 +445,7 @@ usage(const char *progname)
" -X use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead\n"
" of reconnecting, if possible\n"
" -X disable-triggers disable triggers during data-only restore\n"
));
#endif
puts(gettext("If no input file name is supplied, then standard input is used.\n"));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment