* pg_dump is a utility for dumping out a postgres database
* into a script file.
*
- * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* pg_dump will read the system catalogs in a database and dump out a
* Note that pg_dump runs in a transaction-snapshot mode transaction,
* so it sees a consistent snapshot of the database including system
* catalogs. However, it relies in part on various specialized backend
- * functions like pg_get_indexdef(), and those things tend to run on
- * SnapshotNow time, ie they look at the currently committed state. So
- * it is possible to get 'cache lookup failed' error if someone
- * performs DDL changes while a dump is happening. The window for this
- * sort of thing is from the acquisition of the transaction snapshot to
- * getSchemaData() (when pg_dump acquires AccessShareLock on every
- * table it intends to dump). It isn't very large, but it can happen.
+ * functions like pg_get_indexdef(), and those things tend to look at
+ * the currently committed state. So it is possible to get 'cache
+ * lookup failed' error if someone performs DDL changes while a dump is
+ * happening. The window for this sort of thing is from the acquisition
+ * of the transaction snapshot to getSchemaData() (when pg_dump acquires
+ * AccessShareLock on every table it intends to dump). It isn't very large,
+ * but it can happen.
*
* http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
*
#include "catalog/pg_cast.h"
#include "catalog/pg_class.h"
#include "catalog/pg_default_acl.h"
+#include "catalog/pg_event_trigger.h"
#include "catalog/pg_largeobject.h"
#include "catalog/pg_largeobject_metadata.h"
#include "catalog/pg_proc.h"
#include "pg_backup_archiver.h"
#include "pg_backup_db.h"
-#include "dumpmem.h"
+#include "pg_backup_utils.h"
#include "dumputils.h"
-
-extern char *optarg;
-extern int optind,
- opterr;
+#include "parallel.h"
typedef struct
/* global decls */
bool g_verbose; /* User wants verbose narration of our
* activities. */
-PGconn *g_conn; /* the database connection */
/* various user-settable parameters */
-bool schemaOnly;
-bool dataOnly;
-int dumpSections; /* bitmask of chosen sections */
-bool aclsSkip;
-const char *lockWaitTimeout;
+static bool schemaOnly;
+static bool dataOnly;
+static int dumpSections; /* bitmask of chosen sections */
+static bool aclsSkip;
+static const char *lockWaitTimeout;
/* subquery used to convert user ID (eg, datdba) to user name */
static const char *username_subquery;
static const CatalogId nilCatalogId = {0, 0};
-/* these are to avoid passing around info for findNamespace() */
-static NamespaceInfo *g_namespaces;
-static int g_numNamespaces;
-
/* flags for various command-line long options */
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;
static int serializable_deferrable = 0;
SimpleOidList *oids);
static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
+static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
static void dumpComment(Archive *fout, const char *target,
const char *namespace, const char *owner,
static void dumpRule(Archive *fout, RuleInfo *rinfo);
static void dumpAgg(Archive *fout, AggInfo *agginfo);
static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
+static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
static void dumpTable(Archive *fout, TableInfo *tbinfo);
static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
static void dumpSequence(Archive *fout, TableInfo *tbinfo);
+static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
const char *acls);
static void getDependencies(Archive *fout);
+static void BuildArchiveDependencies(Archive *fout);
+static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
+ DumpId **dependencies, int *nDeps, int *allocDeps);
+
+static DumpableObject *createBoundaryObjects(void);
+static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
+ DumpableObject *boundaryObjs);
+
static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
+static void buildMatViewRefreshDependencies(Archive *fout);
static void getTableDataFKConstraints(void);
-static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
+static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
+ bool is_agg);
static char *format_function_arguments_old(Archive *fout,
FuncInfo *finfo, int nallargs,
char **allargtypes,
char **argmodes,
char **argnames);
static char *format_function_signature(Archive *fout,
- FuncInfo *finfo, bool honor_quotes);
-static const char *convertRegProcReference(Archive *fout,
- const char *proc);
-static const char *convertOperatorReference(Archive *fout, const char *opr);
+ FuncInfo *finfo, bool honor_quotes);
+static char *convertRegProcReference(Archive *fout,
+ const char *proc);
+static char *convertOperatorReference(Archive *fout, const char *opr);
static const char *convertTSFunction(Archive *fout, Oid funcOid);
static Oid findLastBuiltinOid_V71(Archive *fout, const char *);
static Oid findLastBuiltinOid_V70(Archive *fout);
static void selectSourceSchema(Archive *fout, const char *schemaName);
static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
static char *myFormatType(const char *typname, int32 typmod);
-static const char *fmtQualifiedId(Archive *fout,
- const char *schema, const char *id);
static void getBlobs(Archive *fout);
static void dumpBlob(Archive *fout, BlobInfo *binfo);
static int dumpBlobs(Archive *fout, void *arg);
DumpableObject *dobj,
const char *objlabel);
static const char *getAttrName(int attrnum, TableInfo *tblInfo);
-static const char *fmtCopyColumnList(const TableInfo *ti);
+static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
+static char *get_synchronized_snapshot(Archive *fout);
+static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
+static void setupDumpWorker(Archive *AHX, RestoreOptions *ropt);
+
int
main(int argc, char **argv)
int numTables;
DumpableObject **dobjs;
int numObjs;
+ DumpableObject *boundaryObjs;
int i;
+ int numWorkers = 1;
enum trivalue prompt_password = TRI_DEFAULT;
int compressLevel = -1;
int plainText = 0;
int outputNoOwner = 0;
char *outputSuperuser = NULL;
char *use_role = NULL;
- int my_version;
int optindex;
RestoreOptions *ropt;
ArchiveFormat archiveFormat = archUnknown;
ArchiveMode archiveMode;
- Archive *fout; /* the script file */
+ Archive *fout; /* the script file */
static int disable_triggers = 0;
static int outputNoTablespaces = 0;
{"blobs", no_argument, NULL, 'b'},
{"clean", no_argument, NULL, 'c'},
{"create", no_argument, NULL, 'C'},
+ {"dbname", required_argument, NULL, 'd'},
{"file", required_argument, NULL, 'f'},
{"format", required_argument, NULL, 'F'},
{"host", required_argument, NULL, 'h'},
{"ignore-version", no_argument, NULL, 'i'},
+ {"jobs", 1, NULL, 'j'},
{"no-reconnect", no_argument, NULL, 'R'},
{"oids", no_argument, NULL, 'o'},
{"no-owner", no_argument, NULL, 'O'},
{"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},
{"serializable-deferrable", no_argument, &serializable_deferrable, 1},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
{"no-security-labels", no_argument, &no_security_labels, 1},
+ {"no-synchronized-snapshots", no_argument, &no_synchronized_snapshots, 1},
{"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
{NULL, 0, NULL, 0}
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
+ /*
+ * Initialize what we need for parallel execution, especially for thread
+ * support on Windows.
+ */
+ init_parallel_dump_utils();
+
g_verbose = false;
strcpy(g_comment_start, "-- ");
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
{
help(progname);
- exit(0);
+ exit_nicely(0);
}
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
{
puts("pg_dump (PostgreSQL) " PG_VERSION);
- exit(0);
+ exit_nicely(0);
}
}
- while ((c = getopt_long(argc, argv, "abcCE:f:F:h:in:N:oOp:RsS:t:T:U:vwWxZ:",
+ while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:ij:n:N:oOp:RsS:t:T:U:vwWxZ:",
long_options, &optindex)) != -1)
{
switch (c)
outputCreateDB = 1;
break;
+ case 'd': /* database name */
+ dbname = pg_strdup(optarg);
+ break;
+
case 'E': /* Dump encoding */
- dumpencoding = optarg;
+ dumpencoding = pg_strdup(optarg);
break;
case 'f':
- filename = optarg;
+ filename = pg_strdup(optarg);
break;
case 'F':
- format = optarg;
+ format = pg_strdup(optarg);
break;
case 'h': /* server host */
- pghost = optarg;
+ pghost = pg_strdup(optarg);
break;
case 'i':
/* ignored, deprecated option */
break;
+ case 'j': /* number of dump jobs */
+ numWorkers = atoi(optarg);
+ break;
+
case 'n': /* include schema(s) */
simple_string_list_append(&schema_include_patterns, optarg);
include_everything = false;
break;
case 'p': /* server port */
- pgport = optarg;
+ pgport = pg_strdup(optarg);
break;
case 'R':
break;
case 'U':
- username = optarg;
+ username = pg_strdup(optarg);
break;
case 'v': /* verbose */
break;
case 2: /* lock-wait-timeout */
- lockWaitTimeout = optarg;
+ lockWaitTimeout = pg_strdup(optarg);
break;
case 3: /* SET ROLE */
- use_role = optarg;
+ use_role = pg_strdup(optarg);
break;
- case 4: /* exclude table(s) data */
+ case 4: /* exclude table(s) data */
simple_string_list_append(&tabledata_exclude_patterns, optarg);
break;
case 5: /* section */
- set_section(optarg, &dumpSections);
+ set_dump_section(optarg, &dumpSections);
break;
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
- exit(1);
+ exit_nicely(1);
}
}
- /* Get database name from command line */
- if (optind < argc)
+ /*
+ * Non-option argument specifies database name as long as it wasn't
+ * already specified with -d / --dbname
+ */
+ if (optind < argc && dbname == NULL)
dbname = argv[optind++];
/* Complain if any arguments remain */
progname, argv[optind]);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
- exit(1);
+ exit_nicely(1);
}
/* --column-inserts implies --inserts */
if (dataOnly && schemaOnly)
{
write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
- exit(1);
- }
-
- if ((dataOnly || schemaOnly) && dumpSections != DUMP_UNSECTIONED)
- {
- write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used with --section\n");
- exit(1);
- }
-
- if (dataOnly)
- dumpSections = DUMP_DATA;
- else if (schemaOnly)
- dumpSections = DUMP_PRE_DATA | DUMP_POST_DATA;
- else if ( dumpSections != DUMP_UNSECTIONED)
- {
- dataOnly = dumpSections == DUMP_DATA;
- schemaOnly = !(dumpSections & DUMP_DATA);
+ exit_nicely(1);
}
if (dataOnly && outputClean)
{
write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
- exit(1);
+ exit_nicely(1);
}
if (dump_inserts && oids)
{
write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
- exit(1);
+ 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);
compressLevel = 0;
}
+ /*
+ * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
+ * parallel jobs because that's the maximum limit for the
+ * WaitForMultipleObjects() call.
+ */
+ if (numWorkers <= 0
+#ifdef WIN32
+ || numWorkers > MAXIMUM_WAIT_OBJECTS
+#endif
+ )
+ exit_horribly(NULL, "%s: invalid number of parallel jobs\n", progname);
+
+ /* Parallel backup only in the directory archive format so far */
+ if (archiveFormat != archDirectory && numWorkers > 1)
+ exit_horribly(NULL, "parallel backup only supported by the directory format\n");
+
/* Open the output file */
- fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode);
+ fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode,
+ setupDumpWorker);
+
+ /* Register the cleanup hook */
+ on_exit_close_archive(fout);
if (fout == NULL)
- {
- write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
- exit(1);
- }
+ exit_horribly(NULL, "could not open output file \"%s\" for writing\n", filename);
/* Let the archiver know how noisy to be */
fout->verbose = g_verbose;
- my_version = parse_version(PG_VERSION);
- if (my_version < 0)
- {
- write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
- exit(1);
- }
-
/*
* We allow the server to be back to 7.0, and up to any minor release of
* our own major version. (See also version check in pg_dumpall.c.)
*/
fout->minRemoteVersion = 70000;
- fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
+ fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
+
+ fout->numWorkers = numWorkers;
/*
* Open the database using the Archiver, so it knows about it. Errors mean
* death.
*/
- g_conn = ConnectDatabase(fout, dbname, pghost, pgport,
- username, prompt_password);
-
+ ConnectDatabase(fout, dbname, pghost, pgport, username, prompt_password);
setup_connection(fout, dumpencoding, use_role);
/*
no_security_labels = 1;
/*
- * Start transaction-snapshot mode transaction to dump consistent data.
+ * When running against 9.0 or later, check if we are in recovery mode,
+ * which means we are on a hot standby.
*/
- ExecuteSqlStatement(fout, "BEGIN");
- if (fout->remoteVersion >= 90100)
+ if (fout->remoteVersion >= 90000)
{
- if (serializable_deferrable)
- ExecuteSqlStatement(fout,
- "SET TRANSACTION ISOLATION LEVEL "
- "SERIALIZABLE, READ ONLY, DEFERRABLE");
- else
- ExecuteSqlStatement(fout,
- "SET TRANSACTION ISOLATION LEVEL "
- "REPEATABLE READ");
+ PGresult *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()");
+
+ if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
+ {
+ /*
+ * On hot standby slaves, never try to dump unlogged table data,
+ * since it will just throw an error.
+ */
+ no_unlogged_table_data = true;
+ }
+ PQclear(res);
}
- else
- ExecuteSqlStatement(fout,
- "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
/* Select the appropriate subquery to convert user IDs to names */
if (fout->remoteVersion >= 80100)
else
username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
+ /* check the version for the synchronized snapshots feature */
+ if (numWorkers > 1 && fout->remoteVersion < 90200
+ && !no_synchronized_snapshots)
+ exit_horribly(NULL,
+ "Synchronized snapshots are not supported by this server version.\n"
+ "Run with --no-synchronized-snapshots instead if you do not need\n"
+ "synchronized snapshots.\n");
+
/* Find the last built-in OID, if needed */
if (fout->remoteVersion < 70300)
{
if (fout->remoteVersion >= 70100)
- g_last_builtin_oid = findLastBuiltinOid_V71(fout, PQdb(g_conn));
+ g_last_builtin_oid = findLastBuiltinOid_V71(fout,
+ PQdb(GetConnection(fout)));
else
g_last_builtin_oid = findLastBuiltinOid_V70(fout);
if (g_verbose)
expand_schema_name_patterns(fout, &schema_include_patterns,
&schema_include_oids);
if (schema_include_oids.head == NULL)
- {
- write_msg(NULL, "No matching schemas were found\n");
- exit_nicely();
- }
+ exit_horribly(NULL, "No matching schemas were found\n");
}
expand_schema_name_patterns(fout, &schema_exclude_patterns,
&schema_exclude_oids);
expand_table_name_patterns(fout, &table_include_patterns,
&table_include_oids);
if (table_include_oids.head == NULL)
- {
- write_msg(NULL, "No matching tables were found\n");
- exit_nicely();
- }
+ exit_horribly(NULL, "No matching tables were found\n");
}
expand_table_name_patterns(fout, &table_exclude_patterns,
&table_exclude_oids);
if (!schemaOnly)
{
getTableData(tblinfo, numTables, oids);
+ buildMatViewRefreshDependencies(fout);
if (dataOnly)
getTableDataFKConstraints();
}
*/
getDependencies(fout);
+ /* Lastly, create dummy objects to represent the section boundaries */
+ boundaryObjs = createBoundaryObjects();
+
+ /* Get pointers to all the known DumpableObjects */
+ getDumpableObjects(&dobjs, &numObjs);
+
+ /*
+ * Add dummy dependencies to enforce the dump section ordering.
+ */
+ addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
+
/*
* Sort the objects into a safe dump order (no forward references).
*
* will dump identically. Before 7.3 we don't have dependencies and we
* use OID ordering as an (unreliable) guide to creation order.
*/
- getDumpableObjects(&dobjs, &numObjs);
-
if (fout->remoteVersion >= 70300)
sortDumpableObjectsByTypeName(dobjs, numObjs);
else
sortDumpableObjectsByTypeOid(dobjs, numObjs);
- sortDumpableObjects(dobjs, numObjs);
+ /* If we do a parallel dump, we want the largest tables to go first */
+ if (archiveFormat == archDirectory && numWorkers > 1)
+ sortDataAndIndexObjectsBySize(dobjs, numObjs);
+
+ sortDumpableObjects(dobjs, numObjs,
+ boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
/*
* Create archive TOC entries for all the objects to be dumped, in a safe
dumpDumpableObject(fout, dobjs[i]);
/*
- * And finally we can do the actual output.
+ * Set up options info to ensure we dump what we want.
*/
- if (plainText)
- {
- ropt = NewRestoreOptions();
- ropt->filename = filename;
- ropt->dropSchema = outputClean;
- ropt->aclsSkip = aclsSkip;
- ropt->superuser = outputSuperuser;
- ropt->createDB = outputCreateDB;
- ropt->noOwner = outputNoOwner;
- ropt->noTablespace = outputNoTablespaces;
- ropt->disable_triggers = disable_triggers;
- ropt->use_setsessauth = use_setsessauth;
- ropt->dataOnly = dataOnly;
-
- if (compressLevel == -1)
- ropt->compression = 0;
- else
- ropt->compression = compressLevel;
+ ropt = NewRestoreOptions();
+ ropt->filename = filename;
+ ropt->dropSchema = outputClean;
+ ropt->dataOnly = dataOnly;
+ ropt->schemaOnly = schemaOnly;
+ ropt->if_exists = if_exists;
+ ropt->dumpSections = dumpSections;
+ ropt->aclsSkip = aclsSkip;
+ ropt->superuser = outputSuperuser;
+ ropt->createDB = outputCreateDB;
+ ropt->noOwner = outputNoOwner;
+ ropt->noTablespace = outputNoTablespaces;
+ ropt->disable_triggers = disable_triggers;
+ ropt->use_setsessauth = use_setsessauth;
- ropt->suppressDumpWarnings = true; /* We've already shown them */
+ if (compressLevel == -1)
+ ropt->compression = 0;
+ else
+ ropt->compression = compressLevel;
- RestoreArchive(fout, ropt);
- }
+ ropt->suppressDumpWarnings = true; /* We've already shown them */
- CloseArchive(fout);
+ SetArchiveRestoreOptions(fout, ropt);
+
+ /*
+ * The archive's TOC entries are now marked as to which ones will actually
+ * be output, so we can set up their dependency lists properly. This isn't
+ * necessary for plain-text output, though.
+ */
+ if (!plainText)
+ BuildArchiveDependencies(fout);
+
+ /*
+ * And finally we can do the actual output.
+ *
+ * Note: for non-plain-text output formats, the output file is written
+ * inside CloseArchive(). This is, um, bizarre; but not worth changing
+ * right now.
+ */
+ if (plainText)
+ RestoreArchive(fout);
- PQfinish(g_conn);
+ CloseArchive(fout);
- exit(0);
+ exit_nicely(0);
}
printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
printf(_("\nGeneral options:\n"));
- printf(_(" -f, --file=FILENAME output file or directory name\n"));
- printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
- " plain text (default))\n"));
- printf(_(" -v, --verbose verbose mode\n"));
- printf(_(" -Z, --compress=0-9 compression level for compressed formats\n"));
- printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
- printf(_(" --help show this help, then exit\n"));
- printf(_(" --version output version information, then exit\n"));
+ printf(_(" -f, --file=FILENAME output file or directory name\n"));
+ printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
+ " plain text (default))\n"));
+ printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
+ printf(_(" -v, --verbose verbose mode\n"));
+ printf(_(" -V, --version output version information, then exit\n"));
+ printf(_(" -Z, --compress=0-9 compression level for compressed formats\n"));
+ printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
+ printf(_(" -?, --help show this help, then exit\n"));
printf(_("\nOptions controlling the output content:\n"));
- printf(_(" -a, --data-only dump only the data, not the schema\n"));
- printf(_(" -b, --blobs include large objects in dump\n"));
- printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
- printf(_(" -C, --create include commands to create database in dump\n"));
- printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
- printf(_(" -n, --schema=SCHEMA dump the named schema(s) only\n"));
- printf(_(" -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
- printf(_(" -o, --oids include OIDs in dump\n"));
- printf(_(" -O, --no-owner skip restoration of object ownership in\n"
- " plain-text format\n"));
- printf(_(" -s, --schema-only dump only the schema, no data\n"));
- printf(_(" -S, --superuser=NAME superuser user name to use in 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(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
- printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
- 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(_(" --exclude-table-data=TABLE do NOT dump data for the named table(s)\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"));
- printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
- printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
- printf(_(" --section=SECTION dump named section (pre-data, data or post-data)\n"));
- printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
+ printf(_(" -a, --data-only dump only the data, not the schema\n"));
+ printf(_(" -b, --blobs include large objects in dump\n"));
+ printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
+ printf(_(" -C, --create include commands to create database in dump\n"));
+ printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
+ printf(_(" -n, --schema=SCHEMA dump the named schema(s) only\n"));
+ printf(_(" -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
+ printf(_(" -o, --oids include OIDs in dump\n"));
+ printf(_(" -O, --no-owner skip restoration of object ownership in\n"
+ " plain-text format\n"));
+ printf(_(" -s, --schema-only dump only the schema, no data\n"));
+ printf(_(" -S, --superuser=NAME superuser user name to use in 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(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
+ printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
+ 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(_(" --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"));
+ printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
+ printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
+ printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
+ printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
+ printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
printf(_(" --use-set-session-authorization\n"
- " use SET SESSION AUTHORIZATION commands instead of\n"
- " ALTER OWNER commands to set ownership\n"));
+ " use SET SESSION AUTHORIZATION commands instead of\n"
+ " ALTER OWNER commands to set ownership\n"));
printf(_("\nConnection options:\n"));
+ printf(_(" -d, --dbname=DBNAME database to dump\n"));
printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
printf(_(" -p, --port=PORT database server port number\n"));
printf(_(" -U, --username=NAME connect as specified database user\n"));
printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
}
-void
-exit_nicely(void)
-{
- PQfinish(g_conn);
- if (g_verbose)
- write_msg(NULL, "*** aborted because of error\n");
- exit(1);
-}
-
static void
setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
{
+ PGconn *conn = GetConnection(AH);
const char *std_strings;
- /* Set the client encoding if requested */
+ /*
+ * Set the client encoding if requested. If dumpencoding == NULL then
+ * either it hasn't been requested or we're a cloned connection and then
+ * this has already been set in CloneArchive according to the original
+ * connection encoding.
+ */
if (dumpencoding)
{
- if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
- {
- write_msg(NULL, "invalid client encoding \"%s\" specified\n",
- dumpencoding);
- exit(1);
- }
+ if (PQsetClientEncoding(conn, dumpencoding) < 0)
+ exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
+ dumpencoding);
}
/*
* Get the active encoding and the standard_conforming_strings setting, so
* we know how to escape strings.
*/
- AH->encoding = PQclientEncoding(g_conn);
+ AH->encoding = PQclientEncoding(conn);
- std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
+ std_strings = PQparameterStatus(conn, "standard_conforming_strings");
AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
+ /* Set the role if requested */
+ if (!use_role && AH->use_role)
+ use_role = AH->use_role;
+
/* Set the role if requested */
if (use_role && AH->remoteVersion >= 80100)
{
appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
ExecuteSqlStatement(AH, query->data);
destroyPQExpBuffer(query);
+
+ /* save this for later use on parallel connections */
+ if (!AH->use_role)
+ AH->use_role = strdup(use_role);
}
/* Set the datestyle to ISO to ensure the dump's portability */
*/
if (AH->remoteVersion >= 70300)
ExecuteSqlStatement(AH, "SET statement_timeout = 0");
+ if (AH->remoteVersion >= 90300)
+ ExecuteSqlStatement(AH, "SET lock_timeout = 0");
/*
* Quote all identifiers, if requested.
*/
if (quote_all_identifiers && AH->remoteVersion >= 90100)
ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
+
+ /*
+ * Start transaction-snapshot mode transaction to dump consistent data.
+ */
+ ExecuteSqlStatement(AH, "BEGIN");
+ if (AH->remoteVersion >= 90100)
+ {
+ if (serializable_deferrable)
+ ExecuteSqlStatement(AH,
+ "SET TRANSACTION ISOLATION LEVEL "
+ "SERIALIZABLE, READ ONLY, DEFERRABLE");
+ else
+ ExecuteSqlStatement(AH,
+ "SET TRANSACTION ISOLATION LEVEL "
+ "REPEATABLE READ, READ ONLY");
+ }
+ else if (AH->remoteVersion >= 70400)
+ {
+ /* note: comma was not accepted in SET TRANSACTION before 8.0 */
+ ExecuteSqlStatement(AH,
+ "SET TRANSACTION ISOLATION LEVEL "
+ "SERIALIZABLE READ ONLY");
+ }
+ else
+ ExecuteSqlStatement(AH,
+ "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
+
+
+
+ if (AH->numWorkers > 1 && AH->remoteVersion >= 90200 && !no_synchronized_snapshots)
+ {
+ if (AH->sync_snapshot_id)
+ {
+ PQExpBuffer query = createPQExpBuffer();
+
+ appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
+ appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
+ ExecuteSqlStatement(AH, query->data);
+ destroyPQExpBuffer(query);
+ }
+ else
+ AH->sync_snapshot_id = get_synchronized_snapshot(AH);
+ }
+}
+
+static void
+setupDumpWorker(Archive *AHX, RestoreOptions *ropt)
+{
+ setup_connection(AHX, NULL, NULL);
+}
+
+static char *
+get_synchronized_snapshot(Archive *fout)
+{
+ char *query = "SELECT pg_export_snapshot()";
+ char *result;
+ PGresult *res;
+
+ res = ExecuteSqlQueryForSingleRow(fout, query);
+ result = strdup(PQgetvalue(res, 0, 0));
+ PQclear(res);
+
+ return result;
}
static ArchiveFormat
archiveFormat = archDirectory;
else if (pg_strcasecmp(format, "directory") == 0)
archiveFormat = archDirectory;
- else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0)
-
- /*
- * Dump files into the current directory; for demonstration only, not
- * documented.
- */
- archiveFormat = archFiles;
else if (pg_strcasecmp(format, "p") == 0)
archiveFormat = archNull;
else if (pg_strcasecmp(format, "plain") == 0)
else if (pg_strcasecmp(format, "tar") == 0)
archiveFormat = archTar;
else
- {
- write_msg(NULL, "invalid output format \"%s\" specified\n", format);
- exit(1);
- }
+ exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
return archiveFormat;
}
return; /* nothing to do */
if (fout->remoteVersion < 70300)
- {
- write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
- exit_nicely();
- }
+ exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n");
query = createPQExpBuffer();
for (cell = patterns->head; cell; cell = cell->next)
{
if (cell != patterns->head)
- appendPQExpBuffer(query, "UNION ALL\n");
+ appendPQExpBufferStr(query, "UNION ALL\n");
appendPQExpBuffer(query,
"SELECT oid FROM pg_catalog.pg_namespace n\n");
- processSQLNamePattern(g_conn, query, cell->val, false, false,
- NULL, "n.nspname", NULL,
- NULL);
+ processSQLNamePattern(GetConnection(fout), query, cell->val, false,
+ false, NULL, "n.nspname", NULL, NULL);
}
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
for (cell = patterns->head; cell; cell = cell->next)
{
if (cell != patterns->head)
- appendPQExpBuffer(query, "UNION ALL\n");
+ appendPQExpBufferStr(query, "UNION ALL\n");
appendPQExpBuffer(query,
"SELECT c.oid"
"\nFROM pg_catalog.pg_class c"
"\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
- "\nWHERE c.relkind in ('%c', '%c', '%c', '%c')\n",
+ "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n",
RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
- RELKIND_FOREIGN_TABLE);
- processSQLNamePattern(g_conn, query, cell->val, true, false,
- "n.nspname", "c.relname", NULL,
+ RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
+ processSQLNamePattern(GetConnection(fout), query, cell->val, true,
+ false, "n.nspname", "c.relname", NULL,
"pg_catalog.pg_table_is_visible(c.oid)");
}
if (tyinfo->isArray)
{
tyinfo->dobj.objType = DO_DUMMY_TYPE;
+
/*
* Fall through to set the dump flag; we assume that the subsequent
* rules will do the same thing as they would for the array's base
const bool hasoids = tbinfo->hasoids;
const bool oids = tdinfo->oids;
PQExpBuffer q = createPQExpBuffer();
+
+ /*
+ * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
+ * which uses it already.
+ */
+ PQExpBuffer clistBuf = createPQExpBuffer();
+ PGconn *conn = GetConnection(fout);
PGresult *res;
int ret;
char *copybuf;
* cases involving ADD COLUMN and inheritance.)
*/
if (fout->remoteVersion >= 70300)
- column_list = fmtCopyColumnList(tbinfo);
+ column_list = fmtCopyColumnList(tbinfo, clistBuf);
else
column_list = ""; /* can't select columns in COPY */
if (oids && hasoids)
{
appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
- fmtQualifiedId(fout,
+ fmtQualifiedId(fout->remoteVersion,
tbinfo->dobj.namespace->dobj.name,
classname),
column_list);
else
appendPQExpBufferStr(q, "* ");
appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
- fmtQualifiedId(fout,
+ fmtQualifiedId(fout->remoteVersion,
tbinfo->dobj.namespace->dobj.name,
classname),
tdinfo->filtercond);
else
{
appendPQExpBuffer(q, "COPY %s %s TO stdout;",
- fmtQualifiedId(fout,
+ fmtQualifiedId(fout->remoteVersion,
tbinfo->dobj.namespace->dobj.name,
classname),
column_list);
}
res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
PQclear(res);
+ destroyPQExpBuffer(clistBuf);
for (;;)
{
- ret = PQgetCopyData(g_conn, ©buf, 0);
+ ret = PQgetCopyData(conn, ©buf, 0);
if (ret < 0)
break; /* done or error */
{
/* copy data transfer failed */
write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
- write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
+ write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
write_msg(NULL, "The command was: %s\n", q->data);
- exit_nicely();
+ exit_nicely(1);
}
/* Check command status and return to normal libpq state */
- res = PQgetResult(g_conn);
+ res = PQgetResult(conn);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
- write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
+ write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
write_msg(NULL, "The command was: %s\n", q->data);
- exit_nicely();
+ exit_nicely(1);
}
PQclear(res);
TableInfo *tbinfo = tdinfo->tdtable;
const char *classname = tbinfo->dobj.name;
PQExpBuffer q = createPQExpBuffer();
+ PQExpBuffer insertStmt = NULL;
PGresult *res;
int tuple;
int nfields;
{
appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
"SELECT * FROM ONLY %s",
- fmtQualifiedId(fout,
+ fmtQualifiedId(fout->remoteVersion,
tbinfo->dobj.namespace->dobj.name,
classname));
}
{
appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
"SELECT * FROM %s",
- fmtQualifiedId(fout,
+ fmtQualifiedId(fout->remoteVersion,
tbinfo->dobj.namespace->dobj.name,
classname));
}
nfields = PQnfields(res);
for (tuple = 0; tuple < PQntuples(res); tuple++)
{
- archprintf(fout, "INSERT INTO %s ", fmtId(classname));
- if (nfields == 0)
+ /*
+ * 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)
{
+ insertStmt = createPQExpBuffer();
+ appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
+ fmtId(classname));
+
/* corner case for zero-column table */
- archprintf(fout, "DEFAULT VALUES;\n");
- continue;
- }
- if (column_inserts)
- {
- resetPQExpBuffer(q);
- appendPQExpBuffer(q, "(");
- for (field = 0; field < nfields; field++)
+ if (nfields == 0)
+ {
+ appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
+ }
+ else
{
- if (field > 0)
- appendPQExpBuffer(q, ", ");
- appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
+ /* append the list of column names if required */
+ if (column_inserts)
+ {
+ appendPQExpBufferStr(insertStmt, "(");
+ for (field = 0; field < nfields; field++)
+ {
+ if (field > 0)
+ appendPQExpBufferStr(insertStmt, ", ");
+ appendPQExpBufferStr(insertStmt,
+ fmtId(PQfname(res, field)));
+ }
+ appendPQExpBufferStr(insertStmt, ") ");
+ }
+
+ appendPQExpBufferStr(insertStmt, "VALUES (");
}
- appendPQExpBuffer(q, ") ");
- archputs(q->data, fout);
}
- archprintf(fout, "VALUES (");
+
+ archputs(insertStmt->data, fout);
+
+ /* if it is zero-column table then we're done */
+ if (nfields == 0)
+ continue;
+
for (field = 0; field < nfields; field++)
{
if (field > 0)
- archprintf(fout, ", ");
+ archputs(", ", fout);
if (PQgetisnull(res, tuple, field))
{
- archprintf(fout, "NULL");
+ archputs("NULL", fout);
continue;
}
const char *s = PQgetvalue(res, tuple, field);
if (strspn(s, "0123456789 +-eE.") == strlen(s))
- archprintf(fout, "%s", s);
+ archputs(s, fout);
else
archprintf(fout, "'%s'", s);
}
case BOOLOID:
if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
- archprintf(fout, "true");
+ archputs("true", fout);
else
- archprintf(fout, "false");
+ archputs("false", fout);
break;
default:
break;
}
}
- archprintf(fout, ");\n");
+ archputs(");\n", fout);
}
if (PQntuples(res) <= 0)
PQclear(res);
}
- archprintf(fout, "\n\n");
+ archputs("\n\n", fout);
ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
destroyPQExpBuffer(q);
+ if (insertStmt != NULL)
+ destroyPQExpBuffer(insertStmt);
+
return 1;
}
{
TableInfo *tbinfo = tdinfo->tdtable;
PQExpBuffer copyBuf = createPQExpBuffer();
+ PQExpBuffer clistBuf = createPQExpBuffer();
DataDumperPtr dumpFn;
char *copyStmt;
appendPQExpBuffer(copyBuf, "COPY %s ",
fmtId(tbinfo->dobj.name));
appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
- fmtCopyColumnList(tbinfo),
+ fmtCopyColumnList(tbinfo, clistBuf),
(tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
copyStmt = copyBuf->data;
}
copyStmt = NULL;
}
+ /*
+ * Note: although the TableDataInfo is a full DumpableObject, we treat its
+ * dependency on its table as "special" and pass it to ArchiveEntry now.
+ * See comments for BuildArchiveDependencies.
+ */
ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
NULL, tbinfo->rolname,
false, "TABLE DATA", SECTION_DATA,
"", "", copyStmt,
- tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
+ &(tbinfo->dobj.dumpId), 1,
dumpFn, tdinfo);
destroyPQExpBuffer(copyBuf);
+ destroyPQExpBuffer(clistBuf);
+}
+
+/*
+ * refreshMatViewData -
+ * load or refresh the contents of a single materialized view
+ *
+ * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
+ * statement.
+ */
+static void
+refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
+{
+ TableInfo *tbinfo = tdinfo->tdtable;
+ PQExpBuffer q;
+
+ /* If the materialized view is not flagged as populated, skip this. */
+ if (!tbinfo->relispopulated)
+ return;
+
+ q = createPQExpBuffer();
+
+ appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
+ fmtId(tbinfo->dobj.name));
+
+ ArchiveEntry(fout,
+ tdinfo->dobj.catId, /* catalog ID */
+ tdinfo->dobj.dumpId, /* dump ID */
+ tbinfo->dobj.name, /* Name */
+ tbinfo->dobj.namespace->dobj.name, /* Namespace */
+ NULL, /* Tablespace */
+ tbinfo->rolname, /* Owner */
+ false, /* with oids */
+ "MATERIALIZED VIEW DATA", /* Desc */
+ SECTION_POST_DATA, /* Section */
+ q->data, /* Create */
+ "", /* Del */
+ NULL, /* Copy */
+ tdinfo->dobj.dependencies, /* Deps */
+ tdinfo->dobj.nDeps, /* # Deps */
+ NULL, /* Dumper */
+ NULL); /* Dumper Arg */
+
+ destroyPQExpBuffer(q);
}
/*
/* Skip VIEWs (no data to dump) */
if (tbinfo->relkind == RELKIND_VIEW)
return;
- /* Skip SEQUENCEs (handled elsewhere) */
- if (tbinfo->relkind == RELKIND_SEQUENCE)
- return;
/* Skip FOREIGN TABLEs (no data to dump) */
if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
return;
/* OK, let's dump it */
tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
- tdinfo->dobj.objType = DO_TABLE_DATA;
+ if (tbinfo->relkind == RELKIND_MATVIEW)
+ tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
+ else
+ tdinfo->dobj.objType = DO_TABLE_DATA;
/*
* Note: use tableoid 0 so that this object won't be mistaken for
}
/*
- * getTableDataFKConstraints -
- * add dump-order dependencies reflecting foreign key constraints
+ * The refresh for a materialized view must be dependent on the refresh for
+ * any materialized view that this one is dependent on.
*
- * This code is executed only in a data-only dump --- in schema+data dumps
- * we handle foreign key issues by not creating the FK constraints until
- * after the data is loaded. In a data-only dump, however, we want to
- * order the table data objects in such a way that a table's referenced
- * tables are restored first. (In the presence of circular references or
- * self-references this may be impossible; we'll detect and complain about
- * that during the dependency sorting step.)
+ * This must be called after all the objects are created, but before they are
+ * sorted.
*/
static void
-getTableDataFKConstraints(void)
+buildMatViewRefreshDependencies(Archive *fout)
{
- DumpableObject **dobjs;
- int numObjs;
- int i;
+ PQExpBuffer query;
+ PGresult *res;
+ int ntups,
+ i;
+ int i_classid,
+ i_objid,
+ i_refobjid;
- /* Search through all the dumpable objects for FK constraints */
- getDumpableObjects(&dobjs, &numObjs);
- for (i = 0; i < numObjs; i++)
- {
- if (dobjs[i]->objType == DO_FK_CONSTRAINT)
- {
- ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
- TableInfo *ftable;
+ /* No Mat Views before 9.3. */
+ if (fout->remoteVersion < 90300)
+ return;
- /* Not interesting unless both tables are to be dumped */
- if (cinfo->contable == NULL ||
- cinfo->contable->dataObj == NULL)
- continue;
- ftable = findTableByOid(cinfo->confrelid);
- if (ftable == NULL ||
- ftable->dataObj == NULL)
- continue;
+ /* Make sure we are in proper schema */
+ selectSourceSchema(fout, "pg_catalog");
- /*
- * Okay, make referencing table's TABLE_DATA object depend on the
- * referenced table's TABLE_DATA object.
- */
- addObjectDependency(&cinfo->contable->dataObj->dobj,
- ftable->dataObj->dobj.dumpId);
- }
- }
- free(dobjs);
-}
+ query = createPQExpBuffer();
+ appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
+ "( "
+ "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
+ "FROM pg_depend d1 "
+ "JOIN pg_class c1 ON c1.oid = d1.objid "
+ "AND c1.relkind = 'm' "
+ "JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
+ "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
+ "AND d2.objid = r1.oid "
+ "AND d2.refobjid <> d1.objid "
+ "JOIN pg_class c2 ON c2.oid = d2.refobjid "
+ "AND c2.relkind IN ('m','v') "
+ "WHERE d1.classid = 'pg_class'::regclass "
+ "UNION "
+ "SELECT w.objid, d3.refobjid, c3.relkind "
+ "FROM w "
+ "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
+ "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
+ "AND d3.objid = r3.oid "
+ "AND d3.refobjid <> w.refobjid "
+ "JOIN pg_class c3 ON c3.oid = d3.refobjid "
+ "AND c3.relkind IN ('m','v') "
+ ") "
+ "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
+ "FROM w "
+ "WHERE refrelkind = 'm'");
-/*
- * guessConstraintInheritance:
- * In pre-8.4 databases, we can't tell for certain which constraints
- * are inherited. We assume a CHECK constraint is inherited if its name
- * matches the name of any constraint in the parent. Originally this code
- * tried to compare the expression texts, but that can fail for various
- * reasons --- for example, if the parent and child tables are in different
- * schemas, reverse-listing of function calls may produce different text
- * (schema-qualified or not) depending on search path.
- *
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+
+ i_classid = PQfnumber(res, "classid");
+ i_objid = PQfnumber(res, "objid");
+ i_refobjid = PQfnumber(res, "refobjid");
+
+ for (i = 0; i < ntups; i++)
+ {
+ CatalogId objId;
+ CatalogId refobjId;
+ DumpableObject *dobj;
+ DumpableObject *refdobj;
+ TableInfo *tbinfo;
+ TableInfo *reftbinfo;
+
+ objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
+ objId.oid = atooid(PQgetvalue(res, i, i_objid));
+ refobjId.tableoid = objId.tableoid;
+ refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
+
+ dobj = findObjectByCatalogId(objId);
+ if (dobj == NULL)
+ continue;
+
+ Assert(dobj->objType == DO_TABLE);
+ tbinfo = (TableInfo *) dobj;
+ Assert(tbinfo->relkind == RELKIND_MATVIEW);
+ dobj = (DumpableObject *) tbinfo->dataObj;
+ if (dobj == NULL)
+ continue;
+ Assert(dobj->objType == DO_REFRESH_MATVIEW);
+
+ refdobj = findObjectByCatalogId(refobjId);
+ if (refdobj == NULL)
+ continue;
+
+ Assert(refdobj->objType == DO_TABLE);
+ reftbinfo = (TableInfo *) refdobj;
+ Assert(reftbinfo->relkind == RELKIND_MATVIEW);
+ refdobj = (DumpableObject *) reftbinfo->dataObj;
+ if (refdobj == NULL)
+ continue;
+ Assert(refdobj->objType == DO_REFRESH_MATVIEW);
+
+ addObjectDependency(dobj, refdobj->dumpId);
+
+ if (!reftbinfo->relispopulated)
+ tbinfo->relispopulated = false;
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+}
+
+/*
+ * getTableDataFKConstraints -
+ * add dump-order dependencies reflecting foreign key constraints
+ *
+ * This code is executed only in a data-only dump --- in schema+data dumps
+ * we handle foreign key issues by not creating the FK constraints until
+ * after the data is loaded. In a data-only dump, however, we want to
+ * order the table data objects in such a way that a table's referenced
+ * tables are restored first. (In the presence of circular references or
+ * self-references this may be impossible; we'll detect and complain about
+ * that during the dependency sorting step.)
+ */
+static void
+getTableDataFKConstraints(void)
+{
+ DumpableObject **dobjs;
+ int numObjs;
+ int i;
+
+ /* Search through all the dumpable objects for FK constraints */
+ getDumpableObjects(&dobjs, &numObjs);
+ for (i = 0; i < numObjs; i++)
+ {
+ if (dobjs[i]->objType == DO_FK_CONSTRAINT)
+ {
+ ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
+ TableInfo *ftable;
+
+ /* Not interesting unless both tables are to be dumped */
+ if (cinfo->contable == NULL ||
+ cinfo->contable->dataObj == NULL)
+ continue;
+ ftable = findTableByOid(cinfo->confrelid);
+ if (ftable == NULL ||
+ ftable->dataObj == NULL)
+ continue;
+
+ /*
+ * Okay, make referencing table's TABLE_DATA object depend on the
+ * referenced table's TABLE_DATA object.
+ */
+ addObjectDependency(&cinfo->contable->dataObj->dobj,
+ ftable->dataObj->dobj.dumpId);
+ }
+ }
+ free(dobjs);
+}
+
+
+/*
+ * guessConstraintInheritance:
+ * In pre-8.4 databases, we can't tell for certain which constraints
+ * are inherited. We assume a CHECK constraint is inherited if its name
+ * matches the name of any constraint in the parent. Originally this code
+ * tried to compare the expression texts, but that can fail for various
+ * reasons --- for example, if the parent and child tables are in different
+ * schemas, reverse-listing of function calls may produce different text
+ * (schema-qualified or not) depending on search path.
+ *
* In 8.4 and up we can rely on the conislocal field to decide which
* constraints must be dumped; much safer.
*
PQExpBuffer dbQry = createPQExpBuffer();
PQExpBuffer delQry = createPQExpBuffer();
PQExpBuffer creaQry = createPQExpBuffer();
+ PGconn *conn = GetConnection(fout);
PGresult *res;
- int ntups;
int i_tableoid,
i_oid,
i_dba,
*tablespace;
uint32 frozenxid;
- datname = PQdb(g_conn);
+ datname = PQdb(conn);
if (g_verbose)
write_msg(NULL, "saving database definition\n");
appendStringLiteralAH(dbQry, datname, fout);
}
- res = ExecuteSqlQuery(fout, dbQry->data, PGRES_TUPLES_OK);
-
- ntups = PQntuples(res);
-
- if (ntups <= 0)
- {
- write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
- datname);
- exit_nicely();
- }
-
- if (ntups != 1)
- {
- write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
- ntups, datname);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
i_tableoid = PQfnumber(res, "tableoid");
i_oid = PQfnumber(res, "oid");
fmtId(datname));
if (strlen(encoding) > 0)
{
- appendPQExpBuffer(creaQry, " ENCODING = ");
+ appendPQExpBufferStr(creaQry, " ENCODING = ");
appendStringLiteralAH(creaQry, encoding, fout);
}
if (strlen(collate) > 0)
{
- appendPQExpBuffer(creaQry, " LC_COLLATE = ");
+ appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
appendStringLiteralAH(creaQry, collate, fout);
}
if (strlen(ctype) > 0)
{
- appendPQExpBuffer(creaQry, " LC_CTYPE = ");
+ appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
appendStringLiteralAH(creaQry, ctype, fout);
}
if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
appendPQExpBuffer(creaQry, " TABLESPACE = %s",
fmtId(tablespace));
- appendPQExpBuffer(creaQry, ";\n");
+ appendPQExpBufferStr(creaQry, ";\n");
if (binary_upgrade)
{
- appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
+ appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
"SET datfrozenxid = '%u'\n"
"WHERE datname = ",
frozenxid);
appendStringLiteralAH(creaQry, datname, fout);
- appendPQExpBuffer(creaQry, ";\n");
+ appendPQExpBufferStr(creaQry, ";\n");
}
"WHERE oid = %u;\n",
LargeObjectRelationId);
- lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
-
- if (PQntuples(lo_res) != 1)
- {
- write_msg(NULL, "dumpDatabase(): could not find pg_largeobject.relfrozenxid\n");
- exit_nicely();
- }
+ lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
- appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
+ appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
"SET relfrozenxid = '%u'\n"
"WHERE oid = %u;\n",
"WHERE oid = %u;\n",
LargeObjectMetadataRelationId);
- lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
-
- if (PQntuples(lo_res) != 1)
- {
- write_msg(NULL, "dumpDatabase(): could not find pg_largeobject_metadata.relfrozenxid\n");
- exit_nicely();
- }
+ lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
- appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
+ appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
"SET relfrozenxid = '%u'\n"
"WHERE oid = %u;\n",
*/
appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
appendStringLiteralAH(dbQry, comment, fout);
- appendPQExpBuffer(dbQry, ";\n");
+ appendPQExpBufferStr(dbQry, ";\n");
ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
dba, false, "COMMENT", SECTION_NONE,
{
PQExpBuffer seclabelQry = createPQExpBuffer();
- buildShSecLabelQuery(g_conn, "pg_database", dbCatId.oid, seclabelQry);
+ buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
res = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
resetPQExpBuffer(seclabelQry);
- emitShSecLabels(g_conn, res, seclabelQry, "DATABASE", datname);
+ emitShSecLabels(conn, res, seclabelQry, "DATABASE", datname);
if (strlen(seclabelQry->data))
ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
dba, false, "SECURITY LABEL", SECTION_NONE,
if (g_verbose)
write_msg(NULL, "saving encoding = %s\n", encname);
- appendPQExpBuffer(qry, "SET client_encoding = ");
+ appendPQExpBufferStr(qry, "SET client_encoding = ");
appendStringLiteralAH(qry, encname, AH);
- appendPQExpBuffer(qry, ";\n");
+ appendPQExpBufferStr(qry, ";\n");
ArchiveEntry(AH, nilCatalogId, createDumpId(),
"ENCODING", NULL, NULL, "",
" FROM pg_largeobject_metadata",
username_subquery);
else if (fout->remoteVersion >= 70100)
- appendPQExpBuffer(blobQry,
- "SELECT DISTINCT loid, NULL::oid, NULL::oid"
- " FROM pg_largeobject");
+ appendPQExpBufferStr(blobQry,
+ "SELECT DISTINCT loid, NULL::oid, NULL::oid"
+ " FROM pg_largeobject");
else
- appendPQExpBuffer(blobQry,
- "SELECT oid, NULL::oid, NULL::oid"
- " FROM pg_class WHERE relkind = 'l'");
+ appendPQExpBufferStr(blobQry,
+ "SELECT oid, NULL::oid, NULL::oid"
+ " FROM pg_class WHERE relkind = 'l'");
res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
binfo->rolname, false,
"BLOB", SECTION_PRE_DATA,
cquery->data, dquery->data, NULL,
- binfo->dobj.dependencies, binfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* set up tag for comment and/or ACL */
{
const char *blobQry;
const char *blobFetchQry;
+ PGconn *conn = GetConnection(fout);
PGresult *res;
char buf[LOBBUFSIZE];
int ntups;
blobOid = atooid(PQgetvalue(res, i, 0));
/* Open the BLOB */
- loFd = lo_open(g_conn, blobOid, INV_READ);
+ loFd = lo_open(conn, blobOid, INV_READ);
if (loFd == -1)
- {
- write_msg(NULL, "could not open large object %u: %s",
- blobOid, PQerrorMessage(g_conn));
- exit_nicely();
- }
+ exit_horribly(NULL, "could not open large object %u: %s",
+ blobOid, PQerrorMessage(conn));
StartBlob(fout, blobOid);
/* Now read it in chunks, sending data to archive */
do
{
- cnt = lo_read(g_conn, loFd, buf, LOBBUFSIZE);
+ cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
if (cnt < 0)
- {
- write_msg(NULL, "error reading large object %u: %s",
- blobOid, PQerrorMessage(g_conn));
- exit_nicely();
- }
+ exit_horribly(NULL, "error reading large object %u: %s",
+ blobOid, PQerrorMessage(conn));
WriteData(fout, buf, cnt);
} while (cnt > 0);
- lo_close(g_conn, loFd);
+ lo_close(conn, loFd);
EndBlob(fout, blobOid);
}
PQclear(res);
} while (ntups > 0);
- PQclear(res);
-
return 1;
}
Oid pg_type_oid)
{
PQExpBuffer upgrade_query = createPQExpBuffer();
- int ntups;
PGresult *upgrade_res;
Oid pg_type_array_oid;
- appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
+ appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
appendPQExpBuffer(upgrade_buffer,
"SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
pg_type_oid);
"WHERE pg_type.oid = '%u'::pg_catalog.oid;",
pg_type_oid);
- upgrade_res = ExecuteSqlQuery(fout, upgrade_query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(upgrade_res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, upgrade_query->data);
- exit_nicely();
- }
+ upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
if (OidIsValid(pg_type_array_oid))
{
- appendPQExpBuffer(upgrade_buffer,
+ appendPQExpBufferStr(upgrade_buffer,
"\n-- For binary upgrade, must preserve pg_type array oid\n");
appendPQExpBuffer(upgrade_buffer,
"SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
Oid pg_rel_oid)
{
PQExpBuffer upgrade_query = createPQExpBuffer();
- int ntups;
PGresult *upgrade_res;
Oid pg_type_oid;
bool toast_set = false;
"WHERE c.oid = '%u'::pg_catalog.oid;",
pg_rel_oid);
- upgrade_res = ExecuteSqlQuery(fout, upgrade_query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(upgrade_res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, upgrade_query->data);
- exit_nicely();
- }
+ upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
Oid pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
PQfnumber(upgrade_res, "trel")));
- appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
+ appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
appendPQExpBuffer(upgrade_buffer,
"SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
pg_type_toast_oid);
bool is_index)
{
PQExpBuffer upgrade_query = createPQExpBuffer();
- int ntups;
PGresult *upgrade_res;
Oid pg_class_reltoastrelid;
- Oid pg_class_reltoastidxid;
+ Oid pg_index_indexrelid;
appendPQExpBuffer(upgrade_query,
- "SELECT c.reltoastrelid, t.reltoastidxid "
+ "SELECT c.reltoastrelid, i.indexrelid "
"FROM pg_catalog.pg_class c LEFT JOIN "
- "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
+ "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
"WHERE c.oid = '%u'::pg_catalog.oid;",
pg_class_oid);
- upgrade_res = ExecuteSqlQuery(fout, upgrade_query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(upgrade_res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, upgrade_query->data);
- exit_nicely();
- }
+ upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
- pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid")));
+ pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
- appendPQExpBuffer(upgrade_buffer,
- "\n-- For binary upgrade, must preserve pg_class oids\n");
+ appendPQExpBufferStr(upgrade_buffer,
+ "\n-- For binary upgrade, must preserve pg_class oids\n");
if (!is_index)
{
/* every toast table has an index */
appendPQExpBuffer(upgrade_buffer,
"SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
- pg_class_reltoastidxid);
+ pg_index_indexrelid);
}
}
else
"SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
pg_class_oid);
- appendPQExpBuffer(upgrade_buffer, "\n");
+ appendPQExpBufferChar(upgrade_buffer, '\n');
PQclear(upgrade_res);
destroyPQExpBuffer(upgrade_query);
extobj = NULL;
}
if (extobj == NULL)
- {
- write_msg(NULL, "could not find parent extension for %s", objlabel);
- exit_nicely();
- }
+ exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
- appendPQExpBuffer(upgrade_buffer,
+ appendPQExpBufferStr(upgrade_buffer,
"\n-- For binary upgrade, handle extension membership the hard way\n");
appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
fmtId(extobj->name),
selectDumpableNamespace(&nsinfo[1]);
- g_namespaces = nsinfo;
- g_numNamespaces = *numNamespaces = 2;
+ *numNamespaces = 2;
return nsinfo;
}
PQclear(res);
destroyPQExpBuffer(query);
- g_namespaces = nsinfo;
- g_numNamespaces = *numNamespaces = ntups;
+ *numNamespaces = ntups;
return nsinfo;
}
* getNamespaces
*
* NB: for pre-7.3 source database, we use object OID to guess whether it's
- * a system object or not. In 7.3 and later there is no guessing.
+ * a system object or not. In 7.3 and later there is no guessing, and we
+ * don't use objoid at all.
*/
static NamespaceInfo *
findNamespace(Archive *fout, Oid nsoid, Oid objoid)
{
- int i;
+ NamespaceInfo *nsinfo;
if (fout->remoteVersion >= 70300)
{
- for (i = 0; i < g_numNamespaces; i++)
- {
- NamespaceInfo *nsinfo = &g_namespaces[i];
-
- if (nsoid == nsinfo->dobj.catId.oid)
- return nsinfo;
- }
- write_msg(NULL, "schema with OID %u does not exist\n", nsoid);
- exit_nicely();
+ nsinfo = findNamespaceByOid(nsoid);
}
else
{
- /* This code depends on the layout set up by getNamespaces. */
+ /* This code depends on the dummy objects set up by getNamespaces. */
+ Oid i;
+
if (objoid > g_last_builtin_oid)
i = 0; /* user object */
else
i = 1; /* system object */
- return &g_namespaces[i];
+ nsinfo = findNamespaceByOid(i);
}
- return NULL; /* keep compiler quiet */
+ if (nsinfo == NULL)
+ exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
+
+ return nsinfo;
}
/*
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
- appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, "
- "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
- "FROM pg_extension x "
- "JOIN pg_namespace n ON n.oid = x.extnamespace");
+ appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
+ "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
+ "FROM pg_extension x "
+ "JOIN pg_namespace n ON n.oid = x.extnamespace");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
int i_oid;
int i_typname;
int i_typnamespace;
+ int i_typacl;
int i_rolname;
int i_typinput;
int i_typoutput;
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
- if (fout->remoteVersion >= 80300)
+ if (fout->remoteVersion >= 90200)
+ {
+ appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
+ "typnamespace, typacl, "
+ "(%s typowner) AS rolname, "
+ "typinput::oid AS typinput, "
+ "typoutput::oid AS typoutput, typelem, typrelid, "
+ "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
+ "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
+ "typtype, typisdefined, "
+ "typname[0] = '_' AND typelem != 0 AND "
+ "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
+ "FROM pg_type",
+ username_subquery);
+ }
+ else if (fout->remoteVersion >= 80300)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
- "typnamespace, "
+ "typnamespace, '{=U}' AS typacl, "
"(%s typowner) AS rolname, "
"typinput::oid AS typinput, "
"typoutput::oid AS typoutput, typelem, typrelid, "
else if (fout->remoteVersion >= 70300)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
- "typnamespace, "
+ "typnamespace, '{=U}' AS typacl, "
"(%s typowner) AS rolname, "
"typinput::oid AS typinput, "
"typoutput::oid AS typoutput, typelem, typrelid, "
else if (fout->remoteVersion >= 70100)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
- "0::oid AS typnamespace, "
+ "0::oid AS typnamespace, '{=U}' AS typacl, "
"(%s typowner) AS rolname, "
"typinput::oid AS typinput, "
"typoutput::oid AS typoutput, typelem, typrelid, "
appendPQExpBuffer(query, "SELECT "
"(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
"oid, typname, "
- "0::oid AS typnamespace, "
+ "0::oid AS typnamespace, '{=U}' AS typacl, "
"(%s typowner) AS rolname, "
"typinput::oid AS typinput, "
"typoutput::oid AS typoutput, typelem, typrelid, "
i_oid = PQfnumber(res, "oid");
i_typname = PQfnumber(res, "typname");
i_typnamespace = PQfnumber(res, "typnamespace");
+ i_typacl = PQfnumber(res, "typacl");
i_rolname = PQfnumber(res, "rolname");
i_typinput = PQfnumber(res, "typinput");
i_typoutput = PQfnumber(res, "typoutput");
atooid(PQgetvalue(res, i, i_typnamespace)),
tyinfo[i].dobj.catId.oid);
tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
+ tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
/*
* If it's a base type, make a DumpableObject representing a shell
* definition of the type. We will need to dump that ahead of the I/O
- * functions for the type. Similarly, range types need a shell
+ * functions for the type. Similarly, range types need a shell
* definition in case they have a canonicalize function.
*
* Note: the shell type doesn't have a catId. You might think it
PGresult *res;
int ntups;
int i;
- PQExpBuffer query = createPQExpBuffer();
+ PQExpBuffer query;
CollInfo *collinfo;
int i_tableoid;
int i_oid;
return NULL;
}
+ query = createPQExpBuffer();
+
/*
* find all collations, including builtin collations; we filter out
* system-defined collations at dump-out time.
PGresult *res;
int ntups;
int i;
- PQExpBuffer query = createPQExpBuffer();
+ PQExpBuffer query;
ConvInfo *convinfo;
int i_tableoid;
int i_oid;
return NULL;
}
+ query = createPQExpBuffer();
+
/*
* find all conversions, including builtin conversions; we filter out
* system-defined conversions at dump-out time.
}
else if (fout->remoteVersion >= 70100)
{
- appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
- "0::oid AS opcnamespace, "
- "''::name AS rolname "
- "FROM pg_opclass");
+ appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
+ "0::oid AS opcnamespace, "
+ "''::name AS rolname "
+ "FROM pg_opclass");
}
else
{
- appendPQExpBuffer(query, "SELECT "
- "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
- "oid, opcname, "
- "0::oid AS opcnamespace, "
- "''::name AS rolname "
- "FROM pg_opclass");
+ appendPQExpBufferStr(query, "SELECT "
+ "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
+ "oid, opcname, "
+ "0::oid AS opcnamespace, "
+ "''::name AS rolname "
+ "FROM pg_opclass");
}
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
int i_proargtypes;
int i_rolname;
int i_aggacl;
+ int i_proiargs;
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
* rationale behind the filtering logic.
*/
- if (fout->remoteVersion >= 80200)
+ if (fout->remoteVersion >= 80400)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
"pronamespace AS aggnamespace, "
"pronargs, proargtypes, "
+ "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
"(%s proowner) AS rolname, "
"proacl AS aggacl "
"FROM pg_proc p "
"WHERE nspname = 'pg_catalog')",
username_subquery);
if (binary_upgrade && fout->remoteVersion >= 90100)
- appendPQExpBuffer(query,
- " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
- "classid = 'pg_proc'::regclass AND "
- "objid = p.oid AND "
- "refclassid = 'pg_extension'::regclass AND "
- "deptype = 'e')");
- appendPQExpBuffer(query, ")");
+ appendPQExpBufferStr(query,
+ " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+ "classid = 'pg_proc'::regclass AND "
+ "objid = p.oid AND "
+ "refclassid = 'pg_extension'::regclass AND "
+ "deptype = 'e')");
+ appendPQExpBufferChar(query, ')');
+ }
+ else if (fout->remoteVersion >= 80200)
+ {
+ appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
+ "pronamespace AS aggnamespace, "
+ "pronargs, proargtypes, "
+ "NULL::text AS proiargs,"
+ "(%s proowner) AS rolname, "
+ "proacl AS aggacl "
+ "FROM pg_proc p "
+ "WHERE proisagg AND ("
+ "pronamespace != "
+ "(SELECT oid FROM pg_namespace "
+ "WHERE nspname = 'pg_catalog'))",
+ username_subquery);
}
else if (fout->remoteVersion >= 70300)
{
"pronamespace AS aggnamespace, "
"CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
"proargtypes, "
+ "NULL::text AS proiargs, "
"(%s proowner) AS rolname, "
"proacl AS aggacl "
"FROM pg_proc "
"0::oid AS aggnamespace, "
"CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
"aggbasetype AS proargtypes, "
+ "NULL::text AS proiargs, "
"(%s aggowner) AS rolname, "
"'{=X}' AS aggacl "
"FROM pg_aggregate "
"0::oid AS aggnamespace, "
"CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
"aggbasetype AS proargtypes, "
+ "NULL::text AS proiargs, "
"(%s aggowner) AS rolname, "
"'{=X}' AS aggacl "
"FROM pg_aggregate "
i_proargtypes = PQfnumber(res, "proargtypes");
i_rolname = PQfnumber(res, "rolname");
i_aggacl = PQfnumber(res, "aggacl");
+ i_proiargs = PQfnumber(res, "proiargs");
for (i = 0; i < ntups; i++)
{
agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
+ agginfo[i].aggfn.proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
if (agginfo[i].aggfn.nargs == 0)
agginfo[i].aggfn.argtypes = NULL;
int i_proargtypes;
int i_prorettype;
int i_proacl;
+ int i_proiargs;
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
* doesn't have; otherwise we might not get creation ordering correct.
*/
- if (fout->remoteVersion >= 70300)
+ if (fout->remoteVersion >= 80400)
{
appendPQExpBuffer(query,
"SELECT tableoid, oid, proname, prolang, "
"pronargs, proargtypes, prorettype, proacl, "
"pronamespace, "
+ "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
"(%s proowner) AS rolname "
"FROM pg_proc p "
"WHERE NOT proisagg AND ("
"WHERE nspname = 'pg_catalog')",
username_subquery);
if (fout->remoteVersion >= 90200)
- appendPQExpBuffer(query,
- "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
- "WHERE classid = 'pg_proc'::regclass AND "
- "objid = p.oid AND deptype = 'i')");
+ appendPQExpBufferStr(query,
+ "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
+ "WHERE classid = 'pg_proc'::regclass AND "
+ "objid = p.oid AND deptype = 'i')");
if (binary_upgrade && fout->remoteVersion >= 90100)
- appendPQExpBuffer(query,
- "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
- "classid = 'pg_proc'::regclass AND "
- "objid = p.oid AND "
- "refclassid = 'pg_extension'::regclass AND "
- "deptype = 'e')");
- appendPQExpBuffer(query, ")");
+ appendPQExpBufferStr(query,
+ "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+ "classid = 'pg_proc'::regclass AND "
+ "objid = p.oid AND "
+ "refclassid = 'pg_extension'::regclass AND "
+ "deptype = 'e')");
+ appendPQExpBufferChar(query, ')');
+ }
+ else if (fout->remoteVersion >= 70300)
+ {
+ appendPQExpBuffer(query,
+ "SELECT tableoid, oid, proname, prolang, "
+ "pronargs, proargtypes, prorettype, proacl, "
+ "pronamespace, "
+ "NULL::text AS proiargs,"
+ "(%s proowner) AS rolname "
+ "FROM pg_proc p "
+ "WHERE NOT proisagg AND ("
+ "pronamespace != "
+ "(SELECT oid FROM pg_namespace "
+ "WHERE nspname = 'pg_catalog'))",
+ username_subquery);
}
else if (fout->remoteVersion >= 70100)
{
"pronargs, proargtypes, prorettype, "
"'{=X}' AS proacl, "
"0::oid AS pronamespace, "
+ "NULL::text AS proiargs,"
"(%s proowner) AS rolname "
"FROM pg_proc "
"WHERE pg_proc.oid > '%u'::oid",
"pronargs, proargtypes, prorettype, "
"'{=X}' AS proacl, "
"0::oid AS pronamespace, "
+ "NULL::text AS proiargs,"
"(%s proowner) AS rolname "
"FROM pg_proc "
"where pg_proc.oid > '%u'::oid",
*numFuncs = ntups;
- finfo = (FuncInfo *) pg_calloc(ntups, sizeof(FuncInfo));
+ finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
i_tableoid = PQfnumber(res, "tableoid");
i_oid = PQfnumber(res, "oid");
i_proargtypes = PQfnumber(res, "proargtypes");
i_prorettype = PQfnumber(res, "prorettype");
i_proacl = PQfnumber(res, "proacl");
+ i_proiargs = PQfnumber(res, "proiargs");
for (i = 0; i < ntups; i++)
{
finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
+ finfo[i].proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
if (finfo[i].nargs == 0)
int i_toastoid;
int i_toastfrozenxid;
int i_relpersistence;
+ int i_relispopulated;
+ int i_relreplident;
int i_owning_tab;
int i_owning_col;
int i_reltablespace;
int i_reloptions;
+ int i_checkoption;
int i_toastreloptions;
int i_reloftype;
+ int i_relpages;
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
/*
- * Find all the tables (including views and sequences).
+ * Find all the tables and table-like objects.
*
* We include system catalogs, so that we can work if a user table is
* defined to inherit from a system catalog (pretty weird, but...)
*
- * We ignore tables that are not type 'r' (ordinary relation), 'S'
- * (sequence), 'v' (view), or 'c' (composite type).
+ * We ignore relations that are not ordinary tables, sequences, views,
+ * materialized views, composite types, or foreign tables.
*
* Composite-type table entries won't be dumped as such, but we have to
* make a DumpableObject for them so that we can track dependencies of the
* we cannot correctly identify inherited columns, owned sequences, etc.
*/
- if (fout->remoteVersion >= 90100)
+ if (fout->remoteVersion >= 90400)
{
/*
* Left join to pick up dependency info linking sequences to their
"c.relhasindex, c.relhasrules, c.relhasoids, "
"c.relfrozenxid, tc.oid AS toid, "
"tc.relfrozenxid AS tfrozenxid, "
- "c.relpersistence, "
+ "c.relpersistence, c.relispopulated, "
+ "c.relreplident, c.relpages, "
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
- "array_to_string(c.reloptions, ', ') AS reloptions, "
+ "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
+ "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
+ "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"d.objsubid = 0 AND "
"d.refclassid = c.tableoid AND d.deptype = 'a') "
"LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
- "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c') "
+ "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
"ORDER BY c.oid",
username_subquery,
RELKIND_SEQUENCE,
RELKIND_RELATION, RELKIND_SEQUENCE,
RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
- RELKIND_FOREIGN_TABLE);
+ RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
}
- else if (fout->remoteVersion >= 90000)
+ else if (fout->remoteVersion >= 90300)
{
/*
* Left join to pick up dependency info linking sequences to their
"c.relhasindex, c.relhasrules, c.relhasoids, "
"c.relfrozenxid, tc.oid AS toid, "
"tc.relfrozenxid AS tfrozenxid, "
- "'p' AS relpersistence, "
+ "c.relpersistence, c.relispopulated, "
+ "'d' AS relreplident, c.relpages, "
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
- "array_to_string(c.reloptions, ', ') AS reloptions, "
+ "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
+ "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
+ "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
"array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"d.objsubid = 0 AND "
"d.refclassid = c.tableoid AND d.deptype = 'a') "
"LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
- "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
+ "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
"ORDER BY c.oid",
username_subquery,
RELKIND_SEQUENCE,
RELKIND_RELATION, RELKIND_SEQUENCE,
- RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
+ RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
+ RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
}
- else if (fout->remoteVersion >= 80400)
+ else if (fout->remoteVersion >= 90100)
{
/*
* Left join to pick up dependency info linking sequences to their
"c.relhasindex, c.relhasrules, c.relhasoids, "
"c.relfrozenxid, tc.oid AS toid, "
"tc.relfrozenxid AS tfrozenxid, "
- "'p' AS relpersistence, "
- "NULL AS reloftype, "
+ "c.relpersistence, 't' as relispopulated, "
+ "'d' AS relreplident, c.relpages, "
+ "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"d.objsubid = 0 AND "
"d.refclassid = c.tableoid AND d.deptype = 'a') "
"LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
- "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
+ "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
"ORDER BY c.oid",
username_subquery,
RELKIND_SEQUENCE,
RELKIND_RELATION, RELKIND_SEQUENCE,
- RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
+ RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
+ RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
}
- else if (fout->remoteVersion >= 80200)
+ else if (fout->remoteVersion >= 90000)
{
/*
* Left join to pick up dependency info linking sequences to their
"SELECT c.tableoid, c.oid, c.relname, "
"c.relacl, c.relkind, c.relnamespace, "
"(%s c.relowner) AS rolname, "
- "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
+ "c.relchecks, c.relhastriggers, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
"c.relfrozenxid, tc.oid AS toid, "
"tc.relfrozenxid AS tfrozenxid, "
- "'p' AS relpersistence, "
- "NULL AS reloftype, "
+ "'p' AS relpersistence, 't' as relispopulated, "
+ "'d' AS relreplident, c.relpages, "
+ "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"array_to_string(c.reloptions, ', ') AS reloptions, "
- "NULL AS toast_reloptions "
+ "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
RELKIND_RELATION, RELKIND_SEQUENCE,
RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
}
- else if (fout->remoteVersion >= 80000)
+ else if (fout->remoteVersion >= 80400)
{
/*
* Left join to pick up dependency info linking sequences to their
- * owning column, if any
+ * owning column, if any (note this dependency is AUTO as of 8.2)
*/
appendPQExpBuffer(query,
- "SELECT c.tableoid, c.oid, relname, "
- "relacl, relkind, relnamespace, "
- "(%s relowner) AS rolname, "
- "relchecks, (reltriggers <> 0) AS relhastriggers, "
- "relhasindex, relhasrules, relhasoids, "
- "0 AS relfrozenxid, "
- "0 AS toid, "
- "0 AS tfrozenxid, "
- "'p' AS relpersistence, "
- "NULL AS reloftype, "
- "d.refobjid AS owning_tab, "
- "d.refobjsubid AS owning_col, "
- "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
- "NULL AS reloptions, "
- "NULL AS toast_reloptions "
+ "SELECT c.tableoid, c.oid, c.relname, "
+ "c.relacl, c.relkind, c.relnamespace, "
+ "(%s c.relowner) AS rolname, "
+ "c.relchecks, c.relhastriggers, "
+ "c.relhasindex, c.relhasrules, c.relhasoids, "
+ "c.relfrozenxid, tc.oid AS toid, "
+ "tc.relfrozenxid AS tfrozenxid, "
+ "'p' AS relpersistence, 't' as relispopulated, "
+ "'d' AS relreplident, c.relpages, "
+ "NULL AS reloftype, "
+ "d.refobjid AS owning_tab, "
+ "d.refobjsubid AS owning_col, "
+ "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
+ "array_to_string(c.reloptions, ', ') AS reloptions, "
+ "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
+ "FROM pg_class c "
+ "LEFT JOIN pg_depend d ON "
+ "(c.relkind = '%c' AND "
+ "d.classid = c.tableoid AND d.objid = c.oid AND "
+ "d.objsubid = 0 AND "
+ "d.refclassid = c.tableoid AND d.deptype = 'a') "
+ "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
+ "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
+ "ORDER BY c.oid",
+ username_subquery,
+ RELKIND_SEQUENCE,
+ RELKIND_RELATION, RELKIND_SEQUENCE,
+ RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
+ }
+ else if (fout->remoteVersion >= 80200)
+ {
+ /*
+ * Left join to pick up dependency info linking sequences to their
+ * owning column, if any (note this dependency is AUTO as of 8.2)
+ */
+ appendPQExpBuffer(query,
+ "SELECT c.tableoid, c.oid, c.relname, "
+ "c.relacl, c.relkind, c.relnamespace, "
+ "(%s c.relowner) AS rolname, "
+ "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
+ "c.relhasindex, c.relhasrules, c.relhasoids, "
+ "c.relfrozenxid, tc.oid AS toid, "
+ "tc.relfrozenxid AS tfrozenxid, "
+ "'p' AS relpersistence, 't' as relispopulated, "
+ "'d' AS relreplident, c.relpages, "
+ "NULL AS reloftype, "
+ "d.refobjid AS owning_tab, "
+ "d.refobjsubid AS owning_col, "
+ "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
+ "array_to_string(c.reloptions, ', ') AS reloptions, "
+ "NULL AS toast_reloptions "
+ "FROM pg_class c "
+ "LEFT JOIN pg_depend d ON "
+ "(c.relkind = '%c' AND "
+ "d.classid = c.tableoid AND d.objid = c.oid AND "
+ "d.objsubid = 0 AND "
+ "d.refclassid = c.tableoid AND d.deptype = 'a') "
+ "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
+ "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
+ "ORDER BY c.oid",
+ username_subquery,
+ RELKIND_SEQUENCE,
+ RELKIND_RELATION, RELKIND_SEQUENCE,
+ RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
+ }
+ else if (fout->remoteVersion >= 80000)
+ {
+ /*
+ * Left join to pick up dependency info linking sequences to their
+ * owning column, if any
+ */
+ appendPQExpBuffer(query,
+ "SELECT c.tableoid, c.oid, relname, "
+ "relacl, relkind, relnamespace, "
+ "(%s relowner) AS rolname, "
+ "relchecks, (reltriggers <> 0) AS relhastriggers, "
+ "relhasindex, relhasrules, relhasoids, "
+ "0 AS relfrozenxid, "
+ "0 AS toid, "
+ "0 AS tfrozenxid, "
+ "'p' AS relpersistence, 't' as relispopulated, "
+ "'d' AS relreplident, relpages, "
+ "NULL AS reloftype, "
+ "d.refobjid AS owning_tab, "
+ "d.refobjsubid AS owning_col, "
+ "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
+ "NULL AS reloptions, "
+ "NULL AS toast_reloptions "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
"0 AS relfrozenxid, "
"0 AS toid, "
"0 AS tfrozenxid, "
- "'p' AS relpersistence, "
+ "'p' AS relpersistence, 't' as relispopulated, "
+ "'d' AS relreplident, relpages, "
"NULL AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"0 AS relfrozenxid, "
"0 AS toid, "
"0 AS tfrozenxid, "
- "'p' AS relpersistence, "
+ "'p' AS relpersistence, 't' as relispopulated, "
+ "'d' AS relreplident, relpages, "
"NULL AS reloftype, "
"NULL::oid AS owning_tab, "
"NULL::int4 AS owning_col, "
"0 AS relfrozenxid, "
"0 AS toid, "
"0 AS tfrozenxid, "
- "'p' AS relpersistence, "
+ "'p' AS relpersistence, 't' as relispopulated, "
+ "'d' AS relreplident, relpages, "
"NULL AS reloftype, "
"NULL::oid AS owning_tab, "
"NULL::int4 AS owning_col, "
"0 as relfrozenxid, "
"0 AS toid, "
"0 AS tfrozenxid, "
- "'p' AS relpersistence, "
+ "'p' AS relpersistence, 't' as relispopulated, "
+ "'d' AS relreplident, 0 AS relpages, "
"NULL AS reloftype, "
"NULL::oid AS owning_tab, "
"NULL::int4 AS owning_col, "
* only one, because we don't yet know which tables might be inheritance
* ancestors of the target table.
*/
- tblinfo = (TableInfo *) pg_calloc(ntups, sizeof(TableInfo));
+ tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
i_reltableoid = PQfnumber(res, "tableoid");
i_reloid = PQfnumber(res, "oid");
i_toastoid = PQfnumber(res, "toid");
i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
i_relpersistence = PQfnumber(res, "relpersistence");
+ i_relispopulated = PQfnumber(res, "relispopulated");
+ i_relreplident = PQfnumber(res, "relreplident");
+ i_relpages = PQfnumber(res, "relpages");
i_owning_tab = PQfnumber(res, "owning_tab");
i_owning_col = PQfnumber(res, "owning_col");
i_reltablespace = PQfnumber(res, "reltablespace");
i_reloptions = PQfnumber(res, "reloptions");
+ i_checkoption = PQfnumber(res, "checkoption");
i_toastreloptions = PQfnumber(res, "toast_reloptions");
i_reloftype = PQfnumber(res, "reloftype");
* applied to other things too.
*/
resetPQExpBuffer(query);
- appendPQExpBuffer(query, "SET statement_timeout = ");
- appendStringLiteralConn(query, lockWaitTimeout, g_conn);
+ appendPQExpBufferStr(query, "SET statement_timeout = ");
+ appendStringLiteralConn(query, lockWaitTimeout, GetConnection(fout));
ExecuteSqlStatement(fout, query->data);
}
tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
+ tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
+ tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
+ tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
}
tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
+ if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
+ tblinfo[i].checkoption = NULL;
+ else
+ tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
/* other fields were zeroed above */
selectDumpableTable(&tblinfo[i]);
tblinfo[i].interesting = tblinfo[i].dobj.dump;
+ tblinfo[i].postponed_def = false; /* might get set during sort */
+
/*
* Read-lock target tables to make sure they aren't DROPPED or altered
* in schema before we get around to dumping them.
resetPQExpBuffer(query);
appendPQExpBuffer(query,
"LOCK TABLE %s IN ACCESS SHARE MODE",
- fmtQualifiedId(fout,
+ fmtQualifiedId(fout->remoteVersion,
tblinfo[i].dobj.namespace->dobj.name,
- tblinfo[i].dobj.name));
+ tblinfo[i].dobj.name));
ExecuteSqlStatement(fout, query->data);
}
PQclear(res);
+ destroyPQExpBuffer(query);
+
+ return tblinfo;
+}
+
+/*
+ * getOwnedSeqs
+ * identify owned sequences and mark them as dumpable if owning table is
+ *
+ * We used to do this in getTables(), but it's better to do it after the
+ * index used by findTableByOid() has been set up.
+ */
+void
+getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
+{
+ int i;
+
/*
* Force sequences that are "owned" by table columns to be dumped whenever
* their owning table is being dumped.
*/
- for (i = 0; i < ntups; i++)
+ for (i = 0; i < numTables; i++)
{
TableInfo *seqinfo = &tblinfo[i];
- int j;
+ TableInfo *owning_tab;
if (!OidIsValid(seqinfo->owning_tab))
continue; /* not an owned sequence */
if (seqinfo->dobj.dump)
continue; /* no need to search */
-
- /* can't use findTableByOid yet, unfortunately */
- for (j = 0; j < ntups; j++)
+ owning_tab = findTableByOid(seqinfo->owning_tab);
+ if (owning_tab && owning_tab->dobj.dump)
{
- if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
- {
- if (tblinfo[j].dobj.dump)
- {
- seqinfo->interesting = true;
- seqinfo->dobj.dump = true;
- }
- break;
- }
+ seqinfo->interesting = true;
+ seqinfo->dobj.dump = true;
}
}
-
- destroyPQExpBuffer(query);
-
- return tblinfo;
}
/*
/* find all the inheritance information */
- appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
+ appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
i_indnkeys,
i_indkey,
i_indisclustered,
+ i_indisreplident,
i_contype,
i_conname,
i_condeferrable,
i_conoid,
i_condef,
i_tablespace,
- i_options;
+ i_options,
+ i_relpages;
int ntups;
for (i = 0; i < numTables; i++)
{
TableInfo *tbinfo = &tblinfo[i];
- /* Only plain tables have indexes */
- if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
+ /* Only plain tables and materialized views have indexes. */
+ if (tbinfo->relkind != RELKIND_RELATION &&
+ tbinfo->relkind != RELKIND_MATVIEW)
+ continue;
+ if (!tbinfo->hasindex)
continue;
/* Ignore indexes of tables not to be dumped */
* is not.
*/
resetPQExpBuffer(query);
- if (fout->remoteVersion >= 90000)
+ if (fout->remoteVersion >= 90400)
+ {
+ /*
+ * the test on indisready is necessary in 9.2, and harmless in
+ * earlier/later versions
+ */
+ appendPQExpBuffer(query,
+ "SELECT t.tableoid, t.oid, "
+ "t.relname AS indexname, "
+ "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
+ "t.relnatts AS indnkeys, "
+ "i.indkey, i.indisclustered, "
+ "i.indisreplident, t.relpages, "
+ "c.contype, c.conname, "
+ "c.condeferrable, c.condeferred, "
+ "c.tableoid AS contableoid, "
+ "c.oid AS conoid, "
+ "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
+ "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
+ "array_to_string(t.reloptions, ', ') AS options "
+ "FROM pg_catalog.pg_index i "
+ "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
+ "LEFT JOIN pg_catalog.pg_constraint c "
+ "ON (i.indrelid = c.conrelid AND "
+ "i.indexrelid = c.conindid AND "
+ "c.contype IN ('p','u','x')) "
+ "WHERE i.indrelid = '%u'::pg_catalog.oid "
+ "AND i.indisvalid AND i.indisready "
+ "ORDER BY indexname",
+ tbinfo->dobj.catId.oid);
+ }
+ else if (fout->remoteVersion >= 90000)
{
+ /*
+ * the test on indisready is necessary in 9.2, and harmless in
+ * earlier/later versions
+ */
appendPQExpBuffer(query,
"SELECT t.tableoid, t.oid, "
"t.relname AS indexname, "
"pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
"t.relnatts AS indnkeys, "
"i.indkey, i.indisclustered, "
+ "false AS indisreplident, t.relpages, "
"c.contype, c.conname, "
"c.condeferrable, c.condeferred, "
"c.tableoid AS contableoid, "
"i.indexrelid = c.conindid AND "
"c.contype IN ('p','u','x')) "
"WHERE i.indrelid = '%u'::pg_catalog.oid "
+ "AND i.indisvalid AND i.indisready "
"ORDER BY indexname",
tbinfo->dobj.catId.oid);
}
"pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
"t.relnatts AS indnkeys, "
"i.indkey, i.indisclustered, "
+ "false AS indisreplident, t.relpages, "
"c.contype, c.conname, "
"c.condeferrable, c.condeferred, "
"c.tableoid AS contableoid, "
"ON (d.refclassid = c.tableoid "
"AND d.refobjid = c.oid) "
"WHERE i.indrelid = '%u'::pg_catalog.oid "
+ "AND i.indisvalid "
"ORDER BY indexname",
tbinfo->dobj.catId.oid);
}
"pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
"t.relnatts AS indnkeys, "
"i.indkey, i.indisclustered, "
+ "false AS indisreplident, t.relpages, "
"c.contype, c.conname, "
"c.condeferrable, c.condeferred, "
"c.tableoid AS contableoid, "
"pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
"t.relnatts AS indnkeys, "
"i.indkey, i.indisclustered, "
+ "false AS indisreplident, t.relpages, "
"c.contype, c.conname, "
"c.condeferrable, c.condeferred, "
"c.tableoid AS contableoid, "
"pg_get_indexdef(i.indexrelid) AS indexdef, "
"t.relnatts AS indnkeys, "
"i.indkey, false AS indisclustered, "
+ "false AS indisreplident, t.relpages, "
"CASE WHEN i.indisprimary THEN 'p'::char "
"ELSE '0'::char END AS contype, "
"t.relname AS conname, "
"pg_get_indexdef(i.indexrelid) AS indexdef, "
"t.relnatts AS indnkeys, "
"i.indkey, false AS indisclustered, "
+ "false AS indisreplident, t.relpages, "
"CASE WHEN i.indisprimary THEN 'p'::char "
"ELSE '0'::char END AS contype, "
"t.relname AS conname, "
i_indnkeys = PQfnumber(res, "indnkeys");
i_indkey = PQfnumber(res, "indkey");
i_indisclustered = PQfnumber(res, "indisclustered");
+ i_indisreplident = PQfnumber(res, "indisreplident");
+ i_relpages = PQfnumber(res, "relpages");
i_contype = PQfnumber(res, "contype");
i_conname = PQfnumber(res, "conname");
i_condeferrable = PQfnumber(res, "condeferrable");
parseOidArray(PQgetvalue(res, j, i_indkey),
indxinfo[j].indkeys, INDEX_MAX_KEYS);
indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
+ indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
+ indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
contype = *(PQgetvalue(res, j, i_contype));
if (contype == 'p' || contype == 'u' || contype == 'x')
for (i = 0; i < ntups; i++)
{
- bool validated = PQgetvalue(res, i, 4)[0] == 't';
+ bool validated = PQgetvalue(res, i, 4)[0] == 't';
constrinfo[i].dobj.objType = DO_CONSTRAINT;
constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
/*
* Make the domain depend on the constraint, ensuring it won't be
- * output till any constraint dependencies are OK. If the constraint
+ * output till any constraint dependencies are OK. If the constraint
* has not been validated, it's going to be dumped after the domain
* anyway, so this doesn't matter.
*/
if (fout->remoteVersion >= 80300)
{
- appendPQExpBuffer(query, "SELECT "
- "tableoid, oid, rulename, "
- "ev_class AS ruletable, ev_type, is_instead, "
- "ev_enabled "
- "FROM pg_rewrite "
- "ORDER BY oid");
+ appendPQExpBufferStr(query, "SELECT "
+ "tableoid, oid, rulename, "
+ "ev_class AS ruletable, ev_type, is_instead, "
+ "ev_enabled "
+ "FROM pg_rewrite "
+ "ORDER BY oid");
}
else if (fout->remoteVersion >= 70100)
{
- appendPQExpBuffer(query, "SELECT "
- "tableoid, oid, rulename, "
- "ev_class AS ruletable, ev_type, is_instead, "
- "'O'::char AS ev_enabled "
- "FROM pg_rewrite "
- "ORDER BY oid");
+ appendPQExpBufferStr(query, "SELECT "
+ "tableoid, oid, rulename, "
+ "ev_class AS ruletable, ev_type, is_instead, "
+ "'O'::char AS ev_enabled "
+ "FROM pg_rewrite "
+ "ORDER BY oid");
}
else
{
- appendPQExpBuffer(query, "SELECT "
- "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
- "oid, rulename, "
- "ev_class AS ruletable, ev_type, is_instead, "
- "'O'::char AS ev_enabled "
- "FROM pg_rewrite "
- "ORDER BY oid");
+ appendPQExpBufferStr(query, "SELECT "
+ "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
+ "oid, rulename, "
+ "ev_class AS ruletable, ev_type, is_instead, "
+ "'O'::char AS ev_enabled "
+ "FROM pg_rewrite "
+ "ORDER BY oid");
}
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
ruleinfo[i].ruletable = findTableByOid(ruletableoid);
if (ruleinfo[i].ruletable == NULL)
- {
- write_msg(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
- ruletableoid,
- ruleinfo[i].dobj.catId.oid);
- exit_nicely();
- }
+ exit_horribly(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
+ ruletableoid, ruleinfo[i].dobj.catId.oid);
ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
if (ruleinfo[i].ruletable)
{
/*
- * If the table is a view, force its ON SELECT rule to be sorted
- * before the view itself --- this ensures that any dependencies
- * for the rule affect the table's positioning. Other rules are
- * forced to appear after their table.
+ * If the table is a view or materialized view, force its ON
+ * SELECT rule to be sorted before the view itself --- this
+ * ensures that any dependencies for the rule affect the table's
+ * positioning. Other rules are forced to appear after their
+ * table.
*/
- if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
+ if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
+ ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
{
addObjectDependency(&ruleinfo[i].ruletable->dobj,
}
else
ruleinfo[i].separate = true;
+
+ /*
+ * If we're forced to break a dependency loop by dumping a view as a
+ * table and separate _RETURN rule, we'll move the view's reloptions
+ * to the rule. (This is necessary because tables and views have
+ * different valid reloptions, so we can't apply the options until the
+ * backend knows it's a view.) Otherwise the rule's reloptions stay
+ * NULL.
+ */
+ ruleinfo[i].reloptions = NULL;
}
PQclear(res);
if (OidIsValid(tginfo[j].tgconstrrelid))
{
if (PQgetisnull(res, j, i_tgconstrrelname))
- {
- write_msg(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
- tginfo[j].dobj.name, tbinfo->dobj.name,
- tginfo[j].tgconstrrelid);
- exit_nicely();
- }
+ exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
+ tginfo[j].dobj.name,
+ tbinfo->dobj.name,
+ tginfo[j].tgconstrrelid);
tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
}
else
destroyPQExpBuffer(query);
}
+/*
+ * getEventTriggers
+ * get information about event triggers
+ */
+EventTriggerInfo *
+getEventTriggers(Archive *fout, int *numEventTriggers)
+{
+ int i;
+ PQExpBuffer query;
+ PGresult *res;
+ EventTriggerInfo *evtinfo;
+ int i_tableoid,
+ i_oid,
+ i_evtname,
+ i_evtevent,
+ i_evtowner,
+ i_evttags,
+ i_evtfname,
+ i_evtenabled;
+ int ntups;
+
+ /* Before 9.3, there are no event triggers */
+ if (fout->remoteVersion < 90300)
+ {
+ *numEventTriggers = 0;
+ return NULL;
+ }
+
+ query = createPQExpBuffer();
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(fout, "pg_catalog");
+
+ appendPQExpBuffer(query,
+ "SELECT e.tableoid, e.oid, evtname, evtenabled, "
+ "evtevent, (%s evtowner) AS evtowner, "
+ "array_to_string(array("
+ "select quote_literal(x) "
+ " from unnest(evttags) as t(x)), ', ') as evttags, "
+ "e.evtfoid::regproc as evtfname "
+ "FROM pg_event_trigger e "
+ "ORDER BY e.oid",
+ username_subquery);
+
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+
+ *numEventTriggers = ntups;
+
+ evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_evtname = PQfnumber(res, "evtname");
+ i_evtevent = PQfnumber(res, "evtevent");
+ i_evtowner = PQfnumber(res, "evtowner");
+ i_evttags = PQfnumber(res, "evttags");
+ i_evtfname = PQfnumber(res, "evtfname");
+ i_evtenabled = PQfnumber(res, "evtenabled");
+
+ for (i = 0; i < ntups; i++)
+ {
+ evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
+ evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&evtinfo[i].dobj);
+ evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
+ evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
+ evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
+ evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
+ evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
+ evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
+ evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return evtinfo;
+}
+
/*
* getProcLangs
* get basic information about every procedural language in the system
else if (fout->remoteVersion >= 70100)
{
/* No clear notion of an owner at all before 7.4 ... */
- appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
- "WHERE lanispl "
- "ORDER BY oid");
+ appendPQExpBufferStr(query, "SELECT tableoid, oid, * FROM pg_language "
+ "WHERE lanispl "
+ "ORDER BY oid");
}
else
{
- appendPQExpBuffer(query, "SELECT "
- "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
- "oid, * FROM pg_language "
- "WHERE lanispl "
- "ORDER BY oid");
+ appendPQExpBufferStr(query, "SELECT "
+ "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
+ "oid, * FROM pg_language "
+ "WHERE lanispl "
+ "ORDER BY oid");
}
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
if (fout->remoteVersion >= 80400)
{
- appendPQExpBuffer(query, "SELECT tableoid, oid, "
- "castsource, casttarget, castfunc, castcontext, "
- "castmethod "
- "FROM pg_cast ORDER BY 3,4");
+ appendPQExpBufferStr(query, "SELECT tableoid, oid, "
+ "castsource, casttarget, castfunc, castcontext, "
+ "castmethod "
+ "FROM pg_cast ORDER BY 3,4");
}
else if (fout->remoteVersion >= 70300)
{
- appendPQExpBuffer(query, "SELECT tableoid, oid, "
- "castsource, casttarget, castfunc, castcontext, "
+ appendPQExpBufferStr(query, "SELECT tableoid, oid, "
+ "castsource, casttarget, castfunc, castcontext, "
"CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
- "FROM pg_cast ORDER BY 3,4");
+ "FROM pg_cast ORDER BY 3,4");
}
else
{
- appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
- "t1.oid AS castsource, t2.oid AS casttarget, "
- "p.oid AS castfunc, 'e' AS castcontext, "
- "'f' AS castmethod "
- "FROM pg_type t1, pg_type t2, pg_proc p "
- "WHERE p.pronargs = 1 AND "
- "p.proargtypes[0] = t1.oid AND "
- "p.prorettype = t2.oid AND p.proname = t2.typname "
- "ORDER BY 3,4");
+ appendPQExpBufferStr(query, "SELECT 0 AS tableoid, p.oid, "
+ "t1.oid AS castsource, t2.oid AS casttarget, "
+ "p.oid AS castfunc, 'e' AS castcontext, "
+ "'f' AS castmethod "
+ "FROM pg_type t1, pg_type t2, pg_proc p "
+ "WHERE p.pronargs = 1 AND "
+ "p.proargtypes[0] = t1.oid AND "
+ "p.prorettype = t2.oid AND p.proname = t2.typname "
+ "ORDER BY 3,4");
}
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
"pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
"array_to_string(a.attoptions, ', ') AS attoptions, "
"CASE WHEN a.attcollation <> t.typcollation "
- "THEN a.attcollation ELSE 0 END AS attcollation, "
+ "THEN a.attcollation ELSE 0 END AS attcollation, "
"pg_catalog.array_to_string(ARRAY("
"SELECT pg_catalog.quote_ident(option_name) || "
"' ' || pg_catalog.quote_literal(option_value) "
- "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
+ "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
"ORDER BY option_name"
"), E',\n ') AS attfdwoptions "
"FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
"pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
"array_to_string(a.attoptions, ', ') AS attoptions, "
"CASE WHEN a.attcollation <> t.typcollation "
- "THEN a.attcollation ELSE 0 END AS attcollation, "
+ "THEN a.attcollation ELSE 0 END AS attcollation, "
"NULL AS attfdwoptions "
"FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
"ON a.atttypid = t.oid "
for (j = 0; j < ntups; j++)
{
if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
- {
- write_msg(NULL, "invalid column numbering in table \"%s\"\n",
- tbinfo->dobj.name);
- exit_nicely();
- }
+ exit_horribly(NULL,
+ "invalid column numbering in table \"%s\"\n",
+ tbinfo->dobj.name);
tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
adnum = atoi(PQgetvalue(res, j, 2));
if (adnum <= 0 || adnum > ntups)
- {
- write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
- adnum, tbinfo->dobj.name);
- exit_nicely();
- }
+ exit_horribly(NULL,
+ "invalid adnum value %d for table \"%s\"\n",
+ adnum, tbinfo->dobj.name);
/*
* dropped columns shouldn't have defaults, but just in case,
/*
* Defaults on a VIEW must always be dumped as separate ALTER
* TABLE commands. Defaults on regular tables are dumped as
- * part of the CREATE TABLE if possible, which it won't be
- * if the column is not going to be emitted explicitly.
+ * part of the CREATE TABLE if possible, which it won't be if
+ * the column is not going to be emitted explicitly.
*/
if (tbinfo->relkind == RELKIND_VIEW)
{
else
{
attrdefs[j].separate = false;
+
/*
* Mark the default as needing to appear before the table,
* so that any dependencies it has must be emitted before
if (fout->remoteVersion >= 90200)
{
/*
- * conisonly and convalidated are new in 9.2 (actually, the latter
- * is there in 9.1, but it wasn't ever false for check constraints
- * until 9.2).
+ * convalidated is new in 9.2 (actually, it is there in 9.1,
+ * but it wasn't ever false for check constraints until 9.2).
*/
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
"pg_catalog.pg_get_constraintdef(oid) AS consrc, "
- "conislocal, convalidated, conisonly "
+ "conislocal, convalidated "
"FROM pg_catalog.pg_constraint "
"WHERE conrelid = '%u'::pg_catalog.oid "
" AND contype = 'c' "
}
else if (fout->remoteVersion >= 80400)
{
+ /* conislocal is new in 8.4 */
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
"pg_catalog.pg_get_constraintdef(oid) AS consrc, "
- "conislocal, true AS convalidated, "
- "false as conisonly "
+ "conislocal, true AS convalidated "
"FROM pg_catalog.pg_constraint "
"WHERE conrelid = '%u'::pg_catalog.oid "
" AND contype = 'c' "
{
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
"pg_catalog.pg_get_constraintdef(oid) AS consrc, "
- "true AS conislocal, true AS convalidated, "
- "false as conisonly "
+ "true AS conislocal, true AS convalidated "
"FROM pg_catalog.pg_constraint "
"WHERE conrelid = '%u'::pg_catalog.oid "
" AND contype = 'c' "
/* no pg_get_constraintdef, must use consrc */
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
"'CHECK (' || consrc || ')' AS consrc, "
- "true AS conislocal, true AS convalidated, "
- "false as conisonly "
+ "true AS conislocal, true AS convalidated "
"FROM pg_catalog.pg_constraint "
"WHERE conrelid = '%u'::pg_catalog.oid "
" AND contype = 'c' "
appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
"rcname AS conname, "
"'CHECK (' || rcsrc || ')' AS consrc, "
- "true AS conislocal, true AS convalidated, "
- "false as conisonly "
+ "true AS conislocal, true AS convalidated "
"FROM pg_relcheck "
"WHERE rcrelid = '%u'::oid "
"ORDER BY rcname",
appendPQExpBuffer(q, "SELECT tableoid, oid, "
"rcname AS conname, "
"'CHECK (' || rcsrc || ')' AS consrc, "
- "true AS conislocal, true AS convalidated, "
- "false as conisonly "
+ "true AS conislocal, true AS convalidated "
"FROM pg_relcheck "
"WHERE rcrelid = '%u'::oid "
"ORDER BY rcname",
"(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
"oid, rcname AS conname, "
"'CHECK (' || rcsrc || ')' AS consrc, "
- "true AS conislocal, true AS convalidated, "
- "false as conisonly "
+ "true AS conislocal, true AS convalidated "
"FROM pg_relcheck "
"WHERE rcrelid = '%u'::oid "
"ORDER BY rcname",
tbinfo->ncheck),
tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
write_msg(NULL, "(The system catalogs might be corrupted.)\n");
- exit_nicely();
+ exit_nicely(1);
}
constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
for (j = 0; j < numConstrs; j++)
{
- bool validated = PQgetvalue(res, j, 5)[0] == 't';
- bool isonly = PQgetvalue(res, j, 6)[0] == 't';
+ bool validated = PQgetvalue(res, j, 5)[0] == 't';
constrs[j].dobj.objType = DO_CONSTRAINT;
constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
constrs[j].condeferrable = false;
constrs[j].condeferred = false;
constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
- constrs[j].conisonly = isonly;
+
/*
* An unvalidated constraint needs to be dumped separately, so
* that potentially-violating existing data is loaded before
- * the constraint. An ONLY constraint needs to be dumped
- * separately too.
+ * the constraint.
*/
- constrs[j].separate = !validated || isonly;
+ constrs[j].separate = !validated;
constrs[j].dobj.dump = tbinfo->dobj.dump;
* Mark the constraint as needing to appear before the table
* --- this is so that any other dependencies of the
* constraint will be emitted before we try to create the
- * table. If the constraint is to be dumped separately, it will be
- * dumped after data is loaded anyway, so don't do it. (There's
- * an automatic dependency in the opposite direction anyway, so
- * don't need to add one manually here.)
+ * table. If the constraint is to be dumped separately, it
+ * will be dumped after data is loaded anyway, so don't do it.
+ * (There's an automatic dependency in the opposite direction
+ * anyway, so don't need to add one manually here.)
*/
if (!constrs[j].separate)
addObjectDependency(&tbinfo->dobj,
PGresult *res;
int ntups;
int i;
- PQExpBuffer query = createPQExpBuffer();
+ PQExpBuffer query;
TSParserInfo *prsinfo;
int i_tableoid;
int i_oid;
return NULL;
}
+ query = createPQExpBuffer();
+
/*
* find all text search objects, including builtin ones; we filter out
* system-defined objects at dump-out time.
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
- appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
- "prsstart::oid, prstoken::oid, "
- "prsend::oid, prsheadline::oid, prslextype::oid "
- "FROM pg_ts_parser");
+ appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
+ "prsstart::oid, prstoken::oid, "
+ "prsend::oid, prsheadline::oid, prslextype::oid "
+ "FROM pg_ts_parser");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
PGresult *res;
int ntups;
int i;
- PQExpBuffer query = createPQExpBuffer();
+ PQExpBuffer query;
TSDictInfo *dictinfo;
int i_tableoid;
int i_oid;
return NULL;
}
+ query = createPQExpBuffer();
+
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
PGresult *res;
int ntups;
int i;
- PQExpBuffer query = createPQExpBuffer();
+ PQExpBuffer query;
TSTemplateInfo *tmplinfo;
int i_tableoid;
int i_oid;
return NULL;
}
+ query = createPQExpBuffer();
+
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
- appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
- "tmplnamespace, tmplinit::oid, tmpllexize::oid "
- "FROM pg_ts_template");
+ appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
+ "tmplnamespace, tmplinit::oid, tmpllexize::oid "
+ "FROM pg_ts_template");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
PGresult *res;
int ntups;
int i;
- PQExpBuffer query = createPQExpBuffer();
+ PQExpBuffer query;
TSConfigInfo *cfginfo;
int i_tableoid;
int i_oid;
return NULL;
}
+ query = createPQExpBuffer();
+
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
PGresult *res;
int ntups;
int i;
- PQExpBuffer query = createPQExpBuffer();
+ PQExpBuffer query;
FdwInfo *fdwinfo;
int i_tableoid;
int i_oid;
return NULL;
}
+ query = createPQExpBuffer();
+
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
PGresult *res;
int ntups;
int i;
- PQExpBuffer query = createPQExpBuffer();
+ PQExpBuffer query;
ForeignServerInfo *srvinfo;
int i_tableoid;
int i_oid;
return NULL;
}
+ query = createPQExpBuffer();
+
/* Make sure we are in proper schema */
- selectSourceSchema(fout,"pg_catalog");
+ selectSourceSchema(fout, "pg_catalog");
appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
"(%s srvowner) AS rolname, "
appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
appendStringLiteralAH(query, comments->descr, fout);
- appendPQExpBuffer(query, ";\n");
+ appendPQExpBufferStr(query, ";\n");
/*
* We mark comments as SECTION_NONE because they really belong in the
resetPQExpBuffer(query);
appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
appendStringLiteralAH(query, descr, fout);
- appendPQExpBuffer(query, ";\n");
+ appendPQExpBufferStr(query, ";\n");
ArchiveEntry(fout, nilCatalogId, createDumpId(),
target->data,
resetPQExpBuffer(target);
appendPQExpBuffer(target, "COLUMN %s.",
fmtId(tbinfo->dobj.name));
- appendPQExpBuffer(target, "%s",
- fmtId(tbinfo->attnames[objsubid - 1]));
+ appendPQExpBufferStr(target, fmtId(tbinfo->attnames[objsubid - 1]));
resetPQExpBuffer(query);
appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
appendStringLiteralAH(query, descr, fout);
- appendPQExpBuffer(query, ";\n");
+ appendPQExpBufferStr(query, ";\n");
ArchiveEntry(fout, nilCatalogId, createDumpId(),
target->data,
if (fout->remoteVersion >= 70300)
{
- appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
- "FROM pg_catalog.pg_description "
- "ORDER BY classoid, objoid, objsubid");
+ appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
+ "FROM pg_catalog.pg_description "
+ "ORDER BY classoid, objoid, objsubid");
}
else if (fout->remoteVersion >= 70200)
{
- appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
- "FROM pg_description "
- "ORDER BY classoid, objoid, objsubid");
+ appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
+ "FROM pg_description "
+ "ORDER BY classoid, objoid, objsubid");
}
else
{
/* Note: this will fail to find attribute comments in pre-7.2... */
- appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
- "FROM pg_description "
- "ORDER BY objoid");
+ appendPQExpBufferStr(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
+ "FROM pg_description "
+ "ORDER BY objoid");
}
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
static void
dumpDumpableObject(Archive *fout, DumpableObject *dobj)
{
-
- bool skip = false;
-
- switch (dobj->objType)
- {
- case DO_INDEX:
- case DO_TRIGGER:
- case DO_CONSTRAINT:
- case DO_FK_CONSTRAINT:
- case DO_RULE:
- skip = !(dumpSections & DUMP_POST_DATA);
- break;
- case DO_TABLE_DATA:
- skip = !(dumpSections & DUMP_DATA);
- break;
- default:
- skip = !(dumpSections & DUMP_PRE_DATA);
- }
-
- if (skip)
- return;
-
switch (dobj->objType)
{
case DO_NAMESPACE:
case DO_INDEX:
dumpIndex(fout, (IndxInfo *) dobj);
break;
+ case DO_REFRESH_MATVIEW:
+ refreshMatViewData(fout, (TableDataInfo *) dobj);
+ break;
case DO_RULE:
dumpRule(fout, (RuleInfo *) dobj);
break;
case DO_TRIGGER:
dumpTrigger(fout, (TriggerInfo *) dobj);
break;
+ case DO_EVENT_TRIGGER:
+ dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
+ break;
case DO_CONSTRAINT:
dumpConstraint(fout, (ConstraintInfo *) dobj);
break;
dumpCast(fout, (CastInfo *) dobj);
break;
case DO_TABLE_DATA:
- dumpTableData(fout, (TableDataInfo *) dobj);
+ if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE)
+ dumpSequenceData(fout, (TableDataInfo *) dobj);
+ else
+ dumpTableData(fout, (TableDataInfo *) dobj);
break;
case DO_DUMMY_TYPE:
/* table rowtypes and array types are never dumped separately */
dobj->name, NULL, NULL, "",
false, "BLOBS", SECTION_DATA,
"", "", NULL,
- dobj->dependencies, dobj->nDeps,
+ NULL, 0,
dumpBlobs, NULL);
break;
+ case DO_PRE_DATA_BOUNDARY:
+ case DO_POST_DATA_BOUNDARY:
+ /* never dumped, nothing to do */
+ break;
}
}
nspinfo->rolname,
false, "SCHEMA", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Schema Comments and Security Labels */
int i;
int n;
- appendPQExpBuffer(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
- appendPQExpBuffer(q,
+ appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
+
+ /*
+ * We unconditionally create the extension, so we must drop it if it
+ * exists. This could happen if the user deleted 'plpgsql' and then
+ * readded it, causing its oid to be greater than FirstNormalObjectId.
+ * The FirstNormalObjectId test was kept to avoid repeatedly dropping
+ * and recreating extensions like 'plpgsql'.
+ */
+ appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
+
+ appendPQExpBufferStr(q,
"SELECT binary_upgrade.create_empty_extension(");
appendStringLiteralAH(q, extinfo->dobj.name, fout);
- appendPQExpBuffer(q, ", ");
+ appendPQExpBufferStr(q, ", ");
appendStringLiteralAH(q, extinfo->namespace, fout);
- appendPQExpBuffer(q, ", ");
+ appendPQExpBufferStr(q, ", ");
appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
appendStringLiteralAH(q, extinfo->extversion, fout);
- appendPQExpBuffer(q, ", ");
+ appendPQExpBufferStr(q, ", ");
/*
* Note that we're pushing extconfig (an OID array) back into
if (strlen(extinfo->extconfig) > 2)
appendStringLiteralAH(q, extinfo->extconfig, fout);
else
- appendPQExpBuffer(q, "NULL");
- appendPQExpBuffer(q, ", ");
+ appendPQExpBufferStr(q, "NULL");
+ appendPQExpBufferStr(q, ", ");
if (strlen(extinfo->extcondition) > 2)
appendStringLiteralAH(q, extinfo->extcondition, fout);
else
- appendPQExpBuffer(q, "NULL");
- appendPQExpBuffer(q, ", ");
- appendPQExpBuffer(q, "ARRAY[");
+ appendPQExpBufferStr(q, "NULL");
+ appendPQExpBufferStr(q, ", ");
+ appendPQExpBufferStr(q, "ARRAY[");
n = 0;
for (i = 0; i < extinfo->dobj.nDeps; i++)
{
if (extobj && extobj->objType == DO_EXTENSION)
{
if (n++ > 0)
- appendPQExpBuffer(q, ",");
+ appendPQExpBufferChar(q, ',');
appendStringLiteralAH(q, extobj->name, fout);
}
}
- appendPQExpBuffer(q, "]::pg_catalog.text[]");
- appendPQExpBuffer(q, ");\n");
+ appendPQExpBufferStr(q, "]::pg_catalog.text[]");
+ appendPQExpBufferStr(q, ");\n");
}
appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
"",
false, "EXTENSION", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- extinfo->dobj.dependencies, extinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Extension Comments and Security Labels */
int num,
i;
Oid enum_oid;
+ char *qtypname;
char *label;
/* Set proper schema search path */
num = PQntuples(res);
+ qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
+
/*
* DROP must be fully qualified in case same name appears in pg_catalog.
* CASCADE shouldn't be required here as for normal types since the I/O
appendPQExpBuffer(delq, "DROP TYPE %s.",
fmtId(tyinfo->dobj.namespace->dobj.name));
appendPQExpBuffer(delq, "%s;\n",
- fmtId(tyinfo->dobj.name));
+ qtypname);
if (binary_upgrade)
binary_upgrade_set_type_oids_by_type_oid(fout, q,
tyinfo->dobj.catId.oid);
appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
- fmtId(tyinfo->dobj.name));
+ qtypname);
if (!binary_upgrade)
{
{
label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
if (i > 0)
- appendPQExpBuffer(q, ",");
- appendPQExpBuffer(q, "\n ");
+ appendPQExpBufferChar(q, ',');
+ appendPQExpBufferStr(q, "\n ");
appendStringLiteralAH(q, label, fout);
}
}
- appendPQExpBuffer(q, "\n);\n");
+ appendPQExpBufferStr(q, "\n);\n");
if (binary_upgrade)
{
label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
if (i == 0)
- appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
appendPQExpBuffer(q,
"SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
enum_oid);
appendPQExpBuffer(q, "ALTER TYPE %s.",
fmtId(tyinfo->dobj.namespace->dobj.name));
appendPQExpBuffer(q, "%s ADD VALUE ",
- fmtId(tyinfo->dobj.name));
+ qtypname);
appendStringLiteralAH(q, label, fout);
- appendPQExpBuffer(q, ";\n\n");
+ appendPQExpBufferStr(q, ";\n\n");
}
}
- appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
+ appendPQExpBuffer(labelq, "TYPE %s", qtypname);
if (binary_upgrade)
binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
tyinfo->rolname, false,
"TYPE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Type Comments and Security Labels */
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+ qtypname, NULL, tyinfo->dobj.name,
+ tyinfo->dobj.namespace->dobj.name,
+ tyinfo->rolname, tyinfo->typacl);
+
PQclear(res);
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
PQExpBuffer query = createPQExpBuffer();
PGresult *res;
Oid collationOid;
+ char *qtypname;
char *procname;
/*
selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
appendPQExpBuffer(query,
- "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
+ "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
"opc.opcname AS opcname, "
"(SELECT nspname FROM pg_catalog.pg_namespace nsp "
" WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
"rngtypid = '%u'",
tyinfo->dobj.catId.oid);
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
- if (PQntuples(res) != 1)
- {
- write_msg(NULL, "query returned %d pg_range entries for range type \"%s\"\n",
- PQntuples(res), tyinfo->dobj.name);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
+
+ qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
/*
* DROP must be fully qualified in case same name appears in pg_catalog.
appendPQExpBuffer(delq, "DROP TYPE %s.",
fmtId(tyinfo->dobj.namespace->dobj.name));
appendPQExpBuffer(delq, "%s;\n",
- fmtId(tyinfo->dobj.name));
+ qtypname);
if (binary_upgrade)
binary_upgrade_set_type_oids_by_type_oid(fout,
q, tyinfo->dobj.catId.oid);
appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
- fmtId(tyinfo->dobj.name));
+ qtypname);
appendPQExpBuffer(q, "\n subtype = %s",
PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
/* print subtype_opclass only if not default for subtype */
if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
{
- char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
- char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
+ char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
+ char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
/* always schema-qualify, don't try to be smart */
appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
fmtId(nspname));
- appendPQExpBuffer(q, "%s", fmtId(opcname));
+ appendPQExpBufferStr(q, fmtId(opcname));
}
collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
/* always schema-qualify, don't try to be smart */
appendPQExpBuffer(q, ",\n collation = %s.",
fmtId(coll->dobj.namespace->dobj.name));
- appendPQExpBuffer(q, "%s",
- fmtId(coll->dobj.name));
+ appendPQExpBufferStr(q, fmtId(coll->dobj.name));
}
}
if (strcmp(procname, "-") != 0)
appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
- appendPQExpBuffer(q, "\n);\n");
+ appendPQExpBufferStr(q, "\n);\n");
- appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
+ appendPQExpBuffer(labelq, "TYPE %s", qtypname);
if (binary_upgrade)
binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
tyinfo->rolname, false,
"TYPE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Type Comments and Security Labels */
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+ qtypname, NULL, tyinfo->dobj.name,
+ tyinfo->dobj.namespace->dobj.name,
+ tyinfo->rolname, tyinfo->typacl);
+
PQclear(res);
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
PQExpBuffer labelq = createPQExpBuffer();
PQExpBuffer query = createPQExpBuffer();
PGresult *res;
- int ntups;
+ char *qtypname;
char *typlen;
char *typinput;
char *typoutput;
tyinfo->dobj.catId.oid);
}
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
else
typdefault = NULL;
+ qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
+
/*
* DROP must be fully qualified in case same name appears in pg_catalog.
* The reason we include CASCADE is that the circular dependency between
appendPQExpBuffer(delq, "DROP TYPE %s.",
fmtId(tyinfo->dobj.namespace->dobj.name));
appendPQExpBuffer(delq, "%s CASCADE;\n",
- fmtId(tyinfo->dobj.name));
+ qtypname);
/* We might already have a shell type, but setting pg_type_oid is harmless */
if (binary_upgrade)
appendPQExpBuffer(q,
"CREATE TYPE %s (\n"
" INTERNALLENGTH = %s",
- fmtId(tyinfo->dobj.name),
+ qtypname,
(strcmp(typlen, "-1") == 0) ? "variable" : typlen);
if (fout->remoteVersion >= 70300)
}
if (strcmp(typcollatable, "t") == 0)
- appendPQExpBuffer(q, ",\n COLLATABLE = true");
+ appendPQExpBufferStr(q, ",\n COLLATABLE = true");
if (typdefault != NULL)
{
- appendPQExpBuffer(q, ",\n DEFAULT = ");
+ appendPQExpBufferStr(q, ",\n DEFAULT = ");
if (typdefault_is_literal)
appendStringLiteralAH(q, typdefault, fout);
else
if (strcmp(typcategory, "U") != 0)
{
- appendPQExpBuffer(q, ",\n CATEGORY = ");
+ appendPQExpBufferStr(q, ",\n CATEGORY = ");
appendStringLiteralAH(q, typcategory, fout);
}
if (strcmp(typispreferred, "t") == 0)
- appendPQExpBuffer(q, ",\n PREFERRED = true");
+ appendPQExpBufferStr(q, ",\n PREFERRED = true");
if (typdelim && strcmp(typdelim, ",") != 0)
{
- appendPQExpBuffer(q, ",\n DELIMITER = ");
+ appendPQExpBufferStr(q, ",\n DELIMITER = ");
appendStringLiteralAH(q, typdelim, fout);
}
if (strcmp(typalign, "c") == 0)
- appendPQExpBuffer(q, ",\n ALIGNMENT = char");
+ appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
else if (strcmp(typalign, "s") == 0)
- appendPQExpBuffer(q, ",\n ALIGNMENT = int2");
+ appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
else if (strcmp(typalign, "i") == 0)
- appendPQExpBuffer(q, ",\n ALIGNMENT = int4");
+ appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
else if (strcmp(typalign, "d") == 0)
- appendPQExpBuffer(q, ",\n ALIGNMENT = double");
+ appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
if (strcmp(typstorage, "p") == 0)
- appendPQExpBuffer(q, ",\n STORAGE = plain");
+ appendPQExpBufferStr(q, ",\n STORAGE = plain");
else if (strcmp(typstorage, "e") == 0)
- appendPQExpBuffer(q, ",\n STORAGE = external");
+ appendPQExpBufferStr(q, ",\n STORAGE = external");
else if (strcmp(typstorage, "x") == 0)
- appendPQExpBuffer(q, ",\n STORAGE = extended");
+ appendPQExpBufferStr(q, ",\n STORAGE = extended");
else if (strcmp(typstorage, "m") == 0)
- appendPQExpBuffer(q, ",\n STORAGE = main");
+ appendPQExpBufferStr(q, ",\n STORAGE = main");
if (strcmp(typbyval, "t") == 0)
- appendPQExpBuffer(q, ",\n PASSEDBYVALUE");
+ appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
- appendPQExpBuffer(q, "\n);\n");
+ appendPQExpBufferStr(q, "\n);\n");
- appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
+ appendPQExpBuffer(labelq, "TYPE %s", qtypname);
if (binary_upgrade)
binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
tyinfo->rolname, false,
"TYPE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Type Comments and Security Labels */
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+ qtypname, NULL, tyinfo->dobj.name,
+ tyinfo->dobj.namespace->dobj.name,
+ tyinfo->rolname, tyinfo->typacl);
+
PQclear(res);
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
PQExpBuffer labelq = createPQExpBuffer();
PQExpBuffer query = createPQExpBuffer();
PGresult *res;
- int ntups;
int i;
+ char *qtypname;
char *typnotnull;
char *typdefn;
char *typdefault;
tyinfo->dobj.catId.oid);
}
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
binary_upgrade_set_type_oids_by_type_oid(fout, q,
tyinfo->dobj.catId.oid);
+ qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
+
appendPQExpBuffer(q,
"CREATE DOMAIN %s AS %s",
- fmtId(tyinfo->dobj.name),
+ qtypname,
typdefn);
/* Print collation only if different from base type's collation */
/* always schema-qualify, don't try to be smart */
appendPQExpBuffer(q, " COLLATE %s.",
fmtId(coll->dobj.namespace->dobj.name));
- appendPQExpBuffer(q, "%s",
- fmtId(coll->dobj.name));
+ appendPQExpBufferStr(q, fmtId(coll->dobj.name));
}
}
if (typnotnull[0] == 't')
- appendPQExpBuffer(q, " NOT NULL");
+ appendPQExpBufferStr(q, " NOT NULL");
if (typdefault != NULL)
{
- appendPQExpBuffer(q, " DEFAULT ");
+ appendPQExpBufferStr(q, " DEFAULT ");
if (typdefault_is_literal)
appendStringLiteralAH(q, typdefault, fout);
else
fmtId(domcheck->dobj.name), domcheck->condef);
}
- appendPQExpBuffer(q, ";\n");
+ appendPQExpBufferStr(q, ";\n");
/*
* DROP must be fully qualified in case same name appears in pg_catalog
appendPQExpBuffer(delq, "DROP DOMAIN %s.",
fmtId(tyinfo->dobj.namespace->dobj.name));
appendPQExpBuffer(delq, "%s;\n",
- fmtId(tyinfo->dobj.name));
+ qtypname);
- appendPQExpBuffer(labelq, "DOMAIN %s", fmtId(tyinfo->dobj.name));
+ appendPQExpBuffer(labelq, "DOMAIN %s", qtypname);
if (binary_upgrade)
binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
tyinfo->rolname, false,
"DOMAIN", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Domain Comments and Security Labels */
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+ qtypname, NULL, tyinfo->dobj.name,
+ tyinfo->dobj.namespace->dobj.name,
+ tyinfo->rolname, tyinfo->typacl);
+
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
destroyPQExpBuffer(labelq);
PQExpBuffer labelq = createPQExpBuffer();
PQExpBuffer query = createPQExpBuffer();
PGresult *res;
+ char *qtypname;
int ntups;
int i_attname;
int i_atttypdefn;
binary_upgrade_set_pg_class_oids(fout, q, typrelid, false);
}
+ qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
+
appendPQExpBuffer(q, "CREATE TYPE %s AS (",
- fmtId(tyinfo->dobj.name));
+ qtypname);
actual_atts = 0;
for (i = 0; i < ntups; i++)
/* Format properly if not first attr */
if (actual_atts++ > 0)
- appendPQExpBuffer(q, ",");
- appendPQExpBuffer(q, "\n\t");
+ appendPQExpBufferChar(q, ',');
+ appendPQExpBufferStr(q, "\n\t");
if (!attisdropped)
{
/* always schema-qualify, don't try to be smart */
appendPQExpBuffer(q, " COLLATE %s.",
fmtId(coll->dobj.namespace->dobj.name));
- appendPQExpBuffer(q, "%s",
- fmtId(coll->dobj.name));
+ appendPQExpBufferStr(q, fmtId(coll->dobj.name));
}
}
}
appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
/* stash separately for insertion after the CREATE TYPE */
- appendPQExpBuffer(dropped,
+ appendPQExpBufferStr(dropped,
"\n-- For binary upgrade, recreate dropped column.\n");
appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
"SET attlen = %s, "
"attalign = '%s', attbyval = false\n"
"WHERE attname = ", attlen, attalign);
appendStringLiteralAH(dropped, attname, fout);
- appendPQExpBuffer(dropped, "\n AND attrelid = ");
- appendStringLiteralAH(dropped, fmtId(tyinfo->dobj.name), fout);
- appendPQExpBuffer(dropped, "::pg_catalog.regclass;\n");
+ appendPQExpBufferStr(dropped, "\n AND attrelid = ");
+ appendStringLiteralAH(dropped, qtypname, fout);
+ appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
appendPQExpBuffer(dropped, "ALTER TYPE %s ",
- fmtId(tyinfo->dobj.name));
+ qtypname);
appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
fmtId(attname));
}
}
- appendPQExpBuffer(q, "\n);\n");
+ appendPQExpBufferStr(q, "\n);\n");
appendPQExpBufferStr(q, dropped->data);
/*
appendPQExpBuffer(delq, "DROP TYPE %s.",
fmtId(tyinfo->dobj.namespace->dobj.name));
appendPQExpBuffer(delq, "%s;\n",
- fmtId(tyinfo->dobj.name));
+ qtypname);
- appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
+ appendPQExpBuffer(labelq, "TYPE %s", qtypname);
if (binary_upgrade)
binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
tyinfo->rolname, false,
"TYPE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+ qtypname, NULL, tyinfo->dobj.name,
+ tyinfo->dobj.namespace->dobj.name,
+ tyinfo->rolname, tyinfo->typacl);
+
PQclear(res);
destroyPQExpBuffer(q);
destroyPQExpBuffer(dropped);
resetPQExpBuffer(target);
appendPQExpBuffer(target, "COLUMN %s.",
fmtId(tyinfo->dobj.name));
- appendPQExpBuffer(target, "%s",
- fmtId(attname));
+ appendPQExpBufferStr(target, fmtId(attname));
resetPQExpBuffer(query);
appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
appendStringLiteralAH(query, descr, fout);
- appendPQExpBuffer(query, ";\n");
+ appendPQExpBufferStr(query, ";\n");
ArchiveEntry(fout, nilCatalogId, createDumpId(),
target->data,
stinfo->baseType->rolname, false,
"SHELL TYPE", SECTION_PRE_DATA,
q->data, "", NULL,
- stinfo->dobj.dependencies, stinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
destroyPQExpBuffer(q);
fmtId(funcInfo->dobj.name));
if (OidIsValid(plang->laninline))
{
- appendPQExpBuffer(defqry, " INLINE ");
+ appendPQExpBufferStr(defqry, " INLINE ");
/* Cope with possibility that inline is in different schema */
if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
appendPQExpBuffer(defqry, "%s.",
fmtId(inlineInfo->dobj.namespace->dobj.name));
- appendPQExpBuffer(defqry, "%s",
- fmtId(inlineInfo->dobj.name));
+ appendPQExpBufferStr(defqry, fmtId(inlineInfo->dobj.name));
}
if (OidIsValid(plang->lanvalidator))
{
- appendPQExpBuffer(defqry, " VALIDATOR ");
+ appendPQExpBufferStr(defqry, " VALIDATOR ");
/* Cope with possibility that validator is in different schema */
if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
appendPQExpBuffer(defqry, "%s.",
fmtId(validatorInfo->dobj.namespace->dobj.name));
- appendPQExpBuffer(defqry, "%s",
- fmtId(validatorInfo->dobj.name));
+ appendPQExpBufferStr(defqry, fmtId(validatorInfo->dobj.name));
}
}
else
appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
qlanname);
}
- appendPQExpBuffer(defqry, ";\n");
+ appendPQExpBufferStr(defqry, ";\n");
appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
lanschema, NULL, plang->lanowner,
false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
defqry->data, delqry->data, NULL,
- plang->dobj.dependencies, plang->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Proc Lang Comments and Security Labels */
* format_function_arguments: generate function name and argument list
*
* This is used when we can rely on pg_get_function_arguments to format
- * the argument list.
+ * the argument list. Note, however, that pg_get_function_arguments
+ * does not special-case zero-argument aggregates.
*/
static char *
-format_function_arguments(FuncInfo *finfo, char *funcargs)
+format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
{
PQExpBufferData fn;
initPQExpBuffer(&fn);
- appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
+ appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
+ if (is_agg && finfo->nargs == 0)
+ appendPQExpBufferStr(&fn, "(*)");
+ else
+ appendPQExpBuffer(&fn, "(%s)", funcargs);
return fn.data;
}
typname);
free(typname);
}
- appendPQExpBuffer(&fn, ")");
+ appendPQExpBufferChar(&fn, ')');
return fn.data;
}
{
char *typname;
+ if (j > 0)
+ appendPQExpBufferStr(&fn, ", ");
+
typname = getFormattedTypeName(fout, finfo->argtypes[j],
zeroAsOpaque);
-
- appendPQExpBuffer(&fn, "%s%s",
- (j > 0) ? ", " : "",
- typname);
+ appendPQExpBufferStr(&fn, typname);
free(typname);
}
- appendPQExpBuffer(&fn, ")");
+ appendPQExpBufferChar(&fn, ')');
return fn.data;
}
PQExpBuffer asPart;
PGresult *res;
char *funcsig; /* identity signature */
- char *funcfullsig; /* full signature */
+ char *funcfullsig = NULL; /* full signature */
char *funcsig_tag;
- int ntups;
char *proretset;
char *prosrc;
char *probin;
finfo->dobj.catId.oid);
}
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
*/
if (probin[0] != '\0' && strcmp(probin, "-") != 0)
{
- appendPQExpBuffer(asPart, "AS ");
+ appendPQExpBufferStr(asPart, "AS ");
appendStringLiteralAH(asPart, probin, fout);
if (strcmp(prosrc, "-") != 0)
{
- appendPQExpBuffer(asPart, ", ");
+ appendPQExpBufferStr(asPart, ", ");
/*
* where we have bin, use dollar quoting if allowed and src
{
if (strcmp(prosrc, "-") != 0)
{
- appendPQExpBuffer(asPart, "AS ");
+ appendPQExpBufferStr(asPart, "AS ");
/* with no bin, dollar quote src unconditionally if allowed */
if (disable_dollar_quoting)
appendStringLiteralAH(asPart, prosrc, fout);
if (funcargs)
{
/* 8.4 or later; we rely on server-side code for most of the work */
- funcfullsig = format_function_arguments(finfo, funcargs);
- funcsig = format_function_arguments(finfo, funciargs);
+ funcfullsig = format_function_arguments(finfo, funcargs, false);
+ funcsig = format_function_arguments(finfo, funciargs, false);
}
else
- {
/* pre-8.4, do it ourselves */
funcsig = format_function_arguments_old(fout,
finfo, nallargs, allargtypes,
argmodes, argnames);
- funcfullsig = funcsig;
- }
funcsig_tag = format_function_signature(fout, finfo, false);
fmtId(finfo->dobj.namespace->dobj.name),
funcsig);
- appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
+ appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig ? funcfullsig :
+ funcsig);
if (funcresult)
appendPQExpBuffer(q, "RETURNS %s", funcresult);
else
appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
if (proiswindow[0] == 't')
- appendPQExpBuffer(q, " WINDOW");
+ appendPQExpBufferStr(q, " WINDOW");
if (provolatile[0] != PROVOLATILE_VOLATILE)
{
if (provolatile[0] == PROVOLATILE_IMMUTABLE)
- appendPQExpBuffer(q, " IMMUTABLE");
+ appendPQExpBufferStr(q, " IMMUTABLE");
else if (provolatile[0] == PROVOLATILE_STABLE)
- appendPQExpBuffer(q, " STABLE");
+ appendPQExpBufferStr(q, " STABLE");
else if (provolatile[0] != PROVOLATILE_VOLATILE)
- {
- write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
- finfo->dobj.name);
- exit_nicely();
- }
+ exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
+ finfo->dobj.name);
}
if (proisstrict[0] == 't')
- appendPQExpBuffer(q, " STRICT");
+ appendPQExpBufferStr(q, " STRICT");
if (prosecdef[0] == 't')
- appendPQExpBuffer(q, " SECURITY DEFINER");
+ appendPQExpBufferStr(q, " SECURITY DEFINER");
if (proleakproof[0] == 't')
- appendPQExpBuffer(q, " LEAKPROOF");
+ appendPQExpBufferStr(q, " LEAKPROOF");
/*
* COST and ROWS are emitted only if present and not default, so as not to
*/
if (pg_strcasecmp(configitem, "DateStyle") == 0
|| pg_strcasecmp(configitem, "search_path") == 0)
- appendPQExpBuffer(q, "%s", pos);
+ appendPQExpBufferStr(q, pos);
else
appendStringLiteralAH(q, pos, fout);
}
finfo->rolname, false,
"FUNCTION", SECTION_PRE_DATA,
q->data, delqry->data, NULL,
- finfo->dobj.dependencies, finfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Function Comments and Security Labels */
destroyPQExpBuffer(labelq);
destroyPQExpBuffer(asPart);
free(funcsig);
+ if (funcfullsig)
+ free(funcfullsig);
free(funcsig_tag);
if (allargtypes)
free(allargtypes);
labelq = createPQExpBuffer();
appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
- getFormattedTypeName(fout, cast->castsource, zeroAsNone),
- getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
+ getFormattedTypeName(fout, cast->castsource, zeroAsNone),
+ getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
- getFormattedTypeName(fout, cast->castsource, zeroAsNone),
- getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
+ getFormattedTypeName(fout, cast->castsource, zeroAsNone),
+ getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
switch (cast->castmethod)
{
case COERCION_METHOD_BINARY:
- appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
+ appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
break;
case COERCION_METHOD_INOUT:
- appendPQExpBuffer(defqry, "WITH INOUT");
+ appendPQExpBufferStr(defqry, "WITH INOUT");
break;
case COERCION_METHOD_FUNCTION:
+ if (funcInfo)
+ {
+ char *fsig = format_function_signature(fout, funcInfo, true);
- /*
- * Always qualify the function name, in case it is not in
- * pg_catalog schema (format_function_signature won't qualify it).
- */
- appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
- fmtId(funcInfo->dobj.namespace->dobj.name));
- appendPQExpBuffer(defqry, "%s",
- format_function_signature(fout, funcInfo, true));
+ /*
+ * Always qualify the function name, in case it is not in
+ * pg_catalog schema (format_function_signature won't qualify
+ * it).
+ */
+ appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
+ fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
+ free(fsig);
+ }
+ else
+ write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
break;
default:
write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
}
if (cast->castcontext == 'a')
- appendPQExpBuffer(defqry, " AS ASSIGNMENT");
+ appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
else if (cast->castcontext == 'i')
- appendPQExpBuffer(defqry, " AS IMPLICIT");
- appendPQExpBuffer(defqry, ";\n");
+ appendPQExpBufferStr(defqry, " AS IMPLICIT");
+ appendPQExpBufferStr(defqry, ";\n");
appendPQExpBuffer(labelq, "CAST (%s AS %s)",
- getFormattedTypeName(fout, cast->castsource, zeroAsNone),
- getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
+ getFormattedTypeName(fout, cast->castsource, zeroAsNone),
+ getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
if (binary_upgrade)
binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
"pg_catalog", NULL, "",
false, "CAST", SECTION_PRE_DATA,
defqry->data, delqry->data, NULL,
- cast->dobj.dependencies, cast->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Cast Comments */
PQExpBuffer details;
const char *name;
PGresult *res;
- int ntups;
int i_oprkind;
int i_oprcode;
int i_oprleft;
char *oprjoin;
char *oprcanmerge;
char *oprcanhash;
+ char *oprregproc;
+ char *oprref;
/* Skip if not to be dumped */
if (!oprinfo->dobj.dump || dataOnly)
oprinfo->dobj.catId.oid);
}
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
i_oprkind = PQfnumber(res, "oprkind");
i_oprcode = PQfnumber(res, "oprcode");
oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
- appendPQExpBuffer(details, " PROCEDURE = %s",
- convertRegProcReference(fout, oprcode));
+ oprregproc = convertRegProcReference(fout, oprcode);
+ if (oprregproc)
+ {
+ appendPQExpBuffer(details, " PROCEDURE = %s", oprregproc);
+ free(oprregproc);
+ }
appendPQExpBuffer(oprid, "%s (",
oprinfo->dobj.name);
else
name = fmtId(oprleft);
appendPQExpBuffer(details, ",\n LEFTARG = %s", name);
- appendPQExpBuffer(oprid, "%s", name);
+ appendPQExpBufferStr(oprid, name);
}
else
- appendPQExpBuffer(oprid, "NONE");
+ appendPQExpBufferStr(oprid, "NONE");
if (strcmp(oprkind, "l") == 0 ||
strcmp(oprkind, "b") == 0)
appendPQExpBuffer(oprid, ", %s)", name);
}
else
- appendPQExpBuffer(oprid, ", NONE)");
+ appendPQExpBufferStr(oprid, ", NONE)");
- name = convertOperatorReference(fout, oprcom);
- if (name)
- appendPQExpBuffer(details, ",\n COMMUTATOR = %s", name);
+ oprref = convertOperatorReference(fout, oprcom);
+ if (oprref)
+ {
+ appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
+ free(oprref);
+ }
- name = convertOperatorReference(fout, oprnegate);
- if (name)
- appendPQExpBuffer(details, ",\n NEGATOR = %s", name);
+ oprref = convertOperatorReference(fout, oprnegate);
+ if (oprref)
+ {
+ appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
+ free(oprref);
+ }
if (strcmp(oprcanmerge, "t") == 0)
- appendPQExpBuffer(details, ",\n MERGES");
+ appendPQExpBufferStr(details, ",\n MERGES");
if (strcmp(oprcanhash, "t") == 0)
- appendPQExpBuffer(details, ",\n HASHES");
+ appendPQExpBufferStr(details, ",\n HASHES");
- name = convertRegProcReference(fout, oprrest);
- if (name)
- appendPQExpBuffer(details, ",\n RESTRICT = %s", name);
+ oprregproc = convertRegProcReference(fout, oprrest);
+ if (oprregproc)
+ {
+ appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
+ free(oprregproc);
+ }
- name = convertRegProcReference(fout, oprjoin);
- if (name)
- appendPQExpBuffer(details, ",\n JOIN = %s", name);
+ oprregproc = convertRegProcReference(fout, oprjoin);
+ if (oprregproc)
+ {
+ appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
+ free(oprregproc);
+ }
/*
* DROP must be fully qualified in case same name appears in pg_catalog
oprinfo->rolname,
false, "OPERATOR", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Operator Comments */
/*
* Convert a function reference obtained from pg_operator
*
- * Returns what to print, or NULL if function references is InvalidOid
+ * Returns allocated string of what to print, or NULL if function references
+ * is InvalidOid. Returned string is expected to be free'd by the caller.
*
* In 7.3 the input is a REGPROCEDURE display; we have to strip the
* argument-types part. In prior versions, the input is a REGPROC display.
*/
-static const char *
+static char *
convertRegProcReference(Archive *fout, const char *proc)
{
/* In all cases "-" means a null reference */
}
/* REGPROC before 7.3 does not quote its result */
- return fmtId(proc);
+ return pg_strdup(fmtId(proc));
}
/*
* Convert an operator cross-reference obtained from pg_operator
*
- * Returns what to print, or NULL to print nothing
+ * Returns an allocated string of what to print, or NULL to print nothing.
+ * Caller is responsible for free'ing result string.
*
* In 7.3 and up the input is a REGOPERATOR display; we have to strip the
* argument-types part, and add OPERATOR() decoration if the name is
* schema-qualified. In older versions, the input is just a numeric OID,
* which we search our operator list for.
*/
-static const char *
+static char *
convertOperatorReference(Archive *fout, const char *opr)
{
OprInfo *oprInfo;
/* If not schema-qualified, don't need to add OPERATOR() */
if (!sawdot)
return name;
- oname = pg_malloc(strlen(name) + 11);
- sprintf(oname, "OPERATOR(%s)", name);
+ oname = psprintf("OPERATOR(%s)", name);
free(name);
return oname;
}
opr);
return NULL;
}
- return oprInfo->dobj.name;
+ return pg_strdup(oprInfo->dobj.name);
}
/*
char *result;
char query[128];
PGresult *res;
- int ntups;
snprintf(query, sizeof(query),
"SELECT '%u'::pg_catalog.regproc", funcOid);
- res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
-
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query);
result = pg_strdup(PQgetvalue(res, 0, 0));
opcinfo->dobj.catId.oid);
}
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
i_opcintype = PQfnumber(res, "opcintype");
i_opckeytype = PQfnumber(res, "opckeytype");
appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
fmtId(opcinfo->dobj.name));
if (strcmp(opcdefault, "t") == 0)
- appendPQExpBuffer(q, "DEFAULT ");
+ appendPQExpBufferStr(q, "DEFAULT ");
appendPQExpBuffer(q, "FOR TYPE %s USING %s",
opcintype,
fmtId(amname));
(strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
{
- appendPQExpBuffer(q, " FAMILY ");
+ appendPQExpBufferStr(q, " FAMILY ");
if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
}
- appendPQExpBuffer(q, " AS\n ");
+ appendPQExpBufferStr(q, " AS\n ");
needComma = false;
sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
if (needComma)
- appendPQExpBuffer(q, " ,\n ");
+ appendPQExpBufferStr(q, " ,\n ");
appendPQExpBuffer(q, "OPERATOR %s %s",
amopstrategy, amopopr);
if (strlen(sortfamily) > 0)
{
- appendPQExpBuffer(q, " FOR ORDER BY ");
+ appendPQExpBufferStr(q, " FOR ORDER BY ");
if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
- appendPQExpBuffer(q, "%s", fmtId(sortfamily));
+ appendPQExpBufferStr(q, fmtId(sortfamily));
}
if (strcmp(amopreqcheck, "t") == 0)
- appendPQExpBuffer(q, " RECHECK");
+ appendPQExpBufferStr(q, " RECHECK");
needComma = true;
}
amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
if (needComma)
- appendPQExpBuffer(q, " ,\n ");
+ appendPQExpBufferStr(q, " ,\n ");
appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
PQclear(res);
- appendPQExpBuffer(q, ";\n");
+ appendPQExpBufferStr(q, ";\n");
appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
fmtId(opcinfo->dobj.name));
opcinfo->rolname,
false, "OPERATOR CLASS", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Operator Class Comments */
"WHERE oid = '%u'::pg_catalog.oid",
opfinfo->dobj.catId.oid);
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
i_amname = PQfnumber(res, "amname");
sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
if (needComma)
- appendPQExpBuffer(q, " ,\n ");
+ appendPQExpBufferStr(q, " ,\n ");
appendPQExpBuffer(q, "OPERATOR %s %s",
amopstrategy, amopopr);
if (strlen(sortfamily) > 0)
{
- appendPQExpBuffer(q, " FOR ORDER BY ");
+ appendPQExpBufferStr(q, " FOR ORDER BY ");
if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
- appendPQExpBuffer(q, "%s", fmtId(sortfamily));
+ appendPQExpBufferStr(q, fmtId(sortfamily));
}
if (strcmp(amopreqcheck, "t") == 0)
- appendPQExpBuffer(q, " RECHECK");
+ appendPQExpBufferStr(q, " RECHECK");
needComma = true;
}
amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
if (needComma)
- appendPQExpBuffer(q, " ,\n ");
+ appendPQExpBufferStr(q, " ,\n ");
appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
amprocnum, amproclefttype, amprocrighttype,
needComma = true;
}
- appendPQExpBuffer(q, ";\n");
+ appendPQExpBufferStr(q, ";\n");
}
appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
opfinfo->rolname,
false, "OPERATOR FAMILY", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Operator Family Comments */
PQExpBuffer delq;
PQExpBuffer labelq;
PGresult *res;
- int ntups;
int i_collcollate;
int i_collctype;
const char *collcollate;
"WHERE c.oid = '%u'::pg_catalog.oid",
collinfo->dobj.catId.oid);
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
i_collcollate = PQfnumber(res, "collcollate");
i_collctype = PQfnumber(res, "collctype");
appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
fmtId(collinfo->dobj.name));
appendStringLiteralAH(q, collcollate, fout);
- appendPQExpBuffer(q, ", lc_ctype = ");
+ appendPQExpBufferStr(q, ", lc_ctype = ");
appendStringLiteralAH(q, collctype, fout);
- appendPQExpBuffer(q, ");\n");
+ appendPQExpBufferStr(q, ");\n");
appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
collinfo->rolname,
false, "COLLATION", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- collinfo->dobj.dependencies, collinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Collation Comments */
PQExpBuffer delq;
PQExpBuffer labelq;
PGresult *res;
- int ntups;
int i_conforencoding;
int i_contoencoding;
int i_conproc;
"WHERE c.oid = '%u'::pg_catalog.oid",
convinfo->dobj.catId.oid);
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
i_conforencoding = PQfnumber(res, "conforencoding");
i_contoencoding = PQfnumber(res, "contoencoding");
(condefault) ? "DEFAULT " : "",
fmtId(convinfo->dobj.name));
appendStringLiteralAH(q, conforencoding, fout);
- appendPQExpBuffer(q, " TO ");
+ appendPQExpBufferStr(q, " TO ");
appendStringLiteralAH(q, contoencoding, fout);
/* regproc is automatically quoted in 7.3 and above */
appendPQExpBuffer(q, " FROM %s;\n", conproc);
convinfo->rolname,
false, "CONVERSION", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- convinfo->dobj.dependencies, convinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Conversion Comments */
initPQExpBuffer(&buf);
if (honor_quotes)
- appendPQExpBuffer(&buf, "%s",
- fmtId(agginfo->aggfn.dobj.name));
+ appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
else
- appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
+ appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
if (agginfo->aggfn.nargs == 0)
appendPQExpBuffer(&buf, "(*)");
else
{
- appendPQExpBuffer(&buf, "(");
+ appendPQExpBufferChar(&buf, '(');
for (j = 0; j < agginfo->aggfn.nargs; j++)
{
char *typname;
typname);
free(typname);
}
- appendPQExpBuffer(&buf, ")");
+ appendPQExpBufferChar(&buf, ')');
}
return buf.data;
}
PQExpBuffer delq;
PQExpBuffer labelq;
PQExpBuffer details;
- char *aggsig;
+ char *aggsig; /* identity signature */
+ char *aggfullsig = NULL; /* full signature */
char *aggsig_tag;
PGresult *res;
- int ntups;
int i_aggtransfn;
int i_aggfinalfn;
+ int i_aggmtransfn;
+ int i_aggminvtransfn;
+ int i_aggmfinalfn;
+ int i_aggfinalextra;
+ int i_aggmfinalextra;
int i_aggsortop;
+ int i_hypothetical;
int i_aggtranstype;
+ int i_aggtransspace;
+ int i_aggmtranstype;
+ int i_aggmtransspace;
int i_agginitval;
+ int i_aggminitval;
int i_convertok;
const char *aggtransfn;
const char *aggfinalfn;
+ const char *aggmtransfn;
+ const char *aggminvtransfn;
+ const char *aggmfinalfn;
+ bool aggfinalextra;
+ bool aggmfinalextra;
const char *aggsortop;
+ char *aggsortconvop;
+ bool hypothetical;
const char *aggtranstype;
+ const char *aggtransspace;
+ const char *aggmtranstype;
+ const char *aggmtransspace;
const char *agginitval;
+ const char *aggminitval;
bool convertok;
/* Skip if not to be dumped */
selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
/* Get aggregate-specific details */
- if (fout->remoteVersion >= 80100)
+ if (fout->remoteVersion >= 90400)
+ {
+ appendPQExpBuffer(query, "SELECT aggtransfn, "
+ "aggfinalfn, aggtranstype::pg_catalog.regtype, "
+ "aggmtransfn, aggminvtransfn, aggmfinalfn, "
+ "aggmtranstype::pg_catalog.regtype, "
+ "aggfinalextra, aggmfinalextra, "
+ "aggsortop::pg_catalog.regoperator, "
+ "(aggkind = 'h') AS hypothetical, "
+ "aggtransspace, agginitval, "
+ "aggmtransspace, aggminitval, "
+ "true AS convertok, "
+ "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
+ "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
+ "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
+ "WHERE a.aggfnoid = p.oid "
+ "AND p.oid = '%u'::pg_catalog.oid",
+ agginfo->aggfn.dobj.catId.oid);
+ }
+ else if (fout->remoteVersion >= 80400)
{
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
+ "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
+ "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
+ "false AS aggfinalextra, false AS aggmfinalextra, "
"aggsortop::pg_catalog.regoperator, "
- "agginitval, "
- "'t'::boolean AS convertok "
+ "false AS hypothetical, "
+ "0 AS aggtransspace, agginitval, "
+ "0 AS aggmtransspace, NULL AS aggminitval, "
+ "true AS convertok, "
+ "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
+ "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
"AND p.oid = '%u'::pg_catalog.oid",
agginfo->aggfn.dobj.catId.oid);
}
+ else if (fout->remoteVersion >= 80100)
+ {
+ appendPQExpBuffer(query, "SELECT aggtransfn, "
+ "aggfinalfn, aggtranstype::pg_catalog.regtype, "
+ "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
+ "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
+ "false AS aggfinalextra, false AS aggmfinalextra, "
+ "aggsortop::pg_catalog.regoperator, "
+ "false AS hypothetical, "
+ "0 AS aggtransspace, agginitval, "
+ "0 AS aggmtransspace, NULL AS aggminitval, "
+ "true AS convertok "
+ "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
+ "WHERE a.aggfnoid = p.oid "
+ "AND p.oid = '%u'::pg_catalog.oid",
+ agginfo->aggfn.dobj.catId.oid);
+ }
else if (fout->remoteVersion >= 70300)
{
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
+ "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
+ "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
+ "false AS aggfinalextra, false AS aggmfinalextra, "
"0 AS aggsortop, "
- "agginitval, "
- "'t'::boolean AS convertok "
+ "false AS hypothetical, "
+ "0 AS aggtransspace, agginitval, "
+ "0 AS aggmtransspace, NULL AS aggminitval, "
+ "true AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
"AND p.oid = '%u'::pg_catalog.oid",
{
appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
"format_type(aggtranstype, NULL) AS aggtranstype, "
+ "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
+ "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
+ "false AS aggfinalextra, false AS aggmfinalextra, "
"0 AS aggsortop, "
- "agginitval, "
- "'t'::boolean AS convertok "
+ "false AS hypothetical, "
+ "0 AS aggtransspace, agginitval, "
+ "0 AS aggmtransspace, NULL AS aggminitval, "
+ "true AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
agginfo->aggfn.dobj.catId.oid);
appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
"aggfinalfn, "
"(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
+ "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
+ "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
+ "false AS aggfinalextra, false AS aggmfinalextra, "
"0 AS aggsortop, "
- "agginitval1 AS agginitval, "
+ "false AS hypothetical, "
+ "0 AS aggtransspace, agginitval1 AS agginitval, "
+ "0 AS aggmtransspace, NULL AS aggminitval, "
"(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
agginfo->aggfn.dobj.catId.oid);
}
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
i_aggtransfn = PQfnumber(res, "aggtransfn");
i_aggfinalfn = PQfnumber(res, "aggfinalfn");
+ i_aggmtransfn = PQfnumber(res, "aggmtransfn");
+ i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
+ i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
+ i_aggfinalextra = PQfnumber(res, "aggfinalextra");
+ i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
i_aggsortop = PQfnumber(res, "aggsortop");
+ i_hypothetical = PQfnumber(res, "hypothetical");
i_aggtranstype = PQfnumber(res, "aggtranstype");
+ i_aggtransspace = PQfnumber(res, "aggtransspace");
+ i_aggmtranstype = PQfnumber(res, "aggmtranstype");
+ i_aggmtransspace = PQfnumber(res, "aggmtransspace");
i_agginitval = PQfnumber(res, "agginitval");
+ i_aggminitval = PQfnumber(res, "aggminitval");
i_convertok = PQfnumber(res, "convertok");
aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
+ aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
+ aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
+ aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
+ aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
+ aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
aggsortop = PQgetvalue(res, 0, i_aggsortop);
+ hypothetical = (PQgetvalue(res, 0, i_hypothetical)[0] == 't');
aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
+ aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
+ aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
+ aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
agginitval = PQgetvalue(res, 0, i_agginitval);
+ aggminitval = PQgetvalue(res, 0, i_aggminitval);
convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
- aggsig = format_aggregate_signature(agginfo, fout, true);
+ if (fout->remoteVersion >= 80400)
+ {
+ /* 8.4 or later; we rely on server-side code for most of the work */
+ char *funcargs;
+ char *funciargs;
+
+ funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
+ funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
+ aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
+ aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
+ }
+ else
+ /* pre-8.4, do it ourselves */
+ aggsig = format_aggregate_signature(agginfo, fout, true);
+
aggsig_tag = format_aggregate_signature(agginfo, fout, false);
if (!convertok)
{
write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
aggsig);
+
+ if (aggfullsig)
+ free(aggfullsig);
+
+ free(aggsig);
+
return;
}
fmtId(aggtranstype));
}
+ if (strcmp(aggtransspace, "0") != 0)
+ {
+ appendPQExpBuffer(details, ",\n SSPACE = %s",
+ aggtransspace);
+ }
+
if (!PQgetisnull(res, 0, i_agginitval))
{
- appendPQExpBuffer(details, ",\n INITCOND = ");
+ appendPQExpBufferStr(details, ",\n INITCOND = ");
appendStringLiteralAH(details, agginitval, fout);
}
{
appendPQExpBuffer(details, ",\n FINALFUNC = %s",
aggfinalfn);
+ if (aggfinalextra)
+ appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
+ }
+
+ if (strcmp(aggmtransfn, "-") != 0)
+ {
+ appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
+ aggmtransfn,
+ aggminvtransfn,
+ aggmtranstype);
+ }
+
+ if (strcmp(aggmtransspace, "0") != 0)
+ {
+ appendPQExpBuffer(details, ",\n MSSPACE = %s",
+ aggmtransspace);
+ }
+
+ if (!PQgetisnull(res, 0, i_aggminitval))
+ {
+ appendPQExpBufferStr(details, ",\n MINITCOND = ");
+ appendStringLiteralAH(details, aggminitval, fout);
+ }
+
+ if (strcmp(aggmfinalfn, "-") != 0)
+ {
+ appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
+ aggmfinalfn);
+ if (aggmfinalextra)
+ appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
}
- aggsortop = convertOperatorReference(fout, aggsortop);
- if (aggsortop)
+ aggsortconvop = convertOperatorReference(fout, aggsortop);
+ if (aggsortconvop)
{
appendPQExpBuffer(details, ",\n SORTOP = %s",
- aggsortop);
+ aggsortconvop);
+ free(aggsortconvop);
}
+ if (hypothetical)
+ appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
+
/*
* DROP must be fully qualified in case same name appears in pg_catalog
*/
aggsig);
appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
- aggsig, details->data);
+ aggfullsig ? aggfullsig : aggsig, details->data);
appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
agginfo->aggfn.rolname,
false, "AGGREGATE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Aggregate Comments */
/*
* Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
* command look like a function's GRANT; in particular this affects the
- * syntax for zero-argument aggregates.
+ * syntax for zero-argument aggregates and ordered-set aggregates.
*/
free(aggsig);
free(aggsig_tag);
agginfo->aggfn.rolname, agginfo->aggfn.proacl);
free(aggsig);
+ if (aggfullsig)
+ free(aggfullsig);
free(aggsig_tag);
PQclear(res);
"",
false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Parser Comments */
PQExpBuffer labelq;
PQExpBuffer query;
PGresult *res;
- int ntups;
char *nspname;
char *tmplname;
"FROM pg_ts_template p, pg_namespace n "
"WHERE p.oid = '%u' AND n.oid = tmplnamespace",
dictinfo->dicttemplate);
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
nspname = PQgetvalue(res, 0, 0);
tmplname = PQgetvalue(res, 0, 1);
appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
fmtId(dictinfo->dobj.name));
- appendPQExpBuffer(q, " TEMPLATE = ");
+ appendPQExpBufferStr(q, " TEMPLATE = ");
if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
appendPQExpBuffer(q, "%s.", fmtId(nspname));
- appendPQExpBuffer(q, "%s", fmtId(tmplname));
+ appendPQExpBufferStr(q, fmtId(tmplname));
PQclear(res);
if (dictinfo->dictinitoption)
appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
- appendPQExpBuffer(q, " );\n");
+ appendPQExpBufferStr(q, " );\n");
/*
* DROP must be fully qualified in case same name appears in pg_catalog
dictinfo->rolname,
false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Dictionary Comments */
"",
false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Template Comments */
"FROM pg_ts_parser p, pg_namespace n "
"WHERE p.oid = '%u' AND n.oid = prsnamespace",
cfginfo->cfgparser);
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
nspname = PQgetvalue(res, 0, 0);
prsname = PQgetvalue(res, 0, 1);
appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
fmtId(cfginfo->dobj.name));
- appendPQExpBuffer(q, " PARSER = ");
+ appendPQExpBufferStr(q, " PARSER = ");
if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
appendPQExpBuffer(q, "%s.", fmtId(nspname));
appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
{
/* starting a new token type, so start a new command */
if (i > 0)
- appendPQExpBuffer(q, ";\n");
+ appendPQExpBufferStr(q, ";\n");
appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
fmtId(cfginfo->dobj.name));
/* tokenname needs quoting, dictname does NOT */
}
if (ntups > 0)
- appendPQExpBuffer(q, ";\n");
+ appendPQExpBufferStr(q, ";\n");
PQclear(res);
cfginfo->rolname,
false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Configuration Comments */
if (strlen(fdwinfo->fdwoptions) > 0)
appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
- appendPQExpBuffer(q, ";\n");
+ appendPQExpBufferStr(q, ";\n");
appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
qfdwname);
fdwinfo->rolname,
false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Handle the ACL */
PQExpBuffer labelq;
PQExpBuffer query;
PGresult *res;
- int ntups;
char *qsrvname;
char *fdwname;
"FROM pg_foreign_data_wrapper w "
"WHERE w.oid = '%u'",
srvinfo->srvfdw);
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
fdwname = PQgetvalue(res, 0, 0);
appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
{
- appendPQExpBuffer(q, " TYPE ");
+ appendPQExpBufferStr(q, " TYPE ");
appendStringLiteralAH(q, srvinfo->srvtype, fout);
}
if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
{
- appendPQExpBuffer(q, " VERSION ");
+ appendPQExpBufferStr(q, " VERSION ");
appendStringLiteralAH(q, srvinfo->srvversion, fout);
}
- appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
- appendPQExpBuffer(q, "%s", fmtId(fdwname));
+ appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
+ appendPQExpBufferStr(q, fmtId(fdwname));
if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
- appendPQExpBuffer(q, ";\n");
+ appendPQExpBufferStr(q, ";\n");
appendPQExpBuffer(delq, "DROP SERVER %s;\n",
qsrvname);
srvinfo->rolname,
false, "SERVER", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Handle the ACL */
if (umoptions && strlen(umoptions) > 0)
appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
- appendPQExpBuffer(q, ";\n");
+ appendPQExpBufferStr(q, ";\n");
resetPQExpBuffer(delq);
appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
destroyPQExpBuffer(query);
destroyPQExpBuffer(delq);
+ destroyPQExpBuffer(tag);
destroyPQExpBuffer(q);
}
case DEFACLOBJ_FUNCTION:
type = "FUNCTIONS";
break;
+ case DEFACLOBJ_TYPE:
+ type = "TYPES";
+ break;
default:
/* shouldn't get here */
- write_msg(NULL, "unknown object type (%d) in default privileges\n",
- (int) daclinfo->defaclobjtype);
- exit_nicely();
+ exit_horribly(NULL,
+ "unrecognized object type in default privileges: %d\n",
+ (int) daclinfo->defaclobjtype);
type = ""; /* keep compiler quiet */
}
daclinfo->defaclrole,
fout->remoteVersion,
q))
- {
- write_msg(NULL, "could not parse default ACL list (%s)\n",
- daclinfo->defaclacl);
- exit_nicely();
- }
+ exit_horribly(NULL, "could not parse default ACL list (%s)\n",
+ daclinfo->defaclacl);
ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
tag->data,
daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
NULL,
daclinfo->defaclrole,
- false, "DEFAULT ACL", SECTION_NONE,
+ false, "DEFAULT ACL", SECTION_POST_DATA,
q->data, "", NULL,
- daclinfo->dobj.dependencies, daclinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
destroyPQExpBuffer(tag);
if (!buildACLCommands(name, subname, type, acls, owner,
"", fout->remoteVersion, sql))
- {
- write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
- acls, name, type);
- exit_nicely();
- }
+ exit_horribly(NULL,
+ "could not parse ACL list (%s) for object \"%s\" (%s)\n",
+ acls, name, type);
if (sql->len > 0)
ArchiveEntry(fout, nilCatalogId, createDumpId(),
"SECURITY LABEL FOR %s ON %s IS ",
fmtId(labels[i].provider), target);
appendStringLiteralAH(query, labels[i].label, fout);
- appendPQExpBuffer(query, ";\n");
+ appendPQExpBufferStr(query, ";\n");
}
if (query->len > 0)
appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
fmtId(provider), target->data);
appendStringLiteralAH(query, label, fout);
- appendPQExpBuffer(query, ";\n");
+ appendPQExpBufferStr(query, ";\n");
}
if (query->len > 0)
{
query = createPQExpBuffer();
- appendPQExpBuffer(query,
- "SELECT label, provider, classoid, objoid, objsubid "
- "FROM pg_catalog.pg_seclabel "
- "ORDER BY classoid, objoid, objsubid");
+ appendPQExpBufferStr(query,
+ "SELECT label, provider, classoid, objoid, objsubid "
+ "FROM pg_catalog.pg_seclabel "
+ "ORDER BY classoid, objoid, objsubid");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
static void
dumpTable(Archive *fout, TableInfo *tbinfo)
{
- if (tbinfo->dobj.dump)
+ if (tbinfo->dobj.dump && !dataOnly)
{
char *namecopy;
if (tbinfo->relkind == RELKIND_SEQUENCE)
dumpSequence(fout, tbinfo);
- else if (!dataOnly)
+ else
dumpTableSchema(fout, tbinfo);
/* Handle the ACL here */
char *acltag;
attnamecopy = pg_strdup(fmtId(attname));
- acltag = pg_malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
- sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
+ acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
/* Column's GRANT type is always TABLE */
dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
namecopy, attnamecopy, acltag,
}
/*
- * dumpTableSchema
- * write the declaration (not data) of one user-defined table or view
+ * Create the AS clause for a view or materialized view. The semicolon is
+ * stripped because a materialized view must add a WITH NO DATA clause.
+ *
+ * This returns a new buffer which must be freed by the caller.
*/
-static void
-dumpTableSchema(Archive *fout, TableInfo *tbinfo)
+static PQExpBuffer
+createViewAsClause(Archive *fout, TableInfo *tbinfo)
{
PQExpBuffer query = createPQExpBuffer();
- PQExpBuffer q = createPQExpBuffer();
- PQExpBuffer delq = createPQExpBuffer();
- PQExpBuffer labelq = createPQExpBuffer();
+ PQExpBuffer result = createPQExpBuffer();
PGresult *res;
- int numParents;
- TableInfo **parents;
- int actual_atts; /* number of attrs in this CREATE statment */
- const char *reltypename;
- char *storage;
- char *srvname;
- char *ftoptions;
- int j,
- k;
-
- /* Make sure we are in proper schema */
- selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
+ int len;
- if (binary_upgrade)
- binary_upgrade_set_type_oids_by_rel_oid(fout, q,
- tbinfo->dobj.catId.oid);
-
- /* Is it a table or a view? */
- if (tbinfo->relkind == RELKIND_VIEW)
+ /* Fetch the view definition */
+ if (fout->remoteVersion >= 70300)
{
- char *viewdef;
-
- reltypename = "VIEW";
-
- /* Fetch the view definition */
- if (fout->remoteVersion >= 70300)
- {
- /* Beginning in 7.3, viewname is not unique; rely on OID */
- appendPQExpBuffer(query,
- "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
- tbinfo->dobj.catId.oid);
- }
- else
- {
- appendPQExpBuffer(query, "SELECT definition AS viewdef "
- "FROM pg_views WHERE viewname = ");
- appendStringLiteralAH(query, tbinfo->dobj.name, fout);
- appendPQExpBuffer(query, ";");
- }
+ /* Beginning in 7.3, viewname is not unique; rely on OID */
+ appendPQExpBuffer(query,
+ "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
+ tbinfo->dobj.catId.oid);
+ }
+ else
+ {
+ appendPQExpBufferStr(query, "SELECT definition AS viewdef "
+ "FROM pg_views WHERE viewname = ");
+ appendStringLiteralAH(query, tbinfo->dobj.name, fout);
+ }
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
- if (PQntuples(res) != 1)
- {
- if (PQntuples(res) < 1)
- write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
+ if (PQntuples(res) != 1)
+ {
+ if (PQntuples(res) < 1)
+ exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
tbinfo->dobj.name);
- else
- write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
+ else
+ exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
tbinfo->dobj.name);
- exit_nicely();
- }
+ }
- viewdef = PQgetvalue(res, 0, 0);
+ len = PQgetlength(res, 0, 0);
- if (strlen(viewdef) == 0)
- {
- write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
+ if (len == 0)
+ exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
tbinfo->dobj.name);
- exit_nicely();
- }
+
+ /* Strip off the trailing semicolon so that other things may follow. */
+ Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
+ appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
+
+ PQclear(res);
+ destroyPQExpBuffer(query);
+
+ return result;
+}
+
+/*
+ * dumpTableSchema
+ * write the declaration (not data) of one user-defined table or view
+ */
+static void
+dumpTableSchema(Archive *fout, TableInfo *tbinfo)
+{
+ PQExpBuffer q = createPQExpBuffer();
+ PQExpBuffer delq = createPQExpBuffer();
+ PQExpBuffer labelq = createPQExpBuffer();
+ int numParents;
+ TableInfo **parents;
+ int actual_atts; /* number of attrs in this CREATE statement */
+ const char *reltypename;
+ char *storage;
+ char *srvname;
+ char *ftoptions;
+ int j,
+ k;
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
+
+ if (binary_upgrade)
+ binary_upgrade_set_type_oids_by_rel_oid(fout, q,
+ tbinfo->dobj.catId.oid);
+
+ /* Is it a table or a view? */
+ if (tbinfo->relkind == RELKIND_VIEW)
+ {
+ PQExpBuffer result;
+
+ reltypename = "VIEW";
/*
* DROP must be fully qualified in case same name appears in
appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
- appendPQExpBuffer(q, " AS\n %s\n", viewdef);
+ result = createViewAsClause(fout, tbinfo);
+ appendPQExpBuffer(q, " AS\n%s", result->data);
+ destroyPQExpBuffer(result);
+
+ if (tbinfo->checkoption != NULL)
+ appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
+ appendPQExpBufferStr(q, ";\n");
appendPQExpBuffer(labelq, "VIEW %s",
fmtId(tbinfo->dobj.name));
-
- PQclear(res);
}
else
{
- if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
- {
- int i_srvname;
- int i_ftoptions;
-
- reltypename = "FOREIGN TABLE";
-
- /* retrieve name of foreign server and generic options */
- appendPQExpBuffer(query,
- "SELECT fs.srvname, "
- "pg_catalog.array_to_string(ARRAY("
- "SELECT pg_catalog.quote_ident(option_name) || "
- "' ' || pg_catalog.quote_literal(option_value) "
- "FROM pg_catalog.pg_options_to_table(ftoptions) "
- "ORDER BY option_name"
- "), E',\n ') AS ftoptions "
- "FROM pg_catalog.pg_foreign_table ft "
- "JOIN pg_catalog.pg_foreign_server fs "
- "ON (fs.oid = ft.ftserver) "
- "WHERE ft.ftrelid = '%u'",
- tbinfo->dobj.catId.oid);
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
- if (PQntuples(res) != 1)
- {
- write_msg(NULL, ngettext("query returned %d foreign server entry for foreign table \"%s\"\n",
- "query returned %d foreign server entries for foreign table \"%s\"\n",
- PQntuples(res)),
- PQntuples(res), tbinfo->dobj.name);
- exit_nicely();
- }
- i_srvname = PQfnumber(res, "srvname");
- i_ftoptions = PQfnumber(res, "ftoptions");
- srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
- ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
- PQclear(res);
- }
- else
+ switch (tbinfo->relkind)
{
- reltypename = "TABLE";
- srvname = NULL;
- ftoptions = NULL;
+ case (RELKIND_FOREIGN_TABLE):
+ {
+ PQExpBuffer query = createPQExpBuffer();
+ PGresult *res;
+ int i_srvname;
+ int i_ftoptions;
+
+ reltypename = "FOREIGN TABLE";
+
+ /* retrieve name of foreign server and generic options */
+ appendPQExpBuffer(query,
+ "SELECT fs.srvname, "
+ "pg_catalog.array_to_string(ARRAY("
+ "SELECT pg_catalog.quote_ident(option_name) || "
+ "' ' || pg_catalog.quote_literal(option_value) "
+ "FROM pg_catalog.pg_options_to_table(ftoptions) "
+ "ORDER BY option_name"
+ "), E',\n ') AS ftoptions "
+ "FROM pg_catalog.pg_foreign_table ft "
+ "JOIN pg_catalog.pg_foreign_server fs "
+ "ON (fs.oid = ft.ftserver) "
+ "WHERE ft.ftrelid = '%u'",
+ tbinfo->dobj.catId.oid);
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
+ i_srvname = PQfnumber(res, "srvname");
+ i_ftoptions = PQfnumber(res, "ftoptions");
+ srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
+ ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
+ PQclear(res);
+ destroyPQExpBuffer(query);
+ break;
+ }
+ case (RELKIND_MATVIEW):
+ reltypename = "MATERIALIZED VIEW";
+ srvname = NULL;
+ ftoptions = NULL;
+ break;
+ default:
+ reltypename = "TABLE";
+ srvname = NULL;
+ ftoptions = NULL;
}
+
numParents = tbinfo->numParents;
parents = tbinfo->parents;
if (tbinfo->reloftype && !binary_upgrade)
appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
- /* Dump the attributes */
- actual_atts = 0;
- for (j = 0; j < tbinfo->numatts; j++)
+ if (tbinfo->relkind != RELKIND_MATVIEW)
{
- /*
- * Normally, dump if it's locally defined in this table, and not
- * dropped. But for binary upgrade, we'll dump all the columns,
- * and then fix up the dropped and nonlocal cases below.
- */
- if (shouldPrintColumn(tbinfo, j))
+ /* Dump the attributes */
+ actual_atts = 0;
+ for (j = 0; j < tbinfo->numatts; j++)
{
/*
- * Default value --- suppress if to be printed separately.
- */
- bool has_default = (tbinfo->attrdefs[j] != NULL &&
- !tbinfo->attrdefs[j]->separate);
-
- /*
- * Not Null constraint --- suppress if inherited, except in
- * binary-upgrade case where that won't work.
+ * Normally, dump if it's locally defined in this table, and
+ * not dropped. But for binary upgrade, we'll dump all the
+ * columns, and then fix up the dropped and nonlocal cases
+ * below.
*/
- bool has_notnull = (tbinfo->notnull[j] &&
- (!tbinfo->inhNotNull[j] ||
- binary_upgrade));
-
- /* Skip column if fully defined by reloftype */
- if (tbinfo->reloftype &&
- !has_default && !has_notnull && !binary_upgrade)
- continue;
-
- /* Format properly if not first attr */
- if (actual_atts == 0)
- appendPQExpBuffer(q, " (");
- else
- appendPQExpBuffer(q, ",");
- appendPQExpBuffer(q, "\n ");
- actual_atts++;
-
- /* Attribute name */
- appendPQExpBuffer(q, "%s ",
- fmtId(tbinfo->attnames[j]));
-
- if (tbinfo->attisdropped[j])
+ if (shouldPrintColumn(tbinfo, j))
{
/*
- * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
- * so we will not have gotten a valid type name; insert
- * INTEGER as a stopgap. We'll clean things up later.
+ * Default value --- suppress if to be printed separately.
*/
- appendPQExpBuffer(q, "INTEGER /* dummy */");
- /* Skip all the rest, too */
- continue;
- }
+ bool has_default = (tbinfo->attrdefs[j] != NULL &&
+ !tbinfo->attrdefs[j]->separate);
- /* Attribute type */
- if (tbinfo->reloftype && !binary_upgrade)
- {
- appendPQExpBuffer(q, "WITH OPTIONS");
- }
- else if (fout->remoteVersion >= 70100)
- {
- appendPQExpBuffer(q, "%s",
- tbinfo->atttypnames[j]);
- }
- else
- {
- /* If no format_type, fake it */
- appendPQExpBuffer(q, "%s",
- myFormatType(tbinfo->atttypnames[j],
- tbinfo->atttypmod[j]));
- }
+ /*
+ * Not Null constraint --- suppress if inherited, except
+ * in binary-upgrade case where that won't work.
+ */
+ bool has_notnull = (tbinfo->notnull[j] &&
+ (!tbinfo->inhNotNull[j] ||
+ binary_upgrade));
+
+ /* Skip column if fully defined by reloftype */
+ if (tbinfo->reloftype &&
+ !has_default && !has_notnull && !binary_upgrade)
+ continue;
+
+ /* Format properly if not first attr */
+ if (actual_atts == 0)
+ appendPQExpBufferStr(q, " (");
+ else
+ appendPQExpBufferStr(q, ",");
+ appendPQExpBufferStr(q, "\n ");
+ actual_atts++;
- /* Add collation if not default for the type */
- if (OidIsValid(tbinfo->attcollation[j]))
- {
- CollInfo *coll;
+ /* Attribute name */
+ appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
+
+ if (tbinfo->attisdropped[j])
+ {
+ /*
+ * ALTER TABLE DROP COLUMN clears
+ * pg_attribute.atttypid, so we will not have gotten a
+ * valid type name; insert INTEGER as a stopgap. We'll
+ * clean things up later.
+ */
+ appendPQExpBufferStr(q, " INTEGER /* dummy */");
+ /* Skip all the rest, too */
+ continue;
+ }
- coll = findCollationByOid(tbinfo->attcollation[j]);
- if (coll)
+ /* Attribute type */
+ if (tbinfo->reloftype && !binary_upgrade)
{
- /* always schema-qualify, don't try to be smart */
- appendPQExpBuffer(q, " COLLATE %s.",
+ appendPQExpBufferStr(q, " WITH OPTIONS");
+ }
+ else if (fout->remoteVersion >= 70100)
+ {
+ appendPQExpBuffer(q, " %s",
+ tbinfo->atttypnames[j]);
+ }
+ else
+ {
+ /* If no format_type, fake it */
+ appendPQExpBuffer(q, " %s",
+ myFormatType(tbinfo->atttypnames[j],
+ tbinfo->atttypmod[j]));
+ }
+
+ /* Add collation if not default for the type */
+ if (OidIsValid(tbinfo->attcollation[j]))
+ {
+ CollInfo *coll;
+
+ coll = findCollationByOid(tbinfo->attcollation[j]);
+ if (coll)
+ {
+ /* always schema-qualify, don't try to be smart */
+ appendPQExpBuffer(q, " COLLATE %s.",
fmtId(coll->dobj.namespace->dobj.name));
- appendPQExpBuffer(q, "%s",
- fmtId(coll->dobj.name));
+ appendPQExpBufferStr(q, fmtId(coll->dobj.name));
+ }
}
- }
- if (has_default)
- appendPQExpBuffer(q, " DEFAULT %s",
- tbinfo->attrdefs[j]->adef_expr);
+ if (has_default)
+ appendPQExpBuffer(q, " DEFAULT %s",
+ tbinfo->attrdefs[j]->adef_expr);
- if (has_notnull)
- appendPQExpBuffer(q, " NOT NULL");
+ if (has_notnull)
+ appendPQExpBufferStr(q, " NOT NULL");
+ }
}
- }
- /*
- * Add non-inherited CHECK constraints, if any.
- */
- for (j = 0; j < tbinfo->ncheck; j++)
- {
- ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
+ /*
+ * Add non-inherited CHECK constraints, if any.
+ */
+ for (j = 0; j < tbinfo->ncheck; j++)
+ {
+ ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
- if (constr->separate || !constr->conislocal)
- continue;
+ if (constr->separate || !constr->conislocal)
+ continue;
- if (actual_atts == 0)
- appendPQExpBuffer(q, " (\n ");
- else
- appendPQExpBuffer(q, ",\n ");
+ if (actual_atts == 0)
+ appendPQExpBufferStr(q, " (\n ");
+ else
+ appendPQExpBufferStr(q, ",\n ");
- appendPQExpBuffer(q, "CONSTRAINT %s ",
- fmtId(constr->dobj.name));
- appendPQExpBuffer(q, "%s", constr->condef);
+ appendPQExpBuffer(q, "CONSTRAINT %s ",
+ fmtId(constr->dobj.name));
+ appendPQExpBufferStr(q, constr->condef);
- actual_atts++;
- }
+ actual_atts++;
+ }
- if (actual_atts)
- appendPQExpBuffer(q, "\n)");
- else if (!(tbinfo->reloftype && !binary_upgrade))
- {
- /*
- * We must have a parenthesized attribute list, even though empty,
- * when not using the OF TYPE syntax.
- */
- appendPQExpBuffer(q, " (\n)");
- }
+ if (actual_atts)
+ appendPQExpBufferStr(q, "\n)");
+ else if (!(tbinfo->reloftype && !binary_upgrade))
+ {
+ /*
+ * We must have a parenthesized attribute list, even though
+ * empty, when not using the OF TYPE syntax.
+ */
+ appendPQExpBufferStr(q, " (\n)");
+ }
- if (numParents > 0 && !binary_upgrade)
- {
- appendPQExpBuffer(q, "\nINHERITS (");
- for (k = 0; k < numParents; k++)
+ if (numParents > 0 && !binary_upgrade)
{
- TableInfo *parentRel = parents[k];
+ appendPQExpBufferStr(q, "\nINHERITS (");
+ for (k = 0; k < numParents; k++)
+ {
+ TableInfo *parentRel = parents[k];
- if (k > 0)
- appendPQExpBuffer(q, ", ");
- if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
- appendPQExpBuffer(q, "%s.",
+ if (k > 0)
+ appendPQExpBufferStr(q, ", ");
+ if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
+ appendPQExpBuffer(q, "%s.",
fmtId(parentRel->dobj.namespace->dobj.name));
- appendPQExpBuffer(q, "%s",
- fmtId(parentRel->dobj.name));
+ appendPQExpBufferStr(q, fmtId(parentRel->dobj.name));
+ }
+ appendPQExpBufferChar(q, ')');
}
- appendPQExpBuffer(q, ")");
- }
- if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
- appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
+ if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
+ appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
+ }
if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
(tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
{
bool addcomma = false;
- appendPQExpBuffer(q, "\nWITH (");
+ appendPQExpBufferStr(q, "\nWITH (");
if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
{
addcomma = true;
- appendPQExpBuffer(q, "%s", tbinfo->reloptions);
+ appendPQExpBufferStr(q, tbinfo->reloptions);
}
if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
{
appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
tbinfo->toast_reloptions);
}
- appendPQExpBuffer(q, ")");
+ appendPQExpBufferChar(q, ')');
}
/* Dump generic options if any */
if (ftoptions && ftoptions[0])
appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
- appendPQExpBuffer(q, ";\n");
+ /*
+ * For materialized views, create the AS clause just like a view. At
+ * this point, we always mark the view as not populated.
+ */
+ if (tbinfo->relkind == RELKIND_MATVIEW)
+ {
+ PQExpBuffer result;
+
+ result = createViewAsClause(fout, tbinfo);
+ appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
+ result->data);
+ destroyPQExpBuffer(result);
+ }
+ else
+ appendPQExpBufferStr(q, ";\n");
/*
* To create binary-compatible heap files, we have to ensure the same
* attislocal correctly, plus fix up any inherited CHECK constraints.
* Analogously, we set up typed tables using ALTER TABLE / OF here.
*/
- if (binary_upgrade && tbinfo->relkind == RELKIND_RELATION)
+ if (binary_upgrade && (tbinfo->relkind == RELKIND_RELATION ||
+ tbinfo->relkind == RELKIND_FOREIGN_TABLE) )
{
for (j = 0; j < tbinfo->numatts; j++)
{
if (tbinfo->attisdropped[j])
{
- appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
"SET attlen = %d, "
"attalign = '%c', attbyval = false\n"
tbinfo->attlen[j],
tbinfo->attalign[j]);
appendStringLiteralAH(q, tbinfo->attnames[j], fout);
- appendPQExpBuffer(q, "\n AND attrelid = ");
+ appendPQExpBufferStr(q, "\n AND attrelid = ");
appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
- appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
+ appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
+
+ if (tbinfo->relkind == RELKIND_RELATION)
+ appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
+ fmtId(tbinfo->dobj.name));
+ else
+ appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
+ fmtId(tbinfo->dobj.name));
- appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
- fmtId(tbinfo->dobj.name));
appendPQExpBuffer(q, "DROP COLUMN %s;\n",
fmtId(tbinfo->attnames[j]));
}
else if (!tbinfo->attislocal[j])
{
- appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
- appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
+ Assert(tbinfo->relkind != RELKIND_FOREIGN_TABLE);
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
+ appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
"SET attislocal = false\n"
"WHERE attname = ");
appendStringLiteralAH(q, tbinfo->attnames[j], fout);
- appendPQExpBuffer(q, "\n AND attrelid = ");
+ appendPQExpBufferStr(q, "\n AND attrelid = ");
appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
- appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
+ appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
}
}
if (constr->separate || constr->conislocal)
continue;
- appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
fmtId(tbinfo->dobj.name));
appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
fmtId(constr->dobj.name));
appendPQExpBuffer(q, "%s;\n", constr->condef);
- appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
+ appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
"SET conislocal = false\n"
"WHERE contype = 'c' AND conname = ");
appendStringLiteralAH(q, constr->dobj.name, fout);
- appendPQExpBuffer(q, "\n AND conrelid = ");
+ appendPQExpBufferStr(q, "\n AND conrelid = ");
appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
- appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
+ appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
}
if (numParents > 0)
{
- appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
for (k = 0; k < numParents; k++)
{
TableInfo *parentRel = parents[k];
if (tbinfo->reloftype)
{
- appendPQExpBuffer(q, "\n-- For binary upgrade, set up typed tables this way.\n");
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
fmtId(tbinfo->dobj.name),
tbinfo->reloftype);
}
- appendPQExpBuffer(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
"SET relfrozenxid = '%u'\n"
"WHERE oid = ",
tbinfo->frozenxid);
appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
- appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
+ appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
if (tbinfo->toast_oid)
{
/* We preserve the toast oids, so we can use it during restore */
- appendPQExpBuffer(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
"SET relfrozenxid = '%u'\n"
"WHERE oid = '%u';\n",
}
}
+ /*
+ * In binary_upgrade mode, restore matviews' populated status by
+ * poking pg_class directly. This is pretty ugly, but we can't use
+ * REFRESH MATERIALIZED VIEW since it's possible that some underlying
+ * matview is not populated even though this matview is.
+ */
+ if (binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
+ tbinfo->relispopulated)
+ {
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
+ appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
+ "SET relispopulated = 't'\n"
+ "WHERE oid = ");
+ appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
+ appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
+ }
+
/*
* Dump additional per-column properties that we can't handle in the
* main CREATE TABLE command.
}
}
+ /*
+ * dump properties we only have ALTER TABLE syntax for
+ */
+ if ((tbinfo->relkind == RELKIND_RELATION || tbinfo->relkind == RELKIND_MATVIEW) &&
+ tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
+ {
+ if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
+ {
+ /* nothing to do, will be set when the index is dumped */
+ }
+ else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
+ {
+ appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
+ fmtId(tbinfo->dobj.name));
+ }
+ else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
+ {
+ appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
+ fmtId(tbinfo->dobj.name));
+ }
+ }
+
if (binary_upgrade)
binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
(tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
tbinfo->rolname,
(strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
- reltypename, SECTION_PRE_DATA,
+ reltypename,
+ tbinfo->postponed_def ? SECTION_POST_DATA : SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
dumpTableConstraintComment(fout, constr);
}
- destroyPQExpBuffer(query);
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
destroyPQExpBuffer(labelq);
tbinfo->rolname,
false, "DEFAULT", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- adinfo->dobj.dependencies, adinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
destroyPQExpBuffer(q);
case TableOidAttributeNumber:
return "tableoid";
}
- write_msg(NULL, "invalid column number %d for table \"%s\"\n",
- attrnum, tblInfo->dobj.name);
- exit_nicely();
+ exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
+ attrnum, tblInfo->dobj.name);
return NULL; /* keep compiler quiet */
}
dumpIndex(Archive *fout, IndxInfo *indxinfo)
{
TableInfo *tbinfo = indxinfo->indextable;
+ bool is_constraint = (indxinfo->indexconstraint != 0);
PQExpBuffer q;
PQExpBuffer delq;
PQExpBuffer labelq;
/*
* If there's an associated constraint, don't dump the index per se, but
* do dump any comment for it. (This is safe because dependency ordering
- * will have ensured the constraint is emitted first.)
+ * will have ensured the constraint is emitted first.) Note that the
+ * emitted comment has to be shown as depending on the constraint, not
+ * the index, in such cases.
*/
- if (indxinfo->indexconstraint == 0)
+ if (!is_constraint)
{
if (binary_upgrade)
binary_upgrade_set_pg_class_oids(fout, q,
fmtId(indxinfo->dobj.name));
}
+ /* If the index defines identity, we need to record that. */
+ if (indxinfo->indisreplident)
+ {
+ appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
+ fmtId(tbinfo->dobj.name));
+ appendPQExpBuffer(q, " INDEX %s;\n",
+ fmtId(indxinfo->dobj.name));
+ }
+
/*
* DROP must be fully qualified in case same name appears in
* pg_catalog
tbinfo->rolname, false,
"INDEX", SECTION_POST_DATA,
q->data, delq->data, NULL,
- indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
dumpComment(fout, labelq->data,
tbinfo->dobj.namespace->dobj.name,
tbinfo->rolname,
- indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
+ indxinfo->dobj.catId, 0,
+ is_constraint ? indxinfo->indexconstraint :
+ indxinfo->dobj.dumpId);
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
if (indxinfo == NULL)
- {
- write_msg(NULL, "missing index for constraint \"%s\"\n",
- coninfo->dobj.name);
- exit_nicely();
- }
+ exit_horribly(NULL, "missing index for constraint \"%s\"\n",
+ coninfo->dobj.name);
if (binary_upgrade)
binary_upgrade_set_pg_class_oids(fout, q,
fmtId(attname));
}
- appendPQExpBuffer(q, ")");
+ appendPQExpBufferChar(q, ')');
if (indxinfo->options && strlen(indxinfo->options) > 0)
appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
if (coninfo->condeferrable)
{
- appendPQExpBuffer(q, " DEFERRABLE");
+ appendPQExpBufferStr(q, " DEFERRABLE");
if (coninfo->condeferred)
- appendPQExpBuffer(q, " INITIALLY DEFERRED");
+ appendPQExpBufferStr(q, " INITIALLY DEFERRED");
}
- appendPQExpBuffer(q, ";\n");
+ appendPQExpBufferStr(q, ";\n");
}
/* If the index is clustered, we need to record that. */
tbinfo->rolname, false,
"CONSTRAINT", SECTION_POST_DATA,
q->data, delq->data, NULL,
- coninfo->dobj.dependencies, coninfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
else if (coninfo->contype == 'f')
tbinfo->rolname, false,
"FK CONSTRAINT", SECTION_POST_DATA,
q->data, delq->data, NULL,
- coninfo->dobj.dependencies, coninfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
else if (coninfo->contype == 'c' && tbinfo)
/* Ignore if not to be dumped separately */
if (coninfo->separate)
{
- /* add ONLY if we do not want it to propagate to children */
- appendPQExpBuffer(q, "ALTER TABLE %s %s\n",
- coninfo->conisonly ? "ONLY" : "", fmtId(tbinfo->dobj.name));
+ /* not ONLY since we want it to propagate to children */
+ appendPQExpBuffer(q, "ALTER TABLE %s\n",
+ fmtId(tbinfo->dobj.name));
appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
fmtId(coninfo->dobj.name),
coninfo->condef);
tbinfo->rolname, false,
"CHECK CONSTRAINT", SECTION_POST_DATA,
q->data, delq->data, NULL,
- coninfo->dobj.dependencies, coninfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
}
tyinfo->rolname, false,
"CHECK CONSTRAINT", SECTION_POST_DATA,
q->data, delq->data, NULL,
- coninfo->dobj.dependencies, coninfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
}
else
{
- write_msg(NULL, "unrecognized constraint type: %c\n", coninfo->contype);
- exit_nicely();
+ exit_horribly(NULL, "unrecognized constraint type: %c\n",
+ coninfo->contype);
}
/* Dump Constraint Comments --- only works for table constraints */
findLastBuiltinOid_V71(Archive *fout, const char *dbname)
{
PGresult *res;
- int ntups;
Oid last_oid;
PQExpBuffer query = createPQExpBuffer();
resetPQExpBuffer(query);
- appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
+ appendPQExpBufferStr(query, "SELECT datlastsysoid from pg_database where datname = ");
appendStringLiteralAH(query, dbname, fout);
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
-
- ntups = PQntuples(res);
- if (ntups < 1)
- {
- write_msg(NULL, "missing pg_database entry for this database\n");
- exit_nicely();
- }
- if (ntups > 1)
- {
- write_msg(NULL, "found more than one pg_database entry for this database\n");
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
PQclear(res);
destroyPQExpBuffer(query);
findLastBuiltinOid_V70(Archive *fout)
{
PGresult *res;
- int ntups;
int last_oid;
- res = ExecuteSqlQuery(fout,
- "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
- PGRES_TUPLES_OK);
- ntups = PQntuples(res);
- if (ntups < 1)
- {
- write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
- exit_nicely();
- }
- if (ntups > 1)
- {
- write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout,
+ "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
PQclear(res);
return last_oid;
}
+/*
+ * dumpSequence
+ * write the declaration (not data) of one user-defined sequence
+ */
static void
dumpSequence(Archive *fout, TableInfo *tbinfo)
{
PGresult *res;
char *startv,
- *last,
*incby,
*maxv = NULL,
*minv = NULL,
*cache;
char bufm[100],
bufx[100];
- bool cycled,
- called;
+ bool cycled;
PQExpBuffer query = createPQExpBuffer();
PQExpBuffer delqry = createPQExpBuffer();
PQExpBuffer labelq = createPQExpBuffer();
{
appendPQExpBuffer(query,
"SELECT sequence_name, "
- "start_value, last_value, increment_by, "
+ "start_value, increment_by, "
"CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
" WHEN increment_by < 0 AND max_value = -1 THEN NULL "
" ELSE max_value "
" WHEN increment_by < 0 AND min_value = %s THEN NULL "
" ELSE min_value "
"END AS min_value, "
- "cache_value, is_cycled, is_called from %s",
+ "cache_value, is_cycled FROM %s",
bufx, bufm,
fmtId(tbinfo->dobj.name));
}
{
appendPQExpBuffer(query,
"SELECT sequence_name, "
- "0 AS start_value, last_value, increment_by, "
+ "0 AS start_value, increment_by, "
"CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
" WHEN increment_by < 0 AND max_value = -1 THEN NULL "
" ELSE max_value "
" WHEN increment_by < 0 AND min_value = %s THEN NULL "
" ELSE min_value "
"END AS min_value, "
- "cache_value, is_cycled, is_called from %s",
+ "cache_value, is_cycled FROM %s",
bufx, bufm,
fmtId(tbinfo->dobj.name));
}
"query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
PQntuples(res)),
tbinfo->dobj.name, PQntuples(res));
- exit_nicely();
+ exit_nicely(1);
}
/* Disable this check: it fails if sequence has been renamed */
{
write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
tbinfo->dobj.name, PQgetvalue(res, 0, 0));
- exit_nicely();
+ exit_nicely(1);
}
#endif
startv = PQgetvalue(res, 0, 1);
- last = PQgetvalue(res, 0, 2);
- incby = PQgetvalue(res, 0, 3);
+ incby = PQgetvalue(res, 0, 2);
+ if (!PQgetisnull(res, 0, 3))
+ maxv = PQgetvalue(res, 0, 3);
if (!PQgetisnull(res, 0, 4))
- maxv = PQgetvalue(res, 0, 4);
- if (!PQgetisnull(res, 0, 5))
- minv = PQgetvalue(res, 0, 5);
- cache = PQgetvalue(res, 0, 6);
- cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
- called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
+ minv = PQgetvalue(res, 0, 4);
+ cache = PQgetvalue(res, 0, 5);
+ cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
/*
- * The logic we use for restoring sequences is as follows:
- *
- * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
- * last_val for start if called is false, else use min_val for start_val).
- * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
- * BY command for it.
- *
- * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
+ * DROP must be fully qualified in case same name appears in pg_catalog
*/
- if (!dataOnly)
- {
- /*
- * DROP must be fully qualified in case same name appears in
- * pg_catalog
- */
- appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
- fmtId(tbinfo->dobj.namespace->dobj.name));
- appendPQExpBuffer(delqry, "%s;\n",
- fmtId(tbinfo->dobj.name));
+ appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
+ fmtId(tbinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delqry, "%s;\n",
+ fmtId(tbinfo->dobj.name));
- resetPQExpBuffer(query);
+ resetPQExpBuffer(query);
- if (binary_upgrade)
- {
- binary_upgrade_set_pg_class_oids(fout, query,
- tbinfo->dobj.catId.oid, false);
- binary_upgrade_set_type_oids_by_rel_oid(fout, query,
- tbinfo->dobj.catId.oid);
- }
+ if (binary_upgrade)
+ {
+ binary_upgrade_set_pg_class_oids(fout, query,
+ tbinfo->dobj.catId.oid, false);
+ binary_upgrade_set_type_oids_by_rel_oid(fout, query,
+ tbinfo->dobj.catId.oid);
+ }
- appendPQExpBuffer(query,
- "CREATE SEQUENCE %s\n",
- fmtId(tbinfo->dobj.name));
+ appendPQExpBuffer(query,
+ "CREATE SEQUENCE %s\n",
+ fmtId(tbinfo->dobj.name));
- if (fout->remoteVersion >= 80400)
- appendPQExpBuffer(query, " START WITH %s\n", startv);
- else
- {
- /*
- * Versions before 8.4 did not remember the true start value. If
- * is_called is false then the sequence has never been incremented
- * so we can use last_val. Otherwise punt and let it default.
- */
- if (!called)
- appendPQExpBuffer(query, " START WITH %s\n", last);
- }
+ if (fout->remoteVersion >= 80400)
+ appendPQExpBuffer(query, " START WITH %s\n", startv);
- appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
+ appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
- if (minv)
- appendPQExpBuffer(query, " MINVALUE %s\n", minv);
- else
- appendPQExpBuffer(query, " NO MINVALUE\n");
+ if (minv)
+ appendPQExpBuffer(query, " MINVALUE %s\n", minv);
+ else
+ appendPQExpBufferStr(query, " NO MINVALUE\n");
- if (maxv)
- appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
- else
- appendPQExpBuffer(query, " NO MAXVALUE\n");
+ if (maxv)
+ appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
+ else
+ appendPQExpBufferStr(query, " NO MAXVALUE\n");
- appendPQExpBuffer(query,
- " CACHE %s%s",
- cache, (cycled ? "\n CYCLE" : ""));
+ appendPQExpBuffer(query,
+ " CACHE %s%s",
+ cache, (cycled ? "\n CYCLE" : ""));
- appendPQExpBuffer(query, ";\n");
+ appendPQExpBufferStr(query, ";\n");
- appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
+ appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
- /* binary_upgrade: no need to clear TOAST table oid */
+ /* binary_upgrade: no need to clear TOAST table oid */
- if (binary_upgrade)
- binary_upgrade_extension_member(query, &tbinfo->dobj,
- labelq->data);
+ if (binary_upgrade)
+ binary_upgrade_extension_member(query, &tbinfo->dobj,
+ labelq->data);
- ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
- tbinfo->dobj.name,
- tbinfo->dobj.namespace->dobj.name,
- NULL,
- tbinfo->rolname,
- false, "SEQUENCE", SECTION_PRE_DATA,
- query->data, delqry->data, NULL,
- tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
- NULL, NULL);
+ ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
+ tbinfo->dobj.name,
+ tbinfo->dobj.namespace->dobj.name,
+ NULL,
+ tbinfo->rolname,
+ false, "SEQUENCE", SECTION_PRE_DATA,
+ query->data, delqry->data, NULL,
+ NULL, 0,
+ NULL, NULL);
- /*
- * If the sequence is owned by a table column, emit the ALTER for it
- * as a separate TOC entry immediately following the sequence's own
- * entry. It's OK to do this rather than using full sorting logic,
- * because the dependency that tells us it's owned will have forced
- * the table to be created first. We can't just include the ALTER in
- * the TOC entry because it will fail if we haven't reassigned the
- * sequence owner to match the table's owner.
- *
- * We need not schema-qualify the table reference because both
- * sequence and table must be in the same schema.
- */
- if (OidIsValid(tbinfo->owning_tab))
- {
- TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab);
+ /*
+ * If the sequence is owned by a table column, emit the ALTER for it as a
+ * separate TOC entry immediately following the sequence's own entry. It's
+ * OK to do this rather than using full sorting logic, because the
+ * dependency that tells us it's owned will have forced the table to be
+ * created first. We can't just include the ALTER in the TOC entry
+ * because it will fail if we haven't reassigned the sequence owner to
+ * match the table's owner.
+ *
+ * We need not schema-qualify the table reference because both sequence
+ * and table must be in the same schema.
+ */
+ if (OidIsValid(tbinfo->owning_tab))
+ {
+ TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab);
- if (owning_tab && owning_tab->dobj.dump)
- {
- resetPQExpBuffer(query);
- appendPQExpBuffer(query, "ALTER SEQUENCE %s",
- fmtId(tbinfo->dobj.name));
- appendPQExpBuffer(query, " OWNED BY %s",
- fmtId(owning_tab->dobj.name));
- appendPQExpBuffer(query, ".%s;\n",
+ if (owning_tab && owning_tab->dobj.dump)
+ {
+ resetPQExpBuffer(query);
+ appendPQExpBuffer(query, "ALTER SEQUENCE %s",
+ fmtId(tbinfo->dobj.name));
+ appendPQExpBuffer(query, " OWNED BY %s",
+ fmtId(owning_tab->dobj.name));
+ appendPQExpBuffer(query, ".%s;\n",
fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
- ArchiveEntry(fout, nilCatalogId, createDumpId(),
- tbinfo->dobj.name,
- tbinfo->dobj.namespace->dobj.name,
- NULL,
- tbinfo->rolname,
- false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
- query->data, "", NULL,
- &(tbinfo->dobj.dumpId), 1,
- NULL, NULL);
- }
+ ArchiveEntry(fout, nilCatalogId, createDumpId(),
+ tbinfo->dobj.name,
+ tbinfo->dobj.namespace->dobj.name,
+ NULL,
+ tbinfo->rolname,
+ false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
+ query->data, "", NULL,
+ &(tbinfo->dobj.dumpId), 1,
+ NULL, NULL);
}
-
- /* Dump Sequence Comments and Security Labels */
- dumpComment(fout, labelq->data,
- tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
- tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
- dumpSecLabel(fout, labelq->data,
- tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
- tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
}
- if (!schemaOnly)
- {
- resetPQExpBuffer(query);
- appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
- appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
- appendPQExpBuffer(query, ", %s, %s);\n",
- last, (called ? "true" : "false"));
-
- ArchiveEntry(fout, nilCatalogId, createDumpId(),
- tbinfo->dobj.name,
- tbinfo->dobj.namespace->dobj.name,
- NULL,
- tbinfo->rolname,
- false, "SEQUENCE SET", SECTION_PRE_DATA,
- query->data, "", NULL,
- &(tbinfo->dobj.dumpId), 1,
- NULL, NULL);
- }
+ /* Dump Sequence Comments and Security Labels */
+ dumpComment(fout, labelq->data,
+ tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+ tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
+ dumpSecLabel(fout, labelq->data,
+ tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+ tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
PQclear(res);
destroyPQExpBuffer(labelq);
}
+/*
+ * dumpSequenceData
+ * write the data of one user-defined sequence
+ */
+static void
+dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
+{
+ TableInfo *tbinfo = tdinfo->tdtable;
+ PGresult *res;
+ char *last;
+ bool called;
+ PQExpBuffer query = createPQExpBuffer();
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
+
+ appendPQExpBuffer(query,
+ "SELECT last_value, is_called FROM %s",
+ fmtId(tbinfo->dobj.name));
+
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+ if (PQntuples(res) != 1)
+ {
+ write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
+ "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
+ PQntuples(res)),
+ tbinfo->dobj.name, PQntuples(res));
+ exit_nicely(1);
+ }
+
+ last = PQgetvalue(res, 0, 0);
+ called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
+
+ resetPQExpBuffer(query);
+ appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
+ appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
+ appendPQExpBuffer(query, ", %s, %s);\n",
+ last, (called ? "true" : "false"));
+
+ ArchiveEntry(fout, nilCatalogId, createDumpId(),
+ tbinfo->dobj.name,
+ tbinfo->dobj.namespace->dobj.name,
+ NULL,
+ tbinfo->rolname,
+ false, "SEQUENCE SET", SECTION_DATA,
+ query->data, "", NULL,
+ &(tbinfo->dobj.dumpId), 1,
+ NULL, NULL);
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+}
+
+/*
+ * dumpTrigger
+ * write the declaration of one user-defined table trigger
+ */
static void
dumpTrigger(Archive *fout, TriggerInfo *tginfo)
{
const char *p;
int findx;
+ /*
+ * we needn't check dobj.dump because TriggerInfo wouldn't have been
+ * created in the first place for non-dumpable triggers
+ */
if (dataOnly)
return;
{
if (tginfo->tgisconstraint)
{
- appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
+ appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
}
else
{
- appendPQExpBuffer(query, "CREATE TRIGGER ");
+ appendPQExpBufferStr(query, "CREATE TRIGGER ");
appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
}
- appendPQExpBuffer(query, "\n ");
+ appendPQExpBufferStr(query, "\n ");
/* Trigger type */
if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
- appendPQExpBuffer(query, "BEFORE");
+ appendPQExpBufferStr(query, "BEFORE");
else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
- appendPQExpBuffer(query, "AFTER");
+ appendPQExpBufferStr(query, "AFTER");
else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
- appendPQExpBuffer(query, "INSTEAD OF");
+ appendPQExpBufferStr(query, "INSTEAD OF");
else
{
write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
- exit_nicely();
+ exit_nicely(1);
}
findx = 0;
if (TRIGGER_FOR_INSERT(tginfo->tgtype))
{
- appendPQExpBuffer(query, " INSERT");
+ appendPQExpBufferStr(query, " INSERT");
findx++;
}
if (TRIGGER_FOR_DELETE(tginfo->tgtype))
{
if (findx > 0)
- appendPQExpBuffer(query, " OR DELETE");
+ appendPQExpBufferStr(query, " OR DELETE");
else
- appendPQExpBuffer(query, " DELETE");
+ appendPQExpBufferStr(query, " DELETE");
findx++;
}
if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
{
if (findx > 0)
- appendPQExpBuffer(query, " OR UPDATE");
+ appendPQExpBufferStr(query, " OR UPDATE");
else
- appendPQExpBuffer(query, " UPDATE");
+ appendPQExpBufferStr(query, " UPDATE");
findx++;
}
if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
{
if (findx > 0)
- appendPQExpBuffer(query, " OR TRUNCATE");
+ appendPQExpBufferStr(query, " OR TRUNCATE");
else
- appendPQExpBuffer(query, " TRUNCATE");
+ appendPQExpBufferStr(query, " TRUNCATE");
findx++;
}
appendPQExpBuffer(query, " ON %s\n",
fmtId(tginfo->tgconstrrelname));
}
if (!tginfo->tgdeferrable)
- appendPQExpBuffer(query, "NOT ");
- appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
+ appendPQExpBufferStr(query, "NOT ");
+ appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
if (tginfo->tginitdeferred)
- appendPQExpBuffer(query, "DEFERRED\n");
+ appendPQExpBufferStr(query, "DEFERRED\n");
else
- appendPQExpBuffer(query, "IMMEDIATE\n");
+ appendPQExpBufferStr(query, "IMMEDIATE\n");
}
if (TRIGGER_FOR_ROW(tginfo->tgtype))
- appendPQExpBuffer(query, " FOR EACH ROW\n ");
+ appendPQExpBufferStr(query, " FOR EACH ROW\n ");
else
- appendPQExpBuffer(query, " FOR EACH STATEMENT\n ");
+ appendPQExpBufferStr(query, " FOR EACH STATEMENT\n ");
/* In 7.3, result of regproc is already quoted */
if (fout->remoteVersion >= 70300)
tginfo->tgargs,
tginfo->dobj.name,
tbinfo->dobj.name);
- exit_nicely();
+ exit_nicely(1);
}
if (findx > 0)
- appendPQExpBuffer(query, ", ");
+ appendPQExpBufferStr(query, ", ");
appendStringLiteralAH(query, p, fout);
p += tlen + 1;
}
free(tgargs);
- appendPQExpBuffer(query, ");\n");
+ appendPQExpBufferStr(query, ");\n");
}
if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
{
case 'D':
case 'f':
- appendPQExpBuffer(query, "DISABLE");
+ appendPQExpBufferStr(query, "DISABLE");
break;
case 'A':
- appendPQExpBuffer(query, "ENABLE ALWAYS");
+ appendPQExpBufferStr(query, "ENABLE ALWAYS");
break;
case 'R':
- appendPQExpBuffer(query, "ENABLE REPLICA");
+ appendPQExpBufferStr(query, "ENABLE REPLICA");
break;
default:
- appendPQExpBuffer(query, "ENABLE");
+ appendPQExpBufferStr(query, "ENABLE");
break;
}
appendPQExpBuffer(query, " TRIGGER %s;\n",
tbinfo->rolname, false,
"TRIGGER", SECTION_POST_DATA,
query->data, delqry->data, NULL,
- tginfo->dobj.dependencies, tginfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
dumpComment(fout, labelq->data,
destroyPQExpBuffer(labelq);
}
+/*
+ * dumpEventTrigger
+ * write the declaration of one user-defined event trigger
+ */
+static void
+dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
+{
+ PQExpBuffer query;
+ PQExpBuffer labelq;
+
+ /* Skip if not to be dumped */
+ if (!evtinfo->dobj.dump || dataOnly)
+ return;
+
+ query = createPQExpBuffer();
+ labelq = createPQExpBuffer();
+
+ appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
+ appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
+ appendPQExpBufferStr(query, " ON ");
+ appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
+ appendPQExpBufferStr(query, " ");
+
+ if (strcmp("", evtinfo->evttags) != 0)
+ {
+ appendPQExpBufferStr(query, "\n WHEN TAG IN (");
+ appendPQExpBufferStr(query, evtinfo->evttags);
+ appendPQExpBufferStr(query, ") ");
+ }
+
+ appendPQExpBufferStr(query, "\n EXECUTE PROCEDURE ");
+ appendPQExpBufferStr(query, evtinfo->evtfname);
+ appendPQExpBufferStr(query, "();\n");
+
+ if (evtinfo->evtenabled != 'O')
+ {
+ appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
+ fmtId(evtinfo->dobj.name));
+ switch (evtinfo->evtenabled)
+ {
+ case 'D':
+ appendPQExpBufferStr(query, "DISABLE");
+ break;
+ case 'A':
+ appendPQExpBufferStr(query, "ENABLE ALWAYS");
+ break;
+ case 'R':
+ appendPQExpBufferStr(query, "ENABLE REPLICA");
+ break;
+ default:
+ appendPQExpBufferStr(query, "ENABLE");
+ break;
+ }
+ appendPQExpBufferStr(query, ";\n");
+ }
+ appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
+ fmtId(evtinfo->dobj.name));
+
+ ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
+ evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
+ "EVENT TRIGGER", SECTION_POST_DATA,
+ query->data, "", NULL, NULL, 0, NULL, NULL);
+
+ dumpComment(fout, labelq->data,
+ NULL, NULL,
+ evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
+
+ destroyPQExpBuffer(query);
+ destroyPQExpBuffer(labelq);
+}
+
/*
* dumpRule
* Dump a rule
{
write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
rinfo->dobj.name, tbinfo->dobj.name);
- exit_nicely();
+ exit_nicely(1);
}
printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
*/
if (rinfo->ev_enabled != 'O')
{
- appendPQExpBuffer(cmd, "ALTER TABLE %s.",
- fmtId(tbinfo->dobj.namespace->dobj.name));
- appendPQExpBuffer(cmd, "%s ",
- fmtId(tbinfo->dobj.name));
+ appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name));
switch (rinfo->ev_enabled)
{
case 'A':
}
}
+ /*
+ * Apply view's reloptions when its ON SELECT rule is separate.
+ */
+ if (rinfo->reloptions && strlen(rinfo->reloptions) > 0)
+ {
+ appendPQExpBuffer(cmd, "ALTER VIEW %s SET (%s);\n",
+ fmtId(tbinfo->dobj.name),
+ rinfo->reloptions);
+ }
+
/*
* DROP must be fully qualified in case same name appears in pg_catalog
*/
tbinfo->rolname, false,
"RULE", SECTION_POST_DATA,
cmd->data, delcmd->data, NULL,
- rinfo->dobj.dependencies, rinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump rule comments */
query = createPQExpBuffer();
/* refclassid constraint is redundant but may speed the search */
- appendPQExpBuffer(query, "SELECT "
- "classid, objid, refclassid, refobjid "
- "FROM pg_depend "
- "WHERE refclassid = 'pg_extension'::regclass "
- "AND deptype = 'e' "
- "ORDER BY 3,4");
+ appendPQExpBufferStr(query, "SELECT "
+ "classid, objid, refclassid, refobjid "
+ "FROM pg_depend "
+ "WHERE refclassid = 'pg_extension'::regclass "
+ "AND deptype = 'e' "
+ "ORDER BY 3,4");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
int nconfigitems;
int nconditionitems;
- /* Tables of not-to-be-dumped extensions shouldn't be dumped */
- if (!curext->dobj.dump)
- continue;
-
if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
nconfigitems == nconditionitems)
for (j = 0; j < nconfigitems; j++)
{
TableInfo *configtbl;
+ Oid configtbloid = atooid(extconfigarray[j]);
+ bool dumpobj = curext->dobj.dump;
- configtbl = findTableByOid(atooid(extconfigarray[j]));
+ configtbl = findTableByOid(configtbloid);
if (configtbl == NULL)
continue;
/*
- * Note: config tables are dumped without OIDs regardless
- * of the --oids setting. This is because row filtering
- * conditions aren't compatible with dumping OIDs.
+ * Tables of not-to-be-dumped extensions shouldn't be dumped
+ * unless the table or its schema is explicitly included
*/
- makeTableDataInfo(configtbl, false);
- if (configtbl->dataObj != NULL)
+ if (!curext->dobj.dump)
{
- if (strlen(extconditionarray[j]) > 0)
- configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
+ /* check table explicitly requested */
+ if (table_include_oids.head != NULL &&
+ simple_oid_list_member(&table_include_oids,
+ configtbloid))
+ dumpobj = true;
+
+ /* check table's schema explicitly requested */
+ if (configtbl->dobj.namespace->dobj.dump)
+ dumpobj = true;
+ }
+
+ /* check table excluded by an exclusion switch */
+ if (table_exclude_oids.head != NULL &&
+ simple_oid_list_member(&table_exclude_oids,
+ configtbloid))
+ dumpobj = false;
+
+ /* check schema excluded by an exclusion switch */
+ if (simple_oid_list_member(&schema_exclude_oids,
+ configtbl->dobj.namespace->dobj.catId.oid))
+ dumpobj = false;
+
+ if (dumpobj)
+ {
+ /*
+ * Note: config tables are dumped without OIDs regardless
+ * of the --oids setting. This is because row filtering
+ * conditions aren't compatible with dumping OIDs.
+ */
+ makeTableDataInfo(configtbl, false);
+ if (configtbl->dataObj != NULL)
+ {
+ if (strlen(extconditionarray[j]) > 0)
+ configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
+ }
}
}
}
* PIN dependencies aren't interesting, and EXTENSION dependencies were
* already processed by getExtensionMembership.
*/
- appendPQExpBuffer(query, "SELECT "
- "classid, objid, refclassid, refobjid, deptype "
- "FROM pg_depend "
- "WHERE deptype != 'p' AND deptype != 'e' "
- "ORDER BY 1,2");
+ appendPQExpBufferStr(query, "SELECT "
+ "classid, objid, refclassid, refobjid, deptype "
+ "FROM pg_depend "
+ "WHERE deptype != 'p' AND deptype != 'e' "
+ "ORDER BY 1,2");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
}
+/*
+ * createBoundaryObjects - create dummy DumpableObjects to represent
+ * dump section boundaries.
+ */
+static DumpableObject *
+createBoundaryObjects(void)
+{
+ DumpableObject *dobjs;
+
+ dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
+
+ dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
+ dobjs[0].catId = nilCatalogId;
+ AssignDumpId(dobjs + 0);
+ dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
+
+ dobjs[1].objType = DO_POST_DATA_BOUNDARY;
+ dobjs[1].catId = nilCatalogId;
+ AssignDumpId(dobjs + 1);
+ dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
+
+ return dobjs;
+}
+
+/*
+ * addBoundaryDependencies - add dependencies as needed to enforce the dump
+ * section boundaries.
+ */
+static void
+addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
+ DumpableObject *boundaryObjs)
+{
+ DumpableObject *preDataBound = boundaryObjs + 0;
+ DumpableObject *postDataBound = boundaryObjs + 1;
+ int i;
+
+ for (i = 0; i < numObjs; i++)
+ {
+ DumpableObject *dobj = dobjs[i];
+
+ /*
+ * The classification of object types here must match the SECTION_xxx
+ * values assigned during subsequent ArchiveEntry calls!
+ */
+ switch (dobj->objType)
+ {
+ case DO_NAMESPACE:
+ case DO_EXTENSION:
+ case DO_TYPE:
+ case DO_SHELL_TYPE:
+ case DO_FUNC:
+ case DO_AGG:
+ case DO_OPERATOR:
+ case DO_OPCLASS:
+ case DO_OPFAMILY:
+ case DO_COLLATION:
+ case DO_CONVERSION:
+ case DO_TABLE:
+ case DO_ATTRDEF:
+ case DO_PROCLANG:
+ case DO_CAST:
+ case DO_DUMMY_TYPE:
+ case DO_TSPARSER:
+ case DO_TSDICT:
+ case DO_TSTEMPLATE:
+ case DO_TSCONFIG:
+ case DO_FDW:
+ case DO_FOREIGN_SERVER:
+ case DO_BLOB:
+ /* Pre-data objects: must come before the pre-data boundary */
+ addObjectDependency(preDataBound, dobj->dumpId);
+ break;
+ case DO_TABLE_DATA:
+ case DO_BLOB_DATA:
+ /* Data objects: must come between the boundaries */
+ addObjectDependency(dobj, preDataBound->dumpId);
+ addObjectDependency(postDataBound, dobj->dumpId);
+ break;
+ case DO_INDEX:
+ case DO_REFRESH_MATVIEW:
+ case DO_TRIGGER:
+ case DO_EVENT_TRIGGER:
+ case DO_DEFAULT_ACL:
+ /* Post-data objects: must come after the post-data boundary */
+ addObjectDependency(dobj, postDataBound->dumpId);
+ break;
+ case DO_RULE:
+ /* Rules are post-data, but only if dumped separately */
+ if (((RuleInfo *) dobj)->separate)
+ addObjectDependency(dobj, postDataBound->dumpId);
+ break;
+ case DO_CONSTRAINT:
+ case DO_FK_CONSTRAINT:
+ /* Constraints are post-data, but only if dumped separately */
+ if (((ConstraintInfo *) dobj)->separate)
+ addObjectDependency(dobj, postDataBound->dumpId);
+ break;
+ case DO_PRE_DATA_BOUNDARY:
+ /* nothing to do */
+ break;
+ case DO_POST_DATA_BOUNDARY:
+ /* must come after the pre-data boundary */
+ addObjectDependency(dobj, preDataBound->dumpId);
+ break;
+ }
+ }
+}
+
+
+/*
+ * BuildArchiveDependencies - create dependency data for archive TOC entries
+ *
+ * The raw dependency data obtained by getDependencies() is not terribly
+ * useful in an archive dump, because in many cases there are dependency
+ * chains linking through objects that don't appear explicitly in the dump.
+ * For example, a view will depend on its _RETURN rule while the _RETURN rule
+ * will depend on other objects --- but the rule will not appear as a separate
+ * object in the dump. We need to adjust the view's dependencies to include
+ * whatever the rule depends on that is included in the dump.
+ *
+ * Just to make things more complicated, there are also "special" dependencies
+ * such as the dependency of a TABLE DATA item on its TABLE, which we must
+ * not rearrange because pg_restore knows that TABLE DATA only depends on
+ * its table. In these cases we must leave the dependencies strictly as-is
+ * even if they refer to not-to-be-dumped objects.
+ *
+ * To handle this, the convention is that "special" dependencies are created
+ * during ArchiveEntry calls, and an archive TOC item that has any such
+ * entries will not be touched here. Otherwise, we recursively search the
+ * DumpableObject data structures to build the correct dependencies for each
+ * archive TOC item.
+ */
+static void
+BuildArchiveDependencies(Archive *fout)
+{
+ ArchiveHandle *AH = (ArchiveHandle *) fout;
+ TocEntry *te;
+
+ /* Scan all TOC entries in the archive */
+ for (te = AH->toc->next; te != AH->toc; te = te->next)
+ {
+ DumpableObject *dobj;
+ DumpId *dependencies;
+ int nDeps;
+ int allocDeps;
+
+ /* No need to process entries that will not be dumped */
+ if (te->reqs == 0)
+ continue;
+ /* Ignore entries that already have "special" dependencies */
+ if (te->nDeps > 0)
+ continue;
+ /* Otherwise, look up the item's original DumpableObject, if any */
+ dobj = findObjectByDumpId(te->dumpId);
+ if (dobj == NULL)
+ continue;
+ /* No work if it has no dependencies */
+ if (dobj->nDeps <= 0)
+ continue;
+ /* Set up work array */
+ allocDeps = 64;
+ dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
+ nDeps = 0;
+ /* Recursively find all dumpable dependencies */
+ findDumpableDependencies(AH, dobj,
+ &dependencies, &nDeps, &allocDeps);
+ /* And save 'em ... */
+ if (nDeps > 0)
+ {
+ dependencies = (DumpId *) pg_realloc(dependencies,
+ nDeps * sizeof(DumpId));
+ te->dependencies = dependencies;
+ te->nDeps = nDeps;
+ }
+ else
+ free(dependencies);
+ }
+}
+
+/* Recursive search subroutine for BuildArchiveDependencies */
+static void
+findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
+ DumpId **dependencies, int *nDeps, int *allocDeps)
+{
+ int i;
+
+ /*
+ * Ignore section boundary objects: if we search through them, we'll
+ * report lots of bogus dependencies.
+ */
+ if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
+ dobj->objType == DO_POST_DATA_BOUNDARY)
+ return;
+
+ for (i = 0; i < dobj->nDeps; i++)
+ {
+ DumpId depid = dobj->dependencies[i];
+
+ if (TocIDRequired(AH, depid) != 0)
+ {
+ /* Object will be dumped, so just reference it as a dependency */
+ if (*nDeps >= *allocDeps)
+ {
+ *allocDeps *= 2;
+ *dependencies = (DumpId *) pg_realloc(*dependencies,
+ *allocDeps * sizeof(DumpId));
+ }
+ (*dependencies)[*nDeps] = depid;
+ (*nDeps)++;
+ }
+ else
+ {
+ /*
+ * Object will not be dumped, so recursively consider its deps. We
+ * rely on the assumption that sortDumpableObjects already broke
+ * any dependency loops, else we might recurse infinitely.
+ */
+ DumpableObject *otherdobj = findObjectByDumpId(depid);
+
+ if (otherdobj)
+ findDumpableDependencies(AH, otherdobj,
+ dependencies, nDeps, allocDeps);
+ }
+ }
+}
+
+
/*
* selectSourceSchema - make the specified schema the active search path
* in the source database.
*
* Whenever the selected schema is not pg_catalog, be careful to qualify
* references to system catalogs and types in our emitted commands!
+ *
+ * This function is called only from selectSourceSchemaOnAH and
+ * selectSourceSchema.
*/
static void
selectSourceSchema(Archive *fout, const char *schemaName)
{
- static char *curSchemaName = NULL;
PQExpBuffer query;
+ /* This is checked by the callers already */
+ Assert(schemaName != NULL && *schemaName != '\0');
+
/* Not relevant if fetching from pre-7.3 DB */
if (fout->remoteVersion < 70300)
return;
- /* Ignore null schema names */
- if (schemaName == NULL || *schemaName == '\0')
- return;
- /* Optimize away repeated selection of same schema */
- if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
- return;
query = createPQExpBuffer();
appendPQExpBuffer(query, "SET search_path = %s",
fmtId(schemaName));
if (strcmp(schemaName, "pg_catalog") != 0)
- appendPQExpBuffer(query, ", pg_catalog");
+ appendPQExpBufferStr(query, ", pg_catalog");
ExecuteSqlStatement(fout, query->data);
destroyPQExpBuffer(query);
- if (curSchemaName)
- free(curSchemaName);
- curSchemaName = pg_strdup(schemaName);
}
/*
char *result;
PQExpBuffer query;
PGresult *res;
- int ntups;
if (oid == 0)
{
oid);
}
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
- ntups = PQntuples(res);
- if (ntups != 1)
- {
- write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
- "query returned %d rows instead of one: %s\n",
- ntups),
- ntups, query->data);
- exit_nicely();
- }
+ res = ExecuteSqlQueryForSingleRow(fout, query->data);
if (fout->remoteVersion >= 70100)
{
{
int len = (typmod - VARHDRSZ);
- appendPQExpBuffer(buf, "character");
+ appendPQExpBufferStr(buf, "character");
if (len > 1)
appendPQExpBuffer(buf, "(%d)",
typmod - VARHDRSZ);
}
else if (strcmp(typname, "varchar") == 0)
{
- appendPQExpBuffer(buf, "character varying");
+ appendPQExpBufferStr(buf, "character varying");
if (typmod != -1)
appendPQExpBuffer(buf, "(%d)",
typmod - VARHDRSZ);
}
else if (strcmp(typname, "numeric") == 0)
{
- appendPQExpBuffer(buf, "numeric");
+ appendPQExpBufferStr(buf, "numeric");
if (typmod != -1)
{
int32 tmp_typmod;
* through with quotes. - thomas 1998-12-13
*/
else if (strcmp(typname, "char") == 0)
- appendPQExpBuffer(buf, "\"char\"");
+ appendPQExpBufferStr(buf, "\"char\"");
else
- appendPQExpBuffer(buf, "%s", fmtId(typname));
+ appendPQExpBufferStr(buf, fmtId(typname));
/* Append array qualifier for array types */
if (isarray)
- appendPQExpBuffer(buf, "[]");
+ appendPQExpBufferStr(buf, "[]");
result = pg_strdup(buf->data);
destroyPQExpBuffer(buf);
return result;
}
-/*
- * fmtQualifiedId - convert a qualified name to the proper format for
- * the source database.
- *
- * Like fmtId, use the result before calling again.
- */
-static const char *
-fmtQualifiedId(Archive *fout, const char *schema, const char *id)
-{
- static PQExpBuffer id_return = NULL;
-
- if (id_return) /* first time through? */
- resetPQExpBuffer(id_return);
- else
- id_return = createPQExpBuffer();
-
- /* Suppress schema name if fetching from pre-7.3 DB */
- if (fout->remoteVersion >= 70300 && schema && *schema)
- {
- appendPQExpBuffer(id_return, "%s.",
- fmtId(schema));
- }
- appendPQExpBuffer(id_return, "%s",
- fmtId(id));
-
- return id_return->data;
-}
-
/*
* Return a column list clause for the given relation.
*
* "", not an invalid "()" column list.
*/
static const char *
-fmtCopyColumnList(const TableInfo *ti)
+fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
{
- static PQExpBuffer q = NULL;
int numatts = ti->numatts;
char **attnames = ti->attnames;
bool *attisdropped = ti->attisdropped;
bool needComma;
int i;
- if (q) /* first time through? */
- resetPQExpBuffer(q);
- else
- q = createPQExpBuffer();
-
- appendPQExpBuffer(q, "(");
+ appendPQExpBufferChar(buffer, '(');
needComma = false;
for (i = 0; i < numatts; i++)
{
if (attisdropped[i])
continue;
if (needComma)
- appendPQExpBuffer(q, ", ");
- appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
+ appendPQExpBufferStr(buffer, ", ");
+ appendPQExpBufferStr(buffer, fmtId(attnames[i]));
needComma = true;
}
if (!needComma)
return ""; /* no undropped columns */
- appendPQExpBuffer(q, ")");
- return q->data;
+ appendPQExpBufferChar(buffer, ')');
+ return buffer->data;
+}
+
+/*
+ * Execute an SQL query and verify that we got exactly one row back.
+ */
+static PGresult *
+ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
+{
+ PGresult *res;
+ int ntups;
+
+ res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
+
+ /* Expecting a single result only */
+ ntups = PQntuples(res);
+ if (ntups != 1)
+ exit_horribly(NULL,
+ ngettext("query returned %d row instead of one: %s\n",
+ "query returned %d rows instead of one: %s\n",
+ ntups),
+ ntups, query);
+
+ return res;
}