* pg_dump is a utility for dumping out a postgres database
* into a script file.
*
- * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2006, 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.431 2006/03/02 01:18:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.447 2006/08/21 00:57:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
#include "postgres.h"
-#ifndef WIN32_CLIENT_ONLY
#include <unistd.h>
-#endif
#include <ctype.h>
#ifdef ENABLE_NLS
int optreset;
#endif
-#include "access/attnum.h"
+
+
#include "access/htup.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 "mb/pg_wchar.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 */
+/* select and exclude tables and schemas */
+typedef struct objnameArg
+{
+ struct objnameArg *next;
+ char *name; /* name of the relation */
+ bool is_include; /* include/exclude? */
+} objnameArg;
+
+objnameArg *schemaList = NULL; /* List of schemas to include/exclude */
+objnameArg *tableList = NULL; /* List of tables to include/exclude */
+
+char *matchingSchemas = NULL; /* Final list of schemas to dump by oid */
+char *matchingTables = NULL; /* Final list of tables to dump by oid */
char g_opaque_type[10]; /* name for the opaque type */
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);
int
main(int argc, char **argv)
{
+ PQExpBuffer query = createPQExpBuffer();
+ PGresult *res;
+ objnameArg *this_obj_name, *schemaList_tail = NULL, *tableList_tail = NULL;
int c;
const char *filename = NULL;
const char *format = "p";
const char *pgport = NULL;
const char *username = NULL;
const char *dumpencoding = NULL;
+ const char *std_strings;
bool oids = false;
TableInfo *tblinfo;
int numTables;
DumpableObject **dobjs;
int numObjs;
int i;
+ bool switch_include_exclude;
bool force_password = false;
int compressLevel = -1;
bool ignore_version = false;
{"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'},
}
}
- 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:uU:vWxX:Z:",
long_options, &optindex)) != -1)
{
switch (c)
ignore_version = true;
break;
- case 'n': /* Dump data for this schema only */
- selectSchemaName = strdup(optarg);
+ case 'n': /* Include schemas */
+ case 'N': /* Exclude schemas */
+ case 't': /* Include tables */
+ case 'T': /* Exclude tables */
+
+ if (strlen(optarg) < 1)
+ {
+ fprintf(stderr, _("%s: invalid -%c option\n"), progname, c);
+ exit(1);
+ }
+
+ {
+ /* Create a struct for this name */
+ objnameArg *new_obj_name = (objnameArg *)
+ malloc(sizeof(objnameArg));
+
+ new_obj_name->next = NULL;
+ new_obj_name->name = strdup(optarg);
+ new_obj_name->is_include = islower(c) ? true : false;
+
+ /* add new entry to the proper list */
+ if (tolower(c) == 'n')
+ {
+ if (!schemaList_tail)
+ schemaList_tail = schemaList = new_obj_name;
+ else
+ schemaList_tail = schemaList_tail->next = new_obj_name;
+ }
+ else
+ {
+ if (!tableList_tail)
+ tableList_tail = tableList = new_obj_name;
+ else
+ tableList_tail = tableList_tail->next = new_obj_name;
+ }
+ }
break;
case 'o': /* Dump oids */
outputSuperuser = strdup(optarg);
break;
- case 't': /* Dump data for this table only */
- selectTableName = strdup(optarg);
- break;
-
case 'u':
force_password = true;
username = simple_prompt("User name: ", 100, true);
exit(1);
}
- if (selectTableName != NULL || selectSchemaName != NULL)
+ if (matchingTables != NULL || matchingSchemas != NULL)
outputBlobs = false;
if (dumpInserts == true && oids == true)
g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
username, force_password, ignore_version);
+ /* 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);
+ /*
+ * Start serializable transaction to dump consistent data.
+ */
+ do_sql_command(g_conn, "BEGIN");
- sprintf(cmd, "SET client_encoding='%s'", dumpencoding);
- do_sql_command(g_conn, cmd);
- free(cmd);
- }
+ 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)
write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
}
+
+ if (schemaList != NULL && g_fout->remoteVersion < 70300)
+ {
+ write_msg(NULL, "Postgres must be at least version 7.3 to use schema switches\n");
+ exit_nicely();
+ }
+
+ /* Check schema selection flags */
+ resetPQExpBuffer(query);
+ switch_include_exclude = true;
+
+ for (this_obj_name = schemaList; this_obj_name; this_obj_name = this_obj_name->next)
+ {
+ if (switch_include_exclude)
+ {
+ /* Special case for when -N is the first argument */
+ if (this_obj_name == schemaList && !this_obj_name->is_include)
+ appendPQExpBuffer(query,
+ "SELECT oid FROM pg_catalog.pg_namespace "
+ "WHERE nspname NOT LIKE 'pg_%%' AND "
+ " nspname != 'information_schema' EXCEPT\n");
+
+ appendPQExpBuffer(query, "SELECT oid FROM pg_catalog.pg_namespace WHERE");
+ }
+
+ appendPQExpBuffer(query, "%s nspname %c ", switch_include_exclude ? "" : " OR",
+ /* any meta-characters? */
+ strpbrk(this_obj_name->name,"([{\\.?+") == NULL ? '=' : '~');
+ appendStringLiteralAH(query, this_obj_name->name, g_fout);
+
+ if (this_obj_name->next && this_obj_name->next->is_include == this_obj_name->is_include)
+ switch_include_exclude = false;
+ else
+ {
+ switch_include_exclude = true;
+
+ /* Add the joiner if needed */
+ if (this_obj_name->next)
+ appendPQExpBuffer(query, "\n%s\n",
+ this_obj_name->next->is_include ? "UNION" : "EXCEPT");
+ }
+ }
+
+ /* Construct OID list of matching schemas */
+ if (schemaList)
+ {
+ int len;
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ if (PQntuples(res) == 0)
+ {
+ write_msg(NULL, "No matching schemas were found\n");
+ exit_nicely();
+ }
+
+ for (i = 0, len = strlen(" "); i < PQntuples(res); i++)
+ len += strlen(PQgetvalue(res, i, 0)) + 1;
+
+ /*
+ * Need to use comma separators so it can be used by IN. zero
+ * is a dummy placeholder. Format is " oid oid oid ".
+ */
+ matchingSchemas = malloc(len + 1);
+ strcpy(matchingSchemas, " ");
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ strcat(matchingSchemas, PQgetvalue(res, i, 0));
+ strcat(matchingSchemas, " ");
+ }
+ }
+
+ /* Check table selection flags */
+ resetPQExpBuffer(query);
+ switch_include_exclude = true;
+
+ for (this_obj_name = tableList; this_obj_name; this_obj_name = this_obj_name->next)
+ {
+ if (switch_include_exclude)
+ {
+ /* Special case for when -T is the first argument */
+ if (this_obj_name == tableList && !this_obj_name->is_include && !strlen(query->data))
+ appendPQExpBuffer(query,
+ "SELECT pg_class.oid FROM pg_catalog.pg_class, pg_catalog.pg_namespace "
+ "WHERE relkind='r' AND "
+ " relnamespace = pg_namespace.oid AND "
+ " nspname NOT LIKE 'pg_%%' AND "
+ " nspname != 'information_schema' EXCEPT\n");
+
+ appendPQExpBuffer(query, "SELECT oid FROM pg_catalog.pg_class WHERE relkind='r' AND (");
+ }
+
+ appendPQExpBuffer(query, "%srelname %c ", switch_include_exclude ? "" : " OR ",
+ /* any meta-characters? */
+ strpbrk(this_obj_name->name,"([{\\.?+") == NULL ? '=' : '~');
+ appendStringLiteralAH(query, this_obj_name->name, g_fout);
+
+ if (this_obj_name->next && this_obj_name->next->is_include == this_obj_name->is_include)
+ switch_include_exclude = false;
+ else
+ {
+ switch_include_exclude = true;
+ appendPQExpBuffer(query, ")");
+
+ /* Add the joiner if needed */
+ if (this_obj_name->next)
+ appendPQExpBuffer(query, "\n%s\n", this_obj_name->next->is_include ?
+ "UNION" : "EXCEPT");
+ }
+ }
+
+ /* Construct OID list of matching tables */
+ if (tableList)
+ {
+ int len;
+
+ /* Restrict by schema? */
+ if (matchingSchemas != NULL)
+ {
+ char *matchingSchemas_commas = strdup(matchingSchemas), *p;
+
+ /* Construct "IN" SQL string by adding commas, " oid, oid, oid " */
+ for (p = matchingSchemas_commas; *p; p++)
+ {
+ /* No commas for first/last characters */
+ if (*p == ' ' && p != matchingSchemas_commas && *(p+1))
+ *p = ',';
+ }
+
+ appendPQExpBuffer(query,
+ "\nINTERSECT\nSELECT oid FROM pg_catalog.pg_class WHERE relkind='r' AND relnamespace IN (%s)\n",
+ matchingSchemas_commas);
+ }
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ if (PQntuples(res) == 0)
+ {
+ write_msg(NULL, "No matching tables were found\n");
+ exit_nicely();
+ }
+
+ for (i = 0, len = strlen(" "); i < PQntuples(res); i++)
+ len += strlen(PQgetvalue(res, i, 0)) + 1;
+
+ matchingTables = malloc(len + 1);
+ strcpy(matchingTables, " ");
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ strcat(matchingTables, PQgetvalue(res, i, 0));
+ strcat(matchingTables, " ");
+ }
+ }
+
+ destroyPQExpBuffer(query);
+
/*
* 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 (!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 (!dataOnly && matchingTables == NULL && matchingSchemas == NULL)
dumpDatabase(g_fout);
/* Now the rearrangeable objects. */
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(_(" -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(_(" -N, --exclude-schema=SCHEMA do NOT dump the named schema\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(_(" -T, --exclude-table=TABLE do NOT dump the named table\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"));
+ " disable dollar quoting, use SQL standard quoting\n"));
printf(_(" -X disable-triggers, --disable-triggers\n"
- " disable triggers during data-only restore\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"));
+ " use SESSION AUTHORIZATION commands instead of\n"
+ " OWNER TO commands\n"));
printf(_("\nConnection options:\n"));
printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
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)
- nsinfo->dobj.dump = false;
- else if (selectSchemaName != NULL)
+ nsinfo->dobj.dump = false;
+
+ if (matchingTables != NULL)
+ /* false */;
+ else if (matchingSchemas != NULL)
{
- if (strcmp(nsinfo->dobj.name, selectSchemaName) == 0)
+ char *search_oid = malloc(20);
+
+ sprintf(search_oid, " %d ", nsinfo->dobj.catId.oid);
+ if (strstr(matchingSchemas, search_oid) != NULL)
nsinfo->dobj.dump = true;
- else
- nsinfo->dobj.dump = false;
+
+ free(search_oid);
}
- else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
- strcmp(nsinfo->dobj.name, "information_schema") == 0)
- nsinfo->dobj.dump = false;
- else
+ /* The server prevents users from creating pg_ schemas */
+ else if (strncmp(nsinfo->dobj.name, "pg_", 3) != 0 &&
+ strcmp(nsinfo->dobj.name, "information_schema") != 0)
nsinfo->dobj.dump = true;
}
* dump.
*/
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 (matchingTables == NULL)
{
- /* If both -s and -t specified, must match both to dump */
- if (selectSchemaName == NULL)
+ if (tbinfo->dobj.namespace->dobj.dump)
tbinfo->dobj.dump = true;
- else if (strcmp(tbinfo->dobj.namespace->dobj.name, selectSchemaName) == 0)
+ }
+ else
+ {
+ char *search_oid = malloc(20);
+
+ sprintf(search_oid, " %d ", tbinfo->dobj.catId.oid);
+ if (strstr(matchingTables, search_oid) != NULL)
tbinfo->dobj.dump = true;
+
+ free(search_oid);
}
}
* to be dumped.
*/
-#define COPYBUFSIZ 8192
-
static int
dumpTableData_copy(Archive *fout, void *dcontext)
{
PQExpBuffer q = createPQExpBuffer();
PGresult *res;
int ret;
- bool copydone;
- char copybuf[COPYBUFSIZ];
+ char *copybuf;
const char *column_list;
if (g_verbose)
}
res = PQexec(g_conn, q->data);
check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
+ PQclear(res);
- copydone = false;
-
- while (!copydone)
+ for (;;)
{
- ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
+ ret = PQgetCopyData(g_conn, ©buf, 0);
- if (copybuf[0] == '\\' &&
- copybuf[1] == '.' &&
- copybuf[2] == '\0')
- {
- copydone = true; /* don't print this... */
- }
- else
+ if (ret < 0)
+ break; /* done or error */
+
+ if (copybuf)
{
- archputs(copybuf, fout);
- switch (ret)
- {
- case EOF:
- copydone = true;
- /* FALLTHROUGH */
- case 0:
- archputs("\n", fout);
- break;
- case 1:
- break;
- }
+ WriteData(fout, copybuf, ret);
+ PQfreemem(copybuf);
}
/*
*
* There was considerable discussion in late July, 2000 regarding
* slowing down pg_dump when backing up large tables. Users with both
- * slow & fast (muti-processor) machines experienced performance
+ * slow & fast (multi-processor) machines experienced performance
* degradation when doing a backup.
*
* Initial attempts based on sleeping for a number of ms for each ms
}
archprintf(fout, "\\.\n\n\n");
- ret = PQendcopy(g_conn);
- if (ret != 0)
+ if (ret == -2)
{
- write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed: PQendcopy() failed.\n", classname);
+ /* copy data transfer failed */
+ write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
write_msg(NULL, "The command was: %s\n", q->data);
exit_nicely();
}
+ /* Check command status and return to normal libpq state */
+ res = PQgetResult(g_conn);
+ check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
PQclear(res);
+
destroyPQExpBuffer(q);
return 1;
}
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;
}
"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",
if (comment && strlen(comment)) {
resetPQExpBuffer(dbQry);
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,
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_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, "
- "proargtypes[0] as aggbasetype, "
+ "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, "
+ "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;
+
+ if (!OidIsValid(seqinfo->owning_tab))
+ continue; /* not an owned sequence */
+ if (seqinfo->dobj.dump)
+ continue; /* no need to search */
- /* Didn't find a match */
- if (i == ntups)
+ /* 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
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')
}
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);
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(),
{
appendPQExpBuffer(q, ",\n DEFAULT = ");
if (typdefault_is_literal)
- appendStringLiteral(q, typdefault, true);
+ appendStringLiteralAH(q, typdefault, fout);
else
appendPQExpBufferStr(q, typdefault);
}
if (typdelim && strcmp(typdelim, ",") != 0)
{
appendPQExpBuffer(q, ",\n DELIMITER = ");
- appendStringLiteral(q, typdelim, true);
+ appendStringLiteralAH(q, typdelim, fout);
}
if (strcmp(typalign, "c") == 0)
{
appendPQExpBuffer(q, " DEFAULT ");
if (typdefault_is_literal)
- appendStringLiteral(q, typdefault, true);
+ appendStringLiteralAH(q, typdefault, fout);
else
appendPQExpBufferStr(q, typdefault);
}
static bool
shouldDumpProcLangs(void)
{
- if (selectTableName != NULL || selectSchemaName != NULL)
+ if (matchingTables != NULL || matchingSchemas != NULL)
return false;
/* And they're schema not data */
if (dataOnly)
if (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);
}
* Skip this cast if all objects are from pg_
*/
if ((funcInfo == NULL ||
- strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
+ strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
return;
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;
"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 "
"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 "
"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",
"(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",
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");
aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
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');
aggsig = format_aggregate_signature(agginfo, fout, true);
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,
+ appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
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,
+ appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
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",
if (!PQgetisnull(res, 0, i_agginitval))
{
appendPQExpBuffer(details, ",\n INITCOND = ");
- appendStringLiteral(details, agginitval, true);
+ appendStringLiteralAH(details, agginitval, fout);
}
if (strcmp(aggfinalfn, "-") != 0)
aggsig);
appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
- fmtId(agginfo->aggfn.dobj.name),
- details->data);
+ aggsig, details->data);
ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
aggsig_tag,
/*
* 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.
+ * syntax for zero-argument aggregates.
*/
free(aggsig);
free(aggsig_tag);
{
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
+ * 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");
appendPQExpBuffer(q, ")");
}
+ if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
+ appendPQExpBuffer(q, "\nWITH (%s)", tbinfo->reloptions);
+
appendPQExpBuffer(q, ";\n");
/* Loop dumping statistics and storage statements */
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);
/*
* 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 SET OWNED 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);
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)
+ {
+ 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);
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, '\'');