typedefstruct
{
Oid roleoid; /* role's OID */ constchar *rolename; /* role's name */
} RoleNameItem;
typedefstruct
{ constchar *descr; /* comment for an object */
Oid classoid; /* object class (catalog OID) */
Oid objoid; /* object OID */ int objsubid; /* subobject (table column #) */
} CommentItem;
typedefstruct
{ constchar *provider; /* label provider of this security label */ constchar *label; /* security label for an object */
Oid classoid; /* object class (catalog OID) */
Oid objoid; /* object OID */ int objsubid; /* subobject (table column #) */
} SecLabelItem;
typedefstruct
{
Oid oid; /* object OID */ char relkind; /* object kind */
RelFileNumber relfilenumber; /* object filenode */
Oid toast_oid; /* toast table OID */
RelFileNumber toast_relfilenumber; /* toast table filenode */
Oid toast_index_oid; /* toast table index OID */
RelFileNumber toast_index_relfilenumber; /* toast table index filenode */
} BinaryUpgradeClassOidItem;
case10: /* rows per insert */ if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
&dopt.dump_inserts))
exit_nicely(1); break;
case11: /* include foreign data */
simple_string_list_append(&foreign_servers_include_patterns,
optarg); break;
case12: /* include table(s) and their children */
simple_string_list_append(&table_include_patterns_and_children,
optarg);
dopt.include_everything = false; break;
case13: /* exclude table(s) and their children */
simple_string_list_append(&table_exclude_patterns_and_children,
optarg); break;
case14: /* exclude data of table(s) and children */
simple_string_list_append(&tabledata_exclude_patterns_and_children,
optarg); break;
case15: if (!parse_sync_method(optarg, &sync_method))
exit_nicely(1); break;
/* Complain if any arguments remain */ if (optind < argc)
{
pg_log_error("too many command-line arguments (first is \"%s\")",
argv[optind]);
pg_log_error_hint("Try \"%s --help\" for more information.", progname);
exit_nicely(1);
}
/* reject conflicting "-only" options */ if (data_only && schema_only)
pg_fatal("options %s and %s cannot be used together", "-s/--schema-only", "-a/--data-only"); if (schema_only && statistics_only)
pg_fatal("options %s and %s cannot be used together", "-s/--schema-only", "--statistics-only"); if (data_only && statistics_only)
pg_fatal("options %s and %s cannot be used together", "-a/--data-only", "--statistics-only");
/* reject conflicting "-only" and "no-" options */ if (data_only && no_data)
pg_fatal("options %s and %s cannot be used together", "-a/--data-only", "--no-data"); if (schema_only && no_schema)
pg_fatal("options %s and %s cannot be used together", "-s/--schema-only", "--no-schema"); if (statistics_only && no_statistics)
pg_fatal("options %s and %s cannot be used together", "--statistics-only", "--no-statistics");
/* reject conflicting "no-" options */ if (with_statistics && no_statistics)
pg_fatal("options %s and %s cannot be used together", "--statistics", "--no-statistics");
/* reject conflicting "-only" options */ if (data_only && with_statistics)
pg_fatal("options %s and %s cannot be used together", "-a/--data-only", "--statistics"); if (schema_only && with_statistics)
pg_fatal("options %s and %s cannot be used together", "-s/--schema-only", "--statistics");
if (schema_only && foreign_servers_include_patterns.head != NULL)
pg_fatal("options %s and %s cannot be used together", "-s/--schema-only", "--include-foreign-data");
if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
pg_fatal("option %s is not supported with parallel backup", "--include-foreign-data");
if (data_only && dopt.outputClean)
pg_fatal("options %s and %s cannot be used together", "-c/--clean", "-a/--data-only");
/* Identify archive format to emit */
archiveFormat = parseArchiveFormat(format, &archiveMode);
/* archiveFormat specific setup */ if (archiveFormat == archNull)
{
plainText = 1;
/* *Ifyoudon'tprovidearestrictkey,onewillbeappointedforyou.
*/ if (!dopt.restrict_key)
dopt.restrict_key = generate_restrict_key(); if (!dopt.restrict_key)
pg_fatal("could not generate restrict key"); if (!valid_restrict_key(dopt.restrict_key))
pg_fatal("invalid restrict key");
} elseif (dopt.restrict_key)
pg_fatal("option %s can only be used with %s", "--restrict-key", "--format=plain");
error_detail = supports_compression(compression_spec); if (error_detail != NULL)
pg_fatal("%s", error_detail);
/* *Disablesupportforzstdworkersfornow-thesearebasedon *threading,andit'sunclearhowitinteractswithparalleldumpson *platformswherethatreliesonthreadstoo(e.g.Windows).
*/ if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
pg_log_warning("compression option \"%s\" is not currently supported by pg_dump", "workers");
/* *Ifemittinganarchiveformat,wealwayswanttoemitaDATABASEitem, *incase--createisspecifiedatpg_restoretime.
*/ if (!plainText)
dopt.outputCreateDB = 1;
/* Parallel backup only in the directory archive format so far */ if (archiveFormat != archDirectory && numWorkers > 1)
pg_fatal("parallel backup only supported by the directory format");
/* Open the output file */
fout = CreateArchive(filename, archiveFormat, compression_spec,
dosync, archiveMode, setupDumpWorker, sync_method);
/* Make dump options accessible right away */
SetArchiveOptions(fout, &dopt, NULL);
/* Register the cleanup hook */
on_exit_close_archive(fout);
/* Let the archiver know how noisy to be */
fout->verbose = g_verbose;
/* *CollectACLs,comments,andsecuritylabels,ifwanted.
*/ if (!dopt.aclsSkip)
getAdditionalACLs(fout); if (!dopt.no_comments)
collectComments(fout); if (!dopt.no_security_labels)
collectSecLabels(fout);
/* For binary upgrade mode, collect required pg_class information. */ if (dopt.binary_upgrade)
collectBinaryUpgradeClassOids(fout);
ropt->suppressDumpWarnings = true; /* We've already shown them */
SetArchiveOptions(fout, &dopt, ropt);
/* Mark which entries should be output */
ProcessArchiveRestoreOptions(fout);
/* *Thearchive'sTOCentriesarenowmarkedastowhichoneswillactually *beoutput,sowecansetuptheirdependencylistsproperly.Thisisn't *necessaryforplain-textoutput,though.
*/ if (!plainText)
BuildArchiveDependencies(fout);
/* *Andfinallywecandotheactualoutput. * *Note:fornon-plain-textoutputformats,theoutputfileiswritten *insideCloseArchive().Thisis,um,bizarre;butnotworthchanging *rightnow.
*/ if (plainText)
RestoreArchive(fout);
CloseArchive(fout);
exit_nicely(0);
}
staticvoid
help(constchar *progname)
{
printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
printf(_("Usage:\n"));
printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
printf(_("\nGeneral options:\n"));
printf(_(" -f, --file=FILENAME output file or directory name\n"));
printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n" " plain text (default))\n"));
printf(_(" -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=METHOD[:DETAIL]\n" " compress as specified\n"));
printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
printf(_(" -?, --help show this help, then exit\n"));
printf(_("\nOptions controlling the output content:\n"));
printf(_(" -a, --data-only dump only the data, not the schema or statistics\n"));
printf(_(" -b, --large-objects include large objects in dump\n"));
printf(_(" --blobs (same as --large-objects, deprecated)\n"));
printf(_(" -B, --no-large-objects exclude large objects in dump\n"));
printf(_(" --no-blobs (same as --no-large-objects, deprecated)\n"));
printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
printf(_(" -C, --create include commands to create database in dump\n"));
printf(_(" -e, --extension=PATTERN dump the specified extension(s) only\n"));
printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
printf(_(" -n, --schema=PATTERN dump the specified schema(s) only\n"));
printf(_(" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
printf(_(" -O, --no-owner skip restoration of object ownership in\n" " plain-text format\n"));
printf(_(" -s, --schema-only dump only the schema, no data or statistics\n"));
printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
printf(_(" -t, --table=PATTERN dump only the specified table(s)\n"));
printf(_(" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n"));
printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
printf(_(" --disable-triggers disable triggers during data-only restore\n"));
printf(_(" --enable-row-security enable row security (dump only content user has\n" " access to)\n"));
printf(_(" --exclude-extension=PATTERN do NOT dump the specified extension(s)\n"));
printf(_(" --exclude-table-and-children=PATTERN\n" " do NOT dump the specified table(s), including\n" " child and partition tables\n"));
printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
printf(_(" --exclude-table-data-and-children=PATTERN\n" " do NOT dump data for the specified table(s),\n" " including child and partition tables\n"));
printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
printf(_(" --filter=FILENAME include or exclude objects and data from dump\n" " based on expressions in FILENAME\n"));
printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
printf(_(" --include-foreign-data=PATTERN\n" " include data of foreign tables on foreign\n" " servers matching PATTERN\n"));
printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
printf(_(" --load-via-partition-root load partitions via the root table\n"));
printf(_(" --no-comments do not dump comment commands\n"));
printf(_(" --no-data do not dump data\n"));
printf(_(" --no-policies do not dump row security policies\n"));
printf(_(" --no-publications do not dump publications\n"));
printf(_(" --no-schema do not dump schema\n"));
printf(_(" --no-security-labels do not dump security label assignments\n"));
printf(_(" --no-statistics do not dump statistics\n"));
printf(_(" --no-subscriptions do not dump subscriptions\n"));
printf(_(" --no-table-access-method do not dump table access methods\n"));
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
printf(_(" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n"));
printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
printf(_(" --sequence-data include sequence data in dump\n"));
printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
printf(_(" --statistics dump the statistics\n"));
printf(_(" --statistics-only dump only the statistics, not schema or data\n"));
printf(_(" --strict-names require table and/or schema include patterns to\n" " match at least one entity each\n"));
printf(_(" --table-and-children=PATTERN dump only the specified table(s), including\n" " child and partition tables\n"));
printf(_(" --use-set-session-authorization\n" " use SET SESSION AUTHORIZATION commands instead of\n" " ALTER OWNER commands to set ownership\n"));
printf(_("\nConnection options:\n"));
printf(_(" -d, --dbname=DBNAME database to dump\n"));
printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
printf(_(" -p, --port=PORT database server port number\n"));
printf(_(" -U, --username=NAME connect as specified database user\n"));
printf(_(" -w, --no-password never prompt for password\n"));
printf(_(" -W, --password force password prompt (should happen automatically)\n"));
printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n" "variable value is used.\n\n"));
printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
}
/* *Ifuserspecifiedasnapshottouse,selectthat.Inaparalleldump *worker,we'llbepasseddumpsnapshot==NULL,butAH->sync_snapshot_id *isalreadyset(iftheservercanhandleit)andweshouldusethat.
*/ if (dumpsnapshot)
AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
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);
} elseif (AH->numWorkers > 1)
{ if (AH->isStandby && AH->remoteVersion < 100000)
pg_fatal("parallel dumps from standby servers are not supported by this server version");
AH->sync_snapshot_id = get_synchronized_snapshot(AH);
}
}
/* Set up connection for a parallel worker process */ staticvoid
setupDumpWorker(Archive *AH)
{ /* *Wewanttore-selectallthesamevaluestheleaderconnectionis *using.We'llhaveinheriteddirectly-usablevaluesin *AH->sync_snapshot_idandAH->use_role,butweneedtotranslatethe *inheritedencodingvaluebacktoastringtopasstosetup_connection.
*/
setup_connection(AH,
pg_encoding_to_char(AH->encoding),
NULL,
NULL);
}
for (cell = patterns->head; cell; cell = cell->next)
{
PQExpBufferData dbbuf; int dotcnt;
appendPQExpBufferStr(query, "SELECT oid FROM pg_catalog.pg_namespace n\n");
initPQExpBuffer(&dbbuf);
processSQLNamePattern(GetConnection(fout), query, cell->val, false, false, NULL, "n.nspname", NULL, NULL, &dbbuf,
&dotcnt); if (dotcnt > 1)
pg_fatal("improper qualified name (too many dotted names): %s",
cell->val); elseif (dotcnt == 1)
prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
termPQExpBuffer(&dbbuf);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); if (strict_names && PQntuples(res) == 0)
pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
for (i = 0; i < PQntuples(res); i++)
{
simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
}
if (patterns->head == NULL) return; /* nothing to do */
query = createPQExpBuffer();
/* *TheloopbelowrunsmultipleSELECTsmightsometimesresultin *duplicateentriesintheOIDlist,butwedon'tcare.
*/ for (cell = patterns->head; cell; cell = cell->next)
{ int dotcnt;
appendPQExpBufferStr(query, "SELECT oid FROM pg_catalog.pg_extension e\n");
processSQLNamePattern(GetConnection(fout), query, cell->val, false, false, NULL, "e.extname", NULL, NULL, NULL,
&dotcnt); if (dotcnt > 0)
pg_fatal("improper qualified name (too many dotted names): %s",
cell->val);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); if (strict_names && PQntuples(res) == 0)
pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
for (i = 0; i < PQntuples(res); i++)
{
simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
}
for (cell = patterns->head; cell; cell = cell->next)
{ int dotcnt;
appendPQExpBufferStr(query, "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
processSQLNamePattern(GetConnection(fout), query, cell->val, false, false, NULL, "s.srvname", NULL, NULL, NULL,
&dotcnt); if (dotcnt > 0)
pg_fatal("improper qualified name (too many dotted names): %s",
cell->val);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); if (PQntuples(res) == 0)
pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
for (i = 0; i < PQntuples(res); i++)
simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
if (with_child_tables)
{
appendPQExpBufferStr(query, "UNION" "\nSELECT i.inhrelid" "\nFROM partition_tree p" "\n JOIN pg_catalog.pg_inherits i" "\n ON p.relid OPERATOR(pg_catalog.=) i.inhparent" "\n)" "\nSELECT relid FROM partition_tree");
}
ExecuteSqlStatement(fout, "RESET search_path");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
PQclear(ExecuteSqlQueryForSingleRow(fout,
ALWAYS_SECURE_SEARCH_PATH_SQL)); if (strict_names && PQntuples(res) == 0)
pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
for (i = 0; i < PQntuples(res); i++)
{
simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
}
if (dinfo->dobj.namespace) /* default ACLs are considered part of the namespace */
dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains; else
dinfo->dobj.dump = dopt->include_everything ?
DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
}
/* *selectDumpableExtension:policy-settingsubroutine *Markanextensionastobedumpedornot * *Built-inextensionsshouldbeskippedexceptforcheckingACLs,sincewe *assumethosewillalreadybeinstalledinthetargetdatabase.Weidentify *suchextensionsbytheirhavingOIDsintherangereservedforinitdb. *Wedumpalluser-addedextensionsbydefault.Noextensionsaredumped *ifinclude_everythingisfalse(i.e.,a--schemaor--tableswitchwas *given),exceptif--extensionspecifiesalistofextensionstodump.
*/ staticvoid
selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
{ /* *UseDUMP_COMPONENT_ACLforbuilt-inextensions,toallowusersto *changepermissionsontheirmemberobjects,iftheywishto,andhave *thosechangespreserved.
*/ if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL; else
{ /* check if there is a list of extensions to dump */ if (extension_include_oids.head != NULL)
extinfo->dobj.dump = extinfo->dobj.dump_contains =
simple_oid_list_member(&extension_include_oids,
extinfo->dobj.catId.oid) ?
DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE; else
extinfo->dobj.dump = extinfo->dobj.dump_contains =
dopt->include_everything ?
DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
/* check that the extension is not explicitly excluded */ if (extinfo->dobj.dump &&
simple_oid_list_member(&extension_exclude_oids,
extinfo->dobj.catId.oid))
extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
}
}
/* *UseCOPY(SELECT...)TOwhendumpingaforeigntable'sdata,andwhen *afilterconditionwasspecified.ForothercasesasimpleCOPY *suffices.
*/ if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
{ /* Temporary allows to access to foreign tables to dump data */ if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
set_restrict_relation_kind(fout, "view");
appendPQExpBufferStr(q, "COPY (SELECT "); /* klugery to get rid of parens in column list */ if (strlen(column_list) > 2)
{
appendPQExpBufferStr(q, column_list + 1);
q->data[q->len - 1] = ' ';
} else
appendPQExpBufferStr(q, "* ");
if (ret == -2)
{ /* copy data transfer failed */
pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
pg_log_error_detail("Command was: %s", q->data);
exit_nicely(1);
}
/* Check command status and return to normal libpq state */
res = PQgetResult(conn); if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
pg_log_error_detail("Command was: %s", q->data);
exit_nicely(1);
}
PQclear(res);
/* Do this to ensure we've pumped libpq back to idle state */ if (PQgetResult(conn) != NULL)
pg_log_warning("unexpected extra results during COPY of table \"%s\"",
classname);
destroyPQExpBuffer(q);
/* Revert back the setting */ if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
set_restrict_relation_kind(fout, "view, foreign-table");
/* Temporary allows to access to foreign tables to dump data */ if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
set_restrict_relation_kind(fout, "view");
/* *Ifwe'regoingtoemitINSERTswithcolumnnames,themostefficient *waytodealwithgeneratedcolumnsistoexcludethementirely.For *INSERTswithoutcolumnnames,wehavetoemitDEFAULTratherthanthe *actualcolumnvalue---butwecansaveafewcyclesbyfetchingnulls *ratherthantheuninteresting-to-usvalue.
*/
attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
nfields = 0; for (i = 0; i < tbinfo->numatts; i++)
{ if (tbinfo->attisdropped[i]) continue; if (tbinfo->attgenerated[i] && dopt->column_inserts) continue; if (nfields > 0)
appendPQExpBufferStr(q, ", "); if (tbinfo->attgenerated[i])
appendPQExpBufferStr(q, "NULL"); else
appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
attgenerated[nfields] = tbinfo->attgenerated[i];
nfields++;
} /* Servers before 9.4 will complain about zero-column SELECT */ if (nfields == 0)
appendPQExpBufferStr(q, "NULL");
appendPQExpBuffer(q, " FROM ONLY %s",
fmtQualifiedDumpable(tbinfo)); if (tdinfo->filtercond)
appendPQExpBuffer(q, " %s", tdinfo->filtercond);
ExecuteSqlStatement(fout, q->data);
while (1)
{
res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
PGRES_TUPLES_OK);
/* cross-check field count, allowing for dummy NULL if any */ if (nfields != PQnfields(res) &&
!(nfields == 0 && PQnfields(res) == 1))
pg_fatal("wrong number of fields retrieved from table \"%s\"",
tbinfo->dobj.name);
appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
fmtQualifiedDumpable(targettab));
/* corner case for zero-column table */ if (nfields == 0)
{
appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
} else
{ /* append the list of column names if required */ if (dopt->column_inserts)
{
appendPQExpBufferChar(insertStmt, '('); for (int field = 0; field < nfields; field++)
{ if (field > 0)
appendPQExpBufferStr(insertStmt, ", ");
appendPQExpBufferStr(insertStmt,
fmtId(PQfname(res, field)));
}
appendPQExpBufferStr(insertStmt, ") ");
}
if (tbinfo->needs_override)
appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
appendPQExpBufferStr(insertStmt, "VALUES");
}
}
for (int tuple = 0; tuple < PQntuples(res); tuple++)
{ /* Write the INSERT if not in the middle of a multi-row INSERT. */ if (rows_this_statement == 0)
archputs(insertStmt->data, fout);
for (int field = 0; field < nfields; field++)
{ if (field > 0)
archputs(", ", fout); if (attgenerated[field])
{
archputs("DEFAULT", fout); continue;
} if (PQgetisnull(res, tuple, field))
{
archputs("NULL", fout); continue;
}
/* XXX This code is partially duplicated in ruleutils.c */ switch (PQftype(res, field))
{ case INT2OID: case INT4OID: case INT8OID: case OIDOID: case FLOAT4OID: case FLOAT8OID: case NUMERICOID:
{ /* *Thesetypesareprintedwithoutquotesunless *theycontainvaluesthataren'tacceptedbythe *scannerunquoted(e.g.,'NaN').Notethat *strtod()andfriendsmightacceptNaN,sowe *can'tusethattotest. * *Inrealityweonlyneedtodefendagainst *infinityandNaN,soweneednotgettoocrazy *aboutpatternmatchinghere.
*/ constchar *s = PQgetvalue(res, tuple, field);
case BITOID: case VARBITOID:
archprintf(fout, "B'%s'",
PQgetvalue(res, tuple, field)); break;
case BOOLOID: if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
archputs("true", fout); else
archputs("false", fout); break;
default: /* All other types are printed as string literals. */
resetPQExpBuffer(q);
appendStringLiteralAH(q,
PQgetvalue(res, tuple, field),
fout);
archputs(q->data, fout); break;
}
}
/* Terminate the row ... */
archputs(")", fout);
/* ... and the statement, if the target no. of rows is reached */ if (++rows_this_statement >= rows_per_statement)
{ if (dopt->do_nothing)
archputs(" ON CONFLICT DO NOTHING;\n", fout); else
archputs(";\n", fout); /* Reset the row counter */
rows_this_statement = 0;
}
}
if (PQntuples(res) <= 0)
{
PQclear(res); break;
}
PQclear(res);
}
/* Terminate any statements that didn't make the row count. */ if (rows_this_statement > 0)
{ if (dopt->do_nothing)
archputs(" ON CONFLICT DO NOTHING;\n", fout); else
archputs(";\n", fout);
}
/* *Nothingtodoifwealreadydecidedtodumpthetable.Thiswill *happenfor"config"tables.
*/ if (tbinfo->dataObj != NULL) return;
/* Skip VIEWs (no data to dump) */ if (tbinfo->relkind == RELKIND_VIEW) return; /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */ if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
(foreign_servers_include_oids.head == NULL ||
!simple_oid_list_member(&foreign_servers_include_oids,
tbinfo->foreign_server))) return; /* Skip partitioned tables (data in partitions) */ if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE) return;
/* Don't dump data in unlogged tables, if so requested */ if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
dopt->no_unlogged_table_data) return;
/* Check that the data is not explicitly excluded */ if (simple_oid_list_member(&tabledata_exclude_oids,
tbinfo->dobj.catId.oid)) return;
/* Search through all the dumpable objects for FK constraints */
getDumpableObjects(&dobjs, &numObjs); for (i = 0; i < numObjs; i++)
{ if (dobjs[i]->objType == DO_FK_CONSTRAINT)
{
ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
TableInfo *ftable;
/* Not interesting unless both tables are to be dumped */ if (cinfo->contable == NULL ||
cinfo->contable->dataObj == NULL) continue;
ftable = findTableByOid(cinfo->confrelid); if (ftable == NULL ||
ftable->dataObj == NULL) continue;
appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n"); for (int i = 0; i < PQntuples(lo_res); ++i)
{
Oid oid;
RelFileNumber relfilenumber;
appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n" "SET relfrozenxid = '%u', relminmxid = '%u'\n" "WHERE oid = %u;\n",
atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
atooid(PQgetvalue(lo_res, i, ii_oid)));
oid = atooid(PQgetvalue(lo_res, i, ii_oid));
relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
/* First collect database-specific options */
printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting " "WHERE setrole = 0 AND setdatabase = '%u'::oid",
dboid);
res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
for (int i = 0; i < PQntuples(res); i++)
makeAlterConfigCommand(conn, PQgetvalue(res, i, 0), "DATABASE", dbname, NULL, NULL,
outbuf);
PQclear(res);
/* Now look for role-and-database-specific options */
printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) " "FROM pg_db_role_setting s, pg_roles r " "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
dboid);
res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
for (int i = 0; i < PQntuples(res); i++)
makeAlterConfigCommand(conn, PQgetvalue(res, i, 1), "ROLE", PQgetvalue(res, i, 0), "DATABASE", dbname,
outbuf);
if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
pg_fatal("could not parse result of current_schemas()");
/* *Weuseset_config(),notasimple"SETsearch_path"command,because *thelatterhasless-cleanbehaviorifthesearchpathisempty.While *that'slikelytogetfixedatsomepoint,itseemslikeagoodideato *beasbackwards-compatibleaspossibleinwhatweputintoarchives.
*/ for (i = 0; i < nschemanames; i++)
{ if (i > 0)
appendPQExpBufferStr(path, ", ");
appendPQExpBufferStr(path, fmtId(schemanames[i]));
}
/* *getLOs: *Collectschema-leveldataaboutlargeobjects
*/ staticvoid
getLOs(Archive *fout)
{
DumpOptions *dopt = fout->dopt;
PQExpBuffer loQry = createPQExpBuffer();
PGresult *res; int ntups; int i; int n; int i_oid; int i_lomowner; int i_lomacl; int i_acldefault;
/* *Grouptheblobsintosuitably-sizedgroupsthathavethesameownerand *ACLsetting,andbuildametadataandadataDumpableObjectforeach *group.(Ifwesupportedinitprivsforblobs,we'dhavetoinsistthat *groupsalsoshareinitprivssettings,sincetheDumpableObjectonlyhas *roomforone.)iistheindexofthefirsttupleinthecurrentgroup, *andnisthenumberoftuplesweincludeinthegroup.
*/ for (i = 0; i < ntups; i += n)
{
Oid thisoid = atooid(PQgetvalue(res, i, i_oid)); char *thisowner = PQgetvalue(res, i, i_lomowner); char *thisacl = PQgetvalue(res, i, i_lomacl);
LoInfo *loinfo;
DumpableObject *lodata; char namebuf[64];
/* Scan to find first tuple not to be included in group */
n = 1; while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
{ if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0) break;
n++;
}
/* Build the metadata DumpableObject */
loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
if (n > 1)
snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
atooid(PQgetvalue(res, i + n - 1, i_oid))); else
snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
loinfo->dobj.name = pg_strdup(namebuf);
loinfo->dacl.acl = pg_strdup(thisacl);
loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
loinfo->dacl.privtype = 0;
loinfo->dacl.initprivs = NULL;
loinfo->rolname = getRoleName(thisowner);
loinfo->numlos = n;
loinfo->looids[0] = thisoid; /* Collect OIDs of the remaining blobs in this group */ for (int k = 1; k < n; k++)
{
CatalogId extraID;
loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
/* Make sure we can look up loinfo by any of the blobs' OIDs */
extraID.tableoid = LargeObjectRelationId;
extraID.oid = loinfo->looids[k];
recordAdditionalCatalogID(extraID, &loinfo->dobj);
}
/* LOs have data */
loinfo->dobj.components |= DUMP_COMPONENT_DATA;
/* Mark whether LO group has a non-empty ACL */ if (!PQgetisnull(res, i, i_lomacl))
loinfo->dobj.components |= DUMP_COMPONENT_ACL;
pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
for (int i = 0; i < loinfo->numlos; i++)
{
Oid loOid = loinfo->looids[i]; int loFd; int cnt;
/* Open the LO */
loFd = lo_open(conn, loOid, INV_READ); if (loFd == -1)
pg_fatal("could not open large object %u: %s",
loOid, PQerrorMessage(conn));
StartLO(fout, loOid);
/* Now read it in chunks, sending data to archive */ do
{
cnt = lo_read(conn, loFd, buf, LOBBUFSIZE); if (cnt < 0)
pg_fatal("error reading large object %u: %s",
loOid, PQerrorMessage(conn));
WriteData(fout, buf, cnt);
} while (cnt > 0);
lo_close(conn, loFd);
EndLO(fout, loOid);
}
return1;
}
/* *getPolicies *getinformationaboutallRLSpoliciesondumpabletables.
*/ void
getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
{
DumpOptions *dopt = fout->dopt;
PQExpBuffer query;
PQExpBuffer tbloids;
PGresult *res;
PolicyInfo *polinfo; int i_oid; int i_tableoid; int i_polrelid; int i_polname; int i_polcmd; int i_polpermissive; int i_polroles; int i_polqual; int i_polwithcheck; int i,
j,
ntups;
/* No policies before 9.5 */ if (fout->remoteVersion < 90500) return;
/* Skip if --no-policies was specified */ if (dopt->no_policies) return;
/* *Identifytablesofinterest,andcheckwhichoneshaveRLSenabled.
*/
appendPQExpBufferChar(tbloids, '{'); for (i = 0; i < numTables; i++)
{
TableInfo *tbinfo = &tblinfo[i];
/* Ignore row security on tables not to be dumped */ if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY)) continue;
/* It can't have RLS or policies if it's not a table */ if (tbinfo->relkind != RELKIND_RELATION &&
tbinfo->relkind != RELKIND_PARTITIONED_TABLE) continue;
/* Add it to the list of table OIDs to be probed below */ if (tbloids->len > 1) /* do we have more than the '{'? */
appendPQExpBufferChar(tbloids, ',');
appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
/* Is RLS enabled? (That's separate from whether it has policies) */ if (tbinfo->rowsec)
{
tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
printfPQExpBuffer(query, "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, "); if (fout->remoteVersion >= 100000)
appendPQExpBufferStr(query, "pol.polpermissive, "); else
appendPQExpBufferStr(query, "'t' as polpermissive, ");
appendPQExpBuffer(query, "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE " " pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, " "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, " "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck " "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
tbloids->data);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
/* *getPublications *getinformationaboutpublications
*/ void
getPublications(Archive *fout)
{
DumpOptions *dopt = fout->dopt;
PQExpBuffer query;
PGresult *res;
PublicationInfo *pubinfo; int i_tableoid; int i_oid; int i_pubname; int i_pubowner; int i_puballtables; int i_pubinsert; int i_pubupdate; int i_pubdelete; int i_pubtruncate; int i_pubviaroot; int i_pubgencols; int i,
ntups;
if (dopt->no_publications || fout->remoteVersion < 100000) return;
query = createPQExpBuffer();
/* Get the publications. */
appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, " "p.pubowner, p.puballtables, p.pubinsert, " "p.pubupdate, p.pubdelete, ");
if (fout->remoteVersion >= 110000)
appendPQExpBufferStr(query, "p.pubtruncate, "); else
appendPQExpBufferStr(query, "false AS pubtruncate, ");
if (fout->remoteVersion >= 130000)
appendPQExpBufferStr(query, "p.pubviaroot, "); else
appendPQExpBufferStr(query, "false AS pubviaroot, ");
if (fout->remoteVersion >= 180000)
appendPQExpBufferStr(query, "p.pubgencols "); else
appendPQExpBuffer(query, "'%c' AS pubgencols ", PUBLISH_GENCOLS_NONE);
/* *getPublicationNamespaces *getinformationaboutpublicationmembershipfordumpableschemas.
*/ void
getPublicationNamespaces(Archive *fout)
{
PQExpBuffer query;
PGresult *res;
PublicationSchemaInfo *pubsinfo;
DumpOptions *dopt = fout->dopt; int i_tableoid; int i_oid; int i_pnpubid; int i_pnnspid; int i,
j,
ntups;
if (dopt->no_publications || fout->remoteVersion < 150000) return;
/* this allocation may be more than we need */
pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
j = 0;
for (i = 0; i < ntups; i++)
{
Oid pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
Oid pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
PublicationInfo *pubinfo;
NamespaceInfo *nspinfo;
/* *Ignoreanyentriesforwhichwearen'tinterestedineitherthe *publicationortherel.
*/
pubinfo = findPublicationByOid(pnpubid); if (pubinfo == NULL) continue;
nspinfo = findNamespaceByOid(pnnspid); if (nspinfo == NULL) continue;
/* OK, make a DumpableObject for this relationship */
pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
pubsinfo[j].dobj.catId.tableoid =
atooid(PQgetvalue(res, i, i_tableoid));
pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&pubsinfo[j].dobj);
pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
pubsinfo[j].dobj.name = nspinfo->dobj.name;
pubsinfo[j].publication = pubinfo;
pubsinfo[j].pubschema = nspinfo;
/* Decide whether we want to dump it */
selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
j++;
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getPublicationTables *getinformationaboutpublicationmembershipfordumpabletables.
*/ void
getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
{
PQExpBuffer query;
PGresult *res;
PublicationRelInfo *pubrinfo;
DumpOptions *dopt = fout->dopt; int i_tableoid; int i_oid; int i_prpubid; int i_prrelid; int i_prrelqual; int i_prattrs; int i,
j,
ntups;
if (dopt->no_publications || fout->remoteVersion < 100000) return;
query = createPQExpBuffer();
/* Collect all publication membership info. */ if (fout->remoteVersion >= 150000)
appendPQExpBufferStr(query, "SELECT tableoid, oid, prpubid, prrelid, " "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, " "(CASE\n" " WHEN pr.prattrs IS NOT NULL THEN\n" " (SELECT array_agg(attname)\n" " FROM\n" " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n" " pg_catalog.pg_attribute\n" " WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n" " ELSE NULL END) prattrs " "FROM pg_catalog.pg_publication_rel pr"); else
appendPQExpBufferStr(query, "SELECT tableoid, oid, prpubid, prrelid, " "NULL AS prrelqual, NULL AS prattrs " "FROM pg_catalog.pg_publication_rel");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
/* this allocation may be more than we need */
pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
j = 0;
for (i = 0; i < ntups; i++)
{
Oid prpubid = atooid(PQgetvalue(res, i, i_prpubid));
Oid prrelid = atooid(PQgetvalue(res, i, i_prrelid));
PublicationInfo *pubinfo;
TableInfo *tbinfo;
/* *Ignoreanyentriesforwhichwearen'tinterestedineitherthe *publicationortherel.
*/
pubinfo = findPublicationByOid(prpubid); if (pubinfo == NULL) continue;
tbinfo = findTableByOid(prrelid); if (tbinfo == NULL) continue;
/* OK, make a DumpableObject for this relationship */
pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
pubrinfo[j].dobj.catId.tableoid =
atooid(PQgetvalue(res, i, i_tableoid));
pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&pubrinfo[j].dobj);
pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
pubrinfo[j].dobj.name = tbinfo->dobj.name;
pubrinfo[j].publication = pubinfo;
pubrinfo[j].pubtable = tbinfo; if (PQgetisnull(res, i, i_prrelqual))
pubrinfo[j].pubrelqual = NULL; else
pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
if (!PQgetisnull(res, i, i_prattrs))
{ char **attnames; int nattnames;
PQExpBuffer attribs;
if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
&attnames, &nattnames))
pg_fatal("could not parse %s array", "prattrs");
attribs = createPQExpBuffer(); for (int k = 0; k < nattnames; k++)
{ if (k > 0)
appendPQExpBufferStr(attribs, ", ");
appendPQExpBufferStr(attribs, fmtId(attnames[k]));
}
pubrinfo[j].pubrattrs = attribs->data;
free(attribs); /* but not attribs->data */
free(attnames);
} else
pubrinfo[j].pubrattrs = NULL;
/* Decide whether we want to dump it */
selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
appendPQExpBuffer(query, "SELECT set_config(name, '%s', false) " "FROM pg_settings " "WHERE name = 'restrict_nonsystem_relation_kind'",
value);
res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getSubscriptions *getinformationaboutsubscriptions
*/ void
getSubscriptions(Archive *fout)
{
DumpOptions *dopt = fout->dopt;
PQExpBuffer query;
PGresult *res;
SubscriptionInfo *subinfo; int i_tableoid; int i_oid; int i_subname; int i_subowner; int i_subbinary; int i_substream; int i_subtwophasestate; int i_subdisableonerr; int i_subpasswordrequired; int i_subrunasowner; int i_subconninfo; int i_subslotname; int i_subsynccommit; int i_subpublications; int i_suborigin; int i_suboriginremotelsn; int i_subenabled; int i_subfailover; int i,
ntups;
if (dopt->no_subscriptions || fout->remoteVersion < 100000) return;
if (!is_superuser(fout))
{ int n;
res = ExecuteSqlQuery(fout, "SELECT count(*) FROM pg_subscription " "WHERE subdbid = (SELECT oid FROM pg_database" " WHERE datname = current_database())",
PGRES_TUPLES_OK);
n = atoi(PQgetvalue(res, 0, 0)); if (n > 0)
pg_log_warning("subscriptions not dumped because current user is not a superuser");
PQclear(res); return;
}
query = createPQExpBuffer();
/* Get the subscriptions in current database. */
appendPQExpBufferStr(query, "SELECT s.tableoid, s.oid, s.subname,\n" " s.subowner,\n" " s.subconninfo, s.subslotname, s.subsynccommit,\n" " s.subpublications,\n");
if (fout->remoteVersion >= 140000)
appendPQExpBufferStr(query, " s.subbinary,\n"); else
appendPQExpBufferStr(query, " false AS subbinary,\n");
if (fout->remoteVersion >= 140000)
appendPQExpBufferStr(query, " s.substream,\n"); else
appendPQExpBufferStr(query, " 'f' AS substream,\n");
if (fout->remoteVersion >= 150000)
appendPQExpBufferStr(query, " s.subtwophasestate,\n" " s.subdisableonerr,\n"); else
appendPQExpBuffer(query, " '%c' AS subtwophasestate,\n" " false AS subdisableonerr,\n",
LOGICALREP_TWOPHASE_STATE_DISABLED);
if (fout->remoteVersion >= 160000)
appendPQExpBufferStr(query, " s.subpasswordrequired,\n" " s.subrunasowner,\n" " s.suborigin,\n"); else
appendPQExpBuffer(query, " 't' AS subpasswordrequired,\n" " 't' AS subrunasowner,\n" " '%s' AS suborigin,\n",
LOGICALREP_ORIGIN_ANY);
if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n" " s.subenabled,\n"); else
appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n" " false AS subenabled,\n");
if (fout->remoteVersion >= 170000)
appendPQExpBufferStr(query, " s.subfailover\n"); else
appendPQExpBufferStr(query, " false AS subfailover\n");
for (i = 0; i < ntups; i++)
{
subinfo[i].dobj.objType = DO_SUBSCRIPTION;
subinfo[i].dobj.catId.tableoid =
atooid(PQgetvalue(res, i, i_tableoid));
subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&subinfo[i].dobj);
subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
subinfo[i].subenabled =
(strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
subinfo[i].subbinary =
(strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
subinfo[i].subdisableonerr =
(strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
subinfo[i].subpasswordrequired =
(strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
subinfo[i].subrunasowner =
(strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
subinfo[i].subfailover =
(strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
subinfo[i].subconninfo =
pg_strdup(PQgetvalue(res, i, i_subconninfo)); if (PQgetisnull(res, i, i_subslotname))
subinfo[i].subslotname = NULL; else
subinfo[i].subslotname =
pg_strdup(PQgetvalue(res, i, i_subslotname));
subinfo[i].subsynccommit =
pg_strdup(PQgetvalue(res, i, i_subsynccommit));
subinfo[i].subpublications =
pg_strdup(PQgetvalue(res, i, i_subpublications));
subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin)); if (PQgetisnull(res, i, i_suboriginremotelsn))
subinfo[i].suboriginremotelsn = NULL; else
subinfo[i].suboriginremotelsn =
pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
/* Decide whether we want to dump it */
selectDumpableObject(&(subinfo[i].dobj), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getSubscriptionTables *Getinformationaboutsubscriptionmembershipfordumpabletables.This *willbeusedonlyinbinary-upgrademodeforPG17orlaterversions.
*/ void
getSubscriptionTables(Archive *fout)
{
DumpOptions *dopt = fout->dopt;
SubscriptionInfo *subinfo = NULL;
SubRelInfo *subrinfo;
PGresult *res; int i_srsubid; int i_srrelid; int i_srsubstate; int i_srsublsn; int ntups;
Oid last_srsubid = InvalidOid;
if (dopt->no_subscriptions || !dopt->binary_upgrade ||
fout->remoteVersion < 170000) return;
res = ExecuteSqlQuery(fout, "SELECT srsubid, srrelid, srsubstate, srsublsn " "FROM pg_catalog.pg_subscription_rel " "ORDER BY srsubid",
PGRES_TUPLES_OK);
ntups = PQntuples(res); if (ntups == 0) goto cleanup;
subrinfo = pg_malloc(ntups * sizeof(SubRelInfo)); for (int i = 0; i < ntups; i++)
{
Oid cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
Oid relid = atooid(PQgetvalue(res, i, i_srrelid));
TableInfo *tblinfo;
/* *Ifweswitchedtoanewsubscription,checkifthesubscription *exists.
*/ if (cur_srsubid != last_srsubid)
{
subinfo = findSubscriptionByOid(cur_srsubid); if (subinfo == NULL)
pg_fatal("subscription with OID %u does not exist", cur_srsubid);
last_srsubid = cur_srsubid;
}
tblinfo = findTableByOid(relid); if (tblinfo == NULL)
pg_fatal("failed sanity check, table with OID %u not found",
relid);
/* OK, make a DumpableObject for this relationship */
subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
subrinfo[i].dobj.catId.tableoid = relid;
subrinfo[i].dobj.catId.oid = cur_srsubid;
AssignDumpId(&subrinfo[i].dobj);
subrinfo[i].dobj.namespace = tblinfo->dobj.namespace;
subrinfo[i].dobj.name = tblinfo->dobj.name;
subrinfo[i].subinfo = subinfo;
subrinfo[i].tblinfo = tblinfo;
subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0]; if (PQgetisnull(res, i, i_srsublsn))
subrinfo[i].srsublsn = NULL; else
subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
/* Decide whether we want to dump it */
selectDumpableObject(&(subrinfo[i].dobj), fout);
}
/* Build list of quoted publications and append them to query. */ if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
pg_fatal("could not parse %s array", "subpublications");
publications = createPQExpBuffer(); for (i = 0; i < npubnames; i++)
{ if (i > 0)
appendPQExpBufferStr(publications, ", ");
for (int i = 0; i < nbinaryUpgradeClassOids; i++)
{
binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
}
/* every toast table has an index */
appendPQExpBuffer(upgrade_buffer, "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
entry->toast_index_oid);
appendPQExpBuffer(upgrade_buffer, "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
entry->toast_index_relfilenumber);
}
} else
{ /* Preserve the OID and relfilenumber of the index */
appendPQExpBuffer(upgrade_buffer, "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
pg_class_oid);
appendPQExpBuffer(upgrade_buffer, "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
entry->relfilenumber);
}
/* *Findtheparentextension.Wecouldavoidthissearchifwewantedto *addalinkfieldtoDumpableObject,butthespacecostsofthatwould *beconsiderable.Weassumethatmemberobjectscouldonlyhavea *directdependencyontheirownextension,notanyothers.
*/ for (i = 0; i < dobj->nDeps; i++)
{
extobj = findObjectByDumpId(dobj->dependencies[i]); if (extobj && extobj->objType == DO_EXTENSION) break;
extobj = NULL;
} if (extobj == NULL)
pg_fatal("could not find parent extension for %s %s",
objtype, objname);
appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, handle extension membership the hard way\n");
appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
fmtId(extobj->name),
objtype); if (objnamespace && *objnamespace)
appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
}
/* *getNamespaces: *getinformationaboutallnamespacesinthesystemcatalogs
*/ void
getNamespaces(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query;
NamespaceInfo *nsinfo; int i_tableoid; int i_oid; int i_nspname; int i_nspowner; int i_nspacl; int i_acldefault;
nsinfo = findNamespaceByOid(nsoid); if (nsinfo == NULL)
pg_fatal("schema with OID %u does not exist", nsoid); return nsinfo;
}
/* *getExtensions: *readallextensionsinthesystemcatalogsandreturntheminthe *ExtensionInfo*structure * *numExtensionsissettothenumberofextensionsreadin
*/
ExtensionInfo *
getExtensions(Archive *fout, int *numExtensions)
{
DumpOptions *dopt = fout->dopt;
PGresult *res; int ntups; int i;
PQExpBuffer query;
ExtensionInfo *extinfo = NULL; int i_tableoid; int i_oid; int i_extname; int i_nspname; int i_extrelocatable; int i_extversion; int i_extconfig; int i_extcondition;
query = createPQExpBuffer();
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);
ntups = PQntuples(res); if (ntups == 0) goto cleanup;
for (i = 0; i < ntups; i++)
{
extinfo[i].dobj.objType = DO_EXTENSION;
extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&extinfo[i].dobj);
extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
/* Decide whether we want to dump it */
selectDumpableExtension(&(extinfo[i]), dopt);
}
cleanup:
PQclear(res);
destroyPQExpBuffer(query);
*numExtensions = ntups;
return extinfo;
}
/* *getTypes: *getinformationaboutalltypesinthesystemcatalogs * *NB:thismustrunaftergetFuncs()becauseweassumewecando *findFuncByOid().
*/ void
getTypes(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query = createPQExpBuffer();
TypeInfo *tyinfo;
ShellTypeInfo *stinfo; int i_tableoid; int i_oid; int i_typname; int i_typnamespace; int i_typacl; int i_acldefault; int i_typowner; int i_typelem; int i_typrelid; int i_typrelkind; int i_typtype; int i_typisdefined; int i_isarray; int i_typarray;
/* *weincludeeventhebuilt-intypesbecausethosemaybeusedasarray *elementsbyuser-definedtypes * *wefilteroutthebuilt-intypeswhenwedumpoutthetypes * *sameapproachforundefined(shell)typesandarraytypes * *Note:asof8.3wecanreliablydetectwhetheratypeisan *auto-generatedarraytypebycheckingtheelementtype'styparray. *(Beforethatthetestiscapableofgeneratingfalsepositives.)We *stillcheckfornamebeginningwith'_',though,soastoavoidthe *costofthesubselectprobeforallstandardtypes.Thiswouldhaveto *berevisitedifthebackendeverallowsrenamingofarraytypes.
*/
appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, " "typnamespace, typacl, " "acldefault('T', typowner) AS acldefault, " "typowner, " "typelem, typrelid, typarray, " "CASE WHEN typrelid = 0 THEN ' '::\"char\" " "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, " "typtype, typisdefined, " "typname[0] = '_' AND typelem != 0 AND " "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray " "FROM pg_type");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
/* *getOperators: *getinformationaboutalloperatorsinthesystemcatalogs
*/ void
getOperators(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query = createPQExpBuffer();
OprInfo *oprinfo; int i_tableoid; int i_oid; int i_oprname; int i_oprnamespace; int i_oprowner; int i_oprkind; int i_oprleft; int i_oprright; int i_oprcode;
for (i = 0; i < ntups; i++)
{
oprinfo[i].dobj.objType = DO_OPERATOR;
oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&oprinfo[i].dobj);
oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
oprinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
/* Decide whether we want to dump it */
selectDumpableObject(&(oprinfo[i].dobj), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getCollations: *getinformationaboutallcollationsinthesystemcatalogs
*/ void
getCollations(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query;
CollInfo *collinfo; int i_tableoid; int i_oid; int i_collname; int i_collnamespace; int i_collowner; int i_collencoding;
for (i = 0; i < ntups; i++)
{
collinfo[i].dobj.objType = DO_COLLATION;
collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&collinfo[i].dobj);
collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
collinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
/* Decide whether we want to dump it */
selectDumpableObject(&(collinfo[i].dobj), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getConversions: *getinformationaboutallconversionsinthesystemcatalogs
*/ void
getConversions(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query;
ConvInfo *convinfo; int i_tableoid; int i_oid; int i_conname; int i_connamespace; int i_conowner;
for (i = 0; i < ntups; i++)
{
convinfo[i].dobj.objType = DO_CONVERSION;
convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&convinfo[i].dobj);
convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
convinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
/* Decide whether we want to dump it */
selectDumpableObject(&(convinfo[i].dobj), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getAccessMethods: *getinformationaboutalluser-definedaccessmethods
*/ void
getAccessMethods(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query;
AccessMethodInfo *aminfo; int i_tableoid; int i_oid; int i_amname; int i_amhandler; int i_amtype;
query = createPQExpBuffer();
/* *Selectallaccessmethodsfrompg_amtable.v9.6introducedCREATE *ACCESSMETHOD,soearlierversionsusuallyhaveonlybuilt-inaccess *methods.v9.6alsochangedtheaccessmethodAPI,replacingdozensof *pg_amcolumnswithamhandler.Evenifausercreatedanaccessmethod *by"INSERTINTOpg_am",wehavenowaytotranslatepre-v9.6pg_am *columnstoav9.6+CREATEACCESSMETHOD.Hence,beforev9.6,read *pg_amjusttofacilitatefindAccessMethodByOid()providingthe *OID-to-namemapping.
*/
appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, "); if (fout->remoteVersion >= 90600)
appendPQExpBufferStr(query, "amtype, " "amhandler::pg_catalog.regproc AS amhandler "); else
appendPQExpBufferStr(query, "'i'::pg_catalog.\"char\" AS amtype, " "'-'::pg_catalog.regproc AS amhandler ");
appendPQExpBufferStr(query, "FROM pg_am");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
for (i = 0; i < ntups; i++)
{
aminfo[i].dobj.objType = DO_ACCESS_METHOD;
aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&aminfo[i].dobj);
aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
aminfo[i].dobj.namespace = NULL;
aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
/* Decide whether we want to dump it */
selectDumpableAccessMethod(&(aminfo[i]), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getOpclasses: *getinformationaboutallopclassesinthesystemcatalogs
*/ void
getOpclasses(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query = createPQExpBuffer();
OpclassInfo *opcinfo; int i_tableoid; int i_oid; int i_opcmethod; int i_opcname; int i_opcnamespace; int i_opcowner;
for (i = 0; i < ntups; i++)
{
opcinfo[i].dobj.objType = DO_OPCLASS;
opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&opcinfo[i].dobj);
opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
opcinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
/* Decide whether we want to dump it */
selectDumpableObject(&(opcinfo[i].dobj), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getOpfamilies: *getinformationaboutallopfamiliesinthesystemcatalogs
*/ void
getOpfamilies(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query;
OpfamilyInfo *opfinfo; int i_tableoid; int i_oid; int i_opfmethod; int i_opfname; int i_opfnamespace; int i_opfowner;
for (i = 0; i < ntups; i++)
{
opfinfo[i].dobj.objType = DO_OPFAMILY;
opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&opfinfo[i].dobj);
opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
opfinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
/* Decide whether we want to dump it */
selectDumpableObject(&(opfinfo[i].dobj), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getAggregates: *getinformationaboutalluser-definedaggregatesinthesystemcatalogs
*/ void
getAggregates(Archive *fout)
{
DumpOptions *dopt = fout->dopt;
PGresult *res; int ntups; int i;
PQExpBuffer query = createPQExpBuffer();
AggInfo *agginfo; int i_tableoid; int i_oid; int i_aggname; int i_aggnamespace; int i_pronargs; int i_proargtypes; int i_proowner; int i_aggacl; int i_acldefault;
for (i = 0; i < ntups; i++)
{
agginfo[i].aggfn.dobj.objType = DO_AGG;
agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&agginfo[i].aggfn.dobj);
agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
agginfo[i].aggfn.dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
agginfo[i].aggfn.dacl.privtype = 0;
agginfo[i].aggfn.dacl.initprivs = NULL;
agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs)); if (agginfo[i].aggfn.nargs == 0)
agginfo[i].aggfn.argtypes = NULL; else
{
agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
parseOidArray(PQgetvalue(res, i, i_proargtypes),
agginfo[i].aggfn.argtypes,
agginfo[i].aggfn.nargs);
}
agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
/* Decide whether we want to dump it */
selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
/* Mark whether aggregate has an ACL */ if (!PQgetisnull(res, i, i_aggacl))
agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getFuncs: *getinformationaboutalluser-definedfunctionsinthesystemcatalogs
*/ void
getFuncs(Archive *fout)
{
DumpOptions *dopt = fout->dopt;
PGresult *res; int ntups; int i;
PQExpBuffer query = createPQExpBuffer();
FuncInfo *finfo; int i_tableoid; int i_oid; int i_proname; int i_pronamespace; int i_proowner; int i_prolang; int i_pronargs; int i_proargtypes; int i_prorettype; int i_proacl; int i_acldefault;
appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, p.proname, p.prolang, " "p.pronargs, p.proargtypes, p.prorettype, " "p.proacl, " "acldefault('f', p.proowner) AS acldefault, " "p.pronamespace, " "p.proowner " "FROM pg_proc p " "LEFT JOIN pg_init_privs pip ON " "(p.oid = pip.objoid " "AND pip.classoid = 'pg_proc'::regclass " "AND pip.objsubid = 0) " "WHERE %s" "\n AND NOT EXISTS (SELECT 1 FROM pg_depend " "WHERE classid = 'pg_proc'::regclass AND " "objid = p.oid AND deptype = 'i')" "\n AND (" "\n pronamespace != " "(SELECT oid FROM pg_namespace " "WHERE nspname = 'pg_catalog')" "\n OR EXISTS (SELECT 1 FROM pg_cast" "\n WHERE pg_cast.oid > %u " "\n AND p.oid = pg_cast.castfunc)" "\n OR EXISTS (SELECT 1 FROM pg_transform" "\n WHERE pg_transform.oid > %u AND " "\n (p.oid = pg_transform.trffromsql" "\n OR p.oid = pg_transform.trftosql))",
not_agg_check,
g_last_builtin_oid,
g_last_builtin_oid); if (dopt->binary_upgrade)
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')");
appendPQExpBufferStr(query, "\n OR p.proacl IS DISTINCT FROM pip.initprivs");
appendPQExpBufferChar(query, ')');
} else
{
appendPQExpBuffer(query, "SELECT tableoid, oid, proname, prolang, " "pronargs, proargtypes, prorettype, proacl, " "acldefault('f', proowner) AS acldefault, " "pronamespace, " "proowner " "FROM pg_proc p " "WHERE NOT proisagg" "\n AND NOT EXISTS (SELECT 1 FROM pg_depend " "WHERE classid = 'pg_proc'::regclass AND " "objid = p.oid AND deptype = 'i')" "\n AND (" "\n pronamespace != " "(SELECT oid FROM pg_namespace " "WHERE nspname = 'pg_catalog')" "\n OR EXISTS (SELECT 1 FROM pg_cast" "\n WHERE pg_cast.oid > '%u'::oid" "\n AND p.oid = pg_cast.castfunc)",
g_last_builtin_oid);
if (fout->remoteVersion >= 90500)
appendPQExpBuffer(query, "\n OR EXISTS (SELECT 1 FROM pg_transform" "\n WHERE pg_transform.oid > '%u'::oid" "\n AND (p.oid = pg_transform.trffromsql" "\n OR p.oid = pg_transform.trftosql))",
g_last_builtin_oid);
if (dopt->binary_upgrade)
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, ')');
}
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
/* *Ordinarily,statsgoinSECTION_DATAfortablesand *SECTION_POST_DATAforindexes. * *However,thesectionmaybeupdatedlaterformaterializedview *stats.REFRESHMATERIALIZEDVIEWreplacesthestorageandresets *thestats,sothestatsmustberestoredafterthedata.Also,the *materializedviewdefinitionmaybepostponedtoSECTION_POST_DATA *(seerepairMatViewBoundaryMultiLoop()).
*/ switch (info->relkind)
{ case RELKIND_RELATION: case RELKIND_PARTITIONED_TABLE: case RELKIND_MATVIEW: case RELKIND_FOREIGN_TABLE:
info->section = SECTION_DATA; break; case RELKIND_INDEX: case RELKIND_PARTITIONED_INDEX:
info->section = SECTION_POST_DATA; break; default:
pg_fatal("cannot dump statistics for relation kind \"%c\"",
info->relkind);
}
return info;
} return NULL;
}
/* *getTables *readallthetables(noindexes)inthesystemcatalogs, *andreturnthemasanarrayofTableInfostructures * **numTablesissettothenumberoftablesreadin
*/
TableInfo *
getTables(Archive *fout, int *numTables)
{
DumpOptions *dopt = fout->dopt;
PGresult *res; int ntups; int i;
PQExpBuffer query = createPQExpBuffer();
TableInfo *tblinfo; int i_reltableoid; int i_reloid; int i_relname; int i_relnamespace; int i_relkind; int i_reltype; int i_relowner; int i_relchecks; int i_relhasindex; int i_relhasrules; int i_relpages; int i_reltuples; int i_relallvisible; int i_relallfrozen; int i_toastpages; int i_owning_tab; int i_owning_col; int i_reltablespace; int i_relhasoids; int i_relhastriggers; int i_relpersistence; int i_relispopulated; int i_relreplident; int i_relrowsec; int i_relforcerowsec; int i_relfrozenxid; int i_toastfrozenxid; int i_toastoid; int i_relminmxid; int i_toastminmxid; int i_reloptions; int i_checkoption; int i_toastreloptions; int i_reloftype; int i_foreignserver; int i_amname; int i_is_identity_sequence; int i_relacl; int i_acldefault; int i_ispartition;
if (fout->remoteVersion >= 180000)
appendPQExpBufferStr(query, "c.relallfrozen, "); else
appendPQExpBufferStr(query, "0 AS relallfrozen, ");
appendPQExpBufferStr(query, "c.relhastriggers, c.relpersistence, " "c.reloftype, " "c.relacl, " "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE) " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, " "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN " "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) " "ELSE 0 END AS foreignserver, " "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, " "tc.oid AS toid, " "tc.relpages AS toastpages, " "tc.reloptions AS toast_reloptions, " "d.refobjid AS owning_tab, " "d.refobjsubid AS owning_col, " "tsp.spcname AS reltablespace, ");
if (fout->remoteVersion >= 120000)
appendPQExpBufferStr(query, "false AS relhasoids, "); else
appendPQExpBufferStr(query, "c.relhasoids, ");
if (fout->remoteVersion >= 90300)
appendPQExpBufferStr(query, "c.relispopulated, "); else
appendPQExpBufferStr(query, "'t' as relispopulated, ");
if (fout->remoteVersion >= 90400)
appendPQExpBufferStr(query, "c.relreplident, "); else
appendPQExpBufferStr(query, "'d' AS relreplident, ");
if (fout->remoteVersion >= 90500)
appendPQExpBufferStr(query, "c.relrowsecurity, c.relforcerowsecurity, "); else
appendPQExpBufferStr(query, "false AS relrowsecurity, " "false AS relforcerowsecurity, ");
if (fout->remoteVersion >= 90300)
appendPQExpBufferStr(query, "c.relminmxid, tc.relminmxid AS tminmxid, "); else
appendPQExpBufferStr(query, "0 AS relminmxid, 0 AS tminmxid, ");
if (fout->remoteVersion >= 90300)
appendPQExpBufferStr(query, "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, "); else
appendPQExpBufferStr(query, "c.reloptions, NULL AS checkoption, ");
if (fout->remoteVersion >= 90600)
appendPQExpBufferStr(query, "am.amname, "); else
appendPQExpBufferStr(query, "NULL AS amname, ");
if (fout->remoteVersion >= 90600)
appendPQExpBufferStr(query, "(d.deptype = 'i') IS TRUE AS is_identity_sequence, "); else
appendPQExpBufferStr(query, "false AS is_identity_sequence, ");
if (fout->remoteVersion >= 100000)
appendPQExpBufferStr(query, "c.relispartition AS ispartition "); else
appendPQExpBufferStr(query, "false AS ispartition ");
/* *Leftjointopg_dependtopickupdependencyinfolinkingsequencesto *theirowningcolumn,ifany(notethisdependencyisAUTOexceptfor *identitysequences,whereit'sINTERNAL).Alsojointopg_tablespaceto *collectthespcname.
*/
appendPQExpBufferStr(query, "\nFROM pg_class c\n" "LEFT JOIN pg_depend d ON " "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND " "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND " "d.objsubid = 0 AND " "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n" "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
/* *In9.6andup,leftjointopg_amtopickuptheamname.
*/ if (fout->remoteVersion >= 90600)
appendPQExpBufferStr(query, "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
/* *WepurposefullyignoretoastOIDsforpartitionedtables;thereasonis *thatversions10and11havethem,butlaterversionsdonot,so *emittingthemcausestheupgradetofail.
*/
appendPQExpBufferStr(query, "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid" " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE) " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
for (i = 0; i < ntups; i++)
{
int32 relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
int32 relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
tblinfo[i].dobj.objType = DO_TABLE;
tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
AssignDumpId(&tblinfo[i].dobj);
tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
tblinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
tblinfo[i].dacl.privtype = 0;
tblinfo[i].dacl.initprivs = NULL;
tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages)); if (PQgetisnull(res, i, i_toastpages))
tblinfo[i].toastpages = 0; else
tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages)); if (PQgetisnull(res, i, i_owning_tab))
{
tblinfo[i].owning_tab = InvalidOid;
tblinfo[i].owning_col = 0;
} else
{
tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
}
tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions)); if (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));
tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver)); if (PQgetisnull(res, i, i_amname))
tblinfo[i].amname = NULL; else
tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
tblinfo[i].dummy_view = false; /* might get set during sort */
tblinfo[i].postponed_def = false; /* might get set during sort */
/* Tables have data */
tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
/* Mark whether table has an ACL */ if (!PQgetisnull(res, i, i_relacl))
tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
tblinfo[i].hascolumnACLs = false; /* may get set later */
/* Add statistics */ if (tblinfo[i].interesting)
{
RelStatsInfo *stats;
/* Arbitrarily end a batch when query length reaches 100K. */ if (query->len >= 100000)
{ /* Lock another batch of tables. */
appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
ExecuteSqlStatement(fout, query->data);
resetPQExpBuffer(query);
}
}
}
}
if (query->len != 0)
{ /* Lock the tables in the last batch. */
appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
ExecuteSqlStatement(fout, query->data);
}
if (dopt->lockWaitTimeout)
{
ExecuteSqlStatement(fout, "SET statement_timeout = 0");
}
PQclear(res);
destroyPQExpBuffer(query);
return tblinfo;
}
/* *getOwnedSeqs *identifyownedsequencesandmarkthemasdumpableifowningtableis * *WeusedtodothisingetTables(),butit'sbettertodoitafterthe *indexusedbyfindTableByOid()hasbeensetup.
*/ void
getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
{ int i;
/* *Forcesequencesthatare"owned"bytablecolumnstobedumpedwhenever *theirowningtableisbeingdumped.
*/ for (i = 0; i < numTables; i++)
{
TableInfo *seqinfo = &tblinfo[i];
TableInfo *owning_tab;
if (!OidIsValid(seqinfo->owning_tab)) continue; /* not an owned sequence */
owning_tab = findTableByOid(seqinfo->owning_tab); if (owning_tab == NULL)
pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
seqinfo->owning_tab, seqinfo->dobj.catId.oid);
/* Make sure that necessary data is available if we're dumping it */ if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
{
seqinfo->interesting = true;
owning_tab->interesting = true;
}
}
}
/* *getInherits *readalltheinheritanceinformation *fromthesystemcatalogsreturnthemintheInhInfo*structure * *numInheritsissettothenumberofpairsreadin
*/
InhInfo *
getInherits(Archive *fout, int *numInherits)
{
PGresult *res; int ntups; int i;
PQExpBuffer query = createPQExpBuffer();
InhInfo *inhinfo;
int i_inhrelid; int i_inhparent;
/* find all the inheritance information */
appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
for (i = 0; i < ntups; i++)
{
inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
}
/* hash partitioning didn't exist before v11 */ if (fout->remoteVersion < 110000) return; /* needn't bother if not dumping data */ if (!fout->dopt->dumpData) return;
/* *Wewanttoperformjustonequeryagainstpg_index.However,we *mustn'ttrytoselecteveryrowofthecatalogandthensortitouton *theclientside,becausesomeoftheserver-sidefunctionsweneed *wouldbeunsafetoapplytotableswedon'thavelockon.Hence,we *buildanarrayoftheOIDsoftableswecareabout(andnowhavelock *on!),anduseaWHEREclausetoconstrainwhichrowsareselected.
*/
appendPQExpBufferChar(tbloids, '{'); for (int i = 0; i < numTables; i++)
{
TableInfo *tbinfo = &tblinfo[i];
if (!tbinfo->hasindex) continue;
/* *Wecanignoreindexesofuninterestingtables.
*/ if (!tbinfo->interesting) continue;
/* OK, we need info for this table */ if (tbloids->len > 1) /* do we have more than the '{'? */
appendPQExpBufferChar(tbloids, ',');
appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
}
appendPQExpBufferChar(tbloids, '}');
if (fout->remoteVersion >= 180000)
appendPQExpBufferStr(query, "t.relallfrozen, "); else
appendPQExpBufferStr(query, "0 AS relallfrozen, ");
appendPQExpBufferStr(query, "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, " "i.indkey, i.indisclustered, " "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, " "CASE WHEN i.indexprs IS NOT NULL THEN " "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)" " FROM pg_catalog.pg_attribute " " WHERE attrelid = i.indexrelid) " "ELSE NULL END AS indattnames, " "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, " "t.reloptions AS indreloptions, ");
if (fout->remoteVersion >= 90400)
appendPQExpBufferStr(query, "i.indisreplident, "); else
appendPQExpBufferStr(query, "false AS indisreplident, ");
if (fout->remoteVersion >= 110000)
appendPQExpBufferStr(query, "inh.inhparent AS parentidx, " "i.indnkeyatts AS indnkeyatts, " "i.indnatts AS indnatts, " "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) " " FROM pg_catalog.pg_attribute " " WHERE attrelid = i.indexrelid AND " " attstattarget >= 0) AS indstatcols, " "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) " " FROM pg_catalog.pg_attribute " " WHERE attrelid = i.indexrelid AND " " attstattarget >= 0) AS indstatvals, "); else
appendPQExpBufferStr(query, "0 AS parentidx, " "i.indnatts AS indnkeyatts, " "i.indnatts AS indnatts, " "'' AS indstatcols, " "'' AS indstatvals, ");
if (fout->remoteVersion >= 150000)
appendPQExpBufferStr(query, "i.indnullsnotdistinct, "); else
appendPQExpBufferStr(query, "false AS indnullsnotdistinct, ");
if (fout->remoteVersion >= 180000)
appendPQExpBufferStr(query, "c.conperiod "); else
appendPQExpBufferStr(query, "NULL AS conperiod ");
/* *Thepointofthemessy-lookingouterjoinistofindaconstraintthat *isrelatedbyaninternaldependencylinktotheindex.Ifwefindone, *createaCONSTRAINTentrylinkedtotheINDEXentry.Weassumean *indexwon'thavemorethanoneinternaldependency. * *Note:thecheckonconrelidisredundant,butusefulbecausethat *columnisindexedwhileconindidisnot.
*/ if (fout->remoteVersion >= 110000)
{
appendPQExpBuffer(query, "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) " "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) " "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) " "LEFT JOIN pg_catalog.pg_constraint c " "ON (i.indrelid = c.conrelid AND " "i.indexrelid = c.conindid AND " "c.contype IN ('p','u','x')) " "LEFT JOIN pg_catalog.pg_inherits inh " "ON (inh.inhrelid = indexrelid) " "WHERE (i.indisvalid OR t2.relkind = 'p') " "AND i.indisready " "ORDER BY i.indrelid, indexname",
tbloids->data);
} else
{ /* *thetestonindisreadyisnecessaryin9.2,andharmlessin *earlier/laterversions
*/
appendPQExpBuffer(query, "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) " "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.indisvalid AND i.indisready " "ORDER BY i.indrelid, indexname",
tbloids->data);
}
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
/* *Outerloopiteratesoncepertable,notonceperrow.Incrementingof *jishandledbytheinnerloop.
*/
curtblindx = -1; for (int j = 0; j < ntups;)
{
Oid indrelid = atooid(PQgetvalue(res, j, i_indrelid));
TableInfo *tbinfo = NULL; char **indAttNames = NULL; int nindAttNames = 0; int numinds;
/* Count rows for this table */ for (numinds = 1; numinds < ntups - j; numinds++) if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid) break;
/* *LocatetheassociatedTableInfo;werelyontblinfo[]beinginOID *order.
*/ while (++curtblindx < numTables)
{
tbinfo = &tblinfo[curtblindx]; if (tbinfo->dobj.catId.oid == indrelid) break;
} if (curtblindx >= numTables)
pg_fatal("unrecognized table OID %u", indrelid); /* cross-check that we only got requested tables */ if (!tbinfo->hasindex ||
!tbinfo->interesting)
pg_fatal("unexpected index data for table \"%s\"",
tbinfo->dobj.name);
/* Save data for this table */
tbinfo->indexes = indxinfo + j;
tbinfo->numIndexes = numinds;
/* *getExtendedStatistics *getinformationaboutextended-statisticsobjects. * *Note:extendedstatisticsdataisnotreturneddirectlytothecaller,but *itdoesgetenteredintotheDumpableObjecttables.
*/ void
getExtendedStatistics(Archive *fout)
{
PQExpBuffer query;
PGresult *res;
StatsExtInfo *statsextinfo; int ntups; int i_tableoid; int i_oid; int i_stxname; int i_stxnamespace; int i_stxowner; int i_stxrelid; int i_stattarget; int i;
/* Extended statistics were new in v10 */ if (fout->remoteVersion < 100000) return;
for (i = 0; i < ntups; i++)
{
statsextinfo[i].dobj.objType = DO_STATSEXT;
statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&statsextinfo[i].dobj);
statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
statsextinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
statsextinfo[i].stattable =
findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid))); if (PQgetisnull(res, i, i_stattarget))
statsextinfo[i].stattarget = -1; else
statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
/* Decide whether we want to dump it */
selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
}
/* *Wewanttoperformjustonequeryagainstpg_constraint.However,we *mustn'ttrytoselecteveryrowofthecatalogandthensortitouton *theclientside,becausesomeoftheserver-sidefunctionsweneed *wouldbeunsafetoapplytotableswedon'thavelockon.Hence,we *buildanarrayoftheOIDsoftableswecareabout(andnowhavelock *on!),anduseaWHEREclausetoconstrainwhichrowsareselected.
*/
appendPQExpBufferChar(tbloids, '{'); for (int i = 0; i < numTables; i++)
{
TableInfo *tinfo = &tblinfo[i];
if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)) continue;
/* OK, we need info for this table */ if (tbloids->len > 1) /* do we have more than the '{'? */
appendPQExpBufferChar(tbloids, ',');
appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
}
appendPQExpBufferChar(tbloids, '}');
appendPQExpBufferStr(query, "SELECT c.tableoid, c.oid, " "conrelid, conname, confrelid, "); if (fout->remoteVersion >= 110000)
appendPQExpBufferStr(query, "conindid, "); else
appendPQExpBufferStr(query, "0 AS conindid, ");
appendPQExpBuffer(query, "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n" "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n" "WHERE contype = 'f' ",
tbloids->data); if (fout->remoteVersion >= 110000)
appendPQExpBufferStr(query, "AND conparentid = 0 ");
appendPQExpBufferStr(query, "ORDER BY conrelid, conname");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
/* *getRules *getbasicinformationabouteveryruleinthesystem
*/ void
getRules(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query = createPQExpBuffer();
RuleInfo *ruleinfo; int i_tableoid; int i_oid; int i_rulename; int i_ruletable; int i_ev_type; int i_is_instead; int i_ev_enabled;
ruleinfo[i].dobj.objType = DO_RULE;
ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&ruleinfo[i].dobj);
ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
ruleinfo[i].ruletable = findTableByOid(ruletableoid); if (ruleinfo[i].ruletable == NULL)
pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
ruletableoid, ruleinfo[i].dobj.catId.oid);
ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled)); if (ruleinfo[i].ruletable)
{ /* *Ifthetableisaviewormaterializedview,forceitsON *SELECTruletobesortedbeforetheviewitself---this *ensuresthatanydependenciesfortheruleaffectthetable's *positioning.Otherrulesareforcedtoappearaftertheir *table.
*/ if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
{
addObjectDependency(&ruleinfo[i].ruletable->dobj,
ruleinfo[i].dobj.dumpId); /* We'll merge the rule into CREATE VIEW, if possible */
ruleinfo[i].separate = false;
} else
{
addObjectDependency(&ruleinfo[i].dobj,
ruleinfo[i].ruletable->dobj.dumpId);
ruleinfo[i].separate = true;
}
} else
ruleinfo[i].separate = true;
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getTriggers *getinformationabouteverytriggeronadumpabletable * *Note:triggerdataisnotreturneddirectlytothecaller,butit *doesgetenteredintotheDumpableObjecttables.
*/ void
getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
{
PQExpBuffer query = createPQExpBuffer();
PQExpBuffer tbloids = createPQExpBuffer();
PGresult *res; int ntups; int curtblindx;
TriggerInfo *tginfo; int i_tableoid,
i_oid,
i_tgrelid,
i_tgname,
i_tgenabled,
i_tgispartition,
i_tgdef;
/* *Wewanttoperformjustonequeryagainstpg_trigger.However,we *mustn'ttrytoselecteveryrowofthecatalogandthensortitouton *theclientside,becausesomeoftheserver-sidefunctionsweneed *wouldbeunsafetoapplytotableswedon'thavelockon.Hence,we *buildanarrayoftheOIDsoftableswecareabout(andnowhavelock *on!),anduseaWHEREclausetoconstrainwhichrowsareselected.
*/
appendPQExpBufferChar(tbloids, '{'); for (int i = 0; i < numTables; i++)
{
TableInfo *tbinfo = &tblinfo[i];
if (!tbinfo->hastriggers ||
!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)) continue;
/* OK, we need info for this table */ if (tbloids->len > 1) /* do we have more than the '{'? */
appendPQExpBufferChar(tbloids, ',');
appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
}
appendPQExpBufferChar(tbloids, '}');
if (fout->remoteVersion >= 150000)
{ /* *NB:thinknottousepretty=trueinpg_get_triggerdef.Itcould *resultinnon-forward-compatibledumpsofWHENclausesdueto *under-parenthesization. * *NB:Weneedtoseepartitiontriggersincasethetgenabledflag *hasbeenchangedfromtheparent.
*/
appendPQExpBuffer(query, "SELECT t.tgrelid, t.tgname, " "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, " "t.tgenabled, t.tableoid, t.oid, " "t.tgparentid <> 0 AS tgispartition\n" "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) " "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) " "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) " "OR t.tgenabled != u.tgenabled) " "ORDER BY t.tgrelid, t.tgname",
tbloids->data);
} elseif (fout->remoteVersion >= 130000)
{ /* *NB:thinknottousepretty=trueinpg_get_triggerdef.Itcould *resultinnon-forward-compatibledumpsofWHENclausesdueto *under-parenthesization. * *NB:Weneedtoseetgisinternaltriggersinpartitions,incasethe *tgenabledflaghasbeenchangedfromtheparent.
*/
appendPQExpBuffer(query, "SELECT t.tgrelid, t.tgname, " "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, " "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n" "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) " "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) " "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) " "ORDER BY t.tgrelid, t.tgname",
tbloids->data);
} elseif (fout->remoteVersion >= 110000)
{ /* *NB:Weneedtoseetgisinternaltriggersinpartitions,incasethe *tgenabledflaghasbeenchangedfromtheparent.Notgparentidin *version11-12,sowehavetomatchthemviapg_depend. * *Seeaboveaboutpretty=trueinpg_get_triggerdef.
*/
appendPQExpBuffer(query, "SELECT t.tgrelid, t.tgname, " "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, " "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition " "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) " "LEFT JOIN pg_catalog.pg_depend AS d ON " " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND " " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND " " d.objid = t.oid " "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid " "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) " "ORDER BY t.tgrelid, t.tgname",
tbloids->data);
} else
{ /* See above about pretty=true in pg_get_triggerdef */
appendPQExpBuffer(query, "SELECT t.tgrelid, t.tgname, " "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, " "t.tgenabled, false as tgispartition, " "t.tableoid, t.oid " "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) " "WHERE NOT tgisinternal " "ORDER BY t.tgrelid, t.tgname",
tbloids->data);
}
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
for (i = 0; i < ntups; i++)
{
evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&evtinfo[i].dobj);
evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
/* Decide whether we want to dump it */
selectDumpableObject(&(evtinfo[i].dobj), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getProcLangs *getbasicinformationabouteveryprocedurallanguageinthesystem * *NB:thismustrunaftergetFuncs()becauseweassumewecando *findFuncByOid().
*/ void
getProcLangs(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query = createPQExpBuffer();
ProcLangInfo *planginfo; int i_tableoid; int i_oid; int i_lanname; int i_lanpltrusted; int i_lanplcallfoid; int i_laninline; int i_lanvalidator; int i_lanacl; int i_acldefault; int i_lanowner;
for (i = 0; i < ntups; i++)
{
planginfo[i].dobj.objType = DO_PROCLANG;
planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&planginfo[i].dobj);
planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
planginfo[i].dacl.privtype = 0;
planginfo[i].dacl.initprivs = NULL;
planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
/* Decide whether we want to dump it */
selectDumpableProcLang(&(planginfo[i]), fout);
/* Mark whether language has an ACL */ if (!PQgetisnull(res, i, i_lanacl))
planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getCasts *getbasicinformationaboutmostcastsinthesystem * *Skipcastsfromarangetoitsmultirange,sincewe'llcreatethose *automatically.
*/ void
getCasts(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query = createPQExpBuffer();
CastInfo *castinfo; int i_tableoid; int i_oid; int i_castsource; int i_casttarget; int i_castfunc; int i_castcontext; int i_castmethod;
if (fout->remoteVersion >= 140000)
{
appendPQExpBufferStr(query, "SELECT tableoid, oid, " "castsource, casttarget, castfunc, castcontext, " "castmethod " "FROM pg_cast c " "WHERE NOT EXISTS ( " "SELECT 1 FROM pg_range r " "WHERE c.castsource = r.rngtypid " "AND c.casttarget = r.rngmultitypid " ") " "ORDER BY 3,4");
} else
{
appendPQExpBufferStr(query, "SELECT tableoid, oid, " "castsource, casttarget, castfunc, castcontext, " "castmethod " "FROM pg_cast ORDER BY 3,4");
}
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
query = createPQExpBuffer();
appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
res = ExecuteSqlQueryForSingleRow(fout, query->data);
lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
destroyPQExpBuffer(query);
PQclear(res);
return lanname;
}
/* *getTransforms *getbasicinformationabouteverytransforminthesystem
*/ void
getTransforms(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query;
TransformInfo *transforminfo; int i_tableoid; int i_oid; int i_trftype; int i_trflang; int i_trffromsql; int i_trftosql;
/* Decide whether we want to dump it */
selectDumpableObject(&(transforminfo[i].dobj), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getTableAttrs- *foreachinterestingtable,readinfoaboutitsattributes *(names,types,defaultvalues,CHECKconstraints,etc) * *modifiestblinfo
*/ void
getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
{
DumpOptions *dopt = fout->dopt;
PQExpBuffer q = createPQExpBuffer();
PQExpBuffer tbloids = createPQExpBuffer();
PQExpBuffer checkoids = createPQExpBuffer();
PQExpBuffer invalidnotnulloids = NULL;
PGresult *res; int ntups; int curtblindx; int i_attrelid; int i_attnum; int i_attname; int i_atttypname; int i_attstattarget; int i_attstorage; int i_typstorage; int i_attidentity; int i_attgenerated; int i_attisdropped; int i_attlen; int i_attalign; int i_attislocal; int i_notnull_name; int i_notnull_comment; int i_notnull_noinherit; int i_notnull_islocal; int i_notnull_invalidoid; int i_attoptions; int i_attcollation; int i_attcompression; int i_attfdwoptions; int i_attmissingval; int i_atthasdef;
/* *Wewanttoperformjustonequeryagainstpg_attribute,andthenjust *oneagainstpg_attrdef(forDEFAULTs)andtwoagainstpg_constraint *(forCHECKconstraintsandforNOTNULLconstraints).However,we *mustn'ttrytoselecteveryrowofthosecatalogsandthensortitout *ontheclientside,becausesomeoftheserver-sidefunctionsweneed *wouldbeunsafetoapplytotableswedon'thavelockon.Hence,we *buildanarrayoftheOIDsoftableswecareabout(andnowhavelock *on!),anduseaWHEREclausetoconstrainwhichrowsareselected.
*/
appendPQExpBufferChar(tbloids, '{');
appendPQExpBufferChar(checkoids, '{'); for (int i = 0; i < numTables; i++)
{
TableInfo *tbinfo = &tblinfo[i];
/* Don't bother to collect info for sequences */ if (tbinfo->relkind == RELKIND_SEQUENCE) continue;
/* Don't bother with uninteresting tables, either */ if (!tbinfo->interesting) continue;
/* OK, we need info for this table */ if (tbloids->len > 1) /* do we have more than the '{'? */
appendPQExpBufferChar(tbloids, ',');
appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
if (tbinfo->ncheck > 0)
{ /* Also make a list of the ones with check constraints */ if (checkoids->len > 1) /* do we have more than the '{'? */
appendPQExpBufferChar(checkoids, ',');
appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
}
}
appendPQExpBufferChar(tbloids, '}');
appendPQExpBufferChar(checkoids, '}');
/* *Findalltheuserattributesandtheirtypes. * *SinceweonlywanttodumpCOLLATEclausesforattributeswhose *collationisdifferentfromtheirtype'sdefault,weuseaCASEhereto *suppressuninterestingattcollationscheaply.
*/
appendPQExpBufferStr(q, "SELECT\n" "a.attrelid,\n" "a.attnum,\n" "a.attname,\n" "a.attstattarget,\n" "a.attstorage,\n" "t.typstorage,\n" "a.atthasdef,\n" "a.attisdropped,\n" "a.attlen,\n" "a.attalign,\n" "a.attislocal,\n" "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n" "array_to_string(a.attoptions, ', ') AS attoptions,\n" "CASE WHEN a.attcollation <> t.typcollation " "THEN a.attcollation ELSE 0 END AS attcollation,\n" "pg_catalog.array_to_string(ARRAY(" "SELECT pg_catalog.quote_ident(option_name) || " "' ' || pg_catalog.quote_literal(option_value) " "FROM pg_catalog.pg_options_to_table(attfdwoptions) " "ORDER BY option_name" "), E',\n ') AS attfdwoptions,\n");
/* *FindoutanyNOTNULLmarkingsforeachcolumn.In18andupweread *pg_constrainttoobtaintheconstraintname,andforvalidconstraints *alsopg_descriptiontoobtainitscomment.notnull_noinheritisset *accordingtotheNOINHERITproperty.Forversionspriorto18,we *storeanemptystringasthenamewhenaconstraintismarkedas *attnotnull(thiscuesdumpTableSchematoprinttheNOTNULLclause *withoutaname);also,suchcasesareneverNOINHERIT. * *Forinvalidconstraints,weneedtostoretheirOIDsforprocessing *elsewhere,sowebringthepg_constraint.oidvaluewhentheconstraint *isinvalid,andNULLotherwise.Theircommentsarehandlednothere *butbycollectComments,becausethey'retheirowndumpableobject. * *Wetrackinnotnull_islocalwhethertheconstraintwasdefineddirectly *inthistableorviaanancestor,forbinaryupgrade.flagInhAttrs *mightmodifythislater.
*/ if (fout->remoteVersion >= 180000)
appendPQExpBufferStr(q, "co.conname AS notnull_name,\n" "CASE WHEN co.convalidated THEN pt.description" " ELSE NULL END AS notnull_comment,\n" "CASE WHEN NOT co.convalidated THEN co.oid " "ELSE NULL END AS notnull_invalidoid,\n" "co.connoinherit AS notnull_noinherit,\n" "co.conislocal AS notnull_islocal,\n"); else
appendPQExpBufferStr(q, "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n" "NULL AS notnull_comment,\n" "NULL AS notnull_invalidoid,\n" "false AS notnull_noinherit,\n" "CASE WHEN a.attislocal THEN true\n" " WHEN a.attnotnull AND NOT a.attislocal THEN true\n" " ELSE false\n" "END AS notnull_islocal,\n");
if (fout->remoteVersion >= 140000)
appendPQExpBufferStr(q, "a.attcompression AS attcompression,\n"); else
appendPQExpBufferStr(q, "'' AS attcompression,\n");
if (fout->remoteVersion >= 100000)
appendPQExpBufferStr(q, "a.attidentity,\n"); else
appendPQExpBufferStr(q, "'' AS attidentity,\n");
if (fout->remoteVersion >= 110000)
appendPQExpBufferStr(q, "CASE WHEN a.atthasmissing AND NOT a.attisdropped " "THEN a.attmissingval ELSE null END AS attmissingval,\n"); else
appendPQExpBufferStr(q, "NULL AS attmissingval,\n");
if (fout->remoteVersion >= 120000)
appendPQExpBufferStr(q, "a.attgenerated\n"); else
appendPQExpBufferStr(q, "'' AS attgenerated\n");
/* need left join to pg_type to not fail on dropped columns ... */
appendPQExpBuffer(q, "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) " "LEFT JOIN pg_catalog.pg_type t " "ON (a.atttypid = t.oid)\n",
tbloids->data);
/* *Inversions18andup,weneedpg_constraintforexplicitNOTNULL *entriesandpg_descriptiontogettheircomments.
*/ if (fout->remoteVersion >= 180000)
appendPQExpBufferStr(q, " LEFT JOIN pg_catalog.pg_constraint co ON " "(a.attrelid = co.conrelid\n" " AND co.contype = 'n' AND " "co.conkey = array[a.attnum])\n" " LEFT JOIN pg_catalog.pg_description pt ON " "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
appendPQExpBufferStr(q, "WHERE a.attnum > 0::pg_catalog.int2\n" "ORDER BY a.attrelid, a.attnum");
res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
/* Within the next loop, we'll accumulate OIDs of tables with defaults */
resetPQExpBuffer(tbloids);
appendPQExpBufferChar(tbloids, '{');
/* *Outerloopiteratesoncepertable,notonceperrow.Incrementingof *rishandledbytheinnerloop.
*/
curtblindx = -1; for (int r = 0; r < ntups;)
{
Oid attrelid = atooid(PQgetvalue(res, r, i_attrelid));
TableInfo *tbinfo = NULL; int numatts; bool hasdefaults;
/* Count rows for this table */ for (numatts = 1; numatts < ntups - r; numatts++) if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid) break;
/* *LocatetheassociatedTableInfo;werelyontblinfo[]beinginOID *order.
*/ while (++curtblindx < numTables)
{
tbinfo = &tblinfo[curtblindx]; if (tbinfo->dobj.catId.oid == attrelid) break;
} if (curtblindx >= numTables)
pg_fatal("unrecognized table OID %u", attrelid); /* cross-check that we only got requested tables */ if (tbinfo->relkind == RELKIND_SEQUENCE ||
!tbinfo->interesting)
pg_fatal("unexpected column data for table \"%s\"",
tbinfo->dobj.name);
if (hasdefaults)
{ /* Collect OIDs of interesting tables that have defaults */ if (tbloids->len > 1) /* do we have more than the '{'? */
appendPQExpBufferChar(tbloids, ',');
appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
}
}
/* If invalidnotnulloids has any data, finalize it */ if (invalidnotnulloids != NULL)
appendPQExpBufferChar(invalidnotnulloids, '}');
PQclear(res);
/* *Nowgetinfoaboutcolumndefaults.Thisisskippedforadata-only *dump,asitisonlyneededfortableschemas.
*/ if (dopt->dumpSchema && tbloids->len > 1)
{
AttrDefInfo *attrdefs; int numDefaults;
TableInfo *tbinfo = NULL;
pg_log_info("finding table default expressions");
appendPQExpBufferChar(tbloids, '}');
printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, " "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n" "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n" "ORDER BY a.adrelid, a.adnum",
tbloids->data);
res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
/* *GetinfoaboutNOTNULLNOTVALIDconstraints.Thisisskippedfora *data-onlydump,asitisonlyneededfortableschemas.
*/ if (dopt->dumpSchema && invalidnotnulloids)
{
ConstraintInfo *constrs; int numConstrs; int i_tableoid; int i_oid; int i_conrelid; int i_conname; int i_consrc; int i_conislocal;
/* As above, this loop iterates once per table, not once per row */
curtblindx = -1; for (int j = 0; j < numConstrs;)
{
Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
TableInfo *tbinfo = NULL; int numcons;
/* Count rows for this table */ for (numcons = 1; numcons < numConstrs - j; numcons++) if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid) break;
/* *LocatetheassociatedTableInfo;werelyontblinfo[]beingin *OIDorder.
*/ while (++curtblindx < numTables)
{
tbinfo = &tblinfo[curtblindx]; if (tbinfo->dobj.catId.oid == conrelid) break;
} if (curtblindx >= numTables)
pg_fatal("unrecognized table OID %u", conrelid);
/* *GetinfoabouttableCHECKconstraints.Thisisskippedfora *data-onlydump,asitisonlyneededfortableschemas.
*/ if (dopt->dumpSchema && checkoids->len > 2)
{
ConstraintInfo *constrs; int numConstrs; int i_tableoid; int i_oid; int i_conrelid; int i_conname; int i_consrc; int i_conislocal; int i_convalidated;
pg_log_info("finding table check constraints");
resetPQExpBuffer(q);
appendPQExpBuffer(q, "SELECT c.tableoid, c.oid, conrelid, conname, " "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, " "conislocal, convalidated " "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n" "WHERE contype = 'c' " "ORDER BY c.conrelid, c.conname",
checkoids->data);
res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
/* As above, this loop iterates once per table, not once per row */
curtblindx = -1; for (int j = 0; j < numConstrs;)
{
Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
TableInfo *tbinfo = NULL; int numcons;
/* Count rows for this table */ for (numcons = 1; numcons < numConstrs - j; numcons++) if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid) break;
/* *LocatetheassociatedTableInfo;werelyontblinfo[]beingin *OIDorder.
*/ while (++curtblindx < numTables)
{
tbinfo = &tblinfo[curtblindx]; if (tbinfo->dobj.catId.oid == conrelid) break;
} if (curtblindx >= numTables)
pg_fatal("unrecognized table OID %u", conrelid);
if (numcons != tbinfo->ncheck)
{
pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d", "expected %d check constraints on table \"%s\" but found %d",
tbinfo->ncheck),
tbinfo->ncheck, tbinfo->dobj.name, numcons);
pg_log_error_hint("The system catalogs might be corrupted.");
exit_nicely(1);
}
tbinfo->checkexprs = constrs + j;
for (int c = 0; c < numcons; c++, j++)
{ bool validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
/* *getTSParsers: *getinformationaboutalltextsearchparsersinthesystemcatalogs
*/ void
getTSParsers(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query;
TSParserInfo *prsinfo; int i_tableoid; int i_oid; int i_prsname; int i_prsnamespace; int i_prsstart; int i_prstoken; int i_prsend; int i_prsheadline; int i_prslextype;
for (i = 0; i < ntups; i++)
{
prsinfo[i].dobj.objType = DO_TSPARSER;
prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&prsinfo[i].dobj);
prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
prsinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
/* Decide whether we want to dump it */
selectDumpableObject(&(prsinfo[i].dobj), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getTSDictionaries: *getinformationaboutalltextsearchdictionariesinthesystemcatalogs
*/ void
getTSDictionaries(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query;
TSDictInfo *dictinfo; int i_tableoid; int i_oid; int i_dictname; int i_dictnamespace; int i_dictowner; int i_dicttemplate; int i_dictinitoption;
for (i = 0; i < ntups; i++)
{
dictinfo[i].dobj.objType = DO_TSDICT;
dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&dictinfo[i].dobj);
dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
dictinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate)); if (PQgetisnull(res, i, i_dictinitoption))
dictinfo[i].dictinitoption = NULL; else
dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
/* Decide whether we want to dump it */
selectDumpableObject(&(dictinfo[i].dobj), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getTSTemplates: *getinformationaboutalltextsearchtemplatesinthesystemcatalogs
*/ void
getTSTemplates(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query;
TSTemplateInfo *tmplinfo; int i_tableoid; int i_oid; int i_tmplname; int i_tmplnamespace; int i_tmplinit; int i_tmpllexize;
for (i = 0; i < ntups; i++)
{
tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&tmplinfo[i].dobj);
tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
tmplinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
/* Decide whether we want to dump it */
selectDumpableObject(&(tmplinfo[i].dobj), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getTSConfigurations: *getinformationaboutalltextsearchconfigurations
*/ void
getTSConfigurations(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query;
TSConfigInfo *cfginfo; int i_tableoid; int i_oid; int i_cfgname; int i_cfgnamespace; int i_cfgowner; int i_cfgparser;
for (i = 0; i < ntups; i++)
{
cfginfo[i].dobj.objType = DO_TSCONFIG;
cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&cfginfo[i].dobj);
cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
cfginfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
/* Decide whether we want to dump it */
selectDumpableObject(&(cfginfo[i].dobj), fout);
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getForeignDataWrappers: *getinformationaboutallforeign-datawrappersinthesystemcatalogs
*/ void
getForeignDataWrappers(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query;
FdwInfo *fdwinfo; int i_tableoid; int i_oid; int i_fdwname; int i_fdwowner; int i_fdwhandler; int i_fdwvalidator; int i_fdwacl; int i_acldefault; int i_fdwoptions;
for (i = 0; i < ntups; i++)
{
fdwinfo[i].dobj.objType = DO_FDW;
fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&fdwinfo[i].dobj);
fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
fdwinfo[i].dobj.namespace = NULL;
fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
fdwinfo[i].dacl.privtype = 0;
fdwinfo[i].dacl.initprivs = NULL;
fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
/* Decide whether we want to dump it */
selectDumpableObject(&(fdwinfo[i].dobj), fout);
/* Mark whether FDW has an ACL */ if (!PQgetisnull(res, i, i_fdwacl))
fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getForeignServers: *getinformationaboutallforeignserversinthesystemcatalogs
*/ void
getForeignServers(Archive *fout)
{
PGresult *res; int ntups; int i;
PQExpBuffer query;
ForeignServerInfo *srvinfo; int i_tableoid; int i_oid; int i_srvname; int i_srvowner; int i_srvfdw; int i_srvtype; int i_srvversion; int i_srvacl; int i_acldefault; int i_srvoptions;
for (i = 0; i < ntups; i++)
{
srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&srvinfo[i].dobj);
srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
srvinfo[i].dobj.namespace = NULL;
srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
srvinfo[i].dacl.privtype = 0;
srvinfo[i].dacl.initprivs = NULL;
srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
/* Decide whether we want to dump it */
selectDumpableObject(&(srvinfo[i].dobj), fout);
/* Servers have user mappings */
srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
/* Mark whether server has an ACL */ if (!PQgetisnull(res, i, i_srvacl))
srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
}
PQclear(res);
destroyPQExpBuffer(query);
}
/* *getDefaultACLs: *getinformationaboutalldefaultACLinformationinthesystemcatalogs
*/ void
getDefaultACLs(Archive *fout)
{
DumpOptions *dopt = fout->dopt;
DefaultACLInfo *daclinfo;
PQExpBuffer query;
PGresult *res; int i_oid; int i_tableoid; int i_defaclrole; int i_defaclnamespace; int i_defaclobjtype; int i_defaclacl; int i_acldefault; int i,
ntups;
for (i = 0; i < ntups; i++)
{
Oid nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&daclinfo[i].dobj); /* cheesy ... is it worth coming up with a better object name? */
daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
/* Check for per-column ACLs */
appendPQExpBufferStr(query, "SELECT DISTINCT attrelid FROM pg_attribute " "WHERE attacl IS NOT NULL");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res); for (i = 0; i < ntups; i++)
{
Oid relid = atooid(PQgetvalue(res, i, 0));
TableInfo *tblinfo;
tblinfo = findTableByOid(relid); /* OK to ignore tables we haven't got a DumpableObject for */ if (tblinfo)
{
tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
tblinfo->hascolumnACLs = true;
}
}
PQclear(res);
/* Fetch initial-privileges data */ if (fout->remoteVersion >= 90600)
{
printfPQExpBuffer(query, "SELECT objoid, classoid, objsubid, privtype, initprivs " "FROM pg_init_privs");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res); for (i = 0; i < ntups; i++)
{
Oid objoid = atooid(PQgetvalue(res, i, 0));
Oid classoid = atooid(PQgetvalue(res, i, 1)); int objsubid = atoi(PQgetvalue(res, i, 2)); char privtype = *(PQgetvalue(res, i, 3)); char *initprivs = PQgetvalue(res, i, 4);
CatalogId objId;
DumpableObject *dobj;
objId.tableoid = classoid;
objId.oid = objoid;
dobj = findObjectByCatalogId(objId); /* OK to ignore entries we haven't got a DumpableObject for */ if (dobj)
{ /* Cope with sub-object initprivs */ if (objsubid != 0)
{ if (dobj->objType == DO_TABLE)
{ /* For a column initprivs, set the table's ACL flags */
dobj->components |= DUMP_COMPONENT_ACL;
((TableInfo *) dobj)->hascolumnACLs = true;
} else
pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
classoid, objoid, objsubid); continue;
}
/* do nothing, if --no-comments is supplied */ if (dopt->no_comments) return;
/* Comments are schema not data ... except LO comments are data */ if (strcmp(type, "LARGE OBJECT") != 0)
{ if (!dopt->dumpSchema) return;
} else
{ /* We do dump LO comments in binary-upgrade mode */ if (!dopt->dumpData && !dopt->binary_upgrade) return;
}
/* Search for comments associated with catalogId, using table */
ncomments = findComments(catalogId.tableoid, catalogId.oid,
&comments);
/* Is there one matching the subid? */ while (ncomments > 0)
{ if (comments->objsubid == subid) break;
comments++;
ncomments--;
}
/* If a comment exists, build COMMENT ON statement */ if (ncomments > 0)
{
PQExpBuffer query = createPQExpBuffer();
PQExpBuffer tag = createPQExpBuffer();
appendPQExpBuffer(query, "COMMENT ON %s ", type); if (namespace && *namespace)
appendPQExpBuffer(query, "%s.", fmtId(namespace));
appendPQExpBuffer(query, "%s IS ", name);
appendStringLiteralAH(query, comments->descr, fout);
appendPQExpBufferStr(query, ";\n");
/* *dumpRelationStats_dumper-- * *Generatecommandtoimportstatsintotherelationonthenewdatabase. *ThisroutineiscalledbytheArchiverwhenitwantsthestatisticstobe *dumped.
*/ staticchar *
dumpRelationStats_dumper(Archive *fout, constvoid *userArg, const TocEntry *te)
{ const RelStatsInfo *rsinfo = (RelStatsInfo *) userArg; static PGresult *res; staticint rownum;
PQExpBuffer query;
PQExpBufferData out_data;
PQExpBuffer out = &out_data; int i_schemaname; int i_tablename; int i_attname; int i_inherited; int i_null_frac; int i_avg_width; int i_n_distinct; int i_most_common_vals; int i_most_common_freqs; int i_histogram_bounds; int i_correlation; int i_most_common_elems; int i_most_common_elem_freqs; int i_elem_count_histogram; int i_range_length_histogram; int i_range_empty_frac; int i_range_bounds_histogram; static TocEntry *expected_te;
if (fout->remoteVersion >= 180000)
appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
appendPQExpBufferStr(out, "\n);\n");
/* Fetch the next batch of attribute statistics if needed. */ if (rownum >= PQntuples(res))
{
PQclear(res);
res = fetchAttributeStats(fout);
rownum = 0;
}
/* Stop if the next stat row in our cache isn't for this relation. */ if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0) break;
for (int i = 0; i < rsinfo->nindAttNames; i++)
{ if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
{
appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
i + 1);
found = true; break;
}
}
if (!found)
pg_fatal("could not find index attname \"%s\"", attname);
}
/* do nothing, if --no-comments is supplied */ if (dopt->no_comments) return;
/* Comments are SCHEMA not data */ if (!dopt->dumpSchema) return;
/* Search for comments associated with relation, using table */
ncomments = findComments(tbinfo->dobj.catId.tableoid,
tbinfo->dobj.catId.oid,
&comments);
/* If comments exist, build COMMENT ON statements */ if (ncomments <= 0) return;
query = createPQExpBuffer();
tag = createPQExpBuffer();
while (ncomments > 0)
{ constchar *descr = comments->descr; int objsubid = comments->objsubid;
for (i = 0; i < ntups; i++)
{
CatalogId objId; int subid;
objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
objId.oid = atooid(PQgetvalue(res, i, i_objoid));
subid = atoi(PQgetvalue(res, i, i_objsubid));
/* We needn't remember comments that don't match any dumpable object */ if (dobj == NULL ||
dobj->catId.tableoid != objId.tableoid ||
dobj->catId.oid != objId.oid)
dobj = findObjectByCatalogId(objId); if (dobj == NULL) continue;
/* *CASCADEshouldn'tberequiredhereasfornormaltypessincetheI/O *functionsaregenericanddonotgetdropped.
*/
appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
if (dopt->binary_upgrade)
binary_upgrade_set_type_oids_by_type_oid(fout, q,
tyinfo->dobj.catId.oid, false, false);
appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
qualtypname);
if (!dopt->binary_upgrade)
{
i_enumlabel = PQfnumber(res, "enumlabel");
/* Labels with server-assigned oids */ for (i = 0; i < num; i++)
{
label = PQgetvalue(res, i, i_enumlabel); if (i > 0)
appendPQExpBufferChar(q, ',');
appendPQExpBufferStr(q, "\n ");
appendStringLiteralAH(q, label, fout);
}
}
/* Labels with dump-assigned (preserved) oids */ for (i = 0; i < num; i++)
{
enum_oid = atooid(PQgetvalue(res, i, i_oid));
label = PQgetvalue(res, i, i_enumlabel);
if (i == 0)
appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
appendPQExpBuffer(q, "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
enum_oid);
appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
appendStringLiteralAH(q, label, fout);
appendPQExpBufferStr(q, ";\n\n");
}
}
if (dopt->binary_upgrade)
binary_upgrade_extension_member(q, &tyinfo->dobj, "TYPE", qtypname,
tyinfo->dobj.namespace->dobj.name);
if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
{ /* Set up query for range-specific details */
appendPQExpBufferStr(query, "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
appendPQExpBufferStr(query, "SELECT ");
if (fout->remoteVersion >= 140000)
appendPQExpBufferStr(query, "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, "); else
appendPQExpBufferStr(query, "NULL AS rngmultitype, ");
appendPQExpBufferStr(query, "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, " "opc.opcname AS opcname, " "(SELECT nspname FROM pg_catalog.pg_namespace nsp " " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, " "opc.opcdefault, " "CASE WHEN rngcollation = st.typcollation THEN 0 " " ELSE rngcollation END AS collation, " "rngcanonical, rngsubdiff " "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, " " pg_catalog.pg_opclass opc " "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND " "rngtypid = $1");
if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
{ /* Set up query for type-specific details */
appendPQExpBufferStr(query, "PREPARE dumpBaseType(pg_catalog.oid) AS\n" "SELECT typlen, " "typinput, typoutput, typreceive, typsend, " "typreceive::pg_catalog.oid AS typreceiveoid, " "typsend::pg_catalog.oid AS typsendoid, " "typanalyze, " "typanalyze::pg_catalog.oid AS typanalyzeoid, " "typdelim, typbyval, typalign, typstorage, " "typmodin, typmodout, " "typmodin::pg_catalog.oid AS typmodinoid, " "typmodout::pg_catalog.oid AS typmodoutoid, " "typcategory, typispreferred, " "(typcollation <> 0) AS typcollatable, " "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
if (fout->remoteVersion >= 140000)
appendPQExpBufferStr(query, "typsubscript, " "typsubscript::pg_catalog.oid AS typsubscriptoid "); else
appendPQExpBufferStr(query, "'-' AS typsubscript, 0 AS typsubscriptoid ");
appendPQExpBufferStr(query, "FROM pg_catalog.pg_type " "WHERE oid = $1");
if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
{ /* Set up query for domain-specific details */
appendPQExpBufferStr(query, "PREPARE dumpDomain(pg_catalog.oid) AS\n");
appendPQExpBufferStr(query, "SELECT t.typnotnull, " "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, " "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, " "t.typdefault, " "CASE WHEN t.typcollation <> u.typcollation " "THEN t.typcollation ELSE 0 END AS typcollation " "FROM pg_catalog.pg_type t " "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) " "WHERE t.oid = $1");
if (dopt->binary_upgrade)
binary_upgrade_set_type_oids_by_type_oid(fout, q,
tyinfo->dobj.catId.oid, true, /* force array type */ false); /* force multirange type */
if (dopt->binary_upgrade)
{
binary_upgrade_set_type_oids_by_type_oid(fout, q,
tyinfo->dobj.catId.oid, false, false);
binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
}
attname = NULL; for (i = 0; i < ntups; i++)
{ if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
PQgetvalue(res, i, i_attisdropped)[0] != 't')
{
attname = PQgetvalue(res, i, i_attname); break;
}
} if (attname) /* just in case we don't find it */
{ constchar *descr = comments->descr;
if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
{ /* Set up query for function-specific details */
appendPQExpBufferStr(query, "PREPARE dumpFunc(pg_catalog.oid) AS\n");
appendPQExpBufferStr(query, "SELECT\n" "proretset,\n" "prosrc,\n" "probin,\n" "provolatile,\n" "proisstrict,\n" "prosecdef,\n" "lanname,\n" "proconfig,\n" "procost,\n" "prorows,\n" "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n" "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n" "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n" "proleakproof,\n");
if (fout->remoteVersion >= 90500)
appendPQExpBufferStr(query, "array_to_string(protrftypes, ' ') AS protrftypes,\n"); else
appendPQExpBufferStr(query, "NULL AS protrftypes,\n");
if (fout->remoteVersion >= 90600)
appendPQExpBufferStr(query, "proparallel,\n"); else
appendPQExpBufferStr(query, "'u' AS proparallel,\n");
if (fout->remoteVersion >= 110000)
appendPQExpBufferStr(query, "prokind,\n"); else
appendPQExpBufferStr(query, "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
if (fout->remoteVersion >= 120000)
appendPQExpBufferStr(query, "prosupport,\n"); else
appendPQExpBufferStr(query, "'-' AS prosupport,\n");
if (fout->remoteVersion >= 140000)
appendPQExpBufferStr(query, "pg_get_function_sqlbody(p.oid) AS prosqlbody\n"); else
appendPQExpBufferStr(query, "NULL AS prosqlbody\n");
if (strcmp(prosupport, "-") != 0)
{ /* We rely on regprocout to provide quoting and qualification */
appendPQExpBuffer(q, " SUPPORT %s", prosupport);
}
if (proparallel[0] != PROPARALLEL_UNSAFE)
{ if (proparallel[0] == PROPARALLEL_SAFE)
appendPQExpBufferStr(q, " PARALLEL SAFE"); elseif (proparallel[0] == PROPARALLEL_RESTRICTED)
appendPQExpBufferStr(q, " PARALLEL RESTRICTED"); elseif (proparallel[0] != PROPARALLEL_UNSAFE)
pg_fatal("unrecognized proparallel value for function \"%s\"",
finfo->dobj.name);
}
for (int i = 0; i < nconfigitems; i++)
{ /* we feel free to scribble on configitems[] here */ char *configitem = configitems[i]; char *pos;
pos = strchr(configitem, '='); if (pos == NULL) continue;
*pos++ = '\0';
appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
/* Do nothing if not dumping schema */ if (!dopt->dumpSchema) return;
/* Cannot dump if we don't have the cast function's info */ if (OidIsValid(cast->castfunc))
{
funcInfo = findFuncByOid(cast->castfunc); if (funcInfo == NULL)
pg_fatal("could not find function definition for function with OID %u",
cast->castfunc);
}
appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
sourceType, targetType);
switch (cast->castmethod)
{ case COERCION_METHOD_BINARY:
appendPQExpBufferStr(defqry, "WITHOUT FUNCTION"); break; case COERCION_METHOD_INOUT:
appendPQExpBufferStr(defqry, "WITH INOUT"); break; case COERCION_METHOD_FUNCTION: if (funcInfo)
{ char *fsig = format_function_signature(fout, funcInfo, true);
/* *Alwaysqualifythefunctionname(format_function_signature *won'tqualifyit).
*/
appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
free(fsig);
} else
pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field"); break; default:
pg_log_warning("bogus value in pg_cast.castmethod field");
}
if (cast->castcontext == 'a')
appendPQExpBufferStr(defqry, " AS ASSIGNMENT"); elseif (cast->castcontext == 'i')
appendPQExpBufferStr(defqry, " AS IMPLICIT");
appendPQExpBufferStr(defqry, ";\n");
appendPQExpBuffer(labelq, "CAST (%s AS %s)",
sourceType, targetType);
appendPQExpBuffer(castargs, "(%s AS %s)",
sourceType, targetType);
if (dopt->binary_upgrade)
binary_upgrade_extension_member(defqry, &cast->dobj, "CAST", castargs->data, NULL);
/* Do nothing if not dumping schema */ if (!dopt->dumpSchema) return;
/* Cannot dump if we don't have the transform functions' info */ if (OidIsValid(transform->trffromsql))
{
fromsqlFuncInfo = findFuncByOid(transform->trffromsql); if (fromsqlFuncInfo == NULL)
pg_fatal("could not find function definition for function with OID %u",
transform->trffromsql);
} if (OidIsValid(transform->trftosql))
{
tosqlFuncInfo = findFuncByOid(transform->trftosql); if (tosqlFuncInfo == NULL)
pg_fatal("could not find function definition for function with OID %u",
transform->trftosql);
}
appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
transformType, lanname);
appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
transformType, lanname);
if (!transform->trffromsql && !transform->trftosql)
pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
if (transform->trffromsql)
{ if (fromsqlFuncInfo)
{ char *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
/* *Alwaysqualifythefunctionname(format_function_signature *won'tqualifyit).
*/
appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
free(fsig);
} else
pg_log_warning("bogus value in pg_transform.trffromsql field");
}
if (transform->trftosql)
{ if (transform->trffromsql)
appendPQExpBufferStr(defqry, ", ");
if (tosqlFuncInfo)
{ char *fsig = format_function_signature(fout, tosqlFuncInfo, true);
/* *Alwaysqualifythefunctionname(format_function_signature *won'tqualifyit).
*/
appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
free(fsig);
} else
pg_log_warning("bogus value in pg_transform.trftosql field");
}
appendPQExpBufferStr(defqry, ");\n");
appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
transformType, lanname);
appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
transformType, lanname);
if (dopt->binary_upgrade)
binary_upgrade_extension_member(defqry, &transform->dobj, "TRANSFORM", transformargs->data, NULL);
/* In PG14 upwards postfix operator support does not exist anymore. */ if (strcmp(oprkind, "r") == 0)
pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
oprcode);
oprregproc = convertRegProcReference(oprcode); if (oprregproc)
{
appendPQExpBuffer(details, " FUNCTION = %s", oprregproc);
free(oprregproc);
}
/* Get additional fields from the pg_opclass row */
appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, " "opckeytype::pg_catalog.regtype, " "opcdefault, opcfamily, " "opfname AS opcfamilyname, " "nspname AS opcfamilynsp, " "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname " "FROM pg_catalog.pg_opclass c " "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily " "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace " "WHERE c.oid = '%u'::pg_catalog.oid",
opcinfo->dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, query->data);
/* opcintype may still be needed after we PQclear res */
opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
opckeytype = PQgetvalue(res, 0, i_opckeytype);
opcdefault = PQgetvalue(res, 0, i_opcdefault); /* opcfamily will still be needed after we PQclear res */
opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp); /* amname will still be needed after we PQclear res */
amname = pg_strdup(PQgetvalue(res, 0, i_amname));
appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
fmtQualifiedDumpable(opcinfo));
appendPQExpBuffer(delq, " USING %s;\n",
fmtId(amname));
/* Build the fixed portion of the CREATE command */
appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
fmtQualifiedDumpable(opcinfo)); if (strcmp(opcdefault, "t") == 0)
appendPQExpBufferStr(q, "DEFAULT ");
appendPQExpBuffer(q, "FOR TYPE %s USING %s",
opcintype,
fmtId(amname)); if (strlen(opcfamilyname) > 0)
{
appendPQExpBufferStr(q, " FAMILY ");
appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
appendPQExpBufferStr(q, fmtId(opcfamilyname));
}
appendPQExpBufferStr(q, " AS\n ");
for (i = 0; i < ntups; i++)
{
amopstrategy = PQgetvalue(res, i, i_amopstrategy);
amopopr = PQgetvalue(res, i, i_amopopr);
sortfamily = PQgetvalue(res, i, i_sortfamily);
sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
if (strlen(sortfamily) > 0)
{
appendPQExpBufferStr(q, " FOR ORDER BY ");
appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
appendPQExpBufferStr(q, fmtId(sortfamily));
}
for (i = 0; i < ntups; i++)
{
amprocnum = PQgetvalue(res, i, i_amprocnum);
amproc = PQgetvalue(res, i, i_amproc);
amproclefttype = PQgetvalue(res, i, i_amproclefttype);
amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
if (needComma)
appendPQExpBufferStr(q, " ,\n ");
appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
if (*amproclefttype && *amprocrighttype)
appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
/* Get additional fields from the pg_opfamily row */
resetPQExpBuffer(query);
appendPQExpBuffer(query, "SELECT " "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname " "FROM pg_catalog.pg_opfamily " "WHERE oid = '%u'::pg_catalog.oid",
opfinfo->dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, query->data);
i_amname = PQfnumber(res, "amname");
/* amname will still be needed after we PQclear res */
amname = pg_strdup(PQgetvalue(res, 0, i_amname));
appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
fmtQualifiedDumpable(opfinfo));
appendPQExpBuffer(delq, " USING %s;\n",
fmtId(amname));
/* Build the fixed portion of the CREATE command */
appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
fmtQualifiedDumpable(opfinfo));
appendPQExpBuffer(q, " USING %s;\n",
fmtId(amname));
PQclear(res);
/* Do we need an ALTER to add loose members? */ if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
{
appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
fmtQualifiedDumpable(opfinfo));
appendPQExpBuffer(q, " USING %s ADD\n ",
fmtId(amname));
for (i = 0; i < ntups; i++)
{
amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
amopopr = PQgetvalue(res_ops, i, i_amopopr);
sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
if (strlen(sortfamily) > 0)
{
appendPQExpBufferStr(q, " FOR ORDER BY ");
appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
appendPQExpBufferStr(q, fmtId(sortfamily));
}
for (i = 0; i < ntups; i++)
{
amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
amproc = PQgetvalue(res_procs, i, i_amproc);
amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
/* *Forbinaryupgrade,carryoverthecollationversion.Fornormal *dump/restore,omittheversion,sothatitiscomputeduponrestore.
*/ if (dopt->binary_upgrade)
{ int i_collversion;
if (!fout->is_prepared[PREPQUERY_DUMPAGG])
{ /* Set up query for aggregate-specific details */
appendPQExpBufferStr(query, "PREPARE dumpAgg(pg_catalog.oid) AS\n");
appendPQExpBufferStr(query, "SELECT " "aggtransfn,\n" "aggfinalfn,\n" "aggtranstype::pg_catalog.regtype,\n" "agginitval,\n" "aggsortop,\n" "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n" "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
if (fout->remoteVersion >= 90400)
appendPQExpBufferStr(query, "aggkind,\n" "aggmtransfn,\n" "aggminvtransfn,\n" "aggmfinalfn,\n" "aggmtranstype::pg_catalog.regtype,\n" "aggfinalextra,\n" "aggmfinalextra,\n" "aggtransspace,\n" "aggmtransspace,\n" "aggminitval,\n"); else
appendPQExpBufferStr(query, "'n' AS aggkind,\n" "'-' AS aggmtransfn,\n" "'-' AS aggminvtransfn,\n" "'-' AS aggmfinalfn,\n" "0 AS aggmtranstype,\n" "false AS aggfinalextra,\n" "false AS aggmfinalextra,\n" "0 AS aggtransspace,\n" "0 AS aggmtransspace,\n" "NULL AS aggminitval,\n");
if (fout->remoteVersion >= 90600)
appendPQExpBufferStr(query, "aggcombinefn,\n" "aggserialfn,\n" "aggdeserialfn,\n" "proparallel,\n"); else
appendPQExpBufferStr(query, "'-' AS aggcombinefn,\n" "'-' AS aggserialfn,\n" "'-' AS aggdeserialfn,\n" "'u' AS proparallel,\n");
if (fout->remoteVersion >= 110000)
appendPQExpBufferStr(query, "aggfinalmodify,\n" "aggmfinalmodify\n"); else
appendPQExpBufferStr(query, "'0' AS aggfinalmodify,\n" "'0' AS aggmfinalmodify\n");
appendPQExpBufferStr(query, "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " "WHERE a.aggfnoid = p.oid " "AND p.oid = $1");
/* the dictinitoption can be dumped straight into the command */ if (dictinfo->dictinitoption)
appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
appendPQExpBufferStr(q, " );\n");
appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
fmtQualifiedDumpable(dictinfo));
if (dopt->binary_upgrade)
binary_upgrade_extension_member(q, &dictinfo->dobj, "TEXT SEARCH DICTIONARY", qdictname,
dictinfo->dobj.namespace->dobj.name);
resetPQExpBuffer(query);
appendPQExpBuffer(query, "SELECT\n" " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n" " WHERE t.tokid = m.maptokentype ) AS tokenname,\n" " m.mapdict::pg_catalog.regdictionary AS dictname\n" "FROM pg_catalog.pg_ts_config_map AS m\n" "WHERE m.mapcfg = '%u'\n" "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
cfginfo->cfgparser, cfginfo->dobj.catId.oid);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res);
for (i = 0; i < ntups; i++)
{ char *tokenname = PQgetvalue(res, i, i_tokenname); char *dictname = PQgetvalue(res, i, i_dictname);
if (i == 0 ||
strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
{ /* starting a new token type, so start a new command */ if (i > 0)
appendPQExpBufferStr(q, ";\n");
appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
fmtQualifiedDumpable(cfginfo)); /* tokenname needs quoting, dictname does NOT */
appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
fmtId(tokenname), dictname);
} else
appendPQExpBuffer(q, ", %s", dictname);
}
if (ntups > 0)
appendPQExpBufferStr(q, ";\n");
PQclear(res);
appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
fmtQualifiedDumpable(cfginfo));
if (dopt->binary_upgrade)
binary_upgrade_extension_member(q, &cfginfo->dobj, "TEXT SEARCH CONFIGURATION", qcfgname,
cfginfo->dobj.namespace->dobj.name);
resetPQExpBuffer(delq);
appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
resetPQExpBuffer(tag);
appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
usename, servername);
/* Do nothing if not dumping schema, or if we're skipping ACLs */ if (!dopt->dumpSchema || dopt->aclsSkip) return;
q = createPQExpBuffer();
tag = createPQExpBuffer();
switch (daclinfo->defaclobjtype)
{ case DEFACLOBJ_RELATION:
type = "TABLES"; break; case DEFACLOBJ_SEQUENCE:
type = "SEQUENCES"; break; case DEFACLOBJ_FUNCTION:
type = "FUNCTIONS"; break; case DEFACLOBJ_TYPE:
type = "TYPES"; break; case DEFACLOBJ_NAMESPACE:
type = "SCHEMAS"; break; case DEFACLOBJ_LARGEOBJECT:
type = "LARGE OBJECTS"; break; default: /* shouldn't get here */
pg_fatal("unrecognized object type in default privileges: %d",
(int) daclinfo->defaclobjtype);
type = ""; /* keep compiler quiet */
}
appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
/* build the actual command(s) for this tuple */ if (!buildDefaultACLCommands(type,
daclinfo->dobj.namespace != NULL ?
daclinfo->dobj.namespace->dobj.name : NULL,
daclinfo->dacl.acl,
daclinfo->dacl.acldefault,
daclinfo->defaclrole,
fout->remoteVersion,
q))
pg_fatal("could not parse default ACL list (%s)",
daclinfo->dacl.acl);
/* do nothing, if --no-security-labels is supplied */ if (dopt->no_security_labels) return;
/* *Securitylabelsareschemanotdata...exceptlargeobjectlabelsare *data
*/ if (strcmp(type, "LARGE OBJECT") != 0)
{ if (!dopt->dumpSchema) return;
} else
{ /* We do dump large object security labels in binary-upgrade mode */ if (!dopt->dumpData && !dopt->binary_upgrade) return;
}
/* Search for security labels associated with catalogId, using table */
nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
query = createPQExpBuffer();
for (i = 0; i < nlabels; i++)
{ /* *Ignorelabelentriesforwhichthesubiddoesn'tmatch.
*/ if (labels[i].objsubid != subid) continue;
appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s ",
fmtId(labels[i].provider), type); if (namespace && *namespace)
appendPQExpBuffer(query, "%s.", fmtId(namespace));
appendPQExpBuffer(query, "%s IS ", name);
appendStringLiteralAH(query, labels[i].label, fout);
appendPQExpBufferStr(query, ";\n");
}
if (query->len > 0)
{
PQExpBuffer tag = createPQExpBuffer();
middle += nmatch; while (middle <= high)
{ if (classoid != middle->classoid ||
objoid != middle->objoid) break;
middle++;
nmatch++;
}
return nmatch;
}
/* *collectSecLabels * *Constructatableofallsecuritylabelsavailablefordatabaseobjects; *alsosetthehas-seclabelcomponentflagforeachrelevantobject. * *Thetableissortedbyclassoid/objid/objsubidforspeedinlookup.
*/ staticvoid
collectSecLabels(Archive *fout)
{
PGresult *res;
PQExpBuffer query; int i_label; int i_provider; int i_classoid; int i_objoid; int i_objsubid; int ntups; int i;
DumpableObject *dobj;
for (i = 0; i < ntups; i++)
{
CatalogId objId; int subid;
objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
objId.oid = atooid(PQgetvalue(res, i, i_objoid));
subid = atoi(PQgetvalue(res, i, i_objsubid));
/* We needn't remember labels that don't match any dumpable object */ if (dobj == NULL ||
dobj->catId.tableoid != objId.tableoid ||
dobj->catId.oid != objId.oid)
dobj = findObjectByCatalogId(objId); if (dobj == NULL) continue;
if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
{ /* Set up query for column ACLs */
appendPQExpBufferStr(query, "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
if (fout->remoteVersion >= 90600)
{ /* *Inprincipleweshouldcallacldefault('c',relowner)to *getthedefaultACLforacolumn.However,wedon't *currentlystorethenumericOIDoftherelownerin *TableInfo.Wecouldconverttheownernameusingregrole, *butthatcreatesariskoffailureduetoconcurrentrole *renames.GiventhatthedefaultACLforcolumnsisempty *andislikelytostaythatway,it'snotworthextracycles *andrisktoavoidhard-wiringthatknowledgehere.
*/
appendPQExpBufferStr(query, "SELECT at.attname, " "at.attacl, " "'{}' AS acldefault, " "pip.privtype, pip.initprivs " "FROM pg_catalog.pg_attribute at " "LEFT JOIN pg_catalog.pg_init_privs pip ON " "(at.attrelid = pip.objoid " "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass " "AND at.attnum = pip.objsubid) " "WHERE at.attrelid = $1 AND " "NOT at.attisdropped " "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) " "ORDER BY at.attnum");
} else
{
appendPQExpBufferStr(query, "SELECT attname, attacl, '{}' AS acldefault, " "NULL AS privtype, NULL AS initprivs " "FROM pg_catalog.pg_attribute " "WHERE attrelid = $1 AND NOT attisdropped " "AND attacl IS NOT NULL " "ORDER BY attnum");
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.