X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbin%2Fpg_dump%2Fpg_dump.c;h=c2bb6161b214811d38af43f480e5bb517d4db0c1;hb=f0fedfe82c8adea78354652d67c027a1a8fbce88;hp=e6c85ac0aedf11aa6f292e2823006144f78a64ca;hpb=3bf3ab8c563699138be02f9dc305b7b77a724307;p=postgresql diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index e6c85ac0ae..c2bb6161b2 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -4,7 +4,7 @@ * pg_dump is a utility for dumping out a postgres database * into a script file. * - * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * pg_dump will read the system catalogs in a database and dump out a @@ -14,13 +14,13 @@ * Note that pg_dump runs in a transaction-snapshot mode transaction, * so it sees a consistent snapshot of the database including system * catalogs. However, it relies in part on various specialized backend - * functions like pg_get_indexdef(), and those things tend to run on - * SnapshotNow time, ie they look at the currently committed state. So - * it is possible to get 'cache lookup failed' error if someone - * performs DDL changes while a dump is happening. The window for this - * sort of thing is from the acquisition of the transaction snapshot to - * getSchemaData() (when pg_dump acquires AccessShareLock on every - * table it intends to dump). It isn't very large, but it can happen. + * functions like pg_get_indexdef(), and those things tend to look at + * the currently committed state. So it is possible to get 'cache + * lookup failed' error if someone performs DDL changes while a dump is + * happening. The window for this sort of thing is from the acquisition + * of the transaction snapshot to getSchemaData() (when pg_dump acquires + * AccessShareLock on every table it intends to dump). It isn't very large, + * but it can happen. * * http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php * @@ -59,11 +59,9 @@ #include "pg_backup_archiver.h" #include "pg_backup_db.h" +#include "pg_backup_utils.h" #include "dumputils.h" - -extern char *optarg; -extern int optind, - opterr; +#include "parallel.h" typedef struct @@ -88,11 +86,11 @@ bool g_verbose; /* User wants verbose narration of our * activities. */ /* various user-settable parameters */ -bool schemaOnly; -bool dataOnly; -int dumpSections; /* bitmask of chosen sections */ -bool aclsSkip; -const char *lockWaitTimeout; +static bool schemaOnly; +static bool dataOnly; +static int dumpSections; /* bitmask of chosen sections */ +static bool aclsSkip; +static const char *lockWaitTimeout; /* subquery used to convert user ID (eg, datdba) to user name */ static const char *username_subquery; @@ -134,7 +132,9 @@ static int binary_upgrade = 0; static int disable_dollar_quoting = 0; static int dump_inserts = 0; static int column_inserts = 0; +static int if_exists = 0; static int no_security_labels = 0; +static int no_synchronized_snapshots = 0; static int no_unlogged_table_data = 0; static int serializable_deferrable = 0; @@ -226,7 +226,8 @@ static void getTableData(TableInfo *tblinfo, int numTables, bool oids); static void makeTableDataInfo(TableInfo *tbinfo, bool oids); static void buildMatViewRefreshDependencies(Archive *fout); static void getTableDataFKConstraints(void); -static char *format_function_arguments(FuncInfo *finfo, char *funcargs); +static char *format_function_arguments(FuncInfo *finfo, char *funcargs, + bool is_agg); static char *format_function_arguments_old(Archive *fout, FuncInfo *finfo, int nallargs, char **allargtypes, @@ -234,17 +235,15 @@ static char *format_function_arguments_old(Archive *fout, char **argnames); static char *format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes); -static const char *convertRegProcReference(Archive *fout, +static char *convertRegProcReference(Archive *fout, const char *proc); -static const char *convertOperatorReference(Archive *fout, const char *opr); +static char *convertOperatorReference(Archive *fout, const char *opr); static const char *convertTSFunction(Archive *fout, Oid funcOid); static Oid findLastBuiltinOid_V71(Archive *fout, const char *); static Oid findLastBuiltinOid_V70(Archive *fout); static void selectSourceSchema(Archive *fout, const char *schemaName); static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts); static char *myFormatType(const char *typname, int32 typmod); -static const char *fmtQualifiedId(Archive *fout, - const char *schema, const char *id); static void getBlobs(Archive *fout); static void dumpBlob(Archive *fout, BlobInfo *binfo); static int dumpBlobs(Archive *fout, void *arg); @@ -262,8 +261,10 @@ static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer, DumpableObject *dobj, const char *objlabel); static const char *getAttrName(int attrnum, TableInfo *tblInfo); -static const char *fmtCopyColumnList(const TableInfo *ti); +static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer); +static char *get_synchronized_snapshot(Archive *fout); static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query); +static void setupDumpWorker(Archive *AHX, RestoreOptions *ropt); int @@ -284,6 +285,7 @@ main(int argc, char **argv) int numObjs; DumpableObject *boundaryObjs; int i; + int numWorkers = 1; enum trivalue prompt_password = TRI_DEFAULT; int compressLevel = -1; int plainText = 0; @@ -293,7 +295,6 @@ main(int argc, char **argv) int outputNoOwner = 0; char *outputSuperuser = NULL; char *use_role = NULL; - int my_version; int optindex; RestoreOptions *ropt; ArchiveFormat archiveFormat = archUnknown; @@ -314,6 +315,7 @@ main(int argc, char **argv) {"format", required_argument, NULL, 'F'}, {"host", required_argument, NULL, 'h'}, {"ignore-version", no_argument, NULL, 'i'}, + {"jobs", 1, NULL, 'j'}, {"no-reconnect", no_argument, NULL, 'R'}, {"oids", no_argument, NULL, 'o'}, {"no-owner", no_argument, NULL, 'O'}, @@ -344,6 +346,7 @@ main(int argc, char **argv) {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1}, {"disable-triggers", no_argument, &disable_triggers, 1}, {"exclude-table-data", required_argument, NULL, 4}, + {"if-exists", no_argument, &if_exists, 1}, {"inserts", no_argument, &dump_inserts, 1}, {"lock-wait-timeout", required_argument, NULL, 2}, {"no-tablespaces", no_argument, &outputNoTablespaces, 1}, @@ -353,6 +356,7 @@ main(int argc, char **argv) {"serializable-deferrable", no_argument, &serializable_deferrable, 1}, {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, {"no-security-labels", no_argument, &no_security_labels, 1}, + {"no-synchronized-snapshots", no_argument, &no_synchronized_snapshots, 1}, {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1}, {NULL, 0, NULL, 0} @@ -360,6 +364,12 @@ main(int argc, char **argv) set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump")); + /* + * Initialize what we need for parallel execution, especially for thread + * support on Windows. + */ + init_parallel_dump_utils(); + g_verbose = false; strcpy(g_comment_start, "-- "); @@ -390,7 +400,7 @@ main(int argc, char **argv) } } - while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:iK:n:N:oOp:RsS:t:T:U:vwWxZ:", + while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:ij:n:N:oOp:RsS:t:T:U:vwWxZ:", long_options, &optindex)) != -1) { switch (c) @@ -435,6 +445,10 @@ main(int argc, char **argv) /* ignored, deprecated option */ break; + case 'j': /* number of dump jobs */ + numWorkers = atoi(optarg); + break; + case 'n': /* include schema(s) */ simple_string_list_append(&schema_include_patterns, optarg); include_everything = false; @@ -549,10 +563,16 @@ main(int argc, char **argv) dump_inserts = 1; if (dataOnly && schemaOnly) - exit_horribly(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n"); + { + write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n"); + exit_nicely(1); + } if (dataOnly && outputClean) - exit_horribly(NULL, "options -c/--clean and -a/--data-only cannot be used together\n"); + { + write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n"); + exit_nicely(1); + } if (dump_inserts && oids) { @@ -561,6 +581,9 @@ main(int argc, char **argv) exit_nicely(1); } + if (if_exists && !outputClean) + exit_horribly(NULL, "option --if-exists requires -c/--clean option\n"); + /* Identify archive format to emit */ archiveFormat = parseArchiveFormat(format, &archiveMode); @@ -577,8 +600,25 @@ main(int argc, char **argv) compressLevel = 0; } + /* + * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually) + * parallel jobs because that's the maximum limit for the + * WaitForMultipleObjects() call. + */ + if (numWorkers <= 0 +#ifdef WIN32 + || numWorkers > MAXIMUM_WAIT_OBJECTS +#endif + ) + exit_horribly(NULL, "%s: invalid number of parallel jobs\n", progname); + + /* Parallel backup only in the directory archive format so far */ + if (archiveFormat != archDirectory && numWorkers > 1) + exit_horribly(NULL, "parallel backup only supported by the directory format\n"); + /* Open the output file */ - fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode); + fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode, + setupDumpWorker); /* Register the cleanup hook */ on_exit_close_archive(fout); @@ -589,16 +629,14 @@ main(int argc, char **argv) /* Let the archiver know how noisy to be */ fout->verbose = g_verbose; - my_version = parse_version(PG_VERSION); - if (my_version < 0) - exit_horribly(NULL, "could not parse version string \"%s\"\n", PG_VERSION); - /* * We allow the server to be back to 7.0, and up to any minor release of * our own major version. (See also version check in pg_dumpall.c.) */ fout->minRemoteVersion = 70000; - fout->maxRemoteVersion = (my_version / 100) * 100 + 99; + fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99; + + fout->numWorkers = numWorkers; /* * Open the database using the Archiver, so it knows about it. Errors mean @@ -620,7 +658,8 @@ main(int argc, char **argv) */ if (fout->remoteVersion >= 90000) { - PGresult *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()"); + PGresult *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()"); + if (strcmp(PQgetvalue(res, 0, 0), "t") == 0) { /* @@ -632,32 +671,6 @@ main(int argc, char **argv) PQclear(res); } - /* - * Start transaction-snapshot mode transaction to dump consistent data. - */ - ExecuteSqlStatement(fout, "BEGIN"); - if (fout->remoteVersion >= 90100) - { - if (serializable_deferrable) - ExecuteSqlStatement(fout, - "SET TRANSACTION ISOLATION LEVEL " - "SERIALIZABLE, READ ONLY, DEFERRABLE"); - else - ExecuteSqlStatement(fout, - "SET TRANSACTION ISOLATION LEVEL " - "REPEATABLE READ, READ ONLY"); - } - else if (fout->remoteVersion >= 70400) - { - /* note: comma was not accepted in SET TRANSACTION before 8.0 */ - ExecuteSqlStatement(fout, - "SET TRANSACTION ISOLATION LEVEL " - "SERIALIZABLE READ ONLY"); - } - else - ExecuteSqlStatement(fout, - "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"); - /* Select the appropriate subquery to convert user IDs to names */ if (fout->remoteVersion >= 80100) username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid ="; @@ -666,6 +679,14 @@ main(int argc, char **argv) else username_subquery = "SELECT usename FROM pg_user WHERE usesysid ="; + /* check the version for the synchronized snapshots feature */ + if (numWorkers > 1 && fout->remoteVersion < 90200 + && !no_synchronized_snapshots) + exit_horribly(NULL, + "Synchronized snapshots are not supported by this server version.\n" + "Run with --no-synchronized-snapshots instead if you do not need\n" + "synchronized snapshots.\n"); + /* Find the last built-in OID, if needed */ if (fout->remoteVersion < 70300) { @@ -763,6 +784,10 @@ main(int argc, char **argv) else sortDumpableObjectsByTypeOid(dobjs, numObjs); + /* If we do a parallel dump, we want the largest tables to go first */ + if (archiveFormat == archDirectory && numWorkers > 1) + sortDataAndIndexObjectsBySize(dobjs, numObjs); + sortDumpableObjects(dobjs, numObjs, boundaryObjs[0].dumpId, boundaryObjs[1].dumpId); @@ -791,6 +816,7 @@ main(int argc, char **argv) ropt->dropSchema = outputClean; ropt->dataOnly = dataOnly; ropt->schemaOnly = schemaOnly; + ropt->if_exists = if_exists; ropt->dumpSections = dumpSections; ropt->aclsSkip = aclsSkip; ropt->superuser = outputSuperuser; @@ -810,9 +836,9 @@ main(int argc, char **argv) SetArchiveRestoreOptions(fout, ropt); /* - * The archive's TOC entries are now marked as to which ones will - * actually be output, so we can set up their dependency lists properly. - * This isn't necessary for plain-text output, though. + * The archive's TOC entries are now marked as to which ones will actually + * be output, so we can set up their dependency lists properly. This isn't + * necessary for plain-text output, though. */ if (!plainText) BuildArchiveDependencies(fout); @@ -844,6 +870,7 @@ help(const char *progname) printf(_(" -f, --file=FILENAME output file or directory name\n")); printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n" " plain text (default))\n")); + printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n")); printf(_(" -v, --verbose verbose mode\n")); printf(_(" -V, --version output version information, then exit\n")); printf(_(" -Z, --compress=0-9 compression level for compressed formats\n")); @@ -871,8 +898,10 @@ help(const char *progname) printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n")); printf(_(" --disable-triggers disable triggers during data-only restore\n")); printf(_(" --exclude-table-data=TABLE do NOT dump data for the named table(s)\n")); + printf(_(" --if-exists use IF EXISTS when dropping objects\n")); printf(_(" --inserts dump data as INSERT commands, rather than COPY\n")); printf(_(" --no-security-labels do not dump security label assignments\n")); + printf(_(" --no-synchronized-snapshots do not use synchronized snapshots in parallel jobs\n")); printf(_(" --no-tablespaces do not dump tablespace assignments\n")); printf(_(" --no-unlogged-table-data do not dump unlogged table data\n")); printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n")); @@ -902,7 +931,12 @@ setup_connection(Archive *AH, const char *dumpencoding, char *use_role) PGconn *conn = GetConnection(AH); const char *std_strings; - /* Set the client encoding if requested */ + /* + * Set the client encoding if requested. If dumpencoding == NULL then + * either it hasn't been requested or we're a cloned connection and then + * this has already been set in CloneArchive according to the original + * connection encoding. + */ if (dumpencoding) { if (PQsetClientEncoding(conn, dumpencoding) < 0) @@ -919,6 +953,10 @@ setup_connection(Archive *AH, const char *dumpencoding, char *use_role) std_strings = PQparameterStatus(conn, "standard_conforming_strings"); AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0); + /* Set the role if requested */ + if (!use_role && AH->use_role) + use_role = AH->use_role; + /* Set the role if requested */ if (use_role && AH->remoteVersion >= 80100) { @@ -927,6 +965,10 @@ setup_connection(Archive *AH, const char *dumpencoding, char *use_role) appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role)); ExecuteSqlStatement(AH, query->data); destroyPQExpBuffer(query); + + /* save this for later use on parallel connections */ + if (!AH->use_role) + AH->use_role = strdup(use_role); } /* Set the datestyle to ISO to ensure the dump's portability */ @@ -957,12 +999,77 @@ setup_connection(Archive *AH, const char *dumpencoding, char *use_role) */ if (AH->remoteVersion >= 70300) ExecuteSqlStatement(AH, "SET statement_timeout = 0"); + if (AH->remoteVersion >= 90300) + ExecuteSqlStatement(AH, "SET lock_timeout = 0"); /* * Quote all identifiers, if requested. */ if (quote_all_identifiers && AH->remoteVersion >= 90100) ExecuteSqlStatement(AH, "SET quote_all_identifiers = true"); + + /* + * Start transaction-snapshot mode transaction to dump consistent data. + */ + ExecuteSqlStatement(AH, "BEGIN"); + if (AH->remoteVersion >= 90100) + { + if (serializable_deferrable) + ExecuteSqlStatement(AH, + "SET TRANSACTION ISOLATION LEVEL " + "SERIALIZABLE, READ ONLY, DEFERRABLE"); + else + ExecuteSqlStatement(AH, + "SET TRANSACTION ISOLATION LEVEL " + "REPEATABLE READ, READ ONLY"); + } + else if (AH->remoteVersion >= 70400) + { + /* note: comma was not accepted in SET TRANSACTION before 8.0 */ + ExecuteSqlStatement(AH, + "SET TRANSACTION ISOLATION LEVEL " + "SERIALIZABLE READ ONLY"); + } + else + ExecuteSqlStatement(AH, + "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"); + + + + if (AH->numWorkers > 1 && AH->remoteVersion >= 90200 && !no_synchronized_snapshots) + { + if (AH->sync_snapshot_id) + { + PQExpBuffer query = createPQExpBuffer(); + + appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT "); + appendStringLiteralConn(query, AH->sync_snapshot_id, conn); + ExecuteSqlStatement(AH, query->data); + destroyPQExpBuffer(query); + } + else + AH->sync_snapshot_id = get_synchronized_snapshot(AH); + } +} + +static void +setupDumpWorker(Archive *AHX, RestoreOptions *ropt) +{ + setup_connection(AHX, NULL, NULL); +} + +static char * +get_synchronized_snapshot(Archive *fout) +{ + char *query = "SELECT pg_export_snapshot()"; + char *result; + PGresult *res; + + res = ExecuteSqlQueryForSingleRow(fout, query); + result = strdup(PQgetvalue(res, 0, 0)); + PQclear(res); + + return result; } static ArchiveFormat @@ -1029,7 +1136,7 @@ expand_schema_name_patterns(Archive *fout, for (cell = patterns->head; cell; cell = cell->next) { if (cell != patterns->head) - appendPQExpBuffer(query, "UNION ALL\n"); + appendPQExpBufferStr(query, "UNION ALL\n"); appendPQExpBuffer(query, "SELECT oid FROM pg_catalog.pg_namespace n\n"); processSQLNamePattern(GetConnection(fout), query, cell->val, false, @@ -1073,12 +1180,12 @@ expand_table_name_patterns(Archive *fout, for (cell = patterns->head; cell; cell = cell->next) { if (cell != patterns->head) - appendPQExpBuffer(query, "UNION ALL\n"); + appendPQExpBufferStr(query, "UNION ALL\n"); appendPQExpBuffer(query, "SELECT c.oid" "\nFROM pg_catalog.pg_class c" "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace" - "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n", + "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n", RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE); processSQLNamePattern(GetConnection(fout), query, cell->val, true, @@ -1280,6 +1387,12 @@ dumpTableData_copy(Archive *fout, void *dcontext) const bool hasoids = tbinfo->hasoids; const bool oids = tdinfo->oids; PQExpBuffer q = createPQExpBuffer(); + + /* + * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId + * which uses it already. + */ + PQExpBuffer clistBuf = createPQExpBuffer(); PGconn *conn = GetConnection(fout); PGresult *res; int ret; @@ -1304,14 +1417,14 @@ dumpTableData_copy(Archive *fout, void *dcontext) * cases involving ADD COLUMN and inheritance.) */ if (fout->remoteVersion >= 70300) - column_list = fmtCopyColumnList(tbinfo); + column_list = fmtCopyColumnList(tbinfo, clistBuf); else column_list = ""; /* can't select columns in COPY */ if (oids && hasoids) { appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;", - fmtQualifiedId(fout, + fmtQualifiedId(fout->remoteVersion, tbinfo->dobj.namespace->dobj.name, classname), column_list); @@ -1329,7 +1442,7 @@ dumpTableData_copy(Archive *fout, void *dcontext) else appendPQExpBufferStr(q, "* "); appendPQExpBuffer(q, "FROM %s %s) TO stdout;", - fmtQualifiedId(fout, + fmtQualifiedId(fout->remoteVersion, tbinfo->dobj.namespace->dobj.name, classname), tdinfo->filtercond); @@ -1337,13 +1450,14 @@ dumpTableData_copy(Archive *fout, void *dcontext) else { appendPQExpBuffer(q, "COPY %s %s TO stdout;", - fmtQualifiedId(fout, + fmtQualifiedId(fout->remoteVersion, tbinfo->dobj.namespace->dobj.name, classname), column_list); } res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT); PQclear(res); + destroyPQExpBuffer(clistBuf); for (;;) { @@ -1445,6 +1559,7 @@ dumpTableData_insert(Archive *fout, void *dcontext) TableInfo *tbinfo = tdinfo->tdtable; const char *classname = tbinfo->dobj.name; PQExpBuffer q = createPQExpBuffer(); + PQExpBuffer insertStmt = NULL; PGresult *res; int tuple; int nfields; @@ -1462,7 +1577,7 @@ dumpTableData_insert(Archive *fout, void *dcontext) { appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " "SELECT * FROM ONLY %s", - fmtQualifiedId(fout, + fmtQualifiedId(fout->remoteVersion, tbinfo->dobj.namespace->dobj.name, classname)); } @@ -1470,7 +1585,7 @@ dumpTableData_insert(Archive *fout, void *dcontext) { appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " "SELECT * FROM %s", - fmtQualifiedId(fout, + fmtQualifiedId(fout->remoteVersion, tbinfo->dobj.namespace->dobj.name, classname)); } @@ -1486,34 +1601,57 @@ dumpTableData_insert(Archive *fout, void *dcontext) nfields = PQnfields(res); for (tuple = 0; tuple < PQntuples(res); tuple++) { - archprintf(fout, "INSERT INTO %s ", fmtId(classname)); - if (nfields == 0) + /* + * First time through, we build as much of the INSERT statement as + * possible in "insertStmt", which we can then just print for each + * line. If the table happens to have zero columns then this will + * be a complete statement, otherwise it will end in "VALUES(" and + * be ready to have the row's column values appended. + */ + if (insertStmt == NULL) { + insertStmt = createPQExpBuffer(); + appendPQExpBuffer(insertStmt, "INSERT INTO %s ", + fmtId(classname)); + /* corner case for zero-column table */ - archprintf(fout, "DEFAULT VALUES;\n"); - continue; - } - if (column_inserts) - { - resetPQExpBuffer(q); - appendPQExpBuffer(q, "("); - for (field = 0; field < nfields; field++) + if (nfields == 0) { - if (field > 0) - appendPQExpBuffer(q, ", "); - appendPQExpBufferStr(q, fmtId(PQfname(res, field))); + appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n"); + } + else + { + /* append the list of column names if required */ + if (column_inserts) + { + appendPQExpBufferStr(insertStmt, "("); + for (field = 0; field < nfields; field++) + { + if (field > 0) + appendPQExpBufferStr(insertStmt, ", "); + appendPQExpBufferStr(insertStmt, + fmtId(PQfname(res, field))); + } + appendPQExpBufferStr(insertStmt, ") "); + } + + appendPQExpBufferStr(insertStmt, "VALUES ("); } - appendPQExpBuffer(q, ") "); - archputs(q->data, fout); } - archprintf(fout, "VALUES ("); + + archputs(insertStmt->data, fout); + + /* if it is zero-column table then we're done */ + if (nfields == 0) + continue; + for (field = 0; field < nfields; field++) { if (field > 0) - archprintf(fout, ", "); + archputs(", ", fout); if (PQgetisnull(res, tuple, field)) { - archprintf(fout, "NULL"); + archputs("NULL", fout); continue; } @@ -1542,7 +1680,7 @@ dumpTableData_insert(Archive *fout, void *dcontext) const char *s = PQgetvalue(res, tuple, field); if (strspn(s, "0123456789 +-eE.") == strlen(s)) - archprintf(fout, "%s", s); + archputs(s, fout); else archprintf(fout, "'%s'", s); } @@ -1556,9 +1694,9 @@ dumpTableData_insert(Archive *fout, void *dcontext) case BOOLOID: if (strcmp(PQgetvalue(res, tuple, field), "t") == 0) - archprintf(fout, "true"); + archputs("true", fout); else - archprintf(fout, "false"); + archputs("false", fout); break; default: @@ -1571,7 +1709,7 @@ dumpTableData_insert(Archive *fout, void *dcontext) break; } } - archprintf(fout, ");\n"); + archputs(");\n", fout); } if (PQntuples(res) <= 0) @@ -1582,11 +1720,14 @@ dumpTableData_insert(Archive *fout, void *dcontext) PQclear(res); } - archprintf(fout, "\n\n"); + archputs("\n\n", fout); ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor"); destroyPQExpBuffer(q); + if (insertStmt != NULL) + destroyPQExpBuffer(insertStmt); + return 1; } @@ -1602,6 +1743,7 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo) { TableInfo *tbinfo = tdinfo->tdtable; PQExpBuffer copyBuf = createPQExpBuffer(); + PQExpBuffer clistBuf = createPQExpBuffer(); DataDumperPtr dumpFn; char *copyStmt; @@ -1613,7 +1755,7 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo) appendPQExpBuffer(copyBuf, "COPY %s ", fmtId(tbinfo->dobj.name)); appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n", - fmtCopyColumnList(tbinfo), + fmtCopyColumnList(tbinfo, clistBuf), (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : ""); copyStmt = copyBuf->data; } @@ -1638,6 +1780,7 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo) dumpFn, tdinfo); destroyPQExpBuffer(copyBuf); + destroyPQExpBuffer(clistBuf); } /* @@ -1653,8 +1796,8 @@ refreshMatViewData(Archive *fout, TableDataInfo *tdinfo) TableInfo *tbinfo = tdinfo->tdtable; PQExpBuffer q; - /* If the materialized view is not flagged as scannable, skip this. */ - if (!tbinfo->isscannable) + /* If the materialized view is not flagged as populated, skip this. */ + if (!tbinfo->relispopulated) return; q = createPQExpBuffer(); @@ -1663,22 +1806,22 @@ refreshMatViewData(Archive *fout, TableDataInfo *tdinfo) fmtId(tbinfo->dobj.name)); ArchiveEntry(fout, - tdinfo->dobj.catId, /* catalog ID */ - tdinfo->dobj.dumpId, /* dump ID */ - tbinfo->dobj.name, /* Name */ - tbinfo->dobj.namespace->dobj.name, /* Namespace */ - NULL, /* Tablespace */ - tbinfo->rolname, /* Owner */ - false, /* with oids */ - "MATERIALIZED VIEW DATA", /* Desc */ - SECTION_POST_DATA, /* Section */ - q->data, /* Create */ - "", /* Del */ - NULL, /* Copy */ - tdinfo->dobj.dependencies, /* Deps */ - tdinfo->dobj.nDeps, /* # Deps */ - NULL, /* Dumper */ - NULL); /* Dumper Arg */ + tdinfo->dobj.catId, /* catalog ID */ + tdinfo->dobj.dumpId, /* dump ID */ + tbinfo->dobj.name, /* Name */ + tbinfo->dobj.namespace->dobj.name, /* Namespace */ + NULL, /* Tablespace */ + tbinfo->rolname, /* Owner */ + false, /* with oids */ + "MATERIALIZED VIEW DATA", /* Desc */ + SECTION_POST_DATA, /* Section */ + q->data, /* Create */ + "", /* Del */ + NULL, /* Copy */ + tdinfo->dobj.dependencies, /* Deps */ + tdinfo->dobj.nDeps, /* # Deps */ + NULL, /* Dumper */ + NULL); /* Dumper Arg */ destroyPQExpBuffer(q); } @@ -1769,7 +1912,7 @@ makeTableDataInfo(TableInfo *tbinfo, bool oids) static void buildMatViewRefreshDependencies(Archive *fout) { - PQExpBuffer query = createPQExpBuffer(); + PQExpBuffer query; PGresult *res; int ntups, i; @@ -1777,38 +1920,41 @@ buildMatViewRefreshDependencies(Archive *fout) i_objid, i_refobjid; + /* No Mat Views before 9.3. */ + if (fout->remoteVersion < 90300) + return; + /* Make sure we are in proper schema */ selectSourceSchema(fout, "pg_catalog"); - if (fout->remoteVersion >= 90300) - { - appendPQExpBuffer(query, "with recursive w as " - "( " - "select d1.objid, d2.refobjid, c2.relkind as refrelkind " - "from pg_depend d1 " - "join pg_class c1 on c1.oid = d1.objid " - "and c1.relkind = 'm' " - "join pg_rewrite r1 on r1.ev_class = d1.objid " - "join pg_depend d2 on d2.classid = 'pg_rewrite'::regclass " - "and d2.objid = r1.oid " - "and d2.refobjid <> d1.objid " - "join pg_class c2 on c2.oid = d2.refobjid " - "and c2.relkind in ('m','v') " - "where d1.classid = 'pg_class'::regclass " - "union " - "select w.objid, d3.refobjid, c3.relkind " - "from w " - "join pg_rewrite r3 on r3.ev_class = w.refobjid " - "join pg_depend d3 on d3.classid = 'pg_rewrite'::regclass " - "and d3.objid = r3.oid " - "and d3.refobjid <> w.refobjid " - "join pg_class c3 on c3.oid = d3.refobjid " - "and c3.relkind in ('m','v') " - ") " - "select 'pg_class'::regclass::oid as classid, objid, refobjid " - "from w " - "where refrelkind = 'm'"); - } + query = createPQExpBuffer(); + + appendPQExpBufferStr(query, "WITH RECURSIVE w AS " + "( " + "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind " + "FROM pg_depend d1 " + "JOIN pg_class c1 ON c1.oid = d1.objid " + "AND c1.relkind = 'm' " + "JOIN pg_rewrite r1 ON r1.ev_class = d1.objid " + "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass " + "AND d2.objid = r1.oid " + "AND d2.refobjid <> d1.objid " + "JOIN pg_class c2 ON c2.oid = d2.refobjid " + "AND c2.relkind IN ('m','v') " + "WHERE d1.classid = 'pg_class'::regclass " + "UNION " + "SELECT w.objid, d3.refobjid, c3.relkind " + "FROM w " + "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid " + "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass " + "AND d3.objid = r3.oid " + "AND d3.refobjid <> w.refobjid " + "JOIN pg_class c3 ON c3.oid = d3.refobjid " + "AND c3.relkind IN ('m','v') " + ") " + "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid " + "FROM w " + "WHERE refrelkind = 'm'"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -1822,10 +1968,10 @@ buildMatViewRefreshDependencies(Archive *fout) { CatalogId objId; CatalogId refobjId; - DumpableObject *dobj; - DumpableObject *refdobj; - TableInfo *tbinfo; - TableInfo *reftbinfo; + DumpableObject *dobj; + DumpableObject *refdobj; + TableInfo *tbinfo; + TableInfo *reftbinfo; objId.tableoid = atooid(PQgetvalue(res, i, i_classid)); objId.oid = atooid(PQgetvalue(res, i, i_objid)); @@ -1858,8 +2004,8 @@ buildMatViewRefreshDependencies(Archive *fout) addObjectDependency(dobj, refdobj->dumpId); - if (!reftbinfo->isscannable) - tbinfo->isscannable = false; + if (!reftbinfo->relispopulated) + tbinfo->relispopulated = false; } PQclear(res); @@ -2123,33 +2269,33 @@ dumpDatabase(Archive *fout) fmtId(datname)); if (strlen(encoding) > 0) { - appendPQExpBuffer(creaQry, " ENCODING = "); + appendPQExpBufferStr(creaQry, " ENCODING = "); appendStringLiteralAH(creaQry, encoding, fout); } if (strlen(collate) > 0) { - appendPQExpBuffer(creaQry, " LC_COLLATE = "); + appendPQExpBufferStr(creaQry, " LC_COLLATE = "); appendStringLiteralAH(creaQry, collate, fout); } if (strlen(ctype) > 0) { - appendPQExpBuffer(creaQry, " LC_CTYPE = "); + appendPQExpBufferStr(creaQry, " LC_CTYPE = "); appendStringLiteralAH(creaQry, ctype, fout); } if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0) appendPQExpBuffer(creaQry, " TABLESPACE = %s", fmtId(tablespace)); - appendPQExpBuffer(creaQry, ";\n"); + appendPQExpBufferStr(creaQry, ";\n"); if (binary_upgrade) { - appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n"); + appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n"); appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n" "SET datfrozenxid = '%u'\n" "WHERE datname = ", frozenxid); appendStringLiteralAH(creaQry, datname, fout); - appendPQExpBuffer(creaQry, ";\n"); + appendPQExpBufferStr(creaQry, ";\n"); } @@ -2199,7 +2345,7 @@ dumpDatabase(Archive *fout) i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid"); - appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n"); + appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n"); appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n" "SET relfrozenxid = '%u'\n" "WHERE oid = %u;\n", @@ -2231,7 +2377,7 @@ dumpDatabase(Archive *fout) i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid"); - appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n"); + appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n"); appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n" "SET relfrozenxid = '%u'\n" "WHERE oid = %u;\n", @@ -2270,7 +2416,7 @@ dumpDatabase(Archive *fout) */ appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname)); appendStringLiteralAH(dbQry, comment, fout); - appendPQExpBuffer(dbQry, ";\n"); + appendPQExpBufferStr(dbQry, ";\n"); ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL, dba, false, "COMMENT", SECTION_NONE, @@ -2323,9 +2469,9 @@ dumpEncoding(Archive *AH) if (g_verbose) write_msg(NULL, "saving encoding = %s\n", encname); - appendPQExpBuffer(qry, "SET client_encoding = "); + appendPQExpBufferStr(qry, "SET client_encoding = "); appendStringLiteralAH(qry, encname, AH); - appendPQExpBuffer(qry, ";\n"); + appendPQExpBufferStr(qry, ";\n"); ArchiveEntry(AH, nilCatalogId, createDumpId(), "ENCODING", NULL, NULL, "", @@ -2393,13 +2539,13 @@ getBlobs(Archive *fout) " FROM pg_largeobject_metadata", username_subquery); else if (fout->remoteVersion >= 70100) - appendPQExpBuffer(blobQry, - "SELECT DISTINCT loid, NULL::oid, NULL::oid" - " FROM pg_largeobject"); + appendPQExpBufferStr(blobQry, + "SELECT DISTINCT loid, NULL::oid, NULL::oid" + " FROM pg_largeobject"); else - appendPQExpBuffer(blobQry, - "SELECT oid, NULL::oid, NULL::oid" - " FROM pg_class WHERE relkind = 'l'"); + appendPQExpBufferStr(blobQry, + "SELECT oid, NULL::oid, NULL::oid" + " FROM pg_class WHERE relkind = 'l'"); res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK); @@ -2586,7 +2732,7 @@ binary_upgrade_set_type_oids_by_type_oid(Archive *fout, PGresult *upgrade_res; Oid pg_type_array_oid; - appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n"); + appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n"); appendPQExpBuffer(upgrade_buffer, "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n", pg_type_oid); @@ -2604,7 +2750,7 @@ binary_upgrade_set_type_oids_by_type_oid(Archive *fout, if (OidIsValid(pg_type_array_oid)) { - appendPQExpBuffer(upgrade_buffer, + appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type array oid\n"); appendPQExpBuffer(upgrade_buffer, "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n", @@ -2647,7 +2793,7 @@ binary_upgrade_set_type_oids_by_rel_oid(Archive *fout, Oid pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "trel"))); - appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n"); + appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n"); appendPQExpBuffer(upgrade_buffer, "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n", pg_type_toast_oid); @@ -2669,22 +2815,22 @@ binary_upgrade_set_pg_class_oids(Archive *fout, PQExpBuffer upgrade_query = createPQExpBuffer(); PGresult *upgrade_res; Oid pg_class_reltoastrelid; - Oid pg_class_reltoastidxid; + Oid pg_index_indexrelid; appendPQExpBuffer(upgrade_query, - "SELECT c.reltoastrelid, t.reltoastidxid " + "SELECT c.reltoastrelid, i.indexrelid " "FROM pg_catalog.pg_class c LEFT JOIN " - "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) " + "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) " "WHERE c.oid = '%u'::pg_catalog.oid;", pg_class_oid); upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid"))); - pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid"))); + pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid"))); - appendPQExpBuffer(upgrade_buffer, - "\n-- For binary upgrade, must preserve pg_class oids\n"); + appendPQExpBufferStr(upgrade_buffer, + "\n-- For binary upgrade, must preserve pg_class oids\n"); if (!is_index) { @@ -2710,7 +2856,7 @@ binary_upgrade_set_pg_class_oids(Archive *fout, /* every toast table has an index */ appendPQExpBuffer(upgrade_buffer, "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n", - pg_class_reltoastidxid); + pg_index_indexrelid); } } else @@ -2718,7 +2864,7 @@ binary_upgrade_set_pg_class_oids(Archive *fout, "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n", pg_class_oid); - appendPQExpBuffer(upgrade_buffer, "\n"); + appendPQExpBufferChar(upgrade_buffer, '\n'); PQclear(upgrade_res); destroyPQExpBuffer(upgrade_query); @@ -2755,7 +2901,7 @@ binary_upgrade_extension_member(PQExpBuffer upgrade_buffer, if (extobj == NULL) exit_horribly(NULL, "could not find parent extension for %s\n", objlabel); - appendPQExpBuffer(upgrade_buffer, + appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, handle extension membership the hard way\n"); appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n", fmtId(extobj->name), @@ -2942,10 +3088,10 @@ getExtensions(Archive *fout, int *numExtensions) /* Make sure we are in proper schema */ selectSourceSchema(fout, "pg_catalog"); - appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, " - "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition " - "FROM pg_extension x " - "JOIN pg_namespace n ON n.oid = x.extnamespace"); + appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, " + "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition " + "FROM pg_extension x " + "JOIN pg_namespace n ON n.oid = x.extnamespace"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -3465,7 +3611,7 @@ getConversions(Archive *fout, int *numConversions) PGresult *res; int ntups; int i; - PQExpBuffer query = createPQExpBuffer(); + PQExpBuffer query; ConvInfo *convinfo; int i_tableoid; int i_oid; @@ -3480,6 +3626,8 @@ getConversions(Archive *fout, int *numConversions) return NULL; } + query = createPQExpBuffer(); + /* * find all conversions, including builtin conversions; we filter out * system-defined conversions at dump-out time. @@ -3570,19 +3718,19 @@ getOpclasses(Archive *fout, int *numOpclasses) } else if (fout->remoteVersion >= 70100) { - appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, " - "0::oid AS opcnamespace, " - "''::name AS rolname " - "FROM pg_opclass"); + appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, " + "0::oid AS opcnamespace, " + "''::name AS rolname " + "FROM pg_opclass"); } else { - appendPQExpBuffer(query, "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, " - "oid, opcname, " - "0::oid AS opcnamespace, " - "''::name AS rolname " - "FROM pg_opclass"); + appendPQExpBufferStr(query, "SELECT " + "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, " + "oid, opcname, " + "0::oid AS opcnamespace, " + "''::name AS rolname " + "FROM pg_opclass"); } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -3755,7 +3903,7 @@ getAggregates(Archive *fout, int *numAggs) appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, " "pronamespace AS aggnamespace, " "pronargs, proargtypes, " - "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs," + "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs," "(%s proowner) AS rolname, " "proacl AS aggacl " "FROM pg_proc p " @@ -3765,13 +3913,13 @@ getAggregates(Archive *fout, int *numAggs) "WHERE nspname = 'pg_catalog')", username_subquery); if (binary_upgrade && fout->remoteVersion >= 90100) - appendPQExpBuffer(query, - " OR EXISTS(SELECT 1 FROM pg_depend WHERE " - "classid = 'pg_proc'::regclass AND " - "objid = p.oid AND " - "refclassid = 'pg_extension'::regclass AND " - "deptype = 'e')"); - appendPQExpBuffer(query, ")"); + appendPQExpBufferStr(query, + " OR EXISTS(SELECT 1 FROM pg_depend WHERE " + "classid = 'pg_proc'::regclass AND " + "objid = p.oid AND " + "refclassid = 'pg_extension'::regclass AND " + "deptype = 'e')"); + appendPQExpBufferChar(query, ')'); } else if (fout->remoteVersion >= 80200) { @@ -3948,7 +4096,7 @@ getFuncs(Archive *fout, int *numFuncs) "SELECT tableoid, oid, proname, prolang, " "pronargs, proargtypes, prorettype, proacl, " "pronamespace, " - "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs," + "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs," "(%s proowner) AS rolname " "FROM pg_proc p " "WHERE NOT proisagg AND (" @@ -3957,18 +4105,18 @@ getFuncs(Archive *fout, int *numFuncs) "WHERE nspname = 'pg_catalog')", username_subquery); if (fout->remoteVersion >= 90200) - appendPQExpBuffer(query, - "\n AND NOT EXISTS (SELECT 1 FROM pg_depend " - "WHERE classid = 'pg_proc'::regclass AND " - "objid = p.oid AND deptype = 'i')"); + appendPQExpBufferStr(query, + "\n AND NOT EXISTS (SELECT 1 FROM pg_depend " + "WHERE classid = 'pg_proc'::regclass AND " + "objid = p.oid AND deptype = 'i')"); if (binary_upgrade && fout->remoteVersion >= 90100) - appendPQExpBuffer(query, - "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE " - "classid = 'pg_proc'::regclass AND " - "objid = p.oid AND " - "refclassid = 'pg_extension'::regclass AND " - "deptype = 'e')"); - appendPQExpBuffer(query, ")"); + appendPQExpBufferStr(query, + "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE " + "classid = 'pg_proc'::regclass AND " + "objid = p.oid AND " + "refclassid = 'pg_extension'::regclass AND " + "deptype = 'e')"); + appendPQExpBufferChar(query, ')'); } else if (fout->remoteVersion >= 70300) { @@ -4110,13 +4258,16 @@ getTables(Archive *fout, int *numTables) int i_toastoid; int i_toastfrozenxid; int i_relpersistence; - int i_isscannable; + int i_relispopulated; + int i_relreplident; int i_owning_tab; int i_owning_col; int i_reltablespace; int i_reloptions; + int i_checkoption; int i_toastreloptions; int i_reloftype; + int i_relpages; /* Make sure we are in proper schema */ selectSourceSchema(fout, "pg_catalog"); @@ -4141,7 +4292,7 @@ getTables(Archive *fout, int *numTables) * we cannot correctly identify inherited columns, owned sequences, etc. */ - if (fout->remoteVersion >= 90100) + if (fout->remoteVersion >= 90400) { /* * Left join to pick up dependency info linking sequences to their @@ -4155,7 +4306,86 @@ getTables(Archive *fout, int *numTables) "c.relhasindex, c.relhasrules, c.relhasoids, " "c.relfrozenxid, tc.oid AS toid, " "tc.relfrozenxid AS tfrozenxid, " - "c.relpersistence, pg_relation_is_scannable(c.oid) as isscannable, " + "c.relpersistence, c.relispopulated, " + "c.relreplident, c.relpages, " + "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, " + "d.refobjid AS owning_tab, " + "d.refobjsubid AS owning_col, " + "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " + "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, " + "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text " + "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, " + "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions " + "FROM pg_class c " + "LEFT JOIN pg_depend d ON " + "(c.relkind = '%c' AND " + "d.classid = c.tableoid AND d.objid = c.oid AND " + "d.objsubid = 0 AND " + "d.refclassid = c.tableoid AND d.deptype = 'a') " + "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) " + "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') " + "ORDER BY c.oid", + username_subquery, + RELKIND_SEQUENCE, + RELKIND_RELATION, RELKIND_SEQUENCE, + RELKIND_VIEW, RELKIND_COMPOSITE_TYPE, + RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE); + } + else if (fout->remoteVersion >= 90300) + { + /* + * Left join to pick up dependency info linking sequences to their + * owning column, if any (note this dependency is AUTO as of 8.2) + */ + appendPQExpBuffer(query, + "SELECT c.tableoid, c.oid, c.relname, " + "c.relacl, c.relkind, c.relnamespace, " + "(%s c.relowner) AS rolname, " + "c.relchecks, c.relhastriggers, " + "c.relhasindex, c.relhasrules, c.relhasoids, " + "c.relfrozenxid, tc.oid AS toid, " + "tc.relfrozenxid AS tfrozenxid, " + "c.relpersistence, c.relispopulated, " + "'d' AS relreplident, c.relpages, " + "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, " + "d.refobjid AS owning_tab, " + "d.refobjsubid AS owning_col, " + "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " + "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, " + "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text " + "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, " + "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions " + "FROM pg_class c " + "LEFT JOIN pg_depend d ON " + "(c.relkind = '%c' AND " + "d.classid = c.tableoid AND d.objid = c.oid AND " + "d.objsubid = 0 AND " + "d.refclassid = c.tableoid AND d.deptype = 'a') " + "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) " + "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') " + "ORDER BY c.oid", + username_subquery, + RELKIND_SEQUENCE, + RELKIND_RELATION, RELKIND_SEQUENCE, + RELKIND_VIEW, RELKIND_COMPOSITE_TYPE, + RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE); + } + else if (fout->remoteVersion >= 90100) + { + /* + * Left join to pick up dependency info linking sequences to their + * owning column, if any (note this dependency is AUTO as of 8.2) + */ + appendPQExpBuffer(query, + "SELECT c.tableoid, c.oid, c.relname, " + "c.relacl, c.relkind, c.relnamespace, " + "(%s c.relowner) AS rolname, " + "c.relchecks, c.relhastriggers, " + "c.relhasindex, c.relhasrules, c.relhasoids, " + "c.relfrozenxid, tc.oid AS toid, " + "tc.relfrozenxid AS tfrozenxid, " + "c.relpersistence, 't' as relispopulated, " + "'d' AS relreplident, c.relpages, " "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, " "d.refobjid AS owning_tab, " "d.refobjsubid AS owning_col, " @@ -4169,7 +4399,7 @@ getTables(Archive *fout, int *numTables) "d.objsubid = 0 AND " "d.refclassid = c.tableoid AND d.deptype = 'a') " "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) " - "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') " + "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') " "ORDER BY c.oid", username_subquery, RELKIND_SEQUENCE, @@ -4191,7 +4421,8 @@ getTables(Archive *fout, int *numTables) "c.relhasindex, c.relhasrules, c.relhasoids, " "c.relfrozenxid, tc.oid AS toid, " "tc.relfrozenxid AS tfrozenxid, " - "'p' AS relpersistence, 't'::bool as isscannable, " + "'p' AS relpersistence, 't' as relispopulated, " + "'d' AS relreplident, c.relpages, " "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, " "d.refobjid AS owning_tab, " "d.refobjsubid AS owning_col, " @@ -4226,7 +4457,8 @@ getTables(Archive *fout, int *numTables) "c.relhasindex, c.relhasrules, c.relhasoids, " "c.relfrozenxid, tc.oid AS toid, " "tc.relfrozenxid AS tfrozenxid, " - "'p' AS relpersistence, 't'::bool as isscannable, " + "'p' AS relpersistence, 't' as relispopulated, " + "'d' AS relreplident, c.relpages, " "NULL AS reloftype, " "d.refobjid AS owning_tab, " "d.refobjsubid AS owning_col, " @@ -4261,7 +4493,8 @@ getTables(Archive *fout, int *numTables) "c.relhasindex, c.relhasrules, c.relhasoids, " "c.relfrozenxid, tc.oid AS toid, " "tc.relfrozenxid AS tfrozenxid, " - "'p' AS relpersistence, 't'::bool as isscannable, " + "'p' AS relpersistence, 't' as relispopulated, " + "'d' AS relreplident, c.relpages, " "NULL AS reloftype, " "d.refobjid AS owning_tab, " "d.refobjsubid AS owning_col, " @@ -4297,7 +4530,8 @@ getTables(Archive *fout, int *numTables) "0 AS relfrozenxid, " "0 AS toid, " "0 AS tfrozenxid, " - "'p' AS relpersistence, 't'::bool as isscannable, " + "'p' AS relpersistence, 't' as relispopulated, " + "'d' AS relreplident, relpages, " "NULL AS reloftype, " "d.refobjid AS owning_tab, " "d.refobjsubid AS owning_col, " @@ -4332,7 +4566,8 @@ getTables(Archive *fout, int *numTables) "0 AS relfrozenxid, " "0 AS toid, " "0 AS tfrozenxid, " - "'p' AS relpersistence, 't'::bool as isscannable, " + "'p' AS relpersistence, 't' as relispopulated, " + "'d' AS relreplident, relpages, " "NULL AS reloftype, " "d.refobjid AS owning_tab, " "d.refobjsubid AS owning_col, " @@ -4363,7 +4598,8 @@ getTables(Archive *fout, int *numTables) "0 AS relfrozenxid, " "0 AS toid, " "0 AS tfrozenxid, " - "'p' AS relpersistence, 't'::bool as isscannable, " + "'p' AS relpersistence, 't' as relispopulated, " + "'d' AS relreplident, relpages, " "NULL AS reloftype, " "NULL::oid AS owning_tab, " "NULL::int4 AS owning_col, " @@ -4389,7 +4625,8 @@ getTables(Archive *fout, int *numTables) "0 AS relfrozenxid, " "0 AS toid, " "0 AS tfrozenxid, " - "'p' AS relpersistence, 't'::bool as isscannable, " + "'p' AS relpersistence, 't' as relispopulated, " + "'d' AS relreplident, relpages, " "NULL AS reloftype, " "NULL::oid AS owning_tab, " "NULL::int4 AS owning_col, " @@ -4425,7 +4662,8 @@ getTables(Archive *fout, int *numTables) "0 as relfrozenxid, " "0 AS toid, " "0 AS tfrozenxid, " - "'p' AS relpersistence, 't'::bool as isscannable, " + "'p' AS relpersistence, 't' as relispopulated, " + "'d' AS relreplident, 0 AS relpages, " "NULL AS reloftype, " "NULL::oid AS owning_tab, " "NULL::int4 AS owning_col, " @@ -4473,11 +4711,14 @@ getTables(Archive *fout, int *numTables) i_toastoid = PQfnumber(res, "toid"); i_toastfrozenxid = PQfnumber(res, "tfrozenxid"); i_relpersistence = PQfnumber(res, "relpersistence"); - i_isscannable = PQfnumber(res, "isscannable"); + i_relispopulated = PQfnumber(res, "relispopulated"); + i_relreplident = PQfnumber(res, "relreplident"); + i_relpages = PQfnumber(res, "relpages"); i_owning_tab = PQfnumber(res, "owning_tab"); i_owning_col = PQfnumber(res, "owning_col"); i_reltablespace = PQfnumber(res, "reltablespace"); i_reloptions = PQfnumber(res, "reloptions"); + i_checkoption = PQfnumber(res, "checkoption"); i_toastreloptions = PQfnumber(res, "toast_reloptions"); i_reloftype = PQfnumber(res, "reloftype"); @@ -4491,7 +4732,7 @@ getTables(Archive *fout, int *numTables) * applied to other things too. */ resetPQExpBuffer(query); - appendPQExpBuffer(query, "SET statement_timeout = "); + appendPQExpBufferStr(query, "SET statement_timeout = "); appendStringLiteralConn(query, lockWaitTimeout, GetConnection(fout)); ExecuteSqlStatement(fout, query->data); } @@ -4515,7 +4756,9 @@ getTables(Archive *fout, int *numTables) tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0); tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0); tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0); - tblinfo[i].isscannable = (strcmp(PQgetvalue(res, i, i_isscannable), "t") == 0); + tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0); + tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident)); + tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages)); tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid)); tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid)); tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid)); @@ -4536,6 +4779,10 @@ getTables(Archive *fout, int *numTables) } tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace)); tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions)); + if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption)) + tblinfo[i].checkoption = NULL; + else + tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption)); tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions)); /* other fields were zeroed above */ @@ -4549,6 +4796,8 @@ getTables(Archive *fout, int *numTables) selectDumpableTable(&tblinfo[i]); tblinfo[i].interesting = tblinfo[i].dobj.dump; + tblinfo[i].postponed_def = false; /* might get set during sort */ + /* * Read-lock target tables to make sure they aren't DROPPED or altered * in schema before we get around to dumping them. @@ -4565,7 +4814,7 @@ getTables(Archive *fout, int *numTables) resetPQExpBuffer(query); appendPQExpBuffer(query, "LOCK TABLE %s IN ACCESS SHARE MODE", - fmtQualifiedId(fout, + fmtQualifiedId(fout->remoteVersion, tblinfo[i].dobj.namespace->dobj.name, tblinfo[i].dobj.name)); ExecuteSqlStatement(fout, query->data); @@ -4647,7 +4896,7 @@ getInherits(Archive *fout, int *numInherits) /* find all the inheritance information */ - appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits"); + appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -4696,6 +4945,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) i_indnkeys, i_indkey, i_indisclustered, + i_indisreplident, i_contype, i_conname, i_condeferrable, @@ -4704,7 +4954,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) i_conoid, i_condef, i_tablespace, - i_options; + i_options, + i_relpages; int ntups; for (i = 0; i < numTables; i++) @@ -4741,14 +4992,50 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) * is not. */ resetPQExpBuffer(query); - if (fout->remoteVersion >= 90000) + if (fout->remoteVersion >= 90400) + { + /* + * the test on indisready is necessary in 9.2, and harmless in + * earlier/later versions + */ + appendPQExpBuffer(query, + "SELECT t.tableoid, t.oid, " + "t.relname AS indexname, " + "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, " + "t.relnatts AS indnkeys, " + "i.indkey, i.indisclustered, " + "i.indisreplident, t.relpages, " + "c.contype, c.conname, " + "c.condeferrable, c.condeferred, " + "c.tableoid AS contableoid, " + "c.oid AS conoid, " + "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, " + "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, " + "array_to_string(t.reloptions, ', ') AS options " + "FROM pg_catalog.pg_index i " + "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) " + "LEFT JOIN pg_catalog.pg_constraint c " + "ON (i.indrelid = c.conrelid AND " + "i.indexrelid = c.conindid AND " + "c.contype IN ('p','u','x')) " + "WHERE i.indrelid = '%u'::pg_catalog.oid " + "AND i.indisvalid AND i.indisready " + "ORDER BY indexname", + tbinfo->dobj.catId.oid); + } + else if (fout->remoteVersion >= 90000) { + /* + * the test on indisready is necessary in 9.2, and harmless in + * earlier/later versions + */ appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, " "t.relname AS indexname, " "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, " "t.relnatts AS indnkeys, " "i.indkey, i.indisclustered, " + "false AS indisreplident, t.relpages, " "c.contype, c.conname, " "c.condeferrable, c.condeferred, " "c.tableoid AS contableoid, " @@ -4763,6 +5050,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "i.indexrelid = c.conindid AND " "c.contype IN ('p','u','x')) " "WHERE i.indrelid = '%u'::pg_catalog.oid " + "AND i.indisvalid AND i.indisready " "ORDER BY indexname", tbinfo->dobj.catId.oid); } @@ -4774,6 +5062,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, " "t.relnatts AS indnkeys, " "i.indkey, i.indisclustered, " + "false AS indisreplident, t.relpages, " "c.contype, c.conname, " "c.condeferrable, c.condeferred, " "c.tableoid AS contableoid, " @@ -4791,6 +5080,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "ON (d.refclassid = c.tableoid " "AND d.refobjid = c.oid) " "WHERE i.indrelid = '%u'::pg_catalog.oid " + "AND i.indisvalid " "ORDER BY indexname", tbinfo->dobj.catId.oid); } @@ -4802,6 +5092,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, " "t.relnatts AS indnkeys, " "i.indkey, i.indisclustered, " + "false AS indisreplident, t.relpages, " "c.contype, c.conname, " "c.condeferrable, c.condeferred, " "c.tableoid AS contableoid, " @@ -4830,6 +5121,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, " "t.relnatts AS indnkeys, " "i.indkey, i.indisclustered, " + "false AS indisreplident, t.relpages, " "c.contype, c.conname, " "c.condeferrable, c.condeferred, " "c.tableoid AS contableoid, " @@ -4858,6 +5150,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "pg_get_indexdef(i.indexrelid) AS indexdef, " "t.relnatts AS indnkeys, " "i.indkey, false AS indisclustered, " + "false AS indisreplident, t.relpages, " "CASE WHEN i.indisprimary THEN 'p'::char " "ELSE '0'::char END AS contype, " "t.relname AS conname, " @@ -4884,6 +5177,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "pg_get_indexdef(i.indexrelid) AS indexdef, " "t.relnatts AS indnkeys, " "i.indkey, false AS indisclustered, " + "false AS indisreplident, t.relpages, " "CASE WHEN i.indisprimary THEN 'p'::char " "ELSE '0'::char END AS contype, " "t.relname AS conname, " @@ -4912,6 +5206,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) i_indnkeys = PQfnumber(res, "indnkeys"); i_indkey = PQfnumber(res, "indkey"); i_indisclustered = PQfnumber(res, "indisclustered"); + i_indisreplident = PQfnumber(res, "indisreplident"); + i_relpages = PQfnumber(res, "relpages"); i_contype = PQfnumber(res, "contype"); i_conname = PQfnumber(res, "conname"); i_condeferrable = PQfnumber(res, "condeferrable"); @@ -4954,6 +5250,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) parseOidArray(PQgetvalue(res, j, i_indkey), indxinfo[j].indkeys, INDEX_MAX_KEYS); indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't'); + indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't'); + indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages)); contype = *(PQgetvalue(res, j, i_contype)); if (contype == 'p' || contype == 'u' || contype == 'x') @@ -5232,31 +5530,31 @@ getRules(Archive *fout, int *numRules) if (fout->remoteVersion >= 80300) { - appendPQExpBuffer(query, "SELECT " - "tableoid, oid, rulename, " - "ev_class AS ruletable, ev_type, is_instead, " - "ev_enabled " - "FROM pg_rewrite " - "ORDER BY oid"); + appendPQExpBufferStr(query, "SELECT " + "tableoid, oid, rulename, " + "ev_class AS ruletable, ev_type, is_instead, " + "ev_enabled " + "FROM pg_rewrite " + "ORDER BY oid"); } else if (fout->remoteVersion >= 70100) { - appendPQExpBuffer(query, "SELECT " - "tableoid, oid, rulename, " - "ev_class AS ruletable, ev_type, is_instead, " - "'O'::char AS ev_enabled " - "FROM pg_rewrite " - "ORDER BY oid"); + appendPQExpBufferStr(query, "SELECT " + "tableoid, oid, rulename, " + "ev_class AS ruletable, ev_type, is_instead, " + "'O'::char AS ev_enabled " + "FROM pg_rewrite " + "ORDER BY oid"); } else { - appendPQExpBuffer(query, "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, " - "oid, rulename, " - "ev_class AS ruletable, ev_type, is_instead, " - "'O'::char AS ev_enabled " - "FROM pg_rewrite " - "ORDER BY oid"); + appendPQExpBufferStr(query, "SELECT " + "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, " + "oid, rulename, " + "ev_class AS ruletable, ev_type, is_instead, " + "'O'::char AS ev_enabled " + "FROM pg_rewrite " + "ORDER BY oid"); } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -5304,7 +5602,7 @@ getRules(Archive *fout, int *numRules) * table. */ if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW || - ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) && + ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) && ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead) { addObjectDependency(&ruleinfo[i].ruletable->dobj, @@ -5573,7 +5871,7 @@ EventTriggerInfo * getEventTriggers(Archive *fout, int *numEventTriggers) { int i; - PQExpBuffer query = createPQExpBuffer(); + PQExpBuffer query; PGresult *res; EventTriggerInfo *evtinfo; int i_tableoid, @@ -5593,6 +5891,8 @@ getEventTriggers(Archive *fout, int *numEventTriggers) return NULL; } + query = createPQExpBuffer(); + /* Make sure we are in proper schema */ selectSourceSchema(fout, "pg_catalog"); @@ -5723,17 +6023,17 @@ getProcLangs(Archive *fout, int *numProcLangs) else if (fout->remoteVersion >= 70100) { /* No clear notion of an owner at all before 7.4 ... */ - appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language " - "WHERE lanispl " - "ORDER BY oid"); + appendPQExpBufferStr(query, "SELECT tableoid, oid, * FROM pg_language " + "WHERE lanispl " + "ORDER BY oid"); } else { - appendPQExpBuffer(query, "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, " - "oid, * FROM pg_language " - "WHERE lanispl " - "ORDER BY oid"); + appendPQExpBufferStr(query, "SELECT " + "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, " + "oid, * FROM pg_language " + "WHERE lanispl " + "ORDER BY oid"); } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -5831,29 +6131,29 @@ getCasts(Archive *fout, int *numCasts) if (fout->remoteVersion >= 80400) { - appendPQExpBuffer(query, "SELECT tableoid, oid, " - "castsource, casttarget, castfunc, castcontext, " - "castmethod " - "FROM pg_cast ORDER BY 3,4"); + appendPQExpBufferStr(query, "SELECT tableoid, oid, " + "castsource, casttarget, castfunc, castcontext, " + "castmethod " + "FROM pg_cast ORDER BY 3,4"); } else if (fout->remoteVersion >= 70300) { - appendPQExpBuffer(query, "SELECT tableoid, oid, " - "castsource, casttarget, castfunc, castcontext, " + appendPQExpBufferStr(query, "SELECT tableoid, oid, " + "castsource, casttarget, castfunc, castcontext, " "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod " - "FROM pg_cast ORDER BY 3,4"); + "FROM pg_cast ORDER BY 3,4"); } else { - appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, " - "t1.oid AS castsource, t2.oid AS casttarget, " - "p.oid AS castfunc, 'e' AS castcontext, " - "'f' AS castmethod " - "FROM pg_type t1, pg_type t2, pg_proc p " - "WHERE p.pronargs = 1 AND " - "p.proargtypes[0] = t1.oid AND " - "p.prorettype = t2.oid AND p.proname = t2.typname " - "ORDER BY 3,4"); + appendPQExpBufferStr(query, "SELECT 0 AS tableoid, p.oid, " + "t1.oid AS castsource, t2.oid AS casttarget, " + "p.oid AS castfunc, 'e' AS castcontext, " + "'f' AS castmethod " + "FROM pg_type t1, pg_type t2, pg_proc p " + "WHERE p.pronargs = 1 AND " + "p.proargtypes[0] = t1.oid AND " + "p.prorettype = t2.oid AND p.proname = t2.typname " + "ORDER BY 3,4"); } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -6553,10 +6853,10 @@ getTSParsers(Archive *fout, int *numTSParsers) /* Make sure we are in proper schema */ selectSourceSchema(fout, "pg_catalog"); - appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, " - "prsstart::oid, prstoken::oid, " - "prsend::oid, prsheadline::oid, prslextype::oid " - "FROM pg_ts_parser"); + appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, " + "prsstart::oid, prstoken::oid, " + "prsend::oid, prsheadline::oid, prslextype::oid " + "FROM pg_ts_parser"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -6722,9 +7022,9 @@ getTSTemplates(Archive *fout, int *numTSTemplates) /* Make sure we are in proper schema */ selectSourceSchema(fout, "pg_catalog"); - appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, " - "tmplnamespace, tmplinit::oid, tmpllexize::oid " - "FROM pg_ts_template"); + appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, " + "tmplnamespace, tmplinit::oid, tmpllexize::oid " + "FROM pg_ts_template"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -6856,7 +7156,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers) PGresult *res; int ntups; int i; - PQExpBuffer query = createPQExpBuffer(); + PQExpBuffer query; FdwInfo *fdwinfo; int i_tableoid; int i_oid; @@ -6874,6 +7174,8 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers) return NULL; } + query = createPQExpBuffer(); + /* Make sure we are in proper schema */ selectSourceSchema(fout, "pg_catalog"); @@ -6962,7 +7264,7 @@ getForeignServers(Archive *fout, int *numForeignServers) PGresult *res; int ntups; int i; - PQExpBuffer query = createPQExpBuffer(); + PQExpBuffer query; ForeignServerInfo *srvinfo; int i_tableoid; int i_oid; @@ -6981,6 +7283,8 @@ getForeignServers(Archive *fout, int *numForeignServers) return NULL; } + query = createPQExpBuffer(); + /* Make sure we are in proper schema */ selectSourceSchema(fout, "pg_catalog"); @@ -7184,7 +7488,7 @@ dumpComment(Archive *fout, const char *target, appendPQExpBuffer(query, "COMMENT ON %s IS ", target); appendStringLiteralAH(query, comments->descr, fout); - appendPQExpBuffer(query, ";\n"); + appendPQExpBufferStr(query, ";\n"); /* * We mark comments as SECTION_NONE because they really belong in the @@ -7248,7 +7552,7 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo, resetPQExpBuffer(query); appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data); appendStringLiteralAH(query, descr, fout); - appendPQExpBuffer(query, ";\n"); + appendPQExpBufferStr(query, ";\n"); ArchiveEntry(fout, nilCatalogId, createDumpId(), target->data, @@ -7264,13 +7568,12 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo, resetPQExpBuffer(target); appendPQExpBuffer(target, "COLUMN %s.", fmtId(tbinfo->dobj.name)); - appendPQExpBuffer(target, "%s", - fmtId(tbinfo->attnames[objsubid - 1])); + appendPQExpBufferStr(target, fmtId(tbinfo->attnames[objsubid - 1])); resetPQExpBuffer(query); appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data); appendStringLiteralAH(query, descr, fout); - appendPQExpBuffer(query, ";\n"); + appendPQExpBufferStr(query, ";\n"); ArchiveEntry(fout, nilCatalogId, createDumpId(), target->data, @@ -7411,22 +7714,22 @@ collectComments(Archive *fout, CommentItem **items) if (fout->remoteVersion >= 70300) { - appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid " - "FROM pg_catalog.pg_description " - "ORDER BY classoid, objoid, objsubid"); + appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid " + "FROM pg_catalog.pg_description " + "ORDER BY classoid, objoid, objsubid"); } else if (fout->remoteVersion >= 70200) { - appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid " - "FROM pg_description " - "ORDER BY classoid, objoid, objsubid"); + appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid " + "FROM pg_description " + "ORDER BY classoid, objoid, objsubid"); } else { /* Note: this will fail to find attribute comments in pre-7.2... */ - appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid " - "FROM pg_description " - "ORDER BY objoid"); + appendPQExpBufferStr(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid " + "FROM pg_description " + "ORDER BY objoid"); } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -7689,26 +7992,26 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo) int i; int n; - appendPQExpBuffer(q, "-- For binary upgrade, create an empty extension and insert objects into it\n"); + appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n"); /* - * We unconditionally create the extension, so we must drop it if it - * exists. This could happen if the user deleted 'plpgsql' and then - * readded it, causing its oid to be greater than FirstNormalObjectId. - * The FirstNormalObjectId test was kept to avoid repeatedly dropping - * and recreating extensions like 'plpgsql'. + * We unconditionally create the extension, so we must drop it if it + * exists. This could happen if the user deleted 'plpgsql' and then + * readded it, causing its oid to be greater than FirstNormalObjectId. + * The FirstNormalObjectId test was kept to avoid repeatedly dropping + * and recreating extensions like 'plpgsql'. */ appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname); - appendPQExpBuffer(q, + appendPQExpBufferStr(q, "SELECT binary_upgrade.create_empty_extension("); appendStringLiteralAH(q, extinfo->dobj.name, fout); - appendPQExpBuffer(q, ", "); + appendPQExpBufferStr(q, ", "); appendStringLiteralAH(q, extinfo->namespace, fout); - appendPQExpBuffer(q, ", "); + appendPQExpBufferStr(q, ", "); appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false"); appendStringLiteralAH(q, extinfo->extversion, fout); - appendPQExpBuffer(q, ", "); + appendPQExpBufferStr(q, ", "); /* * Note that we're pushing extconfig (an OID array) back into @@ -7718,14 +8021,14 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo) if (strlen(extinfo->extconfig) > 2) appendStringLiteralAH(q, extinfo->extconfig, fout); else - appendPQExpBuffer(q, "NULL"); - appendPQExpBuffer(q, ", "); + appendPQExpBufferStr(q, "NULL"); + appendPQExpBufferStr(q, ", "); if (strlen(extinfo->extcondition) > 2) appendStringLiteralAH(q, extinfo->extcondition, fout); else - appendPQExpBuffer(q, "NULL"); - appendPQExpBuffer(q, ", "); - appendPQExpBuffer(q, "ARRAY["); + appendPQExpBufferStr(q, "NULL"); + appendPQExpBufferStr(q, ", "); + appendPQExpBufferStr(q, "ARRAY["); n = 0; for (i = 0; i < extinfo->dobj.nDeps; i++) { @@ -7735,12 +8038,12 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo) if (extobj && extobj->objType == DO_EXTENSION) { if (n++ > 0) - appendPQExpBuffer(q, ","); + appendPQExpBufferChar(q, ','); appendStringLiteralAH(q, extobj->name, fout); } } - appendPQExpBuffer(q, "]::pg_catalog.text[]"); - appendPQExpBuffer(q, ");\n"); + appendPQExpBufferStr(q, "]::pg_catalog.text[]"); + appendPQExpBufferStr(q, ");\n"); } appendPQExpBuffer(labelq, "EXTENSION %s", qextname); @@ -7860,13 +8163,13 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo) { label = PQgetvalue(res, i, PQfnumber(res, "enumlabel")); if (i > 0) - appendPQExpBuffer(q, ","); - appendPQExpBuffer(q, "\n "); + appendPQExpBufferChar(q, ','); + appendPQExpBufferStr(q, "\n "); appendStringLiteralAH(q, label, fout); } } - appendPQExpBuffer(q, "\n);\n"); + appendPQExpBufferStr(q, "\n);\n"); if (binary_upgrade) { @@ -7877,7 +8180,7 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo) label = PQgetvalue(res, i, PQfnumber(res, "enumlabel")); if (i == 0) - appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n"); + appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n"); appendPQExpBuffer(q, "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n", enum_oid); @@ -7886,7 +8189,7 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo) appendPQExpBuffer(q, "%s ADD VALUE ", qtypname); appendStringLiteralAH(q, label, fout); - appendPQExpBuffer(q, ";\n\n"); + appendPQExpBufferStr(q, ";\n\n"); } } @@ -7995,7 +8298,7 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo) /* always schema-qualify, don't try to be smart */ appendPQExpBuffer(q, ",\n subtype_opclass = %s.", fmtId(nspname)); - appendPQExpBuffer(q, "%s", fmtId(opcname)); + appendPQExpBufferStr(q, fmtId(opcname)); } collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation"))); @@ -8008,8 +8311,7 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo) /* always schema-qualify, don't try to be smart */ appendPQExpBuffer(q, ",\n collation = %s.", fmtId(coll->dobj.namespace->dobj.name)); - appendPQExpBuffer(q, "%s", - fmtId(coll->dobj.name)); + appendPQExpBufferStr(q, fmtId(coll->dobj.name)); } } @@ -8021,7 +8323,7 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo) if (strcmp(procname, "-") != 0) appendPQExpBuffer(q, ",\n subtype_diff = %s", procname); - appendPQExpBuffer(q, "\n);\n"); + appendPQExpBufferStr(q, "\n);\n"); appendPQExpBuffer(labelq, "TYPE %s", qtypname); @@ -8353,11 +8655,11 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo) } if (strcmp(typcollatable, "t") == 0) - appendPQExpBuffer(q, ",\n COLLATABLE = true"); + appendPQExpBufferStr(q, ",\n COLLATABLE = true"); if (typdefault != NULL) { - appendPQExpBuffer(q, ",\n DEFAULT = "); + appendPQExpBufferStr(q, ",\n DEFAULT = "); if (typdefault_is_literal) appendStringLiteralAH(q, typdefault, fout); else @@ -8377,41 +8679,41 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo) if (strcmp(typcategory, "U") != 0) { - appendPQExpBuffer(q, ",\n CATEGORY = "); + appendPQExpBufferStr(q, ",\n CATEGORY = "); appendStringLiteralAH(q, typcategory, fout); } if (strcmp(typispreferred, "t") == 0) - appendPQExpBuffer(q, ",\n PREFERRED = true"); + appendPQExpBufferStr(q, ",\n PREFERRED = true"); if (typdelim && strcmp(typdelim, ",") != 0) { - appendPQExpBuffer(q, ",\n DELIMITER = "); + appendPQExpBufferStr(q, ",\n DELIMITER = "); appendStringLiteralAH(q, typdelim, fout); } if (strcmp(typalign, "c") == 0) - appendPQExpBuffer(q, ",\n ALIGNMENT = char"); + appendPQExpBufferStr(q, ",\n ALIGNMENT = char"); else if (strcmp(typalign, "s") == 0) - appendPQExpBuffer(q, ",\n ALIGNMENT = int2"); + appendPQExpBufferStr(q, ",\n ALIGNMENT = int2"); else if (strcmp(typalign, "i") == 0) - appendPQExpBuffer(q, ",\n ALIGNMENT = int4"); + appendPQExpBufferStr(q, ",\n ALIGNMENT = int4"); else if (strcmp(typalign, "d") == 0) - appendPQExpBuffer(q, ",\n ALIGNMENT = double"); + appendPQExpBufferStr(q, ",\n ALIGNMENT = double"); if (strcmp(typstorage, "p") == 0) - appendPQExpBuffer(q, ",\n STORAGE = plain"); + appendPQExpBufferStr(q, ",\n STORAGE = plain"); else if (strcmp(typstorage, "e") == 0) - appendPQExpBuffer(q, ",\n STORAGE = external"); + appendPQExpBufferStr(q, ",\n STORAGE = external"); else if (strcmp(typstorage, "x") == 0) - appendPQExpBuffer(q, ",\n STORAGE = extended"); + appendPQExpBufferStr(q, ",\n STORAGE = extended"); else if (strcmp(typstorage, "m") == 0) - appendPQExpBuffer(q, ",\n STORAGE = main"); + appendPQExpBufferStr(q, ",\n STORAGE = main"); if (strcmp(typbyval, "t") == 0) - appendPQExpBuffer(q, ",\n PASSEDBYVALUE"); + appendPQExpBufferStr(q, ",\n PASSEDBYVALUE"); - appendPQExpBuffer(q, "\n);\n"); + appendPQExpBufferStr(q, "\n);\n"); appendPQExpBuffer(labelq, "TYPE %s", qtypname); @@ -8535,17 +8837,16 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) /* always schema-qualify, don't try to be smart */ appendPQExpBuffer(q, " COLLATE %s.", fmtId(coll->dobj.namespace->dobj.name)); - appendPQExpBuffer(q, "%s", - fmtId(coll->dobj.name)); + appendPQExpBufferStr(q, fmtId(coll->dobj.name)); } } if (typnotnull[0] == 't') - appendPQExpBuffer(q, " NOT NULL"); + appendPQExpBufferStr(q, " NOT NULL"); if (typdefault != NULL) { - appendPQExpBuffer(q, " DEFAULT "); + appendPQExpBufferStr(q, " DEFAULT "); if (typdefault_is_literal) appendStringLiteralAH(q, typdefault, fout); else @@ -8566,7 +8867,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) fmtId(domcheck->dobj.name), domcheck->condef); } - appendPQExpBuffer(q, ";\n"); + appendPQExpBufferStr(q, ";\n"); /* * DROP must be fully qualified in case same name appears in pg_catalog @@ -8729,8 +9030,8 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo) /* Format properly if not first attr */ if (actual_atts++ > 0) - appendPQExpBuffer(q, ","); - appendPQExpBuffer(q, "\n\t"); + appendPQExpBufferChar(q, ','); + appendPQExpBufferStr(q, "\n\t"); if (!attisdropped) { @@ -8747,8 +9048,7 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo) /* always schema-qualify, don't try to be smart */ appendPQExpBuffer(q, " COLLATE %s.", fmtId(coll->dobj.namespace->dobj.name)); - appendPQExpBuffer(q, "%s", - fmtId(coll->dobj.name)); + appendPQExpBufferStr(q, fmtId(coll->dobj.name)); } } } @@ -8763,16 +9063,16 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo) appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname)); /* stash separately for insertion after the CREATE TYPE */ - appendPQExpBuffer(dropped, + appendPQExpBufferStr(dropped, "\n-- For binary upgrade, recreate dropped column.\n"); appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n" "SET attlen = %s, " "attalign = '%s', attbyval = false\n" "WHERE attname = ", attlen, attalign); appendStringLiteralAH(dropped, attname, fout); - appendPQExpBuffer(dropped, "\n AND attrelid = "); + appendPQExpBufferStr(dropped, "\n AND attrelid = "); appendStringLiteralAH(dropped, qtypname, fout); - appendPQExpBuffer(dropped, "::pg_catalog.regclass;\n"); + appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n"); appendPQExpBuffer(dropped, "ALTER TYPE %s ", qtypname); @@ -8780,7 +9080,7 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo) fmtId(attname)); } } - appendPQExpBuffer(q, "\n);\n"); + appendPQExpBufferStr(q, "\n);\n"); appendPQExpBufferStr(q, dropped->data); /* @@ -8913,13 +9213,12 @@ dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo) resetPQExpBuffer(target); appendPQExpBuffer(target, "COLUMN %s.", fmtId(tyinfo->dobj.name)); - appendPQExpBuffer(target, "%s", - fmtId(attname)); + appendPQExpBufferStr(target, fmtId(attname)); resetPQExpBuffer(query); appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data); appendStringLiteralAH(query, descr, fout); - appendPQExpBuffer(query, ";\n"); + appendPQExpBufferStr(query, ";\n"); ArchiveEntry(fout, nilCatalogId, createDumpId(), target->data, @@ -9109,23 +9408,21 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang) fmtId(funcInfo->dobj.name)); if (OidIsValid(plang->laninline)) { - appendPQExpBuffer(defqry, " INLINE "); + appendPQExpBufferStr(defqry, " INLINE "); /* Cope with possibility that inline is in different schema */ if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace) appendPQExpBuffer(defqry, "%s.", fmtId(inlineInfo->dobj.namespace->dobj.name)); - appendPQExpBuffer(defqry, "%s", - fmtId(inlineInfo->dobj.name)); + appendPQExpBufferStr(defqry, fmtId(inlineInfo->dobj.name)); } if (OidIsValid(plang->lanvalidator)) { - appendPQExpBuffer(defqry, " VALIDATOR "); + appendPQExpBufferStr(defqry, " VALIDATOR "); /* Cope with possibility that validator is in different schema */ if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace) appendPQExpBuffer(defqry, "%s.", fmtId(validatorInfo->dobj.namespace->dobj.name)); - appendPQExpBuffer(defqry, "%s", - fmtId(validatorInfo->dobj.name)); + appendPQExpBufferStr(defqry, fmtId(validatorInfo->dobj.name)); } } else @@ -9142,7 +9439,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang) appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s", qlanname); } - appendPQExpBuffer(defqry, ";\n"); + appendPQExpBufferStr(defqry, ";\n"); appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname); @@ -9182,15 +9479,20 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang) * format_function_arguments: generate function name and argument list * * This is used when we can rely on pg_get_function_arguments to format - * the argument list. + * the argument list. Note, however, that pg_get_function_arguments + * does not special-case zero-argument aggregates. */ static char * -format_function_arguments(FuncInfo *finfo, char *funcargs) +format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg) { PQExpBufferData fn; initPQExpBuffer(&fn); - appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs); + appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name)); + if (is_agg && finfo->nargs == 0) + appendPQExpBufferStr(&fn, "(*)"); + else + appendPQExpBuffer(&fn, "(%s)", funcargs); return fn.data; } @@ -9261,7 +9563,7 @@ format_function_arguments_old(Archive *fout, typname); free(typname); } - appendPQExpBuffer(&fn, ")"); + appendPQExpBufferChar(&fn, ')'); return fn.data; } @@ -9290,15 +9592,15 @@ format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes) { char *typname; + if (j > 0) + appendPQExpBufferStr(&fn, ", "); + typname = getFormattedTypeName(fout, finfo->argtypes[j], zeroAsOpaque); - - appendPQExpBuffer(&fn, "%s%s", - (j > 0) ? ", " : "", - typname); + appendPQExpBufferStr(&fn, typname); free(typname); } - appendPQExpBuffer(&fn, ")"); + appendPQExpBufferChar(&fn, ')'); return fn.data; } @@ -9317,7 +9619,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) PQExpBuffer asPart; PGresult *res; char *funcsig; /* identity signature */ - char *funcfullsig; /* full signature */ + char *funcfullsig = NULL; /* full signature */ char *funcsig_tag; char *proretset; char *prosrc; @@ -9530,11 +9832,11 @@ dumpFunc(Archive *fout, FuncInfo *finfo) */ if (probin[0] != '\0' && strcmp(probin, "-") != 0) { - appendPQExpBuffer(asPart, "AS "); + appendPQExpBufferStr(asPart, "AS "); appendStringLiteralAH(asPart, probin, fout); if (strcmp(prosrc, "-") != 0) { - appendPQExpBuffer(asPart, ", "); + appendPQExpBufferStr(asPart, ", "); /* * where we have bin, use dollar quoting if allowed and src @@ -9551,7 +9853,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) { if (strcmp(prosrc, "-") != 0) { - appendPQExpBuffer(asPart, "AS "); + appendPQExpBufferStr(asPart, "AS "); /* with no bin, dollar quote src unconditionally if allowed */ if (disable_dollar_quoting) appendStringLiteralAH(asPart, prosrc, fout); @@ -9621,17 +9923,14 @@ dumpFunc(Archive *fout, FuncInfo *finfo) if (funcargs) { /* 8.4 or later; we rely on server-side code for most of the work */ - funcfullsig = format_function_arguments(finfo, funcargs); - funcsig = format_function_arguments(finfo, funciargs); + funcfullsig = format_function_arguments(finfo, funcargs, false); + funcsig = format_function_arguments(finfo, funciargs, false); } else - { /* pre-8.4, do it ourselves */ funcsig = format_function_arguments_old(fout, finfo, nallargs, allargtypes, argmodes, argnames); - funcfullsig = funcsig; - } funcsig_tag = format_function_signature(fout, finfo, false); @@ -9642,7 +9941,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) fmtId(finfo->dobj.namespace->dobj.name), funcsig); - appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig); + appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig ? funcfullsig : + funcsig); if (funcresult) appendPQExpBuffer(q, "RETURNS %s", funcresult); else @@ -9658,27 +9958,27 @@ dumpFunc(Archive *fout, FuncInfo *finfo) appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname)); if (proiswindow[0] == 't') - appendPQExpBuffer(q, " WINDOW"); + appendPQExpBufferStr(q, " WINDOW"); if (provolatile[0] != PROVOLATILE_VOLATILE) { if (provolatile[0] == PROVOLATILE_IMMUTABLE) - appendPQExpBuffer(q, " IMMUTABLE"); + appendPQExpBufferStr(q, " IMMUTABLE"); else if (provolatile[0] == PROVOLATILE_STABLE) - appendPQExpBuffer(q, " STABLE"); + appendPQExpBufferStr(q, " STABLE"); else if (provolatile[0] != PROVOLATILE_VOLATILE) exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n", finfo->dobj.name); } if (proisstrict[0] == 't') - appendPQExpBuffer(q, " STRICT"); + appendPQExpBufferStr(q, " STRICT"); if (prosecdef[0] == 't') - appendPQExpBuffer(q, " SECURITY DEFINER"); + appendPQExpBufferStr(q, " SECURITY DEFINER"); if (proleakproof[0] == 't') - appendPQExpBuffer(q, " LEAKPROOF"); + appendPQExpBufferStr(q, " LEAKPROOF"); /* * COST and ROWS are emitted only if present and not default, so as not to @@ -9722,7 +10022,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) */ if (pg_strcasecmp(configitem, "DateStyle") == 0 || pg_strcasecmp(configitem, "search_path") == 0) - appendPQExpBuffer(q, "%s", pos); + appendPQExpBufferStr(q, pos); else appendStringLiteralAH(q, pos, fout); } @@ -9765,6 +10065,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) destroyPQExpBuffer(labelq); destroyPQExpBuffer(asPart); free(funcsig); + if (funcfullsig) + free(funcfullsig); free(funcsig_tag); if (allargtypes) free(allargtypes); @@ -9867,10 +10169,10 @@ dumpCast(Archive *fout, CastInfo *cast) switch (cast->castmethod) { case COERCION_METHOD_BINARY: - appendPQExpBuffer(defqry, "WITHOUT FUNCTION"); + appendPQExpBufferStr(defqry, "WITHOUT FUNCTION"); break; case COERCION_METHOD_INOUT: - appendPQExpBuffer(defqry, "WITH INOUT"); + appendPQExpBufferStr(defqry, "WITH INOUT"); break; case COERCION_METHOD_FUNCTION: if (funcInfo) @@ -9894,10 +10196,10 @@ dumpCast(Archive *fout, CastInfo *cast) } if (cast->castcontext == 'a') - appendPQExpBuffer(defqry, " AS ASSIGNMENT"); + appendPQExpBufferStr(defqry, " AS ASSIGNMENT"); else if (cast->castcontext == 'i') - appendPQExpBuffer(defqry, " AS IMPLICIT"); - appendPQExpBuffer(defqry, ";\n"); + appendPQExpBufferStr(defqry, " AS IMPLICIT"); + appendPQExpBufferStr(defqry, ";\n"); appendPQExpBuffer(labelq, "CAST (%s AS %s)", getFormattedTypeName(fout, cast->castsource, zeroAsNone), @@ -9959,6 +10261,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) char *oprjoin; char *oprcanmerge; char *oprcanhash; + char *oprregproc; + char *oprref; /* Skip if not to be dumped */ if (!oprinfo->dobj.dump || dataOnly) @@ -10065,8 +10369,12 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge); oprcanhash = PQgetvalue(res, 0, i_oprcanhash); - appendPQExpBuffer(details, " PROCEDURE = %s", - convertRegProcReference(fout, oprcode)); + oprregproc = convertRegProcReference(fout, oprcode); + if (oprregproc) + { + appendPQExpBuffer(details, " PROCEDURE = %s", oprregproc); + free(oprregproc); + } appendPQExpBuffer(oprid, "%s (", oprinfo->dobj.name); @@ -10083,10 +10391,10 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) else name = fmtId(oprleft); appendPQExpBuffer(details, ",\n LEFTARG = %s", name); - appendPQExpBuffer(oprid, "%s", name); + appendPQExpBufferStr(oprid, name); } else - appendPQExpBuffer(oprid, "NONE"); + appendPQExpBufferStr(oprid, "NONE"); if (strcmp(oprkind, "l") == 0 || strcmp(oprkind, "b") == 0) @@ -10099,29 +10407,41 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) appendPQExpBuffer(oprid, ", %s)", name); } else - appendPQExpBuffer(oprid, ", NONE)"); + appendPQExpBufferStr(oprid, ", NONE)"); - name = convertOperatorReference(fout, oprcom); - if (name) - appendPQExpBuffer(details, ",\n COMMUTATOR = %s", name); + oprref = convertOperatorReference(fout, oprcom); + if (oprref) + { + appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref); + free(oprref); + } - name = convertOperatorReference(fout, oprnegate); - if (name) - appendPQExpBuffer(details, ",\n NEGATOR = %s", name); + oprref = convertOperatorReference(fout, oprnegate); + if (oprref) + { + appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref); + free(oprref); + } if (strcmp(oprcanmerge, "t") == 0) - appendPQExpBuffer(details, ",\n MERGES"); + appendPQExpBufferStr(details, ",\n MERGES"); if (strcmp(oprcanhash, "t") == 0) - appendPQExpBuffer(details, ",\n HASHES"); + appendPQExpBufferStr(details, ",\n HASHES"); - name = convertRegProcReference(fout, oprrest); - if (name) - appendPQExpBuffer(details, ",\n RESTRICT = %s", name); + oprregproc = convertRegProcReference(fout, oprrest); + if (oprregproc) + { + appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc); + free(oprregproc); + } - name = convertRegProcReference(fout, oprjoin); - if (name) - appendPQExpBuffer(details, ",\n JOIN = %s", name); + oprregproc = convertRegProcReference(fout, oprjoin); + if (oprregproc) + { + appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc); + free(oprregproc); + } /* * DROP must be fully qualified in case same name appears in pg_catalog @@ -10166,12 +10486,13 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) /* * Convert a function reference obtained from pg_operator * - * Returns what to print, or NULL if function references is InvalidOid + * Returns allocated string of what to print, or NULL if function references + * is InvalidOid. Returned string is expected to be free'd by the caller. * * In 7.3 the input is a REGPROCEDURE display; we have to strip the * argument-types part. In prior versions, the input is a REGPROC display. */ -static const char * +static char * convertRegProcReference(Archive *fout, const char *proc) { /* In all cases "-" means a null reference */ @@ -10201,20 +10522,21 @@ convertRegProcReference(Archive *fout, const char *proc) } /* REGPROC before 7.3 does not quote its result */ - return fmtId(proc); + return pg_strdup(fmtId(proc)); } /* * Convert an operator cross-reference obtained from pg_operator * - * Returns what to print, or NULL to print nothing + * Returns an allocated string of what to print, or NULL to print nothing. + * Caller is responsible for free'ing result string. * * In 7.3 and up the input is a REGOPERATOR display; we have to strip the * argument-types part, and add OPERATOR() decoration if the name is * schema-qualified. In older versions, the input is just a numeric OID, * which we search our operator list for. */ -static const char * +static char * convertOperatorReference(Archive *fout, const char *opr) { OprInfo *oprInfo; @@ -10250,8 +10572,7 @@ convertOperatorReference(Archive *fout, const char *opr) /* If not schema-qualified, don't need to add OPERATOR() */ if (!sawdot) return name; - oname = pg_malloc(strlen(name) + 11); - sprintf(oname, "OPERATOR(%s)", name); + oname = psprintf("OPERATOR(%s)", name); free(name); return oname; } @@ -10263,7 +10584,7 @@ convertOperatorReference(Archive *fout, const char *opr) opr); return NULL; } - return oprInfo->dobj.name; + return pg_strdup(oprInfo->dobj.name); } /* @@ -10423,7 +10744,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ", fmtId(opcinfo->dobj.name)); if (strcmp(opcdefault, "t") == 0) - appendPQExpBuffer(q, "DEFAULT "); + appendPQExpBufferStr(q, "DEFAULT "); appendPQExpBuffer(q, "FOR TYPE %s USING %s", opcintype, fmtId(amname)); @@ -10431,12 +10752,12 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 || strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)) { - appendPQExpBuffer(q, " FAMILY "); + appendPQExpBufferStr(q, " FAMILY "); if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0) appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp)); appendPQExpBuffer(q, "%s", fmtId(opcfamilyname)); } - appendPQExpBuffer(q, " AS\n "); + appendPQExpBufferStr(q, " AS\n "); needComma = false; @@ -10543,21 +10864,21 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp); if (needComma) - appendPQExpBuffer(q, " ,\n "); + appendPQExpBufferStr(q, " ,\n "); appendPQExpBuffer(q, "OPERATOR %s %s", amopstrategy, amopopr); if (strlen(sortfamily) > 0) { - appendPQExpBuffer(q, " FOR ORDER BY "); + appendPQExpBufferStr(q, " FOR ORDER BY "); if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0) appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp)); - appendPQExpBuffer(q, "%s", fmtId(sortfamily)); + appendPQExpBufferStr(q, fmtId(sortfamily)); } if (strcmp(amopreqcheck, "t") == 0) - appendPQExpBuffer(q, " RECHECK"); + appendPQExpBufferStr(q, " RECHECK"); needComma = true; } @@ -10621,7 +10942,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) amprocrighttype = PQgetvalue(res, i, i_amprocrighttype); if (needComma) - appendPQExpBuffer(q, " ,\n "); + appendPQExpBufferStr(q, " ,\n "); appendPQExpBuffer(q, "FUNCTION %s", amprocnum); @@ -10635,7 +10956,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) PQclear(res); - appendPQExpBuffer(q, ";\n"); + appendPQExpBufferStr(q, ";\n"); appendPQExpBuffer(labelq, "OPERATOR CLASS %s", fmtId(opcinfo->dobj.name)); @@ -10901,21 +11222,21 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo) sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp); if (needComma) - appendPQExpBuffer(q, " ,\n "); + appendPQExpBufferStr(q, " ,\n "); appendPQExpBuffer(q, "OPERATOR %s %s", amopstrategy, amopopr); if (strlen(sortfamily) > 0) { - appendPQExpBuffer(q, " FOR ORDER BY "); + appendPQExpBufferStr(q, " FOR ORDER BY "); if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0) appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp)); - appendPQExpBuffer(q, "%s", fmtId(sortfamily)); + appendPQExpBufferStr(q, fmtId(sortfamily)); } if (strcmp(amopreqcheck, "t") == 0) - appendPQExpBuffer(q, " RECHECK"); + appendPQExpBufferStr(q, " RECHECK"); needComma = true; } @@ -10938,7 +11259,7 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo) amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype); if (needComma) - appendPQExpBuffer(q, " ,\n "); + appendPQExpBufferStr(q, " ,\n "); appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s", amprocnum, amproclefttype, amprocrighttype, @@ -10947,7 +11268,7 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo) needComma = true; } - appendPQExpBuffer(q, ";\n"); + appendPQExpBufferStr(q, ";\n"); } appendPQExpBuffer(labelq, "OPERATOR FAMILY %s", @@ -11038,9 +11359,9 @@ dumpCollation(Archive *fout, CollInfo *collinfo) appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ", fmtId(collinfo->dobj.name)); appendStringLiteralAH(q, collcollate, fout); - appendPQExpBuffer(q, ", lc_ctype = "); + appendPQExpBufferStr(q, ", lc_ctype = "); appendStringLiteralAH(q, collctype, fout); - appendPQExpBuffer(q, ");\n"); + appendPQExpBufferStr(q, ");\n"); appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name)); @@ -11136,7 +11457,7 @@ dumpConversion(Archive *fout, ConvInfo *convinfo) (condefault) ? "DEFAULT " : "", fmtId(convinfo->dobj.name)); appendStringLiteralAH(q, conforencoding, fout); - appendPQExpBuffer(q, " TO "); + appendPQExpBufferStr(q, " TO "); appendStringLiteralAH(q, contoencoding, fout); /* regproc is automatically quoted in 7.3 and above */ appendPQExpBuffer(q, " FROM %s;\n", conproc); @@ -11183,16 +11504,15 @@ format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes) initPQExpBuffer(&buf); if (honor_quotes) - appendPQExpBuffer(&buf, "%s", - fmtId(agginfo->aggfn.dobj.name)); + appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name)); else - appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name); + appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name); if (agginfo->aggfn.nargs == 0) appendPQExpBuffer(&buf, "(*)"); else { - appendPQExpBuffer(&buf, "("); + appendPQExpBufferChar(&buf, '('); for (j = 0; j < agginfo->aggfn.nargs; j++) { char *typname; @@ -11205,7 +11525,7 @@ format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes) typname); free(typname); } - appendPQExpBuffer(&buf, ")"); + appendPQExpBufferChar(&buf, ')'); } return buf.data; } @@ -11222,20 +11542,42 @@ dumpAgg(Archive *fout, AggInfo *agginfo) PQExpBuffer delq; PQExpBuffer labelq; PQExpBuffer details; - char *aggsig; + char *aggsig; /* identity signature */ + char *aggfullsig = NULL; /* full signature */ char *aggsig_tag; PGresult *res; int i_aggtransfn; int i_aggfinalfn; + int i_aggmtransfn; + int i_aggminvtransfn; + int i_aggmfinalfn; + int i_aggfinalextra; + int i_aggmfinalextra; int i_aggsortop; + int i_hypothetical; int i_aggtranstype; + int i_aggtransspace; + int i_aggmtranstype; + int i_aggmtransspace; int i_agginitval; + int i_aggminitval; int i_convertok; const char *aggtransfn; const char *aggfinalfn; + const char *aggmtransfn; + const char *aggminvtransfn; + const char *aggmfinalfn; + bool aggfinalextra; + bool aggmfinalextra; const char *aggsortop; + char *aggsortconvop; + bool hypothetical; const char *aggtranstype; + const char *aggtransspace; + const char *aggmtranstype; + const char *aggmtransspace; const char *agginitval; + const char *aggminitval; bool convertok; /* Skip if not to be dumped */ @@ -11252,25 +11594,73 @@ dumpAgg(Archive *fout, AggInfo *agginfo) selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name); /* Get aggregate-specific details */ - if (fout->remoteVersion >= 80100) + if (fout->remoteVersion >= 90400) { appendPQExpBuffer(query, "SELECT aggtransfn, " "aggfinalfn, aggtranstype::pg_catalog.regtype, " + "aggmtransfn, aggminvtransfn, aggmfinalfn, " + "aggmtranstype::pg_catalog.regtype, " + "aggfinalextra, aggmfinalextra, " "aggsortop::pg_catalog.regoperator, " - "agginitval, " - "'t'::boolean AS convertok " + "(aggkind = 'h') AS hypothetical, " + "aggtransspace, agginitval, " + "aggmtransspace, aggminitval, " + "true AS convertok, " + "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, " + "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs " "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " "WHERE a.aggfnoid = p.oid " "AND p.oid = '%u'::pg_catalog.oid", agginfo->aggfn.dobj.catId.oid); } + else if (fout->remoteVersion >= 80400) + { + appendPQExpBuffer(query, "SELECT aggtransfn, " + "aggfinalfn, aggtranstype::pg_catalog.regtype, " + "'-' AS aggmtransfn, '-' AS aggminvtransfn, " + "'-' AS aggmfinalfn, 0 AS aggmtranstype, " + "false AS aggfinalextra, false AS aggmfinalextra, " + "aggsortop::pg_catalog.regoperator, " + "false AS hypothetical, " + "0 AS aggtransspace, agginitval, " + "0 AS aggmtransspace, NULL AS aggminitval, " + "true AS convertok, " + "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, " + "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs " + "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " + "WHERE a.aggfnoid = p.oid " + "AND p.oid = '%u'::pg_catalog.oid", + agginfo->aggfn.dobj.catId.oid); + } + else if (fout->remoteVersion >= 80100) + { + appendPQExpBuffer(query, "SELECT aggtransfn, " + "aggfinalfn, aggtranstype::pg_catalog.regtype, " + "'-' AS aggmtransfn, '-' AS aggminvtransfn, " + "'-' AS aggmfinalfn, 0 AS aggmtranstype, " + "false AS aggfinalextra, false AS aggmfinalextra, " + "aggsortop::pg_catalog.regoperator, " + "false AS hypothetical, " + "0 AS aggtransspace, agginitval, " + "0 AS aggmtransspace, NULL AS aggminitval, " + "true AS convertok " + "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " + "WHERE a.aggfnoid = p.oid " + "AND p.oid = '%u'::pg_catalog.oid", + agginfo->aggfn.dobj.catId.oid); + } else if (fout->remoteVersion >= 70300) { appendPQExpBuffer(query, "SELECT aggtransfn, " "aggfinalfn, aggtranstype::pg_catalog.regtype, " + "'-' AS aggmtransfn, '-' AS aggminvtransfn, " + "'-' AS aggmfinalfn, 0 AS aggmtranstype, " + "false AS aggfinalextra, false AS aggmfinalextra, " "0 AS aggsortop, " - "agginitval, " - "'t'::boolean AS convertok " + "false AS hypothetical, " + "0 AS aggtransspace, agginitval, " + "0 AS aggmtransspace, NULL AS aggminitval, " + "true AS convertok " "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " "WHERE a.aggfnoid = p.oid " "AND p.oid = '%u'::pg_catalog.oid", @@ -11280,9 +11670,14 @@ dumpAgg(Archive *fout, AggInfo *agginfo) { appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, " "format_type(aggtranstype, NULL) AS aggtranstype, " + "'-' AS aggmtransfn, '-' AS aggminvtransfn, " + "'-' AS aggmfinalfn, 0 AS aggmtranstype, " + "false AS aggfinalextra, false AS aggmfinalextra, " "0 AS aggsortop, " - "agginitval, " - "'t'::boolean AS convertok " + "false AS hypothetical, " + "0 AS aggtransspace, agginitval, " + "0 AS aggmtransspace, NULL AS aggminitval, " + "true AS convertok " "FROM pg_aggregate " "WHERE oid = '%u'::oid", agginfo->aggfn.dobj.catId.oid); @@ -11292,8 +11687,13 @@ dumpAgg(Archive *fout, AggInfo *agginfo) appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, " "aggfinalfn, " "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, " + "'-' AS aggmtransfn, '-' AS aggminvtransfn, " + "'-' AS aggmfinalfn, 0 AS aggmtranstype, " + "false AS aggfinalextra, false AS aggmfinalextra, " "0 AS aggsortop, " - "agginitval1 AS agginitval, " + "false AS hypothetical, " + "0 AS aggtransspace, agginitval1 AS agginitval, " + "0 AS aggmtransspace, NULL AS aggminitval, " "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok " "FROM pg_aggregate " "WHERE oid = '%u'::oid", @@ -11304,25 +11704,65 @@ dumpAgg(Archive *fout, AggInfo *agginfo) i_aggtransfn = PQfnumber(res, "aggtransfn"); i_aggfinalfn = PQfnumber(res, "aggfinalfn"); + i_aggmtransfn = PQfnumber(res, "aggmtransfn"); + i_aggminvtransfn = PQfnumber(res, "aggminvtransfn"); + i_aggmfinalfn = PQfnumber(res, "aggmfinalfn"); + i_aggfinalextra = PQfnumber(res, "aggfinalextra"); + i_aggmfinalextra = PQfnumber(res, "aggmfinalextra"); i_aggsortop = PQfnumber(res, "aggsortop"); + i_hypothetical = PQfnumber(res, "hypothetical"); i_aggtranstype = PQfnumber(res, "aggtranstype"); + i_aggtransspace = PQfnumber(res, "aggtransspace"); + i_aggmtranstype = PQfnumber(res, "aggmtranstype"); + i_aggmtransspace = PQfnumber(res, "aggmtransspace"); i_agginitval = PQfnumber(res, "agginitval"); + i_aggminitval = PQfnumber(res, "aggminitval"); i_convertok = PQfnumber(res, "convertok"); aggtransfn = PQgetvalue(res, 0, i_aggtransfn); aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn); + aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn); + aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn); + aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn); + aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't'); + aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't'); aggsortop = PQgetvalue(res, 0, i_aggsortop); + hypothetical = (PQgetvalue(res, 0, i_hypothetical)[0] == 't'); aggtranstype = PQgetvalue(res, 0, i_aggtranstype); + aggtransspace = PQgetvalue(res, 0, i_aggtransspace); + aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype); + aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace); agginitval = PQgetvalue(res, 0, i_agginitval); + aggminitval = PQgetvalue(res, 0, i_aggminitval); convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't'); - aggsig = format_aggregate_signature(agginfo, fout, true); + if (fout->remoteVersion >= 80400) + { + /* 8.4 or later; we rely on server-side code for most of the work */ + char *funcargs; + char *funciargs; + + funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs")); + funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs")); + aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true); + aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true); + } + else + /* pre-8.4, do it ourselves */ + aggsig = format_aggregate_signature(agginfo, fout, true); + aggsig_tag = format_aggregate_signature(agginfo, fout, false); if (!convertok) { write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n", aggsig); + + if (aggfullsig) + free(aggfullsig); + + free(aggsig); + return; } @@ -11349,9 +11789,15 @@ dumpAgg(Archive *fout, AggInfo *agginfo) fmtId(aggtranstype)); } + if (strcmp(aggtransspace, "0") != 0) + { + appendPQExpBuffer(details, ",\n SSPACE = %s", + aggtransspace); + } + if (!PQgetisnull(res, 0, i_agginitval)) { - appendPQExpBuffer(details, ",\n INITCOND = "); + appendPQExpBufferStr(details, ",\n INITCOND = "); appendStringLiteralAH(details, agginitval, fout); } @@ -11359,15 +11805,49 @@ dumpAgg(Archive *fout, AggInfo *agginfo) { appendPQExpBuffer(details, ",\n FINALFUNC = %s", aggfinalfn); + if (aggfinalextra) + appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA"); + } + + if (strcmp(aggmtransfn, "-") != 0) + { + appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s", + aggmtransfn, + aggminvtransfn, + aggmtranstype); } - aggsortop = convertOperatorReference(fout, aggsortop); - if (aggsortop) + if (strcmp(aggmtransspace, "0") != 0) + { + appendPQExpBuffer(details, ",\n MSSPACE = %s", + aggmtransspace); + } + + if (!PQgetisnull(res, 0, i_aggminitval)) + { + appendPQExpBufferStr(details, ",\n MINITCOND = "); + appendStringLiteralAH(details, aggminitval, fout); + } + + if (strcmp(aggmfinalfn, "-") != 0) + { + appendPQExpBuffer(details, ",\n MFINALFUNC = %s", + aggmfinalfn); + if (aggmfinalextra) + appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA"); + } + + aggsortconvop = convertOperatorReference(fout, aggsortop); + if (aggsortconvop) { appendPQExpBuffer(details, ",\n SORTOP = %s", - aggsortop); + aggsortconvop); + free(aggsortconvop); } + if (hypothetical) + appendPQExpBufferStr(details, ",\n HYPOTHETICAL"); + /* * DROP must be fully qualified in case same name appears in pg_catalog */ @@ -11376,7 +11856,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) aggsig); appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n", - aggsig, details->data); + aggfullsig ? aggfullsig : aggsig, details->data); appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig); @@ -11404,7 +11884,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) /* * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL * command look like a function's GRANT; in particular this affects the - * syntax for zero-argument aggregates. + * syntax for zero-argument aggregates and ordered-set aggregates. */ free(aggsig); free(aggsig_tag); @@ -11419,6 +11899,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo) agginfo->aggfn.rolname, agginfo->aggfn.proacl); free(aggsig); + if (aggfullsig) + free(aggfullsig); free(aggsig_tag); PQclear(res); @@ -11541,10 +12023,10 @@ dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo) appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n", fmtId(dictinfo->dobj.name)); - appendPQExpBuffer(q, " TEMPLATE = "); + appendPQExpBufferStr(q, " TEMPLATE = "); if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0) appendPQExpBuffer(q, "%s.", fmtId(nspname)); - appendPQExpBuffer(q, "%s", fmtId(tmplname)); + appendPQExpBufferStr(q, fmtId(tmplname)); PQclear(res); @@ -11552,7 +12034,7 @@ dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo) if (dictinfo->dictinitoption) appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption); - appendPQExpBuffer(q, " );\n"); + appendPQExpBufferStr(q, " );\n"); /* * DROP must be fully qualified in case same name appears in pg_catalog @@ -11698,7 +12180,7 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo) appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n", fmtId(cfginfo->dobj.name)); - appendPQExpBuffer(q, " PARSER = "); + appendPQExpBufferStr(q, " PARSER = "); if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0) appendPQExpBuffer(q, "%s.", fmtId(nspname)); appendPQExpBuffer(q, "%s );\n", fmtId(prsname)); @@ -11732,7 +12214,7 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo) { /* starting a new token type, so start a new command */ if (i > 0) - appendPQExpBuffer(q, ";\n"); + appendPQExpBufferStr(q, ";\n"); appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n", fmtId(cfginfo->dobj.name)); /* tokenname needs quoting, dictname does NOT */ @@ -11744,7 +12226,7 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo) } if (ntups > 0) - appendPQExpBuffer(q, ";\n"); + appendPQExpBufferStr(q, ";\n"); PQclear(res); @@ -11825,7 +12307,7 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo) if (strlen(fdwinfo->fdwoptions) > 0) appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions); - appendPQExpBuffer(q, ";\n"); + appendPQExpBufferStr(q, ";\n"); appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n", qfdwname); @@ -11903,22 +12385,22 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo) appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname); if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0) { - appendPQExpBuffer(q, " TYPE "); + appendPQExpBufferStr(q, " TYPE "); appendStringLiteralAH(q, srvinfo->srvtype, fout); } if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0) { - appendPQExpBuffer(q, " VERSION "); + appendPQExpBufferStr(q, " VERSION "); appendStringLiteralAH(q, srvinfo->srvversion, fout); } - appendPQExpBuffer(q, " FOREIGN DATA WRAPPER "); - appendPQExpBuffer(q, "%s", fmtId(fdwname)); + appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER "); + appendPQExpBufferStr(q, fmtId(fdwname)); if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0) appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions); - appendPQExpBuffer(q, ";\n"); + appendPQExpBufferStr(q, ";\n"); appendPQExpBuffer(delq, "DROP SERVER %s;\n", qsrvname); @@ -12035,7 +12517,7 @@ dumpUserMappings(Archive *fout, if (umoptions && strlen(umoptions) > 0) appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions); - appendPQExpBuffer(q, ";\n"); + appendPQExpBufferStr(q, ";\n"); resetPQExpBuffer(delq); appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename)); @@ -12060,6 +12542,7 @@ dumpUserMappings(Archive *fout, destroyPQExpBuffer(query); destroyPQExpBuffer(delq); + destroyPQExpBuffer(tag); destroyPQExpBuffer(q); } @@ -12097,7 +12580,7 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo) default: /* shouldn't get here */ exit_horribly(NULL, - "unrecognized object type in default privileges: %d\n", + "unrecognized object type in default privileges: %d\n", (int) daclinfo->defaclobjtype); type = ""; /* keep compiler quiet */ } @@ -12244,7 +12727,7 @@ dumpSecLabel(Archive *fout, const char *target, "SECURITY LABEL FOR %s ON %s IS ", fmtId(labels[i].provider), target); appendStringLiteralAH(query, labels[i].label, fout); - appendPQExpBuffer(query, ";\n"); + appendPQExpBufferStr(query, ";\n"); } if (query->len > 0) @@ -12318,7 +12801,7 @@ dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename) appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ", fmtId(provider), target->data); appendStringLiteralAH(query, label, fout); - appendPQExpBuffer(query, ";\n"); + appendPQExpBufferStr(query, ";\n"); } if (query->len > 0) { @@ -12448,10 +12931,10 @@ collectSecLabels(Archive *fout, SecLabelItem **items) query = createPQExpBuffer(); - appendPQExpBuffer(query, - "SELECT label, provider, classoid, objoid, objsubid " - "FROM pg_catalog.pg_seclabel " - "ORDER BY classoid, objoid, objsubid"); + appendPQExpBufferStr(query, + "SELECT label, provider, classoid, objoid, objsubid " + "FROM pg_catalog.pg_seclabel " + "ORDER BY classoid, objoid, objsubid"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -12533,8 +13016,7 @@ dumpTable(Archive *fout, TableInfo *tbinfo) char *acltag; attnamecopy = pg_strdup(fmtId(attname)); - acltag = pg_malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2); - sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname); + acltag = psprintf("%s.%s", tbinfo->dobj.name, attname); /* Column's GRANT type is always TABLE */ dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE", namecopy, attnamecopy, acltag, @@ -12570,15 +13052,14 @@ createViewAsClause(Archive *fout, TableInfo *tbinfo) { /* Beginning in 7.3, viewname is not unique; rely on OID */ appendPQExpBuffer(query, - "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef", + "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef", tbinfo->dobj.catId.oid); } else { - appendPQExpBuffer(query, "SELECT definition AS viewdef " - "FROM pg_views WHERE viewname = "); + appendPQExpBufferStr(query, "SELECT definition AS viewdef " + "FROM pg_views WHERE viewname = "); appendStringLiteralAH(query, tbinfo->dobj.name, fout); - appendPQExpBuffer(query, ";"); } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -12600,7 +13081,7 @@ createViewAsClause(Archive *fout, TableInfo *tbinfo) tbinfo->dobj.name); /* Strip off the trailing semicolon so that other things may follow. */ - Assert(PQgetvalue(res, 0, 0)[len-1] == ';'); + Assert(PQgetvalue(res, 0, 0)[len - 1] == ';'); appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1); PQclear(res); @@ -12660,9 +13141,13 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions); result = createViewAsClause(fout, tbinfo); - appendPQExpBuffer(q, " AS\n%s;\n", result->data); + appendPQExpBuffer(q, " AS\n%s", result->data); destroyPQExpBuffer(result); + if (tbinfo->checkoption != NULL) + appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption); + appendPQExpBufferStr(q, ";\n"); + appendPQExpBuffer(labelq, "VIEW %s", fmtId(tbinfo->dobj.name)); } @@ -12671,37 +13156,37 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) switch (tbinfo->relkind) { case (RELKIND_FOREIGN_TABLE): - { - PQExpBuffer query = createPQExpBuffer(); - PGresult *res; - int i_srvname; - int i_ftoptions; - - reltypename = "FOREIGN TABLE"; - - /* retrieve name of foreign server and generic options */ - appendPQExpBuffer(query, - "SELECT fs.srvname, " - "pg_catalog.array_to_string(ARRAY(" - "SELECT pg_catalog.quote_ident(option_name) || " - "' ' || pg_catalog.quote_literal(option_value) " - "FROM pg_catalog.pg_options_to_table(ftoptions) " - "ORDER BY option_name" - "), E',\n ') AS ftoptions " - "FROM pg_catalog.pg_foreign_table ft " - "JOIN pg_catalog.pg_foreign_server fs " - "ON (fs.oid = ft.ftserver) " - "WHERE ft.ftrelid = '%u'", - tbinfo->dobj.catId.oid); - res = ExecuteSqlQueryForSingleRow(fout, query->data); - i_srvname = PQfnumber(res, "srvname"); - i_ftoptions = PQfnumber(res, "ftoptions"); - srvname = pg_strdup(PQgetvalue(res, 0, i_srvname)); - ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions)); - PQclear(res); - destroyPQExpBuffer(query); - break; - } + { + PQExpBuffer query = createPQExpBuffer(); + PGresult *res; + int i_srvname; + int i_ftoptions; + + reltypename = "FOREIGN TABLE"; + + /* retrieve name of foreign server and generic options */ + appendPQExpBuffer(query, + "SELECT fs.srvname, " + "pg_catalog.array_to_string(ARRAY(" + "SELECT pg_catalog.quote_ident(option_name) || " + "' ' || pg_catalog.quote_literal(option_value) " + "FROM pg_catalog.pg_options_to_table(ftoptions) " + "ORDER BY option_name" + "), E',\n ') AS ftoptions " + "FROM pg_catalog.pg_foreign_table ft " + "JOIN pg_catalog.pg_foreign_server fs " + "ON (fs.oid = ft.ftserver) " + "WHERE ft.ftrelid = '%u'", + tbinfo->dobj.catId.oid); + res = ExecuteSqlQueryForSingleRow(fout, query->data); + i_srvname = PQfnumber(res, "srvname"); + i_ftoptions = PQfnumber(res, "ftoptions"); + srvname = pg_strdup(PQgetvalue(res, 0, i_srvname)); + ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions)); + PQclear(res); + destroyPQExpBuffer(query); + break; + } case (RELKIND_MATVIEW): reltypename = "MATERIALIZED VIEW"; srvname = NULL; @@ -12747,156 +13232,155 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) if (tbinfo->relkind != RELKIND_MATVIEW) { - /* Dump the attributes */ - actual_atts = 0; - for (j = 0; j < tbinfo->numatts; j++) - { - /* - * Normally, dump if it's locally defined in this table, and not - * dropped. But for binary upgrade, we'll dump all the columns, - * and then fix up the dropped and nonlocal cases below. - */ - if (shouldPrintColumn(tbinfo, j)) + /* Dump the attributes */ + actual_atts = 0; + for (j = 0; j < tbinfo->numatts; j++) { /* - * Default value --- suppress if to be printed separately. + * Normally, dump if it's locally defined in this table, and + * not dropped. But for binary upgrade, we'll dump all the + * columns, and then fix up the dropped and nonlocal cases + * below. */ - bool has_default = (tbinfo->attrdefs[j] != NULL && - !tbinfo->attrdefs[j]->separate); - - /* - * Not Null constraint --- suppress if inherited, except in - * binary-upgrade case where that won't work. - */ - bool has_notnull = (tbinfo->notnull[j] && - (!tbinfo->inhNotNull[j] || - binary_upgrade)); - - /* Skip column if fully defined by reloftype */ - if (tbinfo->reloftype && - !has_default && !has_notnull && !binary_upgrade) - continue; - - /* Format properly if not first attr */ - if (actual_atts == 0) - appendPQExpBuffer(q, " ("); - else - appendPQExpBuffer(q, ","); - appendPQExpBuffer(q, "\n "); - actual_atts++; - - /* Attribute name */ - appendPQExpBuffer(q, "%s", - fmtId(tbinfo->attnames[j])); - - if (tbinfo->attisdropped[j]) + if (shouldPrintColumn(tbinfo, j)) { /* - * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid, - * so we will not have gotten a valid type name; insert - * INTEGER as a stopgap. We'll clean things up later. + * Default value --- suppress if to be printed separately. */ - appendPQExpBuffer(q, " INTEGER /* dummy */"); - /* Skip all the rest, too */ - continue; - } + bool has_default = (tbinfo->attrdefs[j] != NULL && + !tbinfo->attrdefs[j]->separate); - /* Attribute type */ - if (tbinfo->reloftype && !binary_upgrade) - { - appendPQExpBuffer(q, " WITH OPTIONS"); - } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(q, " %s", - tbinfo->atttypnames[j]); - } - else - { - /* If no format_type, fake it */ - appendPQExpBuffer(q, " %s", - myFormatType(tbinfo->atttypnames[j], - tbinfo->atttypmod[j])); - } + /* + * Not Null constraint --- suppress if inherited, except + * in binary-upgrade case where that won't work. + */ + bool has_notnull = (tbinfo->notnull[j] && + (!tbinfo->inhNotNull[j] || + binary_upgrade)); + + /* Skip column if fully defined by reloftype */ + if (tbinfo->reloftype && + !has_default && !has_notnull && !binary_upgrade) + continue; + + /* Format properly if not first attr */ + if (actual_atts == 0) + appendPQExpBufferStr(q, " ("); + else + appendPQExpBufferStr(q, ","); + appendPQExpBufferStr(q, "\n "); + actual_atts++; - /* Add collation if not default for the type */ - if (OidIsValid(tbinfo->attcollation[j])) - { - CollInfo *coll; + /* Attribute name */ + appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j])); + + if (tbinfo->attisdropped[j]) + { + /* + * ALTER TABLE DROP COLUMN clears + * pg_attribute.atttypid, so we will not have gotten a + * valid type name; insert INTEGER as a stopgap. We'll + * clean things up later. + */ + appendPQExpBufferStr(q, " INTEGER /* dummy */"); + /* Skip all the rest, too */ + continue; + } + + /* Attribute type */ + if (tbinfo->reloftype && !binary_upgrade) + { + appendPQExpBufferStr(q, " WITH OPTIONS"); + } + else if (fout->remoteVersion >= 70100) + { + appendPQExpBuffer(q, " %s", + tbinfo->atttypnames[j]); + } + else + { + /* If no format_type, fake it */ + appendPQExpBuffer(q, " %s", + myFormatType(tbinfo->atttypnames[j], + tbinfo->atttypmod[j])); + } - coll = findCollationByOid(tbinfo->attcollation[j]); - if (coll) + /* Add collation if not default for the type */ + if (OidIsValid(tbinfo->attcollation[j])) { - /* always schema-qualify, don't try to be smart */ - appendPQExpBuffer(q, " COLLATE %s.", + CollInfo *coll; + + coll = findCollationByOid(tbinfo->attcollation[j]); + if (coll) + { + /* always schema-qualify, don't try to be smart */ + appendPQExpBuffer(q, " COLLATE %s.", fmtId(coll->dobj.namespace->dobj.name)); - appendPQExpBuffer(q, "%s", - fmtId(coll->dobj.name)); + appendPQExpBufferStr(q, fmtId(coll->dobj.name)); + } } - } - if (has_default) - appendPQExpBuffer(q, " DEFAULT %s", - tbinfo->attrdefs[j]->adef_expr); + if (has_default) + appendPQExpBuffer(q, " DEFAULT %s", + tbinfo->attrdefs[j]->adef_expr); - if (has_notnull) - appendPQExpBuffer(q, " NOT NULL"); + if (has_notnull) + appendPQExpBufferStr(q, " NOT NULL"); + } } - } - /* - * Add non-inherited CHECK constraints, if any. - */ - for (j = 0; j < tbinfo->ncheck; j++) - { - ConstraintInfo *constr = &(tbinfo->checkexprs[j]); + /* + * Add non-inherited CHECK constraints, if any. + */ + for (j = 0; j < tbinfo->ncheck; j++) + { + ConstraintInfo *constr = &(tbinfo->checkexprs[j]); - if (constr->separate || !constr->conislocal) - continue; + if (constr->separate || !constr->conislocal) + continue; - if (actual_atts == 0) - appendPQExpBuffer(q, " (\n "); - else - appendPQExpBuffer(q, ",\n "); + if (actual_atts == 0) + appendPQExpBufferStr(q, " (\n "); + else + appendPQExpBufferStr(q, ",\n "); - appendPQExpBuffer(q, "CONSTRAINT %s ", - fmtId(constr->dobj.name)); - appendPQExpBuffer(q, "%s", constr->condef); + appendPQExpBuffer(q, "CONSTRAINT %s ", + fmtId(constr->dobj.name)); + appendPQExpBufferStr(q, constr->condef); - actual_atts++; - } + actual_atts++; + } - if (actual_atts) - appendPQExpBuffer(q, "\n)"); - else if (!(tbinfo->reloftype && !binary_upgrade)) - { - /* - * We must have a parenthesized attribute list, even though empty, - * when not using the OF TYPE syntax. - */ - appendPQExpBuffer(q, " (\n)"); - } + if (actual_atts) + appendPQExpBufferStr(q, "\n)"); + else if (!(tbinfo->reloftype && !binary_upgrade)) + { + /* + * We must have a parenthesized attribute list, even though + * empty, when not using the OF TYPE syntax. + */ + appendPQExpBufferStr(q, " (\n)"); + } - if (numParents > 0 && !binary_upgrade) - { - appendPQExpBuffer(q, "\nINHERITS ("); - for (k = 0; k < numParents; k++) + if (numParents > 0 && !binary_upgrade) { - TableInfo *parentRel = parents[k]; + appendPQExpBufferStr(q, "\nINHERITS ("); + for (k = 0; k < numParents; k++) + { + TableInfo *parentRel = parents[k]; - if (k > 0) - appendPQExpBuffer(q, ", "); - if (parentRel->dobj.namespace != tbinfo->dobj.namespace) - appendPQExpBuffer(q, "%s.", + if (k > 0) + appendPQExpBufferStr(q, ", "); + if (parentRel->dobj.namespace != tbinfo->dobj.namespace) + appendPQExpBuffer(q, "%s.", fmtId(parentRel->dobj.namespace->dobj.name)); - appendPQExpBuffer(q, "%s", - fmtId(parentRel->dobj.name)); + appendPQExpBufferStr(q, fmtId(parentRel->dobj.name)); + } + appendPQExpBufferChar(q, ')'); } - appendPQExpBuffer(q, ")"); - } - if (tbinfo->relkind == RELKIND_FOREIGN_TABLE) - appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname)); + if (tbinfo->relkind == RELKIND_FOREIGN_TABLE) + appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname)); } if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) || @@ -12904,18 +13388,18 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) { bool addcomma = false; - appendPQExpBuffer(q, "\nWITH ("); + appendPQExpBufferStr(q, "\nWITH ("); if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) { addcomma = true; - appendPQExpBuffer(q, "%s", tbinfo->reloptions); + appendPQExpBufferStr(q, tbinfo->reloptions); } if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0) { appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "", tbinfo->toast_reloptions); } - appendPQExpBuffer(q, ")"); + appendPQExpBufferChar(q, ')'); } /* Dump generic options if any */ @@ -12923,7 +13407,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions); /* - * For materialized views, create the AS clause just like a view. + * For materialized views, create the AS clause just like a view. At + * this point, we always mark the view as not populated. */ if (tbinfo->relkind == RELKIND_MATVIEW) { @@ -12935,7 +13420,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) destroyPQExpBuffer(result); } else - appendPQExpBuffer(q, ";\n"); + appendPQExpBufferStr(q, ";\n"); /* * To create binary-compatible heap files, we have to ensure the same @@ -12950,13 +13435,14 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) * attislocal correctly, plus fix up any inherited CHECK constraints. * Analogously, we set up typed tables using ALTER TABLE / OF here. */ - if (binary_upgrade && tbinfo->relkind == RELKIND_RELATION) + if (binary_upgrade && (tbinfo->relkind == RELKIND_RELATION || + tbinfo->relkind == RELKIND_FOREIGN_TABLE) ) { for (j = 0; j < tbinfo->numatts; j++) { if (tbinfo->attisdropped[j]) { - appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n"); + appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n"); appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n" "SET attlen = %d, " "attalign = '%c', attbyval = false\n" @@ -12964,25 +13450,31 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) tbinfo->attlen[j], tbinfo->attalign[j]); appendStringLiteralAH(q, tbinfo->attnames[j], fout); - appendPQExpBuffer(q, "\n AND attrelid = "); + appendPQExpBufferStr(q, "\n AND attrelid = "); appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout); - appendPQExpBuffer(q, "::pg_catalog.regclass;\n"); + appendPQExpBufferStr(q, "::pg_catalog.regclass;\n"); + + if (tbinfo->relkind == RELKIND_RELATION) + appendPQExpBuffer(q, "ALTER TABLE ONLY %s ", + fmtId(tbinfo->dobj.name)); + else + appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ", + fmtId(tbinfo->dobj.name)); - appendPQExpBuffer(q, "ALTER TABLE ONLY %s ", - fmtId(tbinfo->dobj.name)); appendPQExpBuffer(q, "DROP COLUMN %s;\n", fmtId(tbinfo->attnames[j])); } else if (!tbinfo->attislocal[j]) { - appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n"); - appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n" + Assert(tbinfo->relkind != RELKIND_FOREIGN_TABLE); + appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n"); + appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n" "SET attislocal = false\n" "WHERE attname = "); appendStringLiteralAH(q, tbinfo->attnames[j], fout); - appendPQExpBuffer(q, "\n AND attrelid = "); + appendPQExpBufferStr(q, "\n AND attrelid = "); appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout); - appendPQExpBuffer(q, "::pg_catalog.regclass;\n"); + appendPQExpBufferStr(q, "::pg_catalog.regclass;\n"); } } @@ -12993,24 +13485,24 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) if (constr->separate || constr->conislocal) continue; - appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n"); + appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n"); appendPQExpBuffer(q, "ALTER TABLE ONLY %s ", fmtId(tbinfo->dobj.name)); appendPQExpBuffer(q, " ADD CONSTRAINT %s ", fmtId(constr->dobj.name)); appendPQExpBuffer(q, "%s;\n", constr->condef); - appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n" + appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n" "SET conislocal = false\n" "WHERE contype = 'c' AND conname = "); appendStringLiteralAH(q, constr->dobj.name, fout); - appendPQExpBuffer(q, "\n AND conrelid = "); + appendPQExpBufferStr(q, "\n AND conrelid = "); appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout); - appendPQExpBuffer(q, "::pg_catalog.regclass;\n"); + appendPQExpBufferStr(q, "::pg_catalog.regclass;\n"); } if (numParents > 0) { - appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n"); + appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n"); for (k = 0; k < numParents; k++) { TableInfo *parentRel = parents[k]; @@ -13027,24 +13519,24 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) if (tbinfo->reloftype) { - appendPQExpBuffer(q, "\n-- For binary upgrade, set up typed tables this way.\n"); + appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n"); appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n", fmtId(tbinfo->dobj.name), tbinfo->reloftype); } - appendPQExpBuffer(q, "\n-- For binary upgrade, set heap's relfrozenxid\n"); + appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid\n"); appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n" "SET relfrozenxid = '%u'\n" "WHERE oid = ", tbinfo->frozenxid); appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout); - appendPQExpBuffer(q, "::pg_catalog.regclass;\n"); + appendPQExpBufferStr(q, "::pg_catalog.regclass;\n"); if (tbinfo->toast_oid) { /* We preserve the toast oids, so we can use it during restore */ - appendPQExpBuffer(q, "\n-- For binary upgrade, set toast's relfrozenxid\n"); + appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid\n"); appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n" "SET relfrozenxid = '%u'\n" "WHERE oid = '%u';\n", @@ -13052,6 +13544,23 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) } } + /* + * In binary_upgrade mode, restore matviews' populated status by + * poking pg_class directly. This is pretty ugly, but we can't use + * REFRESH MATERIALIZED VIEW since it's possible that some underlying + * matview is not populated even though this matview is. + */ + if (binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW && + tbinfo->relispopulated) + { + appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n"); + appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n" + "SET relispopulated = 't'\n" + "WHERE oid = "); + appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout); + appendPQExpBufferStr(q, "::pg_catalog.regclass;\n"); + } + /* * Dump additional per-column properties that we can't handle in the * main CREATE TABLE command. @@ -13159,6 +13668,28 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) } } + /* + * dump properties we only have ALTER TABLE syntax for + */ + if ((tbinfo->relkind == RELKIND_RELATION || tbinfo->relkind == RELKIND_MATVIEW) && + tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT) + { + if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX) + { + /* nothing to do, will be set when the index is dumped */ + } + else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING) + { + appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n", + fmtId(tbinfo->dobj.name)); + } + else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL) + { + appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n", + fmtId(tbinfo->dobj.name)); + } + } + if (binary_upgrade) binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data); @@ -13168,7 +13699,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace, tbinfo->rolname, (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false, - reltypename, SECTION_PRE_DATA, + reltypename, + tbinfo->postponed_def ? SECTION_POST_DATA : SECTION_PRE_DATA, q->data, delq->data, NULL, NULL, 0, NULL, NULL); @@ -13290,6 +13822,7 @@ static void dumpIndex(Archive *fout, IndxInfo *indxinfo) { TableInfo *tbinfo = indxinfo->indextable; + bool is_constraint = (indxinfo->indexconstraint != 0); PQExpBuffer q; PQExpBuffer delq; PQExpBuffer labelq; @@ -13307,9 +13840,11 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) /* * If there's an associated constraint, don't dump the index per se, but * do dump any comment for it. (This is safe because dependency ordering - * will have ensured the constraint is emitted first.) + * will have ensured the constraint is emitted first.) Note that the + * emitted comment has to be shown as depending on the constraint, not + * the index, in such cases. */ - if (indxinfo->indexconstraint == 0) + if (!is_constraint) { if (binary_upgrade) binary_upgrade_set_pg_class_oids(fout, q, @@ -13327,6 +13862,15 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) fmtId(indxinfo->dobj.name)); } + /* If the index defines identity, we need to record that. */ + if (indxinfo->indisreplident) + { + appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING", + fmtId(tbinfo->dobj.name)); + appendPQExpBuffer(q, " INDEX %s;\n", + fmtId(indxinfo->dobj.name)); + } + /* * DROP must be fully qualified in case same name appears in * pg_catalog @@ -13351,7 +13895,9 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) dumpComment(fout, labelq->data, tbinfo->dobj.namespace->dobj.name, tbinfo->rolname, - indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId); + indxinfo->dobj.catId, 0, + is_constraint ? indxinfo->indexconstraint : + indxinfo->dobj.dumpId); destroyPQExpBuffer(q); destroyPQExpBuffer(delq); @@ -13422,19 +13968,19 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) fmtId(attname)); } - appendPQExpBuffer(q, ")"); + appendPQExpBufferChar(q, ')'); if (indxinfo->options && strlen(indxinfo->options) > 0) appendPQExpBuffer(q, " WITH (%s)", indxinfo->options); if (coninfo->condeferrable) { - appendPQExpBuffer(q, " DEFERRABLE"); + appendPQExpBufferStr(q, " DEFERRABLE"); if (coninfo->condeferred) - appendPQExpBuffer(q, " INITIALLY DEFERRED"); + appendPQExpBufferStr(q, " INITIALLY DEFERRED"); } - appendPQExpBuffer(q, ";\n"); + appendPQExpBufferStr(q, ";\n"); } /* If the index is clustered, we need to record that. */ @@ -13627,7 +14173,7 @@ findLastBuiltinOid_V71(Archive *fout, const char *dbname) PQExpBuffer query = createPQExpBuffer(); resetPQExpBuffer(query); - appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = "); + appendPQExpBufferStr(query, "SELECT datlastsysoid from pg_database where datname = "); appendStringLiteralAH(query, dbname, fout); res = ExecuteSqlQueryForSingleRow(fout, query->data); @@ -13779,18 +14325,18 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) if (minv) appendPQExpBuffer(query, " MINVALUE %s\n", minv); else - appendPQExpBuffer(query, " NO MINVALUE\n"); + appendPQExpBufferStr(query, " NO MINVALUE\n"); if (maxv) appendPQExpBuffer(query, " MAXVALUE %s\n", maxv); else - appendPQExpBuffer(query, " NO MAXVALUE\n"); + appendPQExpBufferStr(query, " NO MAXVALUE\n"); appendPQExpBuffer(query, " CACHE %s%s", cache, (cycled ? "\n CYCLE" : "")); - appendPQExpBuffer(query, ";\n"); + appendPQExpBufferStr(query, ";\n"); appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name)); @@ -13812,8 +14358,8 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) /* * 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 + * 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 @@ -13898,7 +14444,7 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo) called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0); resetPQExpBuffer(query); - appendPQExpBuffer(query, "SELECT pg_catalog.setval("); + appendPQExpBufferStr(query, "SELECT pg_catalog.setval("); appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout); appendPQExpBuffer(query, ", %s, %s);\n", last, (called ? "true" : "false")); @@ -13918,6 +14464,10 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo) destroyPQExpBuffer(query); } +/* + * dumpTrigger + * write the declaration of one user-defined table trigger + */ static void dumpTrigger(Archive *fout, TriggerInfo *tginfo) { @@ -13930,6 +14480,10 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) const char *p; int findx; + /* + * we needn't check dobj.dump because TriggerInfo wouldn't have been + * created in the first place for non-dumpable triggers + */ if (dataOnly) return; @@ -13955,23 +14509,23 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) { if (tginfo->tgisconstraint) { - appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER "); + appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER "); appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname)); } else { - appendPQExpBuffer(query, "CREATE TRIGGER "); + appendPQExpBufferStr(query, "CREATE TRIGGER "); appendPQExpBufferStr(query, fmtId(tginfo->dobj.name)); } - appendPQExpBuffer(query, "\n "); + appendPQExpBufferStr(query, "\n "); /* Trigger type */ if (TRIGGER_FOR_BEFORE(tginfo->tgtype)) - appendPQExpBuffer(query, "BEFORE"); + appendPQExpBufferStr(query, "BEFORE"); else if (TRIGGER_FOR_AFTER(tginfo->tgtype)) - appendPQExpBuffer(query, "AFTER"); + appendPQExpBufferStr(query, "AFTER"); else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype)) - appendPQExpBuffer(query, "INSTEAD OF"); + appendPQExpBufferStr(query, "INSTEAD OF"); else { write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype); @@ -13981,31 +14535,31 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) findx = 0; if (TRIGGER_FOR_INSERT(tginfo->tgtype)) { - appendPQExpBuffer(query, " INSERT"); + appendPQExpBufferStr(query, " INSERT"); findx++; } if (TRIGGER_FOR_DELETE(tginfo->tgtype)) { if (findx > 0) - appendPQExpBuffer(query, " OR DELETE"); + appendPQExpBufferStr(query, " OR DELETE"); else - appendPQExpBuffer(query, " DELETE"); + appendPQExpBufferStr(query, " DELETE"); findx++; } if (TRIGGER_FOR_UPDATE(tginfo->tgtype)) { if (findx > 0) - appendPQExpBuffer(query, " OR UPDATE"); + appendPQExpBufferStr(query, " OR UPDATE"); else - appendPQExpBuffer(query, " UPDATE"); + appendPQExpBufferStr(query, " UPDATE"); findx++; } if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype)) { if (findx > 0) - appendPQExpBuffer(query, " OR TRUNCATE"); + appendPQExpBufferStr(query, " OR TRUNCATE"); else - appendPQExpBuffer(query, " TRUNCATE"); + appendPQExpBufferStr(query, " TRUNCATE"); findx++; } appendPQExpBuffer(query, " ON %s\n", @@ -14024,18 +14578,18 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) fmtId(tginfo->tgconstrrelname)); } if (!tginfo->tgdeferrable) - appendPQExpBuffer(query, "NOT "); - appendPQExpBuffer(query, "DEFERRABLE INITIALLY "); + appendPQExpBufferStr(query, "NOT "); + appendPQExpBufferStr(query, "DEFERRABLE INITIALLY "); if (tginfo->tginitdeferred) - appendPQExpBuffer(query, "DEFERRED\n"); + appendPQExpBufferStr(query, "DEFERRED\n"); else - appendPQExpBuffer(query, "IMMEDIATE\n"); + appendPQExpBufferStr(query, "IMMEDIATE\n"); } if (TRIGGER_FOR_ROW(tginfo->tgtype)) - appendPQExpBuffer(query, " FOR EACH ROW\n "); + appendPQExpBufferStr(query, " FOR EACH ROW\n "); else - appendPQExpBuffer(query, " FOR EACH STATEMENT\n "); + appendPQExpBufferStr(query, " FOR EACH STATEMENT\n "); /* In 7.3, result of regproc is already quoted */ if (fout->remoteVersion >= 70300) @@ -14064,12 +14618,12 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) } if (findx > 0) - appendPQExpBuffer(query, ", "); + appendPQExpBufferStr(query, ", "); appendStringLiteralAH(query, p, fout); p += tlen + 1; } free(tgargs); - appendPQExpBuffer(query, ");\n"); + appendPQExpBufferStr(query, ");\n"); } if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O') @@ -14080,16 +14634,16 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) { case 'D': case 'f': - appendPQExpBuffer(query, "DISABLE"); + appendPQExpBufferStr(query, "DISABLE"); break; case 'A': - appendPQExpBuffer(query, "ENABLE ALWAYS"); + appendPQExpBufferStr(query, "ENABLE ALWAYS"); break; case 'R': - appendPQExpBuffer(query, "ENABLE REPLICA"); + appendPQExpBufferStr(query, "ENABLE REPLICA"); break; default: - appendPQExpBuffer(query, "ENABLE"); + appendPQExpBufferStr(query, "ENABLE"); break; } appendPQExpBuffer(query, " TRIGGER %s;\n", @@ -14120,18 +14674,26 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) destroyPQExpBuffer(labelq); } +/* + * dumpEventTrigger + * write the declaration of one user-defined event trigger + */ static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo) { PQExpBuffer query; PQExpBuffer labelq; + /* Skip if not to be dumped */ + if (!evtinfo->dobj.dump || dataOnly) + return; + query = createPQExpBuffer(); labelq = createPQExpBuffer(); - appendPQExpBuffer(query, "CREATE EVENT TRIGGER "); + appendPQExpBufferStr(query, "CREATE EVENT TRIGGER "); appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name)); - appendPQExpBuffer(query, " ON "); + appendPQExpBufferStr(query, " ON "); appendPQExpBufferStr(query, fmtId(evtinfo->evtevent)); appendPQExpBufferStr(query, " "); @@ -14142,9 +14704,9 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo) appendPQExpBufferStr(query, ") "); } - appendPQExpBuffer(query, "\n EXECUTE PROCEDURE "); + appendPQExpBufferStr(query, "\n EXECUTE PROCEDURE "); appendPQExpBufferStr(query, evtinfo->evtfname); - appendPQExpBuffer(query, "();\n"); + appendPQExpBufferStr(query, "();\n"); if (evtinfo->evtenabled != 'O') { @@ -14153,19 +14715,19 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo) switch (evtinfo->evtenabled) { case 'D': - appendPQExpBuffer(query, "DISABLE"); + appendPQExpBufferStr(query, "DISABLE"); break; case 'A': - appendPQExpBuffer(query, "ENABLE ALWAYS"); + appendPQExpBufferStr(query, "ENABLE ALWAYS"); break; case 'R': - appendPQExpBuffer(query, "ENABLE REPLICA"); + appendPQExpBufferStr(query, "ENABLE REPLICA"); break; default: - appendPQExpBuffer(query, "ENABLE"); + appendPQExpBufferStr(query, "ENABLE"); break; } - appendPQExpBuffer(query, ";\n"); + appendPQExpBufferStr(query, ";\n"); } appendPQExpBuffer(labelq, "EVENT TRIGGER %s ", fmtId(evtinfo->dobj.name)); @@ -14344,12 +14906,12 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], query = createPQExpBuffer(); /* refclassid constraint is redundant but may speed the search */ - appendPQExpBuffer(query, "SELECT " - "classid, objid, refclassid, refobjid " - "FROM pg_depend " - "WHERE refclassid = 'pg_extension'::regclass " - "AND deptype = 'e' " - "ORDER BY 3,4"); + appendPQExpBufferStr(query, "SELECT " + "classid, objid, refclassid, refobjid " + "FROM pg_depend " + "WHERE refclassid = 'pg_extension'::regclass " + "AND deptype = 'e' " + "ORDER BY 3,4"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -14445,10 +15007,6 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int nconfigitems; int nconditionitems; - /* Tables of not-to-be-dumped extensions shouldn't be dumped */ - if (!curext->dobj.dump) - continue; - if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) && parsePGArray(extcondition, &extconditionarray, &nconditionitems) && nconfigitems == nconditionitems) @@ -14458,21 +15016,54 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], for (j = 0; j < nconfigitems; j++) { TableInfo *configtbl; + Oid configtbloid = atooid(extconfigarray[j]); + bool dumpobj = curext->dobj.dump; - configtbl = findTableByOid(atooid(extconfigarray[j])); + configtbl = findTableByOid(configtbloid); if (configtbl == NULL) continue; /* - * Note: config tables are dumped without OIDs regardless of - * the --oids setting. This is because row filtering - * conditions aren't compatible with dumping OIDs. + * Tables of not-to-be-dumped extensions shouldn't be dumped + * unless the table or its schema is explicitly included */ - makeTableDataInfo(configtbl, false); - if (configtbl->dataObj != NULL) + if (!curext->dobj.dump) + { + /* check table explicitly requested */ + if (table_include_oids.head != NULL && + simple_oid_list_member(&table_include_oids, + configtbloid)) + dumpobj = true; + + /* check table's schema explicitly requested */ + if (configtbl->dobj.namespace->dobj.dump) + dumpobj = true; + } + + /* check table excluded by an exclusion switch */ + if (table_exclude_oids.head != NULL && + simple_oid_list_member(&table_exclude_oids, + configtbloid)) + dumpobj = false; + + /* check schema excluded by an exclusion switch */ + if (simple_oid_list_member(&schema_exclude_oids, + configtbl->dobj.namespace->dobj.catId.oid)) + dumpobj = false; + + if (dumpobj) { - if (strlen(extconditionarray[j]) > 0) - configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]); + /* + * Note: config tables are dumped without OIDs regardless + * of the --oids setting. This is because row filtering + * conditions aren't compatible with dumping OIDs. + */ + makeTableDataInfo(configtbl, false); + if (configtbl->dataObj != NULL) + { + if (strlen(extconditionarray[j]) > 0) + configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]); + } } } } @@ -14519,11 +15110,11 @@ getDependencies(Archive *fout) * PIN dependencies aren't interesting, and EXTENSION dependencies were * already processed by getExtensionMembership. */ - appendPQExpBuffer(query, "SELECT " - "classid, objid, refclassid, refobjid, deptype " - "FROM pg_depend " - "WHERE deptype != 'p' AND deptype != 'e' " - "ORDER BY 1,2"); + appendPQExpBufferStr(query, "SELECT " + "classid, objid, refclassid, refobjid, deptype " + "FROM pg_depend " + "WHERE deptype != 'p' AND deptype != 'e' " + "ORDER BY 1,2"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -14722,7 +15313,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs, * chains linking through objects that don't appear explicitly in the dump. * For example, a view will depend on its _RETURN rule while the _RETURN rule * will depend on other objects --- but the rule will not appear as a separate - * object in the dump. We need to adjust the view's dependencies to include + * object in the dump. We need to adjust the view's dependencies to include * whatever the rule depends on that is included in the dump. * * Just to make things more complicated, there are also "special" dependencies @@ -14810,7 +15401,7 @@ findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj, { *allocDeps *= 2; *dependencies = (DumpId *) pg_realloc(*dependencies, - *allocDeps * sizeof(DumpId)); + *allocDeps * sizeof(DumpId)); } (*dependencies)[*nDeps] = depid; (*nDeps)++; @@ -14818,9 +15409,9 @@ findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj, else { /* - * Object will not be dumped, so recursively consider its deps. - * We rely on the assumption that sortDumpableObjects already - * broke any dependency loops, else we might recurse infinitely. + * Object will not be dumped, so recursively consider its deps. We + * rely on the assumption that sortDumpableObjects already broke + * any dependency loops, else we might recurse infinitely. */ DumpableObject *otherdobj = findObjectByDumpId(depid); @@ -14843,35 +15434,31 @@ findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj, * * Whenever the selected schema is not pg_catalog, be careful to qualify * references to system catalogs and types in our emitted commands! + * + * This function is called only from selectSourceSchemaOnAH and + * selectSourceSchema. */ static void selectSourceSchema(Archive *fout, const char *schemaName) { - static char *curSchemaName = NULL; PQExpBuffer query; + /* This is checked by the callers already */ + Assert(schemaName != NULL && *schemaName != '\0'); + /* Not relevant if fetching from pre-7.3 DB */ if (fout->remoteVersion < 70300) return; - /* Ignore null schema names */ - if (schemaName == NULL || *schemaName == '\0') - return; - /* Optimize away repeated selection of same schema */ - if (curSchemaName && strcmp(curSchemaName, schemaName) == 0) - return; query = createPQExpBuffer(); appendPQExpBuffer(query, "SET search_path = %s", fmtId(schemaName)); if (strcmp(schemaName, "pg_catalog") != 0) - appendPQExpBuffer(query, ", pg_catalog"); + appendPQExpBufferStr(query, ", pg_catalog"); ExecuteSqlStatement(fout, query->data); destroyPQExpBuffer(query); - if (curSchemaName) - free(curSchemaName); - curSchemaName = pg_strdup(schemaName); } /* @@ -14960,21 +15547,21 @@ myFormatType(const char *typname, int32 typmod) { int len = (typmod - VARHDRSZ); - appendPQExpBuffer(buf, "character"); + appendPQExpBufferStr(buf, "character"); if (len > 1) appendPQExpBuffer(buf, "(%d)", typmod - VARHDRSZ); } else if (strcmp(typname, "varchar") == 0) { - appendPQExpBuffer(buf, "character varying"); + appendPQExpBufferStr(buf, "character varying"); if (typmod != -1) appendPQExpBuffer(buf, "(%d)", typmod - VARHDRSZ); } else if (strcmp(typname, "numeric") == 0) { - appendPQExpBuffer(buf, "numeric"); + appendPQExpBufferStr(buf, "numeric"); if (typmod != -1) { int32 tmp_typmod; @@ -14994,13 +15581,13 @@ myFormatType(const char *typname, int32 typmod) * through with quotes. - thomas 1998-12-13 */ else if (strcmp(typname, "char") == 0) - appendPQExpBuffer(buf, "\"char\""); + appendPQExpBufferStr(buf, "\"char\""); else - appendPQExpBuffer(buf, "%s", fmtId(typname)); + appendPQExpBufferStr(buf, fmtId(typname)); /* Append array qualifier for array types */ if (isarray) - appendPQExpBuffer(buf, "[]"); + appendPQExpBufferStr(buf, "[]"); result = pg_strdup(buf->data); destroyPQExpBuffer(buf); @@ -15008,34 +15595,6 @@ myFormatType(const char *typname, int32 typmod) return result; } -/* - * fmtQualifiedId - convert a qualified name to the proper format for - * the source database. - * - * Like fmtId, use the result before calling again. - */ -static const char * -fmtQualifiedId(Archive *fout, const char *schema, const char *id) -{ - static PQExpBuffer id_return = NULL; - - if (id_return) /* first time through? */ - resetPQExpBuffer(id_return); - else - id_return = createPQExpBuffer(); - - /* Suppress schema name if fetching from pre-7.3 DB */ - if (fout->remoteVersion >= 70300 && schema && *schema) - { - appendPQExpBuffer(id_return, "%s.", - fmtId(schema)); - } - appendPQExpBuffer(id_return, "%s", - fmtId(id)); - - return id_return->data; -} - /* * Return a column list clause for the given relation. * @@ -15043,37 +15602,31 @@ fmtQualifiedId(Archive *fout, const char *schema, const char *id) * "", not an invalid "()" column list. */ static const char * -fmtCopyColumnList(const TableInfo *ti) +fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer) { - static PQExpBuffer q = NULL; int numatts = ti->numatts; char **attnames = ti->attnames; bool *attisdropped = ti->attisdropped; bool needComma; int i; - if (q) /* first time through? */ - resetPQExpBuffer(q); - else - q = createPQExpBuffer(); - - appendPQExpBuffer(q, "("); + appendPQExpBufferChar(buffer, '('); needComma = false; for (i = 0; i < numatts; i++) { if (attisdropped[i]) continue; if (needComma) - appendPQExpBuffer(q, ", "); - appendPQExpBuffer(q, "%s", fmtId(attnames[i])); + appendPQExpBufferStr(buffer, ", "); + appendPQExpBufferStr(buffer, fmtId(attnames[i])); needComma = true; } if (!needComma) return ""; /* no undropped columns */ - appendPQExpBuffer(q, ")"); - return q->data; + appendPQExpBufferChar(buffer, ')'); + return buffer->data; } /*