* pg_dump is a utility for dumping out a postgres database
* into a script file.
*
- * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2008, 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
* by PostgreSQL
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.433 2006/03/05 15:58:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.495 2008/07/16 16:55:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
-/*
- * Although this is not a backend module, we must include postgres.h anyway
- * so that we can include a bunch of backend include files. pg_dump has
- * never pretended to be very independent of the backend anyhow ...
- */
-#include "postgres.h"
+#include "postgres_fe.h"
-#ifndef WIN32_CLIENT_ONLY
#include <unistd.h>
-#endif
-
#include <ctype.h>
#ifdef ENABLE_NLS
#include <locale.h>
#include <termios.h>
#endif
-#ifndef HAVE_STRDUP
-#include "strdup.h"
-#endif
-
#include "getopt_long.h"
#ifndef HAVE_INT_OPTRESET
#endif
#include "access/attnum.h"
-#include "access/htup.h"
+#include "access/sysattr.h"
#include "catalog/pg_class.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
-
-#include "commands/sequence.h"
-
-#include "libpq-fe.h"
#include "libpq/libpq-fs.h"
-#include "pg_dump.h"
-#include "pg_backup.h"
#include "pg_backup_archiver.h"
#include "dumputils.h"
/* obsolete as of 7.3: */
static Oid g_last_builtin_oid; /* value of the last builtin oid */
-static char *selectTableName = NULL; /* name of a single table to dump */
-static char *selectSchemaName = NULL; /* name of a single schema to dump */
+/*
+ * Object inclusion/exclusion lists
+ *
+ * The string lists record the patterns given by command-line switches,
+ * which we then convert to lists of OIDs of matching objects.
+ */
+static SimpleStringList schema_include_patterns = {NULL, NULL};
+static SimpleOidList schema_include_oids = {NULL, NULL};
+static SimpleStringList schema_exclude_patterns = {NULL, NULL};
+static SimpleOidList schema_exclude_oids = {NULL, NULL};
+
+static SimpleStringList table_include_patterns = {NULL, NULL};
+static SimpleOidList table_include_oids = {NULL, NULL};
+static SimpleStringList table_exclude_patterns = {NULL, NULL};
+static SimpleOidList table_exclude_oids = {NULL, NULL};
+
+/* default, if no "inclusion" switches appear, is to dump everything */
+static bool include_everything = true;
char g_opaque_type[10]; /* name for the opaque type */
static void help(const char *progname);
+static void expand_schema_name_patterns(SimpleStringList *patterns,
+ SimpleOidList *oids);
+static void expand_table_name_patterns(SimpleStringList *patterns,
+ SimpleOidList *oids);
static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
static void dumpTableData(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,
CatalogId catalogId, int subid, DumpId dumpId);
static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
static void dumpType(Archive *fout, TypeInfo *tinfo);
static void dumpBaseType(Archive *fout, TypeInfo *tinfo);
+static void dumpEnumType(Archive *fout, TypeInfo *tinfo);
static void dumpDomain(Archive *fout, TypeInfo *tinfo);
static void dumpCompositeType(Archive *fout, TypeInfo *tinfo);
static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
static void dumpCast(Archive *fout, CastInfo *cast);
static void dumpOpr(Archive *fout, OprInfo *oprinfo);
static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
+static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
static void dumpConversion(Archive *fout, ConvInfo *convinfo);
static void dumpRule(Archive *fout, RuleInfo *rinfo);
static void dumpAgg(Archive *fout, AggInfo *agginfo);
static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
+static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
+static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
+static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
+static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
const char *type, const char *name,
static char *format_function_signature(FuncInfo *finfo, bool honor_quotes);
static const char *convertRegProcReference(const char *proc);
static const char *convertOperatorReference(const char *opr);
+static const char *convertTSFunction(Oid funcOid);
static Oid findLastBuiltinOid_V71(const char *);
static Oid findLastBuiltinOid_V70(void);
static void selectSourceSchema(const char *schemaName);
static int dumpBlobComments(Archive *AH, void *arg);
static void dumpDatabase(Archive *AH);
static void dumpEncoding(Archive *AH);
+static void dumpStdStrings(Archive *AH);
static const char *getAttrName(int attrnum, TableInfo *tblInfo);
static const char *fmtCopyColumnList(const TableInfo *ti);
static void do_sql_command(PGconn *conn, const char *query);
const char *pgport = NULL;
const char *username = NULL;
const char *dumpencoding = NULL;
+ const char *std_strings;
bool oids = false;
TableInfo *tblinfo;
int numTables;
int i;
bool force_password = false;
int compressLevel = -1;
- bool ignore_version = false;
int plainText = 0;
int outputClean = 0;
int outputCreate = 0;
- bool outputBlobs = true;
+ bool outputBlobs = false;
int outputNoOwner = 0;
- static int use_setsessauth = 0;
- static int disable_triggers = 0;
char *outputSuperuser = NULL;
-
+ int my_version;
+ int optindex;
RestoreOptions *ropt;
+ static int disable_triggers = 0;
+ static int outputNoTablespaces = 0;
+ static int use_setsessauth = 0;
+
static struct option long_options[] = {
{"data-only", no_argument, NULL, 'a'},
{"blobs", no_argument, NULL, 'b'},
{"no-owner", no_argument, NULL, 'O'},
{"port", required_argument, NULL, 'p'},
{"schema", required_argument, NULL, 'n'},
+ {"exclude-schema", required_argument, NULL, 'N'},
{"schema-only", no_argument, NULL, 's'},
{"superuser", required_argument, NULL, 'S'},
{"table", required_argument, NULL, 't'},
+ {"exclude-table", required_argument, NULL, 'T'},
{"password", no_argument, NULL, 'W'},
{"username", required_argument, NULL, 'U'},
{"verbose", no_argument, NULL, 'v'},
{"version", no_argument, NULL, 'V'},
/*
- * the following options don't have an equivalent short option letter,
- * but are available as '-X long-name'
+ * the following options don't have an equivalent short option letter
*/
{"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
{"disable-triggers", no_argument, &disable_triggers, 1},
+ {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
{NULL, 0, NULL, 0}
};
- int optindex;
set_pglocale_pgservice(argv[0], "pg_dump");
}
}
- while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:oOp:RsS:t:uU:vWxX:Z:",
+ while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:N:oOp:RsS:t:T:U:vWxX:Z:",
long_options, &optindex)) != -1)
{
switch (c)
break;
case 'b': /* Dump blobs */
- /* this is now default, so just ignore the switch */
+ outputBlobs = true;
break;
case 'c': /* clean (i.e., drop) schema prior to create */
pghost = optarg;
break;
- case 'i': /* ignore database version mismatch */
- ignore_version = true;
+ case 'i':
+ /* ignored, deprecated option */
+ break;
+
+ case 'n': /* include schema(s) */
+ simple_string_list_append(&schema_include_patterns, optarg);
+ include_everything = false;
break;
- case 'n': /* Dump data for this schema only */
- selectSchemaName = strdup(optarg);
+ case 'N': /* exclude schema(s) */
+ simple_string_list_append(&schema_exclude_patterns, optarg);
break;
case 'o': /* Dump oids */
case 's': /* dump schema only */
schemaOnly = true;
- outputBlobs = false;
break;
case 'S': /* Username for superuser in plain text output */
outputSuperuser = strdup(optarg);
break;
- case 't': /* Dump data for this table only */
- selectTableName = strdup(optarg);
+ case 't': /* include table(s) */
+ simple_string_list_append(&table_include_patterns, optarg);
+ include_everything = false;
break;
- case 'u':
- force_password = true;
- username = simple_prompt("User name: ", 100, true);
+ case 'T': /* exclude table(s) */
+ simple_string_list_append(&table_exclude_patterns, optarg);
break;
case 'U':
aclsSkip = true;
break;
- /*
- * Option letters were getting scarce, so I invented this new
- * scheme: '-X feature' turns on some feature. Compare to the
- * -f option in GCC. You should also add an equivalent
- * GNU-style option --feature. Features that require
- * arguments should use '-X feature=foo'.
- */
case 'X':
+ /* -X is a deprecated alternative to long options */
if (strcmp(optarg, "disable-dollar-quoting") == 0)
disable_dollar_quoting = 1;
else if (strcmp(optarg, "disable-triggers") == 0)
disable_triggers = 1;
+ else if (strcmp(optarg, "no-tablespaces") == 0)
+ outputNoTablespaces = 1;
else if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
else
case 'Z': /* Compression Level */
compressLevel = atoi(optarg);
break;
- /* This covers the long options equivalent to -X xxx. */
case 0:
+ /* This covers the long options equivalent to -X xxx. */
break;
default:
if (dataOnly && schemaOnly)
{
- write_msg(NULL, "options \"schema only\" (-s) and \"data only\" (-a) cannot be used together\n");
+ write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
exit(1);
}
if (dataOnly && outputClean)
{
- write_msg(NULL, "options \"clean\" (-c) and \"data only\" (-a) cannot be used together\n");
+ write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
exit(1);
}
- if (selectTableName != NULL || selectSchemaName != NULL)
- outputBlobs = false;
-
if (dumpInserts == true && oids == true)
{
- write_msg(NULL, "INSERT (-d, -D) and OID (-o) options cannot be used together\n");
+ write_msg(NULL, "options -d/-D/--inserts/--column-inserts and -o/--oids cannot be used together\n");
write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
exit(1);
}
/* open the output file */
- switch (format[0])
+ if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
{
- case 'c':
- case 'C':
- g_fout = CreateArchive(filename, archCustom, compressLevel);
- break;
-
- case 'f':
- case 'F':
- g_fout = CreateArchive(filename, archFiles, compressLevel);
- break;
-
- case 'p':
- case 'P':
- plainText = 1;
- g_fout = CreateArchive(filename, archNull, 0);
- break;
-
- case 't':
- case 'T':
- g_fout = CreateArchive(filename, archTar, compressLevel);
- break;
-
- default:
- write_msg(NULL, "invalid output format \"%s\" specified\n", format);
- exit(1);
+ /* This is used by pg_dumpall, and is not documented */
+ plainText = 1;
+ g_fout = CreateArchive(filename, archNull, 0, archModeAppend);
+ }
+ else if (pg_strcasecmp(format, "c") == 0 || pg_strcasecmp(format, "custom") == 0)
+ g_fout = CreateArchive(filename, archCustom, compressLevel, archModeWrite);
+ else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0)
+ {
+ /*
+ * Dump files into the current directory; for demonstration only, not
+ * documented.
+ */
+ g_fout = CreateArchive(filename, archFiles, compressLevel, archModeWrite);
+ }
+ else if (pg_strcasecmp(format, "p") == 0 || pg_strcasecmp(format, "plain") == 0)
+ {
+ plainText = 1;
+ g_fout = CreateArchive(filename, archNull, 0, archModeWrite);
+ }
+ else if (pg_strcasecmp(format, "t") == 0 || pg_strcasecmp(format, "tar") == 0)
+ g_fout = CreateArchive(filename, archTar, compressLevel, archModeWrite);
+ else
+ {
+ write_msg(NULL, "invalid output format \"%s\" specified\n", format);
+ exit(1);
}
if (g_fout == NULL)
/* Let the archiver know how noisy to be */
g_fout->verbose = g_verbose;
- g_fout->minRemoteVersion = 70000; /* we can handle back to 7.0 */
- g_fout->maxRemoteVersion = parse_version(PG_VERSION);
- if (g_fout->maxRemoteVersion < 0)
+ 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.)
+ */
+ g_fout->minRemoteVersion = 70000;
+ g_fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
+
+ /*
* Open the database using the Archiver, so it knows about it. Errors mean
* death.
*/
g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
- username, force_password, ignore_version);
+ username, force_password);
+
+ /* Set the client encoding if requested */
+ if (dumpencoding)
+ {
+ if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
+ {
+ write_msg(NULL, "invalid client encoding \"%s\" specified\n",
+ dumpencoding);
+ exit(1);
+ }
+ }
/*
- * Start serializable transaction to dump consistent data.
+ * Get the active encoding and the standard_conforming_strings setting, so
+ * we know how to escape strings.
*/
- do_sql_command(g_conn, "BEGIN");
+ g_fout->encoding = PQclientEncoding(g_conn);
- do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
+ std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
+ g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
/* Set the datestyle to ISO to ensure the dump's portability */
do_sql_command(g_conn, "SET DATESTYLE = ISO");
- /* Set the client encoding */
- if (dumpencoding)
- {
- char *cmd = malloc(strlen(dumpencoding) + 32);
+ /*
+ * If supported, set extra_float_digits so that we can dump float data
+ * exactly (given correctly implemented float I/O code, anyway)
+ */
+ if (g_fout->remoteVersion >= 70400)
+ do_sql_command(g_conn, "SET extra_float_digits TO 2");
- sprintf(cmd, "SET client_encoding='%s'", dumpencoding);
- do_sql_command(g_conn, cmd);
- free(cmd);
- }
+ /*
+ * If synchronized scanning is supported, disable it, to prevent
+ * unpredictable changes in row ordering across a dump and reload.
+ */
+ if (g_fout->remoteVersion >= 80300)
+ do_sql_command(g_conn, "SET synchronize_seqscans TO off");
+
+ /*
+ * Disable timeouts if supported.
+ */
+ if (g_fout->remoteVersion >= 70300)
+ do_sql_command(g_conn, "SET statement_timeout = 0");
+
+ /*
+ * Start serializable transaction to dump consistent data.
+ */
+ do_sql_command(g_conn, "BEGIN");
+
+ do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
/* Select the appropriate subquery to convert user IDs to names */
if (g_fout->remoteVersion >= 80100)
else
username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
- /*
- * If supported, set extra_float_digits so that we can dump float data
- * exactly (given correctly implemented float I/O code, anyway)
- */
- if (g_fout->remoteVersion >= 70400)
- do_sql_command(g_conn, "SET extra_float_digits TO 2");
-
/* Find the last built-in OID, if needed */
if (g_fout->remoteVersion < 70300)
{
write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
}
+ /* Expand schema selection patterns into OID lists */
+ if (schema_include_patterns.head != NULL)
+ {
+ expand_schema_name_patterns(&schema_include_patterns,
+ &schema_include_oids);
+ if (schema_include_oids.head == NULL)
+ {
+ write_msg(NULL, "No matching schemas were found\n");
+ exit_nicely();
+ }
+ }
+ expand_schema_name_patterns(&schema_exclude_patterns,
+ &schema_exclude_oids);
+ /* non-matching exclusion patterns aren't an error */
+
+ /* Expand table selection patterns into OID lists */
+ if (table_include_patterns.head != NULL)
+ {
+ expand_table_name_patterns(&table_include_patterns,
+ &table_include_oids);
+ if (table_include_oids.head == NULL)
+ {
+ write_msg(NULL, "No matching tables were found\n");
+ exit_nicely();
+ }
+ }
+ expand_table_name_patterns(&table_exclude_patterns,
+ &table_exclude_oids);
+ /* non-matching exclusion patterns aren't an error */
+
+ /*
+ * Dumping blobs is now default unless we saw an inclusion switch or -s
+ * ... but even if we did see one of these, -b turns it back on.
+ */
+ if (include_everything && !schemaOnly)
+ outputBlobs = true;
+
/*
* Now scan the database and create DumpableObject structs for all the
* objects we intend to dump.
*/
- tblinfo = getSchemaData(&numTables, schemaOnly, dataOnly);
+ tblinfo = getSchemaData(&numTables);
+
+ if (g_fout->remoteVersion < 80400)
+ guessConstraintInheritance(tblinfo, numTables);
if (!schemaOnly)
getTableData(tblinfo, numTables, oids);
* order.
*/
- /* First the special encoding entry. */
+ /* First the special ENCODING and STDSTRINGS entries. */
dumpEncoding(g_fout);
+ dumpStdStrings(g_fout);
- /* The database item is always second, unless we don't want it at all */
- if (!dataOnly && selectTableName == NULL && selectSchemaName == NULL)
+ /* The database item is always next, unless we don't want it at all */
+ if (include_everything && !dataOnly)
dumpDatabase(g_fout);
/* Now the rearrangeable objects. */
ropt->superuser = outputSuperuser;
ropt->create = outputCreate;
ropt->noOwner = outputNoOwner;
+ ropt->noTablespace = outputNoTablespaces;
ropt->disable_triggers = disable_triggers;
ropt->use_setsessauth = use_setsessauth;
ropt->dataOnly = dataOnly;
printf(_("\nGeneral options:\n"));
printf(_(" -f, --file=FILENAME output file name\n"));
printf(_(" -F, --format=c|t|p output file format (custom, tar, plain text)\n"));
- printf(_(" -i, --ignore-version proceed even when server version mismatches\n"
- " pg_dump version\n"));
printf(_(" -v, --verbose verbose mode\n"));
printf(_(" -Z, --compress=0-9 compression level for compressed formats\n"));
printf(_(" --help show this help, then exit\n"));
printf(_(" --version output version information, then exit\n"));
printf(_("\nOptions controlling the output content:\n"));
- printf(_(" -a, --data-only dump only the data, not the schema\n"));
- printf(_(" -c, --clean clean (drop) schema prior to create\n"));
- printf(_(" -C, --create include commands to create database in dump\n"));
- printf(_(" -d, --inserts dump data as INSERT, rather than COPY, commands\n"));
- printf(_(" -D, --column-inserts dump data as INSERT commands with column names\n"));
- printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
- printf(_(" -n, --schema=SCHEMA dump the named schema only\n"));
- printf(_(" -o, --oids include OIDs in dump\n"));
- printf(_(" -O, --no-owner skip restoration of object ownership\n"
- " in plain text format\n"));
- printf(_(" -s, --schema-only dump only the schema, no data\n"));
- printf(_(" -S, --superuser=NAME specify the superuser user name to use in\n"
- " plain text format\n"));
- printf(_(" -t, --table=TABLE dump the named table only\n"));
- printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
- printf(_(" -X disable-dollar-quoting, --disable-dollar-quoting\n"
- " disable dollar quoting, use SQL standard quoting\n"));
- printf(_(" -X disable-triggers, --disable-triggers\n"
- " disable triggers during data-only restore\n"));
- printf(_(" -X use-set-session-authorization, --use-set-session-authorization\n"
- " use SESSION AUTHORIZATION commands instead of\n"
- " OWNER TO commands\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) schema prior to create\n"));
+ printf(_(" -C, --create include commands to create database in dump\n"));
+ printf(_(" -d, --inserts dump data as INSERT commands, rather than COPY\n"));
+ printf(_(" -D, --column-inserts dump data as INSERT commands with column names\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\n"
+ " in plain text format\n"));
+ printf(_(" -s, --schema-only dump only the schema, no data\n"));
+ printf(_(" -S, --superuser=NAME specify the superuser user name to use in\n"
+ " 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(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
+ printf(_(" --disable-triggers disable triggers during data-only restore\n"));
+ printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
+ printf(_(" --use-set-session-authorization\n"
+ " use SESSION AUTHORIZATION commands instead of\n"
+ " ALTER OWNER commands to set ownership\n"));
printf(_("\nConnection options:\n"));
printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
}
/*
+ * Find the OIDs of all schemas matching the given list of patterns,
+ * and append them to the given OID list.
+ */
+static void
+expand_schema_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
+{
+ PQExpBuffer query;
+ PGresult *res;
+ SimpleStringListCell *cell;
+ int i;
+
+ if (patterns->head == NULL)
+ return; /* nothing to do */
+
+ if (g_fout->remoteVersion < 70300)
+ {
+ write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
+ exit_nicely();
+ }
+
+ query = createPQExpBuffer();
+
+ /*
+ * We use UNION ALL rather than UNION; this might sometimes result in
+ * duplicate entries in the OID list, but we don't care.
+ */
+
+ for (cell = patterns->head; cell; cell = cell->next)
+ {
+ if (cell != patterns->head)
+ appendPQExpBuffer(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);
+ }
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
+ }
+
+ PQclear(res);
+ destroyPQExpBuffer(query);
+}
+
+/*
+ * Find the OIDs of all tables matching the given list of patterns,
+ * and append them to the given OID list.
+ */
+static void
+expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
+{
+ PQExpBuffer query;
+ PGresult *res;
+ SimpleStringListCell *cell;
+ int i;
+
+ if (patterns->head == NULL)
+ return; /* nothing to do */
+
+ query = createPQExpBuffer();
+
+ /*
+ * We use UNION ALL rather than UNION; this might sometimes result in
+ * duplicate entries in the OID list, but we don't care.
+ */
+
+ for (cell = patterns->head; cell; cell = cell->next)
+ {
+ if (cell != patterns->head)
+ appendPQExpBuffer(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')\n",
+ RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
+ processSQLNamePattern(g_conn, query, cell->val, true, false,
+ "n.nspname", "c.relname", NULL,
+ "pg_catalog.pg_table_is_visible(c.oid)");
+ }
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
+ }
+
+ PQclear(res);
+ destroyPQExpBuffer(query);
+}
+
+/*
* selectDumpableNamespace: policy-setting subroutine
* Mark a namespace as to be dumped or not
*/
selectDumpableNamespace(NamespaceInfo *nsinfo)
{
/*
- * If a specific table is being dumped, do not dump any complete
- * namespaces. If a specific namespace is being dumped, dump just that
- * namespace. Otherwise, dump all non-system namespaces.
+ * If specific tables are being dumped, do not dump any complete
+ * namespaces. If specific namespaces are being dumped, dump just those
+ * namespaces. Otherwise, dump all non-system namespaces.
*/
- if (selectTableName != NULL)
+ if (table_include_oids.head != NULL)
nsinfo->dobj.dump = false;
- else if (selectSchemaName != NULL)
- {
- if (strcmp(nsinfo->dobj.name, selectSchemaName) == 0)
- nsinfo->dobj.dump = true;
- else
- nsinfo->dobj.dump = false;
- }
+ else if (schema_include_oids.head != NULL)
+ nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
+ nsinfo->dobj.catId.oid);
else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
strcmp(nsinfo->dobj.name, "information_schema") == 0)
nsinfo->dobj.dump = false;
else
nsinfo->dobj.dump = true;
+
+ /*
+ * In any case, a namespace can be excluded by an exclusion switch
+ */
+ if (nsinfo->dobj.dump &&
+ simple_oid_list_member(&schema_exclude_oids,
+ nsinfo->dobj.catId.oid))
+ nsinfo->dobj.dump = false;
}
/*
selectDumpableTable(TableInfo *tbinfo)
{
/*
- * Always dump if dumping parent namespace; else, if a particular
- * tablename has been specified, dump matching table name; else, do not
- * dump.
+ * If specific tables are being dumped, dump just those tables; else, dump
+ * according to the parent namespace's dump flag.
*/
- tbinfo->dobj.dump = false;
- if (tbinfo->dobj.namespace->dobj.dump)
- tbinfo->dobj.dump = true;
- else if (selectTableName != NULL &&
- strcmp(tbinfo->dobj.name, selectTableName) == 0)
- {
- /* If both -s and -t specified, must match both to dump */
- if (selectSchemaName == NULL)
- tbinfo->dobj.dump = true;
- else if (strcmp(tbinfo->dobj.namespace->dobj.name, selectSchemaName) == 0)
- tbinfo->dobj.dump = true;
- }
+ if (table_include_oids.head != NULL)
+ tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
+ tbinfo->dobj.catId.oid);
+ else
+ tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
+
+ /*
+ * In any case, a table can be excluded by an exclusion switch
+ */
+ if (tbinfo->dobj.dump &&
+ simple_oid_list_member(&table_exclude_oids,
+ tbinfo->dobj.catId.oid))
+ tbinfo->dobj.dump = false;
}
/*
else if (!tinfo->isDefined)
tinfo->dobj.dump = false;
- /* skip all array types that start w/ underscore */
- else if ((tinfo->dobj.name[0] == '_') &&
- OidIsValid(tinfo->typelem))
+ /* skip auto-generated array types */
+ else if (tinfo->isArray)
tinfo->dobj.dump = false;
else
selectDumpableObject(DumpableObject *dobj)
{
/*
- * Default policy is to dump if parent namespace is dumpable,
- * or always for non-namespace-associated items.
+ * Default policy is to dump if parent namespace is dumpable, or always
+ * for non-namespace-associated items.
*/
if (dobj->namespace)
dobj->dump = dobj->namespace->dobj.dump;
PQfreemem(copybuf);
}
- /*
+ /* ----------
* THROTTLE:
*
* There was considerable discussion in late July, 2000 regarding
* implementation was suggested. The latter failed because the loop
* was too tight. Finally, the following was implemented:
*
- * If throttle is non-zero, then See how long since the last sleep.
- * Work out how long to sleep (based on ratio). If sleep is more than
- * 100ms, then sleep reset timer EndIf EndIf
+ * If throttle is non-zero, then
+ * See how long since the last sleep.
+ * Work out how long to sleep (based on ratio).
+ * If sleep is more than 100ms, then
+ * sleep
+ * reset timer
+ * EndIf
+ * EndIf
*
* where the throttle value was the number of ms to sleep per ms of
* work. The calculation was done in each loop.
*
* This will return after the interval specified in the structure tvi.
* Finally, call gettimeofday again to save the 'last sleep time'.
+ * ----------
*/
}
archprintf(fout, "\\.\n\n\n");
default:
/* All other types are printed as string literals. */
resetPQExpBuffer(q);
- appendStringLiteral(q, PQgetvalue(res, tuple, field), false);
+ appendStringLiteralAH(q,
+ PQgetvalue(res, tuple, field),
+ fout);
archputs(q->data, fout);
break;
}
/*
+ * 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.
+ *
+ * This function assumes all conislocal flags were initialized to TRUE.
+ * It clears the flag on anything that seems to be inherited.
+ */
+static void
+guessConstraintInheritance(TableInfo *tblinfo, int numTables)
+{
+ int i,
+ j,
+ k;
+
+ for (i = 0; i < numTables; i++)
+ {
+ TableInfo *tbinfo = &(tblinfo[i]);
+ int numParents;
+ TableInfo **parents;
+ TableInfo *parent;
+
+ /* Sequences and views never have parents */
+ if (tbinfo->relkind == RELKIND_SEQUENCE ||
+ tbinfo->relkind == RELKIND_VIEW)
+ continue;
+
+ /* Don't bother computing anything for non-target tables, either */
+ if (!tbinfo->dobj.dump)
+ continue;
+
+ numParents = tbinfo->numParents;
+ parents = tbinfo->parents;
+
+ if (numParents == 0)
+ continue; /* nothing to see here, move along */
+
+ /* scan for inherited CHECK constraints */
+ for (j = 0; j < tbinfo->ncheck; j++)
+ {
+ ConstraintInfo *constr;
+
+ constr = &(tbinfo->checkexprs[j]);
+
+ for (k = 0; k < numParents; k++)
+ {
+ int l;
+
+ parent = parents[k];
+ for (l = 0; l < parent->ncheck; l++)
+ {
+ ConstraintInfo *pconstr = &(parent->checkexprs[l]);
+
+ if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
+ {
+ constr->conislocal = false;
+ break;
+ }
+ }
+ if (!constr->conislocal)
+ break;
+ }
+ }
+ }
+}
+
+
+/*
* dumpDatabase:
* dump the database definition
*/
"(%s datdba) as dba, "
"pg_encoding_to_char(encoding) as encoding, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) as tablespace, "
- "shobj_description(oid, 'pg_database') as description "
+ "shobj_description(oid, 'pg_database') as description "
"FROM pg_database "
"WHERE datname = ",
username_subquery);
- appendStringLiteral(dbQry, datname, true);
+ appendStringLiteralAH(dbQry, datname, AH);
}
else if (g_fout->remoteVersion >= 80000)
{
"FROM pg_database "
"WHERE datname = ",
username_subquery);
- appendStringLiteral(dbQry, datname, true);
+ appendStringLiteralAH(dbQry, datname, AH);
}
else if (g_fout->remoteVersion >= 70100)
{
"FROM pg_database "
"WHERE datname = ",
username_subquery);
- appendStringLiteral(dbQry, datname, true);
+ appendStringLiteralAH(dbQry, datname, AH);
}
else
{
"FROM pg_database "
"WHERE datname = ",
username_subquery);
- appendStringLiteral(dbQry, datname, true);
+ appendStringLiteralAH(dbQry, datname, AH);
}
res = PQexec(g_conn, dbQry->data);
if (strlen(encoding) > 0)
{
appendPQExpBuffer(creaQry, " ENCODING = ");
- appendStringLiteral(creaQry, encoding, true);
+ appendStringLiteralAH(creaQry, encoding, AH);
}
if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
appendPQExpBuffer(creaQry, " TABLESPACE = %s",
/* Dump DB comment if any */
if (g_fout->remoteVersion >= 80200)
{
- /* 8.2 keeps comments on shared objects in a shared table, so
- * we cannot use the dumpComment used for other database objects.
+ /*
+ * 8.2 keeps comments on shared objects in a shared table, so we
+ * cannot use the dumpComment used for other database objects.
*/
- char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
- if (comment && strlen(comment)) {
+ char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
+
+ if (comment && strlen(comment))
+ {
resetPQExpBuffer(dbQry);
+ /* Generates warning when loaded into a differently-named database.*/
appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
- appendStringLiteral(dbQry, comment, false);
+ appendStringLiteralAH(dbQry, comment, AH);
appendPQExpBuffer(dbQry, ";\n");
ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
- dba, false, "COMMENT", dbQry->data, "", NULL,
- &dbDumpId, 1, NULL, NULL);
+ dba, false, "COMMENT", dbQry->data, "", NULL,
+ &dbDumpId, 1, NULL, NULL);
}
- } else {
+ }
+ else
+ {
resetPQExpBuffer(dbQry);
appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
dumpComment(AH, dbQry->data, NULL, "",
- dbCatId, 0, dbDumpId);
+ dbCatId, 0, dbDumpId);
}
PQclear(res);
static void
dumpEncoding(Archive *AH)
{
- PQExpBuffer qry;
- PGresult *res;
-
- /* Can't read the encoding from pre-7.3 servers (SHOW isn't a query) */
- if (AH->remoteVersion < 70300)
- return;
+ const char *encname = pg_encoding_to_char(AH->encoding);
+ PQExpBuffer qry = createPQExpBuffer();
if (g_verbose)
- write_msg(NULL, "saving encoding\n");
-
- qry = createPQExpBuffer();
-
- appendPQExpBuffer(qry, "SHOW client_encoding");
-
- res = PQexec(g_conn, qry->data);
-
- check_sql_result(res, g_conn, qry->data, PGRES_TUPLES_OK);
-
- resetPQExpBuffer(qry);
+ write_msg(NULL, "saving encoding = %s\n", encname);
appendPQExpBuffer(qry, "SET client_encoding = ");
- appendStringLiteral(qry, PQgetvalue(res, 0, 0), true);
+ appendStringLiteralAH(qry, encname, AH);
appendPQExpBuffer(qry, ";\n");
ArchiveEntry(AH, nilCatalogId, createDumpId(),
NULL, 0,
NULL, NULL);
- PQclear(res);
+ destroyPQExpBuffer(qry);
+}
+
+
+/*
+ * dumpStdStrings: put the correct escape string behavior into the archive
+ */
+static void
+dumpStdStrings(Archive *AH)
+{
+ const char *stdstrings = AH->std_strings ? "on" : "off";
+ PQExpBuffer qry = createPQExpBuffer();
+
+ if (g_verbose)
+ write_msg(NULL, "saving standard_conforming_strings = %s\n",
+ stdstrings);
+
+ appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
+ stdstrings);
+
+ ArchiveEntry(AH, nilCatalogId, createDumpId(),
+ "STDSTRINGS", NULL, NULL, "",
+ false, "STDSTRINGS", qry->data, "", NULL,
+ NULL, 0,
+ NULL, NULL);
destroyPQExpBuffer(qry);
}
/* Cursor to get all BLOB comments */
if (AH->remoteVersion >= 70200)
- blobQry = "DECLARE blobcmt CURSOR FOR SELECT DISTINCT loid, obj_description(loid, 'pg_largeobject') FROM pg_largeobject";
+ blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, obj_description(loid, 'pg_largeobject') FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
else if (AH->remoteVersion >= 70100)
- blobQry = "DECLARE blobcmt CURSOR FOR SELECT DISTINCT loid, obj_description(loid) FROM pg_largeobject";
+ blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, obj_description(loid) FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
else
blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, (SELECT description FROM pg_description pd WHERE pd.objoid=pc.oid) FROM pg_class pc WHERE relkind = 'l'";
printfPQExpBuffer(commentcmd, "COMMENT ON LARGE OBJECT %u IS ",
blobOid);
- appendStringLiteral(commentcmd, comment, false);
+ appendStringLiteralAH(commentcmd, comment, AH);
appendPQExpBuffer(commentcmd, ";\n");
archputs(commentcmd->data, AH);
nsinfo[i].dobj.name);
}
- /*
- * If the user attempted to dump a specific namespace, check to ensure
- * that the specified namespace actually exists.
- */
- if (selectSchemaName)
- {
- for (i = 0; i < ntups; i++)
- if (strcmp(nsinfo[i].dobj.name, selectSchemaName) == 0)
- break;
-
- /* Didn't find a match */
- if (i == ntups)
- {
- write_msg(NULL, "specified schema \"%s\" does not exist\n",
- selectSchemaName);
- exit_nicely();
- }
- }
-
PQclear(res);
destroyPQExpBuffer(query);
int i_typrelkind;
int i_typtype;
int i_typisdefined;
+ int i_isarray;
/*
* we include even the built-in types because those may be used as array
*
* we filter out the built-in types when we dump out the types
*
- * same approach for undefined (shell) types
+ * same approach for undefined (shell) types and array types
+ *
+ * Note: as of 8.3 we can reliably detect whether a type is an
+ * auto-generated array type by checking the element type's typarray.
+ * (Before that the test is capable of generating false positives.) We
+ * still check for name beginning with '_', though, so as to avoid the
+ * cost of the subselect probe for all standard types. This would have to
+ * be revisited if the backend ever allows renaming of array types.
*/
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
- if (g_fout->remoteVersion >= 70300)
+ if (g_fout->remoteVersion >= 80300)
+ {
+ appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
+ "typnamespace, "
+ "(%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 (g_fout->remoteVersion >= 70300)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
"typnamespace, "
"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 "
+ "typtype, typisdefined, "
+ "typname[0] = '_' AND typelem != 0 AS isarray "
"FROM pg_type",
username_subquery);
}
"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 "
+ "typtype, typisdefined, "
+ "typname[0] = '_' AND typelem != 0 AS isarray "
"FROM pg_type",
username_subquery);
}
"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 "
+ "typtype, typisdefined, "
+ "typname[0] = '_' AND typelem != 0 AS isarray "
"FROM pg_type",
username_subquery);
}
i_typrelkind = PQfnumber(res, "typrelkind");
i_typtype = PQfnumber(res, "typtype");
i_typisdefined = PQfnumber(res, "typisdefined");
+ i_isarray = PQfnumber(res, "isarray");
for (i = 0; i < ntups; i++)
{
tinfo[i].typrelkind != RELKIND_COMPOSITE_TYPE)
tinfo[i].dobj.objType = DO_TABLE_TYPE;
- /*
- * check for user-defined array types, omit system generated ones
- */
- if (OidIsValid(tinfo[i].typelem) &&
- tinfo[i].dobj.name[0] != '_')
- tinfo[i].isArray = true;
- else
- tinfo[i].isArray = false;
-
if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
tinfo[i].isDefined = true;
else
tinfo[i].isDefined = false;
+ if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
+ tinfo[i].isArray = true;
+ else
+ tinfo[i].isArray = false;
+
/* Decide whether we want to dump it */
selectDumpableType(&tinfo[i]);
*/
tinfo[i].nDomChecks = 0;
tinfo[i].domChecks = NULL;
- if (tinfo[i].dobj.dump && tinfo[i].typtype == 'd')
+ if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_DOMAIN)
getDomainConstraints(&(tinfo[i]));
/*
* 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.
+ * definition of the type. We will need to dump that ahead of the I/O
+ * functions for the type.
*
* Note: the shell type doesn't have a catId. You might think it
- * should copy the base type's catId, but then it might capture
- * the pg_depend entries for the type, which we don't want.
+ * should copy the base type's catId, but then it might capture the
+ * pg_depend entries for the type, which we don't want.
*/
- if (tinfo[i].dobj.dump && tinfo[i].typtype == 'b')
+ if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_BASE)
{
stinfo = (ShellTypeInfo *) malloc(sizeof(ShellTypeInfo));
stinfo->dobj.objType = DO_SHELL_TYPE;
tinfo[i].shellType = stinfo;
/*
- * Initially mark the shell type as not to be dumped. We'll
- * only dump it if the I/O functions need to be dumped; this
- * is taken care of while sorting dependencies.
+ * Initially mark the shell type as not to be dumped. We'll only
+ * dump it if the I/O functions need to be dumped; this is taken
+ * care of while sorting dependencies.
*/
stinfo->dobj.dump = false;
}
/*
+ * getOpfamilies:
+ * read all opfamilies in the system catalogs and return them in the
+ * OpfamilyInfo* structure
+ *
+ * numOpfamilies is set to the number of opfamilies read in
+ */
+OpfamilyInfo *
+getOpfamilies(int *numOpfamilies)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query;
+ OpfamilyInfo *opfinfo;
+ int i_tableoid;
+ int i_oid;
+ int i_opfname;
+ int i_opfnamespace;
+ int i_rolname;
+
+ /* Before 8.3, there is no separate concept of opfamilies */
+ if (g_fout->remoteVersion < 80300)
+ {
+ *numOpfamilies = 0;
+ return NULL;
+ }
+
+ query = createPQExpBuffer();
+
+ /*
+ * find all opfamilies, including builtin opfamilies; we filter out
+ * system-defined opfamilies at dump-out time.
+ */
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema("pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
+ "opfnamespace, "
+ "(%s opfowner) as rolname "
+ "FROM pg_opfamily",
+ username_subquery);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ *numOpfamilies = ntups;
+
+ opfinfo = (OpfamilyInfo *) malloc(ntups * sizeof(OpfamilyInfo));
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_opfname = PQfnumber(res, "opfname");
+ i_opfnamespace = PQfnumber(res, "opfnamespace");
+ i_rolname = PQfnumber(res, "rolname");
+
+ for (i = 0; i < ntups; i++)
+ {
+ opfinfo[i].dobj.objType = DO_OPFAMILY;
+ opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&opfinfo[i].dobj);
+ opfinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opfname));
+ opfinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)),
+ opfinfo[i].dobj.catId.oid);
+ opfinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
+
+ /* Decide whether we want to dump it */
+ selectDumpableObject(&(opfinfo[i].dobj));
+
+ if (g_fout->remoteVersion >= 70300)
+ {
+ if (strlen(opfinfo[i].rolname) == 0)
+ write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
+ opfinfo[i].dobj.name);
+ }
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return opfinfo;
+}
+
+/*
* getAggregates:
* read all the user-defined aggregates in the system catalogs and
* return them in the AggInfo* structure
int i_oid;
int i_aggname;
int i_aggnamespace;
- int i_aggbasetype;
+ int i_pronargs;
+ int i_proargtypes;
int i_rolname;
int i_aggacl;
/* find all user-defined aggregates */
- if (g_fout->remoteVersion >= 70300)
+ if (g_fout->remoteVersion >= 80200)
+ {
+ appendPQExpBuffer(query, "SELECT tableoid, oid, proname as aggname, "
+ "pronamespace as aggnamespace, "
+ "pronargs, proargtypes, "
+ "(%s proowner) as rolname, "
+ "proacl as aggacl "
+ "FROM pg_proc "
+ "WHERE proisagg "
+ "AND pronamespace != "
+ "(select oid from pg_namespace where nspname = 'pg_catalog')",
+ username_subquery);
+ }
+ else if (g_fout->remoteVersion >= 70300)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, proname as aggname, "
"pronamespace as aggnamespace, "
- "proargtypes[0] as aggbasetype, "
+ "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END as pronargs, "
+ "proargtypes, "
"(%s proowner) as rolname, "
"proacl as aggacl "
"FROM pg_proc "
{
appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
"0::oid as aggnamespace, "
- "aggbasetype, "
+ "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END as pronargs, "
+ "aggbasetype as proargtypes, "
"(%s aggowner) as rolname, "
"'{=X}' as aggacl "
"FROM pg_aggregate "
"(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
"oid, aggname, "
"0::oid as aggnamespace, "
- "aggbasetype, "
+ "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END as pronargs, "
+ "aggbasetype as proargtypes, "
"(%s aggowner) as rolname, "
"'{=X}' as aggacl "
"FROM pg_aggregate "
i_oid = PQfnumber(res, "oid");
i_aggname = PQfnumber(res, "aggname");
i_aggnamespace = PQfnumber(res, "aggnamespace");
- i_aggbasetype = PQfnumber(res, "aggbasetype");
+ i_pronargs = PQfnumber(res, "pronargs");
+ i_proargtypes = PQfnumber(res, "proargtypes");
i_rolname = PQfnumber(res, "rolname");
i_aggacl = PQfnumber(res, "aggacl");
write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
agginfo[i].aggfn.dobj.name);
agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
- agginfo[i].aggfn.nargs = 1;
- agginfo[i].aggfn.argtypes = (Oid *) malloc(sizeof(Oid));
- agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_aggbasetype));
agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
agginfo[i].aggfn.proacl = strdup(PQgetvalue(res, i, i_aggacl));
- agginfo[i].anybasetype = false; /* computed when it's dumped */
- agginfo[i].fmtbasetype = NULL; /* computed when it's dumped */
+ agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
+ if (agginfo[i].aggfn.nargs == 0)
+ agginfo[i].aggfn.argtypes = NULL;
+ else
+ {
+ agginfo[i].aggfn.argtypes = (Oid *) malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
+ if (g_fout->remoteVersion >= 70300)
+ parseOidArray(PQgetvalue(res, i, i_proargtypes),
+ agginfo[i].aggfn.argtypes,
+ agginfo[i].aggfn.nargs);
+ else
+ /* it's just aggbasetype */
+ agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
+ }
/* Decide whether we want to dump it */
selectDumpableObject(&(agginfo[i].aggfn.dobj));
int i_owning_tab;
int i_owning_col;
int i_reltablespace;
+ int i_reloptions;
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
* Note: in this phase we should collect only a minimal amount of
* information about each table, basically just enough to decide if it is
* interesting. We must fetch all tables in this phase because otherwise
- * we cannot correctly identify inherited columns, serial columns, etc.
+ * we cannot correctly identify inherited columns, owned sequences, etc.
*/
- if (g_fout->remoteVersion >= 80000)
+ if (g_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, relname, "
+ "relacl, relkind, relnamespace, "
+ "(%s relowner) as rolname, "
+ "relchecks, reltriggers, "
+ "relhasindex, relhasrules, relhasoids, "
+ "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 "
+ "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') "
+ "where 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 (g_fout->remoteVersion >= 80000)
{
/*
* Left join to pick up dependency info linking sequences to their
- * serial column, if any
+ * owning column, if any
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, relname, "
"relhasindex, relhasrules, relhasoids, "
"d.refobjid as owning_tab, "
"d.refobjsubid as owning_col, "
- "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace "
+ "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
+ "NULL as reloptions "
"from pg_class c "
"left join pg_depend d on "
"(c.relkind = '%c' and "
{
/*
* Left join to pick up dependency info linking sequences to their
- * serial column, if any
+ * owning column, if any
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, relname, "
"relhasindex, relhasrules, relhasoids, "
"d.refobjid as owning_tab, "
"d.refobjsubid as owning_col, "
- "NULL as reltablespace "
+ "NULL as reltablespace, "
+ "NULL as reloptions "
"from pg_class c "
"left join pg_depend d on "
"(c.relkind = '%c' and "
"relhasindex, relhasrules, relhasoids, "
"NULL::oid as owning_tab, "
"NULL::int4 as owning_col, "
- "NULL as reltablespace "
+ "NULL as reltablespace, "
+ "NULL as reloptions "
"from pg_class "
"where relkind in ('%c', '%c', '%c') "
"order by oid",
"'t'::bool as relhasoids, "
"NULL::oid as owning_tab, "
"NULL::int4 as owning_col, "
- "NULL as reltablespace "
+ "NULL as reltablespace, "
+ "NULL as reloptions "
"from pg_class "
"where relkind in ('%c', '%c', '%c') "
"order by oid",
"'t'::bool as relhasoids, "
"NULL::oid as owning_tab, "
"NULL::int4 as owning_col, "
- "NULL as reltablespace "
+ "NULL as reltablespace, "
+ "NULL as reloptions "
"from pg_class c "
"where relkind in ('%c', '%c') "
"order by oid",
i_owning_tab = PQfnumber(res, "owning_tab");
i_owning_col = PQfnumber(res, "owning_col");
i_reltablespace = PQfnumber(res, "reltablespace");
+ i_reloptions = PQfnumber(res, "reloptions");
for (i = 0; i < ntups; i++)
{
tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
}
tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
+ tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions));
/* other fields were zeroed above */
/*
- * Decide whether we want to dump this table. Sequences owned by
- * serial columns are never dumpable on their own; we will transpose
- * their owning table's dump flag to them below.
+ * Decide whether we want to dump this table.
*/
if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
tblinfo[i].dobj.dump = false;
- else if (OidIsValid(tblinfo[i].owning_tab))
- tblinfo[i].dobj.dump = false;
else
selectDumpableTable(&tblinfo[i]);
tblinfo[i].interesting = tblinfo[i].dobj.dump;
tblinfo[i].dobj.name);
}
+ PQclear(res);
+
/*
- * If the user is attempting to dump a specific table, check to ensure
- * that the specified table actually exists. (This is a bit simplistic
- * since we don't fully check the combination of -n and -t switches.)
+ * Force sequences that are "owned" by table columns to be dumped whenever
+ * their owning table is being dumped.
*/
- if (selectTableName)
+ for (i = 0; i < ntups; i++)
{
- for (i = 0; i < ntups; i++)
- if (strcmp(tblinfo[i].dobj.name, selectTableName) == 0)
- break;
+ TableInfo *seqinfo = &tblinfo[i];
+ int j;
- /* Didn't find a match */
- if (i == ntups)
+ 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++)
{
- write_msg(NULL, "specified table \"%s\" does not exist\n",
- selectTableName);
- exit_nicely();
+ if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
+ {
+ if (tblinfo[j].dobj.dump)
+ {
+ seqinfo->interesting = true;
+ seqinfo->dobj.dump = true;
+ }
+ break;
+ }
}
}
- PQclear(res);
destroyPQExpBuffer(query);
destroyPQExpBuffer(delqry);
destroyPQExpBuffer(lockquery);
i_conname,
i_contableoid,
i_conoid,
- i_tablespace;
+ i_tablespace,
+ i_options;
int ntups;
for (i = 0; i < numTables; i++)
* assume an index won't have more than one internal dependency.
*/
resetPQExpBuffer(query);
- if (g_fout->remoteVersion >= 80000)
+ if (g_fout->remoteVersion >= 80200)
+ {
+ 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, "
+ "c.contype, c.conname, "
+ "c.tableoid as contableoid, "
+ "c.oid as conoid, "
+ "(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_depend d "
+ "ON (d.classid = t.tableoid "
+ "AND d.objid = t.oid "
+ "AND d.deptype = 'i') "
+ "LEFT JOIN pg_catalog.pg_constraint c "
+ "ON (d.refclassid = c.tableoid "
+ "AND d.refobjid = c.oid) "
+ "WHERE i.indrelid = '%u'::pg_catalog.oid "
+ "ORDER BY indexname",
+ tbinfo->dobj.catId.oid);
+ }
+ else if (g_fout->remoteVersion >= 80000)
{
appendPQExpBuffer(query,
"SELECT t.tableoid, t.oid, "
"c.contype, c.conname, "
"c.tableoid as contableoid, "
"c.oid as conoid, "
- "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) as tablespace "
+ "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) as tablespace, "
+ "null as options "
"FROM pg_catalog.pg_index i "
"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
"LEFT JOIN pg_catalog.pg_depend d "
"c.contype, c.conname, "
"c.tableoid as contableoid, "
"c.oid as conoid, "
- "NULL as tablespace "
+ "NULL as tablespace, "
+ "null as options "
"FROM pg_catalog.pg_index i "
"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
"LEFT JOIN pg_catalog.pg_depend d "
"t.relname as conname, "
"0::oid as contableoid, "
"t.oid as conoid, "
- "NULL as tablespace "
+ "NULL as tablespace, "
+ "null as options "
"FROM pg_index i, pg_class t "
"WHERE t.oid = i.indexrelid "
"AND i.indrelid = '%u'::oid "
"t.relname as conname, "
"0::oid as contableoid, "
"t.oid as conoid, "
- "NULL as tablespace "
+ "NULL as tablespace, "
+ "null as options "
"FROM pg_index i, pg_class t "
"WHERE t.oid = i.indexrelid "
"AND i.indrelid = '%u'::oid "
i_contableoid = PQfnumber(res, "contableoid");
i_conoid = PQfnumber(res, "conoid");
i_tablespace = PQfnumber(res, "tablespace");
+ i_options = PQfnumber(res, "options");
indxinfo = (IndxInfo *) malloc(ntups * sizeof(IndxInfo));
constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef));
indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
indxinfo[j].tablespace = strdup(PQgetvalue(res, j, i_tablespace));
+ indxinfo[j].options = strdup(PQgetvalue(res, j, i_options));
/*
* In pre-7.4 releases, indkeys may contain more entries than
constrinfo[j].contype = contype;
constrinfo[j].condef = NULL;
constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
- constrinfo[j].coninherited = false;
+ constrinfo[j].conislocal = true;
constrinfo[j].separate = true;
indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
constrinfo[j].contype = 'f';
constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
constrinfo[j].conindex = 0;
- constrinfo[j].coninherited = false;
+ constrinfo[j].conislocal = true;
constrinfo[j].separate = true;
}
constrinfo[i].contype = 'c';
constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc));
constrinfo[i].conindex = 0;
- constrinfo[i].coninherited = false;
+ constrinfo[i].conislocal = true;
constrinfo[i].separate = false;
/*
int i_ruletable;
int i_ev_type;
int i_is_instead;
+ int i_ev_enabled;
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
- if (g_fout->remoteVersion >= 70100)
+ if (g_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");
+ }
+ else if (g_fout->remoteVersion >= 70100)
{
appendPQExpBuffer(query, "SELECT "
"tableoid, oid, rulename, "
- "ev_class as ruletable, ev_type, is_instead "
+ "ev_class as ruletable, ev_type, is_instead, "
+ "'O'::char as ev_enabled "
"FROM pg_rewrite "
"ORDER BY oid");
}
appendPQExpBuffer(query, "SELECT "
"(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
"oid, rulename, "
- "ev_class as ruletable, ev_type, is_instead "
+ "ev_class as ruletable, ev_type, is_instead, "
+ "'O'::char as ev_enabled "
"FROM pg_rewrite "
"ORDER BY oid");
}
i_ruletable = PQfnumber(res, "ruletable");
i_ev_type = PQfnumber(res, "ev_type");
i_is_instead = PQfnumber(res, "is_instead");
+ i_ev_enabled = PQfnumber(res, "ev_enabled");
for (i = 0; i < ntups; i++)
{
ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
+ ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
if (ruleinfo[i].ruletable)
{
/*
selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
resetPQExpBuffer(query);
- if (g_fout->remoteVersion >= 70300)
+ if (g_fout->remoteVersion >= 80300)
{
/*
* We ignore triggers that are tied to a foreign-key constraint
"tgconstrrelid::pg_catalog.regclass as tgconstrrelname "
"from pg_catalog.pg_trigger t "
"where tgrelid = '%u'::pg_catalog.oid "
+ "and tgconstraint = 0",
+ tbinfo->dobj.catId.oid);
+ }
+ else if (g_fout->remoteVersion >= 70300)
+ {
+ /*
+ * We ignore triggers that are tied to a foreign-key constraint,
+ * but in these versions we have to grovel through pg_constraint
+ * to find out
+ */
+ appendPQExpBuffer(query,
+ "SELECT tgname, "
+ "tgfoid::pg_catalog.regproc as tgfname, "
+ "tgtype, tgnargs, tgargs, tgenabled, "
+ "tgisconstraint, tgconstrname, tgdeferrable, "
+ "tgconstrrelid, tginitdeferred, tableoid, oid, "
+ "tgconstrrelid::pg_catalog.regclass as tgconstrrelname "
+ "from pg_catalog.pg_trigger t "
+ "where tgrelid = '%u'::pg_catalog.oid "
"and (not tgisconstraint "
" OR NOT EXISTS"
" (SELECT 1 FROM pg_catalog.pg_depend d "
tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
tginfo[j].tgargs = strdup(PQgetvalue(res, j, i_tgargs));
tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
- tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled)) == 't';
+ tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
- if (g_fout->remoteVersion >= 80100)
+ if (g_fout->remoteVersion >= 80300)
+ {
+ /* pg_language has a lanowner column */
+ appendPQExpBuffer(query, "SELECT tableoid, oid, "
+ "lanname, lanpltrusted, lanplcallfoid, "
+ "lanvalidator, lanacl, "
+ "(%s lanowner) as lanowner "
+ "FROM pg_language "
+ "WHERE lanispl "
+ "ORDER BY oid",
+ username_subquery);
+ }
+ else if (g_fout->remoteVersion >= 80100)
{
/* Languages are owned by the bootstrap superuser, OID 10 */
appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
getTableAttrs(TableInfo *tblinfo, int numTables)
{
int i,
- j,
- k;
+ j;
PQExpBuffer q = createPQExpBuffer();
int i_attnum;
int i_attname;
tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
- tbinfo->attisserial = (bool *) malloc(ntups * sizeof(bool));
tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
- tbinfo->attisserial[j] = false; /* fix below */
tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
tbinfo->attrdefs[j] = NULL; /* fix below */
if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
tbinfo->dobj.name);
resetPQExpBuffer(q);
- if (g_fout->remoteVersion >= 70400)
+ if (g_fout->remoteVersion >= 80400)
+ {
+ appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
+ "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
+ "conislocal "
+ "FROM pg_catalog.pg_constraint "
+ "WHERE conrelid = '%u'::pg_catalog.oid "
+ " AND contype = 'c' "
+ "ORDER BY conname",
+ tbinfo->dobj.catId.oid);
+ }
+ else if (g_fout->remoteVersion >= 70400)
{
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
- "pg_catalog.pg_get_constraintdef(oid) AS consrc "
+ "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
+ "true as conislocal "
"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 "
+ "'CHECK (' || consrc || ')' AS consrc, "
+ "true as conislocal "
"FROM pg_catalog.pg_constraint "
"WHERE conrelid = '%u'::pg_catalog.oid "
" AND contype = 'c' "
/* 7.2 did not have OIDs in pg_relcheck */
appendPQExpBuffer(q, "SELECT tableoid, 0 as oid, "
"rcname AS conname, "
- "'CHECK (' || rcsrc || ')' AS consrc "
+ "'CHECK (' || rcsrc || ')' AS consrc, "
+ "true as conislocal "
"FROM pg_relcheck "
"WHERE rcrelid = '%u'::oid "
"ORDER BY rcname",
{
appendPQExpBuffer(q, "SELECT tableoid, oid, "
"rcname AS conname, "
- "'CHECK (' || rcsrc || ')' AS consrc "
+ "'CHECK (' || rcsrc || ')' AS consrc, "
+ "true as conislocal "
"FROM pg_relcheck "
"WHERE rcrelid = '%u'::oid "
"ORDER BY rcname",
appendPQExpBuffer(q, "SELECT "
"(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
"oid, rcname AS conname, "
- "'CHECK (' || rcsrc || ')' AS consrc "
+ "'CHECK (' || rcsrc || ')' AS consrc, "
+ "true as conislocal "
"FROM pg_relcheck "
"WHERE rcrelid = '%u'::oid "
"ORDER BY rcname",
constrs[j].contype = 'c';
constrs[j].condef = strdup(PQgetvalue(res, j, 3));
constrs[j].conindex = 0;
- constrs[j].coninherited = false;
+ constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
constrs[j].separate = false;
constrs[j].dobj.dump = tbinfo->dobj.dump;
/*
* If the constraint is inherited, this will be detected
- * later. We also detect later if the constraint must be
- * split out from the table definition.
+ * later (in pre-8.4 databases). We also detect later if the
+ * constraint must be split out from the table definition.
*/
}
PQclear(res);
}
-
- /*
- * Check to see if any columns are serial columns. Our first quick
- * filter is that it must be integer or bigint with a default. If so,
- * we scan to see if we found a sequence linked to this column. If we
- * did, mark the column and sequence appropriately.
- */
- for (j = 0; j < ntups; j++)
- {
- /*
- * Note assumption that format_type will show these types as
- * exactly "integer" and "bigint" regardless of schema path. This
- * is correct in 7.3 but needs to be watched.
- */
- if (strcmp(tbinfo->atttypnames[j], "integer") != 0 &&
- strcmp(tbinfo->atttypnames[j], "bigint") != 0)
- continue;
- if (tbinfo->attrdefs[j] == NULL)
- continue;
- for (k = 0; k < numTables; k++)
- {
- TableInfo *seqinfo = &tblinfo[k];
-
- if (OidIsValid(seqinfo->owning_tab) &&
- seqinfo->owning_tab == tbinfo->dobj.catId.oid &&
- seqinfo->owning_col == j + 1)
- {
- /*
- * Found a match. Copy the table's interesting and
- * dumpable flags to the sequence.
- */
- tbinfo->attisserial[j] = true;
- seqinfo->interesting = tbinfo->interesting;
- seqinfo->dobj.dump = tbinfo->dobj.dump;
- break;
- }
- }
- }
}
destroyPQExpBuffer(q);
/*
- * dumpComment --
- *
- * This routine is used to dump any comments associated with the
- * object handed to this routine. The routine takes a constant character
- * string for the target part of the comment-creation command, plus
- * the namespace and owner of the object (for labeling the ArchiveEntry),
- * plus catalog ID and subid which are the lookup key for pg_description,
- * plus the dump ID for the object (for setting a dependency).
- * If a matching pg_description entry is found, it is dumped.
+ * getTSParsers:
+ * read all text search parsers in the system catalogs and return them
+ * in the TSParserInfo* structure
*
- * Note: although this routine takes a dumpId for dependency purposes,
- * that purpose is just to mark the dependency in the emitted dump file
- * for possible future use by pg_restore. We do NOT use it for determining
- * ordering of the comment in the dump file, because this routine is called
- * after dependency sorting occurs. This routine should be called just after
- * calling ArchiveEntry() for the specified object.
+ * numTSParsers is set to the number of parsers read in
*/
-static void
-dumpComment(Archive *fout, const char *target,
- const char *namespace, const char *owner,
- CatalogId catalogId, int subid, DumpId dumpId)
+TSParserInfo *
+getTSParsers(int *numTSParsers)
{
- CommentItem *comments;
- int ncomments;
-
- /* Comments are SCHEMA not data */
- if (dataOnly)
- return;
-
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query = createPQExpBuffer();
+ TSParserInfo *prsinfo;
+ int i_tableoid;
+ int i_oid;
+ int i_prsname;
+ int i_prsnamespace;
+ int i_prsstart;
+ int i_prstoken;
+ int i_prsend;
+ int i_prsheadline;
+ int i_prslextype;
+
+ /* Before 8.3, there is no built-in text search support */
+ if (g_fout->remoteVersion < 80300)
+ {
+ *numTSParsers = 0;
+ return NULL;
+ }
+
+ /*
+ * 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("pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
+ "prsstart::oid, prstoken::oid, "
+ "prsend::oid, prsheadline::oid, prslextype::oid "
+ "FROM pg_ts_parser");
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ *numTSParsers = ntups;
+
+ prsinfo = (TSParserInfo *) malloc(ntups * sizeof(TSParserInfo));
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_prsname = PQfnumber(res, "prsname");
+ i_prsnamespace = PQfnumber(res, "prsnamespace");
+ i_prsstart = PQfnumber(res, "prsstart");
+ i_prstoken = PQfnumber(res, "prstoken");
+ i_prsend = PQfnumber(res, "prsend");
+ i_prsheadline = PQfnumber(res, "prsheadline");
+ i_prslextype = PQfnumber(res, "prslextype");
+
+ for (i = 0; i < ntups; i++)
+ {
+ prsinfo[i].dobj.objType = DO_TSPARSER;
+ prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&prsinfo[i].dobj);
+ prsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_prsname));
+ prsinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)),
+ prsinfo[i].dobj.catId.oid);
+ prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
+ prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
+ prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
+ prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
+ prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
+
+ /* Decide whether we want to dump it */
+ selectDumpableObject(&(prsinfo[i].dobj));
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return prsinfo;
+}
+
+/*
+ * getTSDictionaries:
+ * read all text search dictionaries in the system catalogs and return them
+ * in the TSDictInfo* structure
+ *
+ * numTSDicts is set to the number of dictionaries read in
+ */
+TSDictInfo *
+getTSDictionaries(int *numTSDicts)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query = createPQExpBuffer();
+ TSDictInfo *dictinfo;
+ int i_tableoid;
+ int i_oid;
+ int i_dictname;
+ int i_dictnamespace;
+ int i_rolname;
+ int i_dicttemplate;
+ int i_dictinitoption;
+
+ /* Before 8.3, there is no built-in text search support */
+ if (g_fout->remoteVersion < 80300)
+ {
+ *numTSDicts = 0;
+ return NULL;
+ }
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema("pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
+ "dictnamespace, (%s dictowner) as rolname, "
+ "dicttemplate, dictinitoption "
+ "FROM pg_ts_dict",
+ username_subquery);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ *numTSDicts = ntups;
+
+ dictinfo = (TSDictInfo *) malloc(ntups * sizeof(TSDictInfo));
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_dictname = PQfnumber(res, "dictname");
+ i_dictnamespace = PQfnumber(res, "dictnamespace");
+ i_rolname = PQfnumber(res, "rolname");
+ i_dictinitoption = PQfnumber(res, "dictinitoption");
+ i_dicttemplate = PQfnumber(res, "dicttemplate");
+
+ for (i = 0; i < ntups; i++)
+ {
+ dictinfo[i].dobj.objType = DO_TSDICT;
+ dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&dictinfo[i].dobj);
+ dictinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_dictname));
+ dictinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)),
+ dictinfo[i].dobj.catId.oid);
+ dictinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
+ dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
+ if (PQgetisnull(res, i, i_dictinitoption))
+ dictinfo[i].dictinitoption = NULL;
+ else
+ dictinfo[i].dictinitoption = strdup(PQgetvalue(res, i, i_dictinitoption));
+
+ /* Decide whether we want to dump it */
+ selectDumpableObject(&(dictinfo[i].dobj));
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return dictinfo;
+}
+
+/*
+ * getTSTemplates:
+ * read all text search templates in the system catalogs and return them
+ * in the TSTemplateInfo* structure
+ *
+ * numTSTemplates is set to the number of templates read in
+ */
+TSTemplateInfo *
+getTSTemplates(int *numTSTemplates)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query = createPQExpBuffer();
+ TSTemplateInfo *tmplinfo;
+ int i_tableoid;
+ int i_oid;
+ int i_tmplname;
+ int i_tmplnamespace;
+ int i_tmplinit;
+ int i_tmpllexize;
+
+ /* Before 8.3, there is no built-in text search support */
+ if (g_fout->remoteVersion < 80300)
+ {
+ *numTSTemplates = 0;
+ return NULL;
+ }
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema("pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
+ "tmplnamespace, tmplinit::oid, tmpllexize::oid "
+ "FROM pg_ts_template");
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ *numTSTemplates = ntups;
+
+ tmplinfo = (TSTemplateInfo *) malloc(ntups * sizeof(TSTemplateInfo));
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_tmplname = PQfnumber(res, "tmplname");
+ i_tmplnamespace = PQfnumber(res, "tmplnamespace");
+ i_tmplinit = PQfnumber(res, "tmplinit");
+ i_tmpllexize = PQfnumber(res, "tmpllexize");
+
+ for (i = 0; i < ntups; i++)
+ {
+ tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
+ tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&tmplinfo[i].dobj);
+ tmplinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_tmplname));
+ tmplinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)),
+ tmplinfo[i].dobj.catId.oid);
+ tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
+ tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
+
+ /* Decide whether we want to dump it */
+ selectDumpableObject(&(tmplinfo[i].dobj));
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return tmplinfo;
+}
+
+/*
+ * getTSConfigurations:
+ * read all text search configurations in the system catalogs and return
+ * them in the TSConfigInfo* structure
+ *
+ * numTSConfigs is set to the number of configurations read in
+ */
+TSConfigInfo *
+getTSConfigurations(int *numTSConfigs)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query = createPQExpBuffer();
+ TSConfigInfo *cfginfo;
+ int i_tableoid;
+ int i_oid;
+ int i_cfgname;
+ int i_cfgnamespace;
+ int i_rolname;
+ int i_cfgparser;
+
+ /* Before 8.3, there is no built-in text search support */
+ if (g_fout->remoteVersion < 80300)
+ {
+ *numTSConfigs = 0;
+ return NULL;
+ }
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema("pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
+ "cfgnamespace, (%s cfgowner) as rolname, cfgparser "
+ "FROM pg_ts_config",
+ username_subquery);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ *numTSConfigs = ntups;
+
+ cfginfo = (TSConfigInfo *) malloc(ntups * sizeof(TSConfigInfo));
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_cfgname = PQfnumber(res, "cfgname");
+ i_cfgnamespace = PQfnumber(res, "cfgnamespace");
+ i_rolname = PQfnumber(res, "rolname");
+ i_cfgparser = PQfnumber(res, "cfgparser");
+
+ for (i = 0; i < ntups; i++)
+ {
+ cfginfo[i].dobj.objType = DO_TSCONFIG;
+ cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&cfginfo[i].dobj);
+ cfginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_cfgname));
+ cfginfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)),
+ cfginfo[i].dobj.catId.oid);
+ cfginfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
+ cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
+
+ /* Decide whether we want to dump it */
+ selectDumpableObject(&(cfginfo[i].dobj));
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return cfginfo;
+}
+
+
+/*
+ * dumpComment --
+ *
+ * This routine is used to dump any comments associated with the
+ * object handed to this routine. The routine takes a constant character
+ * string for the target part of the comment-creation command, plus
+ * the namespace and owner of the object (for labeling the ArchiveEntry),
+ * plus catalog ID and subid which are the lookup key for pg_description,
+ * plus the dump ID for the object (for setting a dependency).
+ * If a matching pg_description entry is found, it is dumped.
+ *
+ * Note: although this routine takes a dumpId for dependency purposes,
+ * that purpose is just to mark the dependency in the emitted dump file
+ * for possible future use by pg_restore. We do NOT use it for determining
+ * ordering of the comment in the dump file, because this routine is called
+ * after dependency sorting occurs. This routine should be called just after
+ * calling ArchiveEntry() for the specified object.
+ */
+static void
+dumpComment(Archive *fout, const char *target,
+ const char *namespace, const char *owner,
+ CatalogId catalogId, int subid, DumpId dumpId)
+{
+ CommentItem *comments;
+ int ncomments;
+
+ /* Comments are SCHEMA not data */
+ if (dataOnly)
+ return;
+
/* Search for comments associated with catalogId, using table */
ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
&comments);
PQExpBuffer query = createPQExpBuffer();
appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
- appendStringLiteral(query, comments->descr, false);
+ appendStringLiteralAH(query, comments->descr, fout);
appendPQExpBuffer(query, ";\n");
ArchiveEntry(fout, nilCatalogId, createDumpId(),
resetPQExpBuffer(query);
appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
- appendStringLiteral(query, descr, false);
+ appendStringLiteralAH(query, descr, fout);
appendPQExpBuffer(query, ";\n");
ArchiveEntry(fout, nilCatalogId, createDumpId(),
resetPQExpBuffer(query);
appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
- appendStringLiteral(query, descr, false);
+ appendStringLiteralAH(query, descr, fout);
appendPQExpBuffer(query, ";\n");
ArchiveEntry(fout, nilCatalogId, createDumpId(),
case DO_OPCLASS:
dumpOpclass(fout, (OpclassInfo *) dobj);
break;
+ case DO_OPFAMILY:
+ dumpOpfamily(fout, (OpfamilyInfo *) dobj);
+ break;
case DO_CONVERSION:
dumpConversion(fout, (ConvInfo *) dobj);
break;
case DO_TABLE_TYPE:
/* table rowtypes are never dumped separately */
break;
+ case DO_TSPARSER:
+ dumpTSParser(fout, (TSParserInfo *) dobj);
+ break;
+ case DO_TSDICT:
+ dumpTSDictionary(fout, (TSDictInfo *) dobj);
+ break;
+ case DO_TSTEMPLATE:
+ dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
+ break;
+ case DO_TSCONFIG:
+ dumpTSConfig(fout, (TSConfigInfo *) dobj);
+ break;
case DO_BLOBS:
ArchiveEntry(fout, dobj->catId, dobj->dumpId,
dobj->name, NULL, NULL, "",
return;
/* Dump out in proper style */
- if (tinfo->typtype == 'b')
+ if (tinfo->typtype == TYPTYPE_BASE)
dumpBaseType(fout, tinfo);
- else if (tinfo->typtype == 'd')
+ else if (tinfo->typtype == TYPTYPE_DOMAIN)
dumpDomain(fout, tinfo);
- else if (tinfo->typtype == 'c')
+ else if (tinfo->typtype == TYPTYPE_COMPOSITE)
dumpCompositeType(fout, tinfo);
+ else if (tinfo->typtype == TYPTYPE_ENUM)
+ dumpEnumType(fout, tinfo);
}
/*
- * dumpBaseType
- * writes out to fout the queries to recreate a user-defined base type
+ * dumpEnumType
+ * writes out to fout the queries to recreate a user-defined enum type
*/
static void
-dumpBaseType(Archive *fout, TypeInfo *tinfo)
+dumpEnumType(Archive *fout, TypeInfo *tinfo)
{
PQExpBuffer q = createPQExpBuffer();
PQExpBuffer delq = createPQExpBuffer();
PQExpBuffer query = createPQExpBuffer();
PGresult *res;
- int ntups;
- char *typlen;
- char *typinput;
- char *typoutput;
- char *typreceive;
- char *typsend;
- char *typanalyze;
- Oid typinputoid;
- Oid typoutputoid;
- Oid typreceiveoid;
- Oid typsendoid;
- Oid typanalyzeoid;
- char *typdelim;
- char *typbyval;
- char *typalign;
- char *typstorage;
- char *typdefault;
- bool typdefault_is_literal = false;
+ int num,
+ i;
+ char *label;
/* Set proper schema search path so regproc references list correctly */
selectSourceSchema(tinfo->dobj.namespace->dobj.name);
- /* Fetch type-specific details */
- if (fout->remoteVersion >= 80000)
+ appendPQExpBuffer(query, "SELECT enumlabel FROM pg_catalog.pg_enum "
+ "WHERE enumtypid = '%u'"
+ "ORDER BY oid",
+ tinfo->dobj.catId.oid);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ num = PQntuples(res);
+ /* should be at least 1 value */
+ if (num == 0)
{
- appendPQExpBuffer(query, "SELECT typlen, "
- "typinput, typoutput, typreceive, typsend, "
- "typanalyze, "
- "typinput::pg_catalog.oid as typinputoid, "
- "typoutput::pg_catalog.oid as typoutputoid, "
- "typreceive::pg_catalog.oid as typreceiveoid, "
- "typsend::pg_catalog.oid as typsendoid, "
- "typanalyze::pg_catalog.oid as typanalyzeoid, "
- "typdelim, typbyval, typalign, typstorage, "
- "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault "
- "FROM pg_catalog.pg_type "
- "WHERE oid = '%u'::pg_catalog.oid",
- tinfo->dobj.catId.oid);
+ write_msg(NULL, "no label definitions found for enum ID %u\n", tinfo->dobj.catId.oid);
+ exit_nicely();
}
- else if (fout->remoteVersion >= 70400)
+
+ /*
+ * 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
+ * functions are generic and do not get dropped.
+ */
+ appendPQExpBuffer(delq, "DROP TYPE %s.",
+ fmtId(tinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, "%s;\n",
+ fmtId(tinfo->dobj.name));
+ appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (\n",
+ fmtId(tinfo->dobj.name));
+ for (i = 0; i < num; i++)
{
- appendPQExpBuffer(query, "SELECT typlen, "
- "typinput, typoutput, typreceive, typsend, "
- "'-' as typanalyze, "
- "typinput::pg_catalog.oid as typinputoid, "
+ label = PQgetvalue(res, i, 0);
+ if (i > 0)
+ appendPQExpBuffer(q, ",\n");
+ appendPQExpBuffer(q, " ");
+ appendStringLiteralAH(q, label, fout);
+ }
+ appendPQExpBuffer(q, "\n);\n");
+
+ ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
+ tinfo->dobj.name,
+ tinfo->dobj.namespace->dobj.name,
+ NULL,
+ tinfo->rolname, false,
+ "TYPE", q->data, delq->data, NULL,
+ tinfo->dobj.dependencies, tinfo->dobj.nDeps,
+ NULL, NULL);
+
+ /* Dump Type Comments */
+ resetPQExpBuffer(q);
+
+ appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
+ dumpComment(fout, q->data,
+ tinfo->dobj.namespace->dobj.name, tinfo->rolname,
+ tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
+
+ PQclear(res);
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+ destroyPQExpBuffer(query);
+}
+
+/*
+ * dumpBaseType
+ * writes out to fout the queries to recreate a user-defined base type
+ */
+static void
+dumpBaseType(Archive *fout, TypeInfo *tinfo)
+{
+ PQExpBuffer q = createPQExpBuffer();
+ PQExpBuffer delq = createPQExpBuffer();
+ PQExpBuffer query = createPQExpBuffer();
+ PGresult *res;
+ int ntups;
+ char *typlen;
+ char *typinput;
+ char *typoutput;
+ char *typreceive;
+ char *typsend;
+ char *typmodin;
+ char *typmodout;
+ char *typanalyze;
+ Oid typinputoid;
+ Oid typoutputoid;
+ Oid typreceiveoid;
+ Oid typsendoid;
+ Oid typmodinoid;
+ Oid typmodoutoid;
+ Oid typanalyzeoid;
+ char *typdelim;
+ char *typbyval;
+ char *typalign;
+ char *typstorage;
+ char *typdefault;
+ bool typdefault_is_literal = false;
+
+ /* Set proper schema search path so regproc references list correctly */
+ selectSourceSchema(tinfo->dobj.namespace->dobj.name);
+
+ /* Fetch type-specific details */
+ if (fout->remoteVersion >= 80300)
+ {
+ appendPQExpBuffer(query, "SELECT typlen, "
+ "typinput, typoutput, typreceive, typsend, "
+ "typmodin, typmodout, typanalyze, "
+ "typinput::pg_catalog.oid as typinputoid, "
"typoutput::pg_catalog.oid as typoutputoid, "
"typreceive::pg_catalog.oid as typreceiveoid, "
"typsend::pg_catalog.oid as typsendoid, "
+ "typmodin::pg_catalog.oid as typmodinoid, "
+ "typmodout::pg_catalog.oid as typmodoutoid, "
+ "typanalyze::pg_catalog.oid as typanalyzeoid, "
+ "typdelim, typbyval, typalign, typstorage, "
+ "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault "
+ "FROM pg_catalog.pg_type "
+ "WHERE oid = '%u'::pg_catalog.oid",
+ tinfo->dobj.catId.oid);
+ }
+ else if (fout->remoteVersion >= 80000)
+ {
+ appendPQExpBuffer(query, "SELECT typlen, "
+ "typinput, typoutput, typreceive, typsend, "
+ "'-' as typmodin, '-' as typmodout, "
+ "typanalyze, "
+ "typinput::pg_catalog.oid as typinputoid, "
+ "typoutput::pg_catalog.oid as typoutputoid, "
+ "typreceive::pg_catalog.oid as typreceiveoid, "
+ "typsend::pg_catalog.oid as typsendoid, "
+ "0 as typmodinoid, 0 as typmodoutoid, "
+ "typanalyze::pg_catalog.oid as typanalyzeoid, "
+ "typdelim, typbyval, typalign, typstorage, "
+ "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault "
+ "FROM pg_catalog.pg_type "
+ "WHERE oid = '%u'::pg_catalog.oid",
+ tinfo->dobj.catId.oid);
+ }
+ else if (fout->remoteVersion >= 70400)
+ {
+ appendPQExpBuffer(query, "SELECT typlen, "
+ "typinput, typoutput, typreceive, typsend, "
+ "'-' as typmodin, '-' as typmodout, "
+ "'-' as typanalyze, "
+ "typinput::pg_catalog.oid as typinputoid, "
+ "typoutput::pg_catalog.oid as typoutputoid, "
+ "typreceive::pg_catalog.oid as typreceiveoid, "
+ "typsend::pg_catalog.oid as typsendoid, "
+ "0 as typmodinoid, 0 as typmodoutoid, "
"0 as typanalyzeoid, "
"typdelim, typbyval, typalign, typstorage, "
"pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault "
appendPQExpBuffer(query, "SELECT typlen, "
"typinput, typoutput, "
"'-' as typreceive, '-' as typsend, "
+ "'-' as typmodin, '-' as typmodout, "
"'-' as typanalyze, "
"typinput::pg_catalog.oid as typinputoid, "
"typoutput::pg_catalog.oid as typoutputoid, "
"0 as typreceiveoid, 0 as typsendoid, "
+ "0 as typmodinoid, 0 as typmodoutoid, "
"0 as typanalyzeoid, "
"typdelim, typbyval, typalign, typstorage, "
"pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault "
appendPQExpBuffer(query, "SELECT typlen, "
"typinput, typoutput, "
"'-' as typreceive, '-' as typsend, "
+ "'-' as typmodin, '-' as typmodout, "
"'-' as typanalyze, "
"typinput::oid as typinputoid, "
"typoutput::oid as typoutputoid, "
"0 as typreceiveoid, 0 as typsendoid, "
+ "0 as typmodinoid, 0 as typmodoutoid, "
"0 as typanalyzeoid, "
"typdelim, typbyval, typalign, typstorage, "
"NULL as typdefaultbin, typdefault "
appendPQExpBuffer(query, "SELECT typlen, "
"typinput, typoutput, "
"'-' as typreceive, '-' as typsend, "
+ "'-' as typmodin, '-' as typmodout, "
"'-' as typanalyze, "
"typinput::oid as typinputoid, "
"typoutput::oid as typoutputoid, "
"0 as typreceiveoid, 0 as typsendoid, "
+ "0 as typmodinoid, 0 as typmodoutoid, "
"0 as typanalyzeoid, "
"typdelim, typbyval, typalign, typstorage, "
"NULL as typdefaultbin, NULL as typdefault "
appendPQExpBuffer(query, "SELECT typlen, "
"typinput, typoutput, "
"'-' as typreceive, '-' as typsend, "
+ "'-' as typmodin, '-' as typmodout, "
"'-' as typanalyze, "
"typinput::oid as typinputoid, "
"typoutput::oid as typoutputoid, "
"0 as typreceiveoid, 0 as typsendoid, "
+ "0 as typmodinoid, 0 as typmodoutoid, "
"0 as typanalyzeoid, "
"typdelim, typbyval, typalign, "
"'p'::char as typstorage, "
ntups = PQntuples(res);
if (ntups != 1)
{
- write_msg(NULL, "Got %d rows instead of one from: %s",
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
ntups, query->data);
exit_nicely();
}
typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
+ typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
+ typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
typinputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typinputoid")));
typoutputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typoutputoid")));
typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
+ typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
+ typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
{
typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
- typdefault_is_literal = true; /* it needs quotes */
+ typdefault_is_literal = true; /* it needs quotes */
}
else
typdefault = NULL;
/*
* DROP must be fully qualified in case same name appears in pg_catalog.
* The reason we include CASCADE is that the circular dependency between
- * the type and its I/O functions makes it impossible to drop the type
- * any other way.
+ * the type and its I/O functions makes it impossible to drop the type any
+ * other way.
*/
appendPQExpBuffer(delq, "DROP TYPE %s.",
fmtId(tinfo->dobj.namespace->dobj.name));
appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
if (OidIsValid(typsendoid))
appendPQExpBuffer(q, ",\n SEND = %s", typsend);
+ if (OidIsValid(typmodinoid))
+ appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
+ if (OidIsValid(typmodoutoid))
+ appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
if (OidIsValid(typanalyzeoid))
appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
}
/* cannot combine these because fmtId uses static result area */
appendPQExpBuffer(q, ",\n INPUT = %s", fmtId(typinput));
appendPQExpBuffer(q, ",\n OUTPUT = %s", fmtId(typoutput));
- /* no chance that receive/send/analyze need be printed */
+ /* receive/send/typmodin/typmodout/analyze need not be printed */
}
if (typdefault != NULL)
{
appendPQExpBuffer(q, ",\n DEFAULT = ");
if (typdefault_is_literal)
- appendStringLiteral(q, typdefault, true);
+ appendStringLiteralAH(q, typdefault, fout);
else
appendPQExpBufferStr(q, typdefault);
}
- if (tinfo->isArray)
+ if (OidIsValid(tinfo->typelem))
{
char *elemType;
if (typdelim && strcmp(typdelim, ",") != 0)
{
appendPQExpBuffer(q, ",\n DELIMITER = ");
- appendStringLiteral(q, typdelim, true);
+ appendStringLiteralAH(q, typdelim, fout);
}
if (strcmp(typalign, "c") == 0)
ntups = PQntuples(res);
if (ntups != 1)
{
- write_msg(NULL, "Got %d rows instead of one from: %s",
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
ntups, query->data);
exit_nicely();
}
else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
{
typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
- typdefault_is_literal = true; /* it needs quotes */
+ typdefault_is_literal = true; /* it needs quotes */
}
else
typdefault = NULL;
{
appendPQExpBuffer(q, " DEFAULT ");
if (typdefault_is_literal)
- appendStringLiteral(q, typdefault, true);
+ appendStringLiteralAH(q, typdefault, fout);
else
appendPQExpBufferStr(q, typdefault);
}
ntups = PQntuples(res);
if (ntups < 1)
{
- write_msg(NULL, "query yielded no rows: %s\n", query->data);
+ write_msg(NULL, "query returned no rows: %s\n", query->data);
exit_nicely();
}
/*
* Note the lack of a DROP command for the shell type; any required DROP
- * is driven off the base type entry, instead. This interacts with
+ * is driven off the base type entry, instead. This interacts with
* _printTocEntry()'s use of the presence of a DROP command to decide
- * whether an entry needs an ALTER OWNER command. We don't want to
- * alter the shell type's owner immediately on creation; that should
- * happen only after it's filled in, otherwise the backend complains.
+ * whether an entry needs an ALTER OWNER command. We don't want to alter
+ * the shell type's owner immediately on creation; that should happen only
+ * after it's filled in, otherwise the backend complains.
*/
appendPQExpBuffer(q, "CREATE TYPE %s;\n",
static bool
shouldDumpProcLangs(void)
{
- if (selectTableName != NULL || selectSchemaName != NULL)
+ if (!include_everything)
return false;
/* And they're schema not data */
if (dataOnly)
{
switch (argmodes[j][0])
{
- case 'i':
+ case PROARGMODE_IN:
argmode = "";
break;
- case 'o':
+ case PROARGMODE_OUT:
argmode = "OUT ";
break;
- case 'b':
+ case PROARGMODE_INOUT:
argmode = "INOUT ";
break;
+ case PROARGMODE_VARIADIC:
+ argmode = "VARIADIC ";
+ break;
default:
write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
argmode = "";
char *provolatile;
char *proisstrict;
char *prosecdef;
+ char *proconfig;
+ char *procost;
+ char *prorows;
char *lanname;
char *rettypename;
int nallargs;
char **allargtypes = NULL;
char **argmodes = NULL;
char **argnames = NULL;
+ char **configitems = NULL;
+ int nconfigitems = 0;
+ int i;
/* Skip if not to be dumped */
if (!finfo->dobj.dump || dataOnly)
selectSourceSchema(finfo->dobj.namespace->dobj.name);
/* Fetch function-specific details */
- if (g_fout->remoteVersion >= 80100)
+ if (g_fout->remoteVersion >= 80300)
+ {
+ appendPQExpBuffer(query,
+ "SELECT proretset, prosrc, probin, "
+ "proallargtypes, proargmodes, proargnames, "
+ "provolatile, proisstrict, prosecdef, "
+ "proconfig, procost, prorows, "
+ "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
+ "FROM pg_catalog.pg_proc "
+ "WHERE oid = '%u'::pg_catalog.oid",
+ finfo->dobj.catId.oid);
+ }
+ else if (g_fout->remoteVersion >= 80100)
{
appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, "
"proallargtypes, proargmodes, proargnames, "
"provolatile, proisstrict, prosecdef, "
+ "null as proconfig, 0 as procost, 0 as prorows, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
"null as proargmodes, "
"proargnames, "
"provolatile, proisstrict, prosecdef, "
+ "null as proconfig, 0 as procost, 0 as prorows, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
"null as proargmodes, "
"null as proargnames, "
"provolatile, proisstrict, prosecdef, "
+ "null as proconfig, 0 as procost, 0 as prorows, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
"case when proiscachable then 'i' else 'v' end as provolatile, "
"proisstrict, "
"'f'::boolean as prosecdef, "
+ "null as proconfig, 0 as procost, 0 as prorows, "
"(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
"FROM pg_proc "
"WHERE oid = '%u'::oid",
"case when proiscachable then 'i' else 'v' end as provolatile, "
"'f'::boolean as proisstrict, "
"'f'::boolean as prosecdef, "
+ "null as proconfig, 0 as procost, 0 as prorows, "
"(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
"FROM pg_proc "
"WHERE oid = '%u'::oid",
ntups = PQntuples(res);
if (ntups != 1)
{
- write_msg(NULL, "Got %d rows instead of one from: %s",
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
ntups, query->data);
exit_nicely();
}
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
+ proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
+ procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
+ prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
/*
- * See backend/commands/define.c for details of how the 'AS' clause is
- * used.
+ * See backend/commands/functioncmds.c for details of how the 'AS' clause
+ * is used. In 8.4 and up, an unused probin is NULL (here ""); previous
+ * versions would set it to "-". There are no known cases in which prosrc
+ * is unused, so the tests below for "-" are probably useless.
*/
- if (strcmp(probin, "-") != 0)
+ if (probin[0] != '\0' && strcmp(probin, "-") != 0)
{
appendPQExpBuffer(asPart, "AS ");
- appendStringLiteral(asPart, probin, true);
+ appendStringLiteralAH(asPart, probin, fout);
if (strcmp(prosrc, "-") != 0)
{
appendPQExpBuffer(asPart, ", ");
* where we have bin, use dollar quoting if allowed and src
* contains quote or backslash; else use regular quoting.
*/
- if (disable_dollar_quoting)
- appendStringLiteral(asPart, prosrc, false);
+ if (disable_dollar_quoting ||
+ (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
+ appendStringLiteralAH(asPart, prosrc, fout);
else
- appendStringLiteralDQOpt(asPart, prosrc, false, NULL);
+ appendStringLiteralDQ(asPart, prosrc, NULL);
}
}
else
appendPQExpBuffer(asPart, "AS ");
/* with no bin, dollar quote src unconditionally if allowed */
if (disable_dollar_quoting)
- appendStringLiteral(asPart, prosrc, false);
+ appendStringLiteralAH(asPart, prosrc, fout);
else
appendStringLiteralDQ(asPart, prosrc, NULL);
}
}
}
+ if (proconfig && *proconfig)
+ {
+ if (!parsePGArray(proconfig, &configitems, &nconfigitems))
+ {
+ write_msg(NULL, "WARNING: could not parse proconfig array\n");
+ if (configitems)
+ free(configitems);
+ configitems = NULL;
+ nconfigitems = 0;
+ }
+ }
+
funcsig = format_function_arguments(finfo, nallargs, allargtypes,
argmodes, argnames);
funcsig_tag = format_function_signature(finfo, false);
rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcsig);
- appendPQExpBuffer(q, "RETURNS %s%s\n %s\n LANGUAGE %s",
+ appendPQExpBuffer(q, "RETURNS %s%s",
(proretset[0] == 't') ? "SETOF " : "",
- rettypename,
- asPart->data,
- fmtId(lanname));
-
+ rettypename);
free(rettypename);
+ appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
if (provolatile[0] != PROVOLATILE_VOLATILE)
{
if (provolatile[0] == PROVOLATILE_IMMUTABLE)
if (prosecdef[0] == 't')
appendPQExpBuffer(q, " SECURITY DEFINER");
- appendPQExpBuffer(q, ";\n");
+ /*
+ * COST and ROWS are emitted only if present and not default, so as not to
+ * break backwards-compatibility of the dump without need. Keep this code
+ * in sync with the defaults in functioncmds.c.
+ */
+ if (strcmp(procost, "0") != 0)
+ {
+ if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
+ {
+ /* default cost is 1 */
+ if (strcmp(procost, "1") != 0)
+ appendPQExpBuffer(q, " COST %s", procost);
+ }
+ else
+ {
+ /* default cost is 100 */
+ if (strcmp(procost, "100") != 0)
+ appendPQExpBuffer(q, " COST %s", procost);
+ }
+ }
+ if (proretset[0] == 't' &&
+ strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
+ appendPQExpBuffer(q, " ROWS %s", prorows);
+
+ for (i = 0; i < nconfigitems; i++)
+ {
+ /* we feel free to scribble on configitems[] here */
+ char *configitem = configitems[i];
+ char *pos;
+
+ pos = strchr(configitem, '=');
+ if (pos == NULL)
+ continue;
+ *pos++ = '\0';
+ appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
+
+ /*
+ * Some GUC variable names are 'LIST' type and hence must not be
+ * quoted.
+ */
+ if (pg_strcasecmp(configitem, "DateStyle") == 0
+ || pg_strcasecmp(configitem, "search_path") == 0)
+ appendPQExpBuffer(q, "%s", pos);
+ else
+ appendStringLiteralAH(q, pos, fout);
+ }
+
+ appendPQExpBuffer(q, "\n %s;\n", asPart->data);
ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
funcsig_tag,
free(argmodes);
if (argnames)
free(argnames);
+ if (configitems)
+ free(configitems);
}
int i_oprnegate;
int i_oprrest;
int i_oprjoin;
+ int i_oprcanmerge;
int i_oprcanhash;
- int i_oprlsortop;
- int i_oprrsortop;
- int i_oprltcmpop;
- int i_oprgtcmpop;
char *oprkind;
char *oprcode;
char *oprleft;
char *oprnegate;
char *oprrest;
char *oprjoin;
+ char *oprcanmerge;
char *oprcanhash;
- char *oprlsortop;
- char *oprrsortop;
- char *oprltcmpop;
- char *oprgtcmpop;
/* Skip if not to be dumped */
if (!oprinfo->dobj.dump || dataOnly)
/* Make sure we are in proper schema so regoperator works correctly */
selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
- if (g_fout->remoteVersion >= 70300)
+ if (g_fout->remoteVersion >= 80300)
+ {
+ appendPQExpBuffer(query, "SELECT oprkind, "
+ "oprcode::pg_catalog.regprocedure, "
+ "oprleft::pg_catalog.regtype, "
+ "oprright::pg_catalog.regtype, "
+ "oprcom::pg_catalog.regoperator, "
+ "oprnegate::pg_catalog.regoperator, "
+ "oprrest::pg_catalog.regprocedure, "
+ "oprjoin::pg_catalog.regprocedure, "
+ "oprcanmerge, oprcanhash "
+ "from pg_catalog.pg_operator "
+ "where oid = '%u'::pg_catalog.oid",
+ oprinfo->dobj.catId.oid);
+ }
+ else if (g_fout->remoteVersion >= 70300)
{
appendPQExpBuffer(query, "SELECT oprkind, "
"oprcode::pg_catalog.regprocedure, "
"oprnegate::pg_catalog.regoperator, "
"oprrest::pg_catalog.regprocedure, "
"oprjoin::pg_catalog.regprocedure, "
- "oprcanhash, "
- "oprlsortop::pg_catalog.regoperator, "
- "oprrsortop::pg_catalog.regoperator, "
- "oprltcmpop::pg_catalog.regoperator, "
- "oprgtcmpop::pg_catalog.regoperator "
+ "(oprlsortop != 0) as oprcanmerge, "
+ "oprcanhash "
"from pg_catalog.pg_operator "
"where oid = '%u'::pg_catalog.oid",
oprinfo->dobj.catId.oid);
"CASE WHEN oprright = 0 THEN '-' "
"ELSE format_type(oprright, NULL) END as oprright, "
"oprcom, oprnegate, oprrest, oprjoin, "
- "oprcanhash, oprlsortop, oprrsortop, "
- "0 as oprltcmpop, 0 as oprgtcmpop "
+ "(oprlsortop != 0) as oprcanmerge, "
+ "oprcanhash "
"from pg_operator "
"where oid = '%u'::oid",
oprinfo->dobj.catId.oid);
"CASE WHEN oprright = 0 THEN '-'::name "
"ELSE (select typname from pg_type where oid = oprright) END as oprright, "
"oprcom, oprnegate, oprrest, oprjoin, "
- "oprcanhash, oprlsortop, oprrsortop, "
- "0 as oprltcmpop, 0 as oprgtcmpop "
+ "(oprlsortop != 0) as oprcanmerge, "
+ "oprcanhash "
"from pg_operator "
"where oid = '%u'::oid",
oprinfo->dobj.catId.oid);
ntups = PQntuples(res);
if (ntups != 1)
{
- write_msg(NULL, "Got %d rows instead of one from: %s",
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
ntups, query->data);
exit_nicely();
}
i_oprnegate = PQfnumber(res, "oprnegate");
i_oprrest = PQfnumber(res, "oprrest");
i_oprjoin = PQfnumber(res, "oprjoin");
+ i_oprcanmerge = PQfnumber(res, "oprcanmerge");
i_oprcanhash = PQfnumber(res, "oprcanhash");
- i_oprlsortop = PQfnumber(res, "oprlsortop");
- i_oprrsortop = PQfnumber(res, "oprrsortop");
- i_oprltcmpop = PQfnumber(res, "oprltcmpop");
- i_oprgtcmpop = PQfnumber(res, "oprgtcmpop");
oprkind = PQgetvalue(res, 0, i_oprkind);
oprcode = PQgetvalue(res, 0, i_oprcode);
oprnegate = PQgetvalue(res, 0, i_oprnegate);
oprrest = PQgetvalue(res, 0, i_oprrest);
oprjoin = PQgetvalue(res, 0, i_oprjoin);
+ oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
- oprlsortop = PQgetvalue(res, 0, i_oprlsortop);
- oprrsortop = PQgetvalue(res, 0, i_oprrsortop);
- oprltcmpop = PQgetvalue(res, 0, i_oprltcmpop);
- oprgtcmpop = PQgetvalue(res, 0, i_oprgtcmpop);
appendPQExpBuffer(details, " PROCEDURE = %s",
convertRegProcReference(oprcode));
if (name)
appendPQExpBuffer(details, ",\n NEGATOR = %s", name);
+ if (strcmp(oprcanmerge, "t") == 0)
+ appendPQExpBuffer(details, ",\n MERGES");
+
if (strcmp(oprcanhash, "t") == 0)
appendPQExpBuffer(details, ",\n HASHES");
if (name)
appendPQExpBuffer(details, ",\n JOIN = %s", name);
- name = convertOperatorReference(oprlsortop);
- if (name)
- appendPQExpBuffer(details, ",\n SORT1 = %s", name);
-
- name = convertOperatorReference(oprrsortop);
- if (name)
- appendPQExpBuffer(details, ",\n SORT2 = %s", name);
-
- name = convertOperatorReference(oprltcmpop);
- if (name)
- appendPQExpBuffer(details, ",\n LTCMP = %s", name);
-
- name = convertOperatorReference(oprgtcmpop);
- if (name)
- appendPQExpBuffer(details, ",\n GTCMP = %s", name);
-
/*
* DROP must be fully qualified in case same name appears in pg_catalog
*/
}
/*
+ * Convert a function OID obtained from pg_ts_parser or pg_ts_template
+ *
+ * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
+ * argument lists of these functions are predetermined. Note that the
+ * caller should ensure we are in the proper schema, because the results
+ * are search path dependent!
+ */
+static const char *
+convertTSFunction(Oid funcOid)
+{
+ char *result;
+ char query[128];
+ PGresult *res;
+ int ntups;
+
+ snprintf(query, sizeof(query),
+ "SELECT '%u'::pg_catalog.regproc", funcOid);
+ res = PQexec(g_conn, query);
+ check_sql_result(res, g_conn, query, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ if (ntups != 1)
+ {
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
+ ntups, query);
+ exit_nicely();
+ }
+
+ result = strdup(PQgetvalue(res, 0, 0));
+
+ PQclear(res);
+
+ return result;
+}
+
+
+/*
* dumpOpclass
* write out a single operator class definition
*/
int i_opcintype;
int i_opckeytype;
int i_opcdefault;
+ int i_opcfamily;
+ int i_opcfamilynsp;
int i_amname;
int i_amopstrategy;
int i_amopreqcheck;
char *opcintype;
char *opckeytype;
char *opcdefault;
+ char *opcfamily;
+ char *opcfamilynsp;
char *amname;
char *amopstrategy;
char *amopreqcheck;
selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
/* Get additional fields from the pg_opclass row */
- appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
- "opckeytype::pg_catalog.regtype, "
- "opcdefault, "
- "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
- "FROM pg_catalog.pg_opclass "
- "WHERE oid = '%u'::pg_catalog.oid",
- opcinfo->dobj.catId.oid);
+ if (g_fout->remoteVersion >= 80300)
+ {
+ appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
+ "opckeytype::pg_catalog.regtype, "
+ "opcdefault, "
+ "opfname AS opcfamily, "
+ "nspname AS opcfamilynsp, "
+ "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
+ "FROM pg_catalog.pg_opclass c "
+ "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
+ "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
+ "WHERE c.oid = '%u'::pg_catalog.oid",
+ opcinfo->dobj.catId.oid);
+ }
+ else
+ {
+ appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
+ "opckeytype::pg_catalog.regtype, "
+ "opcdefault, "
+ "NULL AS opcfamily, "
+ "NULL AS opcfamilynsp, "
+ "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
+ "FROM pg_catalog.pg_opclass "
+ "WHERE oid = '%u'::pg_catalog.oid",
+ opcinfo->dobj.catId.oid);
+ }
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res);
if (ntups != 1)
{
- write_msg(NULL, "Got %d rows instead of one from: %s",
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
ntups, query->data);
exit_nicely();
}
i_opcintype = PQfnumber(res, "opcintype");
i_opckeytype = PQfnumber(res, "opckeytype");
i_opcdefault = PQfnumber(res, "opcdefault");
+ i_opcfamily = PQfnumber(res, "opcfamily");
+ i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
i_amname = PQfnumber(res, "amname");
opcintype = PQgetvalue(res, 0, i_opcintype);
opckeytype = PQgetvalue(res, 0, i_opckeytype);
opcdefault = PQgetvalue(res, 0, i_opcdefault);
+ opcfamily = PQgetvalue(res, 0, i_opcfamily);
+ opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
/* amname will still be needed after we PQclear res */
amname = strdup(PQgetvalue(res, 0, i_amname));
fmtId(opcinfo->dobj.name));
if (strcmp(opcdefault, "t") == 0)
appendPQExpBuffer(q, "DEFAULT ");
- appendPQExpBuffer(q, "FOR TYPE %s USING %s AS\n ",
+ appendPQExpBuffer(q, "FOR TYPE %s USING %s",
opcintype,
fmtId(amname));
+ if (strlen(opcfamily) > 0 &&
+ (strcmp(opcfamily, opcinfo->dobj.name) != 0 ||
+ strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
+ {
+ appendPQExpBuffer(q, " FAMILY ");
+ if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
+ appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
+ appendPQExpBuffer(q, "%s", fmtId(opcfamily));
+ }
+ appendPQExpBuffer(q, " AS\n ");
needComma = false;
*/
resetPQExpBuffer(query);
- appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
- "amopopr::pg_catalog.regoperator "
- "FROM pg_catalog.pg_amop "
- "WHERE amopclaid = '%u'::pg_catalog.oid "
- "ORDER BY amopstrategy",
- opcinfo->dobj.catId.oid);
+ if (g_fout->remoteVersion >= 80400)
+ {
+ /*
+ * Print only those opfamily members that are tied to the opclass by
+ * pg_depend entries.
+ *
+ * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
+ * an older server's table in which it is used. Would it be better
+ * to silently ignore it?
+ */
+ appendPQExpBuffer(query, "SELECT amopstrategy, false as amopreqcheck, "
+ "amopopr::pg_catalog.regoperator "
+ "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
+ "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
+ "AND refobjid = '%u'::pg_catalog.oid "
+ "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
+ "AND objid = ao.oid "
+ "ORDER BY amopstrategy",
+ opcinfo->dobj.catId.oid);
+ }
+ else if (g_fout->remoteVersion >= 80300)
+ {
+ /*
+ * Print only those opfamily members that are tied to the opclass by
+ * pg_depend entries.
+ */
+ appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
+ "amopopr::pg_catalog.regoperator "
+ "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
+ "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
+ "AND refobjid = '%u'::pg_catalog.oid "
+ "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
+ "AND objid = ao.oid "
+ "ORDER BY amopstrategy",
+ opcinfo->dobj.catId.oid);
+ }
+ else
+ {
+ appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
+ "amopopr::pg_catalog.regoperator "
+ "FROM pg_catalog.pg_amop "
+ "WHERE amopclaid = '%u'::pg_catalog.oid "
+ "ORDER BY amopstrategy",
+ opcinfo->dobj.catId.oid);
+ }
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
*/
resetPQExpBuffer(query);
- appendPQExpBuffer(query, "SELECT amprocnum, "
- "amproc::pg_catalog.regprocedure "
- "FROM pg_catalog.pg_amproc "
- "WHERE amopclaid = '%u'::pg_catalog.oid "
- "ORDER BY amprocnum",
- opcinfo->dobj.catId.oid);
+ if (g_fout->remoteVersion >= 80300)
+ {
+ /*
+ * Print only those opfamily members that are tied to the opclass by
+ * pg_depend entries.
+ */
+ appendPQExpBuffer(query, "SELECT amprocnum, "
+ "amproc::pg_catalog.regprocedure "
+ "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
+ "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
+ "AND refobjid = '%u'::pg_catalog.oid "
+ "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
+ "AND objid = ap.oid "
+ "ORDER BY amprocnum",
+ opcinfo->dobj.catId.oid);
+ }
+ else
+ {
+ appendPQExpBuffer(query, "SELECT amprocnum, "
+ "amproc::pg_catalog.regprocedure "
+ "FROM pg_catalog.pg_amproc "
+ "WHERE amopclaid = '%u'::pg_catalog.oid "
+ "ORDER BY amprocnum",
+ opcinfo->dobj.catId.oid);
+ }
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
}
/*
- * dumpConversion
- * write out a single conversion definition
+ * dumpOpfamily
+ * write out a single operator family definition
*/
static void
-dumpConversion(Archive *fout, ConvInfo *convinfo)
+dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
{
PQExpBuffer query;
PQExpBuffer q;
PQExpBuffer delq;
- PQExpBuffer details;
PGresult *res;
+ PGresult *res_ops;
+ PGresult *res_procs;
int ntups;
- int i_conname;
- int i_conforencoding;
- int i_contoencoding;
- int i_conproc;
- int i_condefault;
- const char *conname;
- const char *conforencoding;
- const char *contoencoding;
- const char *conproc;
- bool condefault;
+ int i_amname;
+ int i_amopstrategy;
+ int i_amopreqcheck;
+ int i_amopopr;
+ int i_amprocnum;
+ int i_amproc;
+ int i_amproclefttype;
+ int i_amprocrighttype;
+ char *amname;
+ char *amopstrategy;
+ char *amopreqcheck;
+ char *amopopr;
+ char *amprocnum;
+ char *amproc;
+ char *amproclefttype;
+ char *amprocrighttype;
+ bool needComma;
+ int i;
/* Skip if not to be dumped */
- if (!convinfo->dobj.dump || dataOnly)
+ if (!opfinfo->dobj.dump || dataOnly)
return;
+ /*
+ * We want to dump the opfamily only if (1) it contains "loose" operators
+ * or functions, or (2) it contains an opclass with a different name or
+ * owner. Otherwise it's sufficient to let it be created during creation
+ * of the contained opclass, and not dumping it improves portability of
+ * the dump. Since we have to fetch the loose operators/funcs anyway, do
+ * that first.
+ */
+
query = createPQExpBuffer();
q = createPQExpBuffer();
delq = createPQExpBuffer();
- details = createPQExpBuffer();
- /* Make sure we are in proper schema */
- selectSourceSchema(convinfo->dobj.namespace->dobj.name);
+ /* Make sure we are in proper schema so regoperator works correctly */
+ selectSourceSchema(opfinfo->dobj.namespace->dobj.name);
- /* Get conversion-specific details */
- appendPQExpBuffer(query, "SELECT conname, "
- "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
- "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
- "conproc, condefault "
- "FROM pg_catalog.pg_conversion c "
- "WHERE c.oid = '%u'::pg_catalog.oid",
+ /*
+ * Fetch only those opfamily members that are tied directly to the
+ * opfamily by pg_depend entries.
+ */
+ if (g_fout->remoteVersion >= 80400)
+ {
+ /*
+ * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
+ * an older server's table in which it is used. Would it be better
+ * to silently ignore it?
+ */
+ appendPQExpBuffer(query, "SELECT amopstrategy, false as amopreqcheck, "
+ "amopopr::pg_catalog.regoperator "
+ "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
+ "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
+ "AND refobjid = '%u'::pg_catalog.oid "
+ "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
+ "AND objid = ao.oid "
+ "ORDER BY amopstrategy",
+ opfinfo->dobj.catId.oid);
+ }
+ else
+ {
+ appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
+ "amopopr::pg_catalog.regoperator "
+ "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
+ "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
+ "AND refobjid = '%u'::pg_catalog.oid "
+ "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
+ "AND objid = ao.oid "
+ "ORDER BY amopstrategy",
+ opfinfo->dobj.catId.oid);
+ }
+
+ res_ops = PQexec(g_conn, query->data);
+ check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK);
+
+ resetPQExpBuffer(query);
+
+ appendPQExpBuffer(query, "SELECT amprocnum, "
+ "amproc::pg_catalog.regprocedure, "
+ "amproclefttype::pg_catalog.regtype, "
+ "amprocrighttype::pg_catalog.regtype "
+ "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
+ "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
+ "AND refobjid = '%u'::pg_catalog.oid "
+ "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
+ "AND objid = ap.oid "
+ "ORDER BY amprocnum",
+ opfinfo->dobj.catId.oid);
+
+ res_procs = PQexec(g_conn, query->data);
+ check_sql_result(res_procs, g_conn, query->data, PGRES_TUPLES_OK);
+
+ if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
+ {
+ /* No loose members, so check contained opclasses */
+ resetPQExpBuffer(query);
+
+ appendPQExpBuffer(query, "SELECT 1 "
+ "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
+ "WHERE f.oid = '%u'::pg_catalog.oid "
+ "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
+ "AND refobjid = f.oid "
+ "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
+ "AND objid = c.oid "
+ "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
+ "LIMIT 1",
+ opfinfo->dobj.catId.oid);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ if (PQntuples(res) == 0)
+ {
+ /* no need to dump it, so bail out */
+ PQclear(res);
+ PQclear(res_ops);
+ PQclear(res_procs);
+ destroyPQExpBuffer(query);
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+ return;
+ }
+
+ PQclear(res);
+ }
+
+ /* Get additional fields from the pg_opfamily row */
+ resetPQExpBuffer(query);
+
+ appendPQExpBuffer(query, "SELECT "
+ "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
+ "FROM pg_catalog.pg_opfamily "
+ "WHERE oid = '%u'::pg_catalog.oid",
+ opfinfo->dobj.catId.oid);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ /* Expecting a single result only */
+ ntups = PQntuples(res);
+ if (ntups != 1)
+ {
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
+ ntups, query->data);
+ exit_nicely();
+ }
+
+ i_amname = PQfnumber(res, "amname");
+
+ /* amname will still be needed after we PQclear res */
+ amname = strdup(PQgetvalue(res, 0, i_amname));
+
+ /*
+ * DROP must be fully qualified in case same name appears in pg_catalog
+ */
+ appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
+ fmtId(opfinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, ".%s",
+ fmtId(opfinfo->dobj.name));
+ appendPQExpBuffer(delq, " USING %s;\n",
+ fmtId(amname));
+
+ /* Build the fixed portion of the CREATE command */
+ appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
+ fmtId(opfinfo->dobj.name));
+ appendPQExpBuffer(q, " USING %s;\n",
+ fmtId(amname));
+
+ PQclear(res);
+
+ /* Do we need an ALTER to add loose members? */
+ if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
+ {
+ appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
+ fmtId(opfinfo->dobj.name));
+ appendPQExpBuffer(q, " USING %s ADD\n ",
+ fmtId(amname));
+
+ needComma = false;
+
+ /*
+ * Now fetch and print the OPERATOR entries (pg_amop rows).
+ */
+ ntups = PQntuples(res_ops);
+
+ i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
+ i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
+ i_amopopr = PQfnumber(res_ops, "amopopr");
+
+ for (i = 0; i < ntups; i++)
+ {
+ amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
+ amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
+ amopopr = PQgetvalue(res_ops, i, i_amopopr);
+
+ if (needComma)
+ appendPQExpBuffer(q, " ,\n ");
+
+ appendPQExpBuffer(q, "OPERATOR %s %s",
+ amopstrategy, amopopr);
+ if (strcmp(amopreqcheck, "t") == 0)
+ appendPQExpBuffer(q, " RECHECK");
+
+ needComma = true;
+ }
+
+ /*
+ * Now fetch and print the FUNCTION entries (pg_amproc rows).
+ */
+ ntups = PQntuples(res_procs);
+
+ i_amprocnum = PQfnumber(res_procs, "amprocnum");
+ i_amproc = PQfnumber(res_procs, "amproc");
+ i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
+ i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
+
+ for (i = 0; i < ntups; i++)
+ {
+ amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
+ amproc = PQgetvalue(res_procs, i, i_amproc);
+ amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
+ amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
+
+ if (needComma)
+ appendPQExpBuffer(q, " ,\n ");
+
+ appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
+ amprocnum, amproclefttype, amprocrighttype,
+ amproc);
+
+ needComma = true;
+ }
+
+ appendPQExpBuffer(q, ";\n");
+ }
+
+ ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
+ opfinfo->dobj.name,
+ opfinfo->dobj.namespace->dobj.name,
+ NULL,
+ opfinfo->rolname,
+ false, "OPERATOR FAMILY", q->data, delq->data, NULL,
+ opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
+ NULL, NULL);
+
+ /* Dump Operator Family Comments */
+ resetPQExpBuffer(q);
+ appendPQExpBuffer(q, "OPERATOR FAMILY %s",
+ fmtId(opfinfo->dobj.name));
+ appendPQExpBuffer(q, " USING %s",
+ fmtId(amname));
+ dumpComment(fout, q->data,
+ NULL, opfinfo->rolname,
+ opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
+
+ free(amname);
+ PQclear(res_ops);
+ PQclear(res_procs);
+ destroyPQExpBuffer(query);
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+}
+
+/*
+ * dumpConversion
+ * write out a single conversion definition
+ */
+static void
+dumpConversion(Archive *fout, ConvInfo *convinfo)
+{
+ PQExpBuffer query;
+ PQExpBuffer q;
+ PQExpBuffer delq;
+ PQExpBuffer details;
+ PGresult *res;
+ int ntups;
+ int i_conname;
+ int i_conforencoding;
+ int i_contoencoding;
+ int i_conproc;
+ int i_condefault;
+ const char *conname;
+ const char *conforencoding;
+ const char *contoencoding;
+ const char *conproc;
+ bool condefault;
+
+ /* Skip if not to be dumped */
+ if (!convinfo->dobj.dump || dataOnly)
+ return;
+
+ query = createPQExpBuffer();
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+ details = createPQExpBuffer();
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(convinfo->dobj.namespace->dobj.name);
+
+ /* Get conversion-specific details */
+ appendPQExpBuffer(query, "SELECT conname, "
+ "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
+ "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
+ "conproc, condefault "
+ "FROM pg_catalog.pg_conversion c "
+ "WHERE c.oid = '%u'::pg_catalog.oid",
convinfo->dobj.catId.oid);
res = PQexec(g_conn, query->data);
ntups = PQntuples(res);
if (ntups != 1)
{
- write_msg(NULL, "Got %d rows instead of one from: %s",
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
ntups, query->data);
exit_nicely();
}
appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
(condefault) ? "DEFAULT " : "",
fmtId(convinfo->dobj.name));
- appendStringLiteral(q, conforencoding, true);
+ appendStringLiteralAH(q, conforencoding, fout);
appendPQExpBuffer(q, " TO ");
- appendStringLiteral(q, contoencoding, true);
+ appendStringLiteralAH(q, contoencoding, fout);
/* regproc is automatically quoted in 7.3 and above */
appendPQExpBuffer(q, " FROM %s;\n", conproc);
format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
{
PQExpBufferData buf;
+ int j;
initPQExpBuffer(&buf);
if (honor_quotes)
else
appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
- /* If using regtype or format_type, fmtbasetype is already quoted */
- if (fout->remoteVersion >= 70100)
- {
- if (agginfo->anybasetype)
- appendPQExpBuffer(&buf, "(*)");
- else
- appendPQExpBuffer(&buf, "(%s)", agginfo->fmtbasetype);
- }
+ if (agginfo->aggfn.nargs == 0)
+ appendPQExpBuffer(&buf, "(*)");
else
{
- if (agginfo->anybasetype)
- appendPQExpBuffer(&buf, "(*)");
- else
- appendPQExpBuffer(&buf, "(%s)",
- fmtId(agginfo->fmtbasetype));
- }
+ appendPQExpBuffer(&buf, "(");
+ for (j = 0; j < agginfo->aggfn.nargs; j++)
+ {
+ char *typname;
+ typname = getFormattedTypeName(agginfo->aggfn.argtypes[j], zeroAsOpaque);
+
+ appendPQExpBuffer(&buf, "%s%s",
+ (j > 0) ? ", " : "",
+ typname);
+ free(typname);
+ }
+ appendPQExpBuffer(&buf, ")");
+ }
return buf.data;
}
int i_aggsortop;
int i_aggtranstype;
int i_agginitval;
- int i_anybasetype;
- int i_fmtbasetype;
int i_convertok;
const char *aggtransfn;
const char *aggfinalfn;
/* Make sure we are in proper schema */
selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
- /* Get aggregate-specific details */
- if (g_fout->remoteVersion >= 80100)
- {
- appendPQExpBuffer(query, "SELECT aggtransfn, "
- "aggfinalfn, aggtranstype::pg_catalog.regtype, "
- "aggsortop::pg_catalog.regoperator, "
- "agginitval, "
- "proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype as anybasetype, "
- "proargtypes[0]::pg_catalog.regtype as fmtbasetype, "
- "'t'::boolean 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 (g_fout->remoteVersion >= 70300)
- {
- appendPQExpBuffer(query, "SELECT aggtransfn, "
- "aggfinalfn, aggtranstype::pg_catalog.regtype, "
- "0 as aggsortop, "
- "agginitval, "
- "proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype as anybasetype, "
- "proargtypes[0]::pg_catalog.regtype as fmtbasetype, "
- "'t'::boolean 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 (g_fout->remoteVersion >= 70100)
- {
- appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
- "format_type(aggtranstype, NULL) as aggtranstype, "
- "0 as aggsortop, "
- "agginitval, "
- "aggbasetype = 0 as anybasetype, "
- "CASE WHEN aggbasetype = 0 THEN '-' "
- "ELSE format_type(aggbasetype, NULL) END as fmtbasetype, "
- "'t'::boolean as convertok "
- "from pg_aggregate "
- "where oid = '%u'::oid",
- agginfo->aggfn.dobj.catId.oid);
- }
- else
- {
- appendPQExpBuffer(query, "SELECT aggtransfn1 as aggtransfn, "
- "aggfinalfn, "
- "(select typname from pg_type where oid = aggtranstype1) as aggtranstype, "
- "0 as aggsortop, "
- "agginitval1 as agginitval, "
- "aggbasetype = 0 as anybasetype, "
- "(select typname from pg_type where oid = aggbasetype) as fmtbasetype, "
- "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) as convertok "
- "from pg_aggregate "
- "where oid = '%u'::oid",
- agginfo->aggfn.dobj.catId.oid);
- }
+ /* Get aggregate-specific details */
+ if (g_fout->remoteVersion >= 80100)
+ {
+ appendPQExpBuffer(query, "SELECT aggtransfn, "
+ "aggfinalfn, aggtranstype::pg_catalog.regtype, "
+ "aggsortop::pg_catalog.regoperator, "
+ "agginitval, "
+ "'t'::boolean 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 (g_fout->remoteVersion >= 70300)
+ {
+ appendPQExpBuffer(query, "SELECT aggtransfn, "
+ "aggfinalfn, aggtranstype::pg_catalog.regtype, "
+ "0 as aggsortop, "
+ "agginitval, "
+ "'t'::boolean 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 (g_fout->remoteVersion >= 70100)
+ {
+ appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
+ "format_type(aggtranstype, NULL) as aggtranstype, "
+ "0 as aggsortop, "
+ "agginitval, "
+ "'t'::boolean as convertok "
+ "from pg_aggregate "
+ "where oid = '%u'::oid",
+ agginfo->aggfn.dobj.catId.oid);
+ }
+ else
+ {
+ appendPQExpBuffer(query, "SELECT aggtransfn1 as aggtransfn, "
+ "aggfinalfn, "
+ "(select typname from pg_type where oid = aggtranstype1) as aggtranstype, "
+ "0 as aggsortop, "
+ "agginitval1 as agginitval, "
+ "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) as convertok "
+ "from pg_aggregate "
+ "where oid = '%u'::oid",
+ agginfo->aggfn.dobj.catId.oid);
+ }
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ /* Expecting a single result only */
+ ntups = PQntuples(res);
+ if (ntups != 1)
+ {
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
+ ntups, query->data);
+ exit_nicely();
+ }
+
+ i_aggtransfn = PQfnumber(res, "aggtransfn");
+ i_aggfinalfn = PQfnumber(res, "aggfinalfn");
+ i_aggsortop = PQfnumber(res, "aggsortop");
+ i_aggtranstype = PQfnumber(res, "aggtranstype");
+ i_agginitval = PQfnumber(res, "agginitval");
+ i_convertok = PQfnumber(res, "convertok");
+
+ aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
+ aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
+ aggsortop = PQgetvalue(res, 0, i_aggsortop);
+ aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
+ agginitval = PQgetvalue(res, 0, i_agginitval);
+ convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
+
+ 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);
+ return;
+ }
+
+ if (g_fout->remoteVersion >= 70300)
+ {
+ /* If using 7.3's regproc or regtype, data is already quoted */
+ appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
+ aggtransfn,
+ aggtranstype);
+ }
+ else if (g_fout->remoteVersion >= 70100)
+ {
+ /* format_type quotes, regproc does not */
+ appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
+ fmtId(aggtransfn),
+ aggtranstype);
+ }
+ else
+ {
+ /* need quotes all around */
+ appendPQExpBuffer(details, " SFUNC = %s,\n",
+ fmtId(aggtransfn));
+ appendPQExpBuffer(details, " STYPE = %s",
+ fmtId(aggtranstype));
+ }
+
+ if (!PQgetisnull(res, 0, i_agginitval))
+ {
+ appendPQExpBuffer(details, ",\n INITCOND = ");
+ appendStringLiteralAH(details, agginitval, fout);
+ }
+
+ if (strcmp(aggfinalfn, "-") != 0)
+ {
+ appendPQExpBuffer(details, ",\n FINALFUNC = %s",
+ aggfinalfn);
+ }
+
+ aggsortop = convertOperatorReference(aggsortop);
+ if (aggsortop)
+ {
+ appendPQExpBuffer(details, ",\n SORTOP = %s",
+ aggsortop);
+ }
+
+ /*
+ * DROP must be fully qualified in case same name appears in pg_catalog
+ */
+ appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
+ fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
+ aggsig);
+
+ appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
+ aggsig, details->data);
+
+ ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
+ aggsig_tag,
+ agginfo->aggfn.dobj.namespace->dobj.name,
+ NULL,
+ agginfo->aggfn.rolname,
+ false, "AGGREGATE", q->data, delq->data, NULL,
+ agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
+ NULL, NULL);
+
+ /* Dump Aggregate Comments */
+ resetPQExpBuffer(q);
+ appendPQExpBuffer(q, "AGGREGATE %s", aggsig);
+ dumpComment(fout, q->data,
+ agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
+ agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+
+ /*
+ * 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.
+ */
+ free(aggsig);
+ free(aggsig_tag);
+
+ aggsig = format_function_signature(&agginfo->aggfn, true);
+ aggsig_tag = format_function_signature(&agginfo->aggfn, false);
+
+ dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
+ "FUNCTION",
+ aggsig, aggsig_tag,
+ agginfo->aggfn.dobj.namespace->dobj.name,
+ agginfo->aggfn.rolname, agginfo->aggfn.proacl);
+
+ free(aggsig);
+ free(aggsig_tag);
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+ destroyPQExpBuffer(details);
+}
+
+/*
+ * dumpTSParser
+ * write out a single text search parser
+ */
+static void
+dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
+{
+ PQExpBuffer q;
+ PQExpBuffer delq;
+
+ /* Skip if not to be dumped */
+ if (!prsinfo->dobj.dump || dataOnly)
+ return;
+
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(prsinfo->dobj.namespace->dobj.name);
+
+ appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
+ fmtId(prsinfo->dobj.name));
+
+ appendPQExpBuffer(q, " START = %s,\n",
+ convertTSFunction(prsinfo->prsstart));
+ appendPQExpBuffer(q, " GETTOKEN = %s,\n",
+ convertTSFunction(prsinfo->prstoken));
+ appendPQExpBuffer(q, " END = %s,\n",
+ convertTSFunction(prsinfo->prsend));
+ if (prsinfo->prsheadline != InvalidOid)
+ appendPQExpBuffer(q, " HEADLINE = %s,\n",
+ convertTSFunction(prsinfo->prsheadline));
+ appendPQExpBuffer(q, " LEXTYPES = %s );\n",
+ convertTSFunction(prsinfo->prslextype));
+
+ /*
+ * DROP must be fully qualified in case same name appears in pg_catalog
+ */
+ appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
+ fmtId(prsinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, ".%s;\n",
+ fmtId(prsinfo->dobj.name));
+
+ ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
+ prsinfo->dobj.name,
+ prsinfo->dobj.namespace->dobj.name,
+ NULL,
+ "",
+ false, "TEXT SEARCH PARSER", q->data, delq->data, NULL,
+ prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
+ NULL, NULL);
+
+ /* Dump Parser Comments */
+ resetPQExpBuffer(q);
+ appendPQExpBuffer(q, "TEXT SEARCH PARSER %s",
+ fmtId(prsinfo->dobj.name));
+ dumpComment(fout, q->data,
+ NULL, "",
+ prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
+
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+}
+
+/*
+ * dumpTSDictionary
+ * write out a single text search dictionary
+ */
+static void
+dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
+{
+ PQExpBuffer q;
+ PQExpBuffer delq;
+ PQExpBuffer query;
+ PGresult *res;
+ int ntups;
+ char *nspname;
+ char *tmplname;
+
+ /* Skip if not to be dumped */
+ if (!dictinfo->dobj.dump || dataOnly)
+ return;
+
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+ query = createPQExpBuffer();
+
+ /* Fetch name and namespace of the dictionary's template */
+ selectSourceSchema("pg_catalog");
+ appendPQExpBuffer(query, "SELECT nspname, tmplname "
+ "FROM pg_ts_template p, pg_namespace n "
+ "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
+ dictinfo->dicttemplate);
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ ntups = PQntuples(res);
+ if (ntups != 1)
+ {
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
+ ntups, query->data);
+ exit_nicely();
+ }
+ nspname = PQgetvalue(res, 0, 0);
+ tmplname = PQgetvalue(res, 0, 1);
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(dictinfo->dobj.namespace->dobj.name);
+
+ appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
+ fmtId(dictinfo->dobj.name));
+
+ appendPQExpBuffer(q, " TEMPLATE = ");
+ if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
+ appendPQExpBuffer(q, "%s.", fmtId(nspname));
+ appendPQExpBuffer(q, "%s", fmtId(tmplname));
+
+ PQclear(res);
+
+ /* the dictinitoption can be dumped straight into the command */
+ if (dictinfo->dictinitoption)
+ appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
+
+ appendPQExpBuffer(q, " );\n");
+
+ /*
+ * DROP must be fully qualified in case same name appears in pg_catalog
+ */
+ appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
+ fmtId(dictinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, ".%s;\n",
+ fmtId(dictinfo->dobj.name));
+
+ ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
+ dictinfo->dobj.name,
+ dictinfo->dobj.namespace->dobj.name,
+ NULL,
+ dictinfo->rolname,
+ false, "TEXT SEARCH DICTIONARY", q->data, delq->data, NULL,
+ dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
+ NULL, NULL);
+
+ /* Dump Dictionary Comments */
+ resetPQExpBuffer(q);
+ appendPQExpBuffer(q, "TEXT SEARCH DICTIONARY %s",
+ fmtId(dictinfo->dobj.name));
+ dumpComment(fout, q->data,
+ NULL, dictinfo->rolname,
+ dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
+
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+ destroyPQExpBuffer(query);
+}
+
+/*
+ * dumpTSTemplate
+ * write out a single text search template
+ */
+static void
+dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
+{
+ PQExpBuffer q;
+ PQExpBuffer delq;
+
+ /* Skip if not to be dumped */
+ if (!tmplinfo->dobj.dump || dataOnly)
+ return;
+
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(tmplinfo->dobj.namespace->dobj.name);
+
+ appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
+ fmtId(tmplinfo->dobj.name));
+
+ if (tmplinfo->tmplinit != InvalidOid)
+ appendPQExpBuffer(q, " INIT = %s,\n",
+ convertTSFunction(tmplinfo->tmplinit));
+ appendPQExpBuffer(q, " LEXIZE = %s );\n",
+ convertTSFunction(tmplinfo->tmpllexize));
+
+ /*
+ * DROP must be fully qualified in case same name appears in pg_catalog
+ */
+ appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
+ fmtId(tmplinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, ".%s;\n",
+ fmtId(tmplinfo->dobj.name));
+
+ ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
+ tmplinfo->dobj.name,
+ tmplinfo->dobj.namespace->dobj.name,
+ NULL,
+ "",
+ false, "TEXT SEARCH TEMPLATE", q->data, delq->data, NULL,
+ tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
+ NULL, NULL);
+
+ /* Dump Template Comments */
+ resetPQExpBuffer(q);
+ appendPQExpBuffer(q, "TEXT SEARCH TEMPLATE %s",
+ fmtId(tmplinfo->dobj.name));
+ dumpComment(fout, q->data,
+ NULL, "",
+ tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
+
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+}
+
+/*
+ * dumpTSConfig
+ * write out a single text search configuration
+ */
+static void
+dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
+{
+ PQExpBuffer q;
+ PQExpBuffer delq;
+ PQExpBuffer query;
+ PGresult *res;
+ char *nspname;
+ char *prsname;
+ int ntups,
+ i;
+ int i_tokenname;
+ int i_dictname;
+
+ /* Skip if not to be dumped */
+ if (!cfginfo->dobj.dump || dataOnly)
+ return;
+
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+ query = createPQExpBuffer();
+ /* Fetch name and namespace of the config's parser */
+ selectSourceSchema("pg_catalog");
+ appendPQExpBuffer(query, "SELECT nspname, prsname "
+ "FROM pg_ts_parser p, pg_namespace n "
+ "WHERE p.oid = '%u' AND n.oid = prsnamespace",
+ cfginfo->cfgparser);
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
-
- /* Expecting a single result only */
ntups = PQntuples(res);
if (ntups != 1)
{
- write_msg(NULL, "Got %d rows instead of one from: %s",
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
ntups, query->data);
exit_nicely();
}
+ nspname = PQgetvalue(res, 0, 0);
+ prsname = PQgetvalue(res, 0, 1);
- i_aggtransfn = PQfnumber(res, "aggtransfn");
- i_aggfinalfn = PQfnumber(res, "aggfinalfn");
- i_aggsortop = PQfnumber(res, "aggsortop");
- i_aggtranstype = PQfnumber(res, "aggtranstype");
- i_agginitval = PQfnumber(res, "agginitval");
- i_anybasetype = PQfnumber(res, "anybasetype");
- i_fmtbasetype = PQfnumber(res, "fmtbasetype");
- i_convertok = PQfnumber(res, "convertok");
+ /* Make sure we are in proper schema */
+ selectSourceSchema(cfginfo->dobj.namespace->dobj.name);
- aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
- aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
- aggsortop = PQgetvalue(res, 0, i_aggsortop);
- aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
- agginitval = PQgetvalue(res, 0, i_agginitval);
- /* we save anybasetype for format_aggregate_signature */
- agginfo->anybasetype = (PQgetvalue(res, 0, i_anybasetype)[0] == 't');
- /* we save fmtbasetype for format_aggregate_signature */
- agginfo->fmtbasetype = strdup(PQgetvalue(res, 0, i_fmtbasetype));
- convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
+ appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
+ fmtId(cfginfo->dobj.name));
- aggsig = format_aggregate_signature(agginfo, fout, true);
- aggsig_tag = format_aggregate_signature(agginfo, fout, false);
+ appendPQExpBuffer(q, " PARSER = ");
+ if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
+ appendPQExpBuffer(q, "%s.", fmtId(nspname));
+ appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
- if (!convertok)
- {
- write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
- aggsig);
- return;
- }
+ PQclear(res);
- if (g_fout->remoteVersion >= 70300)
- {
- /* If using 7.3's regproc or regtype, data is already quoted */
- appendPQExpBuffer(details, " BASETYPE = %s,\n SFUNC = %s,\n STYPE = %s",
- agginfo->anybasetype ? "'any'" :
- agginfo->fmtbasetype,
- aggtransfn,
- aggtranstype);
- }
- else if (g_fout->remoteVersion >= 70100)
- {
- /* format_type quotes, regproc does not */
- appendPQExpBuffer(details, " BASETYPE = %s,\n SFUNC = %s,\n STYPE = %s",
- agginfo->anybasetype ? "'any'" :
- agginfo->fmtbasetype,
- fmtId(aggtransfn),
- aggtranstype);
- }
- else
- {
- /* need quotes all around */
- appendPQExpBuffer(details, " BASETYPE = %s,\n",
- agginfo->anybasetype ? "'any'" :
- fmtId(agginfo->fmtbasetype));
- appendPQExpBuffer(details, " SFUNC = %s,\n",
- fmtId(aggtransfn));
- appendPQExpBuffer(details, " STYPE = %s",
- fmtId(aggtranstype));
- }
+ resetPQExpBuffer(query);
+ appendPQExpBuffer(query,
+ "SELECT \n"
+ " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
+ " WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
+ " m.mapdict::pg_catalog.regdictionary AS dictname \n"
+ "FROM pg_catalog.pg_ts_config_map AS m \n"
+ "WHERE m.mapcfg = '%u' \n"
+ "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
+ cfginfo->cfgparser, cfginfo->dobj.catId.oid);
- if (!PQgetisnull(res, 0, i_agginitval))
- {
- appendPQExpBuffer(details, ",\n INITCOND = ");
- appendStringLiteral(details, agginitval, true);
- }
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ ntups = PQntuples(res);
- if (strcmp(aggfinalfn, "-") != 0)
- {
- appendPQExpBuffer(details, ",\n FINALFUNC = %s",
- aggfinalfn);
- }
+ i_tokenname = PQfnumber(res, "tokenname");
+ i_dictname = PQfnumber(res, "dictname");
- aggsortop = convertOperatorReference(aggsortop);
- if (aggsortop)
+ for (i = 0; i < ntups; i++)
{
- appendPQExpBuffer(details, ",\n SORTOP = %s",
- aggsortop);
+ char *tokenname = PQgetvalue(res, i, i_tokenname);
+ char *dictname = PQgetvalue(res, i, i_dictname);
+
+ if (i == 0 ||
+ strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
+ {
+ /* starting a new token type, so start a new command */
+ if (i > 0)
+ appendPQExpBuffer(q, ";\n");
+ appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
+ fmtId(cfginfo->dobj.name));
+ /* tokenname needs quoting, dictname does NOT */
+ appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
+ fmtId(tokenname), dictname);
+ }
+ else
+ appendPQExpBuffer(q, ", %s", dictname);
}
+ if (ntups > 0)
+ appendPQExpBuffer(q, ";\n");
+
+ PQclear(res);
+
/*
* DROP must be fully qualified in case same name appears in pg_catalog
*/
- appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
- fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
- aggsig);
-
- appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
- fmtId(agginfo->aggfn.dobj.name),
- details->data);
+ appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
+ fmtId(cfginfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, ".%s;\n",
+ fmtId(cfginfo->dobj.name));
- ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
- aggsig_tag,
- agginfo->aggfn.dobj.namespace->dobj.name,
+ ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
+ cfginfo->dobj.name,
+ cfginfo->dobj.namespace->dobj.name,
NULL,
- agginfo->aggfn.rolname,
- false, "AGGREGATE", q->data, delq->data, NULL,
- agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
+ cfginfo->rolname,
+ false, "TEXT SEARCH CONFIGURATION", q->data, delq->data, NULL,
+ cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
NULL, NULL);
- /* Dump Aggregate Comments */
+ /* Dump Configuration Comments */
resetPQExpBuffer(q);
- appendPQExpBuffer(q, "AGGREGATE %s", aggsig);
+ appendPQExpBuffer(q, "TEXT SEARCH CONFIGURATION %s",
+ fmtId(cfginfo->dobj.name));
dumpComment(fout, q->data,
- agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
- agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
-
- /*
- * 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 aggregates on ANY.
- */
- free(aggsig);
- free(aggsig_tag);
-
- aggsig = format_function_signature(&agginfo->aggfn, true);
- aggsig_tag = format_function_signature(&agginfo->aggfn, false);
-
- dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
- "FUNCTION",
- aggsig, aggsig_tag,
- agginfo->aggfn.dobj.namespace->dobj.name,
- agginfo->aggfn.rolname, agginfo->aggfn.proacl);
-
- free(aggsig);
- free(aggsig_tag);
-
- PQclear(res);
+ NULL, cfginfo->rolname,
+ cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
- destroyPQExpBuffer(query);
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
- destroyPQExpBuffer(details);
+ destroyPQExpBuffer(query);
}
{
appendPQExpBuffer(query, "SELECT definition as viewdef "
" from pg_views where viewname = ");
- appendStringLiteral(query, tbinfo->dobj.name, true);
+ appendStringLiteralAH(query, tbinfo->dobj.name, fout);
appendPQExpBuffer(query, ";");
}
/* Attribute type */
if (g_fout->remoteVersion >= 70100)
{
- char *typname = tbinfo->atttypnames[j];
-
- if (tbinfo->attisserial[j])
- {
- if (strcmp(typname, "integer") == 0)
- typname = "serial";
- else if (strcmp(typname, "bigint") == 0)
- typname = "bigserial";
- }
- appendPQExpBuffer(q, "%s", typname);
+ appendPQExpBuffer(q, "%s",
+ tbinfo->atttypnames[j]);
}
else
{
}
/*
- * Default value --- suppress if inherited, serial, or to be
- * printed separately.
+ * Default value --- suppress if inherited or to be printed
+ * separately.
*/
if (tbinfo->attrdefs[j] != NULL &&
!tbinfo->inhAttrDef[j] &&
- !tbinfo->attisserial[j] &&
!tbinfo->attrdefs[j]->separate)
appendPQExpBuffer(q, " DEFAULT %s",
tbinfo->attrdefs[j]->adef_expr);
/*
* Not Null constraint --- suppress if inherited
- *
- * Note: we could suppress this for serial columns since
- * SERIAL implies NOT NULL. We choose not to for forward
- * compatibility, since there has been some talk of making
- * SERIAL not imply NOT NULL, in which case the explicit
- * specification would be needed.
*/
if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
appendPQExpBuffer(q, " NOT NULL");
{
ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
- if (constr->coninherited || constr->separate)
+ if (constr->separate || !constr->conislocal)
continue;
if (actual_atts > 0)
appendPQExpBuffer(q, ")");
}
+ if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
+ appendPQExpBuffer(q, "\nWITH (%s)", tbinfo->reloptions);
+
appendPQExpBuffer(q, ";\n");
/* Loop dumping statistics and storage statements */
{
ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
- if (constr->coninherited || constr->separate)
+ if (constr->separate || !constr->conislocal)
continue;
dumpTableConstraintComment(fout, constr);
if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
return;
- /* Don't print inherited or serial defaults, either */
- if (tbinfo->inhAttrDef[adnum - 1] || tbinfo->attisserial[adnum - 1])
+ /* Don't print inherited defaults, either */
+ if (tbinfo->inhAttrDef[adnum - 1])
return;
q = createPQExpBuffer();
fmtId(attname));
}
- appendPQExpBuffer(q, ");\n");
+ appendPQExpBuffer(q, ")");
+
+ if (indxinfo->options && strlen(indxinfo->options) > 0)
+ appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
+
+ appendPQExpBuffer(q, ";\n");
/* If the index is clustered, we need to record that. */
if (indxinfo->indisclustered)
resetPQExpBuffer(query);
appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
- appendStringLiteral(query, dbname, true);
+ appendStringLiteralAH(query, dbname, g_fout);
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
dumpSequence(Archive *fout, TableInfo *tbinfo)
{
PGresult *res;
- char *last,
+ char *startv,
+ *last,
*incby,
*maxv = NULL,
*minv = NULL,
snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
- appendPQExpBuffer(query,
- "SELECT sequence_name, last_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 "
- "END AS max_value, "
- "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
- " 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",
- bufx, bufm,
- fmtId(tbinfo->dobj.name));
+ if (g_fout->remoteVersion >= 80400)
+ {
+ appendPQExpBuffer(query,
+ "SELECT sequence_name, "
+ "start_value, last_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 "
+ "END AS max_value, "
+ "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
+ " 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",
+ bufx, bufm,
+ fmtId(tbinfo->dobj.name));
+ }
+ else
+ {
+ appendPQExpBuffer(query,
+ "SELECT sequence_name, "
+ "0 as start_value, last_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 "
+ "END AS max_value, "
+ "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
+ " 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",
+ bufx, bufm,
+ fmtId(tbinfo->dobj.name));
+ }
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
}
#endif
- last = PQgetvalue(res, 0, 1);
- incby = PQgetvalue(res, 0, 2);
- if (!PQgetisnull(res, 0, 3))
- maxv = PQgetvalue(res, 0, 3);
+ startv = PQgetvalue(res, 0, 1);
+ last = PQgetvalue(res, 0, 2);
+ incby = PQgetvalue(res, 0, 3);
if (!PQgetisnull(res, 0, 4))
- minv = PQgetvalue(res, 0, 4);
- cache = PQgetvalue(res, 0, 5);
- cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
- called = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
+ 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);
/*
* The logic we use for restoring sequences is as follows:
*
- * Add a basic CREATE SEQUENCE statement (use last_val for start if called
- * is false, else use min_val for start_val). Skip this if the sequence
- * came from a SERIAL column.
+ * 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)' at restore-time iff we load
- * data. We do this for serial sequences too.
+ * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
*/
-
- if (!dataOnly && !OidIsValid(tbinfo->owning_tab))
+ if (!dataOnly)
{
resetPQExpBuffer(delqry);
"CREATE SEQUENCE %s\n",
fmtId(tbinfo->dobj.name));
- if (!called)
- appendPQExpBuffer(query, " START WITH %s\n", last);
+ if (g_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);
+ }
appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
false, "SEQUENCE", query->data, delqry->data, NULL,
tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
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 (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", query->data, "", NULL,
+ &(tbinfo->dobj.dumpId), 1,
+ NULL, NULL);
+ }
+ }
+
+ /* Dump Sequence Comments */
+ resetPQExpBuffer(query);
+ appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
+ dumpComment(fout, query->data,
+ tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+ tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
}
if (!schemaOnly)
{
- TableInfo *owning_tab;
-
resetPQExpBuffer(query);
appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
-
- /*
- * If this is a SERIAL sequence, then use the pg_get_serial_sequence
- * function to avoid hard-coding the sequence name. Note that this
- * implicitly assumes that the sequence and its owning table are in
- * the same schema, because we don't schema-qualify the reference.
- */
- if (OidIsValid(tbinfo->owning_tab) &&
- (owning_tab = findTableByOid(tbinfo->owning_tab)) != NULL)
- {
- appendPQExpBuffer(query, "pg_catalog.pg_get_serial_sequence(");
- appendStringLiteral(query, fmtId(owning_tab->dobj.name), true);
- appendPQExpBuffer(query, ", ");
- appendStringLiteral(query, owning_tab->attnames[tbinfo->owning_col - 1], true);
- appendPQExpBuffer(query, ")");
- }
- else
- appendStringLiteral(query, fmtId(tbinfo->dobj.name), true);
+ appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
appendPQExpBuffer(query, ", %s, %s);\n",
last, (called ? "true" : "false"));
NULL, NULL);
}
- if (!dataOnly)
- {
- /* Dump Sequence Comments */
- resetPQExpBuffer(query);
- appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
- dumpComment(fout, query->data,
- tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
- tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
- }
-
PQclear(res);
destroyPQExpBuffer(query);
else
appendPQExpBuffer(query, " UPDATE");
}
+ if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
+ {
+ if (findx > 0)
+ appendPQExpBuffer(query, " OR TRUNCATE");
+ else
+ appendPQExpBuffer(query, " TRUNCATE");
+ }
appendPQExpBuffer(query, " ON %s\n",
fmtId(tbinfo->dobj.name));
p = tginfo->tgargs;
for (findx = 0; findx < tginfo->tgnargs; findx++)
{
- const char *s = p,
- *s2 = p;
+ const char *s = p;
/* Set 'p' to end of arg string. marked by '\000' */
for (;;)
}
p--;
- while (s2 < p)
- if (*s2++ == '\\')
- {
- appendPQExpBufferChar(query, ESCAPE_STRING_SYNTAX);
- break;
- }
-
appendPQExpBufferChar(query, '\'');
while (s < p)
{
- if (*s == '\'') /* bytea already doubles backslashes */
+ if (*s == '\'')
appendPQExpBufferChar(query, '\'');
+
+ /*
+ * bytea unconditionally doubles backslashes, so we suppress the
+ * doubling for standard_conforming_strings.
+ */
+ if (fout->std_strings && *s == '\\' && s[1] == '\\')
+ s++;
appendPQExpBufferChar(query, *s++);
}
appendPQExpBufferChar(query, '\'');
}
appendPQExpBuffer(query, ");\n");
- if (!tginfo->tgenabled)
+ if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
{
appendPQExpBuffer(query, "\nALTER TABLE %s ",
fmtId(tbinfo->dobj.name));
- appendPQExpBuffer(query, "DISABLE TRIGGER %s;\n",
+ switch (tginfo->tgenabled)
+ {
+ case 'D':
+ case 'f':
+ appendPQExpBuffer(query, "DISABLE");
+ break;
+ case 'A':
+ appendPQExpBuffer(query, "ENABLE ALWAYS");
+ break;
+ case 'R':
+ appendPQExpBuffer(query, "ENABLE REPLICA");
+ break;
+ default:
+ appendPQExpBuffer(query, "ENABLE");
+ break;
+ }
+ appendPQExpBuffer(query, " TRIGGER %s;\n",
fmtId(tginfo->dobj.name));
}
if (PQntuples(res) != 1)
{
- write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
+ 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();
}
printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
/*
+ * Add the command to alter the rules replication firing semantics if it
+ * differs from the default.
+ */
+ if (rinfo->ev_enabled != 'O')
+ {
+ appendPQExpBuffer(cmd, "ALTER TABLE %s.",
+ fmtId(tbinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(cmd, "%s ",
+ fmtId(tbinfo->dobj.name));
+ switch (rinfo->ev_enabled)
+ {
+ case 'A':
+ appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
+ fmtId(rinfo->dobj.name));
+ break;
+ case 'R':
+ appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
+ fmtId(rinfo->dobj.name));
+ break;
+ case 'D':
+ appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
+ fmtId(rinfo->dobj.name));
+ break;
+ }
+ }
+
+ /*
* DROP must be fully qualified in case same name appears in pg_catalog
*/
appendPQExpBuffer(delcmd, "DROP RULE %s ",
ntups = PQntuples(res);
if (ntups != 1)
{
- write_msg(NULL, "query yielded %d rows instead of one: %s\n",
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
ntups, query->data);
exit_nicely();
}