PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_dump.c File Reference
#include "postgres_fe.h"
#include <unistd.h>
#include <ctype.h>
#include <limits.h>
#include "access/attnum.h"
#include "access/sysattr.h"
#include "access/transam.h"
#include "catalog/pg_aggregate_d.h"
#include "catalog/pg_am_d.h"
#include "catalog/pg_attribute_d.h"
#include "catalog/pg_authid_d.h"
#include "catalog/pg_cast_d.h"
#include "catalog/pg_class_d.h"
#include "catalog/pg_constraint_d.h"
#include "catalog/pg_default_acl_d.h"
#include "catalog/pg_largeobject_d.h"
#include "catalog/pg_largeobject_metadata_d.h"
#include "catalog/pg_proc_d.h"
#include "catalog/pg_publication_d.h"
#include "catalog/pg_shdepend_d.h"
#include "catalog/pg_subscription_d.h"
#include "catalog/pg_type_d.h"
#include "common/connect.h"
#include "common/int.h"
#include "common/relpath.h"
#include "common/shortest_dec.h"
#include "compress_io.h"
#include "dumputils.h"
#include "fe_utils/option_utils.h"
#include "fe_utils/string_utils.h"
#include "filter.h"
#include "getopt_long.h"
#include "libpq/libpq-fs.h"
#include "parallel.h"
#include "pg_backup_db.h"
#include "pg_backup_utils.h"
#include "pg_dump.h"
#include "statistics/statistics_format.h"
#include "storage/block.h"
Include dependency graph for pg_dump.c:

Go to the source code of this file.

Data Structures

struct  RoleNameItem
 
struct  CommentItem
 
struct  SecLabelItem
 
struct  BinaryUpgradeClassOidItem
 
struct  SequenceItem
 

Macros

#define MAX_ATTR_STATS_RELS   64
 
#define DUMP_DEFAULT_ROWS_PER_INSERT   1
 
#define MAX_BLOBS_PER_ARCHIVE_ENTRY   1000
 
#define fmtQualifiedDumpable(obj)
 

Typedefs

typedef enum SeqType SeqType
 
typedef enum OidOptions OidOptions
 

Enumerations

enum  SeqType { SEQTYPE_SMALLINT , SEQTYPE_INTEGER , SEQTYPE_BIGINT }
 
enum  OidOptions { zeroIsError = 1 , zeroAsStar = 2 , zeroAsNone = 4 }
 

Functions

 StaticAssertDecl (lengthof(SeqTypeNames)==(SEQTYPE_BIGINT+1), "array length mismatch")
 
static void help (const char *progname)
 
static void setup_connection (Archive *AH, const char *dumpencoding, const char *dumpsnapshot, char *use_role)
 
static ArchiveFormat parseArchiveFormat (const char *format, ArchiveMode *mode)
 
static void expand_schema_name_patterns (Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names)
 
static void expand_extension_name_patterns (Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names)
 
static void expand_foreign_server_name_patterns (Archive *fout, SimpleStringList *patterns, SimpleOidList *oids)
 
static void expand_table_name_patterns (Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names, bool with_child_tables)
 
static void prohibit_crossdb_refs (PGconn *conn, const char *dbname, const char *pattern)
 
static NamespaceInfofindNamespace (Oid nsoid)
 
static void dumpTableData (Archive *fout, const TableDataInfo *tdinfo)
 
static void refreshMatViewData (Archive *fout, const TableDataInfo *tdinfo)
 
static const chargetRoleName (const char *roleoid_str)
 
static void collectRoleNames (Archive *fout)
 
static void getAdditionalACLs (Archive *fout)
 
static void dumpCommentExtended (Archive *fout, const char *type, const char *name, const char *namespace, const char *owner, CatalogId catalogId, int subid, DumpId dumpId, const char *initdb_comment)
 
static void dumpComment (Archive *fout, const char *type, const char *name, const char *namespace, const char *owner, CatalogId catalogId, int subid, DumpId dumpId)
 
static int findComments (Oid classoid, Oid objoid, CommentItem **items)
 
static void collectComments (Archive *fout)
 
static void dumpSecLabel (Archive *fout, const char *type, const char *name, const char *namespace, const char *owner, CatalogId catalogId, int subid, DumpId dumpId)
 
static int findSecLabels (Oid classoid, Oid objoid, SecLabelItem **items)
 
static void collectSecLabels (Archive *fout)
 
static void dumpDumpableObject (Archive *fout, DumpableObject *dobj)
 
static void dumpNamespace (Archive *fout, const NamespaceInfo *nspinfo)
 
static void dumpExtension (Archive *fout, const ExtensionInfo *extinfo)
 
static void dumpType (Archive *fout, const TypeInfo *tyinfo)
 
static void dumpBaseType (Archive *fout, const TypeInfo *tyinfo)
 
static void dumpEnumType (Archive *fout, const TypeInfo *tyinfo)
 
static void dumpRangeType (Archive *fout, const TypeInfo *tyinfo)
 
static void dumpUndefinedType (Archive *fout, const TypeInfo *tyinfo)
 
static void dumpDomain (Archive *fout, const TypeInfo *tyinfo)
 
static void dumpCompositeType (Archive *fout, const TypeInfo *tyinfo)
 
static void dumpCompositeTypeColComments (Archive *fout, const TypeInfo *tyinfo, PGresult *res)
 
static void dumpShellType (Archive *fout, const ShellTypeInfo *stinfo)
 
static void dumpProcLang (Archive *fout, const ProcLangInfo *plang)
 
static void dumpFunc (Archive *fout, const FuncInfo *finfo)
 
static void dumpCast (Archive *fout, const CastInfo *cast)
 
static void dumpTransform (Archive *fout, const TransformInfo *transform)
 
static void dumpOpr (Archive *fout, const OprInfo *oprinfo)
 
static void dumpAccessMethod (Archive *fout, const AccessMethodInfo *aminfo)
 
static void dumpOpclass (Archive *fout, const OpclassInfo *opcinfo)
 
static void dumpOpfamily (Archive *fout, const OpfamilyInfo *opfinfo)
 
static void dumpCollation (Archive *fout, const CollInfo *collinfo)
 
static void dumpConversion (Archive *fout, const ConvInfo *convinfo)
 
static void dumpRule (Archive *fout, const RuleInfo *rinfo)
 
static void dumpAgg (Archive *fout, const AggInfo *agginfo)
 
static void dumpTrigger (Archive *fout, const TriggerInfo *tginfo)
 
static void dumpEventTrigger (Archive *fout, const EventTriggerInfo *evtinfo)
 
static void dumpTable (Archive *fout, const TableInfo *tbinfo)
 
static void dumpTableSchema (Archive *fout, const TableInfo *tbinfo)
 
static void dumpTableAttach (Archive *fout, const TableAttachInfo *attachinfo)
 
static void dumpAttrDef (Archive *fout, const AttrDefInfo *adinfo)
 
static void collectSequences (Archive *fout)
 
static void dumpSequence (Archive *fout, const TableInfo *tbinfo)
 
static void dumpSequenceData (Archive *fout, const TableDataInfo *tdinfo)
 
static void dumpIndex (Archive *fout, const IndxInfo *indxinfo)
 
static void dumpIndexAttach (Archive *fout, const IndexAttachInfo *attachinfo)
 
static void dumpStatisticsExt (Archive *fout, const StatsExtInfo *statsextinfo)
 
static void dumpStatisticsExtStats (Archive *fout, const StatsExtInfo *statsextinfo)
 
static void dumpConstraint (Archive *fout, const ConstraintInfo *coninfo)
 
static void dumpTableConstraintComment (Archive *fout, const ConstraintInfo *coninfo)
 
static void dumpTSParser (Archive *fout, const TSParserInfo *prsinfo)
 
static void dumpTSDictionary (Archive *fout, const TSDictInfo *dictinfo)
 
static void dumpTSTemplate (Archive *fout, const TSTemplateInfo *tmplinfo)
 
static void dumpTSConfig (Archive *fout, const TSConfigInfo *cfginfo)
 
static void dumpForeignDataWrapper (Archive *fout, const FdwInfo *fdwinfo)
 
static void dumpForeignServer (Archive *fout, const ForeignServerInfo *srvinfo)
 
static void dumpUserMappings (Archive *fout, const char *servername, const char *namespace, const char *owner, CatalogId catalogId, DumpId dumpId)
 
static void dumpDefaultACL (Archive *fout, const DefaultACLInfo *daclinfo)
 
static DumpId dumpACL (Archive *fout, DumpId objDumpId, DumpId altDumpId, const char *type, const char *name, const char *subname, const char *nspname, const char *tag, const char *owner, const DumpableAcl *dacl)
 
static void getDependencies (Archive *fout)
 
static void BuildArchiveDependencies (Archive *fout)
 
static void findDumpableDependencies (ArchiveHandle *AH, const DumpableObject *dobj, DumpId **dependencies, int *nDeps, int *allocDeps)
 
static DumpableObjectcreateBoundaryObjects (void)
 
static void addBoundaryDependencies (DumpableObject **dobjs, int numObjs, DumpableObject *boundaryObjs)
 
static void addConstrChildIdxDeps (DumpableObject *dobj, const IndxInfo *refidx)
 
static void getDomainConstraints (Archive *fout, TypeInfo *tyinfo)
 
static void getTableData (DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
 
static void makeTableDataInfo (DumpOptions *dopt, TableInfo *tbinfo)
 
static void buildMatViewRefreshDependencies (Archive *fout)
 
static void getTableDataFKConstraints (void)
 
static void determineNotNullFlags (Archive *fout, PGresult *res, int r, TableInfo *tbinfo, int j, int i_notnull_name, int i_notnull_comment, int i_notnull_invalidoid, int i_notnull_noinherit, int i_notnull_islocal, PQExpBuffer *invalidnotnulloids)
 
static charformat_function_arguments (const FuncInfo *finfo, const char *funcargs, bool is_agg)
 
static charformat_function_signature (Archive *fout, const FuncInfo *finfo, bool honor_quotes)
 
static charconvertRegProcReference (const char *proc)
 
static chargetFormattedOperatorName (const char *oproid)
 
static charconvertTSFunction (Archive *fout, Oid funcOid)
 
static const chargetFormattedTypeName (Archive *fout, Oid oid, OidOptions opts)
 
static void getLOs (Archive *fout)
 
static void dumpLO (Archive *fout, const LoInfo *loinfo)
 
static int dumpLOs (Archive *fout, const void *arg)
 
static void dumpPolicy (Archive *fout, const PolicyInfo *polinfo)
 
static void dumpPublication (Archive *fout, const PublicationInfo *pubinfo)
 
static void dumpPublicationTable (Archive *fout, const PublicationRelInfo *pubrinfo)
 
static void dumpSubscription (Archive *fout, const SubscriptionInfo *subinfo)
 
static void dumpSubscriptionTable (Archive *fout, const SubRelInfo *subrinfo)
 
static void dumpDatabase (Archive *fout)
 
static void dumpDatabaseConfig (Archive *AH, PQExpBuffer outbuf, const char *dbname, Oid dboid)
 
static void dumpEncoding (Archive *AH)
 
static void dumpStdStrings (Archive *AH)
 
static void dumpSearchPath (Archive *AH)
 
static void binary_upgrade_set_type_oids_by_type_oid (Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_type_oid, bool force_array_type, bool include_multirange_type)
 
static void binary_upgrade_set_type_oids_by_rel (Archive *fout, PQExpBuffer upgrade_buffer, const TableInfo *tbinfo)
 
static void collectBinaryUpgradeClassOids (Archive *fout)
 
static void binary_upgrade_set_pg_class_oids (Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_class_oid)
 
static void binary_upgrade_extension_member (PQExpBuffer upgrade_buffer, const DumpableObject *dobj, const char *objtype, const char *objname, const char *objnamespace)
 
static const chargetAttrName (int attrnum, const TableInfo *tblInfo)
 
static const charfmtCopyColumnList (const TableInfo *ti, PQExpBuffer buffer)
 
static bool nonemptyReloptions (const char *reloptions)
 
static void appendReloptionsArrayAH (PQExpBuffer buffer, const char *reloptions, const char *prefix, Archive *fout)
 
static charget_synchronized_snapshot (Archive *fout)
 
static void set_restrict_relation_kind (Archive *AH, const char *value)
 
static void setupDumpWorker (Archive *AH)
 
static TableInfogetRootTableInfo (const TableInfo *tbinfo)
 
static bool forcePartitionRootLoad (const TableInfo *tbinfo)
 
static void read_dump_filters (const char *filename, DumpOptions *dopt)
 
int main (int argc, char **argv)
 
static bool checkExtensionMembership (DumpableObject *dobj, Archive *fout)
 
static void selectDumpableNamespace (NamespaceInfo *nsinfo, Archive *fout)
 
static void selectDumpableTable (TableInfo *tbinfo, Archive *fout)
 
static void selectDumpableType (TypeInfo *tyinfo, Archive *fout)
 
static void selectDumpableDefaultACL (DefaultACLInfo *dinfo, DumpOptions *dopt)
 
static void selectDumpableCast (CastInfo *cast, Archive *fout)
 
static void selectDumpableProcLang (ProcLangInfo *plang, Archive *fout)
 
static void selectDumpableAccessMethod (AccessMethodInfo *method, Archive *fout)
 
static void selectDumpableExtension (ExtensionInfo *extinfo, DumpOptions *dopt)
 
static void selectDumpablePublicationObject (DumpableObject *dobj, Archive *fout)
 
static void selectDumpableStatisticsObject (StatsExtInfo *sobj, Archive *fout)
 
static void selectDumpableObject (DumpableObject *dobj, Archive *fout)
 
static int dumpTableData_copy (Archive *fout, const void *dcontext)
 
static int dumpTableData_insert (Archive *fout, const void *dcontext)
 
void getPolicies (Archive *fout, TableInfo tblinfo[], int numTables)
 
void getPublications (Archive *fout)
 
void getPublicationNamespaces (Archive *fout)
 
void getPublicationTables (Archive *fout, TableInfo tblinfo[], int numTables)
 
static void dumpPublicationNamespace (Archive *fout, const PublicationSchemaInfo *pubsinfo)
 
static bool is_superuser (Archive *fout)
 
void getSubscriptions (Archive *fout)
 
void getSubscriptionRelations (Archive *fout)
 
static void append_depends_on_extension (Archive *fout, PQExpBuffer create, const DumpableObject *dobj, const char *catalog, const char *keyword, const char *objname)
 
static Oid get_next_possible_free_pg_type_oid (Archive *fout, PQExpBuffer upgrade_query)
 
static int BinaryUpgradeClassOidItemCmp (const void *p1, const void *p2)
 
void getNamespaces (Archive *fout)
 
ExtensionInfogetExtensions (Archive *fout, int *numExtensions)
 
void getTypes (Archive *fout)
 
void getOperators (Archive *fout)
 
void getCollations (Archive *fout)
 
void getConversions (Archive *fout)
 
void getAccessMethods (Archive *fout)
 
void getOpclasses (Archive *fout)
 
void getOpfamilies (Archive *fout)
 
void getAggregates (Archive *fout)
 
void getFuncs (Archive *fout)
 
static RelStatsInfogetRelationStatistics (Archive *fout, DumpableObject *rel, int32 relpages, char *reltuples, int32 relallvisible, int32 relallfrozen, char relkind, char **indAttNames, int nindAttNames)
 
TableInfogetTables (Archive *fout, int *numTables)
 
void getOwnedSeqs (Archive *fout, TableInfo tblinfo[], int numTables)
 
InhInfogetInherits (Archive *fout, int *numInherits)
 
void getPartitioningInfo (Archive *fout)
 
void getIndexes (Archive *fout, TableInfo tblinfo[], int numTables)
 
void getExtendedStatistics (Archive *fout)
 
void getConstraints (Archive *fout, TableInfo tblinfo[], int numTables)
 
void getRules (Archive *fout)
 
void getTriggers (Archive *fout, TableInfo tblinfo[], int numTables)
 
void getEventTriggers (Archive *fout)
 
void getProcLangs (Archive *fout)
 
void getCasts (Archive *fout)
 
static charget_language_name (Archive *fout, Oid langid)
 
void getTransforms (Archive *fout)
 
void getTableAttrs (Archive *fout, TableInfo *tblinfo, int numTables)
 
bool shouldPrintColumn (const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
 
void getTSParsers (Archive *fout)
 
void getTSDictionaries (Archive *fout)
 
void getTSTemplates (Archive *fout)
 
void getTSConfigurations (Archive *fout)
 
void getForeignDataWrappers (Archive *fout)
 
void getForeignServers (Archive *fout)
 
void getDefaultACLs (Archive *fout)
 
static void appendNamedArgument (PQExpBuffer out, Archive *fout, const char *argname, const char *argtype, const char *argval)
 
static PGresultfetchAttributeStats (Archive *fout)
 
static chardumpRelationStats_dumper (Archive *fout, const void *userArg, const TocEntry *te)
 
static void dumpRelationStats (Archive *fout, const RelStatsInfo *rsinfo)
 
static void dumpTableComment (Archive *fout, const TableInfo *tbinfo, const char *reltypename)
 
static charformat_aggregate_signature (const AggInfo *agginfo, Archive *fout, bool honor_quotes)
 
static void dumpTableSecLabel (Archive *fout, const TableInfo *tbinfo, const char *reltypename)
 
static PQExpBuffer createViewAsClause (Archive *fout, const TableInfo *tbinfo)
 
static PQExpBuffer createDummyViewAsClause (Archive *fout, const TableInfo *tbinfo)
 
static SeqType parse_sequence_type (const char *name)
 
static int SequenceItemCmp (const void *p1, const void *p2)
 
void getExtensionMembership (Archive *fout, ExtensionInfo extinfo[], int numExtensions)
 
void processExtensionTables (Archive *fout, ExtensionInfo extinfo[], int numExtensions)
 

Variables

static const char *const SeqTypeNames []
 
static bool dosync = true
 
static Oid g_last_builtin_oid
 
static int strict_names = 0
 
static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE
 
static SimpleStringList schema_include_patterns = {NULL, NULL}
 
static SimpleOidList schema_include_oids = {NULL, NULL}
 
static SimpleStringList schema_exclude_patterns = {NULL, NULL}
 
static SimpleOidList schema_exclude_oids = {NULL, NULL}
 
static SimpleStringList table_include_patterns = {NULL, NULL}
 
static SimpleStringList table_include_patterns_and_children = {NULL, NULL}
 
static SimpleOidList table_include_oids = {NULL, NULL}
 
static SimpleStringList table_exclude_patterns = {NULL, NULL}
 
static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL}
 
static SimpleOidList table_exclude_oids = {NULL, NULL}
 
static SimpleStringList tabledata_exclude_patterns = {NULL, NULL}
 
static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL}
 
static SimpleOidList tabledata_exclude_oids = {NULL, NULL}
 
static SimpleStringList foreign_servers_include_patterns = {NULL, NULL}
 
static SimpleOidList foreign_servers_include_oids = {NULL, NULL}
 
static SimpleStringList extension_include_patterns = {NULL, NULL}
 
static SimpleOidList extension_include_oids = {NULL, NULL}
 
static SimpleStringList extension_exclude_patterns = {NULL, NULL}
 
static SimpleOidList extension_exclude_oids = {NULL, NULL}
 
static const CatalogId nilCatalogId = {0, 0}
 
static bool have_extra_float_digits = false
 
static int extra_float_digits
 
static RoleNameItemrolenames = NULL
 
static int nrolenames = 0
 
static CommentItemcomments = NULL
 
static int ncomments = 0
 
static SecLabelItemseclabels = NULL
 
static int nseclabels = 0
 
static BinaryUpgradeClassOidItembinaryUpgradeClassOids = NULL
 
static int nbinaryUpgradeClassOids = 0
 
static SequenceItemsequences = NULL
 
static int nsequences = 0
 

Macro Definition Documentation

◆ DUMP_DEFAULT_ROWS_PER_INSERT

#define DUMP_DEFAULT_ROWS_PER_INSERT   1

Definition at line 224 of file pg_dump.c.

◆ fmtQualifiedDumpable

#define fmtQualifiedDumpable (   obj)
Value:
fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
(obj)->dobj.name)
const char * fmtQualifiedId(const char *schema, const char *id)

Definition at line 236 of file pg_dump.c.

418{
419 int c;
420 const char *filename = NULL;
421 const char *format = "p";
422 TableInfo *tblinfo;
423 int numTables;
425 int numObjs;
427 int i;
428 int optindex;
429 RestoreOptions *ropt;
430 Archive *fout; /* the script file */
431 bool g_verbose = false;
432 const char *dumpencoding = NULL;
433 const char *dumpsnapshot = NULL;
434 char *use_role = NULL;
435 int numWorkers = 1;
436 int plainText = 0;
439 pg_compress_specification compression_spec = {0};
440 char *compression_detail = NULL;
441 char *compression_algorithm_str = "none";
442 char *error_detail = NULL;
443 bool user_compression_defined = false;
445 bool data_only = false;
446 bool schema_only = false;
447 bool statistics_only = false;
448 bool with_statistics = false;
449 bool no_data = false;
450 bool no_schema = false;
451 bool no_statistics = false;
452
453 static DumpOptions dopt;
454
455 static struct option long_options[] = {
456 {"data-only", no_argument, NULL, 'a'},
457 {"blobs", no_argument, NULL, 'b'},
458 {"large-objects", no_argument, NULL, 'b'},
459 {"no-blobs", no_argument, NULL, 'B'},
460 {"no-large-objects", no_argument, NULL, 'B'},
461 {"clean", no_argument, NULL, 'c'},
462 {"create", no_argument, NULL, 'C'},
463 {"dbname", required_argument, NULL, 'd'},
464 {"extension", required_argument, NULL, 'e'},
465 {"file", required_argument, NULL, 'f'},
466 {"format", required_argument, NULL, 'F'},
467 {"host", required_argument, NULL, 'h'},
468 {"jobs", 1, NULL, 'j'},
469 {"no-reconnect", no_argument, NULL, 'R'},
470 {"no-owner", no_argument, NULL, 'O'},
471 {"port", required_argument, NULL, 'p'},
472 {"schema", required_argument, NULL, 'n'},
473 {"exclude-schema", required_argument, NULL, 'N'},
474 {"schema-only", no_argument, NULL, 's'},
475 {"superuser", required_argument, NULL, 'S'},
476 {"table", required_argument, NULL, 't'},
477 {"exclude-table", required_argument, NULL, 'T'},
478 {"no-password", no_argument, NULL, 'w'},
479 {"password", no_argument, NULL, 'W'},
480 {"username", required_argument, NULL, 'U'},
481 {"verbose", no_argument, NULL, 'v'},
482 {"no-privileges", no_argument, NULL, 'x'},
483 {"no-acl", no_argument, NULL, 'x'},
484 {"compress", required_argument, NULL, 'Z'},
485 {"encoding", required_argument, NULL, 'E'},
486 {"help", no_argument, NULL, '?'},
487 {"version", no_argument, NULL, 'V'},
488
489 /*
490 * the following options don't have an equivalent short option letter
491 */
492 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
493 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
494 {"column-inserts", no_argument, &dopt.column_inserts, 1},
495 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
496 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
497 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
498 {"exclude-table-data", required_argument, NULL, 4},
499 {"extra-float-digits", required_argument, NULL, 8},
500 {"if-exists", no_argument, &dopt.if_exists, 1},
501 {"inserts", no_argument, NULL, 9},
502 {"lock-wait-timeout", required_argument, NULL, 2},
503 {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
504 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
505 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
506 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
507 {"role", required_argument, NULL, 3},
508 {"section", required_argument, NULL, 5},
509 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
510 {"snapshot", required_argument, NULL, 6},
511 {"statistics", no_argument, NULL, 22},
512 {"statistics-only", no_argument, NULL, 18},
513 {"strict-names", no_argument, &strict_names, 1},
514 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
515 {"no-comments", no_argument, &dopt.no_comments, 1},
516 {"no-data", no_argument, NULL, 19},
517 {"no-policies", no_argument, &dopt.no_policies, 1},
518 {"no-publications", no_argument, &dopt.no_publications, 1},
519 {"no-schema", no_argument, NULL, 20},
520 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
521 {"no-statistics", no_argument, NULL, 21},
522 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
523 {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
524 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
525 {"no-sync", no_argument, NULL, 7},
526 {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
527 {"rows-per-insert", required_argument, NULL, 10},
528 {"include-foreign-data", required_argument, NULL, 11},
529 {"table-and-children", required_argument, NULL, 12},
530 {"exclude-table-and-children", required_argument, NULL, 13},
531 {"exclude-table-data-and-children", required_argument, NULL, 14},
532 {"sync-method", required_argument, NULL, 15},
533 {"filter", required_argument, NULL, 16},
534 {"exclude-extension", required_argument, NULL, 17},
535 {"sequence-data", no_argument, &dopt.sequence_data, 1},
536 {"restrict-key", required_argument, NULL, 25},
537
538 {NULL, 0, NULL, 0}
539 };
540
541 pg_logging_init(argv[0]);
543 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
544
545 /*
546 * Initialize what we need for parallel execution, especially for thread
547 * support on Windows.
548 */
550
551 progname = get_progname(argv[0]);
552
553 if (argc > 1)
554 {
555 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
556 {
557 help(progname);
558 exit_nicely(0);
559 }
560 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
561 {
562 puts("pg_dump (PostgreSQL) " PG_VERSION);
563 exit_nicely(0);
564 }
565 }
566
567 InitDumpOptions(&dopt);
568
569 while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
570 long_options, &optindex)) != -1)
571 {
572 switch (c)
573 {
574 case 'a': /* Dump data only */
575 data_only = true;
576 break;
577
578 case 'b': /* Dump LOs */
579 dopt.outputLOs = true;
580 break;
581
582 case 'B': /* Don't dump LOs */
583 dopt.dontOutputLOs = true;
584 break;
585
586 case 'c': /* clean (i.e., drop) schema prior to create */
587 dopt.outputClean = 1;
588 break;
589
590 case 'C': /* Create DB */
591 dopt.outputCreateDB = 1;
592 break;
593
594 case 'd': /* database name */
596 break;
597
598 case 'e': /* include extension(s) */
600 dopt.include_everything = false;
601 break;
602
603 case 'E': /* Dump encoding */
605 break;
606
607 case 'f':
609 break;
610
611 case 'F':
613 break;
614
615 case 'h': /* server host */
617 break;
618
619 case 'j': /* number of dump jobs */
620 if (!option_parse_int(optarg, "-j/--jobs", 1,
622 &numWorkers))
623 exit_nicely(1);
624 break;
625
626 case 'n': /* include schema(s) */
628 dopt.include_everything = false;
629 break;
630
631 case 'N': /* exclude schema(s) */
633 break;
634
635 case 'O': /* Don't reconnect to match owner */
636 dopt.outputNoOwner = 1;
637 break;
638
639 case 'p': /* server port */
641 break;
642
643 case 'R':
644 /* no-op, still accepted for backwards compatibility */
645 break;
646
647 case 's': /* dump schema only */
648 schema_only = true;
649 break;
650
651 case 'S': /* Username for superuser in plain text output */
653 break;
654
655 case 't': /* include table(s) */
657 dopt.include_everything = false;
658 break;
659
660 case 'T': /* exclude table(s) */
662 break;
663
664 case 'U':
666 break;
667
668 case 'v': /* verbose */
669 g_verbose = true;
671 break;
672
673 case 'w':
675 break;
676
677 case 'W':
679 break;
680
681 case 'x': /* skip ACL dump */
682 dopt.aclsSkip = true;
683 break;
684
685 case 'Z': /* Compression */
689 break;
690
691 case 0:
692 /* This covers the long options. */
693 break;
694
695 case 2: /* lock-wait-timeout */
697 break;
698
699 case 3: /* SET ROLE */
700 use_role = pg_strdup(optarg);
701 break;
702
703 case 4: /* exclude table(s) data */
705 break;
706
707 case 5: /* section */
709 break;
710
711 case 6: /* snapshot */
713 break;
714
715 case 7: /* no-sync */
716 dosync = false;
717 break;
718
719 case 8:
721 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
723 exit_nicely(1);
724 break;
725
726 case 9: /* inserts */
727
728 /*
729 * dump_inserts also stores --rows-per-insert, careful not to
730 * overwrite that.
731 */
732 if (dopt.dump_inserts == 0)
734 break;
735
736 case 10: /* rows per insert */
737 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
738 &dopt.dump_inserts))
739 exit_nicely(1);
740 break;
741
742 case 11: /* include foreign data */
744 optarg);
745 break;
746
747 case 12: /* include table(s) and their children */
749 optarg);
750 dopt.include_everything = false;
751 break;
752
753 case 13: /* exclude table(s) and their children */
755 optarg);
756 break;
757
758 case 14: /* exclude data of table(s) and children */
760 optarg);
761 break;
762
763 case 15:
765 exit_nicely(1);
766 break;
767
768 case 16: /* read object filters from file */
770 break;
771
772 case 17: /* exclude extension(s) */
774 optarg);
775 break;
776
777 case 18:
778 statistics_only = true;
779 break;
780
781 case 19:
782 no_data = true;
783 break;
784
785 case 20:
786 no_schema = true;
787 break;
788
789 case 21:
790 no_statistics = true;
791 break;
792
793 case 22:
794 with_statistics = true;
795 break;
796
797 case 25:
799 break;
800
801 default:
802 /* getopt_long already emitted a complaint */
803 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
804 exit_nicely(1);
805 }
806 }
807
808 /*
809 * Non-option argument specifies database name as long as it wasn't
810 * already specified with -d / --dbname
811 */
812 if (optind < argc && dopt.cparams.dbname == NULL)
813 dopt.cparams.dbname = argv[optind++];
814
815 /* Complain if any arguments remain */
816 if (optind < argc)
817 {
818 pg_log_error("too many command-line arguments (first is \"%s\")",
819 argv[optind]);
820 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
821 exit_nicely(1);
822 }
823
824 /* --column-inserts implies --inserts */
825 if (dopt.column_inserts && dopt.dump_inserts == 0)
827
828 /* *-only options are incompatible with each other */
829 check_mut_excl_opts(data_only, "-a/--data-only",
830 schema_only, "-s/--schema-only",
831 statistics_only, "--statistics-only");
832
833 /* --no-* and *-only for same thing are incompatible */
834 check_mut_excl_opts(data_only, "-a/--data-only",
835 no_data, "--no-data");
836 check_mut_excl_opts(schema_only, "-s/--schema-only",
837 no_schema, "--no-schema");
838 check_mut_excl_opts(statistics_only, "--statistics-only",
839 no_statistics, "--no-statistics");
840
841 /* --statistics and --no-statistics are incompatible */
842 check_mut_excl_opts(with_statistics, "--statistics",
843 no_statistics, "--no-statistics");
844
845 /* --statistics is incompatible with *-only (except --statistics-only) */
846 check_mut_excl_opts(with_statistics, "--statistics",
847 data_only, "-a/--data-only",
848 schema_only, "-s/--schema-only");
849
850 /* --include-foreign-data is incompatible with --schema-only */
852 schema_only, "-s/--schema-only");
853
854 if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
855 pg_fatal("option %s is not supported with parallel backup",
856 "--include-foreign-data");
857
858 /* --clean is incompatible with --data-only */
859 check_mut_excl_opts(dopt.outputClean, "-c/--clean",
860 data_only, "-a/--data-only");
861
862 if (dopt.if_exists && !dopt.outputClean)
863 pg_fatal("option %s requires option %s",
864 "--if-exists", "-c/--clean");
865
866 /*
867 * Set derivative flags. Ambiguous or nonsensical combinations, e.g.
868 * "--schema-only --no-schema", will have already caused an error in one
869 * of the checks above.
870 */
871 dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
872 data_only) && !no_data;
873 dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
875 dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
877
878
879 /*
880 * --inserts are already implied above if --column-inserts or
881 * --rows-per-insert were specified.
882 */
883 if (dopt.do_nothing && dopt.dump_inserts == 0)
884 pg_fatal("option %s requires option %s, %s, or %s",
885 "--on-conflict-do-nothing",
886 "--inserts", "--rows-per-insert", "--column-inserts");
887
888 /* Identify archive format to emit */
890
891 /* archiveFormat specific setup */
892 if (archiveFormat == archNull)
893 {
894 plainText = 1;
895
896 /*
897 * If you don't provide a restrict key, one will be appointed for you.
898 */
899 if (!dopt.restrict_key)
901 if (!dopt.restrict_key)
902 pg_fatal("could not generate restrict key");
904 pg_fatal("invalid restrict key");
905 }
906 else if (dopt.restrict_key)
907 pg_fatal("option %s can only be used with %s",
908 "--restrict-key", "--format=plain");
909
910 /*
911 * Custom and directory formats are compressed by default with gzip when
912 * available, not the others. If gzip is not available, no compression is
913 * done by default.
914 */
917 {
918#ifdef HAVE_LIBZ
920#else
922#endif
923 }
924
925 /*
926 * Compression options
927 */
930 pg_fatal("unrecognized compression algorithm: \"%s\"",
932
934 &compression_spec);
936 if (error_detail != NULL)
937 pg_fatal("invalid compression specification: %s",
939
940 error_detail = supports_compression(compression_spec);
941 if (error_detail != NULL)
942 pg_fatal("%s", error_detail);
943
944 /*
945 * Disable support for zstd workers for now - these are based on
946 * threading, and it's unclear how it interacts with parallel dumps on
947 * platforms where that relies on threads too (e.g. Windows).
948 */
949 if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
950 pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
951 "workers");
952
953 /*
954 * If emitting an archive format, we always want to emit a DATABASE item,
955 * in case --create is specified at pg_restore time.
956 */
957 if (!plainText)
958 dopt.outputCreateDB = 1;
959
960 /* Parallel backup only in the directory archive format so far */
961 if (archiveFormat != archDirectory && numWorkers > 1)
962 pg_fatal("parallel backup only supported by the directory format");
963
964 /* Open the output file */
965 fout = CreateArchive(filename, archiveFormat, compression_spec,
967
968 /* Make dump options accessible right away */
969 SetArchiveOptions(fout, &dopt, NULL);
970
971 /* Register the cleanup hook */
973
974 /* Let the archiver know how noisy to be */
975 fout->verbose = g_verbose;
976
977
978 /*
979 * We allow the server to be back to 10, and up to any minor release of
980 * our own major version. (See also version check in pg_dumpall.c.)
981 */
982 fout->minRemoteVersion = 100000;
983 fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
984
985 fout->numWorkers = numWorkers;
986
987 /*
988 * Open the database using the Archiver, so it knows about it. Errors mean
989 * death.
990 */
991 ConnectDatabaseAhx(fout, &dopt.cparams, false);
993
994 /*
995 * On hot standbys, never try to dump unlogged table data, since it will
996 * just throw an error.
997 */
998 if (fout->isStandby)
999 dopt.no_unlogged_table_data = true;
1000
1001 /*
1002 * Find the last built-in OID, if needed (prior to 8.1)
1003 *
1004 * With 8.1 and above, we can just use FirstNormalObjectId - 1.
1005 */
1007
1008 pg_log_info("last built-in OID is %u", g_last_builtin_oid);
1009
1010 /* Expand schema selection patterns into OID lists */
1012 {
1015 strict_names);
1017 pg_fatal("no matching schemas were found");
1018 }
1021 false);
1022 /* non-matching exclusion patterns aren't an error */
1023
1024 /* Expand table selection patterns into OID lists */
1027 strict_names, false);
1030 strict_names, true);
1034 pg_fatal("no matching tables were found");
1035
1038 false, false);
1041 false, true);
1042
1045 false, false);
1048 false, true);
1049
1052
1053 /* non-matching exclusion patterns aren't an error */
1054
1055 /* Expand extension selection patterns into OID lists */
1057 {
1060 strict_names);
1062 pg_fatal("no matching extensions were found");
1063 }
1066 false);
1067 /* non-matching exclusion patterns aren't an error */
1068
1069 /*
1070 * Dumping LOs is the default for dumps where an inclusion switch is not
1071 * used (an "include everything" dump). -B can be used to exclude LOs
1072 * from those dumps. -b can be used to include LOs even when an inclusion
1073 * switch is used.
1074 *
1075 * -s means "schema only" and LOs are data, not schema, so we never
1076 * include LOs when -s is used.
1077 */
1078 if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
1079 dopt.outputLOs = true;
1080
1081 /*
1082 * Collect role names so we can map object owner OIDs to names.
1083 */
1085
1086 /*
1087 * Now scan the database and create DumpableObject structs for all the
1088 * objects we intend to dump.
1089 */
1090 tblinfo = getSchemaData(fout, &numTables);
1091
1092 if (dopt.dumpData)
1093 {
1094 getTableData(&dopt, tblinfo, numTables, 0);
1096 if (!dopt.dumpSchema)
1098 }
1099
1100 if (!dopt.dumpData && dopt.sequence_data)
1101 getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
1102
1103 /*
1104 * For binary upgrade mode, dump the pg_shdepend rows for large objects
1105 * and maybe even pg_largeobject_metadata (see comment below for details).
1106 * This is faster to restore than the equivalent set of large object
1107 * commands.
1108 */
1109 if (dopt.binary_upgrade)
1110 {
1112
1115
1116 /*
1117 * Only dump large object shdepend rows for this database.
1118 */
1119 shdepend->dataObj->filtercond = "WHERE classid = 'pg_largeobject'::regclass "
1120 "AND dbid = (SELECT oid FROM pg_database "
1121 " WHERE datname = current_database())";
1122
1123 /*
1124 * For binary upgrades from v16 and newer versions, we can copy
1125 * pg_largeobject_metadata's files from the old cluster, so we don't
1126 * need to dump its contents. pg_upgrade can't copy/link the files
1127 * from older versions because aclitem (needed by
1128 * pg_largeobject_metadata.lomacl) changed its storage format in v16.
1129 */
1130 if (fout->remoteVersion < 160000)
1131 {
1133
1136 }
1137 }
1138
1139 /*
1140 * In binary-upgrade mode, we do not have to worry about the actual LO
1141 * data or the associated metadata that resides in the pg_largeobject and
1142 * pg_largeobject_metadata tables, respectively.
1143 *
1144 * However, we do need to collect LO information as there may be comments
1145 * or other information on LOs that we do need to dump out.
1146 */
1147 if (dopt.outputLOs || dopt.binary_upgrade)
1148 getLOs(fout);
1149
1150 /*
1151 * Collect dependency data to assist in ordering the objects.
1152 */
1154
1155 /*
1156 * Collect ACLs, comments, and security labels, if wanted.
1157 */
1158 if (!dopt.aclsSkip)
1160 if (!dopt.no_comments)
1162 if (!dopt.no_security_labels)
1164
1165 /* For binary upgrade mode, collect required pg_class information. */
1166 if (dopt.binary_upgrade)
1168
1169 /* Collect sequence information. */
1171
1172 /* Lastly, create dummy objects to represent the section boundaries */
1174
1175 /* Get pointers to all the known DumpableObjects */
1177
1178 /*
1179 * Add dummy dependencies to enforce the dump section ordering.
1180 */
1182
1183 /*
1184 * Sort the objects into a safe dump order (no forward references).
1185 *
1186 * We rely on dependency information to help us determine a safe order, so
1187 * the initial sort is mostly for cosmetic purposes: we sort by name to
1188 * ensure that logically identical schemas will dump identically.
1189 */
1191
1193 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
1194
1195 /*
1196 * Create archive TOC entries for all the objects to be dumped, in a safe
1197 * order.
1198 */
1199
1200 /*
1201 * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
1202 */
1206
1207 /* The database items are always next, unless we don't want them at all */
1208 if (dopt.outputCreateDB)
1210
1211 /* Now the rearrangeable objects. */
1212 for (i = 0; i < numObjs; i++)
1214
1215 /*
1216 * Set up options info to ensure we dump what we want.
1217 */
1218 ropt = NewRestoreOptions();
1219 ropt->filename = filename;
1220
1221 /* if you change this list, see dumpOptionsFromRestoreOptions */
1222 ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
1223 ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
1224 ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
1227 ropt->dropSchema = dopt.outputClean;
1228 ropt->dumpData = dopt.dumpData;
1229 ropt->dumpSchema = dopt.dumpSchema;
1230 ropt->dumpStatistics = dopt.dumpStatistics;
1231 ropt->if_exists = dopt.if_exists;
1232 ropt->column_inserts = dopt.column_inserts;
1233 ropt->dumpSections = dopt.dumpSections;
1234 ropt->aclsSkip = dopt.aclsSkip;
1235 ropt->superuser = dopt.outputSuperuser;
1236 ropt->createDB = dopt.outputCreateDB;
1237 ropt->noOwner = dopt.outputNoOwner;
1238 ropt->noTableAm = dopt.outputNoTableAm;
1239 ropt->noTablespace = dopt.outputNoTablespaces;
1241 ropt->use_setsessauth = dopt.use_setsessauth;
1243 ropt->dump_inserts = dopt.dump_inserts;
1244 ropt->no_comments = dopt.no_comments;
1245 ropt->no_policies = dopt.no_policies;
1246 ropt->no_publications = dopt.no_publications;
1249 ropt->lockWaitTimeout = dopt.lockWaitTimeout;
1252 ropt->sequence_data = dopt.sequence_data;
1253 ropt->binary_upgrade = dopt.binary_upgrade;
1254 ropt->restrict_key = dopt.restrict_key ? pg_strdup(dopt.restrict_key) : NULL;
1255
1256 ropt->compression_spec = compression_spec;
1257
1258 ropt->suppressDumpWarnings = true; /* We've already shown them */
1259
1260 SetArchiveOptions(fout, &dopt, ropt);
1261
1262 /* Mark which entries should be output */
1264
1265 /*
1266 * The archive's TOC entries are now marked as to which ones will actually
1267 * be output, so we can set up their dependency lists properly. This isn't
1268 * necessary for plain-text output, though.
1269 */
1270 if (!plainText)
1272
1273 /*
1274 * And finally we can do the actual output.
1275 *
1276 * Note: for non-plain-text output formats, the output file is written
1277 * inside CloseArchive(). This is, um, bizarre; but not worth changing
1278 * right now.
1279 */
1280 if (plainText)
1282
1284
1285 exit_nicely(0);
1286}
1287
1288
1289static void
1290help(const char *progname)
1291{
1292 printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
1293 printf(_("Usage:\n"));
1294 printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
1295
1296 printf(_("\nGeneral options:\n"));
1297 printf(_(" -f, --file=FILENAME output file or directory name\n"));
1298 printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
1299 " plain text (default))\n"));
1300 printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
1301 printf(_(" -v, --verbose verbose mode\n"));
1302 printf(_(" -V, --version output version information, then exit\n"));
1303 printf(_(" -Z, --compress=METHOD[:DETAIL]\n"
1304 " compress as specified\n"));
1305 printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
1306 printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
1307 printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
1308 printf(_(" -?, --help show this help, then exit\n"));
1309
1310 printf(_("\nOptions controlling the output content:\n"));
1311 printf(_(" -a, --data-only dump only the data, not the schema or statistics\n"));
1312 printf(_(" -b, --large-objects include large objects in dump\n"));
1313 printf(_(" --blobs (same as --large-objects, deprecated)\n"));
1314 printf(_(" -B, --no-large-objects exclude large objects in dump\n"));
1315 printf(_(" --no-blobs (same as --no-large-objects, deprecated)\n"));
1316 printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
1317 printf(_(" -C, --create include commands to create database in dump\n"));
1318 printf(_(" -e, --extension=PATTERN dump the specified extension(s) only\n"));
1319 printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
1320 printf(_(" -n, --schema=PATTERN dump the specified schema(s) only\n"));
1321 printf(_(" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
1322 printf(_(" -O, --no-owner skip restoration of object ownership in\n"
1323 " plain-text format\n"));
1324 printf(_(" -s, --schema-only dump only the schema, no data or statistics\n"));
1325 printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
1326 printf(_(" -t, --table=PATTERN dump only the specified table(s)\n"));
1327 printf(_(" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n"));
1328 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
1329 printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
1330 printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
1331 printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
1332 printf(_(" --disable-triggers disable triggers during data-only restore\n"));
1333 printf(_(" --enable-row-security enable row security (dump only content user has\n"
1334 " access to)\n"));
1335 printf(_(" --exclude-extension=PATTERN do NOT dump the specified extension(s)\n"));
1336 printf(_(" --exclude-table-and-children=PATTERN\n"
1337 " do NOT dump the specified table(s), including\n"
1338 " child and partition tables\n"));
1339 printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
1340 printf(_(" --exclude-table-data-and-children=PATTERN\n"
1341 " do NOT dump data for the specified table(s),\n"
1342 " including child and partition tables\n"));
1343 printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
1344 printf(_(" --filter=FILENAME include or exclude objects and data from dump\n"
1345 " based on expressions in FILENAME\n"));
1346 printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
1347 printf(_(" --include-foreign-data=PATTERN\n"
1348 " include data of foreign tables on foreign\n"
1349 " servers matching PATTERN\n"));
1350 printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
1351 printf(_(" --load-via-partition-root load partitions via the root table\n"));
1352 printf(_(" --no-comments do not dump comment commands\n"));
1353 printf(_(" --no-data do not dump data\n"));
1354 printf(_(" --no-policies do not dump row security policies\n"));
1355 printf(_(" --no-publications do not dump publications\n"));
1356 printf(_(" --no-schema do not dump schema\n"));
1357 printf(_(" --no-security-labels do not dump security label assignments\n"));
1358 printf(_(" --no-statistics do not dump statistics\n"));
1359 printf(_(" --no-subscriptions do not dump subscriptions\n"));
1360 printf(_(" --no-table-access-method do not dump table access methods\n"));
1361 printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
1362 printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
1363 printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
1364 printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
1365 printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
1366 printf(_(" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n"));
1367 printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
1368 printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
1369 printf(_(" --sequence-data include sequence data in dump\n"));
1370 printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
1371 printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
1372 printf(_(" --statistics dump the statistics\n"));
1373 printf(_(" --statistics-only dump only the statistics, not schema or data\n"));
1374 printf(_(" --strict-names require table and/or schema include patterns to\n"
1375 " match at least one entity each\n"));
1376 printf(_(" --table-and-children=PATTERN dump only the specified table(s), including\n"
1377 " child and partition tables\n"));
1378 printf(_(" --use-set-session-authorization\n"
1379 " use SET SESSION AUTHORIZATION commands instead of\n"
1380 " ALTER OWNER commands to set ownership\n"));
1381
1382 printf(_("\nConnection options:\n"));
1383 printf(_(" -d, --dbname=DBNAME database to dump\n"));
1384 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
1385 printf(_(" -p, --port=PORT database server port number\n"));
1386 printf(_(" -U, --username=NAME connect as specified database user\n"));
1387 printf(_(" -w, --no-password never prompt for password\n"));
1388 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
1389 printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
1390
1391 printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1392 "variable value is used.\n\n"));
1393 printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1394 printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
1395}
1396
1397static void
1398setup_connection(Archive *AH, const char *dumpencoding,
1399 const char *dumpsnapshot, char *use_role)
1400{
1401 DumpOptions *dopt = AH->dopt;
1402 PGconn *conn = GetConnection(AH);
1403
1405
1406 /*
1407 * Set the client encoding if requested.
1408 */
1409 if (dumpencoding)
1410 {
1412 pg_fatal("invalid client encoding \"%s\" specified",
1413 dumpencoding);
1414 }
1415
1416 /*
1417 * Force standard_conforming_strings on, just in case we are dumping from
1418 * an old server that has it disabled. Without this, literals in views,
1419 * expressions, etc, would be incorrect for modern servers.
1420 */
1421 ExecuteSqlStatement(AH, "SET standard_conforming_strings = on");
1422
1423 /*
1424 * And reflect that to AH->std_strings. You might think that we should
1425 * just delete that variable and the code that checks it, but that would
1426 * be problematic for pg_restore, which at least for now should still cope
1427 * with archives containing the other setting (cf. processStdStringsEntry
1428 * in pg_backup_archiver.c).
1429 */
1430 AH->std_strings = true;
1431
1432 /*
1433 * Get the active encoding, so we know how to escape strings.
1434 */
1437
1438 /*
1439 * Set the role if requested. In a parallel dump worker, we'll be passed
1440 * use_role == NULL, but AH->use_role is already set (if user specified it
1441 * originally) and we should use that.
1442 */
1443 if (!use_role && AH->use_role)
1444 use_role = AH->use_role;
1445
1446 /* Set the role if requested */
1447 if (use_role)
1448 {
1450
1451 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1452 ExecuteSqlStatement(AH, query->data);
1453 destroyPQExpBuffer(query);
1454
1455 /* save it for possible later use by parallel workers */
1456 if (!AH->use_role)
1457 AH->use_role = pg_strdup(use_role);
1458 }
1459
1460 /* Set the datestyle to ISO to ensure the dump's portability */
1461 ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1462
1463 /* Likewise, avoid using sql_standard intervalstyle */
1464 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1465
1466 /*
1467 * Use an explicitly specified extra_float_digits if it has been provided.
1468 * Otherwise, set extra_float_digits so that we can dump float data
1469 * exactly (given correctly implemented float I/O code, anyway).
1470 */
1472 {
1474
1475 appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1477 ExecuteSqlStatement(AH, q->data);
1479 }
1480 else
1481 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1482
1483 /*
1484 * Disable synchronized scanning, to prevent unpredictable changes in row
1485 * ordering across a dump and reload.
1486 */
1487 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1488
1489 /*
1490 * Disable timeouts if supported.
1491 */
1492 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1493 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1494 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1495 if (AH->remoteVersion >= 170000)
1496 ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
1497
1498 /*
1499 * Quote all identifiers, if requested.
1500 */
1502 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1503
1504 /*
1505 * Adjust row-security mode, if supported.
1506 */
1507 if (dopt->enable_row_security)
1508 ExecuteSqlStatement(AH, "SET row_security = on");
1509 else
1510 ExecuteSqlStatement(AH, "SET row_security = off");
1511
1512 /*
1513 * For security reasons, we restrict the expansion of non-system views and
1514 * access to foreign tables during the pg_dump process. This restriction
1515 * is adjusted when dumping foreign table data.
1516 */
1517 set_restrict_relation_kind(AH, "view, foreign-table");
1518
1519 /*
1520 * Initialize prepared-query state to "nothing prepared". We do this here
1521 * so that a parallel dump worker will have its own state.
1522 */
1524
1525 /*
1526 * Start transaction-snapshot mode transaction to dump consistent data.
1527 */
1528 ExecuteSqlStatement(AH, "BEGIN");
1529
1530 /*
1531 * To support the combination of serializable_deferrable with the jobs
1532 * option we use REPEATABLE READ for the worker connections that are
1533 * passed a snapshot. As long as the snapshot is acquired in a
1534 * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1535 * REPEATABLE READ transaction provides the appropriate integrity
1536 * guarantees. This is a kluge, but safe for back-patching.
1537 */
1538 if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1540 "SET TRANSACTION ISOLATION LEVEL "
1541 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1542 else
1544 "SET TRANSACTION ISOLATION LEVEL "
1545 "REPEATABLE READ, READ ONLY");
1546
1547 /*
1548 * If user specified a snapshot to use, select that. In a parallel dump
1549 * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1550 * is already set (if the server can handle it) and we should use that.
1551 */
1552 if (dumpsnapshot)
1554
1555 if (AH->sync_snapshot_id)
1556 {
1558
1559 appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
1561 ExecuteSqlStatement(AH, query->data);
1562 destroyPQExpBuffer(query);
1563 }
1564 else if (AH->numWorkers > 1)
1566}
1567
1568/* Set up connection for a parallel worker process */
1569static void
1571{
1572 /*
1573 * We want to re-select all the same values the leader connection is
1574 * using. We'll have inherited directly-usable values in
1575 * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1576 * inherited encoding value back to a string to pass to setup_connection.
1577 */
1580 NULL,
1581 NULL);
1582}
1583
1584static char *
1586{
1587 char *query = "SELECT pg_catalog.pg_export_snapshot()";
1588 char *result;
1589 PGresult *res;
1590
1591 res = ExecuteSqlQueryForSingleRow(fout, query);
1592 result = pg_strdup(PQgetvalue(res, 0, 0));
1593 PQclear(res);
1594
1595 return result;
1596}
1597
1598static ArchiveFormat
1600{
1602
1604
1605 if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1606 {
1607 /* This is used by pg_dumpall, and is not documented */
1610 }
1611 else if (pg_strcasecmp(format, "c") == 0)
1613 else if (pg_strcasecmp(format, "custom") == 0)
1615 else if (pg_strcasecmp(format, "d") == 0)
1617 else if (pg_strcasecmp(format, "directory") == 0)
1619 else if (pg_strcasecmp(format, "p") == 0)
1621 else if (pg_strcasecmp(format, "plain") == 0)
1623 else if (pg_strcasecmp(format, "t") == 0)
1625 else if (pg_strcasecmp(format, "tar") == 0)
1627 else
1628 pg_fatal("invalid output format \"%s\" specified", format);
1629 return archiveFormat;
1630}
1631
1632/*
1633 * Find the OIDs of all schemas matching the given list of patterns,
1634 * and append them to the given OID list.
1635 */
1636static void
1639 SimpleOidList *oids,
1640 bool strict_names)
1641{
1642 PQExpBuffer query;
1643 PGresult *res;
1645 int i;
1646
1647 if (patterns->head == NULL)
1648 return; /* nothing to do */
1649
1650 query = createPQExpBuffer();
1651
1652 /*
1653 * The loop below runs multiple SELECTs might sometimes result in
1654 * duplicate entries in the OID list, but we don't care.
1655 */
1656
1657 for (cell = patterns->head; cell; cell = cell->next)
1658 {
1660 int dotcnt;
1661
1663 "SELECT oid FROM pg_catalog.pg_namespace n\n");
1665 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1666 false, NULL, "n.nspname", NULL, NULL, &dbbuf,
1667 &dotcnt);
1668 if (dotcnt > 1)
1669 pg_fatal("improper qualified name (too many dotted names): %s",
1670 cell->val);
1671 else if (dotcnt == 1)
1674
1675 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1676 if (strict_names && PQntuples(res) == 0)
1677 pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
1678
1679 for (i = 0; i < PQntuples(res); i++)
1680 {
1681 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1682 }
1683
1684 PQclear(res);
1685 resetPQExpBuffer(query);
1686 }
1687
1688 destroyPQExpBuffer(query);
1689}
1690
1691/*
1692 * Find the OIDs of all extensions matching the given list of patterns,
1693 * and append them to the given OID list.
1694 */
1695static void
1698 SimpleOidList *oids,
1699 bool strict_names)
1700{
1701 PQExpBuffer query;
1702 PGresult *res;
1704 int i;
1705
1706 if (patterns->head == NULL)
1707 return; /* nothing to do */
1708
1709 query = createPQExpBuffer();
1710
1711 /*
1712 * The loop below runs multiple SELECTs might sometimes result in
1713 * duplicate entries in the OID list, but we don't care.
1714 */
1715 for (cell = patterns->head; cell; cell = cell->next)
1716 {
1717 int dotcnt;
1718
1720 "SELECT oid FROM pg_catalog.pg_extension e\n");
1721 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1722 false, NULL, "e.extname", NULL, NULL, NULL,
1723 &dotcnt);
1724 if (dotcnt > 0)
1725 pg_fatal("improper qualified name (too many dotted names): %s",
1726 cell->val);
1727
1728 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1729 if (strict_names && PQntuples(res) == 0)
1730 pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
1731
1732 for (i = 0; i < PQntuples(res); i++)
1733 {
1734 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1735 }
1736
1737 PQclear(res);
1738 resetPQExpBuffer(query);
1739 }
1740
1741 destroyPQExpBuffer(query);
1742}
1743
1744/*
1745 * Find the OIDs of all foreign servers matching the given list of patterns,
1746 * and append them to the given OID list.
1747 */
1748static void
1751 SimpleOidList *oids)
1752{
1753 PQExpBuffer query;
1754 PGresult *res;
1756 int i;
1757
1758 if (patterns->head == NULL)
1759 return; /* nothing to do */
1760
1761 query = createPQExpBuffer();
1762
1763 /*
1764 * The loop below runs multiple SELECTs might sometimes result in
1765 * duplicate entries in the OID list, but we don't care.
1766 */
1767
1768 for (cell = patterns->head; cell; cell = cell->next)
1769 {
1770 int dotcnt;
1771
1773 "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
1774 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1775 false, NULL, "s.srvname", NULL, NULL, NULL,
1776 &dotcnt);
1777 if (dotcnt > 0)
1778 pg_fatal("improper qualified name (too many dotted names): %s",
1779 cell->val);
1780
1781 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1782 if (PQntuples(res) == 0)
1783 pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
1784
1785 for (i = 0; i < PQntuples(res); i++)
1786 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1787
1788 PQclear(res);
1789 resetPQExpBuffer(query);
1790 }
1791
1792 destroyPQExpBuffer(query);
1793}
1794
1795/*
1796 * Find the OIDs of all tables matching the given list of patterns,
1797 * and append them to the given OID list. See also expand_dbname_patterns()
1798 * in pg_dumpall.c
1799 */
1800static void
1804{
1805 PQExpBuffer query;
1806 PGresult *res;
1808 int i;
1809
1810 if (patterns->head == NULL)
1811 return; /* nothing to do */
1812
1813 query = createPQExpBuffer();
1814
1815 /*
1816 * this might sometimes result in duplicate entries in the OID list, but
1817 * we don't care.
1818 */
1819
1820 for (cell = patterns->head; cell; cell = cell->next)
1821 {
1823 int dotcnt;
1824
1825 /*
1826 * Query must remain ABSOLUTELY devoid of unqualified names. This
1827 * would be unnecessary given a pg_table_is_visible() variant taking a
1828 * search_path argument.
1829 *
1830 * For with_child_tables, we start with the basic query's results and
1831 * recursively search the inheritance tree to add child tables.
1832 */
1834 {
1835 appendPQExpBufferStr(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
1836 }
1837
1838 appendPQExpBuffer(query,
1839 "SELECT c.oid"
1840 "\nFROM pg_catalog.pg_class c"
1841 "\n LEFT JOIN pg_catalog.pg_namespace n"
1842 "\n ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1843 "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1844 "\n (array['%c', '%c', '%c', '%c', '%c', '%c', '%c'])\n",
1849 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1850 false, "n.nspname", "c.relname", NULL,
1851 "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
1852 &dotcnt);
1853 if (dotcnt > 2)
1854 pg_fatal("improper relation name (too many dotted names): %s",
1855 cell->val);
1856 else if (dotcnt == 2)
1859
1861 {
1862 appendPQExpBufferStr(query, "UNION"
1863 "\nSELECT i.inhrelid"
1864 "\nFROM partition_tree p"
1865 "\n JOIN pg_catalog.pg_inherits i"
1866 "\n ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
1867 "\n)"
1868 "\nSELECT relid FROM partition_tree");
1869 }
1870
1871 ExecuteSqlStatement(fout, "RESET search_path");
1872 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1875 if (strict_names && PQntuples(res) == 0)
1876 pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
1877
1878 for (i = 0; i < PQntuples(res); i++)
1879 {
1880 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1881 }
1882
1883 PQclear(res);
1884 resetPQExpBuffer(query);
1885 }
1886
1887 destroyPQExpBuffer(query);
1888}
1889
1890/*
1891 * Verifies that the connected database name matches the given database name,
1892 * and if not, dies with an error about the given pattern.
1893 *
1894 * The 'dbname' argument should be a literal name parsed from 'pattern'.
1895 */
1896static void
1897prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
1898{
1899 const char *db;
1900
1901 db = PQdb(conn);
1902 if (db == NULL)
1903 pg_fatal("You are currently not connected to a database.");
1904
1905 if (strcmp(db, dbname) != 0)
1906 pg_fatal("cross-database references are not implemented: %s",
1907 pattern);
1908}
1909
1910/*
1911 * checkExtensionMembership
1912 * Determine whether object is an extension member, and if so,
1913 * record an appropriate dependency and set the object's dump flag.
1914 *
1915 * It's important to call this for each object that could be an extension
1916 * member. Generally, we integrate this with determining the object's
1917 * to-be-dumped-ness, since extension membership overrides other rules for that.
1918 *
1919 * Returns true if object is an extension member, else false.
1920 */
1921static bool
1923{
1925
1926 if (ext == NULL)
1927 return false;
1928
1929 dobj->ext_member = true;
1930
1931 /* Record dependency so that getDependencies needn't deal with that */
1932 addObjectDependency(dobj, ext->dobj.dumpId);
1933
1934 /*
1935 * Mark the member object to have any non-initial ACLs dumped. (Any
1936 * initial ACLs will be removed later, using data from pg_init_privs, so
1937 * that we'll dump only the delta from the extension's initial setup.)
1938 *
1939 * In binary upgrades, we still dump all components of the members
1940 * individually, since the idea is to exactly reproduce the database
1941 * contents rather than replace the extension contents with something
1942 * different.
1943 *
1944 * Note: it might be interesting someday to implement storage and delta
1945 * dumping of extension members' RLS policies and/or security labels.
1946 * However there is a pitfall for RLS policies: trying to dump them
1947 * requires getting a lock on their tables, and the calling user might not
1948 * have privileges for that. We need no lock to examine a table's ACLs,
1949 * so the current feature doesn't have a problem of that sort.
1950 */
1951 if (fout->dopt->binary_upgrade)
1952 dobj->dump = ext->dobj.dump;
1953 else
1954 dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
1955
1956 return true;
1957}
1958
1959/*
1960 * selectDumpableNamespace: policy-setting subroutine
1961 * Mark a namespace as to be dumped or not
1962 */
1963static void
1965{
1966 /*
1967 * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
1968 * and (for --clean) a DROP SCHEMA statement. (In the absence of
1969 * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
1970 */
1971 nsinfo->create = true;
1972
1973 /*
1974 * If specific tables are being dumped, do not dump any complete
1975 * namespaces. If specific namespaces are being dumped, dump just those
1976 * namespaces. Otherwise, dump all non-system namespaces.
1977 */
1979 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1980 else if (schema_include_oids.head != NULL)
1981 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1983 nsinfo->dobj.catId.oid) ?
1985 else if (strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1986 {
1987 /*
1988 * We dump out any ACLs defined in pg_catalog, if they are interesting
1989 * (and not the original ACLs which were set at initdb time, see
1990 * pg_init_privs).
1991 */
1992 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1993 }
1994 else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1995 strcmp(nsinfo->dobj.name, "information_schema") == 0)
1996 {
1997 /* Other system schemas don't get dumped */
1998 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1999 }
2000 else if (strcmp(nsinfo->dobj.name, "public") == 0)
2001 {
2002 /*
2003 * The public schema is a strange beast that sits in a sort of
2004 * no-mans-land between being a system object and a user object.
2005 * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
2006 * a comment and an indication of ownership. If the owner is the
2007 * default, omit that superfluous DUMP_COMPONENT_DEFINITION. Before
2008 * v15, the default owner was BOOTSTRAP_SUPERUSERID.
2009 */
2010 nsinfo->create = false;
2011 nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
2012 if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
2013 nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
2014 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
2015
2016 /*
2017 * Also, make like it has a comment even if it doesn't; this is so
2018 * that we'll emit a command to drop the comment, if appropriate.
2019 * (Without this, we'd not call dumpCommentExtended for it.)
2020 */
2021 nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
2022 }
2023 else
2024 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
2025
2026 /*
2027 * In any case, a namespace can be excluded by an exclusion switch
2028 */
2029 if (nsinfo->dobj.dump_contains &&
2031 nsinfo->dobj.catId.oid))
2032 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
2033
2034 /*
2035 * If the schema belongs to an extension, allow extension membership to
2036 * override the dump decision for the schema itself. However, this does
2037 * not change dump_contains, so this won't change what we do with objects
2038 * within the schema. (If they belong to the extension, they'll get
2039 * suppressed by it, otherwise not.)
2040 */
2042}
2043
2044/*
2045 * selectDumpableTable: policy-setting subroutine
2046 * Mark a table as to be dumped or not
2047 */
2048static void
2050{
2052 return; /* extension membership overrides all else */
2053
2054 /*
2055 * If specific tables are being dumped, dump just those tables; else, dump
2056 * according to the parent namespace's dump flag.
2057 */
2060 tbinfo->dobj.catId.oid) ?
2062 else
2063 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
2064
2065 /*
2066 * In any case, a table can be excluded by an exclusion switch
2067 */
2068 if (tbinfo->dobj.dump &&
2070 tbinfo->dobj.catId.oid))
2071 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
2072}
2073
2074/*
2075 * selectDumpableType: policy-setting subroutine
2076 * Mark a type as to be dumped or not
2077 *
2078 * If it's a table's rowtype or an autogenerated array type, we also apply a
2079 * special type code to facilitate sorting into the desired order. (We don't
2080 * want to consider those to be ordinary types because that would bring tables
2081 * up into the datatype part of the dump order.) We still set the object's
2082 * dump flag; that's not going to cause the dummy type to be dumped, but we
2083 * need it so that casts involving such types will be dumped correctly -- see
2084 * dumpCast. This means the flag should be set the same as for the underlying
2085 * object (the table or base type).
2086 */
2087static void
2089{
2090 /* skip complex types, except for standalone composite types */
2091 if (OidIsValid(tyinfo->typrelid) &&
2092 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
2093 {
2094 TableInfo *tytable = findTableByOid(tyinfo->typrelid);
2095
2096 tyinfo->dobj.objType = DO_DUMMY_TYPE;
2097 if (tytable != NULL)
2098 tyinfo->dobj.dump = tytable->dobj.dump;
2099 else
2100 tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
2101 return;
2102 }
2103
2104 /* skip auto-generated array and multirange types */
2105 if (tyinfo->isArray || tyinfo->isMultirange)
2106 {
2107 tyinfo->dobj.objType = DO_DUMMY_TYPE;
2108
2109 /*
2110 * Fall through to set the dump flag; we assume that the subsequent
2111 * rules will do the same thing as they would for the array's base
2112 * type or multirange's range type. (We cannot reliably look up the
2113 * base type here, since getTypes may not have processed it yet.)
2114 */
2115 }
2116
2118 return; /* extension membership overrides all else */
2119
2120 /* Dump based on if the contents of the namespace are being dumped */
2121 tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
2122}
2123
2124/*
2125 * selectDumpableDefaultACL: policy-setting subroutine
2126 * Mark a default ACL as to be dumped or not
2127 *
2128 * For per-schema default ACLs, dump if the schema is to be dumped.
2129 * Otherwise dump if we are dumping "everything". Note that dumpSchema
2130 * and aclsSkip are checked separately.
2131 */
2132static void
2134{
2135 /* Default ACLs can't be extension members */
2136
2137 if (dinfo->dobj.namespace)
2138 /* default ACLs are considered part of the namespace */
2139 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
2140 else
2141 dinfo->dobj.dump = dopt->include_everything ?
2143}
2144
2145/*
2146 * selectDumpableCast: policy-setting subroutine
2147 * Mark a cast as to be dumped or not
2148 *
2149 * Casts do not belong to any particular namespace (since they haven't got
2150 * names), nor do they have identifiable owners. To distinguish user-defined
2151 * casts from built-in ones, we must resort to checking whether the cast's
2152 * OID is in the range reserved for initdb.
2153 */
2154static void
2156{
2157 if (checkExtensionMembership(&cast->dobj, fout))
2158 return; /* extension membership overrides all else */
2159
2160 /*
2161 * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
2162 * support ACLs currently.
2163 */
2164 if (cast->dobj.catId.oid <= g_last_builtin_oid)
2165 cast->dobj.dump = DUMP_COMPONENT_NONE;
2166 else
2167 cast->dobj.dump = fout->dopt->include_everything ?
2169}
2170
2171/*
2172 * selectDumpableProcLang: policy-setting subroutine
2173 * Mark a procedural language as to be dumped or not
2174 *
2175 * Procedural languages do not belong to any particular namespace. To
2176 * identify built-in languages, we must resort to checking whether the
2177 * language's OID is in the range reserved for initdb.
2178 */
2179static void
2181{
2182 if (checkExtensionMembership(&plang->dobj, fout))
2183 return; /* extension membership overrides all else */
2184
2185 /*
2186 * Only include procedural languages when we are dumping everything.
2187 *
2188 * For from-initdb procedural languages, only include ACLs, as we do for
2189 * the pg_catalog namespace. We need this because procedural languages do
2190 * not live in any namespace.
2191 */
2192 if (!fout->dopt->include_everything)
2193 plang->dobj.dump = DUMP_COMPONENT_NONE;
2194 else
2195 {
2196 if (plang->dobj.catId.oid <= g_last_builtin_oid)
2197 plang->dobj.dump = DUMP_COMPONENT_ACL;
2198 else
2199 plang->dobj.dump = DUMP_COMPONENT_ALL;
2200 }
2201}
2202
2203/*
2204 * selectDumpableAccessMethod: policy-setting subroutine
2205 * Mark an access method as to be dumped or not
2206 *
2207 * Access methods do not belong to any particular namespace. To identify
2208 * built-in access methods, we must resort to checking whether the
2209 * method's OID is in the range reserved for initdb.
2210 */
2211static void
2213{
2214 if (checkExtensionMembership(&method->dobj, fout))
2215 return; /* extension membership overrides all else */
2216
2217 /*
2218 * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
2219 * they do not support ACLs currently.
2220 */
2221 if (method->dobj.catId.oid <= g_last_builtin_oid)
2222 method->dobj.dump = DUMP_COMPONENT_NONE;
2223 else
2224 method->dobj.dump = fout->dopt->include_everything ?
2226}
2227
2228/*
2229 * selectDumpableExtension: policy-setting subroutine
2230 * Mark an extension as to be dumped or not
2231 *
2232 * Built-in extensions should be skipped except for checking ACLs, since we
2233 * assume those will already be installed in the target database. We identify
2234 * such extensions by their having OIDs in the range reserved for initdb.
2235 * We dump all user-added extensions by default. No extensions are dumped
2236 * if include_everything is false (i.e., a --schema or --table switch was
2237 * given), except if --extension specifies a list of extensions to dump.
2238 */
2239static void
2241{
2242 /*
2243 * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
2244 * change permissions on their member objects, if they wish to, and have
2245 * those changes preserved.
2246 */
2247 if (extinfo->dobj.catId.oid <= g_last_builtin_oid)
2248 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
2249 else
2250 {
2251 /* check if there is a list of extensions to dump */
2253 extinfo->dobj.dump = extinfo->dobj.dump_contains =
2255 extinfo->dobj.catId.oid) ?
2257 else
2258 extinfo->dobj.dump = extinfo->dobj.dump_contains =
2259 dopt->include_everything ?
2261
2262 /* check that the extension is not explicitly excluded */
2263 if (extinfo->dobj.dump &&
2265 extinfo->dobj.catId.oid))
2266 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
2267 }
2268}
2269
2270/*
2271 * selectDumpablePublicationObject: policy-setting subroutine
2272 * Mark a publication object as to be dumped or not
2273 *
2274 * A publication can have schemas and tables which have schemas, but those are
2275 * ignored in decision making, because publications are only dumped when we are
2276 * dumping everything.
2277 */
2278static void
2280{
2281 if (checkExtensionMembership(dobj, fout))
2282 return; /* extension membership overrides all else */
2283
2284 dobj->dump = fout->dopt->include_everything ?
2286}
2287
2288/*
2289 * selectDumpableStatisticsObject: policy-setting subroutine
2290 * Mark an extended statistics object as to be dumped or not
2291 *
2292 * We dump an extended statistics object if the schema it's in and the table
2293 * it's for are being dumped. (This'll need more thought if statistics
2294 * objects ever support cross-table stats.)
2295 */
2296static void
2298{
2299 if (checkExtensionMembership(&sobj->dobj, fout))
2300 return; /* extension membership overrides all else */
2301
2302 sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
2303 if (sobj->stattable == NULL ||
2304 !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
2305 sobj->dobj.dump = DUMP_COMPONENT_NONE;
2306}
2307
2308/*
2309 * selectDumpableObject: policy-setting subroutine
2310 * Mark a generic dumpable object as to be dumped or not
2311 *
2312 * Use this only for object types without a special-case routine above.
2313 */
2314static void
2316{
2317 if (checkExtensionMembership(dobj, fout))
2318 return; /* extension membership overrides all else */
2319
2320 /*
2321 * Default policy is to dump if parent namespace is dumpable, or for
2322 * non-namespace-associated items, dump if we're dumping "everything".
2323 */
2324 if (dobj->namespace)
2325 dobj->dump = dobj->namespace->dobj.dump_contains;
2326 else
2327 dobj->dump = fout->dopt->include_everything ?
2329}
2330
2331/*
2332 * Dump a table's contents for loading using the COPY command
2333 * - this routine is called by the Archiver when it wants the table
2334 * to be dumped.
2335 */
2336static int
2338{
2339 const TableDataInfo *tdinfo = dcontext;
2340 const TableInfo *tbinfo = tdinfo->tdtable;
2341 const char *classname = tbinfo->dobj.name;
2343
2344 /*
2345 * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
2346 * which uses it already.
2347 */
2350 PGresult *res;
2351 int ret;
2352 char *copybuf;
2353 const char *column_list;
2354
2355 pg_log_info("dumping contents of table \"%s.%s\"",
2356 tbinfo->dobj.namespace->dobj.name, classname);
2357
2358 /*
2359 * Specify the column list explicitly so that we have no possibility of
2360 * retrieving data in the wrong column order. (The default column
2361 * ordering of COPY will not be what we want in certain corner cases
2362 * involving ADD COLUMN and inheritance.)
2363 */
2365
2366 /*
2367 * Use COPY (SELECT ...) TO when dumping a foreign table's data, when a
2368 * filter condition was specified, and when in binary upgrade mode and
2369 * dumping an old pg_largeobject_metadata defined WITH OIDS. For other
2370 * cases a simple COPY suffices.
2371 */
2372 if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
2373 (fout->dopt->binary_upgrade && fout->remoteVersion < 120000 &&
2374 tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId))
2375 {
2376 /* Temporary allows to access to foreign tables to dump data */
2377 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2379
2380 appendPQExpBufferStr(q, "COPY (SELECT ");
2381 /* klugery to get rid of parens in column list */
2382 if (strlen(column_list) > 2)
2383 {
2385 q->data[q->len - 1] = ' ';
2386 }
2387 else
2388 appendPQExpBufferStr(q, "* ");
2389
2390 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
2392 tdinfo->filtercond ? tdinfo->filtercond : "");
2393 }
2394 else
2395 {
2396 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
2398 column_list);
2399 }
2401 PQclear(res);
2403
2404 for (;;)
2405 {
2406 ret = PQgetCopyData(conn, &copybuf, 0);
2407
2408 if (ret < 0)
2409 break; /* done or error */
2410
2411 if (copybuf)
2412 {
2413 WriteData(fout, copybuf, ret);
2415 }
2416
2417 /* ----------
2418 * THROTTLE:
2419 *
2420 * There was considerable discussion in late July, 2000 regarding
2421 * slowing down pg_dump when backing up large tables. Users with both
2422 * slow & fast (multi-processor) machines experienced performance
2423 * degradation when doing a backup.
2424 *
2425 * Initial attempts based on sleeping for a number of ms for each ms
2426 * of work were deemed too complex, then a simple 'sleep in each loop'
2427 * implementation was suggested. The latter failed because the loop
2428 * was too tight. Finally, the following was implemented:
2429 *
2430 * If throttle is non-zero, then
2431 * See how long since the last sleep.
2432 * Work out how long to sleep (based on ratio).
2433 * If sleep is more than 100ms, then
2434 * sleep
2435 * reset timer
2436 * EndIf
2437 * EndIf
2438 *
2439 * where the throttle value was the number of ms to sleep per ms of
2440 * work. The calculation was done in each loop.
2441 *
2442 * Most of the hard work is done in the backend, and this solution
2443 * still did not work particularly well: on slow machines, the ratio
2444 * was 50:1, and on medium paced machines, 1:1, and on fast
2445 * multi-processor machines, it had little or no effect, for reasons
2446 * that were unclear.
2447 *
2448 * Further discussion ensued, and the proposal was dropped.
2449 *
2450 * For those people who want this feature, it can be implemented using
2451 * gettimeofday in each loop, calculating the time since last sleep,
2452 * multiplying that by the sleep ratio, then if the result is more
2453 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
2454 * function to sleep for a subsecond period ie.
2455 *
2456 * select(0, NULL, NULL, NULL, &tvi);
2457 *
2458 * This will return after the interval specified in the structure tvi.
2459 * Finally, call gettimeofday again to save the 'last sleep time'.
2460 * ----------
2461 */
2462 }
2463 archprintf(fout, "\\.\n\n\n");
2464
2465 if (ret == -2)
2466 {
2467 /* copy data transfer failed */
2468 pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
2469 pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2470 pg_log_error_detail("Command was: %s", q->data);
2471 exit_nicely(1);
2472 }
2473
2474 /* Check command status and return to normal libpq state */
2475 res = PQgetResult(conn);
2476 if (PQresultStatus(res) != PGRES_COMMAND_OK)
2477 {
2478 pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
2479 pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2480 pg_log_error_detail("Command was: %s", q->data);
2481 exit_nicely(1);
2482 }
2483 PQclear(res);
2484
2485 /* Do this to ensure we've pumped libpq back to idle state */
2486 if (PQgetResult(conn) != NULL)
2487 pg_log_warning("unexpected extra results during COPY of table \"%s\"",
2488 classname);
2489
2491
2492 /* Revert back the setting */
2493 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2494 set_restrict_relation_kind(fout, "view, foreign-table");
2495
2496 return 1;
2497}
2498
2499/*
2500 * Dump table data using INSERT commands.
2501 *
2502 * Caution: when we restore from an archive file direct to database, the
2503 * INSERT commands emitted by this function have to be parsed by
2504 * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
2505 * E'' strings, or dollar-quoted strings. So don't emit anything like that.
2506 */
2507static int
2509{
2510 const TableDataInfo *tdinfo = dcontext;
2511 const TableInfo *tbinfo = tdinfo->tdtable;
2512 DumpOptions *dopt = fout->dopt;
2515 char *attgenerated;
2516 PGresult *res;
2517 int nfields,
2518 i;
2519 int rows_per_statement = dopt->dump_inserts;
2520 int rows_this_statement = 0;
2521
2522 /* Temporary allows to access to foreign tables to dump data */
2523 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2525
2526 /*
2527 * If we're going to emit INSERTs with column names, the most efficient
2528 * way to deal with generated columns is to exclude them entirely. For
2529 * INSERTs without column names, we have to emit DEFAULT rather than the
2530 * actual column value --- but we can save a few cycles by fetching nulls
2531 * rather than the uninteresting-to-us value.
2532 */
2533 attgenerated = pg_malloc_array(char, tbinfo->numatts);
2534 appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
2535 nfields = 0;
2536 for (i = 0; i < tbinfo->numatts; i++)
2537 {
2538 if (tbinfo->attisdropped[i])
2539 continue;
2540 if (tbinfo->attgenerated[i] && dopt->column_inserts)
2541 continue;
2542 if (nfields > 0)
2543 appendPQExpBufferStr(q, ", ");
2544 if (tbinfo->attgenerated[i])
2545 appendPQExpBufferStr(q, "NULL");
2546 else
2547 appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
2548 attgenerated[nfields] = tbinfo->attgenerated[i];
2549 nfields++;
2550 }
2551 /* Servers before 9.4 will complain about zero-column SELECT */
2552 if (nfields == 0)
2553 appendPQExpBufferStr(q, "NULL");
2554 appendPQExpBuffer(q, " FROM ONLY %s",
2556 if (tdinfo->filtercond)
2557 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
2558
2560
2561 while (1)
2562 {
2563 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
2565
2566 /* cross-check field count, allowing for dummy NULL if any */
2567 if (nfields != PQnfields(res) &&
2568 !(nfields == 0 && PQnfields(res) == 1))
2569 pg_fatal("wrong number of fields retrieved from table \"%s\"",
2570 tbinfo->dobj.name);
2571
2572 /*
2573 * First time through, we build as much of the INSERT statement as
2574 * possible in "insertStmt", which we can then just print for each
2575 * statement. If the table happens to have zero dumpable columns then
2576 * this will be a complete statement, otherwise it will end in
2577 * "VALUES" and be ready to have the row's column values printed.
2578 */
2579 if (insertStmt == NULL)
2580 {
2581 const TableInfo *targettab;
2582
2584
2585 /*
2586 * When load-via-partition-root is set or forced, get the root
2587 * table name for the partition table, so that we can reload data
2588 * through the root table.
2589 */
2590 if (tbinfo->ispartition &&
2591 (dopt->load_via_partition_root ||
2594 else
2595 targettab = tbinfo;
2596
2597 appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
2599
2600 /* corner case for zero-column table */
2601 if (nfields == 0)
2602 {
2603 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
2604 }
2605 else
2606 {
2607 /* append the list of column names if required */
2608 if (dopt->column_inserts)
2609 {
2611 for (int field = 0; field < nfields; field++)
2612 {
2613 if (field > 0)
2616 fmtId(PQfname(res, field)));
2617 }
2619 }
2620
2621 if (tbinfo->needs_override)
2622 appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
2623
2625 }
2626 }
2627
2628 for (int tuple = 0; tuple < PQntuples(res); tuple++)
2629 {
2630 /* Write the INSERT if not in the middle of a multi-row INSERT. */
2631 if (rows_this_statement == 0)
2632 archputs(insertStmt->data, fout);
2633
2634 /*
2635 * If it is zero-column table then we've already written the
2636 * complete statement, which will mean we've disobeyed
2637 * --rows-per-insert when it's set greater than 1. We do support
2638 * a way to make this multi-row with: SELECT UNION ALL SELECT
2639 * UNION ALL ... but that's non-standard so we should avoid it
2640 * given that using INSERTs is mostly only ever needed for
2641 * cross-database exports.
2642 */
2643 if (nfields == 0)
2644 continue;
2645
2646 /* Emit a row heading */
2647 if (rows_per_statement == 1)
2648 archputs(" (", fout);
2649 else if (rows_this_statement > 0)
2650 archputs(",\n\t(", fout);
2651 else
2652 archputs("\n\t(", fout);
2653
2654 for (int field = 0; field < nfields; field++)
2655 {
2656 if (field > 0)
2657 archputs(", ", fout);
2658 if (attgenerated[field])
2659 {
2660 archputs("DEFAULT", fout);
2661 continue;
2662 }
2663 if (PQgetisnull(res, tuple, field))
2664 {
2665 archputs("NULL", fout);
2666 continue;
2667 }
2668
2669 /* XXX This code is partially duplicated in ruleutils.c */
2670 switch (PQftype(res, field))
2671 {
2672 case INT2OID:
2673 case INT4OID:
2674 case INT8OID:
2675 case OIDOID:
2676 case FLOAT4OID:
2677 case FLOAT8OID:
2678 case NUMERICOID:
2679 {
2680 /*
2681 * These types are printed without quotes unless
2682 * they contain values that aren't accepted by the
2683 * scanner unquoted (e.g., 'NaN'). Note that
2684 * strtod() and friends might accept NaN, so we
2685 * can't use that to test.
2686 *
2687 * In reality we only need to defend against
2688 * infinity and NaN, so we need not get too crazy
2689 * about pattern matching here.
2690 */
2691 const char *s = PQgetvalue(res, tuple, field);
2692
2693 if (strspn(s, "0123456789 +-eE.") == strlen(s))
2694 archputs(s, fout);
2695 else
2696 archprintf(fout, "'%s'", s);
2697 }
2698 break;
2699
2700 case BITOID:
2701 case VARBITOID:
2702 archprintf(fout, "B'%s'",
2703 PQgetvalue(res, tuple, field));
2704 break;
2705
2706 case BOOLOID:
2707 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2708 archputs("true", fout);
2709 else
2710 archputs("false", fout);
2711 break;
2712
2713 default:
2714 /* All other types are printed as string literals. */
2717 PQgetvalue(res, tuple, field),
2718 fout);
2719 archputs(q->data, fout);
2720 break;
2721 }
2722 }
2723
2724 /* Terminate the row ... */
2725 archputs(")", fout);
2726
2727 /* ... and the statement, if the target no. of rows is reached */
2729 {
2730 if (dopt->do_nothing)
2731 archputs(" ON CONFLICT DO NOTHING;\n", fout);
2732 else
2733 archputs(";\n", fout);
2734 /* Reset the row counter */
2736 }
2737 }
2738
2739 if (PQntuples(res) <= 0)
2740 {
2741 PQclear(res);
2742 break;
2743 }
2744 PQclear(res);
2745 }
2746
2747 /* Terminate any statements that didn't make the row count. */
2748 if (rows_this_statement > 0)
2749 {
2750 if (dopt->do_nothing)
2751 archputs(" ON CONFLICT DO NOTHING;\n", fout);
2752 else
2753 archputs(";\n", fout);
2754 }
2755
2756 archputs("\n\n", fout);
2757
2758 ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2759
2761 if (insertStmt != NULL)
2763 pg_free(attgenerated);
2764
2765 /* Revert back the setting */
2766 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2767 set_restrict_relation_kind(fout, "view, foreign-table");
2768
2769 return 1;
2770}
2771
2772/*
2773 * getRootTableInfo:
2774 * get the root TableInfo for the given partition table.
2775 */
2776static TableInfo *
2778{
2780
2781 Assert(tbinfo->ispartition);
2782 Assert(tbinfo->numParents == 1);
2783
2784 parentTbinfo = tbinfo->parents[0];
2785 while (parentTbinfo->ispartition)
2786 {
2787 Assert(parentTbinfo->numParents == 1);
2788 parentTbinfo = parentTbinfo->parents[0];
2789 }
2790
2791 return parentTbinfo;
2792}
2793
2794/*
2795 * forcePartitionRootLoad
2796 * Check if we must force load_via_partition_root for this partition.
2797 *
2798 * This is required if any level of ancestral partitioned table has an
2799 * unsafe partitioning scheme.
2800 */
2801static bool
2803{
2805
2806 Assert(tbinfo->ispartition);
2807 Assert(tbinfo->numParents == 1);
2808
2809 parentTbinfo = tbinfo->parents[0];
2810 if (parentTbinfo->unsafe_partitions)
2811 return true;
2812 while (parentTbinfo->ispartition)
2813 {
2814 Assert(parentTbinfo->numParents == 1);
2815 parentTbinfo = parentTbinfo->parents[0];
2816 if (parentTbinfo->unsafe_partitions)
2817 return true;
2818 }
2819
2820 return false;
2821}
2822
2823/*
2824 * dumpTableData -
2825 * dump the contents of a single table
2826 *
2827 * Actually, this just makes an ArchiveEntry for the table contents.
2828 */
2829static void
2831{
2832 DumpOptions *dopt = fout->dopt;
2833 const TableInfo *tbinfo = tdinfo->tdtable;
2836 DataDumperPtr dumpFn;
2837 char *tdDefn = NULL;
2838 char *copyStmt;
2839 const char *copyFrom;
2840
2841 /* We had better have loaded per-column details about this table */
2842 Assert(tbinfo->interesting);
2843
2844 /*
2845 * When load-via-partition-root is set or forced, get the root table name
2846 * for the partition table, so that we can reload data through the root
2847 * table. Then construct a comment to be inserted into the TOC entry's
2848 * defn field, so that such cases can be identified reliably.
2849 */
2850 if (tbinfo->ispartition &&
2851 (dopt->load_via_partition_root ||
2853 {
2854 const TableInfo *parentTbinfo;
2855 char *sanitized;
2856
2860 printfPQExpBuffer(copyBuf, "-- load via partition root %s",
2861 sanitized);
2862 free(sanitized);
2863 tdDefn = pg_strdup(copyBuf->data);
2864 }
2865 else
2867
2868 if (dopt->dump_inserts == 0)
2869 {
2870 /* Dump/restore using COPY */
2871 dumpFn = dumpTableData_copy;
2872 /* must use 2 steps here 'cause fmtId is nonreentrant */
2873 printfPQExpBuffer(copyBuf, "COPY %s ",
2874 copyFrom);
2875 appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2877 copyStmt = copyBuf->data;
2878 }
2879 else
2880 {
2881 /* Restore using INSERT */
2882 dumpFn = dumpTableData_insert;
2883 copyStmt = NULL;
2884 }
2885
2886 /*
2887 * Note: although the TableDataInfo is a full DumpableObject, we treat its
2888 * dependency on its table as "special" and pass it to ArchiveEntry now.
2889 * See comments for BuildArchiveDependencies.
2890 */
2891 if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2892 {
2893 TocEntry *te;
2894
2895 te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2896 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2897 .namespace = tbinfo->dobj.namespace->dobj.name,
2898 .owner = tbinfo->rolname,
2899 .description = "TABLE DATA",
2900 .section = SECTION_DATA,
2901 .createStmt = tdDefn,
2902 .copyStmt = copyStmt,
2903 .deps = &(tbinfo->dobj.dumpId),
2904 .nDeps = 1,
2905 .dumpFn = dumpFn,
2906 .dumpArg = tdinfo));
2907
2908 /*
2909 * Set the TocEntry's dataLength in case we are doing a parallel dump
2910 * and want to order dump jobs by table size. We choose to measure
2911 * dataLength in table pages (including TOAST pages) during dump, so
2912 * no scaling is needed.
2913 *
2914 * However, relpages is declared as "integer" in pg_class, and hence
2915 * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2916 * Cast so that we get the right interpretation of table sizes
2917 * exceeding INT_MAX pages.
2918 */
2919 te->dataLength = (BlockNumber) tbinfo->relpages;
2920 te->dataLength += (BlockNumber) tbinfo->toastpages;
2921
2922 /*
2923 * If pgoff_t is only 32 bits wide, the above refinement is useless,
2924 * and instead we'd better worry about integer overflow. Clamp to
2925 * INT_MAX if the correct result exceeds that.
2926 */
2927 if (sizeof(te->dataLength) == 4 &&
2928 (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
2929 te->dataLength < 0))
2930 te->dataLength = INT_MAX;
2931 }
2932
2935}
2936
2937/*
2938 * refreshMatViewData -
2939 * load or refresh the contents of a single materialized view
2940 *
2941 * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2942 * statement.
2943 */
2944static void
2946{
2947 TableInfo *tbinfo = tdinfo->tdtable;
2948 PQExpBuffer q;
2949
2950 /* If the materialized view is not flagged as populated, skip this. */
2951 if (!tbinfo->relispopulated)
2952 return;
2953
2954 q = createPQExpBuffer();
2955
2956 appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2958
2959 if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2961 tdinfo->dobj.catId, /* catalog ID */
2962 tdinfo->dobj.dumpId, /* dump ID */
2963 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2964 .namespace = tbinfo->dobj.namespace->dobj.name,
2965 .owner = tbinfo->rolname,
2966 .description = "MATERIALIZED VIEW DATA",
2967 .section = SECTION_POST_DATA,
2968 .createStmt = q->data,
2969 .deps = tdinfo->dobj.dependencies,
2970 .nDeps = tdinfo->dobj.nDeps));
2971
2973}
2974
2975/*
2976 * getTableData -
2977 * set up dumpable objects representing the contents of tables
2978 */
2979static void
2980getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2981{
2982 int i;
2983
2984 for (i = 0; i < numTables; i++)
2985 {
2986 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2987 (!relkind || tblinfo[i].relkind == relkind))
2988 makeTableDataInfo(dopt, &(tblinfo[i]));
2989 }
2990}
2991
2992/*
2993 * Make a dumpable object for the data of this specific table
2994 *
2995 * Note: we make a TableDataInfo if and only if we are going to dump the
2996 * table data; the "dump" field in such objects isn't very interesting.
2997 */
2998static void
3000{
3002
3003 /*
3004 * Nothing to do if we already decided to dump the table. This will
3005 * happen for "config" tables.
3006 */
3007 if (tbinfo->dataObj != NULL)
3008 return;
3009
3010 /* Skip property graphs (no data to dump) */
3011 if (tbinfo->relkind == RELKIND_PROPGRAPH)
3012 return;
3013 /* Skip VIEWs (no data to dump) */
3014 if (tbinfo->relkind == RELKIND_VIEW)
3015 return;
3016 /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
3017 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
3020 tbinfo->foreign_server)))
3021 return;
3022 /* Skip partitioned tables (data in partitions) */
3023 if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
3024 return;
3025
3026 /* Don't dump data in unlogged tables, if so requested */
3027 if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
3029 return;
3030
3031 /* Check that the data is not explicitly excluded */
3033 tbinfo->dobj.catId.oid))
3034 return;
3035
3036 /* OK, let's dump it */
3038
3039 if (tbinfo->relkind == RELKIND_MATVIEW)
3040 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
3041 else if (tbinfo->relkind == RELKIND_SEQUENCE)
3042 tdinfo->dobj.objType = DO_SEQUENCE_SET;
3043 else
3044 tdinfo->dobj.objType = DO_TABLE_DATA;
3045
3046 /*
3047 * Note: use tableoid 0 so that this object won't be mistaken for
3048 * something that pg_depend entries apply to.
3049 */
3050 tdinfo->dobj.catId.tableoid = 0;
3051 tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3052 AssignDumpId(&tdinfo->dobj);
3053 tdinfo->dobj.name = tbinfo->dobj.name;
3054 tdinfo->dobj.namespace = tbinfo->dobj.namespace;
3055 tdinfo->tdtable = tbinfo;
3056 tdinfo->filtercond = NULL; /* might get set later */
3057 addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
3058
3059 /* A TableDataInfo contains data, of course */
3060 tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
3061
3062 tbinfo->dataObj = tdinfo;
3063
3064 /*
3065 * Materialized view statistics must be restored after the data, because
3066 * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
3067 *
3068 * The dependency is added here because the statistics objects are created
3069 * first.
3070 */
3071 if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
3072 {
3073 tbinfo->stats->section = SECTION_POST_DATA;
3074 addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
3075 }
3076
3077 /* Make sure that we'll collect per-column info for this table. */
3078 tbinfo->interesting = true;
3079}
3080
3081/*
3082 * The refresh for a materialized view must be dependent on the refresh for
3083 * any materialized view that this one is dependent on.
3084 *
3085 * This must be called after all the objects are created, but before they are
3086 * sorted.
3087 */
3088static void
3090{
3091 PQExpBuffer query;
3092 PGresult *res;
3093 int ntups,
3094 i;
3095 int i_classid,
3096 i_objid,
3097 i_refobjid;
3098
3099 query = createPQExpBuffer();
3100
3101 appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
3102 "( "
3103 "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
3104 "FROM pg_depend d1 "
3105 "JOIN pg_class c1 ON c1.oid = d1.objid "
3106 "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
3107 " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
3108 "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
3109 "AND d2.objid = r1.oid "
3110 "AND d2.refobjid <> d1.objid "
3111 "JOIN pg_class c2 ON c2.oid = d2.refobjid "
3112 "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
3114 "WHERE d1.classid = 'pg_class'::regclass "
3115 "UNION "
3116 "SELECT w.objid, d3.refobjid, c3.relkind "
3117 "FROM w "
3118 "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
3119 "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
3120 "AND d3.objid = r3.oid "
3121 "AND d3.refobjid <> w.refobjid "
3122 "JOIN pg_class c3 ON c3.oid = d3.refobjid "
3123 "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
3125 ") "
3126 "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
3127 "FROM w "
3128 "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
3129
3130 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3131
3132 ntups = PQntuples(res);
3133
3134 i_classid = PQfnumber(res, "classid");
3135 i_objid = PQfnumber(res, "objid");
3136 i_refobjid = PQfnumber(res, "refobjid");
3137
3138 for (i = 0; i < ntups; i++)
3139 {
3140 CatalogId objId;
3142 DumpableObject *dobj;
3146
3147 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
3148 objId.oid = atooid(PQgetvalue(res, i, i_objid));
3149 refobjId.tableoid = objId.tableoid;
3150 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
3151
3152 dobj = findObjectByCatalogId(objId);
3153 if (dobj == NULL)
3154 continue;
3155
3156 Assert(dobj->objType == DO_TABLE);
3157 tbinfo = (TableInfo *) dobj;
3158 Assert(tbinfo->relkind == RELKIND_MATVIEW);
3159 dobj = (DumpableObject *) tbinfo->dataObj;
3160 if (dobj == NULL)
3161 continue;
3163
3165 if (refdobj == NULL)
3166 continue;
3167
3168 Assert(refdobj->objType == DO_TABLE);
3170 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
3171 refdobj = (DumpableObject *) reftbinfo->dataObj;
3172 if (refdobj == NULL)
3173 continue;
3174 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
3175
3176 addObjectDependency(dobj, refdobj->dumpId);
3177
3178 if (!reftbinfo->relispopulated)
3179 tbinfo->relispopulated = false;
3180 }
3181
3182 PQclear(res);
3183
3184 destroyPQExpBuffer(query);
3185}
3186
3187/*
3188 * getTableDataFKConstraints -
3189 * add dump-order dependencies reflecting foreign key constraints
3190 *
3191 * This code is executed only in a data-only dump --- in schema+data dumps
3192 * we handle foreign key issues by not creating the FK constraints until
3193 * after the data is loaded. In a data-only dump, however, we want to
3194 * order the table data objects in such a way that a table's referenced
3195 * tables are restored first. (In the presence of circular references or
3196 * self-references this may be impossible; we'll detect and complain about
3197 * that during the dependency sorting step.)
3198 */
3199static void
3201{
3203 int numObjs;
3204 int i;
3205
3206 /* Search through all the dumpable objects for FK constraints */
3208 for (i = 0; i < numObjs; i++)
3209 {
3210 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
3211 {
3214
3215 /* Not interesting unless both tables are to be dumped */
3216 if (cinfo->contable == NULL ||
3217 cinfo->contable->dataObj == NULL)
3218 continue;
3219 ftable = findTableByOid(cinfo->confrelid);
3220 if (ftable == NULL ||
3221 ftable->dataObj == NULL)
3222 continue;
3223
3224 /*
3225 * Okay, make referencing table's TABLE_DATA object depend on the
3226 * referenced table's TABLE_DATA object.
3227 */
3228 addObjectDependency(&cinfo->contable->dataObj->dobj,
3229 ftable->dataObj->dobj.dumpId);
3230 }
3231 }
3232 free(dobjs);
3233}
3234
3235
3236/*
3237 * dumpDatabase:
3238 * dump the database definition
3239 */
3240static void
3242{
3243 DumpOptions *dopt = fout->dopt;
3249 PGresult *res;
3250 int i_tableoid,
3251 i_oid,
3252 i_datname,
3253 i_datdba,
3254 i_encoding,
3256 i_collate,
3257 i_ctype,
3261 i_minmxid,
3262 i_datacl,
3271 const char *datname,
3272 *dba,
3273 *encoding,
3275 *collate,
3276 *ctype,
3277 *locale,
3278 *icurules,
3280 *datconnlimit,
3281 *tablespace;
3282 uint32 frozenxid,
3283 minmxid;
3284 char *qdatname;
3285
3286 pg_log_info("saving database definition");
3287
3288 /*
3289 * Fetch the database-level properties for this database.
3290 */
3291 appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
3292 "datdba, "
3293 "pg_encoding_to_char(encoding) AS encoding, "
3294 "datcollate, datctype, datfrozenxid, "
3295 "datacl, acldefault('d', datdba) AS acldefault, "
3296 "datistemplate, datconnlimit, ");
3297 appendPQExpBufferStr(dbQry, "datminmxid, ");
3298 if (fout->remoteVersion >= 170000)
3299 appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
3300 else if (fout->remoteVersion >= 150000)
3301 appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
3302 else
3303 appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
3304 if (fout->remoteVersion >= 160000)
3305 appendPQExpBufferStr(dbQry, "daticurules, ");
3306 else
3307 appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
3309 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
3310 "shobj_description(oid, 'pg_database') AS description "
3311 "FROM pg_database "
3312 "WHERE datname = current_database()");
3313
3315
3316 i_tableoid = PQfnumber(res, "tableoid");
3317 i_oid = PQfnumber(res, "oid");
3318 i_datname = PQfnumber(res, "datname");
3319 i_datdba = PQfnumber(res, "datdba");
3320 i_encoding = PQfnumber(res, "encoding");
3321 i_datlocprovider = PQfnumber(res, "datlocprovider");
3322 i_collate = PQfnumber(res, "datcollate");
3323 i_ctype = PQfnumber(res, "datctype");
3324 i_datlocale = PQfnumber(res, "datlocale");
3325 i_daticurules = PQfnumber(res, "daticurules");
3326 i_frozenxid = PQfnumber(res, "datfrozenxid");
3327 i_minmxid = PQfnumber(res, "datminmxid");
3328 i_datacl = PQfnumber(res, "datacl");
3329 i_acldefault = PQfnumber(res, "acldefault");
3330 i_datistemplate = PQfnumber(res, "datistemplate");
3331 i_datconnlimit = PQfnumber(res, "datconnlimit");
3332 i_datcollversion = PQfnumber(res, "datcollversion");
3333 i_tablespace = PQfnumber(res, "tablespace");
3334
3335 dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
3336 dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
3337 datname = PQgetvalue(res, 0, i_datname);
3338 dba = getRoleName(PQgetvalue(res, 0, i_datdba));
3339 encoding = PQgetvalue(res, 0, i_encoding);
3341 collate = PQgetvalue(res, 0, i_collate);
3342 ctype = PQgetvalue(res, 0, i_ctype);
3343 if (!PQgetisnull(res, 0, i_datlocale))
3344 locale = PQgetvalue(res, 0, i_datlocale);
3345 else
3346 locale = NULL;
3347 if (!PQgetisnull(res, 0, i_daticurules))
3349 else
3350 icurules = NULL;
3351 frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
3352 minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
3353 dbdacl.acl = PQgetvalue(res, 0, i_datacl);
3354 dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
3358
3360
3361 /*
3362 * Prepare the CREATE DATABASE command. We must specify OID (if we want
3363 * to preserve that), as well as the encoding, locale, and tablespace
3364 * since those can't be altered later. Other DB properties are left to
3365 * the DATABASE PROPERTIES entry, so that they can be applied after
3366 * reconnecting to the target DB.
3367 *
3368 * For binary upgrade, we use the FILE_COPY strategy because testing has
3369 * shown it to be faster. When the server is in binary upgrade mode, it
3370 * will also skip the checkpoints this strategy ordinarily performs.
3371 */
3372 if (dopt->binary_upgrade)
3373 {
3375 "CREATE DATABASE %s WITH TEMPLATE = template0 "
3376 "OID = %u STRATEGY = FILE_COPY",
3377 qdatname, dbCatId.oid);
3378 }
3379 else
3380 {
3381 appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
3382 qdatname);
3383 }
3384 if (strlen(encoding) > 0)
3385 {
3386 appendPQExpBufferStr(creaQry, " ENCODING = ");
3388 }
3389
3390 appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
3391 if (datlocprovider[0] == 'b')
3392 appendPQExpBufferStr(creaQry, "builtin");
3393 else if (datlocprovider[0] == 'c')
3395 else if (datlocprovider[0] == 'i')
3397 else
3398 pg_fatal("unrecognized locale provider: %s",
3400
3401 if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
3402 {
3403 appendPQExpBufferStr(creaQry, " LOCALE = ");
3405 }
3406 else
3407 {
3408 if (strlen(collate) > 0)
3409 {
3410 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
3412 }
3413 if (strlen(ctype) > 0)
3414 {
3415 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
3417 }
3418 }
3419 if (locale)
3420 {
3421 if (datlocprovider[0] == 'b')
3422 appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
3423 else
3424 appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
3425
3427 }
3428
3429 if (icurules)
3430 {
3431 appendPQExpBufferStr(creaQry, " ICU_RULES = ");
3433 }
3434
3435 /*
3436 * For binary upgrade, carry over the collation version. For normal
3437 * dump/restore, omit the version, so that it is computed upon restore.
3438 */
3439 if (dopt->binary_upgrade)
3440 {
3441 if (!PQgetisnull(res, 0, i_datcollversion))
3442 {
3443 appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
3446 fout);
3447 }
3448 }
3449
3450 /*
3451 * Note: looking at dopt->outputNoTablespaces here is completely the wrong
3452 * thing; the decision whether to specify a tablespace should be left till
3453 * pg_restore, so that pg_restore --no-tablespaces applies. Ideally we'd
3454 * label the DATABASE entry with the tablespace and let the normal
3455 * tablespace selection logic work ... but CREATE DATABASE doesn't pay
3456 * attention to default_tablespace, so that won't work.
3457 */
3458 if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
3459 !dopt->outputNoTablespaces)
3460 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
3461 fmtId(tablespace));
3463
3464 appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
3465 qdatname);
3466
3468
3470 dbCatId, /* catalog ID */
3471 dbDumpId, /* dump ID */
3472 ARCHIVE_OPTS(.tag = datname,
3473 .owner = dba,
3474 .description = "DATABASE",
3475 .section = SECTION_PRE_DATA,
3476 .createStmt = creaQry->data,
3477 .dropStmt = delQry->data));
3478
3479 /* Compute correct tag for archive entry */
3480 appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
3481
3482 /* Dump DB comment if any */
3483 {
3484 /*
3485 * 8.2 and up keep comments on shared objects in a shared table, so we
3486 * cannot use the dumpComment() code used for other database objects.
3487 * Be careful that the ArchiveEntry parameters match that function.
3488 */
3489 char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
3490
3491 if (comment && *comment && !dopt->no_comments)
3492 {
3494
3495 /*
3496 * Generates warning when loaded into a differently-named
3497 * database.
3498 */
3499 appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
3502
3504 ARCHIVE_OPTS(.tag = labelq->data,
3505 .owner = dba,
3506 .description = "COMMENT",
3507 .section = SECTION_NONE,
3508 .createStmt = dbQry->data,
3509 .deps = &dbDumpId,
3510 .nDeps = 1));
3511 }
3512 }
3513
3514 /* Dump DB security label, if enabled */
3515 if (!dopt->no_security_labels)
3516 {
3517 PGresult *shres;
3519
3521
3522 buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
3526 if (seclabelQry->len > 0)
3528 ARCHIVE_OPTS(.tag = labelq->data,
3529 .owner = dba,
3530 .description = "SECURITY LABEL",
3531 .section = SECTION_NONE,
3532 .createStmt = seclabelQry->data,
3533 .deps = &dbDumpId,
3534 .nDeps = 1));
3536 PQclear(shres);
3537 }
3538
3539 /*
3540 * Dump ACL if any. Note that we do not support initial privileges
3541 * (pg_init_privs) on databases.
3542 */
3543 dbdacl.privtype = 0;
3544 dbdacl.initprivs = NULL;
3545
3546 dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
3547 qdatname, NULL, NULL,
3548 NULL, dba, &dbdacl);
3549
3550 /*
3551 * Now construct a DATABASE PROPERTIES archive entry to restore any
3552 * non-default database-level properties. (The reason this must be
3553 * separate is that we cannot put any additional commands into the TOC
3554 * entry that has CREATE DATABASE. pg_restore would execute such a group
3555 * in an implicit transaction block, and the backend won't allow CREATE
3556 * DATABASE in that context.)
3557 */
3560
3561 if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
3562 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
3564
3565 if (strcmp(datistemplate, "t") == 0)
3566 {
3567 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
3568 qdatname);
3569
3570 /*
3571 * The backend won't accept DROP DATABASE on a template database. We
3572 * can deal with that by removing the template marking before the DROP
3573 * gets issued. We'd prefer to use ALTER DATABASE IF EXISTS here, but
3574 * since no such command is currently supported, fake it with a direct
3575 * UPDATE on pg_database.
3576 */
3577 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
3578 "SET datistemplate = false WHERE datname = ");
3581 }
3582
3583 /*
3584 * We do not restore pg_database.dathasloginevt because it is set
3585 * automatically on login event trigger creation.
3586 */
3587
3588 /* Add database-specific SET options */
3590
3591 /*
3592 * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
3593 * entry, too, for lack of a better place.
3594 */
3595 if (dopt->binary_upgrade)
3596 {
3597 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
3598 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
3599 "SET datfrozenxid = '%u', datminmxid = '%u'\n"
3600 "WHERE datname = ",
3601 frozenxid, minmxid);
3604 }
3605
3606 if (creaQry->len > 0)
3608 ARCHIVE_OPTS(.tag = datname,
3609 .owner = dba,
3610 .description = "DATABASE PROPERTIES",
3611 .section = SECTION_PRE_DATA,
3612 .createStmt = creaQry->data,
3613 .dropStmt = delQry->data,
3614 .deps = &dbDumpId));
3615
3616 /*
3617 * pg_largeobject comes from the old system intact, so set its
3618 * relfrozenxids, relminmxids and relfilenode.
3619 *
3620 * pg_largeobject_metadata also comes from the old system intact for
3621 * upgrades from v16 and newer, so set its relfrozenxids, relminmxids, and
3622 * relfilenode, too. pg_upgrade can't copy/link the files from older
3623 * versions because aclitem (needed by pg_largeobject_metadata.lomacl)
3624 * changed its storage format in v16.
3625 */
3626 if (dopt->binary_upgrade)
3627 {
3634 int ii_relfrozenxid,
3636 ii_oid,
3638
3639 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
3640 "FROM pg_catalog.pg_class\n"
3641 "WHERE oid IN (%u, %u, %u, %u);\n",
3644
3646
3647 ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
3648 ii_relminmxid = PQfnumber(lo_res, "relminmxid");
3649 ii_relfilenode = PQfnumber(lo_res, "relfilenode");
3650 ii_oid = PQfnumber(lo_res, "oid");
3651
3652 appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3653 appendPQExpBufferStr(lomHorizonQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
3654 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
3655 appendPQExpBufferStr(lomOutQry, "\n-- For binary upgrade, preserve pg_largeobject_metadata and index relfilenodes\n");
3656 for (int i = 0; i < PQntuples(lo_res); ++i)
3657 {
3658 Oid oid;
3659 RelFileNumber relfilenumber;
3662
3663 oid = atooid(PQgetvalue(lo_res, i, ii_oid));
3664 relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
3665
3666 if (oid == LargeObjectRelationId ||
3668 {
3670 outQry = loOutQry;
3671 }
3672 else
3673 {
3675 outQry = lomOutQry;
3676 }
3677
3678 appendPQExpBuffer(horizonQry, "UPDATE pg_catalog.pg_class\n"
3679 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3680 "WHERE oid = %u;\n",
3684
3685 if (oid == LargeObjectRelationId ||
3688 "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
3689 relfilenumber);
3690 else if (oid == LargeObjectLOidPNIndexId ||
3693 "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
3694 relfilenumber);
3695 }
3696
3698 "TRUNCATE pg_catalog.pg_largeobject;\n");
3700 "TRUNCATE pg_catalog.pg_largeobject_metadata;\n");
3701
3704
3706 ARCHIVE_OPTS(.tag = "pg_largeobject",
3707 .description = "pg_largeobject",
3708 .section = SECTION_PRE_DATA,
3709 .createStmt = loOutQry->data));
3710
3711 if (fout->remoteVersion >= 160000)
3713 ARCHIVE_OPTS(.tag = "pg_largeobject_metadata",
3714 .description = "pg_largeobject_metadata",
3715 .section = SECTION_PRE_DATA,
3716 .createStmt = lomOutQry->data));
3717
3718 PQclear(lo_res);
3719
3725 }
3726
3727 PQclear(res);
3728
3734}
3735
3736/*
3737 * Collect any database-specific or role-and-database-specific SET options
3738 * for this database, and append them to outbuf.
3739 */
3740static void
3742 const char *dbname, Oid dboid)
3743{
3744 PGconn *conn = GetConnection(AH);
3746 PGresult *res;
3747
3748 /* First collect database-specific options */
3749 printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
3750 "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3751 dboid);
3752
3753 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3754
3755 for (int i = 0; i < PQntuples(res); i++)
3757 "DATABASE", dbname, NULL, NULL,
3758 outbuf);
3759
3760 PQclear(res);
3761
3762 /* Now look for role-and-database-specific options */
3763 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3764 "FROM pg_db_role_setting s, pg_roles r "
3765 "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3766 dboid);
3767
3768 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3769
3770 for (int i = 0; i < PQntuples(res); i++)
3772 "ROLE", PQgetvalue(res, i, 0),
3773 "DATABASE", dbname,
3774 outbuf);
3775
3776 PQclear(res);
3777
3779}
3780
3781/*
3782 * dumpEncoding: put the correct encoding into the archive
3783 */
3784static void
3786{
3787 const char *encname = pg_encoding_to_char(AH->encoding);
3789
3790 pg_log_info("saving encoding = %s", encname);
3791
3792 appendPQExpBufferStr(qry, "SET client_encoding = ");
3794 appendPQExpBufferStr(qry, ";\n");
3795
3797 ARCHIVE_OPTS(.tag = "ENCODING",
3798 .description = "ENCODING",
3799 .section = SECTION_PRE_DATA,
3800 .createStmt = qry->data));
3801
3802 destroyPQExpBuffer(qry);
3803}
3804
3805
3806/*
3807 * dumpStdStrings: put the correct escape string behavior into the archive
3808 */
3809static void
3811{
3812 const char *stdstrings = AH->std_strings ? "on" : "off";
3814
3815 pg_log_info("saving \"standard_conforming_strings = %s\"",
3816 stdstrings);
3817
3818 appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3819 stdstrings);
3820
3822 ARCHIVE_OPTS(.tag = "STDSTRINGS",
3823 .description = "STDSTRINGS",
3824 .section = SECTION_PRE_DATA,
3825 .createStmt = qry->data));
3826
3827 destroyPQExpBuffer(qry);
3828}
3829
3830/*
3831 * dumpSearchPath: record the active search_path in the archive
3832 */
3833static void
3835{
3838 PGresult *res;
3839 char **schemanames = NULL;
3840 int nschemanames = 0;
3841 int i;
3842
3843 /*
3844 * We use the result of current_schemas(), not the search_path GUC,
3845 * because that might contain wildcards such as "$user", which won't
3846 * necessarily have the same value during restore. Also, this way avoids
3847 * listing schemas that may appear in search_path but not actually exist,
3848 * which seems like a prudent exclusion.
3849 */
3851 "SELECT pg_catalog.current_schemas(false)");
3852
3853 if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3854 pg_fatal("could not parse result of current_schemas()");
3855
3856 /*
3857 * We use set_config(), not a simple "SET search_path" command, because
3858 * the latter has less-clean behavior if the search path is empty. While
3859 * that's likely to get fixed at some point, it seems like a good idea to
3860 * be as backwards-compatible as possible in what we put into archives.
3861 */
3862 for (i = 0; i < nschemanames; i++)
3863 {
3864 if (i > 0)
3865 appendPQExpBufferStr(path, ", ");
3867 }
3868
3869 appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3870 appendStringLiteralAH(qry, path->data, AH);
3871 appendPQExpBufferStr(qry, ", false);\n");
3872
3873 pg_log_info("saving \"search_path = %s\"", path->data);
3874
3876 ARCHIVE_OPTS(.tag = "SEARCHPATH",
3877 .description = "SEARCHPATH",
3878 .section = SECTION_PRE_DATA,
3879 .createStmt = qry->data));
3880
3881 /* Also save it in AH->searchpath, in case we're doing plain text dump */
3882 AH->searchpath = pg_strdup(qry->data);
3883
3885 PQclear(res);
3886 destroyPQExpBuffer(qry);
3887 destroyPQExpBuffer(path);
3888}
3889
3890
3891/*
3892 * getLOs:
3893 * Collect schema-level data about large objects
3894 */
3895static void
3897{
3898 DumpOptions *dopt = fout->dopt;
3900 PGresult *res;
3901 int ntups;
3902 int i;
3903 int n;
3904 int i_oid;
3905 int i_lomowner;
3906 int i_lomacl;
3907 int i_acldefault;
3908
3909 pg_log_info("reading large objects");
3910
3911 /*
3912 * Fetch LO OIDs and owner/ACL data. Order the data so that all the blobs
3913 * with the same owner/ACL appear together.
3914 */
3916 "SELECT oid, lomowner, lomacl, "
3917 "acldefault('L', lomowner) AS acldefault "
3918 "FROM pg_largeobject_metadata ");
3919
3920 /*
3921 * For binary upgrades, we transfer pg_largeobject_metadata via COPY or by
3922 * copying/linking its files from the old cluster. On such upgrades, we
3923 * only need to consider large objects that have comments or security
3924 * labels, since we still restore those objects via COMMENT/SECURITY LABEL
3925 * commands.
3926 */
3927 if (dopt->binary_upgrade)
3929 "WHERE oid IN "
3930 "(SELECT objoid FROM pg_description "
3931 "WHERE classoid = " CppAsString2(LargeObjectRelationId) " "
3932 "UNION SELECT objoid FROM pg_seclabel "
3933 "WHERE classoid = " CppAsString2(LargeObjectRelationId) ") ");
3934
3936 "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
3937
3939
3940 i_oid = PQfnumber(res, "oid");
3941 i_lomowner = PQfnumber(res, "lomowner");
3942 i_lomacl = PQfnumber(res, "lomacl");
3943 i_acldefault = PQfnumber(res, "acldefault");
3944
3945 ntups = PQntuples(res);
3946
3947 /*
3948 * Group the blobs into suitably-sized groups that have the same owner and
3949 * ACL setting, and build a metadata and a data DumpableObject for each
3950 * group. (If we supported initprivs for blobs, we'd have to insist that
3951 * groups also share initprivs settings, since the DumpableObject only has
3952 * room for one.) i is the index of the first tuple in the current group,
3953 * and n is the number of tuples we include in the group.
3954 */
3955 for (i = 0; i < ntups; i += n)
3956 {
3957 Oid thisoid = atooid(PQgetvalue(res, i, i_oid));
3958 char *thisowner = PQgetvalue(res, i, i_lomowner);
3959 char *thisacl = PQgetvalue(res, i, i_lomacl);
3960 LoInfo *loinfo;
3962 char namebuf[64];
3963
3964 /* Scan to find first tuple not to be included in group */
3965 n = 1;
3966 while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
3967 {
3968 if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
3969 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
3970 break;
3971 n++;
3972 }
3973
3974 /* Build the metadata DumpableObject */
3975 loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
3976
3978 loinfo->dobj.catId.tableoid = LargeObjectRelationId;
3979 loinfo->dobj.catId.oid = thisoid;
3980 AssignDumpId(&loinfo->dobj);
3981
3982 if (n > 1)
3983 snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
3984 atooid(PQgetvalue(res, i + n - 1, i_oid)));
3985 else
3986 snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
3987 loinfo->dobj.name = pg_strdup(namebuf);
3988 loinfo->dacl.acl = pg_strdup(thisacl);
3989 loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
3990 loinfo->dacl.privtype = 0;
3991 loinfo->dacl.initprivs = NULL;
3992 loinfo->rolname = getRoleName(thisowner);
3993 loinfo->numlos = n;
3994 loinfo->looids[0] = thisoid;
3995 /* Collect OIDs of the remaining blobs in this group */
3996 for (int k = 1; k < n; k++)
3997 {
3999
4000 loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
4001
4002 /* Make sure we can look up loinfo by any of the blobs' OIDs */
4003 extraID.tableoid = LargeObjectRelationId;
4004 extraID.oid = loinfo->looids[k];
4006 }
4007
4008 /* LOs have data */
4009 loinfo->dobj.components |= DUMP_COMPONENT_DATA;
4010
4011 /* Mark whether LO group has a non-empty ACL */
4012 if (!PQgetisnull(res, i, i_lomacl))
4013 loinfo->dobj.components |= DUMP_COMPONENT_ACL;
4014
4015 /*
4016 * In binary upgrade mode, pg_largeobject and pg_largeobject_metadata
4017 * are transferred via COPY or by copying/linking the files from the
4018 * old cluster. Thus, we do not need to dump LO data, definitions, or
4019 * ACLs.
4020 */
4021 if (dopt->binary_upgrade)
4023
4024 /*
4025 * Create a "BLOBS" data item for the group, too. This is just a
4026 * placeholder for sorting; it carries no data now.
4027 */
4029 lodata->objType = DO_LARGE_OBJECT_DATA;
4030 lodata->catId = nilCatalogId;
4032 lodata->name = pg_strdup(namebuf);
4033 lodata->components |= DUMP_COMPONENT_DATA;
4034 /* Set up explicit dependency from data to metadata */
4035 lodata->dependencies = pg_malloc_object(DumpId);
4036 lodata->dependencies[0] = loinfo->dobj.dumpId;
4037 lodata->nDeps = lodata->allocDeps = 1;
4038 }
4039
4040 PQclear(res);
4042}
4043
4044/*
4045 * dumpLO
4046 *
4047 * dump the definition (metadata) of the given large object group
4048 */
4049static void
4051{
4053
4054 /*
4055 * The "definition" is just a newline-separated list of OIDs. We need to
4056 * put something into the dropStmt too, but it can just be a comment.
4057 */
4058 for (int i = 0; i < loinfo->numlos; i++)
4059 appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
4060
4061 if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4062 ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
4063 ARCHIVE_OPTS(.tag = loinfo->dobj.name,
4064 .owner = loinfo->rolname,
4065 .description = "BLOB METADATA",
4066 .section = SECTION_DATA,
4067 .createStmt = cquery->data,
4068 .dropStmt = "-- dummy"));
4069
4070 /*
4071 * Dump per-blob comments and seclabels if any. We assume these are rare
4072 * enough that it's okay to generate retail TOC entries for them.
4073 */
4074 if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
4076 {
4077 for (int i = 0; i < loinfo->numlos; i++)
4078 {
4079 CatalogId catId;
4080 char namebuf[32];
4081
4082 /* Build identifying info for this blob */
4083 catId.tableoid = loinfo->dobj.catId.tableoid;
4084 catId.oid = loinfo->looids[i];
4085 snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
4086
4087 if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4088 dumpComment(fout, "LARGE OBJECT", namebuf,
4089 NULL, loinfo->rolname,
4090 catId, 0, loinfo->dobj.dumpId);
4091
4092 if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4093 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
4094 NULL, loinfo->rolname,
4095 catId, 0, loinfo->dobj.dumpId);
4096 }
4097 }
4098
4099 /*
4100 * Dump the ACLs if any (remember that all blobs in the group will have
4101 * the same ACL). If there's just one blob, dump a simple ACL entry; if
4102 * there's more, make a "LARGE OBJECTS" entry that really contains only
4103 * the ACL for the first blob. _printTocEntry() will be cued by the tag
4104 * string to emit a mutated version for each blob.
4105 */
4106 if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
4107 {
4108 char namebuf[32];
4109
4110 /* Build identifying info for the first blob */
4111 snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
4112
4113 if (loinfo->numlos > 1)
4114 {
4115 char tagbuf[64];
4116
4117 snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
4118 loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
4119
4120 dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
4121 "LARGE OBJECT", namebuf, NULL, NULL,
4122 tagbuf, loinfo->rolname, &loinfo->dacl);
4123 }
4124 else
4125 {
4126 dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
4127 "LARGE OBJECT", namebuf, NULL, NULL,
4128 NULL, loinfo->rolname, &loinfo->dacl);
4129 }
4130 }
4131
4133}
4134
4135/*
4136 * dumpLOs:
4137 * dump the data contents of the large objects in the given group
4138 */
4139static int
4140dumpLOs(Archive *fout, const void *arg)
4141{
4142 const LoInfo *loinfo = (const LoInfo *) arg;
4144 char buf[LOBBUFSIZE];
4145
4146 pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
4147
4148 for (int i = 0; i < loinfo->numlos; i++)
4149 {
4150 Oid loOid = loinfo->looids[i];
4151 int loFd;
4152 int cnt;
4153
4154 /* Open the LO */
4155 loFd = lo_open(conn, loOid, INV_READ);
4156 if (loFd == -1)
4157 pg_fatal("could not open large object %u: %s",
4159
4160 StartLO(fout, loOid);
4161
4162 /* Now read it in chunks, sending data to archive */
4163 do
4164 {
4165 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
4166 if (cnt < 0)
4167 pg_fatal("error reading large object %u: %s",
4169
4170 WriteData(fout, buf, cnt);
4171 } while (cnt > 0);
4172
4173 lo_close(conn, loFd);
4174
4175 EndLO(fout, loOid);
4176 }
4177
4178 return 1;
4179}
4180
4181/*
4182 * getPolicies
4183 * get information about all RLS policies on dumpable tables.
4184 */
4185void
4186getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
4187{
4188 DumpOptions *dopt = fout->dopt;
4189 PQExpBuffer query;
4191 PGresult *res;
4193 int i_oid;
4194 int i_tableoid;
4195 int i_polrelid;
4196 int i_polname;
4197 int i_polcmd;
4198 int i_polpermissive;
4199 int i_polroles;
4200 int i_polqual;
4201 int i_polwithcheck;
4202 int i,
4203 j,
4204 ntups;
4205
4206 /* Skip if --no-policies was specified */
4207 if (dopt->no_policies)
4208 return;
4209
4210 query = createPQExpBuffer();
4212
4213 /*
4214 * Identify tables of interest, and check which ones have RLS enabled.
4215 */
4217 for (i = 0; i < numTables; i++)
4218 {
4219 TableInfo *tbinfo = &tblinfo[i];
4220
4221 /* Ignore row security on tables not to be dumped */
4222 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
4223 continue;
4224
4225 /* It can't have RLS or policies if it's not a table */
4226 if (tbinfo->relkind != RELKIND_RELATION &&
4228 continue;
4229
4230 /* Add it to the list of table OIDs to be probed below */
4231 if (tbloids->len > 1) /* do we have more than the '{'? */
4233 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
4234
4235 /* Is RLS enabled? (That's separate from whether it has policies) */
4236 if (tbinfo->rowsec)
4237 {
4238 tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
4239
4240 /*
4241 * We represent RLS being enabled on a table by creating a
4242 * PolicyInfo object with null polname.
4243 *
4244 * Note: use tableoid 0 so that this object won't be mistaken for
4245 * something that pg_depend entries apply to.
4246 */
4248 polinfo->dobj.objType = DO_POLICY;
4249 polinfo->dobj.catId.tableoid = 0;
4250 polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
4251 AssignDumpId(&polinfo->dobj);
4252 polinfo->dobj.namespace = tbinfo->dobj.namespace;
4253 polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
4254 polinfo->poltable = tbinfo;
4255 polinfo->polname = NULL;
4256 polinfo->polcmd = '\0';
4257 polinfo->polpermissive = 0;
4258 polinfo->polroles = NULL;
4259 polinfo->polqual = NULL;
4260 polinfo->polwithcheck = NULL;
4261 }
4262 }
4264
4265 /*
4266 * Now, read all RLS policies belonging to the tables of interest, and
4267 * create PolicyInfo objects for them. (Note that we must filter the
4268 * results server-side not locally, because we dare not apply pg_get_expr
4269 * to tables we don't have lock on.)
4270 */
4271 pg_log_info("reading row-level security policies");
4272
4273 printfPQExpBuffer(query,
4274 "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
4275 appendPQExpBufferStr(query, "pol.polpermissive, ");
4276 appendPQExpBuffer(query,
4277 "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
4278 " 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, "
4279 "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
4280 "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
4281 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
4282 "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
4283 tbloids->data);
4284
4285 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4286
4287 ntups = PQntuples(res);
4288 if (ntups > 0)
4289 {
4290 i_oid = PQfnumber(res, "oid");
4291 i_tableoid = PQfnumber(res, "tableoid");
4292 i_polrelid = PQfnumber(res, "polrelid");
4293 i_polname = PQfnumber(res, "polname");
4294 i_polcmd = PQfnumber(res, "polcmd");
4295 i_polpermissive = PQfnumber(res, "polpermissive");
4296 i_polroles = PQfnumber(res, "polroles");
4297 i_polqual = PQfnumber(res, "polqual");
4298 i_polwithcheck = PQfnumber(res, "polwithcheck");
4299
4301
4302 for (j = 0; j < ntups; j++)
4303 {
4306
4307 tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
4308
4309 polinfo[j].dobj.objType = DO_POLICY;
4310 polinfo[j].dobj.catId.tableoid =
4311 atooid(PQgetvalue(res, j, i_tableoid));
4312 polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4313 AssignDumpId(&polinfo[j].dobj);
4314 polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4315 polinfo[j].poltable = tbinfo;
4316 polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
4317 polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
4318
4319 polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
4320 polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
4321
4322 if (PQgetisnull(res, j, i_polroles))
4323 polinfo[j].polroles = NULL;
4324 else
4325 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
4326
4327 if (PQgetisnull(res, j, i_polqual))
4328 polinfo[j].polqual = NULL;
4329 else
4330 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
4331
4332 if (PQgetisnull(res, j, i_polwithcheck))
4333 polinfo[j].polwithcheck = NULL;
4334 else
4335 polinfo[j].polwithcheck
4337 }
4338 }
4339
4340 PQclear(res);
4341
4342 destroyPQExpBuffer(query);
4344}
4345
4346/*
4347 * dumpPolicy
4348 * dump the definition of the given policy
4349 */
4350static void
4352{
4353 DumpOptions *dopt = fout->dopt;
4354 TableInfo *tbinfo = polinfo->poltable;
4355 PQExpBuffer query;
4358 char *qtabname;
4359 const char *cmd;
4360 char *tag;
4361
4362 /* Do nothing if not dumping schema */
4363 if (!dopt->dumpSchema)
4364 return;
4365
4366 /*
4367 * If polname is NULL, then this record is just indicating that ROW LEVEL
4368 * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
4369 * ROW LEVEL SECURITY.
4370 */
4371 if (polinfo->polname == NULL)
4372 {
4373 query = createPQExpBuffer();
4374
4375 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
4377
4378 /*
4379 * We must emit the ROW SECURITY object's dependency on its table
4380 * explicitly, because it will not match anything in pg_depend (unlike
4381 * the case for other PolicyInfo objects).
4382 */
4383 if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4384 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
4385 ARCHIVE_OPTS(.tag = polinfo->dobj.name,
4386 .namespace = polinfo->dobj.namespace->dobj.name,
4387 .owner = tbinfo->rolname,
4388 .description = "ROW SECURITY",
4389 .section = SECTION_POST_DATA,
4390 .createStmt = query->data,
4391 .deps = &(tbinfo->dobj.dumpId),
4392 .nDeps = 1));
4393
4394 destroyPQExpBuffer(query);
4395 return;
4396 }
4397
4398 if (polinfo->polcmd == '*')
4399 cmd = "";
4400 else if (polinfo->polcmd == 'r')
4401 cmd = " FOR SELECT";
4402 else if (polinfo->polcmd == 'a')
4403 cmd = " FOR INSERT";
4404 else if (polinfo->polcmd == 'w')
4405 cmd = " FOR UPDATE";
4406 else if (polinfo->polcmd == 'd')
4407 cmd = " FOR DELETE";
4408 else
4409 pg_fatal("unexpected policy command type: %c",
4410 polinfo->polcmd);
4411
4412 query = createPQExpBuffer();
4415
4416 qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
4417
4418 appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
4419
4420 appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
4421 !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
4422
4423 if (polinfo->polroles != NULL)
4424 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
4425
4426 if (polinfo->polqual != NULL)
4427 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
4428
4429 if (polinfo->polwithcheck != NULL)
4430 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
4431
4432 appendPQExpBufferStr(query, ";\n");
4433
4434 appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
4436
4437 appendPQExpBuffer(polprefix, "POLICY %s ON",
4438 fmtId(polinfo->polname));
4439
4440 tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
4441
4442 if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4443 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
4444 ARCHIVE_OPTS(.tag = tag,
4445 .namespace = polinfo->dobj.namespace->dobj.name,
4446 .owner = tbinfo->rolname,
4447 .description = "POLICY",
4448 .section = SECTION_POST_DATA,
4449 .createStmt = query->data,
4450 .dropStmt = delqry->data));
4451
4452 if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4454 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
4455 polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
4456
4457 pfree(tag);
4458 destroyPQExpBuffer(query);
4462}
4463
4464/*
4465 * getPublications
4466 * get information about publications
4467 */
4468void
4470{
4471 DumpOptions *dopt = fout->dopt;
4472 PQExpBuffer query;
4473 PGresult *res;
4475 int i_tableoid;
4476 int i_oid;
4477 int i_pubname;
4478 int i_pubowner;
4479 int i_puballtables;
4481 int i_pubinsert;
4482 int i_pubupdate;
4483 int i_pubdelete;
4484 int i_pubtruncate;
4485 int i_pubviaroot;
4486 int i_pubgencols;
4487 int i,
4488 ntups;
4489
4490 if (dopt->no_publications)
4491 return;
4492
4493 query = createPQExpBuffer();
4494
4495 /* Get the publications. */
4496 appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
4497 "p.pubowner, p.puballtables, p.pubinsert, "
4498 "p.pubupdate, p.pubdelete, ");
4499
4500 if (fout->remoteVersion >= 110000)
4501 appendPQExpBufferStr(query, "p.pubtruncate, ");
4502 else
4503 appendPQExpBufferStr(query, "false AS pubtruncate, ");
4504
4505 if (fout->remoteVersion >= 130000)
4506 appendPQExpBufferStr(query, "p.pubviaroot, ");
4507 else
4508 appendPQExpBufferStr(query, "false AS pubviaroot, ");
4509
4510 if (fout->remoteVersion >= 180000)
4511 appendPQExpBufferStr(query, "p.pubgencols, ");
4512 else
4513 appendPQExpBuffer(query, "'%c' AS pubgencols, ", PUBLISH_GENCOLS_NONE);
4514
4515 if (fout->remoteVersion >= 190000)
4516 appendPQExpBufferStr(query, "p.puballsequences ");
4517 else
4518 appendPQExpBufferStr(query, "false AS puballsequences ");
4519
4520 appendPQExpBufferStr(query, "FROM pg_publication p");
4521
4522 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4523
4524 ntups = PQntuples(res);
4525
4526 if (ntups == 0)
4527 goto cleanup;
4528
4529 i_tableoid = PQfnumber(res, "tableoid");
4530 i_oid = PQfnumber(res, "oid");
4531 i_pubname = PQfnumber(res, "pubname");
4532 i_pubowner = PQfnumber(res, "pubowner");
4533 i_puballtables = PQfnumber(res, "puballtables");
4534 i_puballsequences = PQfnumber(res, "puballsequences");
4535 i_pubinsert = PQfnumber(res, "pubinsert");
4536 i_pubupdate = PQfnumber(res, "pubupdate");
4537 i_pubdelete = PQfnumber(res, "pubdelete");
4538 i_pubtruncate = PQfnumber(res, "pubtruncate");
4539 i_pubviaroot = PQfnumber(res, "pubviaroot");
4540 i_pubgencols = PQfnumber(res, "pubgencols");
4541
4543
4544 for (i = 0; i < ntups; i++)
4545 {
4546 pubinfo[i].dobj.objType = DO_PUBLICATION;
4547 pubinfo[i].dobj.catId.tableoid =
4548 atooid(PQgetvalue(res, i, i_tableoid));
4549 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4550 AssignDumpId(&pubinfo[i].dobj);
4551 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
4552 pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
4553 pubinfo[i].puballtables =
4554 (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
4555 pubinfo[i].puballsequences =
4556 (strcmp(PQgetvalue(res, i, i_puballsequences), "t") == 0);
4557 pubinfo[i].pubinsert =
4558 (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
4559 pubinfo[i].pubupdate =
4560 (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
4561 pubinfo[i].pubdelete =
4562 (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
4563 pubinfo[i].pubtruncate =
4564 (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
4565 pubinfo[i].pubviaroot =
4566 (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
4567 pubinfo[i].pubgencols_type =
4568 *(PQgetvalue(res, i, i_pubgencols));
4569 pubinfo[i].except_tables = (SimplePtrList)
4570 {
4571 NULL, NULL
4572 };
4573
4574 /* Decide whether we want to dump it */
4576
4577 /*
4578 * Get the list of tables for publications specified in the EXCEPT
4579 * TABLE clause.
4580 *
4581 * Although individual table entries in EXCEPT list could be stored in
4582 * PublicationRelInfo, dumpPublicationTable cannot be used to emit
4583 * them, because there is no ALTER PUBLICATION ... ADD command to add
4584 * individual table entries to the EXCEPT list.
4585 *
4586 * Therefore, the approach is to dump the complete EXCEPT list in a
4587 * single CREATE PUBLICATION statement. PublicationInfo is used to
4588 * collect this information, which is then emitted by
4589 * dumpPublication().
4590 */
4591 if (fout->remoteVersion >= 190000)
4592 {
4593 int ntbls;
4595
4596 resetPQExpBuffer(query);
4597 appendPQExpBuffer(query,
4598 "SELECT prrelid\n"
4599 "FROM pg_catalog.pg_publication_rel\n"
4600 "WHERE prpubid = %u AND prexcept",
4601 pubinfo[i].dobj.catId.oid);
4602
4604
4606
4607 for (int j = 0; j < ntbls; j++)
4608 {
4609 Oid prrelid;
4611
4613
4615
4616 if (tbinfo != NULL)
4617 simple_ptr_list_append(&pubinfo[i].except_tables, tbinfo);
4618 }
4619
4621 }
4622 }
4623
4624cleanup:
4625 PQclear(res);
4626
4627 destroyPQExpBuffer(query);
4628}
4629
4630/*
4631 * dumpPublication
4632 * dump the definition of the given publication
4633 */
4634static void
4636{
4637 DumpOptions *dopt = fout->dopt;
4639 PQExpBuffer query;
4640 char *qpubname;
4641 bool first = true;
4642
4643 /* Do nothing if not dumping schema */
4644 if (!dopt->dumpSchema)
4645 return;
4646
4648 query = createPQExpBuffer();
4649
4650 qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
4651
4652 appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
4653 qpubname);
4654
4655 appendPQExpBuffer(query, "CREATE PUBLICATION %s",
4656 qpubname);
4657
4658 if (pubinfo->puballtables)
4659 {
4660 int n_except = 0;
4661
4662 appendPQExpBufferStr(query, " FOR ALL TABLES");
4663
4664 /* Include EXCEPT (TABLE) clause if there are except_tables. */
4665 for (SimplePtrListCell *cell = pubinfo->except_tables.head; cell; cell = cell->next)
4666 {
4667 TableInfo *tbinfo = (TableInfo *) cell->ptr;
4668
4669 if (++n_except == 1)
4670 appendPQExpBufferStr(query, " EXCEPT (");
4671 else
4672 appendPQExpBufferStr(query, ", ");
4673 appendPQExpBuffer(query, "TABLE ONLY %s", fmtQualifiedDumpable(tbinfo));
4674 }
4675 if (n_except > 0)
4676 appendPQExpBufferChar(query, ')');
4677
4678 if (pubinfo->puballsequences)
4679 appendPQExpBufferStr(query, ", ALL SEQUENCES");
4680 }
4681 else if (pubinfo->puballsequences)
4682 appendPQExpBufferStr(query, " FOR ALL SEQUENCES");
4683
4684 appendPQExpBufferStr(query, " WITH (publish = '");
4685 if (pubinfo->pubinsert)
4686 {
4687 appendPQExpBufferStr(query, "insert");
4688 first = false;
4689 }
4690
4691 if (pubinfo->pubupdate)
4692 {
4693 if (!first)
4694 appendPQExpBufferStr(query, ", ");
4695
4696 appendPQExpBufferStr(query, "update");
4697 first = false;
4698 }
4699
4700 if (pubinfo->pubdelete)
4701 {
4702 if (!first)
4703 appendPQExpBufferStr(query, ", ");
4704
4705 appendPQExpBufferStr(query, "delete");
4706 first = false;
4707 }
4708
4709 if (pubinfo->pubtruncate)
4710 {
4711 if (!first)
4712 appendPQExpBufferStr(query, ", ");
4713
4714 appendPQExpBufferStr(query, "truncate");
4715 first = false;
4716 }
4717
4718 appendPQExpBufferChar(query, '\'');
4719
4720 if (pubinfo->pubviaroot)
4721 appendPQExpBufferStr(query, ", publish_via_partition_root = true");
4722
4723 if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
4724 appendPQExpBufferStr(query, ", publish_generated_columns = stored");
4725
4726 appendPQExpBufferStr(query, ");\n");
4727
4728 if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4729 ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
4730 ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
4731 .owner = pubinfo->rolname,
4732 .description = "PUBLICATION",
4733 .section = SECTION_POST_DATA,
4734 .createStmt = query->data,
4735 .dropStmt = delq->data));
4736
4737 if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4738 dumpComment(fout, "PUBLICATION", qpubname,
4739 NULL, pubinfo->rolname,
4740 pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4741
4742 if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4743 dumpSecLabel(fout, "PUBLICATION", qpubname,
4744 NULL, pubinfo->rolname,
4745 pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4746
4748 destroyPQExpBuffer(query);
4750}
4751
4752/*
4753 * getPublicationNamespaces
4754 * get information about publication membership for dumpable schemas.
4755 */
4756void
4758{
4759 PQExpBuffer query;
4760 PGresult *res;
4762 DumpOptions *dopt = fout->dopt;
4763 int i_tableoid;
4764 int i_oid;
4765 int i_pnpubid;
4766 int i_pnnspid;
4767 int i,
4768 j,
4769 ntups;
4770
4771 if (dopt->no_publications || fout->remoteVersion < 150000)
4772 return;
4773
4774 query = createPQExpBuffer();
4775
4776 /* Collect all publication membership info. */
4778 "SELECT tableoid, oid, pnpubid, pnnspid "
4779 "FROM pg_catalog.pg_publication_namespace");
4780 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4781
4782 ntups = PQntuples(res);
4783
4784 i_tableoid = PQfnumber(res, "tableoid");
4785 i_oid = PQfnumber(res, "oid");
4786 i_pnpubid = PQfnumber(res, "pnpubid");
4787 i_pnnspid = PQfnumber(res, "pnnspid");
4788
4789 /* this allocation may be more than we need */
4791 j = 0;
4792
4793 for (i = 0; i < ntups; i++)
4794 {
4799
4800 /*
4801 * Ignore any entries for which we aren't interested in either the
4802 * publication or the rel.
4803 */
4805 if (pubinfo == NULL)
4806 continue;
4808 if (nspinfo == NULL)
4809 continue;
4810
4811 /* OK, make a DumpableObject for this relationship */
4813 pubsinfo[j].dobj.catId.tableoid =
4814 atooid(PQgetvalue(res, i, i_tableoid));
4815 pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4816 AssignDumpId(&pubsinfo[j].dobj);
4817 pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
4818 pubsinfo[j].dobj.name = nspinfo->dobj.name;
4819 pubsinfo[j].publication = pubinfo;
4820 pubsinfo[j].pubschema = nspinfo;
4821
4822 /* Decide whether we want to dump it */
4824
4825 j++;
4826 }
4827
4828 PQclear(res);
4829 destroyPQExpBuffer(query);
4830}
4831
4832/*
4833 * getPublicationTables
4834 * get information about publication membership for dumpable tables.
4835 */
4836void
4838{
4839 PQExpBuffer query;
4840 PGresult *res;
4842 DumpOptions *dopt = fout->dopt;
4843 int i_tableoid;
4844 int i_oid;
4845 int i_prpubid;
4846 int i_prrelid;
4847 int i_prrelqual;
4848 int i_prattrs;
4849 int i,
4850 j,
4851 ntups;
4852
4853 if (dopt->no_publications)
4854 return;
4855
4856 query = createPQExpBuffer();
4857
4858 /* Collect all publication membership info. */
4859 if (fout->remoteVersion >= 150000)
4860 {
4862 "SELECT tableoid, oid, prpubid, prrelid, "
4863 "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
4864 "(CASE\n"
4865 " WHEN pr.prattrs IS NOT NULL THEN\n"
4866 " (SELECT array_agg(attname)\n"
4867 " FROM\n"
4868 " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
4869 " pg_catalog.pg_attribute\n"
4870 " WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
4871 " ELSE NULL END) prattrs "
4872 "FROM pg_catalog.pg_publication_rel pr");
4873 if (fout->remoteVersion >= 190000)
4874 appendPQExpBufferStr(query, " WHERE NOT pr.prexcept");
4875 }
4876 else
4878 "SELECT tableoid, oid, prpubid, prrelid, "
4879 "NULL AS prrelqual, NULL AS prattrs "
4880 "FROM pg_catalog.pg_publication_rel");
4881 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4882
4883 ntups = PQntuples(res);
4884
4885 i_tableoid = PQfnumber(res, "tableoid");
4886 i_oid = PQfnumber(res, "oid");
4887 i_prpubid = PQfnumber(res, "prpubid");
4888 i_prrelid = PQfnumber(res, "prrelid");
4889 i_prrelqual = PQfnumber(res, "prrelqual");
4890 i_prattrs = PQfnumber(res, "prattrs");
4891
4892 /* this allocation may be more than we need */
4894 j = 0;
4895
4896 for (i = 0; i < ntups; i++)
4897 {
4902
4903 /*
4904 * Ignore any entries for which we aren't interested in either the
4905 * publication or the rel.
4906 */
4908 if (pubinfo == NULL)
4909 continue;
4911 if (tbinfo == NULL)
4912 continue;
4913
4914 /* OK, make a DumpableObject for this relationship */
4915 pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
4916 pubrinfo[j].dobj.catId.tableoid =
4917 atooid(PQgetvalue(res, i, i_tableoid));
4918 pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4919 AssignDumpId(&pubrinfo[j].dobj);
4920 pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4921 pubrinfo[j].dobj.name = tbinfo->dobj.name;
4922 pubrinfo[j].publication = pubinfo;
4923 pubrinfo[j].pubtable = tbinfo;
4924 if (PQgetisnull(res, i, i_prrelqual))
4925 pubrinfo[j].pubrelqual = NULL;
4926 else
4927 pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
4928
4929 if (!PQgetisnull(res, i, i_prattrs))
4930 {
4931 char **attnames;
4932 int nattnames;
4934
4935 if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
4936 &attnames, &nattnames))
4937 pg_fatal("could not parse %s array", "prattrs");
4939 for (int k = 0; k < nattnames; k++)
4940 {
4941 if (k > 0)
4943
4944 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
4945 }
4946 pubrinfo[j].pubrattrs = attribs->data;
4947 free(attribs); /* but not attribs->data */
4948 free(attnames);
4949 }
4950 else
4951 pubrinfo[j].pubrattrs = NULL;
4952
4953 /* Decide whether we want to dump it */
4955
4956 j++;
4957 }
4958
4959 PQclear(res);
4960 destroyPQExpBuffer(query);
4961}
4962
4963/*
4964 * dumpPublicationNamespace
4965 * dump the definition of the given publication schema mapping.
4966 */
4967static void
4969{
4970 DumpOptions *dopt = fout->dopt;
4971 NamespaceInfo *schemainfo = pubsinfo->pubschema;
4972 PublicationInfo *pubinfo = pubsinfo->publication;
4973 PQExpBuffer query;
4974 char *tag;
4975
4976 /* Do nothing if not dumping schema */
4977 if (!dopt->dumpSchema)
4978 return;
4979
4980 tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
4981
4982 query = createPQExpBuffer();
4983
4984 appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
4985 appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
4986
4987 /*
4988 * There is no point in creating drop query as the drop is done by schema
4989 * drop.
4990 */
4991 if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4992 ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
4993 ARCHIVE_OPTS(.tag = tag,
4994 .namespace = schemainfo->dobj.name,
4995 .owner = pubinfo->rolname,
4996 .description = "PUBLICATION TABLES IN SCHEMA",
4997 .section = SECTION_POST_DATA,
4998 .createStmt = query->data));
4999
5000 /* These objects can't currently have comments or seclabels */
5001
5002 pfree(tag);
5003 destroyPQExpBuffer(query);
5004}
5005
5006/*
5007 * dumpPublicationTable
5008 * dump the definition of the given publication table mapping
5009 */
5010static void
5012{
5013 DumpOptions *dopt = fout->dopt;
5014 PublicationInfo *pubinfo = pubrinfo->publication;
5015 TableInfo *tbinfo = pubrinfo->pubtable;
5016 PQExpBuffer query;
5017 char *tag;
5018
5019 /* Do nothing if not dumping schema */
5020 if (!dopt->dumpSchema)
5021 return;
5022
5023 tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
5024
5025 query = createPQExpBuffer();
5026
5027 appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
5028 fmtId(pubinfo->dobj.name));
5029 appendPQExpBuffer(query, " %s",
5031
5032 if (pubrinfo->pubrattrs)
5033 appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
5034
5035 if (pubrinfo->pubrelqual)
5036 {
5037 /*
5038 * It's necessary to add parentheses around the expression because
5039 * pg_get_expr won't supply the parentheses for things like WHERE
5040 * TRUE.
5041 */
5042 appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
5043 }
5044 appendPQExpBufferStr(query, ";\n");
5045
5046 /*
5047 * There is no point in creating a drop query as the drop is done by table
5048 * drop. (If you think to change this, see also _printTocEntry().)
5049 * Although this object doesn't really have ownership as such, set the
5050 * owner field anyway to ensure that the command is run by the correct
5051 * role at restore time.
5052 */
5053 if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5054 ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
5055 ARCHIVE_OPTS(.tag = tag,
5056 .namespace = tbinfo->dobj.namespace->dobj.name,
5057 .owner = pubinfo->rolname,
5058 .description = "PUBLICATION TABLE",
5059 .section = SECTION_POST_DATA,
5060 .createStmt = query->data));
5061
5062 /* These objects can't currently have comments or seclabels */
5063
5064 pfree(tag);
5065 destroyPQExpBuffer(query);
5066}
5067
5068/*
5069 * Is the currently connected user a superuser?
5070 */
5071static bool
5073{
5075 const char *val;
5076
5077 val = PQparameterStatus(AH->connection, "is_superuser");
5078
5079 if (val && strcmp(val, "on") == 0)
5080 return true;
5081
5082 return false;
5083}
5084
5085/*
5086 * Set the given value to restrict_nonsystem_relation_kind value. Since
5087 * restrict_nonsystem_relation_kind is introduced in minor version releases,
5088 * the setting query is effective only where available.
5089 */
5090static void
5092{
5094 PGresult *res;
5095
5096 appendPQExpBuffer(query,
5097 "SELECT set_config(name, '%s', false) "
5098 "FROM pg_settings "
5099 "WHERE name = 'restrict_nonsystem_relation_kind'",
5100 value);
5101 res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
5102
5103 PQclear(res);
5104 destroyPQExpBuffer(query);
5105}
5106
5107/*
5108 * getSubscriptions
5109 * get information about subscriptions
5110 */
5111void
5113{
5114 DumpOptions *dopt = fout->dopt;
5115 PQExpBuffer query;
5116 PGresult *res;
5117 SubscriptionInfo *subinfo;
5118 int i_tableoid;
5119 int i_oid;
5120 int i_subname;
5121 int i_subowner;
5122 int i_subbinary;
5123 int i_substream;
5127 int i_subrunasowner;
5128 int i_subservername;
5129 int i_subconninfo;
5130 int i_subslotname;
5131 int i_subsynccommit;
5134 int i_suborigin;
5136 int i_subenabled;
5137 int i_subfailover;
5140 int i,
5141 ntups;
5142
5143 if (dopt->no_subscriptions)
5144 return;
5145
5146 if (!is_superuser(fout))
5147 {
5148 int n;
5149
5150 res = ExecuteSqlQuery(fout,
5151 "SELECT count(*) FROM pg_subscription "
5152 "WHERE subdbid = (SELECT oid FROM pg_database"
5153 " WHERE datname = current_database())",
5155 n = atoi(PQgetvalue(res, 0, 0));
5156 if (n > 0)
5157 pg_log_warning("subscriptions not dumped because current user is not a superuser");
5158 PQclear(res);
5159 return;
5160 }
5161
5162 query = createPQExpBuffer();
5163
5164 /* Get the subscriptions in current database. */
5166 "SELECT s.tableoid, s.oid, s.subname,\n"
5167 " s.subowner,\n"
5168 " s.subconninfo, s.subslotname, s.subsynccommit,\n"
5169 " s.subpublications,\n");
5170
5171 if (fout->remoteVersion >= 140000)
5172 appendPQExpBufferStr(query, " s.subbinary,\n");
5173 else
5174 appendPQExpBufferStr(query, " false AS subbinary,\n");
5175
5176 if (fout->remoteVersion >= 140000)
5177 appendPQExpBufferStr(query, " s.substream,\n");
5178 else
5179 appendPQExpBufferStr(query, " 'f' AS substream,\n");
5180
5181 if (fout->remoteVersion >= 150000)
5183 " s.subtwophasestate,\n"
5184 " s.subdisableonerr,\n");
5185 else
5186 appendPQExpBuffer(query,
5187 " '%c' AS subtwophasestate,\n"
5188 " false AS subdisableonerr,\n",
5190
5191 if (fout->remoteVersion >= 160000)
5193 " s.subpasswordrequired,\n"
5194 " s.subrunasowner,\n"
5195 " s.suborigin,\n");
5196 else
5197 appendPQExpBuffer(query,
5198 " 't' AS subpasswordrequired,\n"
5199 " 't' AS subrunasowner,\n"
5200 " '%s' AS suborigin,\n",
5202
5203 if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5204 appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
5205 " s.subenabled,\n");
5206 else
5207 appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
5208 " false AS subenabled,\n");
5209
5210 if (fout->remoteVersion >= 170000)
5212 " s.subfailover,\n");
5213 else
5215 " false AS subfailover,\n");
5216
5217 if (fout->remoteVersion >= 190000)
5219 " s.subretaindeadtuples,\n");
5220 else
5222 " false AS subretaindeadtuples,\n");
5223
5224 if (fout->remoteVersion >= 190000)
5226 " s.submaxretention,\n");
5227 else
5228 appendPQExpBufferStr(query, " 0 AS submaxretention,\n");
5229
5230 if (fout->remoteVersion >= 190000)
5232 " s.subwalrcvtimeout,\n");
5233 else
5235 " '-1' AS subwalrcvtimeout,\n");
5236
5237 if (fout->remoteVersion >= 190000)
5238 appendPQExpBufferStr(query, " fs.srvname AS subservername\n");
5239 else
5240 appendPQExpBufferStr(query, " NULL AS subservername\n");
5241
5243 "FROM pg_subscription s\n");
5244
5245 if (fout->remoteVersion >= 190000)
5247 "LEFT JOIN pg_catalog.pg_foreign_server fs \n"
5248 " ON fs.oid = s.subserver \n");
5249
5250 if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5252 "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
5253 " ON o.external_id = 'pg_' || s.oid::text \n");
5254
5256 "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
5257 " WHERE datname = current_database())");
5258
5259 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5260
5261 ntups = PQntuples(res);
5262
5263 /*
5264 * Get subscription fields. We don't include subskiplsn in the dump as
5265 * after restoring the dump this value may no longer be relevant.
5266 */
5267 i_tableoid = PQfnumber(res, "tableoid");
5268 i_oid = PQfnumber(res, "oid");
5269 i_subname = PQfnumber(res, "subname");
5270 i_subowner = PQfnumber(res, "subowner");
5271 i_subenabled = PQfnumber(res, "subenabled");
5272 i_subbinary = PQfnumber(res, "subbinary");
5273 i_substream = PQfnumber(res, "substream");
5274 i_subtwophasestate = PQfnumber(res, "subtwophasestate");
5275 i_subdisableonerr = PQfnumber(res, "subdisableonerr");
5276 i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
5277 i_subrunasowner = PQfnumber(res, "subrunasowner");
5278 i_subfailover = PQfnumber(res, "subfailover");
5279 i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
5280 i_submaxretention = PQfnumber(res, "submaxretention");
5281 i_subservername = PQfnumber(res, "subservername");
5282 i_subconninfo = PQfnumber(res, "subconninfo");
5283 i_subslotname = PQfnumber(res, "subslotname");
5284 i_subsynccommit = PQfnumber(res, "subsynccommit");
5285 i_subwalrcvtimeout = PQfnumber(res, "subwalrcvtimeout");
5286 i_subpublications = PQfnumber(res, "subpublications");
5287 i_suborigin = PQfnumber(res, "suborigin");
5288 i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
5289
5290 subinfo = pg_malloc_array(SubscriptionInfo, ntups);
5291
5292 for (i = 0; i < ntups; i++)
5293 {
5294 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
5295 subinfo[i].dobj.catId.tableoid =
5296 atooid(PQgetvalue(res, i, i_tableoid));
5297 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5298 AssignDumpId(&subinfo[i].dobj);
5299 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
5300 subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
5301
5302 subinfo[i].subenabled =
5303 (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
5304 if (PQgetisnull(res, i, i_subservername))
5305 subinfo[i].subservername = NULL;
5306 else
5308 subinfo[i].subbinary =
5309 (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
5310 subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
5311 subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
5312 subinfo[i].subdisableonerr =
5313 (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
5314 subinfo[i].subpasswordrequired =
5315 (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
5316 subinfo[i].subrunasowner =
5317 (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
5318 subinfo[i].subfailover =
5319 (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
5320 subinfo[i].subretaindeadtuples =
5321 (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
5322 subinfo[i].submaxretention =
5324 if (PQgetisnull(res, i, i_subconninfo))
5325 subinfo[i].subconninfo = NULL;
5326 else
5327 subinfo[i].subconninfo =
5329 if (PQgetisnull(res, i, i_subslotname))
5330 subinfo[i].subslotname = NULL;
5331 else
5332 subinfo[i].subslotname =
5334 subinfo[i].subsynccommit =
5336 subinfo[i].subwalrcvtimeout =
5338 subinfo[i].subpublications =
5340 subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
5342 subinfo[i].suboriginremotelsn = NULL;
5343 else
5344 subinfo[i].suboriginremotelsn =
5346
5347 /* Decide whether we want to dump it */
5348 selectDumpableObject(&(subinfo[i].dobj), fout);
5349 }
5350 PQclear(res);
5351
5352 destroyPQExpBuffer(query);
5353}
5354
5355/*
5356 * getSubscriptionRelations
5357 * Get information about subscription membership for dumpable relations. This
5358 * will be used only in binary-upgrade mode for PG17 or later versions.
5359 */
5360void
5362{
5363 DumpOptions *dopt = fout->dopt;
5364 SubscriptionInfo *subinfo = NULL;
5366 PGresult *res;
5367 int i_srsubid;
5368 int i_srrelid;
5369 int i_srsubstate;
5370 int i_srsublsn;
5371 int ntups;
5373
5374 if (dopt->no_subscriptions || !dopt->binary_upgrade ||
5375 fout->remoteVersion < 170000)
5376 return;
5377
5378 res = ExecuteSqlQuery(fout,
5379 "SELECT srsubid, srrelid, srsubstate, srsublsn "
5380 "FROM pg_catalog.pg_subscription_rel "
5381 "ORDER BY srsubid",
5383 ntups = PQntuples(res);
5384 if (ntups == 0)
5385 goto cleanup;
5386
5387 /* Get pg_subscription_rel attributes */
5388 i_srsubid = PQfnumber(res, "srsubid");
5389 i_srrelid = PQfnumber(res, "srrelid");
5390 i_srsubstate = PQfnumber(res, "srsubstate");
5391 i_srsublsn = PQfnumber(res, "srsublsn");
5392
5394 for (int i = 0; i < ntups; i++)
5395 {
5397 Oid relid = atooid(PQgetvalue(res, i, i_srrelid));
5398 TableInfo *tblinfo;
5399
5400 /*
5401 * If we switched to a new subscription, check if the subscription
5402 * exists.
5403 */
5405 {
5407 if (subinfo == NULL)
5408 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
5409
5411 }
5412
5413 tblinfo = findTableByOid(relid);
5414 if (tblinfo == NULL)
5415 pg_fatal("failed sanity check, relation with OID %u not found",
5416 relid);
5417
5418 /* OK, make a DumpableObject for this relationship */
5419 subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
5420 subrinfo[i].dobj.catId.tableoid = relid;
5421 subrinfo[i].dobj.catId.oid = cur_srsubid;
5422 AssignDumpId(&subrinfo[i].dobj);
5423 subrinfo[i].dobj.namespace = tblinfo->dobj.namespace;
5424 subrinfo[i].dobj.name = tblinfo->dobj.name;
5425 subrinfo[i].subinfo = subinfo;
5426 subrinfo[i].tblinfo = tblinfo;
5427 subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
5428 if (PQgetisnull(res, i, i_srsublsn))
5429 subrinfo[i].srsublsn = NULL;
5430 else
5431 subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
5432
5433 /* Decide whether we want to dump it */
5435 }
5436
5437cleanup:
5438 PQclear(res);
5439}
5440
5441/*
5442 * dumpSubscriptionTable
5443 * Dump the definition of the given subscription table mapping. This will be
5444 * used only in binary-upgrade mode for PG17 or later versions.
5445 */
5446static void
5448{
5449 DumpOptions *dopt = fout->dopt;
5450 SubscriptionInfo *subinfo = subrinfo->subinfo;
5451 PQExpBuffer query;
5452 char *tag;
5453
5454 /* Do nothing if not dumping schema */
5455 if (!dopt->dumpSchema)
5456 return;
5457
5458 Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
5459
5460 tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->tblinfo->dobj.name);
5461
5462 query = createPQExpBuffer();
5463
5464 if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5465 {
5466 /*
5467 * binary_upgrade_add_sub_rel_state will add the subscription relation
5468 * to pg_subscription_rel table. This will be used only in
5469 * binary-upgrade mode.
5470 */
5472 "\n-- For binary upgrade, must preserve the subscriber table.\n");
5474 "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
5475 appendStringLiteralAH(query, subinfo->dobj.name, fout);
5476 appendPQExpBuffer(query,
5477 ", %u, '%c'",
5478 subrinfo->tblinfo->dobj.catId.oid,
5479 subrinfo->srsubstate);
5480
5481 if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
5482 appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
5483 else
5484 appendPQExpBufferStr(query, ", NULL");
5485
5486 appendPQExpBufferStr(query, ");\n");
5487 }
5488
5489 /*
5490 * There is no point in creating a drop query as the drop is done by table
5491 * drop. (If you think to change this, see also _printTocEntry().)
5492 * Although this object doesn't really have ownership as such, set the
5493 * owner field anyway to ensure that the command is run by the correct
5494 * role at restore time.
5495 */
5496 if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5497 ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
5498 ARCHIVE_OPTS(.tag = tag,
5499 .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
5500 .owner = subinfo->rolname,
5501 .description = "SUBSCRIPTION TABLE",
5502 .section = SECTION_POST_DATA,
5503 .createStmt = query->data));
5504
5505 /* These objects can't currently have comments or seclabels */
5506
5507 pfree(tag);
5508 destroyPQExpBuffer(query);
5509}
5510
5511/*
5512 * dumpSubscription
5513 * dump the definition of the given subscription
5514 */
5515static void
5517{
5518 DumpOptions *dopt = fout->dopt;
5520 PQExpBuffer query;
5521 PQExpBuffer publications;
5522 char *qsubname;
5523 char **pubnames = NULL;
5524 int npubnames = 0;
5525 int i;
5526
5527 /* Do nothing if not dumping schema */
5528 if (!dopt->dumpSchema)
5529 return;
5530
5532 query = createPQExpBuffer();
5533
5534 qsubname = pg_strdup(fmtId(subinfo->dobj.name));
5535
5536 appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
5537 qsubname);
5538
5539 appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s ",
5540 qsubname);
5541 if (subinfo->subservername)
5542 {
5543 appendPQExpBuffer(query, "SERVER %s", fmtId(subinfo->subservername));
5544 }
5545 else
5546 {
5547 appendPQExpBufferStr(query, "CONNECTION ");
5548 appendStringLiteralAH(query, subinfo->subconninfo, fout);
5549 }
5550
5551 /* Build list of quoted publications and append them to query. */
5553 pg_fatal("could not parse %s array", "subpublications");
5554
5555 publications = createPQExpBuffer();
5556 for (i = 0; i < npubnames; i++)
5557 {
5558 if (i > 0)
5559 appendPQExpBufferStr(publications, ", ");
5560
5561 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
5562 }
5563
5564 appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
5565 if (subinfo->subslotname)
5566 appendStringLiteralAH(query, subinfo->subslotname, fout);
5567 else
5568 appendPQExpBufferStr(query, "NONE");
5569
5570 if (subinfo->subbinary)
5571 appendPQExpBufferStr(query, ", binary = true");
5572
5573 if (subinfo->substream == LOGICALREP_STREAM_ON)
5574 appendPQExpBufferStr(query, ", streaming = on");
5575 else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
5576 appendPQExpBufferStr(query, ", streaming = parallel");
5577 else
5578 appendPQExpBufferStr(query, ", streaming = off");
5579
5581 appendPQExpBufferStr(query, ", two_phase = on");
5582
5583 if (subinfo->subdisableonerr)
5584 appendPQExpBufferStr(query, ", disable_on_error = true");
5585
5586 if (!subinfo->subpasswordrequired)
5587 appendPQExpBufferStr(query, ", password_required = false");
5588
5589 if (subinfo->subrunasowner)
5590 appendPQExpBufferStr(query, ", run_as_owner = true");
5591
5592 if (subinfo->subfailover)
5593 appendPQExpBufferStr(query, ", failover = true");
5594
5595 if (subinfo->subretaindeadtuples)
5596 appendPQExpBufferStr(query, ", retain_dead_tuples = true");
5597
5598 if (subinfo->submaxretention)
5599 appendPQExpBuffer(query, ", max_retention_duration = %d", subinfo->submaxretention);
5600
5601 if (strcmp(subinfo->subsynccommit, "off") != 0)
5602 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
5603
5604 if (strcmp(subinfo->subwalrcvtimeout, "-1") != 0)
5605 appendPQExpBuffer(query, ", wal_receiver_timeout = %s", fmtId(subinfo->subwalrcvtimeout));
5606
5607 if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
5608 appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
5609
5610 appendPQExpBufferStr(query, ");\n");
5611
5612 /*
5613 * In binary-upgrade mode, we allow the replication to continue after the
5614 * upgrade.
5615 */
5616 if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5617 {
5618 if (subinfo->suboriginremotelsn)
5619 {
5620 /*
5621 * Preserve the remote_lsn for the subscriber's replication
5622 * origin. This value is required to start the replication from
5623 * the position before the upgrade. This value will be stale if
5624 * the publisher gets upgraded before the subscriber node.
5625 * However, this shouldn't be a problem as the upgrade of the
5626 * publisher ensures that all the transactions were replicated
5627 * before upgrading it.
5628 */
5630 "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
5632 "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
5633 appendStringLiteralAH(query, subinfo->dobj.name, fout);
5634 appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
5635 }
5636
5637 if (subinfo->subenabled)
5638 {
5639 /*
5640 * Enable the subscription to allow the replication to continue
5641 * after the upgrade.
5642 */
5644 "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
5645 appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
5646 }
5647 }
5648
5649 if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5650 ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
5651 ARCHIVE_OPTS(.tag = subinfo->dobj.name,
5652 .owner = subinfo->rolname,
5653 .description = "SUBSCRIPTION",
5654 .section = SECTION_POST_DATA,
5655 .createStmt = query->data,
5656 .dropStmt = delq->data));
5657
5658 if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
5659 dumpComment(fout, "SUBSCRIPTION", qsubname,
5660 NULL, subinfo->rolname,
5661 subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5662
5663 if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
5664 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
5665 NULL, subinfo->rolname,
5666 subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5667
5668 destroyPQExpBuffer(publications);
5669 free(pubnames);
5670
5672 destroyPQExpBuffer(query);
5674}
5675
5676/*
5677 * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
5678 * the object needs.
5679 */
5680static void
5682 PQExpBuffer create,
5683 const DumpableObject *dobj,
5684 const char *catalog,
5685 const char *keyword,
5686 const char *objname)
5687{
5688 if (dobj->depends_on_ext)
5689 {
5690 char *nm;
5691 PGresult *res;
5692 PQExpBuffer query;
5693 int ntups;
5694 int i_extname;
5695 int i;
5696
5697 /* dodge fmtId() non-reentrancy */
5698 nm = pg_strdup(objname);
5699
5700 query = createPQExpBuffer();
5701 appendPQExpBuffer(query,
5702 "SELECT e.extname "
5703 "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
5704 "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
5705 "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
5706 "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
5707 catalog,
5708 dobj->catId.oid);
5709 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5710 ntups = PQntuples(res);
5711 i_extname = PQfnumber(res, "extname");
5712 for (i = 0; i < ntups; i++)
5713 {
5714 appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
5715 keyword, nm,
5716 fmtId(PQgetvalue(res, i, i_extname)));
5717 }
5718
5719 PQclear(res);
5720 destroyPQExpBuffer(query);
5721 pg_free(nm);
5722 }
5723}
5724
5725static Oid
5727{
5728 /*
5729 * If the old version didn't assign an array type, but the new version
5730 * does, we must select an unused type OID to assign. This currently only
5731 * happens for domains, when upgrading pre-v11 to v11 and up.
5732 *
5733 * Note: local state here is kind of ugly, but we must have some, since we
5734 * mustn't choose the same unused OID more than once.
5735 */
5737 PGresult *res;
5738 bool is_dup;
5739
5740 do
5741 {
5744 "SELECT EXISTS(SELECT 1 "
5745 "FROM pg_catalog.pg_type "
5746 "WHERE oid = '%u'::pg_catalog.oid);",
5749 is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
5750 PQclear(res);
5751 } while (is_dup);
5752
5754}
5755
5756static void
5760 bool force_array_type,
5762{
5764 PGresult *res;
5768 TypeInfo *tinfo;
5769
5770 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
5772 "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5773 pg_type_oid);
5774
5776 if (tinfo)
5777 pg_type_array_oid = tinfo->typarray;
5778 else
5780
5783
5785 {
5787 "\n-- For binary upgrade, must preserve pg_type array oid\n");
5789 "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5791 }
5792
5793 /*
5794 * Pre-set the multirange type oid and its own array type oid.
5795 */
5797 {
5798 if (fout->remoteVersion >= 140000)
5799 {
5801 "SELECT t.oid, t.typarray "
5802 "FROM pg_catalog.pg_type t "
5803 "JOIN pg_catalog.pg_range r "
5804 "ON t.oid = r.rngmultitypid "
5805 "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
5806 pg_type_oid);
5807
5809
5810 pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
5811 pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
5812
5813 PQclear(res);
5814 }
5815 else
5816 {
5819 }
5820
5822 "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
5824 "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5827 "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
5829 "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5831 }
5832
5834}
5835
5836static void
5839 const TableInfo *tbinfo)
5840{
5841 Oid pg_type_oid = tbinfo->reltype;
5842
5845 pg_type_oid, false, false);
5846}
5847
5848/*
5849 * bsearch() comparator for BinaryUpgradeClassOidItem
5850 */
5851static int
5852BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
5853{
5856
5857 return pg_cmp_u32(v1.oid, v2.oid);
5858}
5859
5860/*
5861 * collectBinaryUpgradeClassOids
5862 *
5863 * Construct a table of pg_class information required for
5864 * binary_upgrade_set_pg_class_oids(). The table is sorted by OID for speed in
5865 * lookup.
5866 */
5867static void
5869{
5870 PGresult *res;
5871 const char *query;
5872
5873 query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
5874 "ct.relfilenode, i.indexrelid, cti.relfilenode "
5875 "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
5876 "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
5877 "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
5878 "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
5879 "ORDER BY c.oid;";
5880
5881 res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
5882
5886
5887 for (int i = 0; i < nbinaryUpgradeClassOids; i++)
5888 {
5896 }
5897
5898 PQclear(res);
5899}
5900
5901static void
5904{
5907
5909
5910 /*
5911 * Preserve the OID and relfilenumber of the table, table's index, table's
5912 * toast table and toast table's index if any.
5913 *
5914 * One complexity is that the current table definition might not require
5915 * the creation of a TOAST table, but the old database might have a TOAST
5916 * table that was created earlier, before some wide columns were dropped.
5917 * By setting the TOAST oid we force creation of the TOAST heap and index
5918 * by the new backend, so we can copy the files during binary upgrade
5919 * without worrying about this case.
5920 */
5921 key.oid = pg_class_oid;
5925
5927 "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
5928
5929 if (entry->relkind != RELKIND_INDEX &&
5931 {
5933 "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
5934 pg_class_oid);
5935
5936 /*
5937 * Not every relation has storage. Also, in a pre-v12 database,
5938 * partitioned tables have a relfilenumber, which should not be
5939 * preserved when upgrading.
5940 */
5941 if (RelFileNumberIsValid(entry->relfilenumber) &&
5944 "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
5945 entry->relfilenumber);
5946
5947 /*
5948 * In a pre-v12 database, partitioned tables might be marked as having
5949 * toast tables, but we should ignore them if so.
5950 */
5951 if (OidIsValid(entry->toast_oid) &&
5953 {
5955 "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
5956 entry->toast_oid);
5958 "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
5959 entry->toast_relfilenumber);
5960
5961 /* every toast table has an index */
5963 "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5964 entry->toast_index_oid);
5966 "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5968 }
5969 }
5970 else
5971 {
5972 /* Preserve the OID and relfilenumber of the index */
5974 "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5975 pg_class_oid);
5977 "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5978 entry->relfilenumber);
5979 }
5980
5982}
5983
5984/*
5985 * If the DumpableObject is a member of an extension, add a suitable
5986 * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
5987 *
5988 * For somewhat historical reasons, objname should already be quoted,
5989 * but not objnamespace (if any).
5990 */
5991static void
5993 const DumpableObject *dobj,
5994 const char *objtype,
5995 const char *objname,
5996 const char *objnamespace)
5997{
5999 int i;
6000
6001 if (!dobj->ext_member)
6002 return;
6003
6004 /*
6005 * Find the parent extension. We could avoid this search if we wanted to
6006 * add a link field to DumpableObject, but the space costs of that would
6007 * be considerable. We assume that member objects could only have a
6008 * direct dependency on their own extension, not any others.
6009 */
6010 for (i = 0; i < dobj->nDeps; i++)
6011 {
6013 if (extobj && extobj->objType == DO_EXTENSION)
6014 break;
6015 extobj = NULL;
6016 }
6017 if (extobj == NULL)
6018 pg_fatal("could not find parent extension for %s %s",
6019 objtype, objname);
6020
6022 "\n-- For binary upgrade, handle extension membership the hard way\n");
6023 appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
6024 fmtId(extobj->name),
6025 objtype);
6026 if (objnamespace && *objnamespace)
6028 appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
6029}
6030
6031/*
6032 * getNamespaces:
6033 * get information about all namespaces in the system catalogs
6034 */
6035void
6037{
6038 PGresult *res;
6039 int ntups;
6040 int i;
6041 PQExpBuffer query;
6043 int i_tableoid;
6044 int i_oid;
6045 int i_nspname;
6046 int i_nspowner;
6047 int i_nspacl;
6048 int i_acldefault;
6049
6050 query = createPQExpBuffer();
6051
6052 /*
6053 * we fetch all namespaces including system ones, so that every object we
6054 * read in can be linked to a containing namespace.
6055 */
6056 appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
6057 "n.nspowner, "
6058 "n.nspacl, "
6059 "acldefault('n', n.nspowner) AS acldefault "
6060 "FROM pg_namespace n");
6061
6062 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6063
6064 ntups = PQntuples(res);
6065
6067
6068 i_tableoid = PQfnumber(res, "tableoid");
6069 i_oid = PQfnumber(res, "oid");
6070 i_nspname = PQfnumber(res, "nspname");
6071 i_nspowner = PQfnumber(res, "nspowner");
6072 i_nspacl = PQfnumber(res, "nspacl");
6073 i_acldefault = PQfnumber(res, "acldefault");
6074
6075 for (i = 0; i < ntups; i++)
6076 {
6077 const char *nspowner;
6078
6079 nsinfo[i].dobj.objType = DO_NAMESPACE;
6080 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6081 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6082 AssignDumpId(&nsinfo[i].dobj);
6083 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
6084 nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
6085 nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6086 nsinfo[i].dacl.privtype = 0;
6087 nsinfo[i].dacl.initprivs = NULL;
6088 nspowner = PQgetvalue(res, i, i_nspowner);
6089 nsinfo[i].nspowner = atooid(nspowner);
6090 nsinfo[i].rolname = getRoleName(nspowner);
6091
6092 /* Decide whether to dump this namespace */
6094
6095 /* Mark whether namespace has an ACL */
6096 if (!PQgetisnull(res, i, i_nspacl))
6097 nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6098
6099 /*
6100 * We ignore any pg_init_privs.initprivs entry for the public schema
6101 * and assume a predetermined default, for several reasons. First,
6102 * dropping and recreating the schema removes its pg_init_privs entry,
6103 * but an empty destination database starts with this ACL nonetheless.
6104 * Second, we support dump/reload of public schema ownership changes.
6105 * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
6106 * initprivs continues to reflect the initial owner. Hence,
6107 * synthesize the value that nspacl will have after the restore's
6108 * ALTER SCHEMA OWNER. Third, this makes the destination database
6109 * match the source's ACL, even if the latter was an initdb-default
6110 * ACL, which changed in v15. An upgrade pulls in changes to most
6111 * system object ACLs that the DBA had not customized. We've made the
6112 * public schema depart from that, because changing its ACL so easily
6113 * breaks applications.
6114 */
6115 if (strcmp(nsinfo[i].dobj.name, "public") == 0)
6116 {
6119
6120 /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
6131
6132 nsinfo[i].dacl.privtype = 'i';
6133 nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
6134 nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6135
6138 }
6139 }
6140
6141 PQclear(res);
6142 destroyPQExpBuffer(query);
6143}
6144
6145/*
6146 * findNamespace:
6147 * given a namespace OID, look up the info read by getNamespaces
6148 */
6149static NamespaceInfo *
6151{
6153
6155 if (nsinfo == NULL)
6156 pg_fatal("schema with OID %u does not exist", nsoid);
6157 return nsinfo;
6158}
6159
6160/*
6161 * getExtensions:
6162 * read all extensions in the system catalogs and return them in the
6163 * ExtensionInfo* structure
6164 *
6165 * numExtensions is set to the number of extensions read in
6166 */
6169{
6170 DumpOptions *dopt = fout->dopt;
6171 PGresult *res;
6172 int ntups;
6173 int i;
6174 PQExpBuffer query;
6176 int i_tableoid;
6177 int i_oid;
6178 int i_extname;
6179 int i_nspname;
6180 int i_extrelocatable;
6181 int i_extversion;
6182 int i_extconfig;
6183 int i_extcondition;
6184
6185 query = createPQExpBuffer();
6186
6187 appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
6188 "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
6189 "FROM pg_extension x "
6190 "JOIN pg_namespace n ON n.oid = x.extnamespace");
6191
6192 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6193
6194 ntups = PQntuples(res);
6195 if (ntups == 0)
6196 goto cleanup;
6197
6199
6200 i_tableoid = PQfnumber(res, "tableoid");
6201 i_oid = PQfnumber(res, "oid");
6202 i_extname = PQfnumber(res, "extname");
6203 i_nspname = PQfnumber(res, "nspname");
6204 i_extrelocatable = PQfnumber(res, "extrelocatable");
6205 i_extversion = PQfnumber(res, "extversion");
6206 i_extconfig = PQfnumber(res, "extconfig");
6207 i_extcondition = PQfnumber(res, "extcondition");
6208
6209 for (i = 0; i < ntups; i++)
6210 {
6211 extinfo[i].dobj.objType = DO_EXTENSION;
6212 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6213 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6214 AssignDumpId(&extinfo[i].dobj);
6215 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
6216 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
6217 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
6218 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
6219 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
6220 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
6221
6222 /* Decide whether we want to dump it */
6224 }
6225
6226cleanup:
6227 PQclear(res);
6228 destroyPQExpBuffer(query);
6229
6230 *numExtensions = ntups;
6231
6232 return extinfo;
6233}
6234
6235/*
6236 * getTypes:
6237 * get information about all types in the system catalogs
6238 *
6239 * NB: this must run after getFuncs() because we assume we can do
6240 * findFuncByOid().
6241 */
6242void
6244{
6245 PGresult *res;
6246 int ntups;
6247 int i;
6251 int i_tableoid;
6252 int i_oid;
6253 int i_typname;
6254 int i_typnamespace;
6255 int i_typacl;
6256 int i_acldefault;
6257 int i_typowner;
6258 int i_typelem;
6259 int i_typrelid;
6260 int i_typrelkind;
6261 int i_typtype;
6262 int i_typisdefined;
6263 int i_isarray;
6264 int i_typarray;
6265
6266 /*
6267 * we include even the built-in types because those may be used as array
6268 * elements by user-defined types
6269 *
6270 * we filter out the built-in types when we dump out the types
6271 *
6272 * same approach for undefined (shell) types and array types
6273 *
6274 * Note: as of 8.3 we can reliably detect whether a type is an
6275 * auto-generated array type by checking the element type's typarray.
6276 * (Before that the test is capable of generating false positives.) We
6277 * still check for name beginning with '_', though, so as to avoid the
6278 * cost of the subselect probe for all standard types. This would have to
6279 * be revisited if the backend ever allows renaming of array types.
6280 */
6281 appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
6282 "typnamespace, typacl, "
6283 "acldefault('T', typowner) AS acldefault, "
6284 "typowner, "
6285 "typelem, typrelid, typarray, "
6286 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
6287 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
6288 "typtype, typisdefined, "
6289 "typname[0] = '_' AND typelem != 0 AND "
6290 "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
6291 "FROM pg_type");
6292
6293 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6294
6295 ntups = PQntuples(res);
6296
6298
6299 i_tableoid = PQfnumber(res, "tableoid");
6300 i_oid = PQfnumber(res, "oid");
6301 i_typname = PQfnumber(res, "typname");
6302 i_typnamespace = PQfnumber(res, "typnamespace");
6303 i_typacl = PQfnumber(res, "typacl");
6304 i_acldefault = PQfnumber(res, "acldefault");
6305 i_typowner = PQfnumber(res, "typowner");
6306 i_typelem = PQfnumber(res, "typelem");
6307 i_typrelid = PQfnumber(res, "typrelid");
6308 i_typrelkind = PQfnumber(res, "typrelkind");
6309 i_typtype = PQfnumber(res, "typtype");
6310 i_typisdefined = PQfnumber(res, "typisdefined");
6311 i_isarray = PQfnumber(res, "isarray");
6312 i_typarray = PQfnumber(res, "typarray");
6313
6314 for (i = 0; i < ntups; i++)
6315 {
6316 tyinfo[i].dobj.objType = DO_TYPE;
6317 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6318 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6319 AssignDumpId(&tyinfo[i].dobj);
6320 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
6321 tyinfo[i].dobj.namespace =
6323 tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
6324 tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6325 tyinfo[i].dacl.privtype = 0;
6326 tyinfo[i].dacl.initprivs = NULL;
6327 tyinfo[i].ftypname = NULL; /* may get filled later */
6328 tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
6329 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
6330 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
6331 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
6332 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
6333 tyinfo[i].shellType = NULL;
6334
6335 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
6336 tyinfo[i].isDefined = true;
6337 else
6338 tyinfo[i].isDefined = false;
6339
6340 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
6341 tyinfo[i].isArray = true;
6342 else
6343 tyinfo[i].isArray = false;
6344
6345 tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
6346
6347 if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
6348 tyinfo[i].isMultirange = true;
6349 else
6350 tyinfo[i].isMultirange = false;
6351
6352 /* Decide whether we want to dump it */
6354
6355 /* Mark whether type has an ACL */
6356 if (!PQgetisnull(res, i, i_typacl))
6357 tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6358
6359 /*
6360 * If it's a domain, fetch info about its constraints, if any
6361 */
6362 tyinfo[i].nDomChecks = 0;
6363 tyinfo[i].domChecks = NULL;
6364 tyinfo[i].notnull = NULL;
6365 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6366 tyinfo[i].typtype == TYPTYPE_DOMAIN)
6368
6369 /*
6370 * If it's a base type, make a DumpableObject representing a shell
6371 * definition of the type. We will need to dump that ahead of the I/O
6372 * functions for the type. Similarly, range types need a shell
6373 * definition in case they have a canonicalize function.
6374 *
6375 * Note: the shell type doesn't have a catId. You might think it
6376 * should copy the base type's catId, but then it might capture the
6377 * pg_depend entries for the type, which we don't want.
6378 */
6379 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6380 (tyinfo[i].typtype == TYPTYPE_BASE ||
6381 tyinfo[i].typtype == TYPTYPE_RANGE))
6382 {
6384 stinfo->dobj.objType = DO_SHELL_TYPE;
6385 stinfo->dobj.catId = nilCatalogId;
6386 AssignDumpId(&stinfo->dobj);
6387 stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
6388 stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
6389 stinfo->baseType = &(tyinfo[i]);
6390 tyinfo[i].shellType = stinfo;
6391
6392 /*
6393 * Initially mark the shell type as not to be dumped. We'll only
6394 * dump it if the I/O or canonicalize functions need to be dumped;
6395 * this is taken care of while sorting dependencies.
6396 */
6397 stinfo->dobj.dump = DUMP_COMPONENT_NONE;
6398 }
6399 }
6400
6401 PQclear(res);
6402
6403 destroyPQExpBuffer(query);
6404}
6405
6406/*
6407 * getOperators:
6408 * get information about all operators in the system catalogs
6409 */
6410void
6412{
6413 PGresult *res;
6414 int ntups;
6415 int i;
6418 int i_tableoid;
6419 int i_oid;
6420 int i_oprname;
6421 int i_oprnamespace;
6422 int i_oprowner;
6423 int i_oprkind;
6424 int i_oprleft;
6425 int i_oprright;
6426 int i_oprcode;
6427
6428 /*
6429 * find all operators, including builtin operators; we filter out
6430 * system-defined operators at dump-out time.
6431 */
6432
6433 appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
6434 "oprnamespace, "
6435 "oprowner, "
6436 "oprkind, "
6437 "oprleft, "
6438 "oprright, "
6439 "oprcode::oid AS oprcode "
6440 "FROM pg_operator");
6441
6442 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6443
6444 ntups = PQntuples(res);
6445
6447
6448 i_tableoid = PQfnumber(res, "tableoid");
6449 i_oid = PQfnumber(res, "oid");
6450 i_oprname = PQfnumber(res, "oprname");
6451 i_oprnamespace = PQfnumber(res, "oprnamespace");
6452 i_oprowner = PQfnumber(res, "oprowner");
6453 i_oprkind = PQfnumber(res, "oprkind");
6454 i_oprleft = PQfnumber(res, "oprleft");
6455 i_oprright = PQfnumber(res, "oprright");
6456 i_oprcode = PQfnumber(res, "oprcode");
6457
6458 for (i = 0; i < ntups; i++)
6459 {
6460 oprinfo[i].dobj.objType = DO_OPERATOR;
6461 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6462 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6463 AssignDumpId(&oprinfo[i].dobj);
6464 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
6465 oprinfo[i].dobj.namespace =
6467 oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
6468 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
6469 oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
6470 oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
6471 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
6472
6473 /* Decide whether we want to dump it */
6475 }
6476
6477 PQclear(res);
6478
6479 destroyPQExpBuffer(query);
6480}
6481
6482/*
6483 * getCollations:
6484 * get information about all collations in the system catalogs
6485 */
6486void
6488{
6489 PGresult *res;
6490 int ntups;
6491 int i;
6492 PQExpBuffer query;
6494 int i_tableoid;
6495 int i_oid;
6496 int i_collname;
6497 int i_collnamespace;
6498 int i_collowner;
6499 int i_collencoding;
6500
6501 query = createPQExpBuffer();
6502
6503 /*
6504 * find all collations, including builtin collations; we filter out
6505 * system-defined collations at dump-out time.
6506 */
6507
6508 appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
6509 "collnamespace, "
6510 "collowner, "
6511 "collencoding "
6512 "FROM pg_collation");
6513
6514 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6515
6516 ntups = PQntuples(res);
6517
6519
6520 i_tableoid = PQfnumber(res, "tableoid");
6521 i_oid = PQfnumber(res, "oid");
6522 i_collname = PQfnumber(res, "collname");
6523 i_collnamespace = PQfnumber(res, "collnamespace");
6524 i_collowner = PQfnumber(res, "collowner");
6525 i_collencoding = PQfnumber(res, "collencoding");
6526
6527 for (i = 0; i < ntups; i++)
6528 {
6529 collinfo[i].dobj.objType = DO_COLLATION;
6530 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6531 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6532 AssignDumpId(&collinfo[i].dobj);
6533 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
6534 collinfo[i].dobj.namespace =
6536 collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
6537 collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
6538
6539 /* Decide whether we want to dump it */
6541 }
6542
6543 PQclear(res);
6544
6545 destroyPQExpBuffer(query);
6546}
6547
6548/*
6549 * getConversions:
6550 * get information about all conversions in the system catalogs
6551 */
6552void
6554{
6555 PGresult *res;
6556 int ntups;
6557 int i;
6558 PQExpBuffer query;
6560 int i_tableoid;
6561 int i_oid;
6562 int i_conname;
6563 int i_connamespace;
6564 int i_conowner;
6565
6566 query = createPQExpBuffer();
6567
6568 /*
6569 * find all conversions, including builtin conversions; we filter out
6570 * system-defined conversions at dump-out time.
6571 */
6572
6573 appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
6574 "connamespace, "
6575 "conowner "
6576 "FROM pg_conversion");
6577
6578 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6579
6580 ntups = PQntuples(res);
6581
6583
6584 i_tableoid = PQfnumber(res, "tableoid");
6585 i_oid = PQfnumber(res, "oid");
6586 i_conname = PQfnumber(res, "conname");
6587 i_connamespace = PQfnumber(res, "connamespace");
6588 i_conowner = PQfnumber(res, "conowner");
6589
6590 for (i = 0; i < ntups; i++)
6591 {
6592 convinfo[i].dobj.objType = DO_CONVERSION;
6593 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6594 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6595 AssignDumpId(&convinfo[i].dobj);
6596 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
6597 convinfo[i].dobj.namespace =
6599 convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
6600
6601 /* Decide whether we want to dump it */
6603 }
6604
6605 PQclear(res);
6606
6607 destroyPQExpBuffer(query);
6608}
6609
6610/*
6611 * getAccessMethods:
6612 * get information about all user-defined access methods
6613 */
6614void
6616{
6617 PGresult *res;
6618 int ntups;
6619 int i;
6620 PQExpBuffer query;
6622 int i_tableoid;
6623 int i_oid;
6624 int i_amname;
6625 int i_amhandler;
6626 int i_amtype;
6627
6628 query = createPQExpBuffer();
6629
6630 /*
6631 * Select all access methods from pg_am table.
6632 */
6633 appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
6635 "amtype, "
6636 "amhandler::pg_catalog.regproc AS amhandler ");
6637 appendPQExpBufferStr(query, "FROM pg_am");
6638
6639 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6640
6641 ntups = PQntuples(res);
6642
6644
6645 i_tableoid = PQfnumber(res, "tableoid");
6646 i_oid = PQfnumber(res, "oid");
6647 i_amname = PQfnumber(res, "amname");
6648 i_amhandler = PQfnumber(res, "amhandler");
6649 i_amtype = PQfnumber(res, "amtype");
6650
6651 for (i = 0; i < ntups; i++)
6652 {
6653 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
6654 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6655 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6656 AssignDumpId(&aminfo[i].dobj);
6657 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
6658 aminfo[i].dobj.namespace = NULL;
6659 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
6660 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
6661
6662 /* Decide whether we want to dump it */
6664 }
6665
6666 PQclear(res);
6667
6668 destroyPQExpBuffer(query);
6669}
6670
6671
6672/*
6673 * getOpclasses:
6674 * get information about all opclasses in the system catalogs
6675 */
6676void
6678{
6679 PGresult *res;
6680 int ntups;
6681 int i;
6684 int i_tableoid;
6685 int i_oid;
6686 int i_opcmethod;
6687 int i_opcname;
6688 int i_opcnamespace;
6689 int i_opcowner;
6690
6691 /*
6692 * find all opclasses, including builtin opclasses; we filter out
6693 * system-defined opclasses at dump-out time.
6694 */
6695
6696 appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
6697 "opcnamespace, "
6698 "opcowner "
6699 "FROM pg_opclass");
6700
6701 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6702
6703 ntups = PQntuples(res);
6704
6706
6707 i_tableoid = PQfnumber(res, "tableoid");
6708 i_oid = PQfnumber(res, "oid");
6709 i_opcmethod = PQfnumber(res, "opcmethod");
6710 i_opcname = PQfnumber(res, "opcname");
6711 i_opcnamespace = PQfnumber(res, "opcnamespace");
6712 i_opcowner = PQfnumber(res, "opcowner");
6713
6714 for (i = 0; i < ntups; i++)
6715 {
6716 opcinfo[i].dobj.objType = DO_OPCLASS;
6717 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6718 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6719 AssignDumpId(&opcinfo[i].dobj);
6720 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
6721 opcinfo[i].dobj.namespace =
6723 opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
6724 opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
6725
6726 /* Decide whether we want to dump it */
6728 }
6729
6730 PQclear(res);
6731
6732 destroyPQExpBuffer(query);
6733}
6734
6735/*
6736 * getOpfamilies:
6737 * get information about all opfamilies in the system catalogs
6738 */
6739void
6741{
6742 PGresult *res;
6743 int ntups;
6744 int i;
6745 PQExpBuffer query;
6747 int i_tableoid;
6748 int i_oid;
6749 int i_opfmethod;
6750 int i_opfname;
6751 int i_opfnamespace;
6752 int i_opfowner;
6753
6754 query = createPQExpBuffer();
6755
6756 /*
6757 * find all opfamilies, including builtin opfamilies; we filter out
6758 * system-defined opfamilies at dump-out time.
6759 */
6760
6761 appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
6762 "opfnamespace, "
6763 "opfowner "
6764 "FROM pg_opfamily");
6765
6766 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6767
6768 ntups = PQntuples(res);
6769
6771
6772 i_tableoid = PQfnumber(res, "tableoid");
6773 i_oid = PQfnumber(res, "oid");
6774 i_opfname = PQfnumber(res, "opfname");
6775 i_opfmethod = PQfnumber(res, "opfmethod");
6776 i_opfnamespace = PQfnumber(res, "opfnamespace");
6777 i_opfowner = PQfnumber(res, "opfowner");
6778
6779 for (i = 0; i < ntups; i++)
6780 {
6781 opfinfo[i].dobj.objType = DO_OPFAMILY;
6782 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6783 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6784 AssignDumpId(&opfinfo[i].dobj);
6785 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
6786 opfinfo[i].dobj.namespace =
6788 opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
6789 opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
6790
6791 /* Decide whether we want to dump it */
6793 }
6794
6795 PQclear(res);
6796
6797 destroyPQExpBuffer(query);
6798}
6799
6800/*
6801 * getAggregates:
6802 * get information about all user-defined aggregates in the system catalogs
6803 */
6804void
6806{
6807 DumpOptions *dopt = fout->dopt;
6808 PGresult *res;
6809 int ntups;
6810 int i;
6813 int i_tableoid;
6814 int i_oid;
6815 int i_aggname;
6816 int i_aggnamespace;
6817 int i_pronargs;
6818 int i_proargtypes;
6819 int i_proowner;
6820 int i_aggacl;
6821 int i_acldefault;
6822 const char *agg_check;
6823
6824 /*
6825 * Find all interesting aggregates. See comment in getFuncs() for the
6826 * rationale behind the filtering logic.
6827 */
6828 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
6829 : "p.proisagg");
6830
6831 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
6832 "p.proname AS aggname, "
6833 "p.pronamespace AS aggnamespace, "
6834 "p.pronargs, p.proargtypes, "
6835 "p.proowner, "
6836 "p.proacl AS aggacl, "
6837 "acldefault('f', p.proowner) AS acldefault "
6838 "FROM pg_proc p "
6839 "LEFT JOIN pg_init_privs pip ON "
6840 "(p.oid = pip.objoid "
6841 "AND pip.classoid = 'pg_proc'::regclass "
6842 "AND pip.objsubid = 0) "
6843 "WHERE %s AND ("
6844 "p.pronamespace != "
6845 "(SELECT oid FROM pg_namespace "
6846 "WHERE nspname = 'pg_catalog') OR "
6847 "p.proacl IS DISTINCT FROM pip.initprivs",
6848 agg_check);
6849 if (dopt->binary_upgrade)
6851 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6852 "classid = 'pg_proc'::regclass AND "
6853 "objid = p.oid AND "
6854 "refclassid = 'pg_extension'::regclass AND "
6855 "deptype = 'e')");
6856 appendPQExpBufferChar(query, ')');
6857
6858 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6859
6860 ntups = PQntuples(res);
6861
6863
6864 i_tableoid = PQfnumber(res, "tableoid");
6865 i_oid = PQfnumber(res, "oid");
6866 i_aggname = PQfnumber(res, "aggname");
6867 i_aggnamespace = PQfnumber(res, "aggnamespace");
6868 i_pronargs = PQfnumber(res, "pronargs");
6869 i_proargtypes = PQfnumber(res, "proargtypes");
6870 i_proowner = PQfnumber(res, "proowner");
6871 i_aggacl = PQfnumber(res, "aggacl");
6872 i_acldefault = PQfnumber(res, "acldefault");
6873
6874 for (i = 0; i < ntups; i++)
6875 {
6876 agginfo[i].aggfn.dobj.objType = DO_AGG;
6877 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6878 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6879 AssignDumpId(&agginfo[i].aggfn.dobj);
6880 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
6881 agginfo[i].aggfn.dobj.namespace =
6883 agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
6884 agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6885 agginfo[i].aggfn.dacl.privtype = 0;
6886 agginfo[i].aggfn.dacl.initprivs = NULL;
6887 agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
6888 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
6889 agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
6890 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
6891 if (agginfo[i].aggfn.nargs == 0)
6892 agginfo[i].aggfn.argtypes = NULL;
6893 else
6894 {
6895 agginfo[i].aggfn.argtypes = pg_malloc_array(Oid, agginfo[i].aggfn.nargs);
6897 agginfo[i].aggfn.argtypes,
6898 agginfo[i].aggfn.nargs);
6899 }
6900 agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
6901
6902 /* Decide whether we want to dump it */
6903 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
6904
6905 /* Mark whether aggregate has an ACL */
6906 if (!PQgetisnull(res, i, i_aggacl))
6907 agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
6908 }
6909
6910 PQclear(res);
6911
6912 destroyPQExpBuffer(query);
6913}
6914
6915/*
6916 * getFuncs:
6917 * get information about all user-defined functions in the system catalogs
6918 */
6919void
6921{
6922 DumpOptions *dopt = fout->dopt;
6923 PGresult *res;
6924 int ntups;
6925 int i;
6927 FuncInfo *finfo;
6928 int i_tableoid;
6929 int i_oid;
6930 int i_proname;
6931 int i_pronamespace;
6932 int i_proowner;
6933 int i_prolang;
6934 int i_pronargs;
6935 int i_proargtypes;
6936 int i_prorettype;
6937 int i_proacl;
6938 int i_acldefault;
6939 const char *not_agg_check;
6940
6941 /*
6942 * Find all interesting functions. This is a bit complicated:
6943 *
6944 * 1. Always exclude aggregates; those are handled elsewhere.
6945 *
6946 * 2. Always exclude functions that are internally dependent on something
6947 * else, since presumably those will be created as a result of creating
6948 * the something else. This currently acts only to suppress constructor
6949 * functions for range types. Note this is OK only because the
6950 * constructors don't have any dependencies the range type doesn't have;
6951 * otherwise we might not get creation ordering correct.
6952 *
6953 * 3. Otherwise, we normally exclude functions in pg_catalog. However, if
6954 * they're members of extensions and we are in binary-upgrade mode then
6955 * include them, since we want to dump extension members individually in
6956 * that mode. Also, if they are used by casts or transforms then we need
6957 * to gather the information about them, though they won't be dumped if
6958 * they are built-in. Also, include functions in pg_catalog if they have
6959 * an ACL different from what's shown in pg_init_privs (so we have to join
6960 * to pg_init_privs; annoying).
6961 */
6962 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
6963 : "NOT p.proisagg");
6964
6965 appendPQExpBuffer(query,
6966 "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
6967 "p.pronargs, p.proargtypes, p.prorettype, "
6968 "p.proacl, "
6969 "acldefault('f', p.proowner) AS acldefault, "
6970 "p.pronamespace, "
6971 "p.proowner "
6972 "FROM pg_proc p "
6973 "LEFT JOIN pg_init_privs pip ON "
6974 "(p.oid = pip.objoid "
6975 "AND pip.classoid = 'pg_proc'::regclass "
6976 "AND pip.objsubid = 0) "
6977 "WHERE %s"
6978 "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6979 "WHERE classid = 'pg_proc'::regclass AND "
6980 "objid = p.oid AND deptype = 'i')"
6981 "\n AND ("
6982 "\n pronamespace != "
6983 "(SELECT oid FROM pg_namespace "
6984 "WHERE nspname = 'pg_catalog')"
6985 "\n OR EXISTS (SELECT 1 FROM pg_cast"
6986 "\n WHERE pg_cast.oid > %u "
6987 "\n AND p.oid = pg_cast.castfunc)"
6988 "\n OR EXISTS (SELECT 1 FROM pg_transform"
6989 "\n WHERE pg_transform.oid > %u AND "
6990 "\n (p.oid = pg_transform.trffromsql"
6991 "\n OR p.oid = pg_transform.trftosql))",
6995 if (dopt->binary_upgrade)
6997 "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6998 "classid = 'pg_proc'::regclass AND "
6999 "objid = p.oid AND "
7000 "refclassid = 'pg_extension'::regclass AND "
7001 "deptype = 'e')");
7003 "\n OR p.proacl IS DISTINCT FROM pip.initprivs");
7004 appendPQExpBufferChar(query, ')');
7005
7006 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7007
7008 ntups = PQntuples(res);
7009
7010 finfo = pg_malloc0_array(FuncInfo, ntups);
7011
7012 i_tableoid = PQfnumber(res, "tableoid");
7013 i_oid = PQfnumber(res, "oid");
7014 i_proname = PQfnumber(res, "proname");
7015 i_pronamespace = PQfnumber(res, "pronamespace");
7016 i_proowner = PQfnumber(res, "proowner");
7017 i_prolang = PQfnumber(res, "prolang");
7018 i_pronargs = PQfnumber(res, "pronargs");
7019 i_proargtypes = PQfnumber(res, "proargtypes");
7020 i_prorettype = PQfnumber(res, "prorettype");
7021 i_proacl = PQfnumber(res, "proacl");
7022 i_acldefault = PQfnumber(res, "acldefault");
7023
7024 for (i = 0; i < ntups; i++)
7025 {
7026 finfo[i].dobj.objType = DO_FUNC;
7027 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7028 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7029 AssignDumpId(&finfo[i].dobj);
7030 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
7031 finfo[i].dobj.namespace =
7033 finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
7035 finfo[i].dacl.privtype = 0;
7036 finfo[i].dacl.initprivs = NULL;
7037 finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
7038 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
7039 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
7040 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
7041 if (finfo[i].nargs == 0)
7042 finfo[i].argtypes = NULL;
7043 else
7044 {
7045 finfo[i].argtypes = pg_malloc_array(Oid, finfo[i].nargs);
7047 finfo[i].argtypes, finfo[i].nargs);
7048 }
7049 finfo[i].postponed_def = false; /* might get set during sort */
7050
7051 /* Decide whether we want to dump it */
7052 selectDumpableObject(&(finfo[i].dobj), fout);
7053
7054 /* Mark whether function has an ACL */
7055 if (!PQgetisnull(res, i, i_proacl))
7057 }
7058
7059 PQclear(res);
7060
7061 destroyPQExpBuffer(query);
7062}
7063
7064/*
7065 * getRelationStatistics
7066 * register the statistics object as a dependent of the relation.
7067 *
7068 * reltuples is passed as a string to avoid complexities in converting from/to
7069 * floating point.
7070 */
7071static RelStatsInfo *
7073 char *reltuples, int32 relallvisible,
7074 int32 relallfrozen, char relkind,
7075 char **indAttNames, int nindAttNames)
7076{
7077 if (!fout->dopt->dumpStatistics)
7078 return NULL;
7079
7080 if ((relkind == RELKIND_RELATION) ||
7081 (relkind == RELKIND_PARTITIONED_TABLE) ||
7082 (relkind == RELKIND_INDEX) ||
7083 (relkind == RELKIND_PARTITIONED_INDEX) ||
7084 (relkind == RELKIND_MATVIEW ||
7085 relkind == RELKIND_FOREIGN_TABLE))
7086 {
7088 DumpableObject *dobj = &info->dobj;
7089
7090 dobj->objType = DO_REL_STATS;
7091 dobj->catId.tableoid = 0;
7092 dobj->catId.oid = 0;
7093 AssignDumpId(dobj);
7095 dobj->dependencies[0] = rel->dumpId;
7096 dobj->nDeps = 1;
7097 dobj->allocDeps = 1;
7099 dobj->name = pg_strdup(rel->name);
7100 dobj->namespace = rel->namespace;
7101 info->relid = rel->catId.oid;
7102 info->relpages = relpages;
7103 info->reltuples = pstrdup(reltuples);
7104 info->relallvisible = relallvisible;
7105 info->relallfrozen = relallfrozen;
7106 info->relkind = relkind;
7107 info->indAttNames = indAttNames;
7108 info->nindAttNames = nindAttNames;
7109
7110 /*
7111 * Ordinarily, stats go in SECTION_DATA for tables and
7112 * SECTION_POST_DATA for indexes.
7113 *
7114 * However, the section may be updated later for materialized view
7115 * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
7116 * the stats, so the stats must be restored after the data. Also, the
7117 * materialized view definition may be postponed to SECTION_POST_DATA
7118 * (see repairMatViewBoundaryMultiLoop()).
7119 */
7120 switch (info->relkind)
7121 {
7122 case RELKIND_RELATION:
7124 case RELKIND_MATVIEW:
7126 info->section = SECTION_DATA;
7127 break;
7128 case RELKIND_INDEX:
7130 info->section = SECTION_POST_DATA;
7131 break;
7132 default:
7133 pg_fatal("cannot dump statistics for relation kind \"%c\"",
7134 info->relkind);
7135 }
7136
7137 return info;
7138 }
7139 return NULL;
7140}
7141
7142/*
7143 * getTables
7144 * read all the tables (no indexes) in the system catalogs,
7145 * and return them as an array of TableInfo structures
7146 *
7147 * *numTables is set to the number of tables read in
7148 */
7149TableInfo *
7151{
7152 DumpOptions *dopt = fout->dopt;
7153 PGresult *res;
7154 int ntups;
7155 int i;
7157 TableInfo *tblinfo;
7158 int i_reltableoid;
7159 int i_reloid;
7160 int i_relname;
7161 int i_relnamespace;
7162 int i_relkind;
7163 int i_reltype;
7164 int i_relowner;
7165 int i_relchecks;
7166 int i_relhasindex;
7167 int i_relhasrules;
7168 int i_relpages;
7169 int i_reltuples;
7170 int i_relallvisible;
7171 int i_relallfrozen;
7172 int i_toastpages;
7173 int i_owning_tab;
7174 int i_owning_col;
7175 int i_reltablespace;
7176 int i_relhasoids;
7177 int i_relhastriggers;
7178 int i_relpersistence;
7179 int i_relispopulated;
7180 int i_relreplident;
7181 int i_relrowsec;
7182 int i_relforcerowsec;
7183 int i_relfrozenxid;
7184 int i_toastfrozenxid;
7185 int i_toastoid;
7186 int i_relminmxid;
7187 int i_toastminmxid;
7188 int i_reloptions;
7189 int i_checkoption;
7191 int i_reloftype;
7192 int i_foreignserver;
7193 int i_amname;
7195 int i_relacl;
7196 int i_acldefault;
7197 int i_ispartition;
7198
7199 /*
7200 * Find all the tables and table-like objects.
7201 *
7202 * We must fetch all tables in this phase because otherwise we cannot
7203 * correctly identify inherited columns, owned sequences, etc.
7204 *
7205 * We include system catalogs, so that we can work if a user table is
7206 * defined to inherit from a system catalog (pretty weird, but...)
7207 *
7208 * Note: in this phase we should collect only a minimal amount of
7209 * information about each table, basically just enough to decide if it is
7210 * interesting. In particular, since we do not yet have lock on any user
7211 * table, we MUST NOT invoke any server-side data collection functions
7212 * (for instance, pg_get_partkeydef()). Those are likely to fail or give
7213 * wrong answers if any concurrent DDL is happening.
7214 */
7215
7217 "SELECT c.tableoid, c.oid, c.relname, "
7218 "c.relnamespace, c.relkind, c.reltype, "
7219 "c.relowner, "
7220 "c.relchecks, "
7221 "c.relhasindex, c.relhasrules, c.relpages, "
7222 "c.reltuples, c.relallvisible, ");
7223
7224 if (fout->remoteVersion >= 180000)
7225 appendPQExpBufferStr(query, "c.relallfrozen, ");
7226 else
7227 appendPQExpBufferStr(query, "0 AS relallfrozen, ");
7228
7230 "c.relhastriggers, c.relpersistence, "
7231 "c.reloftype, "
7232 "c.relacl, "
7233 "acldefault(CASE"
7234 " WHEN c.relkind = " CppAsString2(RELKIND_PROPGRAPH));
7235 /* 19beta1 didn't support acldefault('g'), so we'll fix that below */
7237 fout->remoteVersion >= 200000 ?
7238 " THEN 'g'::\"char\"" :
7239 " THEN NULL");
7241 " WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
7242 " THEN 's'::\"char\""
7243 " ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
7244 "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
7245 "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
7246 "ELSE 0 END AS foreignserver, "
7247 "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
7248 "tc.oid AS toid, "
7249 "tc.relpages AS toastpages, "
7250 "tc.reloptions AS toast_reloptions, "
7251 "d.refobjid AS owning_tab, "
7252 "d.refobjsubid AS owning_col, "
7253 "tsp.spcname AS reltablespace, ");
7254
7255 if (fout->remoteVersion >= 120000)
7257 "false AS relhasoids, ");
7258 else
7260 "c.relhasoids, ");
7261
7263 "c.relispopulated, ");
7264
7266 "c.relreplident, ");
7267
7269 "c.relrowsecurity, c.relforcerowsecurity, ");
7270
7272 "c.relminmxid, tc.relminmxid AS tminmxid, ");
7273
7275 "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
7276 "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
7277 "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
7278
7280 "am.amname, ");
7281
7283 "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
7284
7286 "c.relispartition AS ispartition ");
7287
7288 /*
7289 * Left join to pg_depend to pick up dependency info linking sequences to
7290 * their owning column, if any (note this dependency is AUTO except for
7291 * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
7292 * collect the spcname.
7293 */
7295 "\nFROM pg_class c\n"
7296 "LEFT JOIN pg_depend d ON "
7297 "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
7298 "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
7299 "d.objsubid = 0 AND "
7300 "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
7301 "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
7302
7303 /*
7304 * Left join to pg_am to pick up the amname.
7305 */
7307 "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
7308
7309 /*
7310 * We purposefully ignore toast OIDs for partitioned tables; the reason is
7311 * that versions 10 and 11 have them, but later versions do not, so
7312 * emitting them causes the upgrade to fail.
7313 */
7315 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
7316 " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
7317 " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
7318
7319 /*
7320 * Restrict to interesting relkinds (in particular, not indexes). Not all
7321 * relkinds are possible in older servers, but it's not worth the trouble
7322 * to emit a version-dependent list.
7323 *
7324 * Composite-type table entries won't be dumped as such, but we have to
7325 * make a DumpableObject for them so that we can track dependencies of the
7326 * composite type (pg_depend entries for columns of the composite type
7327 * link to the pg_class entry not the pg_type entry).
7328 */
7330 "WHERE c.relkind IN ("
7339 "ORDER BY c.oid");
7340
7341 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7342
7343 ntups = PQntuples(res);
7344
7345 *numTables = ntups;
7346
7347 /*
7348 * Extract data from result and lock dumpable tables. We do the locking
7349 * before anything else, to minimize the window wherein a table could
7350 * disappear under us.
7351 *
7352 * Note that we have to save info about all tables here, even when dumping
7353 * only one, because we don't yet know which tables might be inheritance
7354 * ancestors of the target table.
7355 */
7356 tblinfo = pg_malloc0_array(TableInfo, ntups);
7357
7358 i_reltableoid = PQfnumber(res, "tableoid");
7359 i_reloid = PQfnumber(res, "oid");
7360 i_relname = PQfnumber(res, "relname");
7361 i_relnamespace = PQfnumber(res, "relnamespace");
7362 i_relkind = PQfnumber(res, "relkind");
7363 i_reltype = PQfnumber(res, "reltype");
7364 i_relowner = PQfnumber(res, "relowner");
7365 i_relchecks = PQfnumber(res, "relchecks");
7366 i_relhasindex = PQfnumber(res, "relhasindex");
7367 i_relhasrules = PQfnumber(res, "relhasrules");
7368 i_relpages = PQfnumber(res, "relpages");
7369 i_reltuples = PQfnumber(res, "reltuples");
7370 i_relallvisible = PQfnumber(res, "relallvisible");
7371 i_relallfrozen = PQfnumber(res, "relallfrozen");
7372 i_toastpages = PQfnumber(res, "toastpages");
7373 i_owning_tab = PQfnumber(res, "owning_tab");
7374 i_owning_col = PQfnumber(res, "owning_col");
7375 i_reltablespace = PQfnumber(res, "reltablespace");
7376 i_relhasoids = PQfnumber(res, "relhasoids");
7377 i_relhastriggers = PQfnumber(res, "relhastriggers");
7378 i_relpersistence = PQfnumber(res, "relpersistence");
7379 i_relispopulated = PQfnumber(res, "relispopulated");
7380 i_relreplident = PQfnumber(res, "relreplident");
7381 i_relrowsec = PQfnumber(res, "relrowsecurity");
7382 i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
7383 i_relfrozenxid = PQfnumber(res, "relfrozenxid");
7384 i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
7385 i_toastoid = PQfnumber(res, "toid");
7386 i_relminmxid = PQfnumber(res, "relminmxid");
7387 i_toastminmxid = PQfnumber(res, "tminmxid");
7388 i_reloptions = PQfnumber(res, "reloptions");
7389 i_checkoption = PQfnumber(res, "checkoption");
7390 i_toastreloptions = PQfnumber(res, "toast_reloptions");
7391 i_reloftype = PQfnumber(res, "reloftype");
7392 i_foreignserver = PQfnumber(res, "foreignserver");
7393 i_amname = PQfnumber(res, "amname");
7394 i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
7395 i_relacl = PQfnumber(res, "relacl");
7396 i_acldefault = PQfnumber(res, "acldefault");
7397 i_ispartition = PQfnumber(res, "ispartition");
7398
7399 if (dopt->lockWaitTimeout)
7400 {
7401 /*
7402 * Arrange to fail instead of waiting forever for a table lock.
7403 *
7404 * NB: this coding assumes that the only queries issued within the
7405 * following loop are LOCK TABLEs; else the timeout may be undesirably
7406 * applied to other things too.
7407 */
7408 resetPQExpBuffer(query);
7409 appendPQExpBufferStr(query, "SET statement_timeout = ");
7411 ExecuteSqlStatement(fout, query->data);
7412 }
7413
7414 resetPQExpBuffer(query);
7415
7416 for (i = 0; i < ntups; i++)
7417 {
7418 int32 relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
7419 int32 relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
7420
7421 tblinfo[i].dobj.objType = DO_TABLE;
7422 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
7423 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
7424 AssignDumpId(&tblinfo[i].dobj);
7425 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
7426 tblinfo[i].dobj.namespace =
7428 tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
7429 /* acldefault computed below */
7430 tblinfo[i].dacl.privtype = 0;
7431 tblinfo[i].dacl.initprivs = NULL;
7432 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
7433 tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
7434 tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
7435 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
7436 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
7437 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
7438 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
7439 if (PQgetisnull(res, i, i_toastpages))
7440 tblinfo[i].toastpages = 0;
7441 else
7442 tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
7443 if (PQgetisnull(res, i, i_owning_tab))
7444 {
7445 tblinfo[i].owning_tab = InvalidOid;
7446 tblinfo[i].owning_col = 0;
7447 }
7448 else
7449 {
7450 tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
7451 tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
7452 }
7454 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
7455 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
7456 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
7457 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
7458 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
7459 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
7460 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
7461 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
7463 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
7464 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
7465 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
7466 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
7467 if (PQgetisnull(res, i, i_checkoption))
7468 tblinfo[i].checkoption = NULL;
7469 else
7470 tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
7472 tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
7474 if (PQgetisnull(res, i, i_amname))
7475 tblinfo[i].amname = NULL;
7476 else
7477 tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
7478 tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
7479 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
7480
7481 if (tblinfo[i].relkind == RELKIND_PROPGRAPH &&
7482 !(fout->remoteVersion >= 200000))
7483 {
7486
7487 /* Standard ACL as of v19 is {owner=r/owner} */
7489 quoteAclUserName(aclitem, tblinfo[i].rolname);
7491 quoteAclUserName(aclitem, tblinfo[i].rolname);
7494
7495 tblinfo[i].dacl.acldefault = pstrdup(aclarray->data);
7496
7499 }
7500 else
7501 tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
7502
7503 /* other fields were zeroed above */
7504
7505 /*
7506 * Decide whether we want to dump this table.
7507 */
7508 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
7509 tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
7510 else
7511 selectDumpableTable(&tblinfo[i], fout);
7512
7513 /*
7514 * Now, consider the table "interesting" if we need to dump its
7515 * definition, data or its statistics. Later on, we'll skip a lot of
7516 * data collection for uninteresting tables.
7517 *
7518 * Note: the "interesting" flag will also be set by flagInhTables for
7519 * parents of interesting tables, so that we collect necessary
7520 * inheritance info even when the parents are not themselves being
7521 * dumped. This is the main reason why we need an "interesting" flag
7522 * that's separate from the components-to-dump bitmask.
7523 */
7524 tblinfo[i].interesting = (tblinfo[i].dobj.dump &
7528
7529 tblinfo[i].dummy_view = false; /* might get set during sort */
7530 tblinfo[i].postponed_def = false; /* might get set during sort */
7531
7532 /* Tables have data */
7534
7535 /* Mark whether table has an ACL */
7536 if (!PQgetisnull(res, i, i_relacl))
7537 tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
7538 tblinfo[i].hascolumnACLs = false; /* may get set later */
7539
7540 /* Add statistics */
7541 if (tblinfo[i].interesting)
7542 {
7543 RelStatsInfo *stats;
7544
7545 stats = getRelationStatistics(fout, &tblinfo[i].dobj,
7546 tblinfo[i].relpages,
7547 PQgetvalue(res, i, i_reltuples),
7548 relallvisible, relallfrozen,
7549 tblinfo[i].relkind, NULL, 0);
7550 if (tblinfo[i].relkind == RELKIND_MATVIEW)
7551 tblinfo[i].stats = stats;
7552 }
7553
7554 /*
7555 * Read-lock target tables to make sure they aren't DROPPED or altered
7556 * in schema before we get around to dumping them.
7557 *
7558 * Note that we don't explicitly lock parents of the target tables; we
7559 * assume our lock on the child is enough to prevent schema
7560 * alterations to parent tables.
7561 *
7562 * NOTE: it'd be kinda nice to lock other relations too, not only
7563 * plain or partitioned tables, but the backend doesn't presently
7564 * allow that.
7565 *
7566 * We only need to lock the table for certain components; see
7567 * pg_dump.h
7568 */
7569 if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
7570 (tblinfo[i].relkind == RELKIND_RELATION ||
7571 tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
7572 {
7573 /*
7574 * Tables are locked in batches. When dumping from a remote
7575 * server this can save a significant amount of time by reducing
7576 * the number of round trips.
7577 */
7578 if (query->len == 0)
7579 appendPQExpBuffer(query, "LOCK TABLE %s",
7580 fmtQualifiedDumpable(&tblinfo[i]));
7581 else
7582 {
7583 appendPQExpBuffer(query, ", %s",
7584 fmtQualifiedDumpable(&tblinfo[i]));
7585
7586 /* Arbitrarily end a batch when query length reaches 100K. */
7587 if (query->len >= 100000)
7588 {
7589 /* Lock another batch of tables. */
7590 appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7591 ExecuteSqlStatement(fout, query->data);
7592 resetPQExpBuffer(query);
7593 }
7594 }
7595 }
7596 }
7597
7598 if (query->len != 0)
7599 {
7600 /* Lock the tables in the last batch. */
7601 appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7602 ExecuteSqlStatement(fout, query->data);
7603 }
7604
7605 if (dopt->lockWaitTimeout)
7606 {
7607 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
7608 }
7609
7610 PQclear(res);
7611
7612 destroyPQExpBuffer(query);
7613
7614 return tblinfo;
7615}
7616
7617/*
7618 * getOwnedSeqs
7619 * identify owned sequences and mark them as dumpable if owning table is
7620 *
7621 * We used to do this in getTables(), but it's better to do it after the
7622 * index used by findTableByOid() has been set up.
7623 */
7624void
7626{
7627 int i;
7628
7629 /*
7630 * Force sequences that are "owned" by table columns to be dumped whenever
7631 * their owning table is being dumped.
7632 */
7633 for (i = 0; i < numTables; i++)
7634 {
7635 TableInfo *seqinfo = &tblinfo[i];
7636 TableInfo *owning_tab;
7637
7638 if (!OidIsValid(seqinfo->owning_tab))
7639 continue; /* not an owned sequence */
7640
7641 owning_tab = findTableByOid(seqinfo->owning_tab);
7642 if (owning_tab == NULL)
7643 pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
7644 seqinfo->owning_tab, seqinfo->dobj.catId.oid);
7645
7646 /*
7647 * For an identity sequence, dump exactly the same components for the
7648 * sequence as for the owning table. This is important because we
7649 * treat the identity sequence as an integral part of the table. For
7650 * example, there is not any DDL command that allows creation of such
7651 * a sequence independently of the table.
7652 *
7653 * For other owned sequences such as serial sequences, we need to dump
7654 * the components that are being dumped for the table and any
7655 * components that the sequence is explicitly marked with.
7656 *
7657 * We can't simply use the set of components which are being dumped
7658 * for the table as the table might be in an extension (and only the
7659 * non-extension components, eg: ACLs if changed, security labels, and
7660 * policies, are being dumped) while the sequence is not (and
7661 * therefore the definition and other components should also be
7662 * dumped).
7663 *
7664 * If the sequence is part of the extension then it should be properly
7665 * marked by checkExtensionMembership() and this will be a no-op as
7666 * the table will be equivalently marked.
7667 */
7668 if (seqinfo->is_identity_sequence)
7669 seqinfo->dobj.dump = owning_tab->dobj.dump;
7670 else
7671 seqinfo->dobj.dump |= owning_tab->dobj.dump;
7672
7673 /* Make sure that necessary data is available if we're dumping it */
7674 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
7675 {
7676 seqinfo->interesting = true;
7677 owning_tab->interesting = true;
7678 }
7679 }
7680}
7681
7682/*
7683 * getInherits
7684 * read all the inheritance information
7685 * from the system catalogs return them in the InhInfo* structure
7686 *
7687 * numInherits is set to the number of pairs read in
7688 */
7689InhInfo *
7691{
7692 PGresult *res;
7693 int ntups;
7694 int i;
7697
7698 int i_inhrelid;
7699 int i_inhparent;
7700
7701 /* find all the inheritance information */
7702 appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
7703
7704 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7705
7706 ntups = PQntuples(res);
7707
7708 *numInherits = ntups;
7709
7711
7712 i_inhrelid = PQfnumber(res, "inhrelid");
7713 i_inhparent = PQfnumber(res, "inhparent");
7714
7715 for (i = 0; i < ntups; i++)
7716 {
7717 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
7718 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
7719 }
7720
7721 PQclear(res);
7722
7723 destroyPQExpBuffer(query);
7724
7725 return inhinfo;
7726}
7727
7728/*
7729 * getPartitioningInfo
7730 * get information about partitioning
7731 *
7732 * For the most part, we only collect partitioning info about tables we
7733 * intend to dump. However, this function has to consider all partitioned
7734 * tables in the database, because we need to know about parents of partitions
7735 * we are going to dump even if the parents themselves won't be dumped.
7736 *
7737 * Specifically, what we need to know is whether each partitioned table
7738 * has an "unsafe" partitioning scheme that requires us to force
7739 * load-via-partition-root mode for its children. Currently the only case
7740 * for which we force that is hash partitioning on enum columns, since the
7741 * hash codes depend on enum value OIDs which won't be replicated across
7742 * dump-and-reload. There are other cases in which load-via-partition-root
7743 * might be necessary, but we expect users to cope with them.
7744 */
7745void
7747{
7748 PQExpBuffer query;
7749 PGresult *res;
7750 int ntups;
7751
7752 /* hash partitioning didn't exist before v11 */
7753 if (fout->remoteVersion < 110000)
7754 return;
7755 /* needn't bother if not dumping data */
7756 if (!fout->dopt->dumpData)
7757 return;
7758
7759 query = createPQExpBuffer();
7760
7761 /*
7762 * Unsafe partitioning schemes are exactly those for which hash enum_ops
7763 * appears among the partition opclasses. We needn't check partstrat.
7764 *
7765 * Note that this query may well retrieve info about tables we aren't
7766 * going to dump and hence have no lock on. That's okay since we need not
7767 * invoke any unsafe server-side functions.
7768 */
7770 "SELECT partrelid FROM pg_partitioned_table WHERE\n"
7771 "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
7772 "ON c.opcmethod = a.oid\n"
7773 "WHERE opcname = 'enum_ops' "
7774 "AND opcnamespace = 'pg_catalog'::regnamespace "
7775 "AND amname = 'hash') = ANY(partclass)");
7776
7777 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7778
7779 ntups = PQntuples(res);
7780
7781 for (int i = 0; i < ntups; i++)
7782 {
7783 Oid tabrelid = atooid(PQgetvalue(res, i, 0));
7785
7787 if (tbinfo == NULL)
7788 pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
7789 tabrelid);
7790 tbinfo->unsafe_partitions = true;
7791 }
7792
7793 PQclear(res);
7794
7795 destroyPQExpBuffer(query);
7796}
7797
7798/*
7799 * getIndexes
7800 * get information about every index on a dumpable table
7801 *
7802 * Note: index data is not returned directly to the caller, but it
7803 * does get entered into the DumpableObject tables.
7804 */
7805void
7806getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
7807{
7810 PGresult *res;
7811 int ntups;
7812 int curtblindx;
7814 int i_tableoid,
7815 i_oid,
7816 i_indrelid,
7818 i_relpages,
7823 i_indexdef,
7825 i_indnatts,
7826 i_indkey,
7830 i_contype,
7831 i_conname,
7836 i_conoid,
7837 i_condef,
7843
7844 /*
7845 * We want to perform just one query against pg_index. However, we
7846 * mustn't try to select every row of the catalog and then sort it out on
7847 * the client side, because some of the server-side functions we need
7848 * would be unsafe to apply to tables we don't have lock on. Hence, we
7849 * build an array of the OIDs of tables we care about (and now have lock
7850 * on!), and use a WHERE clause to constrain which rows are selected.
7851 */
7853 for (int i = 0; i < numTables; i++)
7854 {
7855 TableInfo *tbinfo = &tblinfo[i];
7856
7857 if (!tbinfo->hasindex)
7858 continue;
7859
7860 /*
7861 * We can ignore indexes of uninteresting tables.
7862 */
7863 if (!tbinfo->interesting)
7864 continue;
7865
7866 /* OK, we need info for this table */
7867 if (tbloids->len > 1) /* do we have more than the '{'? */
7869 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
7870 }
7872
7874 "SELECT t.tableoid, t.oid, i.indrelid, "
7875 "t.relname AS indexname, "
7876 "t.relpages, t.reltuples, t.relallvisible, ");
7877
7878 if (fout->remoteVersion >= 180000)
7879 appendPQExpBufferStr(query, "t.relallfrozen, ");
7880 else
7881 appendPQExpBufferStr(query, "0 AS relallfrozen, ");
7882
7884 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7885 "i.indkey, i.indisclustered, "
7886 "c.contype, c.conname, "
7887 "c.condeferrable, c.condeferred, "
7888 "c.tableoid AS contableoid, "
7889 "c.oid AS conoid, "
7890 "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
7891 "CASE WHEN i.indexprs IS NOT NULL THEN "
7892 "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
7893 " FROM pg_catalog.pg_attribute "
7894 " WHERE attrelid = i.indexrelid) "
7895 "ELSE NULL END AS indattnames, "
7896 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7897 "t.reloptions AS indreloptions, ");
7898
7899
7901 "i.indisreplident, ");
7902
7903 if (fout->remoteVersion >= 110000)
7905 "inh.inhparent AS parentidx, "
7906 "i.indnkeyatts AS indnkeyatts, "
7907 "i.indnatts AS indnatts, "
7908 "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
7909 " FROM pg_catalog.pg_attribute "
7910 " WHERE attrelid = i.indexrelid AND "
7911 " attstattarget >= 0) AS indstatcols, "
7912 "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
7913 " FROM pg_catalog.pg_attribute "
7914 " WHERE attrelid = i.indexrelid AND "
7915 " attstattarget >= 0) AS indstatvals, ");
7916 else
7918 "0 AS parentidx, "
7919 "i.indnatts AS indnkeyatts, "
7920 "i.indnatts AS indnatts, "
7921 "'' AS indstatcols, "
7922 "'' AS indstatvals, ");
7923
7924 if (fout->remoteVersion >= 150000)
7926 "i.indnullsnotdistinct, ");
7927 else
7929 "false AS indnullsnotdistinct, ");
7930
7931 if (fout->remoteVersion >= 180000)
7933 "c.conperiod ");
7934 else
7936 "NULL AS conperiod ");
7937
7938 /*
7939 * The point of the messy-looking outer join is to find a constraint that
7940 * is related by an internal dependency link to the index. If we find one,
7941 * create a CONSTRAINT entry linked to the INDEX entry. We assume an
7942 * index won't have more than one internal dependency.
7943 *
7944 * Note: the check on conrelid is redundant, but useful because that
7945 * column is indexed while conindid is not.
7946 */
7947 if (fout->remoteVersion >= 110000)
7948 {
7949 appendPQExpBuffer(query,
7950 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7951 "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7952 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7953 "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
7954 "LEFT JOIN pg_catalog.pg_constraint c "
7955 "ON (i.indrelid = c.conrelid AND "
7956 "i.indexrelid = c.conindid AND "
7957 "c.contype IN ('p','u','x')) "
7958 "LEFT JOIN pg_catalog.pg_inherits inh "
7959 "ON (inh.inhrelid = indexrelid) "
7960 "WHERE (i.indisvalid OR t2.relkind = 'p') "
7961 "AND i.indisready "
7962 "ORDER BY i.indrelid, indexname",
7963 tbloids->data);
7964 }
7965 else
7966 {
7967 /*
7968 * the test on indisready is necessary in 9.2, and harmless in
7969 * earlier/later versions
7970 */
7971 appendPQExpBuffer(query,
7972 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7973 "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7974 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7975 "LEFT JOIN pg_catalog.pg_constraint c "
7976 "ON (i.indrelid = c.conrelid AND "
7977 "i.indexrelid = c.conindid AND "
7978 "c.contype IN ('p','u','x')) "
7979 "WHERE i.indisvalid AND i.indisready "
7980 "ORDER BY i.indrelid, indexname",
7981 tbloids->data);
7982 }
7983
7984 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7985
7986 ntups = PQntuples(res);
7987
7988 i_tableoid = PQfnumber(res, "tableoid");
7989 i_oid = PQfnumber(res, "oid");
7990 i_indrelid = PQfnumber(res, "indrelid");
7991 i_indexname = PQfnumber(res, "indexname");
7992 i_relpages = PQfnumber(res, "relpages");
7993 i_reltuples = PQfnumber(res, "reltuples");
7994 i_relallvisible = PQfnumber(res, "relallvisible");
7995 i_relallfrozen = PQfnumber(res, "relallfrozen");
7996 i_parentidx = PQfnumber(res, "parentidx");
7997 i_indexdef = PQfnumber(res, "indexdef");
7998 i_indnkeyatts = PQfnumber(res, "indnkeyatts");
7999 i_indnatts = PQfnumber(res, "indnatts");
8000 i_indkey = PQfnumber(res, "indkey");
8001 i_indisclustered = PQfnumber(res, "indisclustered");
8002 i_indisreplident = PQfnumber(res, "indisreplident");
8003 i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
8004 i_contype = PQfnumber(res, "contype");
8005 i_conname = PQfnumber(res, "conname");
8006 i_condeferrable = PQfnumber(res, "condeferrable");
8007 i_condeferred = PQfnumber(res, "condeferred");
8008 i_conperiod = PQfnumber(res, "conperiod");
8009 i_contableoid = PQfnumber(res, "contableoid");
8010 i_conoid = PQfnumber(res, "conoid");
8011 i_condef = PQfnumber(res, "condef");
8012 i_indattnames = PQfnumber(res, "indattnames");
8013 i_tablespace = PQfnumber(res, "tablespace");
8014 i_indreloptions = PQfnumber(res, "indreloptions");
8015 i_indstatcols = PQfnumber(res, "indstatcols");
8016 i_indstatvals = PQfnumber(res, "indstatvals");
8017
8019
8020 /*
8021 * Outer loop iterates once per table, not once per row. Incrementing of
8022 * j is handled by the inner loop.
8023 */
8024 curtblindx = -1;
8025 for (int j = 0; j < ntups;)
8026 {
8029 int numinds;
8030
8031 /* Count rows for this table */
8032 for (numinds = 1; numinds < ntups - j; numinds++)
8033 if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
8034 break;
8035
8036 /*
8037 * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8038 * order.
8039 */
8040 while (++curtblindx < numTables)
8041 {
8042 tbinfo = &tblinfo[curtblindx];
8043 if (tbinfo->dobj.catId.oid == indrelid)
8044 break;
8045 }
8046 if (curtblindx >= numTables)
8047 pg_fatal("unrecognized table OID %u", indrelid);
8048 /* cross-check that we only got requested tables */
8049 if (!tbinfo->hasindex ||
8050 !tbinfo->interesting)
8051 pg_fatal("unexpected index data for table \"%s\"",
8052 tbinfo->dobj.name);
8053
8054 /* Save data for this table */
8055 tbinfo->indexes = indxinfo + j;
8056 tbinfo->numIndexes = numinds;
8057
8058 for (int c = 0; c < numinds; c++, j++)
8059 {
8060 char contype;
8061 char indexkind;
8062 char **indAttNames = NULL;
8063 int nindAttNames = 0;
8065 int32 relpages = atoi(PQgetvalue(res, j, i_relpages));
8066 int32 relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
8067 int32 relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
8068
8069 indxinfo[j].dobj.objType = DO_INDEX;
8070 indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8071 indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8072 AssignDumpId(&indxinfo[j].dobj);
8073 indxinfo[j].dobj.dump = tbinfo->dobj.dump;
8074 indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
8075 indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
8076 indxinfo[j].indextable = tbinfo;
8077 indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
8078 indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
8079 indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
8080 indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
8081 indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
8082 indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
8083 indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
8084 indxinfo[j].indkeys = pg_malloc_array(Oid, indxinfo[j].indnattrs);
8086 indxinfo[j].indkeys, indxinfo[j].indnattrs);
8087 indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
8088 indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
8089 indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
8090 indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
8091 indxinfo[j].partattaches = (SimplePtrList)
8092 {
8093 NULL, NULL
8094 };
8095
8096 if (indxinfo[j].parentidx == 0)
8098 else
8100
8101 if (!PQgetisnull(res, j, i_indattnames))
8102 {
8104 &indAttNames, &nindAttNames))
8105 pg_fatal("could not parse %s array", "indattnames");
8106 }
8107
8108 relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
8109 PQgetvalue(res, j, i_reltuples),
8110 relallvisible, relallfrozen, indexkind,
8111 indAttNames, nindAttNames);
8112
8113 contype = *(PQgetvalue(res, j, i_contype));
8114 if (contype == 'p' || contype == 'u' || contype == 'x')
8115 {
8116 /*
8117 * If we found a constraint matching the index, create an
8118 * entry for it.
8119 */
8121
8123 constrinfo->dobj.objType = DO_CONSTRAINT;
8124 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
8125 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
8126 AssignDumpId(&constrinfo->dobj);
8127 constrinfo->dobj.dump = tbinfo->dobj.dump;
8128 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
8129 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
8130 constrinfo->contable = tbinfo;
8131 constrinfo->condomain = NULL;
8132 constrinfo->contype = contype;
8133 if (contype == 'x')
8134 constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
8135 else
8136 constrinfo->condef = NULL;
8137 constrinfo->confrelid = InvalidOid;
8138 constrinfo->conindex = indxinfo[j].dobj.dumpId;
8139 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
8140 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
8141 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
8142 constrinfo->conislocal = true;
8143 constrinfo->separate = true;
8144
8145 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
8146 if (relstats != NULL)
8147 addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
8148 }
8149 else
8150 {
8151 /* Plain secondary index */
8152 indxinfo[j].indexconstraint = 0;
8153 }
8154 }
8155 }
8156
8157 PQclear(res);
8158
8159 destroyPQExpBuffer(query);
8161}
8162
8163/*
8164 * getExtendedStatistics
8165 * get information about extended-statistics objects.
8166 *
8167 * Note: extended statistics data is not returned directly to the caller, but
8168 * it does get entered into the DumpableObject tables.
8169 */
8170void
8172{
8173 PQExpBuffer query;
8174 PGresult *res;
8176 int ntups;
8177 int i_tableoid;
8178 int i_oid;
8179 int i_stxname;
8180 int i_stxnamespace;
8181 int i_stxowner;
8182 int i_stxrelid;
8183 int i_stattarget;
8184 int i;
8185
8186 query = createPQExpBuffer();
8187
8188 if (fout->remoteVersion < 130000)
8189 appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
8190 "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
8191 "FROM pg_catalog.pg_statistic_ext");
8192 else
8193 appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
8194 "stxnamespace, stxowner, stxrelid, stxstattarget "
8195 "FROM pg_catalog.pg_statistic_ext");
8196
8197 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8198
8199 ntups = PQntuples(res);
8200
8201 i_tableoid = PQfnumber(res, "tableoid");
8202 i_oid = PQfnumber(res, "oid");
8203 i_stxname = PQfnumber(res, "stxname");
8204 i_stxnamespace = PQfnumber(res, "stxnamespace");
8205 i_stxowner = PQfnumber(res, "stxowner");
8206 i_stxrelid = PQfnumber(res, "stxrelid");
8207 i_stattarget = PQfnumber(res, "stxstattarget");
8208
8210
8211 for (i = 0; i < ntups; i++)
8212 {
8213 statsextinfo[i].dobj.objType = DO_STATSEXT;
8214 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8215 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8216 AssignDumpId(&statsextinfo[i].dobj);
8217 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
8218 statsextinfo[i].dobj.namespace =
8220 statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
8221 statsextinfo[i].stattable =
8223 if (PQgetisnull(res, i, i_stattarget))
8224 statsextinfo[i].stattarget = -1;
8225 else
8226 statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
8227
8228 /* Decide whether we want to dump it */
8230
8231 if (fout->dopt->dumpStatistics)
8232 statsextinfo[i].dobj.components |= DUMP_COMPONENT_STATISTICS;
8233 }
8234
8235 PQclear(res);
8236 destroyPQExpBuffer(query);
8237}
8238
8239/*
8240 * getConstraints
8241 *
8242 * Get info about constraints on dumpable tables.
8243 *
8244 * Currently handles foreign keys only.
8245 * Unique and primary key constraints are handled with indexes,
8246 * while check constraints are processed in getTableAttrs().
8247 */
8248void
8250{
8253 PGresult *res;
8254 int ntups;
8255 int curtblindx;
8258 int i_contableoid,
8259 i_conoid,
8260 i_conrelid,
8261 i_conname,
8263 i_conindid,
8264 i_condef;
8265
8266 /*
8267 * We want to perform just one query against pg_constraint. However, we
8268 * mustn't try to select every row of the catalog and then sort it out on
8269 * the client side, because some of the server-side functions we need
8270 * would be unsafe to apply to tables we don't have lock on. Hence, we
8271 * build an array of the OIDs of tables we care about (and now have lock
8272 * on!), and use a WHERE clause to constrain which rows are selected.
8273 */
8275 for (int i = 0; i < numTables; i++)
8276 {
8277 TableInfo *tinfo = &tblinfo[i];
8278
8279 if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
8280 continue;
8281
8282 /* OK, we need info for this table */
8283 if (tbloids->len > 1) /* do we have more than the '{'? */
8285 appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
8286 }
8288
8290 "SELECT c.tableoid, c.oid, "
8291 "conrelid, conname, confrelid, ");
8292 if (fout->remoteVersion >= 110000)
8293 appendPQExpBufferStr(query, "conindid, ");
8294 else
8295 appendPQExpBufferStr(query, "0 AS conindid, ");
8296 appendPQExpBuffer(query,
8297 "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
8298 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8299 "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
8300 "WHERE contype = 'f' ",
8301 tbloids->data);
8302 if (fout->remoteVersion >= 110000)
8304 "AND conparentid = 0 ");
8306 "ORDER BY conrelid, conname");
8307
8308 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8309
8310 ntups = PQntuples(res);
8311
8312 i_contableoid = PQfnumber(res, "tableoid");
8313 i_conoid = PQfnumber(res, "oid");
8314 i_conrelid = PQfnumber(res, "conrelid");
8315 i_conname = PQfnumber(res, "conname");
8316 i_confrelid = PQfnumber(res, "confrelid");
8317 i_conindid = PQfnumber(res, "conindid");
8318 i_condef = PQfnumber(res, "condef");
8319
8321
8322 curtblindx = -1;
8323 for (int j = 0; j < ntups; j++)
8324 {
8325 Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
8327
8328 /*
8329 * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8330 * order.
8331 */
8332 if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
8333 {
8334 while (++curtblindx < numTables)
8335 {
8336 tbinfo = &tblinfo[curtblindx];
8337 if (tbinfo->dobj.catId.oid == conrelid)
8338 break;
8339 }
8340 if (curtblindx >= numTables)
8341 pg_fatal("unrecognized table OID %u", conrelid);
8342 }
8343
8344 constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
8345 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
8346 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
8347 AssignDumpId(&constrinfo[j].dobj);
8348 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
8349 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
8350 constrinfo[j].contable = tbinfo;
8351 constrinfo[j].condomain = NULL;
8352 constrinfo[j].contype = 'f';
8353 constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
8354 constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
8355 constrinfo[j].conindex = 0;
8356 constrinfo[j].condeferrable = false;
8357 constrinfo[j].condeferred = false;
8358 constrinfo[j].conislocal = true;
8359 constrinfo[j].separate = true;
8360
8361 /*
8362 * Restoring an FK that points to a partitioned table requires that
8363 * all partition indexes have been attached beforehand. Ensure that
8364 * happens by making the constraint depend on each index partition
8365 * attach object.
8366 */
8367 reftable = findTableByOid(constrinfo[j].confrelid);
8368 if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
8369 {
8370 Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));
8371
8372 if (indexOid != InvalidOid)
8373 {
8374 for (int k = 0; k < reftable->numIndexes; k++)
8375 {
8377
8378 /* not our index? */
8379 if (reftable->indexes[k].dobj.catId.oid != indexOid)
8380 continue;
8381
8382 refidx = &reftable->indexes[k];
8384 break;
8385 }
8386 }
8387 }
8388 }
8389
8390 PQclear(res);
8391
8392 destroyPQExpBuffer(query);
8394}
8395
8396/*
8397 * addConstrChildIdxDeps
8398 *
8399 * Recursive subroutine for getConstraints
8400 *
8401 * Given an object representing a foreign key constraint and an index on the
8402 * partitioned table it references, mark the constraint object as dependent
8403 * on the DO_INDEX_ATTACH object of each index partition, recursively
8404 * drilling down to their partitions if any. This ensures that the FK is not
8405 * restored until the index is fully marked valid.
8406 */
8407static void
8409{
8410 SimplePtrListCell *cell;
8411
8413
8414 for (cell = refidx->partattaches.head; cell; cell = cell->next)
8415 {
8417
8418 addObjectDependency(dobj, attach->dobj.dumpId);
8419
8420 if (attach->partitionIdx->partattaches.head != NULL)
8421 addConstrChildIdxDeps(dobj, attach->partitionIdx);
8422 }
8423}
8424
8425/*
8426 * getDomainConstraints
8427 *
8428 * Get info about constraints on a domain.
8429 */
8430static void
8432{
8435 PGresult *res;
8436 int i_tableoid,
8437 i_oid,
8438 i_conname,
8439 i_consrc,
8441 i_contype;
8442 int ntups;
8443
8444 if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
8445 {
8446 /*
8447 * Set up query for constraint-specific details. For servers 17 and
8448 * up, domains have constraints of type 'n' as well as 'c', otherwise
8449 * just the latter.
8450 */
8451 appendPQExpBuffer(query,
8452 "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
8453 "SELECT tableoid, oid, conname, "
8454 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8455 "convalidated, contype "
8456 "FROM pg_catalog.pg_constraint "
8457 "WHERE contypid = $1 AND contype IN (%s) "
8458 "ORDER BY conname",
8459 fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
8460
8461 ExecuteSqlStatement(fout, query->data);
8462
8463 fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
8464 }
8465
8466 printfPQExpBuffer(query,
8467 "EXECUTE getDomainConstraints('%u')",
8468 tyinfo->dobj.catId.oid);
8469
8470 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8471
8472 ntups = PQntuples(res);
8473
8474 i_tableoid = PQfnumber(res, "tableoid");
8475 i_oid = PQfnumber(res, "oid");
8476 i_conname = PQfnumber(res, "conname");
8477 i_consrc = PQfnumber(res, "consrc");
8478 i_convalidated = PQfnumber(res, "convalidated");
8479 i_contype = PQfnumber(res, "contype");
8480
8482 tyinfo->domChecks = constrinfo;
8483
8484 /* 'i' tracks result rows; 'j' counts CHECK constraints */
8485 for (int i = 0, j = 0; i < ntups; i++)
8486 {
8487 bool validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
8488 char contype = (PQgetvalue(res, i, i_contype))[0];
8489 ConstraintInfo *constraint;
8490
8491 if (contype == CONSTRAINT_CHECK)
8492 {
8493 constraint = &constrinfo[j++];
8494 tyinfo->nDomChecks++;
8495 }
8496 else
8497 {
8498 Assert(contype == CONSTRAINT_NOTNULL);
8499 Assert(tyinfo->notnull == NULL);
8500 /* use last item in array for the not-null constraint */
8501 tyinfo->notnull = &(constrinfo[ntups - 1]);
8502 constraint = tyinfo->notnull;
8503 }
8504
8505 constraint->dobj.objType = DO_CONSTRAINT;
8506 constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8507 constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8508 AssignDumpId(&(constraint->dobj));
8509 constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
8510 constraint->dobj.namespace = tyinfo->dobj.namespace;
8511 constraint->contable = NULL;
8512 constraint->condomain = tyinfo;
8513 constraint->contype = contype;
8514 constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
8515 constraint->confrelid = InvalidOid;
8516 constraint->conindex = 0;
8517 constraint->condeferrable = false;
8518 constraint->condeferred = false;
8519 constraint->conislocal = true;
8520
8521 constraint->separate = !validated;
8522
8523 /*
8524 * Make the domain depend on the constraint, ensuring it won't be
8525 * output till any constraint dependencies are OK. If the constraint
8526 * has not been validated, it's going to be dumped after the domain
8527 * anyway, so this doesn't matter.
8528 */
8529 if (validated)
8530 addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
8531 }
8532
8533 PQclear(res);
8534
8535 destroyPQExpBuffer(query);
8536}
8537
8538/*
8539 * getRules
8540 * get basic information about every rule in the system
8541 */
8542void
8544{
8545 PGresult *res;
8546 int ntups;
8547 int i;
8550 int i_tableoid;
8551 int i_oid;
8552 int i_rulename;
8553 int i_ruletable;
8554 int i_ev_type;
8555 int i_is_instead;
8556 int i_ev_enabled;
8557
8558 appendPQExpBufferStr(query, "SELECT "
8559 "tableoid, oid, rulename, "
8560 "ev_class AS ruletable, ev_type, is_instead, "
8561 "ev_enabled "
8562 "FROM pg_rewrite "
8563 "ORDER BY oid");
8564
8565 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8566
8567 ntups = PQntuples(res);
8568
8570
8571 i_tableoid = PQfnumber(res, "tableoid");
8572 i_oid = PQfnumber(res, "oid");
8573 i_rulename = PQfnumber(res, "rulename");
8574 i_ruletable = PQfnumber(res, "ruletable");
8575 i_ev_type = PQfnumber(res, "ev_type");
8576 i_is_instead = PQfnumber(res, "is_instead");
8577 i_ev_enabled = PQfnumber(res, "ev_enabled");
8578
8579 for (i = 0; i < ntups; i++)
8580 {
8582
8583 ruleinfo[i].dobj.objType = DO_RULE;
8584 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8585 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8586 AssignDumpId(&ruleinfo[i].dobj);
8587 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
8589 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
8590 if (ruleinfo[i].ruletable == NULL)
8591 pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
8592 ruletableoid, ruleinfo[i].dobj.catId.oid);
8593 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
8594 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
8595 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
8596 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
8597 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
8598 if (ruleinfo[i].ruletable)
8599 {
8600 /*
8601 * If the table is a view or materialized view, force its ON
8602 * SELECT rule to be sorted before the view itself --- this
8603 * ensures that any dependencies for the rule affect the table's
8604 * positioning. Other rules are forced to appear after their
8605 * table.
8606 */
8607 if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
8608 ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
8609 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
8610 {
8611 addObjectDependency(&ruleinfo[i].ruletable->dobj,
8612 ruleinfo[i].dobj.dumpId);
8613 /* We'll merge the rule into CREATE VIEW, if possible */
8614 ruleinfo[i].separate = false;
8615 }
8616 else
8617 {
8619 ruleinfo[i].ruletable->dobj.dumpId);
8620 ruleinfo[i].separate = true;
8621 }
8622 }
8623 else
8624 ruleinfo[i].separate = true;
8625 }
8626
8627 PQclear(res);
8628
8629 destroyPQExpBuffer(query);
8630}
8631
8632/*
8633 * getTriggers
8634 * get information about every trigger on a dumpable table
8635 *
8636 * Note: trigger data is not returned directly to the caller, but it
8637 * does get entered into the DumpableObject tables.
8638 */
8639void
8640getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
8641{
8644 PGresult *res;
8645 int ntups;
8646 int curtblindx;
8648 int i_tableoid,
8649 i_oid,
8650 i_tgrelid,
8651 i_tgname,
8654 i_tgdef;
8655
8656 /*
8657 * We want to perform just one query against pg_trigger. However, we
8658 * mustn't try to select every row of the catalog and then sort it out on
8659 * the client side, because some of the server-side functions we need
8660 * would be unsafe to apply to tables we don't have lock on. Hence, we
8661 * build an array of the OIDs of tables we care about (and now have lock
8662 * on!), and use a WHERE clause to constrain which rows are selected.
8663 */
8665 for (int i = 0; i < numTables; i++)
8666 {
8667 TableInfo *tbinfo = &tblinfo[i];
8668
8669 if (!tbinfo->hastriggers ||
8670 !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
8671 continue;
8672
8673 /* OK, we need info for this table */
8674 if (tbloids->len > 1) /* do we have more than the '{'? */
8676 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8677 }
8679
8680 if (fout->remoteVersion >= 150000)
8681 {
8682 /*
8683 * NB: think not to use pretty=true in pg_get_triggerdef. It could
8684 * result in non-forward-compatible dumps of WHEN clauses due to
8685 * under-parenthesization.
8686 *
8687 * NB: We need to see partition triggers in case the tgenabled flag
8688 * has been changed from the parent.
8689 */
8690 appendPQExpBuffer(query,
8691 "SELECT t.tgrelid, t.tgname, "
8692 "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8693 "t.tgenabled, t.tableoid, t.oid, "
8694 "t.tgparentid <> 0 AS tgispartition\n"
8695 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8696 "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8697 "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8698 "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
8699 "OR t.tgenabled != u.tgenabled) "
8700 "ORDER BY t.tgrelid, t.tgname",
8701 tbloids->data);
8702 }
8703 else if (fout->remoteVersion >= 130000)
8704 {
8705 /*
8706 * NB: think not to use pretty=true in pg_get_triggerdef. It could
8707 * result in non-forward-compatible dumps of WHEN clauses due to
8708 * under-parenthesization.
8709 *
8710 * NB: We need to see tgisinternal triggers in partitions, in case the
8711 * tgenabled flag has been changed from the parent.
8712 */
8713 appendPQExpBuffer(query,
8714 "SELECT t.tgrelid, t.tgname, "
8715 "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8716 "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
8717 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8718 "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8719 "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8720 "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
8721 "ORDER BY t.tgrelid, t.tgname",
8722 tbloids->data);
8723 }
8724 else if (fout->remoteVersion >= 110000)
8725 {
8726 /*
8727 * NB: We need to see tgisinternal triggers in partitions, in case the
8728 * tgenabled flag has been changed from the parent. No tgparentid in
8729 * version 11-12, so we have to match them via pg_depend.
8730 *
8731 * See above about pretty=true in pg_get_triggerdef.
8732 */
8733 appendPQExpBuffer(query,
8734 "SELECT t.tgrelid, t.tgname, "
8735 "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8736 "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
8737 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8738 "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8739 "LEFT JOIN pg_catalog.pg_depend AS d ON "
8740 " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8741 " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8742 " d.objid = t.oid "
8743 "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
8744 "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
8745 "ORDER BY t.tgrelid, t.tgname",
8746 tbloids->data);
8747 }
8748 else
8749 {
8750 /* See above about pretty=true in pg_get_triggerdef */
8751 appendPQExpBuffer(query,
8752 "SELECT t.tgrelid, t.tgname, "
8753 "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8754 "t.tgenabled, false as tgispartition, "
8755 "t.tableoid, t.oid "
8756 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8757 "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8758 "WHERE NOT tgisinternal "
8759 "ORDER BY t.tgrelid, t.tgname",
8760 tbloids->data);
8761 }
8762
8763 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8764
8765 ntups = PQntuples(res);
8766
8767 i_tableoid = PQfnumber(res, "tableoid");
8768 i_oid = PQfnumber(res, "oid");
8769 i_tgrelid = PQfnumber(res, "tgrelid");
8770 i_tgname = PQfnumber(res, "tgname");
8771 i_tgenabled = PQfnumber(res, "tgenabled");
8772 i_tgispartition = PQfnumber(res, "tgispartition");
8773 i_tgdef = PQfnumber(res, "tgdef");
8774
8776
8777 /*
8778 * Outer loop iterates once per table, not once per row. Incrementing of
8779 * j is handled by the inner loop.
8780 */
8781 curtblindx = -1;
8782 for (int j = 0; j < ntups;)
8783 {
8786 int numtrigs;
8787
8788 /* Count rows for this table */
8789 for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
8790 if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
8791 break;
8792
8793 /*
8794 * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8795 * order.
8796 */
8797 while (++curtblindx < numTables)
8798 {
8799 tbinfo = &tblinfo[curtblindx];
8800 if (tbinfo->dobj.catId.oid == tgrelid)
8801 break;
8802 }
8803 if (curtblindx >= numTables)
8804 pg_fatal("unrecognized table OID %u", tgrelid);
8805
8806 /* Save data for this table */
8807 tbinfo->triggers = tginfo + j;
8808 tbinfo->numTriggers = numtrigs;
8809
8810 for (int c = 0; c < numtrigs; c++, j++)
8811 {
8812 tginfo[j].dobj.objType = DO_TRIGGER;
8813 tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8814 tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8815 AssignDumpId(&tginfo[j].dobj);
8816 tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
8817 tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
8818 tginfo[j].tgtable = tbinfo;
8819 tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
8820 tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
8821 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
8822 }
8823 }
8824
8825 PQclear(res);
8826
8827 destroyPQExpBuffer(query);
8829}
8830
8831/*
8832 * getEventTriggers
8833 * get information about event triggers
8834 */
8835void
8837{
8838 int i;
8839 PQExpBuffer query;
8840 PGresult *res;
8842 int i_tableoid,
8843 i_oid,
8844 i_evtname,
8845 i_evtevent,
8846 i_evtowner,
8847 i_evttags,
8848 i_evtfname,
8850 int ntups;
8851
8852 query = createPQExpBuffer();
8853
8855 "SELECT e.tableoid, e.oid, evtname, evtenabled, "
8856 "evtevent, evtowner, "
8857 "array_to_string(array("
8858 "select quote_literal(x) "
8859 " from unnest(evttags) as t(x)), ', ') as evttags, "
8860 "e.evtfoid::regproc as evtfname "
8861 "FROM pg_event_trigger e "
8862 "ORDER BY e.oid");
8863
8864 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8865
8866 ntups = PQntuples(res);
8867
8869
8870 i_tableoid = PQfnumber(res, "tableoid");
8871 i_oid = PQfnumber(res, "oid");
8872 i_evtname = PQfnumber(res, "evtname");
8873 i_evtevent = PQfnumber(res, "evtevent");
8874 i_evtowner = PQfnumber(res, "evtowner");
8875 i_evttags = PQfnumber(res, "evttags");
8876 i_evtfname = PQfnumber(res, "evtfname");
8877 i_evtenabled = PQfnumber(res, "evtenabled");
8878
8879 for (i = 0; i < ntups; i++)
8880 {
8881 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
8882 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8883 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8884 AssignDumpId(&evtinfo[i].dobj);
8885 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
8886 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
8887 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
8888 evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
8889 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
8890 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
8891 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
8892
8893 /* Decide whether we want to dump it */
8895 }
8896
8897 PQclear(res);
8898
8899 destroyPQExpBuffer(query);
8900}
8901
8902/*
8903 * getProcLangs
8904 * get basic information about every procedural language in the system
8905 *
8906 * NB: this must run after getFuncs() because we assume we can do
8907 * findFuncByOid().
8908 */
8909void
8911{
8912 PGresult *res;
8913 int ntups;
8914 int i;
8917 int i_tableoid;
8918 int i_oid;
8919 int i_lanname;
8920 int i_lanpltrusted;
8921 int i_lanplcallfoid;
8922 int i_laninline;
8923 int i_lanvalidator;
8924 int i_lanacl;
8925 int i_acldefault;
8926 int i_lanowner;
8927
8928 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8929 "lanname, lanpltrusted, lanplcallfoid, "
8930 "laninline, lanvalidator, "
8931 "lanacl, "
8932 "acldefault('l', lanowner) AS acldefault, "
8933 "lanowner "
8934 "FROM pg_language "
8935 "WHERE lanispl "
8936 "ORDER BY oid");
8937
8938 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8939
8940 ntups = PQntuples(res);
8941
8943
8944 i_tableoid = PQfnumber(res, "tableoid");
8945 i_oid = PQfnumber(res, "oid");
8946 i_lanname = PQfnumber(res, "lanname");
8947 i_lanpltrusted = PQfnumber(res, "lanpltrusted");
8948 i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
8949 i_laninline = PQfnumber(res, "laninline");
8950 i_lanvalidator = PQfnumber(res, "lanvalidator");
8951 i_lanacl = PQfnumber(res, "lanacl");
8952 i_acldefault = PQfnumber(res, "acldefault");
8953 i_lanowner = PQfnumber(res, "lanowner");
8954
8955 for (i = 0; i < ntups; i++)
8956 {
8957 planginfo[i].dobj.objType = DO_PROCLANG;
8958 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8959 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8960 AssignDumpId(&planginfo[i].dobj);
8961
8962 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
8963 planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
8964 planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
8965 planginfo[i].dacl.privtype = 0;
8966 planginfo[i].dacl.initprivs = NULL;
8967 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
8968 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
8969 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
8970 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
8971 planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
8972
8973 /* Decide whether we want to dump it */
8975
8976 /* Mark whether language has an ACL */
8977 if (!PQgetisnull(res, i, i_lanacl))
8978 planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
8979 }
8980
8981 PQclear(res);
8982
8983 destroyPQExpBuffer(query);
8984}
8985
8986/*
8987 * getCasts
8988 * get basic information about most casts in the system
8989 *
8990 * Skip casts from a range to its multirange, since we'll create those
8991 * automatically.
8992 */
8993void
8995{
8996 PGresult *res;
8997 int ntups;
8998 int i;
9001 int i_tableoid;
9002 int i_oid;
9003 int i_castsource;
9004 int i_casttarget;
9005 int i_castfunc;
9006 int i_castcontext;
9007 int i_castmethod;
9008
9009 if (fout->remoteVersion >= 140000)
9010 {
9011 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9012 "castsource, casttarget, castfunc, castcontext, "
9013 "castmethod "
9014 "FROM pg_cast c "
9015 "WHERE NOT EXISTS ( "
9016 "SELECT 1 FROM pg_range r "
9017 "WHERE c.castsource = r.rngtypid "
9018 "AND c.casttarget = r.rngmultitypid "
9019 ") "
9020 "ORDER BY 3,4");
9021 }
9022 else
9023 {
9024 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9025 "castsource, casttarget, castfunc, castcontext, "
9026 "castmethod "
9027 "FROM pg_cast ORDER BY 3,4");
9028 }
9029
9030 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9031
9032 ntups = PQntuples(res);
9033
9035
9036 i_tableoid = PQfnumber(res, "tableoid");
9037 i_oid = PQfnumber(res, "oid");
9038 i_castsource = PQfnumber(res, "castsource");
9039 i_casttarget = PQfnumber(res, "casttarget");
9040 i_castfunc = PQfnumber(res, "castfunc");
9041 i_castcontext = PQfnumber(res, "castcontext");
9042 i_castmethod = PQfnumber(res, "castmethod");
9043
9044 for (i = 0; i < ntups; i++)
9045 {
9049
9051 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9052 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9053 AssignDumpId(&castinfo[i].dobj);
9054 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
9055 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
9056 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
9057 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
9058 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
9059
9060 /*
9061 * Try to name cast as concatenation of typnames. This is only used
9062 * for purposes of sorting. If we fail to find either type, the name
9063 * will be an empty string.
9064 */
9066 sTypeInfo = findTypeByOid(castinfo[i].castsource);
9067 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
9068 if (sTypeInfo && tTypeInfo)
9069 appendPQExpBuffer(&namebuf, "%s %s",
9070 sTypeInfo->dobj.name, tTypeInfo->dobj.name);
9071 castinfo[i].dobj.name = namebuf.data;
9072
9073 /* Decide whether we want to dump it */
9075 }
9076
9077 PQclear(res);
9078
9079 destroyPQExpBuffer(query);
9080}
9081
9082static char *
9084{
9085 PQExpBuffer query;
9086 PGresult *res;
9087 char *lanname;
9088
9089 query = createPQExpBuffer();
9090 appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
9091 res = ExecuteSqlQueryForSingleRow(fout, query->data);
9092 lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
9093 destroyPQExpBuffer(query);
9094 PQclear(res);
9095
9096 return lanname;
9097}
9098
9099/*
9100 * getTransforms
9101 * get basic information about every transform in the system
9102 */
9103void
9105{
9106 PGresult *res;
9107 int ntups;
9108 int i;
9109 PQExpBuffer query;
9111 int i_tableoid;
9112 int i_oid;
9113 int i_trftype;
9114 int i_trflang;
9115 int i_trffromsql;
9116 int i_trftosql;
9117
9118 query = createPQExpBuffer();
9119
9120 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9121 "trftype, trflang, trffromsql::oid, trftosql::oid "
9122 "FROM pg_transform "
9123 "ORDER BY 3,4");
9124
9125 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9126
9127 ntups = PQntuples(res);
9128
9130
9131 i_tableoid = PQfnumber(res, "tableoid");
9132 i_oid = PQfnumber(res, "oid");
9133 i_trftype = PQfnumber(res, "trftype");
9134 i_trflang = PQfnumber(res, "trflang");
9135 i_trffromsql = PQfnumber(res, "trffromsql");
9136 i_trftosql = PQfnumber(res, "trftosql");
9137
9138 for (i = 0; i < ntups; i++)
9139 {
9142 char *lanname;
9143
9145 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9146 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9148 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
9149 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
9150 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
9151 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
9152
9153 /*
9154 * Try to name transform as concatenation of type and language name.
9155 * This is only used for purposes of sorting. If we fail to find
9156 * either, the name will be an empty string.
9157 */
9161 if (typeInfo && lanname)
9162 appendPQExpBuffer(&namebuf, "%s %s",
9163 typeInfo->dobj.name, lanname);
9164 transforminfo[i].dobj.name = namebuf.data;
9165 free(lanname);
9166
9167 /* Decide whether we want to dump it */
9169 }
9170
9171 PQclear(res);
9172
9173 destroyPQExpBuffer(query);
9174}
9175
9176/*
9177 * getTableAttrs -
9178 * for each interesting table, read info about its attributes
9179 * (names, types, default values, CHECK constraints, etc)
9180 *
9181 * modifies tblinfo
9182 */
9183void
9185{
9186 DumpOptions *dopt = fout->dopt;
9191 PGresult *res;
9192 int ntups;
9193 int curtblindx;
9194 int i_attrelid;
9195 int i_attnum;
9196 int i_attname;
9197 int i_atttypname;
9198 int i_attstattarget;
9199 int i_attstorage;
9200 int i_typstorage;
9201 int i_attidentity;
9202 int i_attgenerated;
9203 int i_attisdropped;
9204 int i_attlen;
9205 int i_attalign;
9206 int i_attislocal;
9207 int i_notnull_name;
9212 int i_attoptions;
9213 int i_attcollation;
9214 int i_attcompression;
9215 int i_attfdwoptions;
9216 int i_attmissingval;
9217 int i_atthasdef;
9218
9219 /*
9220 * We want to perform just one query against pg_attribute, and then just
9221 * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
9222 * (for CHECK constraints and for NOT NULL constraints). However, we
9223 * mustn't try to select every row of those catalogs and then sort it out
9224 * on the client side, because some of the server-side functions we need
9225 * would be unsafe to apply to tables we don't have lock on. Hence, we
9226 * build an array of the OIDs of tables we care about (and now have lock
9227 * on!), and use a WHERE clause to constrain which rows are selected.
9228 */
9231 for (int i = 0; i < numTables; i++)
9232 {
9233 TableInfo *tbinfo = &tblinfo[i];
9234
9235 /* Don't bother to collect info for sequences */
9236 if (tbinfo->relkind == RELKIND_SEQUENCE)
9237 continue;
9238
9239 /*
9240 * Don't bother with uninteresting tables, either. For binary
9241 * upgrades, this is bypassed for pg_largeobject_metadata and
9242 * pg_shdepend so that the columns names are collected for the
9243 * corresponding COPY commands. Restoring the data for those catalogs
9244 * is faster than restoring the equivalent set of large object
9245 * commands.
9246 */
9247 if (!tbinfo->interesting &&
9248 !(fout->dopt->binary_upgrade &&
9249 (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
9250 tbinfo->dobj.catId.oid == SharedDependRelationId)))
9251 continue;
9252
9253 /* OK, we need info for this table */
9254 if (tbloids->len > 1) /* do we have more than the '{'? */
9256 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
9257
9258 if (tbinfo->ncheck > 0)
9259 {
9260 /* Also make a list of the ones with check constraints */
9261 if (checkoids->len > 1) /* do we have more than the '{'? */
9263 appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
9264 }
9265 }
9268
9269 /*
9270 * Find all the user attributes and their types.
9271 *
9272 * Since we only want to dump COLLATE clauses for attributes whose
9273 * collation is different from their type's default, we use a CASE here to
9274 * suppress uninteresting attcollations cheaply.
9275 */
9277 "SELECT\n"
9278 "a.attrelid,\n"
9279 "a.attnum,\n"
9280 "a.attname,\n"
9281 "a.attstattarget,\n"
9282 "a.attstorage,\n"
9283 "t.typstorage,\n"
9284 "a.atthasdef,\n"
9285 "a.attisdropped,\n"
9286 "a.attlen,\n"
9287 "a.attalign,\n"
9288 "a.attislocal,\n"
9289 "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
9290 "array_to_string(a.attoptions, ', ') AS attoptions,\n"
9291 "CASE WHEN a.attcollation <> t.typcollation "
9292 "THEN a.attcollation ELSE 0 END AS attcollation,\n"
9293 "pg_catalog.array_to_string(ARRAY("
9294 "SELECT pg_catalog.quote_ident(option_name) || "
9295 "' ' || pg_catalog.quote_literal(option_value) "
9296 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
9297 "ORDER BY option_name"
9298 "), E',\n ') AS attfdwoptions,\n");
9299
9300 /*
9301 * Find out any NOT NULL markings for each column. In 18 and up we read
9302 * pg_constraint to obtain the constraint name, and for valid constraints
9303 * also pg_description to obtain its comment. notnull_noinherit is set
9304 * according to the NO INHERIT property. For versions prior to 18, we
9305 * store an empty string as the name when a constraint is marked as
9306 * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
9307 * without a name); also, such cases are never NO INHERIT.
9308 *
9309 * For invalid constraints, we need to store their OIDs for processing
9310 * elsewhere, so we bring the pg_constraint.oid value when the constraint
9311 * is invalid, and NULL otherwise. Their comments are handled not here
9312 * but by collectComments, because they're their own dumpable object.
9313 *
9314 * We track in notnull_islocal whether the constraint was defined directly
9315 * in this table or via an ancestor, for binary upgrade. flagInhAttrs
9316 * might modify this later.
9317 */
9318 if (fout->remoteVersion >= 180000)
9320 "co.conname AS notnull_name,\n"
9321 "CASE WHEN co.convalidated THEN pt.description"
9322 " ELSE NULL END AS notnull_comment,\n"
9323 "CASE WHEN NOT co.convalidated THEN co.oid "
9324 "ELSE NULL END AS notnull_invalidoid,\n"
9325 "co.connoinherit AS notnull_noinherit,\n"
9326 "co.conislocal AS notnull_islocal,\n");
9327 else
9329 "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
9330 "NULL AS notnull_comment,\n"
9331 "NULL AS notnull_invalidoid,\n"
9332 "false AS notnull_noinherit,\n"
9333 "CASE WHEN a.attislocal THEN true\n"
9334 " WHEN a.attnotnull AND NOT a.attislocal THEN true\n"
9335 " ELSE false\n"
9336 "END AS notnull_islocal,\n");
9337
9338 if (fout->remoteVersion >= 140000)
9340 "a.attcompression AS attcompression,\n");
9341 else
9343 "'' AS attcompression,\n");
9344
9346 "a.attidentity,\n");
9347
9348 if (fout->remoteVersion >= 110000)
9350 "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
9351 "THEN a.attmissingval ELSE null END AS attmissingval,\n");
9352 else
9354 "NULL AS attmissingval,\n");
9355
9356 if (fout->remoteVersion >= 120000)
9358 "a.attgenerated\n");
9359 else
9361 "'' AS attgenerated\n");
9362
9363 /* need left join to pg_type to not fail on dropped columns ... */
9365 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9366 "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
9367 "LEFT JOIN pg_catalog.pg_type t "
9368 "ON (a.atttypid = t.oid)\n",
9369 tbloids->data);
9370
9371 /*
9372 * In versions 18 and up, we need pg_constraint for explicit NOT NULL
9373 * entries and pg_description to get their comments.
9374 */
9375 if (fout->remoteVersion >= 180000)
9377 " LEFT JOIN pg_catalog.pg_constraint co ON "
9378 "(a.attrelid = co.conrelid\n"
9379 " AND co.contype = 'n' AND "
9380 "co.conkey = array[a.attnum])\n"
9381 " LEFT JOIN pg_catalog.pg_description pt ON "
9382 "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
9383
9385 "WHERE a.attnum > 0::pg_catalog.int2\n");
9386
9387 /*
9388 * For binary upgrades from <v12, be sure to pick up
9389 * pg_largeobject_metadata's oid column.
9390 */
9391 if (fout->dopt->binary_upgrade && fout->remoteVersion < 120000)
9393 "OR (a.attnum = -2::pg_catalog.int2 AND src.tbloid = "
9395
9397 "ORDER BY a.attrelid, a.attnum");
9398
9400
9401 ntups = PQntuples(res);
9402
9403 i_attrelid = PQfnumber(res, "attrelid");
9404 i_attnum = PQfnumber(res, "attnum");
9405 i_attname = PQfnumber(res, "attname");
9406 i_atttypname = PQfnumber(res, "atttypname");
9407 i_attstattarget = PQfnumber(res, "attstattarget");
9408 i_attstorage = PQfnumber(res, "attstorage");
9409 i_typstorage = PQfnumber(res, "typstorage");
9410 i_attidentity = PQfnumber(res, "attidentity");
9411 i_attgenerated = PQfnumber(res, "attgenerated");
9412 i_attisdropped = PQfnumber(res, "attisdropped");
9413 i_attlen = PQfnumber(res, "attlen");
9414 i_attalign = PQfnumber(res, "attalign");
9415 i_attislocal = PQfnumber(res, "attislocal");
9416 i_notnull_name = PQfnumber(res, "notnull_name");
9417 i_notnull_comment = PQfnumber(res, "notnull_comment");
9418 i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
9419 i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
9420 i_notnull_islocal = PQfnumber(res, "notnull_islocal");
9421 i_attoptions = PQfnumber(res, "attoptions");
9422 i_attcollation = PQfnumber(res, "attcollation");
9423 i_attcompression = PQfnumber(res, "attcompression");
9424 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
9425 i_attmissingval = PQfnumber(res, "attmissingval");
9426 i_atthasdef = PQfnumber(res, "atthasdef");
9427
9428 /* Within the next loop, we'll accumulate OIDs of tables with defaults */
9431
9432 /*
9433 * Outer loop iterates once per table, not once per row. Incrementing of
9434 * r is handled by the inner loop.
9435 */
9436 curtblindx = -1;
9437 for (int r = 0; r < ntups;)
9438 {
9439 Oid attrelid = atooid(PQgetvalue(res, r, i_attrelid));
9441 int numatts;
9442 bool hasdefaults;
9443
9444 /* Count rows for this table */
9445 for (numatts = 1; numatts < ntups - r; numatts++)
9446 if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
9447 break;
9448
9449 /*
9450 * Locate the associated TableInfo; we rely on tblinfo[] being in OID
9451 * order.
9452 */
9453 while (++curtblindx < numTables)
9454 {
9455 tbinfo = &tblinfo[curtblindx];
9456 if (tbinfo->dobj.catId.oid == attrelid)
9457 break;
9458 }
9459 if (curtblindx >= numTables)
9460 pg_fatal("unrecognized table OID %u", attrelid);
9461 /* cross-check that we only got requested tables */
9462 if (tbinfo->relkind == RELKIND_SEQUENCE ||
9463 (!tbinfo->interesting &&
9464 !(fout->dopt->binary_upgrade &&
9465 (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
9466 tbinfo->dobj.catId.oid == SharedDependRelationId))))
9467 pg_fatal("unexpected column data for table \"%s\"",
9468 tbinfo->dobj.name);
9469
9470 /* Save data for this table */
9471 tbinfo->numatts = numatts;
9472 tbinfo->attnames = pg_malloc_array(char *, numatts);
9473 tbinfo->atttypnames = pg_malloc_array(char *, numatts);
9474 tbinfo->attstattarget = pg_malloc_array(int, numatts);
9475 tbinfo->attstorage = pg_malloc_array(char, numatts);
9476 tbinfo->typstorage = pg_malloc_array(char, numatts);
9477 tbinfo->attidentity = pg_malloc_array(char, numatts);
9478 tbinfo->attgenerated = pg_malloc_array(char, numatts);
9479 tbinfo->attisdropped = pg_malloc_array(bool, numatts);
9480 tbinfo->attlen = pg_malloc_array(int, numatts);
9481 tbinfo->attalign = pg_malloc_array(char, numatts);
9482 tbinfo->attislocal = pg_malloc_array(bool, numatts);
9483 tbinfo->attoptions = pg_malloc_array(char *, numatts);
9484 tbinfo->attcollation = pg_malloc_array(Oid, numatts);
9485 tbinfo->attcompression = pg_malloc_array(char, numatts);
9486 tbinfo->attfdwoptions = pg_malloc_array(char *, numatts);
9487 tbinfo->attmissingval = pg_malloc_array(char *, numatts);
9488 tbinfo->notnull_constrs = pg_malloc_array(char *, numatts);
9489 tbinfo->notnull_comment = pg_malloc_array(char *, numatts);
9490 tbinfo->notnull_invalid = pg_malloc_array(bool, numatts);
9491 tbinfo->notnull_noinh = pg_malloc_array(bool, numatts);
9492 tbinfo->notnull_islocal = pg_malloc_array(bool, numatts);
9493 tbinfo->attrdefs = pg_malloc_array(AttrDefInfo *, numatts);
9494 hasdefaults = false;
9495
9496 for (int j = 0; j < numatts; j++, r++)
9497 {
9498 if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)) &&
9499 !(fout->dopt->binary_upgrade && fout->remoteVersion < 120000 &&
9500 tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId))
9501 pg_fatal("invalid column numbering in table \"%s\"",
9502 tbinfo->dobj.name);
9503 tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
9504 tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
9505 if (PQgetisnull(res, r, i_attstattarget))
9506 tbinfo->attstattarget[j] = -1;
9507 else
9508 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
9509 tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
9510 tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
9511 tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
9512 tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
9513 tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
9514 tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
9515 tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
9516 tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
9517 tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
9518
9519 /* Handle not-null constraint name and flags */
9521 tbinfo, j,
9528
9529 tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
9531 tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
9532 tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
9533 tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
9534 tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
9535 tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
9536 tbinfo->attrdefs[j] = NULL; /* fix below */
9537 if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
9538 hasdefaults = true;
9539 }
9540
9541 if (hasdefaults)
9542 {
9543 /* Collect OIDs of interesting tables that have defaults */
9544 if (tbloids->len > 1) /* do we have more than the '{'? */
9546 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
9547 }
9548 }
9549
9550 /* If invalidnotnulloids has any data, finalize it */
9551 if (invalidnotnulloids != NULL)
9553
9554 PQclear(res);
9555
9556 /*
9557 * Now get info about column defaults. This is skipped for a data-only
9558 * dump, as it is only needed for table schemas.
9559 */
9560 if (dopt->dumpSchema && tbloids->len > 1)
9561 {
9562 AttrDefInfo *attrdefs;
9563 int numDefaults;
9565
9566 pg_log_info("finding table default expressions");
9567
9569
9570 printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
9571 "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
9572 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9573 "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
9574 "ORDER BY a.adrelid, a.adnum",
9575 tbloids->data);
9576
9578
9579 numDefaults = PQntuples(res);
9581
9582 curtblindx = -1;
9583 for (int j = 0; j < numDefaults; j++)
9584 {
9585 Oid adtableoid = atooid(PQgetvalue(res, j, 0));
9586 Oid adoid = atooid(PQgetvalue(res, j, 1));
9587 Oid adrelid = atooid(PQgetvalue(res, j, 2));
9588 int adnum = atoi(PQgetvalue(res, j, 3));
9589 char *adsrc = PQgetvalue(res, j, 4);
9590
9591 /*
9592 * Locate the associated TableInfo; we rely on tblinfo[] being in
9593 * OID order.
9594 */
9595 if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
9596 {
9597 while (++curtblindx < numTables)
9598 {
9599 tbinfo = &tblinfo[curtblindx];
9600 if (tbinfo->dobj.catId.oid == adrelid)
9601 break;
9602 }
9603 if (curtblindx >= numTables)
9604 pg_fatal("unrecognized table OID %u", adrelid);
9605 }
9606
9607 if (adnum <= 0 || adnum > tbinfo->numatts)
9608 pg_fatal("invalid adnum value %d for table \"%s\"",
9609 adnum, tbinfo->dobj.name);
9610
9611 /*
9612 * dropped columns shouldn't have defaults, but just in case,
9613 * ignore 'em
9614 */
9615 if (tbinfo->attisdropped[adnum - 1])
9616 continue;
9617
9618 attrdefs[j].dobj.objType = DO_ATTRDEF;
9619 attrdefs[j].dobj.catId.tableoid = adtableoid;
9620 attrdefs[j].dobj.catId.oid = adoid;
9621 AssignDumpId(&attrdefs[j].dobj);
9622 attrdefs[j].adtable = tbinfo;
9623 attrdefs[j].adnum = adnum;
9624 attrdefs[j].adef_expr = pg_strdup(adsrc);
9625
9626 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
9627 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
9628
9629 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
9630
9631 /*
9632 * Figure out whether the default/generation expression should be
9633 * dumped as part of the main CREATE TABLE (or similar) command or
9634 * as a separate ALTER TABLE (or similar) command. The preference
9635 * is to put it into the CREATE command, but in some cases that's
9636 * not possible.
9637 */
9638 if (tbinfo->attgenerated[adnum - 1])
9639 {
9640 /*
9641 * Column generation expressions cannot be dumped separately,
9642 * because there is no syntax for it. By setting separate to
9643 * false here we prevent the "default" from being processed as
9644 * its own dumpable object. Later, flagInhAttrs() will mark
9645 * it as not to be dumped at all, if possible (that is, if it
9646 * can be inherited from a parent).
9647 */
9648 attrdefs[j].separate = false;
9649 }
9650 else if (tbinfo->relkind == RELKIND_VIEW)
9651 {
9652 /*
9653 * Defaults on a VIEW must always be dumped as separate ALTER
9654 * TABLE commands.
9655 */
9656 attrdefs[j].separate = true;
9657 }
9658 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
9659 {
9660 /* column will be suppressed, print default separately */
9661 attrdefs[j].separate = true;
9662 }
9663 else
9664 {
9665 attrdefs[j].separate = false;
9666 }
9667
9668 if (!attrdefs[j].separate)
9669 {
9670 /*
9671 * Mark the default as needing to appear before the table, so
9672 * that any dependencies it has must be emitted before the
9673 * CREATE TABLE. If this is not possible, we'll change to
9674 * "separate" mode while sorting dependencies.
9675 */
9677 attrdefs[j].dobj.dumpId);
9678 }
9679
9680 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
9681 }
9682
9683 PQclear(res);
9684 }
9685
9686 /*
9687 * Get info about NOT NULL NOT VALID constraints. This is skipped for a
9688 * data-only dump, as it is only needed for table schemas.
9689 */
9690 if (dopt->dumpSchema && invalidnotnulloids)
9691 {
9693 int numConstrs;
9694 int i_tableoid;
9695 int i_oid;
9696 int i_conrelid;
9697 int i_conname;
9698 int i_consrc;
9699 int i_conislocal;
9700
9701 pg_log_info("finding invalid not-null constraints");
9702
9705 "SELECT c.tableoid, c.oid, conrelid, conname, "
9706 "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9707 "conislocal, convalidated "
9708 "FROM unnest('%s'::pg_catalog.oid[]) AS src(conoid)\n"
9709 "JOIN pg_catalog.pg_constraint c ON (src.conoid = c.oid)\n"
9710 "ORDER BY c.conrelid, c.conname",
9711 invalidnotnulloids->data);
9712
9714
9715 numConstrs = PQntuples(res);
9717
9718 i_tableoid = PQfnumber(res, "tableoid");
9719 i_oid = PQfnumber(res, "oid");
9720 i_conrelid = PQfnumber(res, "conrelid");
9721 i_conname = PQfnumber(res, "conname");
9722 i_consrc = PQfnumber(res, "consrc");
9723 i_conislocal = PQfnumber(res, "conislocal");
9724
9725 /* As above, this loop iterates once per table, not once per row */
9726 curtblindx = -1;
9727 for (int j = 0; j < numConstrs;)
9728 {
9729 Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9731 int numcons;
9732
9733 /* Count rows for this table */
9734 for (numcons = 1; numcons < numConstrs - j; numcons++)
9735 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9736 break;
9737
9738 /*
9739 * Locate the associated TableInfo; we rely on tblinfo[] being in
9740 * OID order.
9741 */
9742 while (++curtblindx < numTables)
9743 {
9744 tbinfo = &tblinfo[curtblindx];
9745 if (tbinfo->dobj.catId.oid == conrelid)
9746 break;
9747 }
9748 if (curtblindx >= numTables)
9749 pg_fatal("unrecognized table OID %u", conrelid);
9750
9751 for (int c = 0; c < numcons; c++, j++)
9752 {
9753 constrs[j].dobj.objType = DO_CONSTRAINT;
9754 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9755 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
9756 AssignDumpId(&constrs[j].dobj);
9757 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
9758 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
9759 constrs[j].contable = tbinfo;
9760 constrs[j].condomain = NULL;
9761 constrs[j].contype = 'n';
9762 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
9763 constrs[j].confrelid = InvalidOid;
9764 constrs[j].conindex = 0;
9765 constrs[j].condeferrable = false;
9766 constrs[j].condeferred = false;
9767 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9768
9769 /*
9770 * All invalid not-null constraints must be dumped separately,
9771 * because CREATE TABLE would not create them as invalid, and
9772 * also because they must be created after potentially
9773 * violating data has been loaded.
9774 */
9775 constrs[j].separate = true;
9776
9777 constrs[j].dobj.dump = tbinfo->dobj.dump;
9778 }
9779 }
9780 PQclear(res);
9781 }
9782
9783 /*
9784 * Get info about table CHECK constraints. This is skipped for a
9785 * data-only dump, as it is only needed for table schemas.
9786 */
9787 if (dopt->dumpSchema && checkoids->len > 2)
9788 {
9790 int numConstrs;
9791 int i_tableoid;
9792 int i_oid;
9793 int i_conrelid;
9794 int i_conname;
9795 int i_consrc;
9796 int i_conislocal;
9797 int i_convalidated;
9798
9799 pg_log_info("finding table check constraints");
9800
9803 "SELECT c.tableoid, c.oid, conrelid, conname, "
9804 "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9805 "conislocal, convalidated "
9806 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9807 "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
9808 "WHERE contype = 'c' "
9809 "ORDER BY c.conrelid, c.conname",
9810 checkoids->data);
9811
9813
9814 numConstrs = PQntuples(res);
9816
9817 i_tableoid = PQfnumber(res, "tableoid");
9818 i_oid = PQfnumber(res, "oid");
9819 i_conrelid = PQfnumber(res, "conrelid");
9820 i_conname = PQfnumber(res, "conname");
9821 i_consrc = PQfnumber(res, "consrc");
9822 i_conislocal = PQfnumber(res, "conislocal");
9823 i_convalidated = PQfnumber(res, "convalidated");
9824
9825 /* As above, this loop iterates once per table, not once per row */
9826 curtblindx = -1;
9827 for (int j = 0; j < numConstrs;)
9828 {
9829 Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9831 int numcons;
9832
9833 /* Count rows for this table */
9834 for (numcons = 1; numcons < numConstrs - j; numcons++)
9835 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9836 break;
9837
9838 /*
9839 * Locate the associated TableInfo; we rely on tblinfo[] being in
9840 * OID order.
9841 */
9842 while (++curtblindx < numTables)
9843 {
9844 tbinfo = &tblinfo[curtblindx];
9845 if (tbinfo->dobj.catId.oid == conrelid)
9846 break;
9847 }
9848 if (curtblindx >= numTables)
9849 pg_fatal("unrecognized table OID %u", conrelid);
9850
9851 if (numcons != tbinfo->ncheck)
9852 {
9853 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
9854 "expected %d check constraints on table \"%s\" but found %d",
9855 tbinfo->ncheck),
9856 tbinfo->ncheck, tbinfo->dobj.name, numcons);
9857 pg_log_error_hint("The system catalogs might be corrupted.");
9858 exit_nicely(1);
9859 }
9860
9861 tbinfo->checkexprs = constrs + j;
9862
9863 for (int c = 0; c < numcons; c++, j++)
9864 {
9865 bool validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
9866
9867 constrs[j].dobj.objType = DO_CONSTRAINT;
9868 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9869 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
9870 AssignDumpId(&constrs[j].dobj);
9871 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
9872 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
9873 constrs[j].contable = tbinfo;
9874 constrs[j].condomain = NULL;
9875 constrs[j].contype = 'c';
9876 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
9877 constrs[j].confrelid = InvalidOid;
9878 constrs[j].conindex = 0;
9879 constrs[j].condeferrable = false;
9880 constrs[j].condeferred = false;
9881 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9882
9883 /*
9884 * An unvalidated constraint needs to be dumped separately, so
9885 * that potentially-violating existing data is loaded before
9886 * the constraint.
9887 */
9888 constrs[j].separate = !validated;
9889
9890 constrs[j].dobj.dump = tbinfo->dobj.dump;
9891
9892 /*
9893 * Mark the constraint as needing to appear before the table
9894 * --- this is so that any other dependencies of the
9895 * constraint will be emitted before we try to create the
9896 * table. If the constraint is to be dumped separately, it
9897 * will be dumped after data is loaded anyway, so don't do it.
9898 * (There's an automatic dependency in the opposite direction
9899 * anyway, so don't need to add one manually here.)
9900 */
9901 if (!constrs[j].separate)
9903 constrs[j].dobj.dumpId);
9904
9905 /*
9906 * We will detect later whether the constraint must be split
9907 * out from the table definition.
9908 */
9909 }
9910 }
9911
9912 PQclear(res);
9913 }
9914
9918}
9919
9920/*
9921 * Based on the getTableAttrs query's row corresponding to one column, set
9922 * the name and flags to handle a not-null constraint for that column in
9923 * the tbinfo struct.
9924 *
9925 * Result row 'r' is for tbinfo's attribute 'j'.
9926 *
9927 * There are four possibilities:
9928 * 1) the column has no not-null constraints. In that case, ->notnull_constrs
9929 * (the constraint name) remains NULL.
9930 * 2) The column has a constraint with no name (this is the case when
9931 * constraints come from pre-18 servers). In this case, ->notnull_constrs
9932 * is set to the empty string; dumpTableSchema will print just "NOT NULL".
9933 * 3) The column has an invalid not-null constraint. This must be treated
9934 * as a separate object (because it must be created after the table data
9935 * is loaded). So we add its OID to invalidnotnulloids for processing
9936 * elsewhere and do nothing further with it here. We distinguish this
9937 * case because the "notnull_invalidoid" column has been set to a non-NULL
9938 * value, which is the constraint OID. Valid constraints have a null OID.
9939 * 4) The column has a constraint with a known name; in that case
9940 * notnull_constrs carries that name and dumpTableSchema will print
9941 * "CONSTRAINT the_name NOT NULL". However, if the name is the default
9942 * (table_column_not_null) and there's no comment on the constraint,
9943 * there's no need to print that name in the dump, so notnull_constrs
9944 * is set to the empty string and it behaves as case 2.
9945 *
9946 * In a child table that inherits from a parent already containing NOT NULL
9947 * constraints and the columns in the child don't have their own NOT NULL
9948 * declarations, we suppress printing constraints in the child: the
9949 * constraints are acquired at the point where the child is attached to the
9950 * parent. This is tracked in ->notnull_islocal; for servers pre-18 this is
9951 * set not here but in flagInhAttrs. That flag is also used when the
9952 * constraint was validated in a child but all its parent have it as NOT
9953 * VALID.
9954 *
9955 * Any of these constraints might have the NO INHERIT bit. If so we set
9956 * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
9957 *
9958 * In case 4 above, the name comparison is a bit of a hack; it actually fails
9959 * to do the right thing in all but the trivial case. However, the downside
9960 * of getting it wrong is simply that the name is printed rather than
9961 * suppressed, so it's not a big deal.
9962 *
9963 * invalidnotnulloids is expected to be given as NULL; if any invalid not-null
9964 * constraints are found, it is initialized and filled with the array of
9965 * OIDs of such constraints, for later processing.
9966 */
9967static void
9969 TableInfo *tbinfo, int j,
9970 int i_notnull_name,
9976{
9977 DumpOptions *dopt = fout->dopt;
9978
9979 /*
9980 * If this not-null constraint is not valid, list its OID in
9981 * invalidnotnulloids and do nothing further. It'll be processed
9982 * elsewhere later.
9983 *
9984 * Because invalid not-null constraints are rare, we don't want to malloc
9985 * invalidnotnulloids until we're sure we're going it need it, which
9986 * happens here.
9987 */
9988 if (!PQgetisnull(res, r, i_notnull_invalidoid))
9989 {
9990 char *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
9991
9992 if (*invalidnotnulloids == NULL)
9993 {
9997 }
9998 else
10000
10001 /*
10002 * Track when a parent constraint is invalid for the cases where a
10003 * child constraint has been validated independenly.
10004 */
10005 tbinfo->notnull_invalid[j] = true;
10006
10007 /* nothing else to do */
10008 tbinfo->notnull_constrs[j] = NULL;
10009 return;
10010 }
10011
10012 /*
10013 * notnull_noinh is straight from the query result. notnull_islocal also,
10014 * though flagInhAttrs may change that one later.
10015 */
10016 tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
10017 tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
10018 tbinfo->notnull_invalid[j] = false;
10019
10020 /*
10021 * Determine a constraint name to use. If the column is not marked not-
10022 * null, we set NULL which cues ... to do nothing. An empty string says
10023 * to print an unnamed NOT NULL, and anything else is a constraint name to
10024 * use.
10025 */
10026 if (fout->remoteVersion < 180000)
10027 {
10028 /*
10029 * < 18 doesn't have not-null names, so an unnamed constraint is
10030 * sufficient.
10031 */
10032 if (PQgetisnull(res, r, i_notnull_name))
10033 tbinfo->notnull_constrs[j] = NULL;
10034 else
10035 tbinfo->notnull_constrs[j] = "";
10036 }
10037 else
10038 {
10039 if (PQgetisnull(res, r, i_notnull_name))
10040 tbinfo->notnull_constrs[j] = NULL;
10041 else
10042 {
10043 /*
10044 * In binary upgrade of inheritance child tables, must have a
10045 * constraint name that we can UPDATE later; same if there's a
10046 * comment on the constraint.
10047 */
10048 if ((dopt->binary_upgrade &&
10049 !tbinfo->ispartition &&
10050 !tbinfo->notnull_islocal[j]) ||
10052 {
10053 tbinfo->notnull_constrs[j] =
10055 }
10056 else
10057 {
10058 char *default_name;
10059
10060 /* XXX should match ChooseConstraintName better */
10061 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
10062 tbinfo->attnames[j]);
10063 if (strcmp(default_name,
10064 PQgetvalue(res, r, i_notnull_name)) == 0)
10065 tbinfo->notnull_constrs[j] = "";
10066 else
10067 {
10068 tbinfo->notnull_constrs[j] =
10070 }
10072 }
10073 }
10074 }
10075}
10076
10077/*
10078 * Test whether a column should be printed as part of table's CREATE TABLE.
10079 * Column number is zero-based.
10080 *
10081 * Normally this is always true, but it's false for dropped columns, as well
10082 * as those that were inherited without any local definition. (If we print
10083 * such a column it will mistakenly get pg_attribute.attislocal set to true.)
10084 * For partitions, it's always true, because we want the partitions to be
10085 * created independently and ATTACH PARTITION used afterwards.
10086 *
10087 * In binary_upgrade mode, we must print all columns and fix the attislocal/
10088 * attisdropped state later, so as to keep control of the physical column
10089 * order.
10090 *
10091 * This function exists because there are scattered nonobvious places that
10092 * must be kept in sync with this decision.
10093 */
10094bool
10095shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
10096{
10097 if (dopt->binary_upgrade)
10098 return true;
10099 if (tbinfo->attisdropped[colno])
10100 return false;
10101 return (tbinfo->attislocal[colno] || tbinfo->ispartition);
10102}
10103
10104
10105/*
10106 * getTSParsers:
10107 * get information about all text search parsers in the system catalogs
10108 */
10109void
10111{
10112 PGresult *res;
10113 int ntups;
10114 int i;
10115 PQExpBuffer query;
10117 int i_tableoid;
10118 int i_oid;
10119 int i_prsname;
10120 int i_prsnamespace;
10121 int i_prsstart;
10122 int i_prstoken;
10123 int i_prsend;
10124 int i_prsheadline;
10125 int i_prslextype;
10126
10127 query = createPQExpBuffer();
10128
10129 /*
10130 * find all text search objects, including builtin ones; we filter out
10131 * system-defined objects at dump-out time.
10132 */
10133
10134 appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
10135 "prsstart::oid, prstoken::oid, "
10136 "prsend::oid, prsheadline::oid, prslextype::oid "
10137 "FROM pg_ts_parser");
10138
10139 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10140
10141 ntups = PQntuples(res);
10142
10144
10145 i_tableoid = PQfnumber(res, "tableoid");
10146 i_oid = PQfnumber(res, "oid");
10147 i_prsname = PQfnumber(res, "prsname");
10148 i_prsnamespace = PQfnumber(res, "prsnamespace");
10149 i_prsstart = PQfnumber(res, "prsstart");
10150 i_prstoken = PQfnumber(res, "prstoken");
10151 i_prsend = PQfnumber(res, "prsend");
10152 i_prsheadline = PQfnumber(res, "prsheadline");
10153 i_prslextype = PQfnumber(res, "prslextype");
10154
10155 for (i = 0; i < ntups; i++)
10156 {
10157 prsinfo[i].dobj.objType = DO_TSPARSER;
10158 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10159 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10160 AssignDumpId(&prsinfo[i].dobj);
10161 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
10162 prsinfo[i].dobj.namespace =
10164 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
10165 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
10166 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
10167 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
10168 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
10169
10170 /* Decide whether we want to dump it */
10172 }
10173
10174 PQclear(res);
10175
10176 destroyPQExpBuffer(query);
10177}
10178
10179/*
10180 * getTSDictionaries:
10181 * get information about all text search dictionaries in the system catalogs
10182 */
10183void
10185{
10186 PGresult *res;
10187 int ntups;
10188 int i;
10189 PQExpBuffer query;
10191 int i_tableoid;
10192 int i_oid;
10193 int i_dictname;
10194 int i_dictnamespace;
10195 int i_dictowner;
10196 int i_dicttemplate;
10197 int i_dictinitoption;
10198
10199 query = createPQExpBuffer();
10200
10201 appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
10202 "dictnamespace, dictowner, "
10203 "dicttemplate, dictinitoption "
10204 "FROM pg_ts_dict");
10205
10206 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10207
10208 ntups = PQntuples(res);
10209
10211
10212 i_tableoid = PQfnumber(res, "tableoid");
10213 i_oid = PQfnumber(res, "oid");
10214 i_dictname = PQfnumber(res, "dictname");
10215 i_dictnamespace = PQfnumber(res, "dictnamespace");
10216 i_dictowner = PQfnumber(res, "dictowner");
10217 i_dictinitoption = PQfnumber(res, "dictinitoption");
10218 i_dicttemplate = PQfnumber(res, "dicttemplate");
10219
10220 for (i = 0; i < ntups; i++)
10221 {
10222 dictinfo[i].dobj.objType = DO_TSDICT;
10223 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10224 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10225 AssignDumpId(&dictinfo[i].dobj);
10226 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
10227 dictinfo[i].dobj.namespace =
10229 dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
10230 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
10231 if (PQgetisnull(res, i, i_dictinitoption))
10232 dictinfo[i].dictinitoption = NULL;
10233 else
10234 dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
10235
10236 /* Decide whether we want to dump it */
10238 }
10239
10240 PQclear(res);
10241
10242 destroyPQExpBuffer(query);
10243}
10244
10245/*
10246 * getTSTemplates:
10247 * get information about all text search templates in the system catalogs
10248 */
10249void
10251{
10252 PGresult *res;
10253 int ntups;
10254 int i;
10255 PQExpBuffer query;
10257 int i_tableoid;
10258 int i_oid;
10259 int i_tmplname;
10260 int i_tmplnamespace;
10261 int i_tmplinit;
10262 int i_tmpllexize;
10263
10264 query = createPQExpBuffer();
10265
10266 appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
10267 "tmplnamespace, tmplinit::oid, tmpllexize::oid "
10268 "FROM pg_ts_template");
10269
10270 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10271
10272 ntups = PQntuples(res);
10273
10275
10276 i_tableoid = PQfnumber(res, "tableoid");
10277 i_oid = PQfnumber(res, "oid");
10278 i_tmplname = PQfnumber(res, "tmplname");
10279 i_tmplnamespace = PQfnumber(res, "tmplnamespace");
10280 i_tmplinit = PQfnumber(res, "tmplinit");
10281 i_tmpllexize = PQfnumber(res, "tmpllexize");
10282
10283 for (i = 0; i < ntups; i++)
10284 {
10285 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
10286 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10287 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10288 AssignDumpId(&tmplinfo[i].dobj);
10289 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
10290 tmplinfo[i].dobj.namespace =
10292 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
10293 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
10294
10295 /* Decide whether we want to dump it */
10297 }
10298
10299 PQclear(res);
10300
10301 destroyPQExpBuffer(query);
10302}
10303
10304/*
10305 * getTSConfigurations:
10306 * get information about all text search configurations
10307 */
10308void
10310{
10311 PGresult *res;
10312 int ntups;
10313 int i;
10314 PQExpBuffer query;
10316 int i_tableoid;
10317 int i_oid;
10318 int i_cfgname;
10319 int i_cfgnamespace;
10320 int i_cfgowner;
10321 int i_cfgparser;
10322
10323 query = createPQExpBuffer();
10324
10325 appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
10326 "cfgnamespace, cfgowner, cfgparser "
10327 "FROM pg_ts_config");
10328
10329 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10330
10331 ntups = PQntuples(res);
10332
10334
10335 i_tableoid = PQfnumber(res, "tableoid");
10336 i_oid = PQfnumber(res, "oid");
10337 i_cfgname = PQfnumber(res, "cfgname");
10338 i_cfgnamespace = PQfnumber(res, "cfgnamespace");
10339 i_cfgowner = PQfnumber(res, "cfgowner");
10340 i_cfgparser = PQfnumber(res, "cfgparser");
10341
10342 for (i = 0; i < ntups; i++)
10343 {
10344 cfginfo[i].dobj.objType = DO_TSCONFIG;
10345 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10346 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10347 AssignDumpId(&cfginfo[i].dobj);
10348 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
10349 cfginfo[i].dobj.namespace =
10351 cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
10352 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
10353
10354 /* Decide whether we want to dump it */
10356 }
10357
10358 PQclear(res);
10359
10360 destroyPQExpBuffer(query);
10361}
10362
10363/*
10364 * getForeignDataWrappers:
10365 * get information about all foreign-data wrappers in the system catalogs
10366 */
10367void
10369{
10370 PGresult *res;
10371 int ntups;
10372 int i;
10373 PQExpBuffer query;
10375 int i_tableoid;
10376 int i_oid;
10377 int i_fdwname;
10378 int i_fdwowner;
10379 int i_fdwhandler;
10380 int i_fdwvalidator;
10381 int i_fdwconnection;
10382 int i_fdwacl;
10383 int i_acldefault;
10384 int i_fdwoptions;
10385
10386 query = createPQExpBuffer();
10387
10388 appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
10389 "fdwowner, "
10390 "fdwhandler::pg_catalog.regproc, "
10391 "fdwvalidator::pg_catalog.regproc, ");
10392
10393 if (fout->remoteVersion >= 190000)
10394 appendPQExpBufferStr(query, "fdwconnection::pg_catalog.regproc, ");
10395 else
10396 appendPQExpBufferStr(query, "'-' AS fdwconnection, ");
10397
10399 "fdwacl, "
10400 "acldefault('F', fdwowner) AS acldefault, "
10401 "array_to_string(ARRAY("
10402 "SELECT quote_ident(option_name) || ' ' || "
10403 "quote_literal(option_value) "
10404 "FROM pg_options_to_table(fdwoptions) "
10405 "ORDER BY option_name"
10406 "), E',\n ') AS fdwoptions "
10407 "FROM pg_foreign_data_wrapper");
10408
10409 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10410
10411 ntups = PQntuples(res);
10412
10414
10415 i_tableoid = PQfnumber(res, "tableoid");
10416 i_oid = PQfnumber(res, "oid");
10417 i_fdwname = PQfnumber(res, "fdwname");
10418 i_fdwowner = PQfnumber(res, "fdwowner");
10419 i_fdwhandler = PQfnumber(res, "fdwhandler");
10420 i_fdwvalidator = PQfnumber(res, "fdwvalidator");
10421 i_fdwconnection = PQfnumber(res, "fdwconnection");
10422 i_fdwacl = PQfnumber(res, "fdwacl");
10423 i_acldefault = PQfnumber(res, "acldefault");
10424 i_fdwoptions = PQfnumber(res, "fdwoptions");
10425
10426 for (i = 0; i < ntups; i++)
10427 {
10428 fdwinfo[i].dobj.objType = DO_FDW;
10429 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10430 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10431 AssignDumpId(&fdwinfo[i].dobj);
10432 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
10433 fdwinfo[i].dobj.namespace = NULL;
10434 fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
10435 fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10436 fdwinfo[i].dacl.privtype = 0;
10437 fdwinfo[i].dacl.initprivs = NULL;
10438 fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
10439 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
10440 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
10441 fdwinfo[i].fdwconnection = pg_strdup(PQgetvalue(res, i, i_fdwconnection));
10442 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
10443
10444 /* Decide whether we want to dump it */
10446
10447 /* Mark whether FDW has an ACL */
10448 if (!PQgetisnull(res, i, i_fdwacl))
10449 fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10450 }
10451
10452 PQclear(res);
10453
10454 destroyPQExpBuffer(query);
10455}
10456
10457/*
10458 * getForeignServers:
10459 * get information about all foreign servers in the system catalogs
10460 */
10461void
10463{
10464 PGresult *res;
10465 int ntups;
10466 int i;
10467 PQExpBuffer query;
10469 int i_tableoid;
10470 int i_oid;
10471 int i_srvname;
10472 int i_srvowner;
10473 int i_srvfdw;
10474 int i_srvtype;
10475 int i_srvversion;
10476 int i_srvacl;
10477 int i_acldefault;
10478 int i_srvoptions;
10479
10480 query = createPQExpBuffer();
10481
10482 appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
10483 "srvowner, "
10484 "srvfdw, srvtype, srvversion, srvacl, "
10485 "acldefault('S', srvowner) AS acldefault, "
10486 "array_to_string(ARRAY("
10487 "SELECT quote_ident(option_name) || ' ' || "
10488 "quote_literal(option_value) "
10489 "FROM pg_options_to_table(srvoptions) "
10490 "ORDER BY option_name"
10491 "), E',\n ') AS srvoptions "
10492 "FROM pg_foreign_server");
10493
10494 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10495
10496 ntups = PQntuples(res);
10497
10499
10500 i_tableoid = PQfnumber(res, "tableoid");
10501 i_oid = PQfnumber(res, "oid");
10502 i_srvname = PQfnumber(res, "srvname");
10503 i_srvowner = PQfnumber(res, "srvowner");
10504 i_srvfdw = PQfnumber(res, "srvfdw");
10505 i_srvtype = PQfnumber(res, "srvtype");
10506 i_srvversion = PQfnumber(res, "srvversion");
10507 i_srvacl = PQfnumber(res, "srvacl");
10508 i_acldefault = PQfnumber(res, "acldefault");
10509 i_srvoptions = PQfnumber(res, "srvoptions");
10510
10511 for (i = 0; i < ntups; i++)
10512 {
10513 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
10514 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10515 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10516 AssignDumpId(&srvinfo[i].dobj);
10517 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
10518 srvinfo[i].dobj.namespace = NULL;
10519 srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
10520 srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10521 srvinfo[i].dacl.privtype = 0;
10522 srvinfo[i].dacl.initprivs = NULL;
10523 srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
10524 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
10525 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
10526 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
10527 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
10528
10529 /* Decide whether we want to dump it */
10531
10532 /* Servers have user mappings */
10533 srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
10534
10535 /* Mark whether server has an ACL */
10536 if (!PQgetisnull(res, i, i_srvacl))
10537 srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10538 }
10539
10540 PQclear(res);
10541
10542 destroyPQExpBuffer(query);
10543}
10544
10545/*
10546 * getDefaultACLs:
10547 * get information about all default ACL information in the system catalogs
10548 */
10549void
10551{
10552 DumpOptions *dopt = fout->dopt;
10554 PQExpBuffer query;
10555 PGresult *res;
10556 int i_oid;
10557 int i_tableoid;
10558 int i_defaclrole;
10560 int i_defaclobjtype;
10561 int i_defaclacl;
10562 int i_acldefault;
10563 int i,
10564 ntups;
10565
10566 query = createPQExpBuffer();
10567
10568 /*
10569 * Global entries (with defaclnamespace=0) replace the hard-wired default
10570 * ACL for their object type. We should dump them as deltas from the
10571 * default ACL, since that will be used as a starting point for
10572 * interpreting the ALTER DEFAULT PRIVILEGES commands. On the other hand,
10573 * non-global entries can only add privileges not revoke them. We must
10574 * dump those as-is (i.e., as deltas from an empty ACL).
10575 *
10576 * We can use defaclobjtype as the object type for acldefault(), except
10577 * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
10578 * 's'.
10579 */
10581 "SELECT oid, tableoid, "
10582 "defaclrole, "
10583 "defaclnamespace, "
10584 "defaclobjtype, "
10585 "defaclacl, "
10586 "CASE WHEN defaclnamespace = 0 THEN "
10587 "acldefault(CASE WHEN defaclobjtype = 'S' "
10588 "THEN 's'::\"char\" ELSE defaclobjtype END, "
10589 "defaclrole) ELSE '{}' END AS acldefault "
10590 "FROM pg_default_acl");
10591
10592 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10593
10594 ntups = PQntuples(res);
10595
10597
10598 i_oid = PQfnumber(res, "oid");
10599 i_tableoid = PQfnumber(res, "tableoid");
10600 i_defaclrole = PQfnumber(res, "defaclrole");
10601 i_defaclnamespace = PQfnumber(res, "defaclnamespace");
10602 i_defaclobjtype = PQfnumber(res, "defaclobjtype");
10603 i_defaclacl = PQfnumber(res, "defaclacl");
10604 i_acldefault = PQfnumber(res, "acldefault");
10605
10606 for (i = 0; i < ntups; i++)
10607 {
10609
10610 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
10611 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10612 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10613 AssignDumpId(&daclinfo[i].dobj);
10614 /* cheesy ... is it worth coming up with a better object name? */
10615 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
10616
10617 if (nspid != InvalidOid)
10618 daclinfo[i].dobj.namespace = findNamespace(nspid);
10619 else
10620 daclinfo[i].dobj.namespace = NULL;
10621
10622 daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
10623 daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10624 daclinfo[i].dacl.privtype = 0;
10625 daclinfo[i].dacl.initprivs = NULL;
10626 daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
10627 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
10628
10629 /* Default ACLs are ACLs, of course */
10630 daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10631
10632 /* Decide whether we want to dump it */
10634 }
10635
10636 PQclear(res);
10637
10638 destroyPQExpBuffer(query);
10639}
10640
10641/*
10642 * getRoleName -- look up the name of a role, given its OID
10643 *
10644 * In current usage, we don't expect failures, so error out for a bad OID.
10645 */
10646static const char *
10647getRoleName(const char *roleoid_str)
10648{
10649 Oid roleoid = atooid(roleoid_str);
10650
10651 /*
10652 * Do binary search to find the appropriate item.
10653 */
10654 if (nrolenames > 0)
10655 {
10656 RoleNameItem *low = &rolenames[0];
10657 RoleNameItem *high = &rolenames[nrolenames - 1];
10658
10659 while (low <= high)
10660 {
10661 RoleNameItem *middle = low + (high - low) / 2;
10662
10663 if (roleoid < middle->roleoid)
10664 high = middle - 1;
10665 else if (roleoid > middle->roleoid)
10666 low = middle + 1;
10667 else
10668 return middle->rolename; /* found a match */
10669 }
10670 }
10671
10672 pg_fatal("role with OID %u does not exist", roleoid);
10673 return NULL; /* keep compiler quiet */
10674}
10675
10676/*
10677 * collectRoleNames --
10678 *
10679 * Construct a table of all known roles.
10680 * The table is sorted by OID for speed in lookup.
10681 */
10682static void
10684{
10685 PGresult *res;
10686 const char *query;
10687 int i;
10688
10689 query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
10690
10691 res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
10692
10693 nrolenames = PQntuples(res);
10694
10696
10697 for (i = 0; i < nrolenames; i++)
10698 {
10699 rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
10701 }
10702
10703 PQclear(res);
10704}
10705
10706/*
10707 * getAdditionalACLs
10708 *
10709 * We have now created all the DumpableObjects, and collected the ACL data
10710 * that appears in the directly-associated catalog entries. However, there's
10711 * more ACL-related info to collect. If any of a table's columns have ACLs,
10712 * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
10713 * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
10714 * Also, in versions having the pg_init_privs catalog, read that and load the
10715 * information into the relevant DumpableObjects.
10716 */
10717static void
10719{
10721 PGresult *res;
10722 int ntups,
10723 i;
10724
10725 /* Check for per-column ACLs */
10727 "SELECT DISTINCT attrelid FROM pg_attribute "
10728 "WHERE attacl IS NOT NULL");
10729
10730 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10731
10732 ntups = PQntuples(res);
10733 for (i = 0; i < ntups; i++)
10734 {
10735 Oid relid = atooid(PQgetvalue(res, i, 0));
10736 TableInfo *tblinfo;
10737
10738 tblinfo = findTableByOid(relid);
10739 /* OK to ignore tables we haven't got a DumpableObject for */
10740 if (tblinfo)
10741 {
10743 tblinfo->hascolumnACLs = true;
10744 }
10745 }
10746 PQclear(res);
10747
10748 /* Fetch initial-privileges data */
10749 printfPQExpBuffer(query,
10750 "SELECT objoid, classoid, objsubid, privtype, initprivs "
10751 "FROM pg_init_privs");
10752
10753 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10754
10755 ntups = PQntuples(res);
10756 for (i = 0; i < ntups; i++)
10757 {
10758 Oid objoid = atooid(PQgetvalue(res, i, 0));
10759 Oid classoid = atooid(PQgetvalue(res, i, 1));
10760 int objsubid = atoi(PQgetvalue(res, i, 2));
10761 char privtype = *(PQgetvalue(res, i, 3));
10762 char *initprivs = PQgetvalue(res, i, 4);
10763 CatalogId objId;
10764 DumpableObject *dobj;
10765
10766 objId.tableoid = classoid;
10767 objId.oid = objoid;
10768 dobj = findObjectByCatalogId(objId);
10769 /* OK to ignore entries we haven't got a DumpableObject for */
10770 if (dobj)
10771 {
10772 /* Cope with sub-object initprivs */
10773 if (objsubid != 0)
10774 {
10775 if (dobj->objType == DO_TABLE)
10776 {
10777 /* For a column initprivs, set the table's ACL flags */
10779 ((TableInfo *) dobj)->hascolumnACLs = true;
10780 }
10781 else
10782 pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10783 classoid, objoid, objsubid);
10784 continue;
10785 }
10786
10787 /*
10788 * We ignore any pg_init_privs.initprivs entry for the public
10789 * schema, as explained in getNamespaces().
10790 */
10791 if (dobj->objType == DO_NAMESPACE &&
10792 strcmp(dobj->name, "public") == 0)
10793 continue;
10794
10795 /* Else it had better be of a type we think has ACLs */
10796 if (dobj->objType == DO_NAMESPACE ||
10797 dobj->objType == DO_TYPE ||
10798 dobj->objType == DO_FUNC ||
10799 dobj->objType == DO_AGG ||
10800 dobj->objType == DO_TABLE ||
10801 dobj->objType == DO_PROCLANG ||
10802 dobj->objType == DO_FDW ||
10803 dobj->objType == DO_FOREIGN_SERVER)
10804 {
10806
10807 daobj->dacl.privtype = privtype;
10808 daobj->dacl.initprivs = pstrdup(initprivs);
10809 }
10810 else
10811 pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10812 classoid, objoid, objsubid);
10813 }
10814 }
10815 PQclear(res);
10816
10817 destroyPQExpBuffer(query);
10818}
10819
10820/*
10821 * dumpCommentExtended --
10822 *
10823 * This routine is used to dump any comments associated with the
10824 * object handed to this routine. The routine takes the object type
10825 * and object name (ready to print, except for schema decoration), plus
10826 * the namespace and owner of the object (for labeling the ArchiveEntry),
10827 * plus catalog ID and subid which are the lookup key for pg_description,
10828 * plus the dump ID for the object (for setting a dependency).
10829 * If a matching pg_description entry is found, it is dumped.
10830 *
10831 * Note: in some cases, such as comments for triggers and rules, the "type"
10832 * string really looks like, e.g., "TRIGGER name ON". This is a bit of a hack
10833 * but it doesn't seem worth complicating the API for all callers to make
10834 * it cleaner.
10835 *
10836 * Note: although this routine takes a dumpId for dependency purposes,
10837 * that purpose is just to mark the dependency in the emitted dump file
10838 * for possible future use by pg_restore. We do NOT use it for determining
10839 * ordering of the comment in the dump file, because this routine is called
10840 * after dependency sorting occurs. This routine should be called just after
10841 * calling ArchiveEntry() for the specified object.
10842 */
10843static void
10844dumpCommentExtended(Archive *fout, const char *type,
10845 const char *name, const char *namespace,
10846 const char *owner, CatalogId catalogId,
10847 int subid, DumpId dumpId,
10848 const char *initdb_comment)
10849{
10850 DumpOptions *dopt = fout->dopt;
10852 int ncomments;
10853
10854 /* do nothing, if --no-comments is supplied */
10855 if (dopt->no_comments)
10856 return;
10857
10858 /* Comments are schema not data ... except LO comments are data */
10859 if (strcmp(type, "LARGE OBJECT") != 0)
10860 {
10861 if (!dopt->dumpSchema)
10862 return;
10863 }
10864 else
10865 {
10866 /* We do dump LO comments in binary-upgrade mode */
10867 if (!dopt->dumpData && !dopt->binary_upgrade)
10868 return;
10869 }
10870
10871 /* Search for comments associated with catalogId, using table */
10872 ncomments = findComments(catalogId.tableoid, catalogId.oid,
10873 &comments);
10874
10875 /* Is there one matching the subid? */
10876 while (ncomments > 0)
10877 {
10878 if (comments->objsubid == subid)
10879 break;
10880 comments++;
10881 ncomments--;
10882 }
10883
10884 if (initdb_comment != NULL)
10885 {
10886 static CommentItem empty_comment = {.descr = ""};
10887
10888 /*
10889 * initdb creates this object with a comment. Skip dumping the
10890 * initdb-provided comment, which would complicate matters for
10891 * non-superuser use of pg_dump. When the DBA has removed initdb's
10892 * comment, replicate that.
10893 */
10894 if (ncomments == 0)
10895 {
10897 ncomments = 1;
10898 }
10899 else if (strcmp(comments->descr, initdb_comment) == 0)
10900 ncomments = 0;
10901 }
10902
10903 /* If a comment exists, build COMMENT ON statement */
10904 if (ncomments > 0)
10905 {
10908
10909 appendPQExpBuffer(query, "COMMENT ON %s ", type);
10910 if (namespace && *namespace)
10911 appendPQExpBuffer(query, "%s.", fmtId(namespace));
10912 appendPQExpBuffer(query, "%s IS ", name);
10914 appendPQExpBufferStr(query, ";\n");
10915
10916 appendPQExpBuffer(tag, "%s %s", type, name);
10917
10918 /*
10919 * We mark comments as SECTION_NONE because they really belong in the
10920 * same section as their parent, whether that is pre-data or
10921 * post-data.
10922 */
10924 ARCHIVE_OPTS(.tag = tag->data,
10925 .namespace = namespace,
10926 .owner = owner,
10927 .description = "COMMENT",
10928 .section = SECTION_NONE,
10929 .createStmt = query->data,
10930 .deps = &dumpId,
10931 .nDeps = 1));
10932
10933 destroyPQExpBuffer(query);
10934 destroyPQExpBuffer(tag);
10935 }
10936}
10937
10938/*
10939 * dumpComment --
10940 *
10941 * Typical simplification of the above function.
10942 */
10943static inline void
10944dumpComment(Archive *fout, const char *type,
10945 const char *name, const char *namespace,
10946 const char *owner, CatalogId catalogId,
10947 int subid, DumpId dumpId)
10948{
10949 dumpCommentExtended(fout, type, name, namespace, owner,
10950 catalogId, subid, dumpId, NULL);
10951}
10952
10953/*
10954 * appendNamedArgument --
10955 *
10956 * Convenience routine for constructing parameters of the form:
10957 * 'paraname', 'value'::type
10958 */
10959static void
10960appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
10961 const char *argtype, const char *argval)
10962{
10963 appendPQExpBufferStr(out, ",\n\t");
10964
10965 appendStringLiteralAH(out, argname, fout);
10966 appendPQExpBufferStr(out, ", ");
10967
10969 appendPQExpBuffer(out, "::%s", argtype);
10970}
10971
10972/*
10973 * fetchAttributeStats --
10974 *
10975 * Fetch next batch of attribute statistics for dumpRelationStats_dumper().
10976 */
10977static PGresult *
10979{
10981 PQExpBuffer relids = createPQExpBuffer();
10984 int count = 0;
10985 PGresult *res = NULL;
10986 static TocEntry *te;
10987 static bool restarted;
10989
10990 /* If we're just starting, set our TOC pointer. */
10991 if (!te)
10992 te = AH->toc->next;
10993
10994 /*
10995 * We can't easily avoid a second TOC scan for the tar format because it
10996 * writes restore.sql separately, which means we must execute the queries
10997 * twice. This feels risky, but there is no known reason it should
10998 * generate different output than the first pass. Even if it does, the
10999 * worst-case scenario is that restore.sql might have different statistics
11000 * data than the archive.
11001 */
11002 if (!restarted && te == AH->toc && AH->format == archTar)
11003 {
11004 te = AH->toc->next;
11005 restarted = true;
11006 }
11007
11008 appendPQExpBufferChar(relids, '{');
11011
11012 /*
11013 * Scan the TOC for the next set of relevant stats entries. We assume
11014 * that statistics are dumped in the order they are listed in the TOC.
11015 * This is perhaps not the sturdiest assumption, so we verify it matches
11016 * reality in dumpRelationStats_dumper().
11017 */
11018 for (; te != AH->toc && count < max_rels; te = te->next)
11019 {
11020 if ((te->reqs & REQ_STATS) == 0 ||
11021 strcmp(te->desc, "STATISTICS DATA") != 0)
11022 continue;
11023
11024 if (fout->remoteVersion >= 190000)
11025 {
11026 const RelStatsInfo *rsinfo = (const RelStatsInfo *) te->defnDumperArg;
11027 char relid[32];
11028
11029 sprintf(relid, "%u", rsinfo->relid);
11030 appendPGArray(relids, relid);
11031 }
11032 else
11033 {
11034 appendPGArray(nspnames, te->namespace);
11036 }
11037
11038 count++;
11039 }
11040
11041 appendPQExpBufferChar(relids, '}');
11044
11045 /* Execute the query for the next batch of relations. */
11046 if (count > 0)
11047 {
11049
11050 appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
11051
11052 if (fout->remoteVersion >= 190000)
11053 {
11054 appendStringLiteralAH(query, relids->data, fout);
11055 appendPQExpBufferStr(query, "::pg_catalog.oid[])");
11056 }
11057 else
11058 {
11059 appendStringLiteralAH(query, nspnames->data, fout);
11060 appendPQExpBufferStr(query, "::pg_catalog.name[],");
11061 appendStringLiteralAH(query, relnames->data, fout);
11062 appendPQExpBufferStr(query, "::pg_catalog.name[])");
11063 }
11064
11065 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11066 destroyPQExpBuffer(query);
11067 }
11068
11069 destroyPQExpBuffer(relids);
11072 return res;
11073}
11074
11075/*
11076 * dumpRelationStats_dumper --
11077 *
11078 * Generate command to import stats into the relation on the new database.
11079 * This routine is called by the Archiver when it wants the statistics to be
11080 * dumped.
11081 */
11082static char *
11083dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
11084{
11085 const RelStatsInfo *rsinfo = userArg;
11086 static PGresult *res;
11087 static int rownum;
11088 PQExpBuffer query;
11090 PQExpBuffer out = &out_data;
11091 int i_schemaname;
11092 int i_tablename;
11093 int i_attname;
11094 int i_inherited;
11095 int i_null_frac;
11096 int i_avg_width;
11097 int i_n_distinct;
11101 int i_correlation;
11108 static TocEntry *expected_te;
11109
11110 /*
11111 * fetchAttributeStats() assumes that the statistics are dumped in the
11112 * order they are listed in the TOC. We verify that here for safety.
11113 */
11114 if (!expected_te)
11115 expected_te = ((ArchiveHandle *) fout)->toc;
11116
11118 while ((expected_te->reqs & REQ_STATS) == 0 ||
11119 strcmp(expected_te->desc, "STATISTICS DATA") != 0)
11121
11122 if (te != expected_te)
11123 pg_fatal("statistics dumped out of order (current: %d %s %s, expected: %d %s %s)",
11124 te->dumpId, te->desc, te->tag,
11125 expected_te->dumpId, expected_te->desc, expected_te->tag);
11126
11127 query = createPQExpBuffer();
11128 if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
11129 {
11130 if (fout->remoteVersion >= 190000)
11132 "PREPARE getAttributeStats(pg_catalog.oid[]) AS\n");
11133 else
11135 "PREPARE getAttributeStats(pg_catalog.name[], pg_catalog.name[]) AS\n");
11136
11138 "SELECT s.schemaname, s.tablename, s.attname, s.inherited, "
11139 "s.null_frac, s.avg_width, s.n_distinct, "
11140 "s.most_common_vals, s.most_common_freqs, "
11141 "s.histogram_bounds, s.correlation, "
11142 "s.most_common_elems, s.most_common_elem_freqs, "
11143 "s.elem_count_histogram, ");
11144
11145 if (fout->remoteVersion >= 170000)
11147 "s.range_length_histogram, "
11148 "s.range_empty_frac, "
11149 "s.range_bounds_histogram ");
11150 else
11152 "NULL AS range_length_histogram,"
11153 "NULL AS range_empty_frac,"
11154 "NULL AS range_bounds_histogram ");
11155
11156 /*
11157 * The results must be in the order of the relations supplied in the
11158 * parameters to ensure we remain in sync as we walk through the TOC.
11159 *
11160 * For versions before 19, the redundant filter clause on s.tablename
11161 * = ANY(...) seems sufficient to convince the planner to use
11162 * pg_class_relname_nsp_index, which avoids a full scan of pg_stats.
11163 * In newer versions, pg_stats returns the table OIDs, eliminating the
11164 * need for that hack.
11165 */
11166 if (fout->remoteVersion >= 190000)
11168 "FROM pg_catalog.pg_stats s "
11169 "JOIN unnest($1) WITH ORDINALITY AS u (tableid, ord) "
11170 "ON s.tableid = u.tableid "
11171 "ORDER BY u.ord, s.attname, s.inherited");
11172 else
11174 "FROM pg_catalog.pg_stats s "
11175 "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) "
11176 "ON s.schemaname = u.schemaname "
11177 "AND s.tablename = u.tablename "
11178 "WHERE s.tablename = ANY($2) "
11179 "ORDER BY u.ord, s.attname, s.inherited");
11180
11181 ExecuteSqlStatement(fout, query->data);
11182
11183 fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
11184 resetPQExpBuffer(query);
11185 }
11186
11187 initPQExpBuffer(out);
11188
11189 /* restore relation stats */
11190 appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
11191 appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
11192 fout->remoteVersion);
11193 appendPQExpBufferStr(out, "\t'schemaname', ");
11194 appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
11195 appendPQExpBufferStr(out, ",\n");
11196 appendPQExpBufferStr(out, "\t'relname', ");
11197 appendStringLiteralAH(out, rsinfo->dobj.name, fout);
11198 appendPQExpBufferStr(out, ",\n");
11199 appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
11200
11201 /*
11202 * Before v14, a reltuples value of 0 was ambiguous: it could either mean
11203 * the relation is empty, or it could mean that it hadn't yet been
11204 * vacuumed or analyzed. (Newer versions use -1 for the latter case.)
11205 * This ambiguity allegedly can cause the planner to choose inefficient
11206 * plans after restoring to v18 or newer. To deal with this, let's just
11207 * set reltuples to -1 in that case.
11208 */
11209 if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
11210 appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
11211 else
11212 appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
11213
11214 appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
11215 rsinfo->relallvisible);
11216
11217 if (fout->remoteVersion >= 180000)
11218 appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
11219
11220 appendPQExpBufferStr(out, "\n);\n");
11221
11222 /* Fetch the next batch of attribute statistics if needed. */
11223 if (rownum >= PQntuples(res))
11224 {
11225 PQclear(res);
11227 rownum = 0;
11228 }
11229
11230 i_schemaname = PQfnumber(res, "schemaname");
11231 i_tablename = PQfnumber(res, "tablename");
11232 i_attname = PQfnumber(res, "attname");
11233 i_inherited = PQfnumber(res, "inherited");
11234 i_null_frac = PQfnumber(res, "null_frac");
11235 i_avg_width = PQfnumber(res, "avg_width");
11236 i_n_distinct = PQfnumber(res, "n_distinct");
11237 i_most_common_vals = PQfnumber(res, "most_common_vals");
11238 i_most_common_freqs = PQfnumber(res, "most_common_freqs");
11239 i_histogram_bounds = PQfnumber(res, "histogram_bounds");
11240 i_correlation = PQfnumber(res, "correlation");
11241 i_most_common_elems = PQfnumber(res, "most_common_elems");
11242 i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
11243 i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
11244 i_range_length_histogram = PQfnumber(res, "range_length_histogram");
11245 i_range_empty_frac = PQfnumber(res, "range_empty_frac");
11246 i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
11247
11248 /* restore attribute stats */
11249 for (; rownum < PQntuples(res); rownum++)
11250 {
11251 const char *attname;
11252
11253 /* Stop if the next stat row in our cache isn't for this relation. */
11254 if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
11255 strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
11256 break;
11257
11258 appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
11259 appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
11260 fout->remoteVersion);
11261 appendPQExpBufferStr(out, "\t'schemaname', ");
11262 appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
11263 appendPQExpBufferStr(out, ",\n\t'relname', ");
11264 appendStringLiteralAH(out, rsinfo->dobj.name, fout);
11265
11266 if (PQgetisnull(res, rownum, i_attname))
11267 pg_fatal("unexpected null attname");
11268 attname = PQgetvalue(res, rownum, i_attname);
11269
11270 /*
11271 * Indexes look up attname in indAttNames to derive attnum, all others
11272 * use attname directly. We must specify attnum for indexes, since
11273 * their attnames are not necessarily stable across dump/reload.
11274 */
11275 if (rsinfo->nindAttNames == 0)
11276 {
11277 appendPQExpBufferStr(out, ",\n\t'attname', ");
11279 }
11280 else
11281 {
11282 bool found = false;
11283
11284 for (int i = 0; i < rsinfo->nindAttNames; i++)
11285 {
11286 if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
11287 {
11288 appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
11289 i + 1);
11290 found = true;
11291 break;
11292 }
11293 }
11294
11295 if (!found)
11296 pg_fatal("could not find index attname \"%s\"", attname);
11297 }
11298
11299 if (!PQgetisnull(res, rownum, i_inherited))
11300 appendNamedArgument(out, fout, "inherited", "boolean",
11301 PQgetvalue(res, rownum, i_inherited));
11302 if (!PQgetisnull(res, rownum, i_null_frac))
11303 appendNamedArgument(out, fout, "null_frac", "real",
11304 PQgetvalue(res, rownum, i_null_frac));
11305 if (!PQgetisnull(res, rownum, i_avg_width))
11306 appendNamedArgument(out, fout, "avg_width", "integer",
11307 PQgetvalue(res, rownum, i_avg_width));
11308 if (!PQgetisnull(res, rownum, i_n_distinct))
11309 appendNamedArgument(out, fout, "n_distinct", "real",
11310 PQgetvalue(res, rownum, i_n_distinct));
11311 if (!PQgetisnull(res, rownum, i_most_common_vals))
11312 appendNamedArgument(out, fout, "most_common_vals", "text",
11313 PQgetvalue(res, rownum, i_most_common_vals));
11314 if (!PQgetisnull(res, rownum, i_most_common_freqs))
11315 appendNamedArgument(out, fout, "most_common_freqs", "real[]",
11316 PQgetvalue(res, rownum, i_most_common_freqs));
11317 if (!PQgetisnull(res, rownum, i_histogram_bounds))
11318 appendNamedArgument(out, fout, "histogram_bounds", "text",
11319 PQgetvalue(res, rownum, i_histogram_bounds));
11320 if (!PQgetisnull(res, rownum, i_correlation))
11321 appendNamedArgument(out, fout, "correlation", "real",
11322 PQgetvalue(res, rownum, i_correlation));
11323 if (!PQgetisnull(res, rownum, i_most_common_elems))
11324 appendNamedArgument(out, fout, "most_common_elems", "text",
11325 PQgetvalue(res, rownum, i_most_common_elems));
11326 if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
11327 appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
11328 PQgetvalue(res, rownum, i_most_common_elem_freqs));
11329 if (!PQgetisnull(res, rownum, i_elem_count_histogram))
11330 appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
11331 PQgetvalue(res, rownum, i_elem_count_histogram));
11332 if (fout->remoteVersion >= 170000)
11333 {
11334 if (!PQgetisnull(res, rownum, i_range_length_histogram))
11335 appendNamedArgument(out, fout, "range_length_histogram", "text",
11336 PQgetvalue(res, rownum, i_range_length_histogram));
11337 if (!PQgetisnull(res, rownum, i_range_empty_frac))
11338 appendNamedArgument(out, fout, "range_empty_frac", "real",
11339 PQgetvalue(res, rownum, i_range_empty_frac));
11340 if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
11341 appendNamedArgument(out, fout, "range_bounds_histogram", "text",
11342 PQgetvalue(res, rownum, i_range_bounds_histogram));
11343 }
11344 appendPQExpBufferStr(out, "\n);\n");
11345 }
11346
11347 destroyPQExpBuffer(query);
11348 return out->data;
11349}
11350
11351/*
11352 * dumpRelationStats --
11353 *
11354 * Make an ArchiveEntry for the relation statistics. The Archiver will take
11355 * care of gathering the statistics and generating the restore commands when
11356 * they are needed.
11357 */
11358static void
11360{
11361 const DumpableObject *dobj = &rsinfo->dobj;
11362
11363 /* nothing to do if we are not dumping statistics */
11364 if (!fout->dopt->dumpStatistics)
11365 return;
11366
11368 ARCHIVE_OPTS(.tag = dobj->name,
11369 .namespace = dobj->namespace->dobj.name,
11370 .description = "STATISTICS DATA",
11371 .section = rsinfo->section,
11372 .defnFn = dumpRelationStats_dumper,
11373 .defnArg = rsinfo,
11374 .deps = dobj->dependencies,
11375 .nDeps = dobj->nDeps));
11376}
11377
11378/*
11379 * dumpTableComment --
11380 *
11381 * As above, but dump comments for both the specified table (or view)
11382 * and its columns.
11383 */
11384static void
11386 const char *reltypename)
11387{
11388 DumpOptions *dopt = fout->dopt;
11390 int ncomments;
11391 PQExpBuffer query;
11392 PQExpBuffer tag;
11393
11394 /* do nothing, if --no-comments is supplied */
11395 if (dopt->no_comments)
11396 return;
11397
11398 /* Comments are SCHEMA not data */
11399 if (!dopt->dumpSchema)
11400 return;
11401
11402 /* Search for comments associated with relation, using table */
11403 ncomments = findComments(tbinfo->dobj.catId.tableoid,
11404 tbinfo->dobj.catId.oid,
11405 &comments);
11406
11407 /* If comments exist, build COMMENT ON statements */
11408 if (ncomments <= 0)
11409 return;
11410
11411 query = createPQExpBuffer();
11412 tag = createPQExpBuffer();
11413
11414 while (ncomments > 0)
11415 {
11416 const char *descr = comments->descr;
11417 int objsubid = comments->objsubid;
11418
11419 if (objsubid == 0)
11420 {
11421 resetPQExpBuffer(tag);
11422 appendPQExpBuffer(tag, "%s %s", reltypename,
11423 fmtId(tbinfo->dobj.name));
11424
11425 resetPQExpBuffer(query);
11426 appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
11428 appendStringLiteralAH(query, descr, fout);
11429 appendPQExpBufferStr(query, ";\n");
11430
11432 ARCHIVE_OPTS(.tag = tag->data,
11433 .namespace = tbinfo->dobj.namespace->dobj.name,
11434 .owner = tbinfo->rolname,
11435 .description = "COMMENT",
11436 .section = SECTION_NONE,
11437 .createStmt = query->data,
11438 .deps = &(tbinfo->dobj.dumpId),
11439 .nDeps = 1));
11440 }
11441 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
11442 {
11443 resetPQExpBuffer(tag);
11444 appendPQExpBuffer(tag, "COLUMN %s.",
11445 fmtId(tbinfo->dobj.name));
11446 appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
11447
11448 resetPQExpBuffer(query);
11449 appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11451 appendPQExpBuffer(query, "%s IS ",
11452 fmtId(tbinfo->attnames[objsubid - 1]));
11453 appendStringLiteralAH(query, descr, fout);
11454 appendPQExpBufferStr(query, ";\n");
11455
11457 ARCHIVE_OPTS(.tag = tag->data,
11458 .namespace = tbinfo->dobj.namespace->dobj.name,
11459 .owner = tbinfo->rolname,
11460 .description = "COMMENT",
11461 .section = SECTION_NONE,
11462 .createStmt = query->data,
11463 .deps = &(tbinfo->dobj.dumpId),
11464 .nDeps = 1));
11465 }
11466
11467 comments++;
11468 ncomments--;
11469 }
11470
11471 destroyPQExpBuffer(query);
11472 destroyPQExpBuffer(tag);
11473}
11474
11475/*
11476 * findComments --
11477 *
11478 * Find the comment(s), if any, associated with the given object. All the
11479 * objsubid values associated with the given classoid/objoid are found with
11480 * one search.
11481 */
11482static int
11483findComments(Oid classoid, Oid objoid, CommentItem **items)
11484{
11486 CommentItem *low;
11487 CommentItem *high;
11488 int nmatch;
11489
11490 /*
11491 * Do binary search to find some item matching the object.
11492 */
11493 low = &comments[0];
11494 high = &comments[ncomments - 1];
11495 while (low <= high)
11496 {
11497 middle = low + (high - low) / 2;
11498
11499 if (classoid < middle->classoid)
11500 high = middle - 1;
11501 else if (classoid > middle->classoid)
11502 low = middle + 1;
11503 else if (objoid < middle->objoid)
11504 high = middle - 1;
11505 else if (objoid > middle->objoid)
11506 low = middle + 1;
11507 else
11508 break; /* found a match */
11509 }
11510
11511 if (low > high) /* no matches */
11512 {
11513 *items = NULL;
11514 return 0;
11515 }
11516
11517 /*
11518 * Now determine how many items match the object. The search loop
11519 * invariant still holds: only items between low and high inclusive could
11520 * match.
11521 */
11522 nmatch = 1;
11523 while (middle > low)
11524 {
11525 if (classoid != middle[-1].classoid ||
11526 objoid != middle[-1].objoid)
11527 break;
11528 middle--;
11529 nmatch++;
11530 }
11531
11532 *items = middle;
11533
11534 middle += nmatch;
11535 while (middle <= high)
11536 {
11537 if (classoid != middle->classoid ||
11538 objoid != middle->objoid)
11539 break;
11540 middle++;
11541 nmatch++;
11542 }
11543
11544 return nmatch;
11545}
11546
11547/*
11548 * collectComments --
11549 *
11550 * Construct a table of all comments available for database objects;
11551 * also set the has-comment component flag for each relevant object.
11552 *
11553 * We used to do per-object queries for the comments, but it's much faster
11554 * to pull them all over at once, and on most databases the memory cost
11555 * isn't high.
11556 *
11557 * The table is sorted by classoid/objid/objsubid for speed in lookup.
11558 */
11559static void
11561{
11562 PGresult *res;
11563 PQExpBuffer query;
11564 int i_description;
11565 int i_classoid;
11566 int i_objoid;
11567 int i_objsubid;
11568 int ntups;
11569 int i;
11570 DumpableObject *dobj;
11571
11572 query = createPQExpBuffer();
11573
11574 appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
11575 "FROM pg_catalog.pg_description "
11576 "ORDER BY classoid, objoid, objsubid");
11577
11578 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11579
11580 /* Construct lookup table containing OIDs in numeric form */
11581
11582 i_description = PQfnumber(res, "description");
11583 i_classoid = PQfnumber(res, "classoid");
11584 i_objoid = PQfnumber(res, "objoid");
11585 i_objsubid = PQfnumber(res, "objsubid");
11586
11587 ntups = PQntuples(res);
11588
11590 ncomments = 0;
11591 dobj = NULL;
11592
11593 for (i = 0; i < ntups; i++)
11594 {
11595 CatalogId objId;
11596 int subid;
11597
11598 objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
11599 objId.oid = atooid(PQgetvalue(res, i, i_objoid));
11600 subid = atoi(PQgetvalue(res, i, i_objsubid));
11601
11602 /* We needn't remember comments that don't match any dumpable object */
11603 if (dobj == NULL ||
11604 dobj->catId.tableoid != objId.tableoid ||
11605 dobj->catId.oid != objId.oid)
11606 dobj = findObjectByCatalogId(objId);
11607 if (dobj == NULL)
11608 continue;
11609
11610 /*
11611 * Comments on columns of composite types are linked to the type's
11612 * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
11613 * in the type's own DumpableObject.
11614 */
11615 if (subid != 0 && dobj->objType == DO_TABLE &&
11616 ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
11617 {
11619
11620 cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
11621 if (cTypeInfo)
11622 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
11623 }
11624 else
11625 dobj->components |= DUMP_COMPONENT_COMMENT;
11626
11629 comments[ncomments].objoid = objId.oid;
11630 comments[ncomments].objsubid = subid;
11631 ncomments++;
11632 }
11633
11634 PQclear(res);
11635 destroyPQExpBuffer(query);
11636}
11637
11638/*
11639 * dumpDumpableObject
11640 *
11641 * This routine and its subsidiaries are responsible for creating
11642 * ArchiveEntries (TOC objects) for each object to be dumped.
11643 */
11644static void
11646{
11647 /*
11648 * Clear any dump-request bits for components that don't exist for this
11649 * object. (This makes it safe to initially use DUMP_COMPONENT_ALL as the
11650 * request for every kind of object.)
11651 */
11652 dobj->dump &= dobj->components;
11653
11654 /* Now, short-circuit if there's nothing to be done here. */
11655 if (dobj->dump == 0)
11656 return;
11657
11658 switch (dobj->objType)
11659 {
11660 case DO_NAMESPACE:
11661 dumpNamespace(fout, (const NamespaceInfo *) dobj);
11662 break;
11663 case DO_EXTENSION:
11664 dumpExtension(fout, (const ExtensionInfo *) dobj);
11665 break;
11666 case DO_TYPE:
11667 dumpType(fout, (const TypeInfo *) dobj);
11668 break;
11669 case DO_SHELL_TYPE:
11670 dumpShellType(fout, (const ShellTypeInfo *) dobj);
11671 break;
11672 case DO_FUNC:
11673 dumpFunc(fout, (const FuncInfo *) dobj);
11674 break;
11675 case DO_AGG:
11676 dumpAgg(fout, (const AggInfo *) dobj);
11677 break;
11678 case DO_OPERATOR:
11679 dumpOpr(fout, (const OprInfo *) dobj);
11680 break;
11681 case DO_ACCESS_METHOD:
11682 dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
11683 break;
11684 case DO_OPCLASS:
11685 dumpOpclass(fout, (const OpclassInfo *) dobj);
11686 break;
11687 case DO_OPFAMILY:
11688 dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
11689 break;
11690 case DO_COLLATION:
11691 dumpCollation(fout, (const CollInfo *) dobj);
11692 break;
11693 case DO_CONVERSION:
11694 dumpConversion(fout, (const ConvInfo *) dobj);
11695 break;
11696 case DO_TABLE:
11697 dumpTable(fout, (const TableInfo *) dobj);
11698 break;
11699 case DO_TABLE_ATTACH:
11700 dumpTableAttach(fout, (const TableAttachInfo *) dobj);
11701 break;
11702 case DO_ATTRDEF:
11703 dumpAttrDef(fout, (const AttrDefInfo *) dobj);
11704 break;
11705 case DO_INDEX:
11706 dumpIndex(fout, (const IndxInfo *) dobj);
11707 break;
11708 case DO_INDEX_ATTACH:
11709 dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
11710 break;
11711 case DO_STATSEXT:
11712 dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
11713 dumpStatisticsExtStats(fout, (const StatsExtInfo *) dobj);
11714 break;
11715 case DO_REFRESH_MATVIEW:
11716 refreshMatViewData(fout, (const TableDataInfo *) dobj);
11717 break;
11718 case DO_RULE:
11719 dumpRule(fout, (const RuleInfo *) dobj);
11720 break;
11721 case DO_TRIGGER:
11722 dumpTrigger(fout, (const TriggerInfo *) dobj);
11723 break;
11724 case DO_EVENT_TRIGGER:
11725 dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
11726 break;
11727 case DO_CONSTRAINT:
11728 dumpConstraint(fout, (const ConstraintInfo *) dobj);
11729 break;
11730 case DO_FK_CONSTRAINT:
11731 dumpConstraint(fout, (const ConstraintInfo *) dobj);
11732 break;
11733 case DO_PROCLANG:
11734 dumpProcLang(fout, (const ProcLangInfo *) dobj);
11735 break;
11736 case DO_CAST:
11737 dumpCast(fout, (const CastInfo *) dobj);
11738 break;
11739 case DO_TRANSFORM:
11740 dumpTransform(fout, (const TransformInfo *) dobj);
11741 break;
11742 case DO_SEQUENCE_SET:
11743 dumpSequenceData(fout, (const TableDataInfo *) dobj);
11744 break;
11745 case DO_TABLE_DATA:
11746 dumpTableData(fout, (const TableDataInfo *) dobj);
11747 break;
11748 case DO_DUMMY_TYPE:
11749 /* table rowtypes and array types are never dumped separately */
11750 break;
11751 case DO_TSPARSER:
11752 dumpTSParser(fout, (const TSParserInfo *) dobj);
11753 break;
11754 case DO_TSDICT:
11755 dumpTSDictionary(fout, (const TSDictInfo *) dobj);
11756 break;
11757 case DO_TSTEMPLATE:
11758 dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
11759 break;
11760 case DO_TSCONFIG:
11761 dumpTSConfig(fout, (const TSConfigInfo *) dobj);
11762 break;
11763 case DO_FDW:
11764 dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
11765 break;
11766 case DO_FOREIGN_SERVER:
11767 dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
11768 break;
11769 case DO_DEFAULT_ACL:
11770 dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
11771 break;
11772 case DO_LARGE_OBJECT:
11773 dumpLO(fout, (const LoInfo *) dobj);
11774 break;
11776 if (dobj->dump & DUMP_COMPONENT_DATA)
11777 {
11778 LoInfo *loinfo;
11779 TocEntry *te;
11780
11782 if (loinfo == NULL)
11783 pg_fatal("missing metadata for large objects \"%s\"",
11784 dobj->name);
11785
11786 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
11787 ARCHIVE_OPTS(.tag = dobj->name,
11788 .owner = loinfo->rolname,
11789 .description = "BLOBS",
11790 .section = SECTION_DATA,
11791 .deps = dobj->dependencies,
11792 .nDeps = dobj->nDeps,
11793 .dumpFn = dumpLOs,
11794 .dumpArg = loinfo));
11795
11796 /*
11797 * Set the TocEntry's dataLength in case we are doing a
11798 * parallel dump and want to order dump jobs by table size.
11799 * (We need some size estimate for every TocEntry with a
11800 * DataDumper function.) We don't currently have any cheap
11801 * way to estimate the size of LOs, but fortunately it doesn't
11802 * matter too much as long as we get large batches of LOs
11803 * processed reasonably early. Assume 8K per blob.
11804 */
11805 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
11806 }
11807 break;
11808 case DO_POLICY:
11809 dumpPolicy(fout, (const PolicyInfo *) dobj);
11810 break;
11811 case DO_PUBLICATION:
11812 dumpPublication(fout, (const PublicationInfo *) dobj);
11813 break;
11814 case DO_PUBLICATION_REL:
11816 break;
11819 (const PublicationSchemaInfo *) dobj);
11820 break;
11821 case DO_SUBSCRIPTION:
11822 dumpSubscription(fout, (const SubscriptionInfo *) dobj);
11823 break;
11825 dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
11826 break;
11827 case DO_REL_STATS:
11828 dumpRelationStats(fout, (const RelStatsInfo *) dobj);
11829 break;
11832 /* never dumped, nothing to do */
11833 break;
11834 }
11835}
11836
11837/*
11838 * dumpNamespace
11839 * writes out to fout the queries to recreate a user-defined namespace
11840 */
11841static void
11843{
11844 DumpOptions *dopt = fout->dopt;
11845 PQExpBuffer q;
11847 char *qnspname;
11848
11849 /* Do nothing if not dumping schema */
11850 if (!dopt->dumpSchema)
11851 return;
11852
11853 q = createPQExpBuffer();
11855
11856 qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
11857
11858 if (nspinfo->create)
11859 {
11860 appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
11861 appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
11862 }
11863 else
11864 {
11865 /* see selectDumpableNamespace() */
11867 "-- *not* dropping schema, since initdb creates it\n");
11869 "-- *not* creating schema, since initdb creates it\n");
11870 }
11871
11872 if (dopt->binary_upgrade)
11874 "SCHEMA", qnspname, NULL);
11875
11876 if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11877 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
11878 ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
11879 .owner = nspinfo->rolname,
11880 .description = "SCHEMA",
11881 .section = SECTION_PRE_DATA,
11882 .createStmt = q->data,
11883 .dropStmt = delq->data));
11884
11885 /* Dump Schema Comments and Security Labels */
11886 if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11887 {
11888 const char *initdb_comment = NULL;
11889
11890 if (!nspinfo->create && strcmp(qnspname, "public") == 0)
11891 initdb_comment = "standard public schema";
11893 NULL, nspinfo->rolname,
11894 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
11896 }
11897
11898 if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11899 dumpSecLabel(fout, "SCHEMA", qnspname,
11900 NULL, nspinfo->rolname,
11901 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
11902
11903 if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
11904 dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
11905 qnspname, NULL, NULL,
11906 NULL, nspinfo->rolname, &nspinfo->dacl);
11907
11909
11912}
11913
11914/*
11915 * dumpExtension
11916 * writes out to fout the queries to recreate an extension
11917 */
11918static void
11920{
11921 DumpOptions *dopt = fout->dopt;
11922 PQExpBuffer q;
11924 char *qextname;
11925
11926 /* Do nothing if not dumping schema */
11927 if (!dopt->dumpSchema)
11928 return;
11929
11930 q = createPQExpBuffer();
11932
11933 qextname = pg_strdup(fmtId(extinfo->dobj.name));
11934
11935 appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
11936
11937 if (!dopt->binary_upgrade)
11938 {
11939 /*
11940 * In a regular dump, we simply create the extension, intentionally
11941 * not specifying a version, so that the destination installation's
11942 * default version is used.
11943 *
11944 * Use of IF NOT EXISTS here is unlike our behavior for other object
11945 * types; but there are various scenarios in which it's convenient to
11946 * manually create the desired extension before restoring, so we
11947 * prefer to allow it to exist already.
11948 */
11949 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
11950 qextname, fmtId(extinfo->namespace));
11951 }
11952 else
11953 {
11954 /*
11955 * In binary-upgrade mode, it's critical to reproduce the state of the
11956 * database exactly, so our procedure is to create an empty extension,
11957 * restore all the contained objects normally, and add them to the
11958 * extension one by one. This function performs just the first of
11959 * those steps. binary_upgrade_extension_member() takes care of
11960 * adding member objects as they're created.
11961 */
11962 int i;
11963 int n;
11964
11965 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
11966
11967 /*
11968 * We unconditionally create the extension, so we must drop it if it
11969 * exists. This could happen if the user deleted 'plpgsql' and then
11970 * readded it, causing its oid to be greater than g_last_builtin_oid.
11971 */
11972 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
11973
11975 "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
11976 appendStringLiteralAH(q, extinfo->dobj.name, fout);
11977 appendPQExpBufferStr(q, ", ");
11978 appendStringLiteralAH(q, extinfo->namespace, fout);
11979 appendPQExpBufferStr(q, ", ");
11980 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
11981 appendStringLiteralAH(q, extinfo->extversion, fout);
11982 appendPQExpBufferStr(q, ", ");
11983
11984 /*
11985 * Note that we're pushing extconfig (an OID array) back into
11986 * pg_extension exactly as-is. This is OK because pg_class OIDs are
11987 * preserved in binary upgrade.
11988 */
11989 if (strlen(extinfo->extconfig) > 2)
11990 appendStringLiteralAH(q, extinfo->extconfig, fout);
11991 else
11992 appendPQExpBufferStr(q, "NULL");
11993 appendPQExpBufferStr(q, ", ");
11994 if (strlen(extinfo->extcondition) > 2)
11995 appendStringLiteralAH(q, extinfo->extcondition, fout);
11996 else
11997 appendPQExpBufferStr(q, "NULL");
11998 appendPQExpBufferStr(q, ", ");
11999 appendPQExpBufferStr(q, "ARRAY[");
12000 n = 0;
12001 for (i = 0; i < extinfo->dobj.nDeps; i++)
12002 {
12004
12005 extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
12006 if (extobj && extobj->objType == DO_EXTENSION)
12007 {
12008 if (n++ > 0)
12009 appendPQExpBufferChar(q, ',');
12011 }
12012 }
12013 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
12014 appendPQExpBufferStr(q, ");\n");
12015 }
12016
12017 if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12018 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
12019 ARCHIVE_OPTS(.tag = extinfo->dobj.name,
12020 .description = "EXTENSION",
12021 .section = SECTION_PRE_DATA,
12022 .createStmt = q->data,
12023 .dropStmt = delq->data));
12024
12025 /* Dump Extension Comments */
12026 if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12027 dumpComment(fout, "EXTENSION", qextname,
12028 NULL, "",
12029 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
12030
12032
12035}
12036
12037/*
12038 * dumpType
12039 * writes out to fout the queries to recreate a user-defined type
12040 */
12041static void
12043{
12044 DumpOptions *dopt = fout->dopt;
12045
12046 /* Do nothing if not dumping schema */
12047 if (!dopt->dumpSchema)
12048 return;
12049
12050 /* Dump out in proper style */
12051 if (tyinfo->typtype == TYPTYPE_BASE)
12053 else if (tyinfo->typtype == TYPTYPE_DOMAIN)
12055 else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
12057 else if (tyinfo->typtype == TYPTYPE_ENUM)
12059 else if (tyinfo->typtype == TYPTYPE_RANGE)
12061 else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
12063 else
12064 pg_log_warning("typtype of data type \"%s\" appears to be invalid",
12065 tyinfo->dobj.name);
12066}
12067
12068/*
12069 * dumpEnumType
12070 * writes out to fout the queries to recreate a user-defined enum type
12071 */
12072static void
12074{
12075 DumpOptions *dopt = fout->dopt;
12079 PGresult *res;
12080 int num,
12081 i;
12082 Oid enum_oid;
12083 char *qtypname;
12084 char *qualtypname;
12085 char *label;
12086 int i_enumlabel;
12087 int i_oid;
12088
12089 if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
12090 {
12091 /* Set up query for enum-specific details */
12093 "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
12094 "SELECT oid, enumlabel "
12095 "FROM pg_catalog.pg_enum "
12096 "WHERE enumtypid = $1 "
12097 "ORDER BY enumsortorder");
12098
12099 ExecuteSqlStatement(fout, query->data);
12100
12101 fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
12102 }
12103
12104 printfPQExpBuffer(query,
12105 "EXECUTE dumpEnumType('%u')",
12106 tyinfo->dobj.catId.oid);
12107
12108 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12109
12110 num = PQntuples(res);
12111
12112 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12114
12115 /*
12116 * CASCADE shouldn't be required here as for normal types since the I/O
12117 * functions are generic and do not get dropped.
12118 */
12119 appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12120
12121 if (dopt->binary_upgrade)
12123 tyinfo->dobj.catId.oid,
12124 false, false);
12125
12126 appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
12127 qualtypname);
12128
12129 if (!dopt->binary_upgrade)
12130 {
12131 i_enumlabel = PQfnumber(res, "enumlabel");
12132
12133 /* Labels with server-assigned oids */
12134 for (i = 0; i < num; i++)
12135 {
12136 label = PQgetvalue(res, i, i_enumlabel);
12137 if (i > 0)
12138 appendPQExpBufferChar(q, ',');
12139 appendPQExpBufferStr(q, "\n ");
12141 }
12142 }
12143
12144 appendPQExpBufferStr(q, "\n);\n");
12145
12146 if (dopt->binary_upgrade)
12147 {
12148 i_oid = PQfnumber(res, "oid");
12149 i_enumlabel = PQfnumber(res, "enumlabel");
12150
12151 /* Labels with dump-assigned (preserved) oids */
12152 for (i = 0; i < num; i++)
12153 {
12154 enum_oid = atooid(PQgetvalue(res, i, i_oid));
12155 label = PQgetvalue(res, i, i_enumlabel);
12156
12157 if (i == 0)
12158 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
12160 "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
12161 enum_oid);
12162 appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
12164 appendPQExpBufferStr(q, ";\n\n");
12165 }
12166 }
12167
12168 if (dopt->binary_upgrade)
12170 "TYPE", qtypname,
12171 tyinfo->dobj.namespace->dobj.name);
12172
12173 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12174 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12175 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12176 .namespace = tyinfo->dobj.namespace->dobj.name,
12177 .owner = tyinfo->rolname,
12178 .description = "TYPE",
12179 .section = SECTION_PRE_DATA,
12180 .createStmt = q->data,
12181 .dropStmt = delq->data));
12182
12183 /* Dump Type Comments and Security Labels */
12184 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12185 dumpComment(fout, "TYPE", qtypname,
12186 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12187 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12188
12189 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12190 dumpSecLabel(fout, "TYPE", qtypname,
12191 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12192 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12193
12194 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12195 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12196 qtypname, NULL,
12197 tyinfo->dobj.namespace->dobj.name,
12198 NULL, tyinfo->rolname, &tyinfo->dacl);
12199
12200 PQclear(res);
12203 destroyPQExpBuffer(query);
12206}
12207
12208/*
12209 * dumpRangeType
12210 * writes out to fout the queries to recreate a user-defined range type
12211 */
12212static void
12214{
12215 DumpOptions *dopt = fout->dopt;
12219 PGresult *res;
12221 char *qtypname;
12222 char *qualtypname;
12223 char *procname;
12224
12225 if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
12226 {
12227 /* Set up query for range-specific details */
12229 "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
12230
12232 "SELECT ");
12233
12234 if (fout->remoteVersion >= 140000)
12236 "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
12237 else
12239 "NULL AS rngmultitype, ");
12240
12242 "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
12243 "opc.opcname AS opcname, "
12244 "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
12245 " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
12246 "opc.opcdefault, "
12247 "CASE WHEN rngcollation = st.typcollation THEN 0 "
12248 " ELSE rngcollation END AS collation, "
12249 "rngcanonical, rngsubdiff "
12250 "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
12251 " pg_catalog.pg_opclass opc "
12252 "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
12253 "rngtypid = $1");
12254
12255 ExecuteSqlStatement(fout, query->data);
12256
12257 fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
12258 }
12259
12260 printfPQExpBuffer(query,
12261 "EXECUTE dumpRangeType('%u')",
12262 tyinfo->dobj.catId.oid);
12263
12264 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12265
12266 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12268
12269 /*
12270 * CASCADE shouldn't be required here as for normal types since the I/O
12271 * functions are generic and do not get dropped.
12272 */
12273 appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12274
12275 if (dopt->binary_upgrade)
12277 tyinfo->dobj.catId.oid,
12278 false, true);
12279
12280 appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
12281 qualtypname);
12282
12283 appendPQExpBuffer(q, "\n subtype = %s",
12284 PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
12285
12286 if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
12287 appendPQExpBuffer(q, ",\n multirange_type_name = %s",
12288 PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
12289
12290 /* print subtype_opclass only if not default for subtype */
12291 if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
12292 {
12293 char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
12294 char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
12295
12296 appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
12297 fmtId(nspname));
12299 }
12300
12301 collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
12303 {
12305
12306 if (coll)
12307 appendPQExpBuffer(q, ",\n collation = %s",
12308 fmtQualifiedDumpable(coll));
12309 }
12310
12311 procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
12312 if (strcmp(procname, "-") != 0)
12313 appendPQExpBuffer(q, ",\n canonical = %s", procname);
12314
12315 procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
12316 if (strcmp(procname, "-") != 0)
12317 appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
12318
12319 appendPQExpBufferStr(q, "\n);\n");
12320
12321 if (dopt->binary_upgrade)
12323 "TYPE", qtypname,
12324 tyinfo->dobj.namespace->dobj.name);
12325
12326 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12327 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12328 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12329 .namespace = tyinfo->dobj.namespace->dobj.name,
12330 .owner = tyinfo->rolname,
12331 .description = "TYPE",
12332 .section = SECTION_PRE_DATA,
12333 .createStmt = q->data,
12334 .dropStmt = delq->data));
12335
12336 /* Dump Type Comments and Security Labels */
12337 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12338 dumpComment(fout, "TYPE", qtypname,
12339 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12340 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12341
12342 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12343 dumpSecLabel(fout, "TYPE", qtypname,
12344 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12345 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12346
12347 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12348 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12349 qtypname, NULL,
12350 tyinfo->dobj.namespace->dobj.name,
12351 NULL, tyinfo->rolname, &tyinfo->dacl);
12352
12353 PQclear(res);
12356 destroyPQExpBuffer(query);
12359}
12360
12361/*
12362 * dumpUndefinedType
12363 * writes out to fout the queries to recreate a !typisdefined type
12364 *
12365 * This is a shell type, but we use different terminology to distinguish
12366 * this case from where we have to emit a shell type definition to break
12367 * circular dependencies. An undefined type shouldn't ever have anything
12368 * depending on it.
12369 */
12370static void
12372{
12373 DumpOptions *dopt = fout->dopt;
12376 char *qtypname;
12377 char *qualtypname;
12378
12379 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12381
12382 appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12383
12384 if (dopt->binary_upgrade)
12386 tyinfo->dobj.catId.oid,
12387 false, false);
12388
12389 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
12390 qualtypname);
12391
12392 if (dopt->binary_upgrade)
12394 "TYPE", qtypname,
12395 tyinfo->dobj.namespace->dobj.name);
12396
12397 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12398 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12399 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12400 .namespace = tyinfo->dobj.namespace->dobj.name,
12401 .owner = tyinfo->rolname,
12402 .description = "TYPE",
12403 .section = SECTION_PRE_DATA,
12404 .createStmt = q->data,
12405 .dropStmt = delq->data));
12406
12407 /* Dump Type Comments and Security Labels */
12408 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12409 dumpComment(fout, "TYPE", qtypname,
12410 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12411 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12412
12413 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12414 dumpSecLabel(fout, "TYPE", qtypname,
12415 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12416 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12417
12418 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12419 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12420 qtypname, NULL,
12421 tyinfo->dobj.namespace->dobj.name,
12422 NULL, tyinfo->rolname, &tyinfo->dacl);
12423
12428}
12429
12430/*
12431 * dumpBaseType
12432 * writes out to fout the queries to recreate a user-defined base type
12433 */
12434static void
12436{
12437 DumpOptions *dopt = fout->dopt;
12441 PGresult *res;
12442 char *qtypname;
12443 char *qualtypname;
12444 char *typlen;
12445 char *typinput;
12446 char *typoutput;
12447 char *typreceive;
12448 char *typsend;
12449 char *typmodin;
12450 char *typmodout;
12451 char *typanalyze;
12452 char *typsubscript;
12459 char *typcategory;
12460 char *typispreferred;
12461 char *typdelim;
12462 char *typbyval;
12463 char *typalign;
12464 char *typstorage;
12465 char *typcollatable;
12466 char *typdefault;
12467 bool typdefault_is_literal = false;
12468
12469 if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
12470 {
12471 /* Set up query for type-specific details */
12473 "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
12474 "SELECT typlen, "
12475 "typinput, typoutput, typreceive, typsend, "
12476 "typreceive::pg_catalog.oid AS typreceiveoid, "
12477 "typsend::pg_catalog.oid AS typsendoid, "
12478 "typanalyze, "
12479 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
12480 "typdelim, typbyval, typalign, typstorage, "
12481 "typmodin, typmodout, "
12482 "typmodin::pg_catalog.oid AS typmodinoid, "
12483 "typmodout::pg_catalog.oid AS typmodoutoid, "
12484 "typcategory, typispreferred, "
12485 "(typcollation <> 0) AS typcollatable, "
12486 "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
12487
12488 if (fout->remoteVersion >= 140000)
12490 "typsubscript, "
12491 "typsubscript::pg_catalog.oid AS typsubscriptoid ");
12492 else
12494 "'-' AS typsubscript, 0 AS typsubscriptoid ");
12495
12496 appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
12497 "WHERE oid = $1");
12498
12499 ExecuteSqlStatement(fout, query->data);
12500
12501 fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
12502 }
12503
12504 printfPQExpBuffer(query,
12505 "EXECUTE dumpBaseType('%u')",
12506 tyinfo->dobj.catId.oid);
12507
12508 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12509
12510 typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
12511 typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
12512 typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
12513 typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
12514 typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
12515 typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
12516 typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
12517 typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
12518 typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
12519 typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
12520 typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
12521 typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
12522 typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
12523 typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
12524 typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
12525 typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
12526 typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
12527 typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
12528 typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
12529 typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
12530 typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
12531 typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
12532 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
12533 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
12534 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
12535 {
12536 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
12537 typdefault_is_literal = true; /* it needs quotes */
12538 }
12539 else
12540 typdefault = NULL;
12541
12542 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12544
12545 /*
12546 * The reason we include CASCADE is that the circular dependency between
12547 * the type and its I/O functions makes it impossible to drop the type any
12548 * other way.
12549 */
12550 appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
12551
12552 /*
12553 * We might already have a shell type, but setting pg_type_oid is
12554 * harmless, and in any case we'd better set the array type OID.
12555 */
12556 if (dopt->binary_upgrade)
12558 tyinfo->dobj.catId.oid,
12559 false, false);
12560
12562 "CREATE TYPE %s (\n"
12563 " INTERNALLENGTH = %s",
12565 (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
12566
12567 /* regproc result is sufficiently quoted already */
12568 appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
12569 appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
12571 appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
12573 appendPQExpBuffer(q, ",\n SEND = %s", typsend);
12575 appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
12577 appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
12579 appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
12580
12581 if (strcmp(typcollatable, "t") == 0)
12582 appendPQExpBufferStr(q, ",\n COLLATABLE = true");
12583
12584 if (typdefault != NULL)
12585 {
12586 appendPQExpBufferStr(q, ",\n DEFAULT = ");
12589 else
12591 }
12592
12594 appendPQExpBuffer(q, ",\n SUBSCRIPT = %s", typsubscript);
12595
12596 if (OidIsValid(tyinfo->typelem))
12597 appendPQExpBuffer(q, ",\n ELEMENT = %s",
12599 zeroIsError));
12600
12601 if (strcmp(typcategory, "U") != 0)
12602 {
12603 appendPQExpBufferStr(q, ",\n CATEGORY = ");
12605 }
12606
12607 if (strcmp(typispreferred, "t") == 0)
12608 appendPQExpBufferStr(q, ",\n PREFERRED = true");
12609
12610 if (typdelim && strcmp(typdelim, ",") != 0)
12611 {
12612 appendPQExpBufferStr(q, ",\n DELIMITER = ");
12613 appendStringLiteralAH(q, typdelim, fout);
12614 }
12615
12616 if (*typalign == TYPALIGN_CHAR)
12617 appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
12618 else if (*typalign == TYPALIGN_SHORT)
12619 appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
12620 else if (*typalign == TYPALIGN_INT)
12621 appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
12622 else if (*typalign == TYPALIGN_DOUBLE)
12623 appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
12624
12625 if (*typstorage == TYPSTORAGE_PLAIN)
12626 appendPQExpBufferStr(q, ",\n STORAGE = plain");
12627 else if (*typstorage == TYPSTORAGE_EXTERNAL)
12628 appendPQExpBufferStr(q, ",\n STORAGE = external");
12629 else if (*typstorage == TYPSTORAGE_EXTENDED)
12630 appendPQExpBufferStr(q, ",\n STORAGE = extended");
12631 else if (*typstorage == TYPSTORAGE_MAIN)
12632 appendPQExpBufferStr(q, ",\n STORAGE = main");
12633
12634 if (strcmp(typbyval, "t") == 0)
12635 appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
12636
12637 appendPQExpBufferStr(q, "\n);\n");
12638
12639 if (dopt->binary_upgrade)
12641 "TYPE", qtypname,
12642 tyinfo->dobj.namespace->dobj.name);
12643
12644 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12645 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12646 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12647 .namespace = tyinfo->dobj.namespace->dobj.name,
12648 .owner = tyinfo->rolname,
12649 .description = "TYPE",
12650 .section = SECTION_PRE_DATA,
12651 .createStmt = q->data,
12652 .dropStmt = delq->data));
12653
12654 /* Dump Type Comments and Security Labels */
12655 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12656 dumpComment(fout, "TYPE", qtypname,
12657 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12658 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12659
12660 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12661 dumpSecLabel(fout, "TYPE", qtypname,
12662 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12663 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12664
12665 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12666 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12667 qtypname, NULL,
12668 tyinfo->dobj.namespace->dobj.name,
12669 NULL, tyinfo->rolname, &tyinfo->dacl);
12670
12671 PQclear(res);
12674 destroyPQExpBuffer(query);
12677}
12678
12679/*
12680 * dumpDomain
12681 * writes out to fout the queries to recreate a user-defined domain
12682 */
12683static void
12685{
12686 DumpOptions *dopt = fout->dopt;
12690 PGresult *res;
12691 int i;
12692 char *qtypname;
12693 char *qualtypname;
12694 char *typnotnull;
12695 char *typdefn;
12696 char *typdefault;
12697 Oid typcollation;
12698 bool typdefault_is_literal = false;
12699
12700 if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
12701 {
12702 /* Set up query for domain-specific details */
12704 "PREPARE dumpDomain(pg_catalog.oid) AS\n");
12705
12706 appendPQExpBufferStr(query, "SELECT t.typnotnull, "
12707 "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
12708 "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
12709 "t.typdefault, "
12710 "CASE WHEN t.typcollation <> u.typcollation "
12711 "THEN t.typcollation ELSE 0 END AS typcollation "
12712 "FROM pg_catalog.pg_type t "
12713 "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
12714 "WHERE t.oid = $1");
12715
12716 ExecuteSqlStatement(fout, query->data);
12717
12718 fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
12719 }
12720
12721 printfPQExpBuffer(query,
12722 "EXECUTE dumpDomain('%u')",
12723 tyinfo->dobj.catId.oid);
12724
12725 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12726
12727 typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
12728 typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
12729 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
12730 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
12731 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
12732 {
12733 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
12734 typdefault_is_literal = true; /* it needs quotes */
12735 }
12736 else
12737 typdefault = NULL;
12738 typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
12739
12740 if (dopt->binary_upgrade)
12742 tyinfo->dobj.catId.oid,
12743 true, /* force array type */
12744 false); /* force multirange type */
12745
12746 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12748
12750 "CREATE DOMAIN %s AS %s",
12752 typdefn);
12753
12754 /* Print collation only if different from base type's collation */
12755 if (OidIsValid(typcollation))
12756 {
12757 CollInfo *coll;
12758
12759 coll = findCollationByOid(typcollation);
12760 if (coll)
12761 appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
12762 }
12763
12764 /*
12765 * Print a not-null constraint if there's one. In servers older than 17
12766 * these don't have names, so just print it unadorned; in newer ones they
12767 * do, but most of the time it's going to be the standard generated one,
12768 * so omit the name in that case also.
12769 */
12770 if (typnotnull[0] == 't')
12771 {
12772 if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
12773 appendPQExpBufferStr(q, " NOT NULL");
12774 else
12775 {
12776 ConstraintInfo *notnull = tyinfo->notnull;
12777
12778 if (!notnull->separate)
12779 {
12780 char *default_name;
12781
12782 /* XXX should match ChooseConstraintName better */
12783 default_name = psprintf("%s_not_null", tyinfo->dobj.name);
12784
12785 if (strcmp(default_name, notnull->dobj.name) == 0)
12786 appendPQExpBufferStr(q, " NOT NULL");
12787 else
12788 appendPQExpBuffer(q, " CONSTRAINT %s %s",
12789 fmtId(notnull->dobj.name), notnull->condef);
12791 }
12792 }
12793 }
12794
12795 if (typdefault != NULL)
12796 {
12797 appendPQExpBufferStr(q, " DEFAULT ");
12800 else
12802 }
12803
12804 PQclear(res);
12805
12806 /*
12807 * Add any CHECK constraints for the domain
12808 */
12809 for (i = 0; i < tyinfo->nDomChecks; i++)
12810 {
12811 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
12812
12813 if (!domcheck->separate && domcheck->contype == 'c')
12814 appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
12815 fmtId(domcheck->dobj.name), domcheck->condef);
12816 }
12817
12818 appendPQExpBufferStr(q, ";\n");
12819
12820 appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
12821
12822 if (dopt->binary_upgrade)
12824 "DOMAIN", qtypname,
12825 tyinfo->dobj.namespace->dobj.name);
12826
12827 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12828 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12829 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12830 .namespace = tyinfo->dobj.namespace->dobj.name,
12831 .owner = tyinfo->rolname,
12832 .description = "DOMAIN",
12833 .section = SECTION_PRE_DATA,
12834 .createStmt = q->data,
12835 .dropStmt = delq->data));
12836
12837 /* Dump Domain Comments and Security Labels */
12838 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12839 dumpComment(fout, "DOMAIN", qtypname,
12840 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12841 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12842
12843 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12844 dumpSecLabel(fout, "DOMAIN", qtypname,
12845 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12846 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12847
12848 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12849 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12850 qtypname, NULL,
12851 tyinfo->dobj.namespace->dobj.name,
12852 NULL, tyinfo->rolname, &tyinfo->dacl);
12853
12854 /* Dump any per-constraint comments */
12855 for (i = 0; i < tyinfo->nDomChecks; i++)
12856 {
12857 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
12859
12860 /* but only if the constraint itself was dumped here */
12861 if (domcheck->separate)
12862 continue;
12863
12865 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
12866 fmtId(domcheck->dobj.name));
12867
12868 if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
12870 tyinfo->dobj.namespace->dobj.name,
12871 tyinfo->rolname,
12872 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
12873
12875 }
12876
12877 /*
12878 * And a comment on the not-null constraint, if there's one -- but only if
12879 * the constraint itself was dumped here
12880 */
12881 if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
12882 {
12884
12885 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
12886 fmtId(tyinfo->notnull->dobj.name));
12887
12888 if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
12890 tyinfo->dobj.namespace->dobj.name,
12891 tyinfo->rolname,
12892 tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
12894 }
12895
12898 destroyPQExpBuffer(query);
12901}
12902
12903/*
12904 * dumpCompositeType
12905 * writes out to fout the queries to recreate a user-defined stand-alone
12906 * composite type
12907 */
12908static void
12910{
12911 DumpOptions *dopt = fout->dopt;
12913 PQExpBuffer dropped = createPQExpBuffer();
12916 PGresult *res;
12917 char *qtypname;
12918 char *qualtypname;
12919 int ntups;
12920 int i_attname;
12921 int i_atttypdefn;
12922 int i_attlen;
12923 int i_attalign;
12924 int i_attisdropped;
12925 int i_attcollation;
12926 int i;
12927 int actual_atts;
12928
12929 if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
12930 {
12931 /*
12932 * Set up query for type-specific details.
12933 *
12934 * Since we only want to dump COLLATE clauses for attributes whose
12935 * collation is different from their type's default, we use a CASE
12936 * here to suppress uninteresting attcollations cheaply. atttypid
12937 * will be 0 for dropped columns; collation does not matter for those.
12938 */
12940 "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
12941 "SELECT a.attname, a.attnum, "
12942 "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
12943 "a.attlen, a.attalign, a.attisdropped, "
12944 "CASE WHEN a.attcollation <> at.typcollation "
12945 "THEN a.attcollation ELSE 0 END AS attcollation "
12946 "FROM pg_catalog.pg_type ct "
12947 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
12948 "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
12949 "WHERE ct.oid = $1 "
12950 "ORDER BY a.attnum");
12951
12952 ExecuteSqlStatement(fout, query->data);
12953
12954 fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
12955 }
12956
12957 printfPQExpBuffer(query,
12958 "EXECUTE dumpCompositeType('%u')",
12959 tyinfo->dobj.catId.oid);
12960
12961 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12962
12963 ntups = PQntuples(res);
12964
12965 i_attname = PQfnumber(res, "attname");
12966 i_atttypdefn = PQfnumber(res, "atttypdefn");
12967 i_attlen = PQfnumber(res, "attlen");
12968 i_attalign = PQfnumber(res, "attalign");
12969 i_attisdropped = PQfnumber(res, "attisdropped");
12970 i_attcollation = PQfnumber(res, "attcollation");
12971
12972 if (dopt->binary_upgrade)
12973 {
12975 tyinfo->dobj.catId.oid,
12976 false, false);
12978 }
12979
12980 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12982
12983 appendPQExpBuffer(q, "CREATE TYPE %s AS (",
12984 qualtypname);
12985
12986 actual_atts = 0;
12987 for (i = 0; i < ntups; i++)
12988 {
12989 char *attname;
12990 char *atttypdefn;
12991 char *attlen;
12992 char *attalign;
12993 bool attisdropped;
12994 Oid attcollation;
12995
12996 attname = PQgetvalue(res, i, i_attname);
12998 attlen = PQgetvalue(res, i, i_attlen);
13000 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
13001 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
13002
13003 if (attisdropped && !dopt->binary_upgrade)
13004 continue;
13005
13006 /* Format properly if not first attr */
13007 if (actual_atts++ > 0)
13008 appendPQExpBufferChar(q, ',');
13009 appendPQExpBufferStr(q, "\n\t");
13010
13011 if (!attisdropped)
13012 {
13014
13015 /* Add collation if not default for the column type */
13016 if (OidIsValid(attcollation))
13017 {
13018 CollInfo *coll;
13019
13020 coll = findCollationByOid(attcollation);
13021 if (coll)
13022 appendPQExpBuffer(q, " COLLATE %s",
13023 fmtQualifiedDumpable(coll));
13024 }
13025 }
13026 else
13027 {
13028 /*
13029 * This is a dropped attribute and we're in binary_upgrade mode.
13030 * Insert a placeholder for it in the CREATE TYPE command, and set
13031 * length and alignment with direct UPDATE to the catalogs
13032 * afterwards. See similar code in dumpTableSchema().
13033 */
13034 appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
13035
13036 /* stash separately for insertion after the CREATE TYPE */
13037 appendPQExpBufferStr(dropped,
13038 "\n-- For binary upgrade, recreate dropped column.\n");
13039 appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
13040 "SET attlen = %s, "
13041 "attalign = '%s', attbyval = false\n"
13042 "WHERE attname = ", attlen, attalign);
13044 appendPQExpBufferStr(dropped, "\n AND attrelid = ");
13046 appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
13047
13048 appendPQExpBuffer(dropped, "ALTER TYPE %s ",
13049 qualtypname);
13050 appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
13051 fmtId(attname));
13052 }
13053 }
13054 appendPQExpBufferStr(q, "\n);\n");
13055 appendPQExpBufferStr(q, dropped->data);
13056
13057 appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
13058
13059 if (dopt->binary_upgrade)
13061 "TYPE", qtypname,
13062 tyinfo->dobj.namespace->dobj.name);
13063
13064 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13065 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
13066 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
13067 .namespace = tyinfo->dobj.namespace->dobj.name,
13068 .owner = tyinfo->rolname,
13069 .description = "TYPE",
13070 .section = SECTION_PRE_DATA,
13071 .createStmt = q->data,
13072 .dropStmt = delq->data));
13073
13074
13075 /* Dump Type Comments and Security Labels */
13076 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13077 dumpComment(fout, "TYPE", qtypname,
13078 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
13079 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
13080
13081 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
13082 dumpSecLabel(fout, "TYPE", qtypname,
13083 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
13084 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
13085
13086 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
13087 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
13088 qtypname, NULL,
13089 tyinfo->dobj.namespace->dobj.name,
13090 NULL, tyinfo->rolname, &tyinfo->dacl);
13091
13092 /* Dump any per-column comments */
13093 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13095
13096 PQclear(res);
13098 destroyPQExpBuffer(dropped);
13100 destroyPQExpBuffer(query);
13103}
13104
13105/*
13106 * dumpCompositeTypeColComments
13107 * writes out to fout the queries to recreate comments on the columns of
13108 * a user-defined stand-alone composite type.
13109 *
13110 * The caller has already made a query to collect the names and attnums
13111 * of the type's columns, so we just pass that result into here rather
13112 * than reading them again.
13113 */
13114static void
13116 PGresult *res)
13117{
13119 int ncomments;
13120 PQExpBuffer query;
13121 PQExpBuffer target;
13122 int i;
13123 int ntups;
13124 int i_attname;
13125 int i_attnum;
13126 int i_attisdropped;
13127
13128 /* do nothing, if --no-comments is supplied */
13129 if (fout->dopt->no_comments)
13130 return;
13131
13132 /* Search for comments associated with type's pg_class OID */
13134 &comments);
13135
13136 /* If no comments exist, we're done */
13137 if (ncomments <= 0)
13138 return;
13139
13140 /* Build COMMENT ON statements */
13141 query = createPQExpBuffer();
13142 target = createPQExpBuffer();
13143
13144 ntups = PQntuples(res);
13145 i_attnum = PQfnumber(res, "attnum");
13146 i_attname = PQfnumber(res, "attname");
13147 i_attisdropped = PQfnumber(res, "attisdropped");
13148 while (ncomments > 0)
13149 {
13150 const char *attname;
13151
13152 attname = NULL;
13153 for (i = 0; i < ntups; i++)
13154 {
13155 if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
13156 PQgetvalue(res, i, i_attisdropped)[0] != 't')
13157 {
13158 attname = PQgetvalue(res, i, i_attname);
13159 break;
13160 }
13161 }
13162 if (attname) /* just in case we don't find it */
13163 {
13164 const char *descr = comments->descr;
13165
13166 resetPQExpBuffer(target);
13167 appendPQExpBuffer(target, "COLUMN %s.",
13168 fmtId(tyinfo->dobj.name));
13170
13171 resetPQExpBuffer(query);
13172 appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
13174 appendPQExpBuffer(query, "%s IS ", fmtId(attname));
13175 appendStringLiteralAH(query, descr, fout);
13176 appendPQExpBufferStr(query, ";\n");
13177
13179 ARCHIVE_OPTS(.tag = target->data,
13180 .namespace = tyinfo->dobj.namespace->dobj.name,
13181 .owner = tyinfo->rolname,
13182 .description = "COMMENT",
13183 .section = SECTION_NONE,
13184 .createStmt = query->data,
13185 .deps = &(tyinfo->dobj.dumpId),
13186 .nDeps = 1));
13187 }
13188
13189 comments++;
13190 ncomments--;
13191 }
13192
13193 destroyPQExpBuffer(query);
13194 destroyPQExpBuffer(target);
13195}
13196
13197/*
13198 * dumpShellType
13199 * writes out to fout the queries to create a shell type
13200 *
13201 * We dump a shell definition in advance of the I/O functions for the type.
13202 */
13203static void
13205{
13206 DumpOptions *dopt = fout->dopt;
13207 PQExpBuffer q;
13208
13209 /* Do nothing if not dumping schema */
13210 if (!dopt->dumpSchema)
13211 return;
13212
13213 q = createPQExpBuffer();
13214
13215 /*
13216 * Note the lack of a DROP command for the shell type; any required DROP
13217 * is driven off the base type entry, instead. This interacts with
13218 * _printTocEntry()'s use of the presence of a DROP command to decide
13219 * whether an entry needs an ALTER OWNER command. We don't want to alter
13220 * the shell type's owner immediately on creation; that should happen only
13221 * after it's filled in, otherwise the backend complains.
13222 */
13223
13224 if (dopt->binary_upgrade)
13226 stinfo->baseType->dobj.catId.oid,
13227 false, false);
13228
13229 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
13231
13232 if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13233 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
13234 ARCHIVE_OPTS(.tag = stinfo->dobj.name,
13235 .namespace = stinfo->dobj.namespace->dobj.name,
13236 .owner = stinfo->baseType->rolname,
13237 .description = "SHELL TYPE",
13238 .section = SECTION_PRE_DATA,
13239 .createStmt = q->data));
13240
13242}
13243
13244/*
13245 * dumpProcLang
13246 * writes out to fout the queries to recreate a user-defined
13247 * procedural language
13248 */
13249static void
13251{
13252 DumpOptions *dopt = fout->dopt;
13255 bool useParams;
13256 char *qlanname;
13260
13261 /* Do nothing if not dumping schema */
13262 if (!dopt->dumpSchema)
13263 return;
13264
13265 /*
13266 * Try to find the support function(s). It is not an error if we don't
13267 * find them --- if the functions are in the pg_catalog schema, as is
13268 * standard in 8.1 and up, then we won't have loaded them. (In this case
13269 * we will emit a parameterless CREATE LANGUAGE command, which will
13270 * require PL template knowledge in the backend to reload.)
13271 */
13272
13273 funcInfo = findFuncByOid(plang->lanplcallfoid);
13274 if (funcInfo != NULL && !funcInfo->dobj.dump)
13275 funcInfo = NULL; /* treat not-dumped same as not-found */
13276
13277 if (OidIsValid(plang->laninline))
13278 {
13279 inlineInfo = findFuncByOid(plang->laninline);
13280 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
13281 inlineInfo = NULL;
13282 }
13283
13284 if (OidIsValid(plang->lanvalidator))
13285 {
13286 validatorInfo = findFuncByOid(plang->lanvalidator);
13287 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
13289 }
13290
13291 /*
13292 * If the functions are dumpable then emit a complete CREATE LANGUAGE with
13293 * parameters. Otherwise, we'll write a parameterless command, which will
13294 * be interpreted as CREATE EXTENSION.
13295 */
13296 useParams = (funcInfo != NULL &&
13297 (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
13298 (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
13299
13302
13303 qlanname = pg_strdup(fmtId(plang->dobj.name));
13304
13305 appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
13306 qlanname);
13307
13308 if (useParams)
13309 {
13310 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
13311 plang->lanpltrusted ? "TRUSTED " : "",
13312 qlanname);
13313 appendPQExpBuffer(defqry, " HANDLER %s",
13315 if (OidIsValid(plang->laninline))
13316 appendPQExpBuffer(defqry, " INLINE %s",
13318 if (OidIsValid(plang->lanvalidator))
13319 appendPQExpBuffer(defqry, " VALIDATOR %s",
13321 }
13322 else
13323 {
13324 /*
13325 * If not dumping parameters, then use CREATE OR REPLACE so that the
13326 * command will not fail if the language is preinstalled in the target
13327 * database.
13328 *
13329 * Modern servers will interpret this as CREATE EXTENSION IF NOT
13330 * EXISTS; perhaps we should emit that instead? But it might just add
13331 * confusion.
13332 */
13333 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
13334 qlanname);
13335 }
13337
13338 if (dopt->binary_upgrade)
13340 "LANGUAGE", qlanname, NULL);
13341
13342 if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
13343 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
13344 ARCHIVE_OPTS(.tag = plang->dobj.name,
13345 .owner = plang->lanowner,
13346 .description = "PROCEDURAL LANGUAGE",
13347 .section = SECTION_PRE_DATA,
13348 .createStmt = defqry->data,
13349 .dropStmt = delqry->data,
13350 ));
13351
13352 /* Dump Proc Lang Comments and Security Labels */
13353 if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
13354 dumpComment(fout, "LANGUAGE", qlanname,
13355 NULL, plang->lanowner,
13356 plang->dobj.catId, 0, plang->dobj.dumpId);
13357
13358 if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
13359 dumpSecLabel(fout, "LANGUAGE", qlanname,
13360 NULL, plang->lanowner,
13361 plang->dobj.catId, 0, plang->dobj.dumpId);
13362
13363 if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
13364 dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
13365 qlanname, NULL, NULL,
13366 NULL, plang->lanowner, &plang->dacl);
13367
13369
13372}
13373
13374/*
13375 * format_function_arguments: generate function name and argument list
13376 *
13377 * This is used when we can rely on pg_get_function_arguments to format
13378 * the argument list. Note, however, that pg_get_function_arguments
13379 * does not special-case zero-argument aggregates.
13380 */
13381static char *
13382format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
13383{
13385
13388 if (is_agg && finfo->nargs == 0)
13389 appendPQExpBufferStr(&fn, "(*)");
13390 else
13391 appendPQExpBuffer(&fn, "(%s)", funcargs);
13392 return fn.data;
13393}
13394
13395/*
13396 * format_function_signature: generate function name and argument list
13397 *
13398 * Only a minimal list of input argument types is generated; this is
13399 * sufficient to reference the function, but not to define it.
13400 *
13401 * If honor_quotes is false then the function name is never quoted.
13402 * This is appropriate for use in TOC tags, but not in SQL commands.
13403 */
13404static char *
13406{
13408 int j;
13409
13411 if (honor_quotes)
13412 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
13413 else
13414 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
13415 for (j = 0; j < finfo->nargs; j++)
13416 {
13417 if (j > 0)
13418 appendPQExpBufferStr(&fn, ", ");
13419
13422 zeroIsError));
13423 }
13425 return fn.data;
13426}
13427
13428
13429/*
13430 * dumpFunc:
13431 * dump out one function
13432 */
13433static void
13434dumpFunc(Archive *fout, const FuncInfo *finfo)
13435{
13436 DumpOptions *dopt = fout->dopt;
13437 PQExpBuffer query;
13438 PQExpBuffer q;
13441 PGresult *res;
13442 char *funcsig; /* identity signature */
13443 char *funcfullsig = NULL; /* full signature */
13444 char *funcsig_tag;
13445 char *qual_funcsig;
13446 char *proretset;
13447 char *prosrc;
13448 char *probin;
13449 char *prosqlbody;
13450 char *funcargs;
13451 char *funciargs;
13452 char *funcresult;
13453 char *protrftypes;
13454 char *prokind;
13455 char *provolatile;
13456 char *proisstrict;
13457 char *prosecdef;
13458 char *proleakproof;
13459 char *proconfig;
13460 char *procost;
13461 char *prorows;
13462 char *prosupport;
13463 char *proparallel;
13464 char *lanname;
13465 char **configitems = NULL;
13466 int nconfigitems = 0;
13467 const char *keyword;
13468
13469 /* Do nothing if not dumping schema */
13470 if (!dopt->dumpSchema)
13471 return;
13472
13473 query = createPQExpBuffer();
13474 q = createPQExpBuffer();
13477
13478 if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
13479 {
13480 /* Set up query for function-specific details */
13482 "PREPARE dumpFunc(pg_catalog.oid) AS\n");
13483
13485 "SELECT\n"
13486 "proretset,\n"
13487 "prosrc,\n"
13488 "probin,\n"
13489 "provolatile,\n"
13490 "proisstrict,\n"
13491 "prosecdef,\n"
13492 "lanname,\n"
13493 "proconfig,\n"
13494 "procost,\n"
13495 "prorows,\n"
13496 "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
13497 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
13498 "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
13499 "proleakproof,\n");
13500
13502 "array_to_string(protrftypes, ' ') AS protrftypes,\n");
13503
13505 "proparallel,\n");
13506
13507 if (fout->remoteVersion >= 110000)
13509 "prokind,\n");
13510 else
13512 "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
13513
13514 if (fout->remoteVersion >= 120000)
13516 "prosupport,\n");
13517 else
13519 "'-' AS prosupport,\n");
13520
13521 if (fout->remoteVersion >= 140000)
13523 "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
13524 else
13526 "NULL AS prosqlbody\n");
13527
13529 "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
13530 "WHERE p.oid = $1 "
13531 "AND l.oid = p.prolang");
13532
13533 ExecuteSqlStatement(fout, query->data);
13534
13535 fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
13536 }
13537
13538 printfPQExpBuffer(query,
13539 "EXECUTE dumpFunc('%u')",
13540 finfo->dobj.catId.oid);
13541
13542 res = ExecuteSqlQueryForSingleRow(fout, query->data);
13543
13544 proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
13545 if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
13546 {
13547 prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
13548 probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
13549 prosqlbody = NULL;
13550 }
13551 else
13552 {
13553 prosrc = NULL;
13554 probin = NULL;
13555 prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
13556 }
13557 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13558 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13559 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
13560 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
13561 prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
13562 provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
13563 proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
13564 prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
13565 proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
13566 proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
13567 procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
13568 prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
13569 prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
13570 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13571 lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
13572
13573 /*
13574 * See backend/commands/functioncmds.c for details of how the 'AS' clause
13575 * is used.
13576 */
13577 if (prosqlbody)
13578 {
13580 }
13581 else if (probin[0] != '\0')
13582 {
13585 if (prosrc[0] != '\0')
13586 {
13588
13589 /*
13590 * where we have bin, use dollar quoting if allowed and src
13591 * contains quote or backslash; else use regular quoting.
13592 */
13593 if (dopt->disable_dollar_quoting ||
13594 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
13596 else
13598 }
13599 }
13600 else
13601 {
13603 /* with no bin, dollar quote src unconditionally if allowed */
13604 if (dopt->disable_dollar_quoting)
13606 else
13608 }
13609
13610 if (*proconfig)
13611 {
13613 pg_fatal("could not parse %s array", "proconfig");
13614 }
13615 else
13616 {
13617 configitems = NULL;
13618 nconfigitems = 0;
13619 }
13620
13623
13625
13626 qual_funcsig = psprintf("%s.%s",
13627 fmtId(finfo->dobj.namespace->dobj.name),
13628 funcsig);
13629
13630 if (prokind[0] == PROKIND_PROCEDURE)
13631 keyword = "PROCEDURE";
13632 else
13633 keyword = "FUNCTION"; /* works for window functions too */
13634
13635 appendPQExpBuffer(delqry, "DROP %s %s;\n",
13636 keyword, qual_funcsig);
13637
13638 appendPQExpBuffer(q, "CREATE %s %s.%s",
13639 keyword,
13640 fmtId(finfo->dobj.namespace->dobj.name),
13642 funcsig);
13643
13644 if (prokind[0] == PROKIND_PROCEDURE)
13645 /* no result type to output */ ;
13646 else if (funcresult)
13647 appendPQExpBuffer(q, " RETURNS %s", funcresult);
13648 else
13649 appendPQExpBuffer(q, " RETURNS %s%s",
13650 (proretset[0] == 't') ? "SETOF " : "",
13651 getFormattedTypeName(fout, finfo->prorettype,
13652 zeroIsError));
13653
13654 appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
13655
13656 if (*protrftypes)
13657 {
13659 int i;
13660
13661 appendPQExpBufferStr(q, " TRANSFORM ");
13663 for (i = 0; typeids[i]; i++)
13664 {
13665 if (i != 0)
13666 appendPQExpBufferStr(q, ", ");
13667 appendPQExpBuffer(q, "FOR TYPE %s",
13669 }
13670
13672 }
13673
13674 if (prokind[0] == PROKIND_WINDOW)
13675 appendPQExpBufferStr(q, " WINDOW");
13676
13678 {
13680 appendPQExpBufferStr(q, " IMMUTABLE");
13681 else if (provolatile[0] == PROVOLATILE_STABLE)
13682 appendPQExpBufferStr(q, " STABLE");
13683 else if (provolatile[0] != PROVOLATILE_VOLATILE)
13684 pg_fatal("unrecognized provolatile value for function \"%s\"",
13685 finfo->dobj.name);
13686 }
13687
13688 if (proisstrict[0] == 't')
13689 appendPQExpBufferStr(q, " STRICT");
13690
13691 if (prosecdef[0] == 't')
13692 appendPQExpBufferStr(q, " SECURITY DEFINER");
13693
13694 if (proleakproof[0] == 't')
13695 appendPQExpBufferStr(q, " LEAKPROOF");
13696
13697 /*
13698 * COST and ROWS are emitted only if present and not default, so as not to
13699 * break backwards-compatibility of the dump without need. Keep this code
13700 * in sync with the defaults in functioncmds.c.
13701 */
13702 if (strcmp(procost, "0") != 0)
13703 {
13704 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
13705 {
13706 /* default cost is 1 */
13707 if (strcmp(procost, "1") != 0)
13708 appendPQExpBuffer(q, " COST %s", procost);
13709 }
13710 else
13711 {
13712 /* default cost is 100 */
13713 if (strcmp(procost, "100") != 0)
13714 appendPQExpBuffer(q, " COST %s", procost);
13715 }
13716 }
13717 if (proretset[0] == 't' &&
13718 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
13719 appendPQExpBuffer(q, " ROWS %s", prorows);
13720
13721 if (strcmp(prosupport, "-") != 0)
13722 {
13723 /* We rely on regprocout to provide quoting and qualification */
13724 appendPQExpBuffer(q, " SUPPORT %s", prosupport);
13725 }
13726
13728 {
13729 if (proparallel[0] == PROPARALLEL_SAFE)
13730 appendPQExpBufferStr(q, " PARALLEL SAFE");
13731 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
13732 appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
13733 else if (proparallel[0] != PROPARALLEL_UNSAFE)
13734 pg_fatal("unrecognized proparallel value for function \"%s\"",
13735 finfo->dobj.name);
13736 }
13737
13738 for (int i = 0; i < nconfigitems; i++)
13739 {
13740 /* we feel free to scribble on configitems[] here */
13741 char *configitem = configitems[i];
13742 char *pos;
13743
13744 pos = strchr(configitem, '=');
13745 if (pos == NULL)
13746 continue;
13747 *pos++ = '\0';
13748 appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
13749
13750 /*
13751 * Variables that are marked GUC_LIST_QUOTE were already fully quoted
13752 * by flatten_set_variable_args() before they were put into the
13753 * proconfig array. However, because the quoting rules used there
13754 * aren't exactly like SQL's, we have to break the list value apart
13755 * and then quote the elements as string literals. (The elements may
13756 * be double-quoted as-is, but we can't just feed them to the SQL
13757 * parser; it would do the wrong thing with elements that are
13758 * zero-length or longer than NAMEDATALEN.) Also, we need a special
13759 * case for empty lists.
13760 *
13761 * Variables that are not so marked should just be emitted as simple
13762 * string literals. If the variable is not known to
13763 * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
13764 * to use GUC_LIST_QUOTE for extension variables.
13765 */
13767 {
13768 char **namelist;
13769 char **nameptr;
13770
13771 /* Parse string into list of identifiers */
13772 /* this shouldn't fail really */
13773 if (SplitGUCList(pos, ',', &namelist))
13774 {
13775 /* Special case: represent an empty list as NULL */
13776 if (*namelist == NULL)
13777 appendPQExpBufferStr(q, "NULL");
13778 for (nameptr = namelist; *nameptr; nameptr++)
13779 {
13780 if (nameptr != namelist)
13781 appendPQExpBufferStr(q, ", ");
13783 }
13784 }
13786 }
13787 else
13788 appendStringLiteralAH(q, pos, fout);
13789 }
13790
13791 appendPQExpBuffer(q, "\n %s;\n", asPart->data);
13792
13794 "pg_catalog.pg_proc", keyword,
13795 qual_funcsig);
13796
13797 if (dopt->binary_upgrade)
13799 keyword, funcsig,
13800 finfo->dobj.namespace->dobj.name);
13801
13802 if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13803 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
13805 .namespace = finfo->dobj.namespace->dobj.name,
13806 .owner = finfo->rolname,
13807 .description = keyword,
13808 .section = finfo->postponed_def ?
13810 .createStmt = q->data,
13811 .dropStmt = delqry->data));
13812
13813 /* Dump Function Comments and Security Labels */
13814 if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13815 dumpComment(fout, keyword, funcsig,
13816 finfo->dobj.namespace->dobj.name, finfo->rolname,
13817 finfo->dobj.catId, 0, finfo->dobj.dumpId);
13818
13819 if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
13820 dumpSecLabel(fout, keyword, funcsig,
13821 finfo->dobj.namespace->dobj.name, finfo->rolname,
13822 finfo->dobj.catId, 0, finfo->dobj.dumpId);
13823
13824 if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
13825 dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
13826 funcsig, NULL,
13827 finfo->dobj.namespace->dobj.name,
13828 NULL, finfo->rolname, &finfo->dacl);
13829
13830 PQclear(res);
13831
13832 destroyPQExpBuffer(query);
13836 free(funcsig);
13841}
13842
13843
13844/*
13845 * Dump a user-defined cast
13846 */
13847static void
13849{
13850 DumpOptions *dopt = fout->dopt;
13856 const char *sourceType;
13857 const char *targetType;
13858
13859 /* Do nothing if not dumping schema */
13860 if (!dopt->dumpSchema)
13861 return;
13862
13863 /* Cannot dump if we don't have the cast function's info */
13864 if (OidIsValid(cast->castfunc))
13865 {
13866 funcInfo = findFuncByOid(cast->castfunc);
13867 if (funcInfo == NULL)
13868 pg_fatal("could not find function definition for function with OID %u",
13869 cast->castfunc);
13870 }
13871
13876
13879 appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
13881
13882 appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
13884
13885 switch (cast->castmethod)
13886 {
13888 appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
13889 break;
13891 appendPQExpBufferStr(defqry, "WITH INOUT");
13892 break;
13894 if (funcInfo)
13895 {
13897
13898 /*
13899 * Always qualify the function name (format_function_signature
13900 * won't qualify it).
13901 */
13902 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
13903 fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
13904 free(fsig);
13905 }
13906 else
13907 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
13908 break;
13909 default:
13910 pg_log_warning("bogus value in pg_cast.castmethod field");
13911 }
13912
13913 if (cast->castcontext == 'a')
13914 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
13915 else if (cast->castcontext == 'i')
13916 appendPQExpBufferStr(defqry, " AS IMPLICIT");
13918
13919 appendPQExpBuffer(labelq, "CAST (%s AS %s)",
13921
13922 appendPQExpBuffer(castargs, "(%s AS %s)",
13924
13925 if (dopt->binary_upgrade)
13927 "CAST", castargs->data, NULL);
13928
13929 if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
13930 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
13931 ARCHIVE_OPTS(.tag = labelq->data,
13932 .description = "CAST",
13933 .section = SECTION_PRE_DATA,
13934 .createStmt = defqry->data,
13935 .dropStmt = delqry->data));
13936
13937 /* Dump Cast Comments */
13938 if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
13939 dumpComment(fout, "CAST", castargs->data,
13940 NULL, "",
13941 cast->dobj.catId, 0, cast->dobj.dumpId);
13942
13947}
13948
13949/*
13950 * Dump a transform
13951 */
13952static void
13953dumpTransform(Archive *fout, const TransformInfo *transform)
13954{
13955 DumpOptions *dopt = fout->dopt;
13962 char *lanname;
13963 const char *transformType;
13964
13965 /* Do nothing if not dumping schema */
13966 if (!dopt->dumpSchema)
13967 return;
13968
13969 /* Cannot dump if we don't have the transform functions' info */
13970 if (OidIsValid(transform->trffromsql))
13971 {
13973 if (fromsqlFuncInfo == NULL)
13974 pg_fatal("could not find function definition for function with OID %u",
13975 transform->trffromsql);
13976 }
13977 if (OidIsValid(transform->trftosql))
13978 {
13979 tosqlFuncInfo = findFuncByOid(transform->trftosql);
13980 if (tosqlFuncInfo == NULL)
13981 pg_fatal("could not find function definition for function with OID %u",
13982 transform->trftosql);
13983 }
13984
13989
13990 lanname = get_language_name(fout, transform->trflang);
13992
13993 appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
13995
13996 appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
13998
13999 if (!transform->trffromsql && !transform->trftosql)
14000 pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
14001
14002 if (transform->trffromsql)
14003 {
14004 if (fromsqlFuncInfo)
14005 {
14007
14008 /*
14009 * Always qualify the function name (format_function_signature
14010 * won't qualify it).
14011 */
14012 appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
14013 fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
14014 free(fsig);
14015 }
14016 else
14017 pg_log_warning("bogus value in pg_transform.trffromsql field");
14018 }
14019
14020 if (transform->trftosql)
14021 {
14022 if (transform->trffromsql)
14024
14025 if (tosqlFuncInfo)
14026 {
14028
14029 /*
14030 * Always qualify the function name (format_function_signature
14031 * won't qualify it).
14032 */
14033 appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
14034 fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
14035 free(fsig);
14036 }
14037 else
14038 pg_log_warning("bogus value in pg_transform.trftosql field");
14039 }
14040
14042
14043 appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
14045
14046 appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
14048
14049 if (dopt->binary_upgrade)
14051 "TRANSFORM", transformargs->data, NULL);
14052
14053 if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
14054 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
14055 ARCHIVE_OPTS(.tag = labelq->data,
14056 .description = "TRANSFORM",
14057 .section = SECTION_PRE_DATA,
14058 .createStmt = defqry->data,
14059 .dropStmt = delqry->data,
14060 .deps = transform->dobj.dependencies,
14061 .nDeps = transform->dobj.nDeps));
14062
14063 /* Dump Transform Comments */
14064 if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
14065 dumpComment(fout, "TRANSFORM", transformargs->data,
14066 NULL, "",
14067 transform->dobj.catId, 0, transform->dobj.dumpId);
14068
14069 free(lanname);
14074}
14075
14076
14077/*
14078 * dumpOpr
14079 * write out a single operator definition
14080 */
14081static void
14083{
14084 DumpOptions *dopt = fout->dopt;
14085 PQExpBuffer query;
14086 PQExpBuffer q;
14089 PQExpBuffer details;
14090 PGresult *res;
14091 int i_oprkind;
14092 int i_oprcode;
14093 int i_oprleft;
14094 int i_oprright;
14095 int i_oprcom;
14096 int i_oprnegate;
14097 int i_oprrest;
14098 int i_oprjoin;
14099 int i_oprcanmerge;
14100 int i_oprcanhash;
14101 char *oprkind;
14102 char *oprcode;
14103 char *oprleft;
14104 char *oprright;
14105 char *oprcom;
14106 char *oprnegate;
14107 char *oprrest;
14108 char *oprjoin;
14109 char *oprcanmerge;
14110 char *oprcanhash;
14111 char *oprregproc;
14112 char *oprref;
14113
14114 /* Do nothing if not dumping schema */
14115 if (!dopt->dumpSchema)
14116 return;
14117
14118 /*
14119 * some operators are invalid because they were the result of user
14120 * defining operators before commutators exist
14121 */
14122 if (!OidIsValid(oprinfo->oprcode))
14123 return;
14124
14125 query = createPQExpBuffer();
14126 q = createPQExpBuffer();
14129 details = createPQExpBuffer();
14130
14131 if (!fout->is_prepared[PREPQUERY_DUMPOPR])
14132 {
14133 /* Set up query for operator-specific details */
14135 "PREPARE dumpOpr(pg_catalog.oid) AS\n"
14136 "SELECT oprkind, "
14137 "oprcode::pg_catalog.regprocedure, "
14138 "oprleft::pg_catalog.regtype, "
14139 "oprright::pg_catalog.regtype, "
14140 "oprcom, "
14141 "oprnegate, "
14142 "oprrest::pg_catalog.regprocedure, "
14143 "oprjoin::pg_catalog.regprocedure, "
14144 "oprcanmerge, oprcanhash "
14145 "FROM pg_catalog.pg_operator "
14146 "WHERE oid = $1");
14147
14148 ExecuteSqlStatement(fout, query->data);
14149
14150 fout->is_prepared[PREPQUERY_DUMPOPR] = true;
14151 }
14152
14153 printfPQExpBuffer(query,
14154 "EXECUTE dumpOpr('%u')",
14155 oprinfo->dobj.catId.oid);
14156
14157 res = ExecuteSqlQueryForSingleRow(fout, query->data);
14158
14159 i_oprkind = PQfnumber(res, "oprkind");
14160 i_oprcode = PQfnumber(res, "oprcode");
14161 i_oprleft = PQfnumber(res, "oprleft");
14162 i_oprright = PQfnumber(res, "oprright");
14163 i_oprcom = PQfnumber(res, "oprcom");
14164 i_oprnegate = PQfnumber(res, "oprnegate");
14165 i_oprrest = PQfnumber(res, "oprrest");
14166 i_oprjoin = PQfnumber(res, "oprjoin");
14167 i_oprcanmerge = PQfnumber(res, "oprcanmerge");
14168 i_oprcanhash = PQfnumber(res, "oprcanhash");
14169
14170 oprkind = PQgetvalue(res, 0, i_oprkind);
14171 oprcode = PQgetvalue(res, 0, i_oprcode);
14172 oprleft = PQgetvalue(res, 0, i_oprleft);
14173 oprright = PQgetvalue(res, 0, i_oprright);
14174 oprcom = PQgetvalue(res, 0, i_oprcom);
14175 oprnegate = PQgetvalue(res, 0, i_oprnegate);
14176 oprrest = PQgetvalue(res, 0, i_oprrest);
14177 oprjoin = PQgetvalue(res, 0, i_oprjoin);
14180
14181 /* In PG14 upwards postfix operator support does not exist anymore. */
14182 if (strcmp(oprkind, "r") == 0)
14183 pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
14184 oprcode);
14185
14187 if (oprregproc)
14188 {
14189 appendPQExpBuffer(details, " FUNCTION = %s", oprregproc);
14191 }
14192
14193 appendPQExpBuffer(oprid, "%s (",
14194 oprinfo->dobj.name);
14195
14196 /*
14197 * right unary means there's a left arg and left unary means there's a
14198 * right arg. (Although the "r" case is dead code for PG14 and later,
14199 * continue to support it in case we're dumping from an old server.)
14200 */
14201 if (strcmp(oprkind, "r") == 0 ||
14202 strcmp(oprkind, "b") == 0)
14203 {
14204 appendPQExpBuffer(details, ",\n LEFTARG = %s", oprleft);
14205 appendPQExpBufferStr(oprid, oprleft);
14206 }
14207 else
14208 appendPQExpBufferStr(oprid, "NONE");
14209
14210 if (strcmp(oprkind, "l") == 0 ||
14211 strcmp(oprkind, "b") == 0)
14212 {
14213 appendPQExpBuffer(details, ",\n RIGHTARG = %s", oprright);
14214 appendPQExpBuffer(oprid, ", %s)", oprright);
14215 }
14216 else
14217 appendPQExpBufferStr(oprid, ", NONE)");
14218
14220 if (oprref)
14221 {
14222 appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
14223 free(oprref);
14224 }
14225
14227 if (oprref)
14228 {
14229 appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
14230 free(oprref);
14231 }
14232
14233 if (strcmp(oprcanmerge, "t") == 0)
14234 appendPQExpBufferStr(details, ",\n MERGES");
14235
14236 if (strcmp(oprcanhash, "t") == 0)
14237 appendPQExpBufferStr(details, ",\n HASHES");
14238
14240 if (oprregproc)
14241 {
14242 appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
14244 }
14245
14247 if (oprregproc)
14248 {
14249 appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
14251 }
14252
14253 appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
14254 fmtId(oprinfo->dobj.namespace->dobj.name),
14255 oprid->data);
14256
14257 appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
14258 fmtId(oprinfo->dobj.namespace->dobj.name),
14259 oprinfo->dobj.name, details->data);
14260
14261 if (dopt->binary_upgrade)
14263 "OPERATOR", oprid->data,
14264 oprinfo->dobj.namespace->dobj.name);
14265
14266 if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14267 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
14268 ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
14269 .namespace = oprinfo->dobj.namespace->dobj.name,
14270 .owner = oprinfo->rolname,
14271 .description = "OPERATOR",
14272 .section = SECTION_PRE_DATA,
14273 .createStmt = q->data,
14274 .dropStmt = delq->data));
14275
14276 /* Dump Operator Comments */
14277 if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14278 dumpComment(fout, "OPERATOR", oprid->data,
14279 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
14280 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
14281
14282 PQclear(res);
14283
14284 destroyPQExpBuffer(query);
14288 destroyPQExpBuffer(details);
14289}
14290
14291/*
14292 * Convert a function reference obtained from pg_operator
14293 *
14294 * Returns allocated string of what to print, or NULL if function references
14295 * is InvalidOid. Returned string is expected to be free'd by the caller.
14296 *
14297 * The input is a REGPROCEDURE display; we have to strip the argument-types
14298 * part.
14299 */
14300static char *
14301convertRegProcReference(const char *proc)
14302{
14303 char *name;
14304 char *paren;
14305 bool inquote;
14306
14307 /* In all cases "-" means a null reference */
14308 if (strcmp(proc, "-") == 0)
14309 return NULL;
14310
14311 name = pg_strdup(proc);
14312 /* find non-double-quoted left paren */
14313 inquote = false;
14314 for (paren = name; *paren; paren++)
14315 {
14316 if (*paren == '(' && !inquote)
14317 {
14318 *paren = '\0';
14319 break;
14320 }
14321 if (*paren == '"')
14322 inquote = !inquote;
14323 }
14324 return name;
14325}
14326
14327/*
14328 * getFormattedOperatorName - retrieve the operator name for the
14329 * given operator OID (presented in string form).
14330 *
14331 * Returns an allocated string, or NULL if the given OID is invalid.
14332 * Caller is responsible for free'ing result string.
14333 *
14334 * What we produce has the format "OPERATOR(schema.oprname)". This is only
14335 * useful in commands where the operator's argument types can be inferred from
14336 * context. We always schema-qualify the name, though. The predecessor to
14337 * this code tried to skip the schema qualification if possible, but that led
14338 * to wrong results in corner cases, such as if an operator and its negator
14339 * are in different schemas.
14340 */
14341static char *
14343{
14345
14346 /* In all cases "0" means a null reference */
14347 if (strcmp(oproid, "0") == 0)
14348 return NULL;
14349
14351 if (oprInfo == NULL)
14352 {
14353 pg_log_warning("could not find operator with OID %s",
14354 oproid);
14355 return NULL;
14356 }
14357
14358 return psprintf("OPERATOR(%s.%s)",
14359 fmtId(oprInfo->dobj.namespace->dobj.name),
14360 oprInfo->dobj.name);
14361}
14362
14363/*
14364 * Convert a function OID obtained from pg_ts_parser or pg_ts_template
14365 *
14366 * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
14367 * argument lists of these functions are predetermined. Note that the
14368 * caller should ensure we are in the proper schema, because the results
14369 * are search path dependent!
14370 */
14371static char *
14373{
14374 char *result;
14375 char query[128];
14376 PGresult *res;
14377
14378 snprintf(query, sizeof(query),
14379 "SELECT '%u'::pg_catalog.regproc", funcOid);
14380 res = ExecuteSqlQueryForSingleRow(fout, query);
14381
14382 result = pg_strdup(PQgetvalue(res, 0, 0));
14383
14384 PQclear(res);
14385
14386 return result;
14387}
14388
14389/*
14390 * dumpAccessMethod
14391 * write out a single access method definition
14392 */
14393static void
14395{
14396 DumpOptions *dopt = fout->dopt;
14397 PQExpBuffer q;
14399 char *qamname;
14400
14401 /* Do nothing if not dumping schema */
14402 if (!dopt->dumpSchema)
14403 return;
14404
14405 q = createPQExpBuffer();
14407
14408 qamname = pg_strdup(fmtId(aminfo->dobj.name));
14409
14410 appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
14411
14412 switch (aminfo->amtype)
14413 {
14414 case AMTYPE_INDEX:
14415 appendPQExpBufferStr(q, "TYPE INDEX ");
14416 break;
14417 case AMTYPE_TABLE:
14418 appendPQExpBufferStr(q, "TYPE TABLE ");
14419 break;
14420 default:
14421 pg_log_warning("invalid type \"%c\" of access method \"%s\"",
14422 aminfo->amtype, qamname);
14426 return;
14427 }
14428
14429 appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
14430
14431 appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
14432 qamname);
14433
14434 if (dopt->binary_upgrade)
14436 "ACCESS METHOD", qamname, NULL);
14437
14438 if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14439 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
14440 ARCHIVE_OPTS(.tag = aminfo->dobj.name,
14441 .description = "ACCESS METHOD",
14442 .section = SECTION_PRE_DATA,
14443 .createStmt = q->data,
14444 .dropStmt = delq->data));
14445
14446 /* Dump Access Method Comments */
14447 if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14448 dumpComment(fout, "ACCESS METHOD", qamname,
14449 NULL, "",
14450 aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
14451
14455}
14456
14457/*
14458 * dumpOpclass
14459 * write out a single operator class definition
14460 */
14461static void
14463{
14464 DumpOptions *dopt = fout->dopt;
14465 PQExpBuffer query;
14466 PQExpBuffer q;
14469 PGresult *res;
14470 int ntups;
14471 int i_opcintype;
14472 int i_opckeytype;
14473 int i_opcdefault;
14474 int i_opcfamily;
14475 int i_opcfamilyname;
14476 int i_opcfamilynsp;
14477 int i_amname;
14478 int i_amopstrategy;
14479 int i_amopopr;
14480 int i_sortfamily;
14481 int i_sortfamilynsp;
14482 int i_amprocnum;
14483 int i_amproc;
14484 int i_amproclefttype;
14486 char *opcintype;
14487 char *opckeytype;
14488 char *opcdefault;
14489 char *opcfamily;
14490 char *opcfamilyname;
14491 char *opcfamilynsp;
14492 char *amname;
14493 char *amopstrategy;
14494 char *amopopr;
14495 char *sortfamily;
14496 char *sortfamilynsp;
14497 char *amprocnum;
14498 char *amproc;
14499 char *amproclefttype;
14500 char *amprocrighttype;
14501 bool needComma;
14502 int i;
14503
14504 /* Do nothing if not dumping schema */
14505 if (!dopt->dumpSchema)
14506 return;
14507
14508 query = createPQExpBuffer();
14509 q = createPQExpBuffer();
14512
14513 /* Get additional fields from the pg_opclass row */
14514 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
14515 "opckeytype::pg_catalog.regtype, "
14516 "opcdefault, opcfamily, "
14517 "opfname AS opcfamilyname, "
14518 "nspname AS opcfamilynsp, "
14519 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
14520 "FROM pg_catalog.pg_opclass c "
14521 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
14522 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14523 "WHERE c.oid = '%u'::pg_catalog.oid",
14524 opcinfo->dobj.catId.oid);
14525
14526 res = ExecuteSqlQueryForSingleRow(fout, query->data);
14527
14528 i_opcintype = PQfnumber(res, "opcintype");
14529 i_opckeytype = PQfnumber(res, "opckeytype");
14530 i_opcdefault = PQfnumber(res, "opcdefault");
14531 i_opcfamily = PQfnumber(res, "opcfamily");
14532 i_opcfamilyname = PQfnumber(res, "opcfamilyname");
14533 i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
14534 i_amname = PQfnumber(res, "amname");
14535
14536 /* opcintype may still be needed after we PQclear res */
14537 opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
14540 /* opcfamily will still be needed after we PQclear res */
14541 opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
14544 /* amname will still be needed after we PQclear res */
14545 amname = pg_strdup(PQgetvalue(res, 0, i_amname));
14546
14547 appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
14549 appendPQExpBuffer(delq, " USING %s;\n",
14550 fmtId(amname));
14551
14552 /* Build the fixed portion of the CREATE command */
14553 appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
14555 if (strcmp(opcdefault, "t") == 0)
14556 appendPQExpBufferStr(q, "DEFAULT ");
14557 appendPQExpBuffer(q, "FOR TYPE %s USING %s",
14558 opcintype,
14559 fmtId(amname));
14560 if (strlen(opcfamilyname) > 0)
14561 {
14562 appendPQExpBufferStr(q, " FAMILY ");
14565 }
14566 appendPQExpBufferStr(q, " AS\n ");
14567
14568 needComma = false;
14569
14570 if (strcmp(opckeytype, "-") != 0)
14571 {
14572 appendPQExpBuffer(q, "STORAGE %s",
14573 opckeytype);
14574 needComma = true;
14575 }
14576
14577 PQclear(res);
14578
14579 /*
14580 * Now fetch and print the OPERATOR entries (pg_amop rows).
14581 *
14582 * Print only those opfamily members that are tied to the opclass by
14583 * pg_depend entries.
14584 */
14585 resetPQExpBuffer(query);
14586 appendPQExpBuffer(query, "SELECT amopstrategy, "
14587 "amopopr::pg_catalog.regoperator, "
14588 "opfname AS sortfamily, "
14589 "nspname AS sortfamilynsp "
14590 "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
14591 "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
14592 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
14593 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14594 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
14595 "AND refobjid = '%u'::pg_catalog.oid "
14596 "AND amopfamily = '%s'::pg_catalog.oid "
14597 "ORDER BY amopstrategy",
14598 opcinfo->dobj.catId.oid,
14599 opcfamily);
14600
14601 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14602
14603 ntups = PQntuples(res);
14604
14605 i_amopstrategy = PQfnumber(res, "amopstrategy");
14606 i_amopopr = PQfnumber(res, "amopopr");
14607 i_sortfamily = PQfnumber(res, "sortfamily");
14608 i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
14609
14610 for (i = 0; i < ntups; i++)
14611 {
14613 amopopr = PQgetvalue(res, i, i_amopopr);
14614 sortfamily = PQgetvalue(res, i, i_sortfamily);
14616
14617 if (needComma)
14618 appendPQExpBufferStr(q, " ,\n ");
14619
14620 appendPQExpBuffer(q, "OPERATOR %s %s",
14622
14623 if (strlen(sortfamily) > 0)
14624 {
14625 appendPQExpBufferStr(q, " FOR ORDER BY ");
14627 appendPQExpBufferStr(q, fmtId(sortfamily));
14628 }
14629
14630 needComma = true;
14631 }
14632
14633 PQclear(res);
14634
14635 /*
14636 * Now fetch and print the FUNCTION entries (pg_amproc rows).
14637 *
14638 * Print only those opfamily members that are tied to the opclass by
14639 * pg_depend entries.
14640 *
14641 * We print the amproclefttype/amprocrighttype even though in most cases
14642 * the backend could deduce the right values, because of the corner case
14643 * of a btree sort support function for a cross-type comparison.
14644 */
14645 resetPQExpBuffer(query);
14646
14647 appendPQExpBuffer(query, "SELECT amprocnum, "
14648 "amproc::pg_catalog.regprocedure, "
14649 "amproclefttype::pg_catalog.regtype, "
14650 "amprocrighttype::pg_catalog.regtype "
14651 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
14652 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
14653 "AND refobjid = '%u'::pg_catalog.oid "
14654 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
14655 "AND objid = ap.oid "
14656 "ORDER BY amprocnum",
14657 opcinfo->dobj.catId.oid);
14658
14659 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14660
14661 ntups = PQntuples(res);
14662
14663 i_amprocnum = PQfnumber(res, "amprocnum");
14664 i_amproc = PQfnumber(res, "amproc");
14665 i_amproclefttype = PQfnumber(res, "amproclefttype");
14666 i_amprocrighttype = PQfnumber(res, "amprocrighttype");
14667
14668 for (i = 0; i < ntups; i++)
14669 {
14671 amproc = PQgetvalue(res, i, i_amproc);
14674
14675 if (needComma)
14676 appendPQExpBufferStr(q, " ,\n ");
14677
14678 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
14679
14682
14683 appendPQExpBuffer(q, " %s", amproc);
14684
14685 needComma = true;
14686 }
14687
14688 PQclear(res);
14689
14690 /*
14691 * If needComma is still false it means we haven't added anything after
14692 * the AS keyword. To avoid printing broken SQL, append a dummy STORAGE
14693 * clause with the same datatype. This isn't sanctioned by the
14694 * documentation, but actually DefineOpClass will treat it as a no-op.
14695 */
14696 if (!needComma)
14697 appendPQExpBuffer(q, "STORAGE %s", opcintype);
14698
14699 appendPQExpBufferStr(q, ";\n");
14700
14702 appendPQExpBuffer(nameusing, " USING %s",
14703 fmtId(amname));
14704
14705 if (dopt->binary_upgrade)
14707 "OPERATOR CLASS", nameusing->data,
14708 opcinfo->dobj.namespace->dobj.name);
14709
14710 if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14711 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
14712 ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
14713 .namespace = opcinfo->dobj.namespace->dobj.name,
14714 .owner = opcinfo->rolname,
14715 .description = "OPERATOR CLASS",
14716 .section = SECTION_PRE_DATA,
14717 .createStmt = q->data,
14718 .dropStmt = delq->data));
14719
14720 /* Dump Operator Class Comments */
14721 if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14722 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
14723 opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
14724 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
14725
14726 pg_free(opcintype);
14727 pg_free(opcfamily);
14728 pg_free(amname);
14729 destroyPQExpBuffer(query);
14733}
14734
14735/*
14736 * dumpOpfamily
14737 * write out a single operator family definition
14738 *
14739 * Note: this also dumps any "loose" operator members that aren't bound to a
14740 * specific opclass within the opfamily.
14741 */
14742static void
14744{
14745 DumpOptions *dopt = fout->dopt;
14746 PQExpBuffer query;
14747 PQExpBuffer q;
14750 PGresult *res;
14753 int ntups;
14754 int i_amname;
14755 int i_amopstrategy;
14756 int i_amopopr;
14757 int i_sortfamily;
14758 int i_sortfamilynsp;
14759 int i_amprocnum;
14760 int i_amproc;
14761 int i_amproclefttype;
14763 char *amname;
14764 char *amopstrategy;
14765 char *amopopr;
14766 char *sortfamily;
14767 char *sortfamilynsp;
14768 char *amprocnum;
14769 char *amproc;
14770 char *amproclefttype;
14771 char *amprocrighttype;
14772 bool needComma;
14773 int i;
14774
14775 /* Do nothing if not dumping schema */
14776 if (!dopt->dumpSchema)
14777 return;
14778
14779 query = createPQExpBuffer();
14780 q = createPQExpBuffer();
14783
14784 /*
14785 * Fetch only those opfamily members that are tied directly to the
14786 * opfamily by pg_depend entries.
14787 */
14788 appendPQExpBuffer(query, "SELECT amopstrategy, "
14789 "amopopr::pg_catalog.regoperator, "
14790 "opfname AS sortfamily, "
14791 "nspname AS sortfamilynsp "
14792 "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
14793 "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
14794 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
14795 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14796 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
14797 "AND refobjid = '%u'::pg_catalog.oid "
14798 "AND amopfamily = '%u'::pg_catalog.oid "
14799 "ORDER BY amopstrategy",
14800 opfinfo->dobj.catId.oid,
14801 opfinfo->dobj.catId.oid);
14802
14804
14805 resetPQExpBuffer(query);
14806
14807 appendPQExpBuffer(query, "SELECT amprocnum, "
14808 "amproc::pg_catalog.regprocedure, "
14809 "amproclefttype::pg_catalog.regtype, "
14810 "amprocrighttype::pg_catalog.regtype "
14811 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
14812 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
14813 "AND refobjid = '%u'::pg_catalog.oid "
14814 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
14815 "AND objid = ap.oid "
14816 "ORDER BY amprocnum",
14817 opfinfo->dobj.catId.oid);
14818
14820
14821 /* Get additional fields from the pg_opfamily row */
14822 resetPQExpBuffer(query);
14823
14824 appendPQExpBuffer(query, "SELECT "
14825 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
14826 "FROM pg_catalog.pg_opfamily "
14827 "WHERE oid = '%u'::pg_catalog.oid",
14828 opfinfo->dobj.catId.oid);
14829
14830 res = ExecuteSqlQueryForSingleRow(fout, query->data);
14831
14832 i_amname = PQfnumber(res, "amname");
14833
14834 /* amname will still be needed after we PQclear res */
14835 amname = pg_strdup(PQgetvalue(res, 0, i_amname));
14836
14837 appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
14839 appendPQExpBuffer(delq, " USING %s;\n",
14840 fmtId(amname));
14841
14842 /* Build the fixed portion of the CREATE command */
14843 appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
14845 appendPQExpBuffer(q, " USING %s;\n",
14846 fmtId(amname));
14847
14848 PQclear(res);
14849
14850 /* Do we need an ALTER to add loose members? */
14851 if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
14852 {
14853 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
14855 appendPQExpBuffer(q, " USING %s ADD\n ",
14856 fmtId(amname));
14857
14858 needComma = false;
14859
14860 /*
14861 * Now fetch and print the OPERATOR entries (pg_amop rows).
14862 */
14863 ntups = PQntuples(res_ops);
14864
14865 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
14866 i_amopopr = PQfnumber(res_ops, "amopopr");
14867 i_sortfamily = PQfnumber(res_ops, "sortfamily");
14868 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
14869
14870 for (i = 0; i < ntups; i++)
14871 {
14874 sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
14876
14877 if (needComma)
14878 appendPQExpBufferStr(q, " ,\n ");
14879
14880 appendPQExpBuffer(q, "OPERATOR %s %s",
14882
14883 if (strlen(sortfamily) > 0)
14884 {
14885 appendPQExpBufferStr(q, " FOR ORDER BY ");
14887 appendPQExpBufferStr(q, fmtId(sortfamily));
14888 }
14889
14890 needComma = true;
14891 }
14892
14893 /*
14894 * Now fetch and print the FUNCTION entries (pg_amproc rows).
14895 */
14896 ntups = PQntuples(res_procs);
14897
14898 i_amprocnum = PQfnumber(res_procs, "amprocnum");
14899 i_amproc = PQfnumber(res_procs, "amproc");
14900 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
14901 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
14902
14903 for (i = 0; i < ntups; i++)
14904 {
14909
14910 if (needComma)
14911 appendPQExpBufferStr(q, " ,\n ");
14912
14913 appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
14915 amproc);
14916
14917 needComma = true;
14918 }
14919
14920 appendPQExpBufferStr(q, ";\n");
14921 }
14922
14924 appendPQExpBuffer(nameusing, " USING %s",
14925 fmtId(amname));
14926
14927 if (dopt->binary_upgrade)
14929 "OPERATOR FAMILY", nameusing->data,
14930 opfinfo->dobj.namespace->dobj.name);
14931
14932 if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14933 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
14934 ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
14935 .namespace = opfinfo->dobj.namespace->dobj.name,
14936 .owner = opfinfo->rolname,
14937 .description = "OPERATOR FAMILY",
14938 .section = SECTION_PRE_DATA,
14939 .createStmt = q->data,
14940 .dropStmt = delq->data));
14941
14942 /* Dump Operator Family Comments */
14943 if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14944 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
14945 opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
14946 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
14947
14948 pg_free(amname);
14951 destroyPQExpBuffer(query);
14955}
14956
14957/*
14958 * dumpCollation
14959 * write out a single collation definition
14960 */
14961static void
14963{
14964 DumpOptions *dopt = fout->dopt;
14965 PQExpBuffer query;
14966 PQExpBuffer q;
14968 char *qcollname;
14969 PGresult *res;
14970 int i_collprovider;
14972 int i_collcollate;
14973 int i_collctype;
14974 int i_colllocale;
14975 int i_collicurules;
14976 const char *collprovider;
14977 const char *collcollate;
14978 const char *collctype;
14979 const char *colllocale;
14980 const char *collicurules;
14981
14982 /* Do nothing if not dumping schema */
14983 if (!dopt->dumpSchema)
14984 return;
14985
14986 query = createPQExpBuffer();
14987 q = createPQExpBuffer();
14989
14990 qcollname = pg_strdup(fmtId(collinfo->dobj.name));
14991
14992 /* Get collation-specific details */
14993 appendPQExpBufferStr(query, "SELECT ");
14994
14996 "collprovider, "
14997 "collversion, ");
14998
14999 if (fout->remoteVersion >= 120000)
15001 "collisdeterministic, ");
15002 else
15004 "true AS collisdeterministic, ");
15005
15006 if (fout->remoteVersion >= 170000)
15008 "colllocale, ");
15009 else if (fout->remoteVersion >= 150000)
15011 "colliculocale AS colllocale, ");
15012 else
15014 "NULL AS colllocale, ");
15015
15016 if (fout->remoteVersion >= 160000)
15018 "collicurules, ");
15019 else
15021 "NULL AS collicurules, ");
15022
15023 appendPQExpBuffer(query,
15024 "collcollate, "
15025 "collctype "
15026 "FROM pg_catalog.pg_collation c "
15027 "WHERE c.oid = '%u'::pg_catalog.oid",
15028 collinfo->dobj.catId.oid);
15029
15030 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15031
15032 i_collprovider = PQfnumber(res, "collprovider");
15033 i_collisdeterministic = PQfnumber(res, "collisdeterministic");
15034 i_collcollate = PQfnumber(res, "collcollate");
15035 i_collctype = PQfnumber(res, "collctype");
15036 i_colllocale = PQfnumber(res, "colllocale");
15037 i_collicurules = PQfnumber(res, "collicurules");
15038
15040
15041 if (!PQgetisnull(res, 0, i_collcollate))
15043 else
15044 collcollate = NULL;
15045
15046 if (!PQgetisnull(res, 0, i_collctype))
15047 collctype = PQgetvalue(res, 0, i_collctype);
15048 else
15049 collctype = NULL;
15050
15051 /*
15052 * Before version 15, collcollate and collctype were of type NAME and
15053 * non-nullable. Treat empty strings as NULL for consistency.
15054 */
15055 if (fout->remoteVersion < 150000)
15056 {
15057 if (collcollate[0] == '\0')
15058 collcollate = NULL;
15059 if (collctype[0] == '\0')
15060 collctype = NULL;
15061 }
15062
15063 if (!PQgetisnull(res, 0, i_colllocale))
15065 else
15066 colllocale = NULL;
15067
15068 if (!PQgetisnull(res, 0, i_collicurules))
15070 else
15072
15073 appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
15075
15076 appendPQExpBuffer(q, "CREATE COLLATION %s (",
15078
15079 appendPQExpBufferStr(q, "provider = ");
15080 if (collprovider[0] == 'b')
15081 appendPQExpBufferStr(q, "builtin");
15082 else if (collprovider[0] == 'c')
15083 appendPQExpBufferStr(q, "libc");
15084 else if (collprovider[0] == 'i')
15085 appendPQExpBufferStr(q, "icu");
15086 else if (collprovider[0] == 'd')
15087 /* to allow dumping pg_catalog; not accepted on input */
15088 appendPQExpBufferStr(q, "default");
15089 else
15090 pg_fatal("unrecognized collation provider: %s",
15091 collprovider);
15092
15093 if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
15094 appendPQExpBufferStr(q, ", deterministic = false");
15095
15096 if (collprovider[0] == 'd')
15097 {
15099 pg_log_warning("invalid collation \"%s\"", qcollname);
15100
15101 /* no locale -- the default collation cannot be reloaded anyway */
15102 }
15103 else if (collprovider[0] == 'b')
15104 {
15106 pg_log_warning("invalid collation \"%s\"", qcollname);
15107
15108 appendPQExpBufferStr(q, ", locale = ");
15110 fout);
15111 }
15112 else if (collprovider[0] == 'i')
15113 {
15114 if (fout->remoteVersion >= 150000)
15115 {
15116 if (collcollate || collctype || !colllocale)
15117 pg_log_warning("invalid collation \"%s\"", qcollname);
15118
15119 appendPQExpBufferStr(q, ", locale = ");
15121 fout);
15122 }
15123 else
15124 {
15125 if (!collcollate || !collctype || colllocale ||
15127 pg_log_warning("invalid collation \"%s\"", qcollname);
15128
15129 appendPQExpBufferStr(q, ", locale = ");
15131 }
15132
15133 if (collicurules)
15134 {
15135 appendPQExpBufferStr(q, ", rules = ");
15137 }
15138 }
15139 else if (collprovider[0] == 'c')
15140 {
15142 pg_log_warning("invalid collation \"%s\"", qcollname);
15143
15145 {
15146 appendPQExpBufferStr(q, ", locale = ");
15148 }
15149 else
15150 {
15151 appendPQExpBufferStr(q, ", lc_collate = ");
15153 appendPQExpBufferStr(q, ", lc_ctype = ");
15155 }
15156 }
15157 else
15158 pg_fatal("unrecognized collation provider: %s", collprovider);
15159
15160 /*
15161 * For binary upgrade, carry over the collation version. For normal
15162 * dump/restore, omit the version, so that it is computed upon restore.
15163 */
15164 if (dopt->binary_upgrade)
15165 {
15166 int i_collversion;
15167
15168 i_collversion = PQfnumber(res, "collversion");
15169 if (!PQgetisnull(res, 0, i_collversion))
15170 {
15171 appendPQExpBufferStr(q, ", version = ");
15173 PQgetvalue(res, 0, i_collversion),
15174 fout);
15175 }
15176 }
15177
15178 appendPQExpBufferStr(q, ");\n");
15179
15180 if (dopt->binary_upgrade)
15182 "COLLATION", qcollname,
15183 collinfo->dobj.namespace->dobj.name);
15184
15185 if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15186 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
15187 ARCHIVE_OPTS(.tag = collinfo->dobj.name,
15188 .namespace = collinfo->dobj.namespace->dobj.name,
15189 .owner = collinfo->rolname,
15190 .description = "COLLATION",
15191 .section = SECTION_PRE_DATA,
15192 .createStmt = q->data,
15193 .dropStmt = delq->data));
15194
15195 /* Dump Collation Comments */
15196 if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15197 dumpComment(fout, "COLLATION", qcollname,
15198 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
15199 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
15200
15201 PQclear(res);
15202
15203 destroyPQExpBuffer(query);
15207}
15208
15209/*
15210 * dumpConversion
15211 * write out a single conversion definition
15212 */
15213static void
15215{
15216 DumpOptions *dopt = fout->dopt;
15217 PQExpBuffer query;
15218 PQExpBuffer q;
15220 char *qconvname;
15221 PGresult *res;
15222 int i_conforencoding;
15223 int i_contoencoding;
15224 int i_conproc;
15225 int i_condefault;
15226 const char *conforencoding;
15227 const char *contoencoding;
15228 const char *conproc;
15229 bool condefault;
15230
15231 /* Do nothing if not dumping schema */
15232 if (!dopt->dumpSchema)
15233 return;
15234
15235 query = createPQExpBuffer();
15236 q = createPQExpBuffer();
15238
15239 qconvname = pg_strdup(fmtId(convinfo->dobj.name));
15240
15241 /* Get conversion-specific details */
15242 appendPQExpBuffer(query, "SELECT "
15243 "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
15244 "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
15245 "conproc, condefault "
15246 "FROM pg_catalog.pg_conversion c "
15247 "WHERE c.oid = '%u'::pg_catalog.oid",
15248 convinfo->dobj.catId.oid);
15249
15250 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15251
15252 i_conforencoding = PQfnumber(res, "conforencoding");
15253 i_contoencoding = PQfnumber(res, "contoencoding");
15254 i_conproc = PQfnumber(res, "conproc");
15255 i_condefault = PQfnumber(res, "condefault");
15256
15259 conproc = PQgetvalue(res, 0, i_conproc);
15260 condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
15261
15262 appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
15264
15265 appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
15266 (condefault) ? "DEFAULT " : "",
15269 appendPQExpBufferStr(q, " TO ");
15271 /* regproc output is already sufficiently quoted */
15272 appendPQExpBuffer(q, " FROM %s;\n", conproc);
15273
15274 if (dopt->binary_upgrade)
15276 "CONVERSION", qconvname,
15277 convinfo->dobj.namespace->dobj.name);
15278
15279 if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15280 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
15281 ARCHIVE_OPTS(.tag = convinfo->dobj.name,
15282 .namespace = convinfo->dobj.namespace->dobj.name,
15283 .owner = convinfo->rolname,
15284 .description = "CONVERSION",
15285 .section = SECTION_PRE_DATA,
15286 .createStmt = q->data,
15287 .dropStmt = delq->data));
15288
15289 /* Dump Conversion Comments */
15290 if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15291 dumpComment(fout, "CONVERSION", qconvname,
15292 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
15293 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
15294
15295 PQclear(res);
15296
15297 destroyPQExpBuffer(query);
15301}
15302
15303/*
15304 * format_aggregate_signature: generate aggregate name and argument list
15305 *
15306 * The argument type names are qualified if needed. The aggregate name
15307 * is never qualified.
15308 */
15309static char *
15311{
15313 int j;
15314
15316 if (honor_quotes)
15317 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
15318 else
15319 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
15320
15321 if (agginfo->aggfn.nargs == 0)
15322 appendPQExpBufferStr(&buf, "(*)");
15323 else
15324 {
15326 for (j = 0; j < agginfo->aggfn.nargs; j++)
15327 appendPQExpBuffer(&buf, "%s%s",
15328 (j > 0) ? ", " : "",
15330 agginfo->aggfn.argtypes[j],
15331 zeroIsError));
15333 }
15334 return buf.data;
15335}
15336
15337/*
15338 * dumpAgg
15339 * write out a single aggregate definition
15340 */
15341static void
15343{
15344 DumpOptions *dopt = fout->dopt;
15345 PQExpBuffer query;
15346 PQExpBuffer q;
15348 PQExpBuffer details;
15349 char *aggsig; /* identity signature */
15350 char *aggfullsig = NULL; /* full signature */
15351 char *aggsig_tag;
15352 PGresult *res;
15353 int i_agginitval;
15354 int i_aggminitval;
15355 const char *aggtransfn;
15356 const char *aggfinalfn;
15357 const char *aggcombinefn;
15358 const char *aggserialfn;
15359 const char *aggdeserialfn;
15360 const char *aggmtransfn;
15361 const char *aggminvtransfn;
15362 const char *aggmfinalfn;
15363 bool aggfinalextra;
15364 bool aggmfinalextra;
15365 char aggfinalmodify;
15366 char aggmfinalmodify;
15367 const char *aggsortop;
15368 char *aggsortconvop;
15369 char aggkind;
15370 const char *aggtranstype;
15371 const char *aggtransspace;
15372 const char *aggmtranstype;
15373 const char *aggmtransspace;
15374 const char *agginitval;
15375 const char *aggminitval;
15376 const char *proparallel;
15377 char defaultfinalmodify;
15378
15379 /* Do nothing if not dumping schema */
15380 if (!dopt->dumpSchema)
15381 return;
15382
15383 query = createPQExpBuffer();
15384 q = createPQExpBuffer();
15386 details = createPQExpBuffer();
15387
15388 if (!fout->is_prepared[PREPQUERY_DUMPAGG])
15389 {
15390 /* Set up query for aggregate-specific details */
15392 "PREPARE dumpAgg(pg_catalog.oid) AS\n");
15393
15395 "SELECT "
15396 "aggtransfn,\n"
15397 "aggfinalfn,\n"
15398 "aggtranstype::pg_catalog.regtype,\n"
15399 "agginitval,\n"
15400 "aggsortop,\n"
15401 "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
15402 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
15403
15405 "aggkind,\n"
15406 "aggmtransfn,\n"
15407 "aggminvtransfn,\n"
15408 "aggmfinalfn,\n"
15409 "aggmtranstype::pg_catalog.regtype,\n"
15410 "aggfinalextra,\n"
15411 "aggmfinalextra,\n"
15412 "aggtransspace,\n"
15413 "aggmtransspace,\n"
15414 "aggminitval,\n");
15415
15417 "aggcombinefn,\n"
15418 "aggserialfn,\n"
15419 "aggdeserialfn,\n"
15420 "proparallel,\n");
15421
15422 if (fout->remoteVersion >= 110000)
15424 "aggfinalmodify,\n"
15425 "aggmfinalmodify\n");
15426 else
15428 "'0' AS aggfinalmodify,\n"
15429 "'0' AS aggmfinalmodify\n");
15430
15432 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
15433 "WHERE a.aggfnoid = p.oid "
15434 "AND p.oid = $1");
15435
15436 ExecuteSqlStatement(fout, query->data);
15437
15438 fout->is_prepared[PREPQUERY_DUMPAGG] = true;
15439 }
15440
15441 printfPQExpBuffer(query,
15442 "EXECUTE dumpAgg('%u')",
15443 agginfo->aggfn.dobj.catId.oid);
15444
15445 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15446
15447 i_agginitval = PQfnumber(res, "agginitval");
15448 i_aggminitval = PQfnumber(res, "aggminitval");
15449
15450 aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
15451 aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
15452 aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
15453 aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
15454 aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
15455 aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
15456 aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
15457 aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
15458 aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
15459 aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
15460 aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
15461 aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
15462 aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
15463 aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
15464 aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
15465 aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
15466 aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
15467 aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
15470 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
15471
15472 {
15473 char *funcargs;
15474 char *funciargs;
15475
15476 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
15477 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
15480 }
15481
15483
15484 /* identify default modify flag for aggkind (must match DefineAggregate) */
15486 /* replace omitted flags for old versions */
15487 if (aggfinalmodify == '0')
15489 if (aggmfinalmodify == '0')
15491
15492 /* regproc and regtype output is already sufficiently quoted */
15493 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
15494 aggtransfn, aggtranstype);
15495
15496 if (strcmp(aggtransspace, "0") != 0)
15497 {
15498 appendPQExpBuffer(details, ",\n SSPACE = %s",
15499 aggtransspace);
15500 }
15501
15502 if (!PQgetisnull(res, 0, i_agginitval))
15503 {
15504 appendPQExpBufferStr(details, ",\n INITCOND = ");
15506 }
15507
15508 if (strcmp(aggfinalfn, "-") != 0)
15509 {
15510 appendPQExpBuffer(details, ",\n FINALFUNC = %s",
15511 aggfinalfn);
15512 if (aggfinalextra)
15513 appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
15515 {
15516 switch (aggfinalmodify)
15517 {
15519 appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_ONLY");
15520 break;
15522 appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = SHAREABLE");
15523 break;
15525 appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_WRITE");
15526 break;
15527 default:
15528 pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
15529 agginfo->aggfn.dobj.name);
15530 break;
15531 }
15532 }
15533 }
15534
15535 if (strcmp(aggcombinefn, "-") != 0)
15536 appendPQExpBuffer(details, ",\n COMBINEFUNC = %s", aggcombinefn);
15537
15538 if (strcmp(aggserialfn, "-") != 0)
15539 appendPQExpBuffer(details, ",\n SERIALFUNC = %s", aggserialfn);
15540
15541 if (strcmp(aggdeserialfn, "-") != 0)
15542 appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
15543
15544 if (strcmp(aggmtransfn, "-") != 0)
15545 {
15546 appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
15550 }
15551
15552 if (strcmp(aggmtransspace, "0") != 0)
15553 {
15554 appendPQExpBuffer(details, ",\n MSSPACE = %s",
15556 }
15557
15558 if (!PQgetisnull(res, 0, i_aggminitval))
15559 {
15560 appendPQExpBufferStr(details, ",\n MINITCOND = ");
15562 }
15563
15564 if (strcmp(aggmfinalfn, "-") != 0)
15565 {
15566 appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
15567 aggmfinalfn);
15568 if (aggmfinalextra)
15569 appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
15571 {
15572 switch (aggmfinalmodify)
15573 {
15575 appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_ONLY");
15576 break;
15578 appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = SHAREABLE");
15579 break;
15581 appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_WRITE");
15582 break;
15583 default:
15584 pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
15585 agginfo->aggfn.dobj.name);
15586 break;
15587 }
15588 }
15589 }
15590
15592 if (aggsortconvop)
15593 {
15594 appendPQExpBuffer(details, ",\n SORTOP = %s",
15597 }
15598
15600 appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
15601
15603 {
15604 if (proparallel[0] == PROPARALLEL_SAFE)
15605 appendPQExpBufferStr(details, ",\n PARALLEL = safe");
15606 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
15607 appendPQExpBufferStr(details, ",\n PARALLEL = restricted");
15608 else if (proparallel[0] != PROPARALLEL_UNSAFE)
15609 pg_fatal("unrecognized proparallel value for function \"%s\"",
15610 agginfo->aggfn.dobj.name);
15611 }
15612
15613 appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
15614 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
15615 aggsig);
15616
15617 appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
15618 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
15619 aggfullsig ? aggfullsig : aggsig, details->data);
15620
15621 if (dopt->binary_upgrade)
15623 "AGGREGATE", aggsig,
15624 agginfo->aggfn.dobj.namespace->dobj.name);
15625
15626 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
15627 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
15628 agginfo->aggfn.dobj.dumpId,
15629 ARCHIVE_OPTS(.tag = aggsig_tag,
15630 .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
15631 .owner = agginfo->aggfn.rolname,
15632 .description = "AGGREGATE",
15633 .section = SECTION_PRE_DATA,
15634 .createStmt = q->data,
15635 .dropStmt = delq->data));
15636
15637 /* Dump Aggregate Comments */
15638 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
15639 dumpComment(fout, "AGGREGATE", aggsig,
15640 agginfo->aggfn.dobj.namespace->dobj.name,
15641 agginfo->aggfn.rolname,
15642 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
15643
15644 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
15645 dumpSecLabel(fout, "AGGREGATE", aggsig,
15646 agginfo->aggfn.dobj.namespace->dobj.name,
15647 agginfo->aggfn.rolname,
15648 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
15649
15650 /*
15651 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
15652 * command look like a function's GRANT; in particular this affects the
15653 * syntax for zero-argument aggregates and ordered-set aggregates.
15654 */
15655 free(aggsig);
15656
15657 aggsig = format_function_signature(fout, &agginfo->aggfn, true);
15658
15659 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
15660 dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
15661 "FUNCTION", aggsig, NULL,
15662 agginfo->aggfn.dobj.namespace->dobj.name,
15663 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
15664
15665 free(aggsig);
15668
15669 PQclear(res);
15670
15671 destroyPQExpBuffer(query);
15674 destroyPQExpBuffer(details);
15675}
15676
15677/*
15678 * dumpTSParser
15679 * write out a single text search parser
15680 */
15681static void
15683{
15684 DumpOptions *dopt = fout->dopt;
15685 PQExpBuffer q;
15687 char *qprsname;
15688
15689 /* Do nothing if not dumping schema */
15690 if (!dopt->dumpSchema)
15691 return;
15692
15693 q = createPQExpBuffer();
15695
15696 qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
15697
15698 appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
15700
15701 appendPQExpBuffer(q, " START = %s,\n",
15702 convertTSFunction(fout, prsinfo->prsstart));
15703 appendPQExpBuffer(q, " GETTOKEN = %s,\n",
15704 convertTSFunction(fout, prsinfo->prstoken));
15705 appendPQExpBuffer(q, " END = %s,\n",
15706 convertTSFunction(fout, prsinfo->prsend));
15707 if (prsinfo->prsheadline != InvalidOid)
15708 appendPQExpBuffer(q, " HEADLINE = %s,\n",
15709 convertTSFunction(fout, prsinfo->prsheadline));
15710 appendPQExpBuffer(q, " LEXTYPES = %s );\n",
15711 convertTSFunction(fout, prsinfo->prslextype));
15712
15713 appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
15715
15716 if (dopt->binary_upgrade)
15718 "TEXT SEARCH PARSER", qprsname,
15719 prsinfo->dobj.namespace->dobj.name);
15720
15721 if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15722 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
15723 ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
15724 .namespace = prsinfo->dobj.namespace->dobj.name,
15725 .description = "TEXT SEARCH PARSER",
15726 .section = SECTION_PRE_DATA,
15727 .createStmt = q->data,
15728 .dropStmt = delq->data));
15729
15730 /* Dump Parser Comments */
15731 if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15732 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
15733 prsinfo->dobj.namespace->dobj.name, "",
15734 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
15735
15739}
15740
15741/*
15742 * dumpTSDictionary
15743 * write out a single text search dictionary
15744 */
15745static void
15747{
15748 DumpOptions *dopt = fout->dopt;
15749 PQExpBuffer q;
15751 PQExpBuffer query;
15752 char *qdictname;
15753 PGresult *res;
15754 char *nspname;
15755 char *tmplname;
15756
15757 /* Do nothing if not dumping schema */
15758 if (!dopt->dumpSchema)
15759 return;
15760
15761 q = createPQExpBuffer();
15763 query = createPQExpBuffer();
15764
15765 qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
15766
15767 /* Fetch name and namespace of the dictionary's template */
15768 appendPQExpBuffer(query, "SELECT nspname, tmplname "
15769 "FROM pg_ts_template p, pg_namespace n "
15770 "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
15771 dictinfo->dicttemplate);
15772 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15773 nspname = PQgetvalue(res, 0, 0);
15774 tmplname = PQgetvalue(res, 0, 1);
15775
15776 appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
15778
15779 appendPQExpBufferStr(q, " TEMPLATE = ");
15780 appendPQExpBuffer(q, "%s.", fmtId(nspname));
15782
15783 PQclear(res);
15784
15785 /* the dictinitoption can be dumped straight into the command */
15786 if (dictinfo->dictinitoption)
15787 appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
15788
15789 appendPQExpBufferStr(q, " );\n");
15790
15791 appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
15793
15794 if (dopt->binary_upgrade)
15796 "TEXT SEARCH DICTIONARY", qdictname,
15797 dictinfo->dobj.namespace->dobj.name);
15798
15799 if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15800 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
15801 ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
15802 .namespace = dictinfo->dobj.namespace->dobj.name,
15803 .owner = dictinfo->rolname,
15804 .description = "TEXT SEARCH DICTIONARY",
15805 .section = SECTION_PRE_DATA,
15806 .createStmt = q->data,
15807 .dropStmt = delq->data));
15808
15809 /* Dump Dictionary Comments */
15810 if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15811 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
15812 dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
15813 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
15814
15817 destroyPQExpBuffer(query);
15819}
15820
15821/*
15822 * dumpTSTemplate
15823 * write out a single text search template
15824 */
15825static void
15827{
15828 DumpOptions *dopt = fout->dopt;
15829 PQExpBuffer q;
15831 char *qtmplname;
15832
15833 /* Do nothing if not dumping schema */
15834 if (!dopt->dumpSchema)
15835 return;
15836
15837 q = createPQExpBuffer();
15839
15840 qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
15841
15842 appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
15844
15845 if (tmplinfo->tmplinit != InvalidOid)
15846 appendPQExpBuffer(q, " INIT = %s,\n",
15847 convertTSFunction(fout, tmplinfo->tmplinit));
15848 appendPQExpBuffer(q, " LEXIZE = %s );\n",
15849 convertTSFunction(fout, tmplinfo->tmpllexize));
15850
15851 appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
15853
15854 if (dopt->binary_upgrade)
15856 "TEXT SEARCH TEMPLATE", qtmplname,
15857 tmplinfo->dobj.namespace->dobj.name);
15858
15859 if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15860 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
15861 ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
15862 .namespace = tmplinfo->dobj.namespace->dobj.name,
15863 .description = "TEXT SEARCH TEMPLATE",
15864 .section = SECTION_PRE_DATA,
15865 .createStmt = q->data,
15866 .dropStmt = delq->data));
15867
15868 /* Dump Template Comments */
15869 if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15870 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
15871 tmplinfo->dobj.namespace->dobj.name, "",
15872 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
15873
15877}
15878
15879/*
15880 * dumpTSConfig
15881 * write out a single text search configuration
15882 */
15883static void
15885{
15886 DumpOptions *dopt = fout->dopt;
15887 PQExpBuffer q;
15889 PQExpBuffer query;
15890 char *qcfgname;
15891 PGresult *res;
15892 char *nspname;
15893 char *prsname;
15894 int ntups,
15895 i;
15896 int i_tokenname;
15897 int i_dictname;
15898
15899 /* Do nothing if not dumping schema */
15900 if (!dopt->dumpSchema)
15901 return;
15902
15903 q = createPQExpBuffer();
15905 query = createPQExpBuffer();
15906
15907 qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
15908
15909 /* Fetch name and namespace of the config's parser */
15910 appendPQExpBuffer(query, "SELECT nspname, prsname "
15911 "FROM pg_ts_parser p, pg_namespace n "
15912 "WHERE p.oid = '%u' AND n.oid = prsnamespace",
15913 cfginfo->cfgparser);
15914 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15915 nspname = PQgetvalue(res, 0, 0);
15916 prsname = PQgetvalue(res, 0, 1);
15917
15918 appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
15920
15921 appendPQExpBuffer(q, " PARSER = %s.", fmtId(nspname));
15922 appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
15923
15924 PQclear(res);
15925
15926 resetPQExpBuffer(query);
15927 appendPQExpBuffer(query,
15928 "SELECT\n"
15929 " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
15930 " WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
15931 " m.mapdict::pg_catalog.regdictionary AS dictname\n"
15932 "FROM pg_catalog.pg_ts_config_map AS m\n"
15933 "WHERE m.mapcfg = '%u'\n"
15934 "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
15935 cfginfo->cfgparser, cfginfo->dobj.catId.oid);
15936
15937 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15938 ntups = PQntuples(res);
15939
15940 i_tokenname = PQfnumber(res, "tokenname");
15941 i_dictname = PQfnumber(res, "dictname");
15942
15943 for (i = 0; i < ntups; i++)
15944 {
15945 char *tokenname = PQgetvalue(res, i, i_tokenname);
15946 char *dictname = PQgetvalue(res, i, i_dictname);
15947
15948 if (i == 0 ||
15949 strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
15950 {
15951 /* starting a new token type, so start a new command */
15952 if (i > 0)
15953 appendPQExpBufferStr(q, ";\n");
15954 appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
15956 /* tokenname needs quoting, dictname does NOT */
15957 appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
15958 fmtId(tokenname), dictname);
15959 }
15960 else
15961 appendPQExpBuffer(q, ", %s", dictname);
15962 }
15963
15964 if (ntups > 0)
15965 appendPQExpBufferStr(q, ";\n");
15966
15967 PQclear(res);
15968
15969 appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
15971
15972 if (dopt->binary_upgrade)
15974 "TEXT SEARCH CONFIGURATION", qcfgname,
15975 cfginfo->dobj.namespace->dobj.name);
15976
15977 if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15978 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
15979 ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
15980 .namespace = cfginfo->dobj.namespace->dobj.name,
15981 .owner = cfginfo->rolname,
15982 .description = "TEXT SEARCH CONFIGURATION",
15983 .section = SECTION_PRE_DATA,
15984 .createStmt = q->data,
15985 .dropStmt = delq->data));
15986
15987 /* Dump Configuration Comments */
15988 if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15989 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
15990 cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
15991 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
15992
15995 destroyPQExpBuffer(query);
15997}
15998
15999/*
16000 * dumpForeignDataWrapper
16001 * write out a single foreign-data wrapper definition
16002 */
16003static void
16005{
16006 DumpOptions *dopt = fout->dopt;
16007 PQExpBuffer q;
16009 char *qfdwname;
16010
16011 /* Do nothing if not dumping schema */
16012 if (!dopt->dumpSchema)
16013 return;
16014
16015 q = createPQExpBuffer();
16017
16018 qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
16019
16020 appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
16021 qfdwname);
16022
16023 if (strcmp(fdwinfo->fdwhandler, "-") != 0)
16024 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
16025
16026 if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
16027 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
16028
16029 if (strcmp(fdwinfo->fdwconnection, "-") != 0)
16030 appendPQExpBuffer(q, " CONNECTION %s", fdwinfo->fdwconnection);
16031
16032 if (strlen(fdwinfo->fdwoptions) > 0)
16033 appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
16034
16035 appendPQExpBufferStr(q, ";\n");
16036
16037 appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
16038 qfdwname);
16039
16040 if (dopt->binary_upgrade)
16042 "FOREIGN DATA WRAPPER", qfdwname,
16043 NULL);
16044
16045 if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16046 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
16047 ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
16048 .owner = fdwinfo->rolname,
16049 .description = "FOREIGN DATA WRAPPER",
16050 .section = SECTION_PRE_DATA,
16051 .createStmt = q->data,
16052 .dropStmt = delq->data));
16053
16054 /* Dump Foreign Data Wrapper Comments */
16055 if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16056 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
16057 NULL, fdwinfo->rolname,
16058 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
16059
16060 /* Handle the ACL */
16061 if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
16062 dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
16063 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
16064 NULL, fdwinfo->rolname, &fdwinfo->dacl);
16065
16067
16070}
16071
16072/*
16073 * dumpForeignServer
16074 * write out a foreign server definition
16075 */
16076static void
16078{
16079 DumpOptions *dopt = fout->dopt;
16080 PQExpBuffer q;
16082 PQExpBuffer query;
16083 PGresult *res;
16084 char *qsrvname;
16085 char *fdwname;
16086
16087 /* Do nothing if not dumping schema */
16088 if (!dopt->dumpSchema)
16089 return;
16090
16091 q = createPQExpBuffer();
16093 query = createPQExpBuffer();
16094
16095 qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
16096
16097 /* look up the foreign-data wrapper */
16098 appendPQExpBuffer(query, "SELECT fdwname "
16099 "FROM pg_foreign_data_wrapper w "
16100 "WHERE w.oid = '%u'",
16101 srvinfo->srvfdw);
16102 res = ExecuteSqlQueryForSingleRow(fout, query->data);
16103 fdwname = PQgetvalue(res, 0, 0);
16104
16105 appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
16106 if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
16107 {
16108 appendPQExpBufferStr(q, " TYPE ");
16109 appendStringLiteralAH(q, srvinfo->srvtype, fout);
16110 }
16111 if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
16112 {
16113 appendPQExpBufferStr(q, " VERSION ");
16114 appendStringLiteralAH(q, srvinfo->srvversion, fout);
16115 }
16116
16117 appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
16118 appendPQExpBufferStr(q, fmtId(fdwname));
16119
16120 if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
16121 appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
16122
16123 appendPQExpBufferStr(q, ";\n");
16124
16125 appendPQExpBuffer(delq, "DROP SERVER %s;\n",
16126 qsrvname);
16127
16128 if (dopt->binary_upgrade)
16130 "SERVER", qsrvname, NULL);
16131
16132 if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16133 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
16134 ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
16135 .owner = srvinfo->rolname,
16136 .description = "SERVER",
16137 .section = SECTION_PRE_DATA,
16138 .createStmt = q->data,
16139 .dropStmt = delq->data));
16140
16141 /* Dump Foreign Server Comments */
16142 if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16143 dumpComment(fout, "SERVER", qsrvname,
16144 NULL, srvinfo->rolname,
16145 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
16146
16147 /* Handle the ACL */
16148 if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
16149 dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
16150 "FOREIGN SERVER", qsrvname, NULL, NULL,
16151 NULL, srvinfo->rolname, &srvinfo->dacl);
16152
16153 /* Dump user mappings */
16154 if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
16156 srvinfo->dobj.name, NULL,
16157 srvinfo->rolname,
16158 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
16159
16160 PQclear(res);
16161
16163
16166 destroyPQExpBuffer(query);
16167}
16168
16169/*
16170 * dumpUserMappings
16171 *
16172 * This routine is used to dump any user mappings associated with the
16173 * server handed to this routine. Should be called after ArchiveEntry()
16174 * for the server.
16175 */
16176static void
16178 const char *servername, const char *namespace,
16179 const char *owner,
16180 CatalogId catalogId, DumpId dumpId)
16181{
16182 PQExpBuffer q;
16184 PQExpBuffer query;
16185 PQExpBuffer tag;
16186 PGresult *res;
16187 int ntups;
16188 int i_usename;
16189 int i_umoptions;
16190 int i;
16191
16192 q = createPQExpBuffer();
16193 tag = createPQExpBuffer();
16195 query = createPQExpBuffer();
16196
16197 /*
16198 * We read from the publicly accessible view pg_user_mappings, so as not
16199 * to fail if run by a non-superuser. Note that the view will show
16200 * umoptions as null if the user hasn't got privileges for the associated
16201 * server; this means that pg_dump will dump such a mapping, but with no
16202 * OPTIONS clause. A possible alternative is to skip such mappings
16203 * altogether, but it's not clear that that's an improvement.
16204 */
16205 appendPQExpBuffer(query,
16206 "SELECT usename, "
16207 "array_to_string(ARRAY("
16208 "SELECT quote_ident(option_name) || ' ' || "
16209 "quote_literal(option_value) "
16210 "FROM pg_options_to_table(umoptions) "
16211 "ORDER BY option_name"
16212 "), E',\n ') AS umoptions "
16213 "FROM pg_user_mappings "
16214 "WHERE srvid = '%u' "
16215 "ORDER BY usename",
16216 catalogId.oid);
16217
16218 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16219
16220 ntups = PQntuples(res);
16221 i_usename = PQfnumber(res, "usename");
16222 i_umoptions = PQfnumber(res, "umoptions");
16223
16224 for (i = 0; i < ntups; i++)
16225 {
16226 char *usename;
16227 char *umoptions;
16228
16229 usename = PQgetvalue(res, i, i_usename);
16231
16233 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
16234 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
16235
16236 if (umoptions && strlen(umoptions) > 0)
16237 appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
16238
16239 appendPQExpBufferStr(q, ";\n");
16240
16242 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
16243 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
16244
16245 resetPQExpBuffer(tag);
16246 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
16247 usename, servername);
16248
16250 ARCHIVE_OPTS(.tag = tag->data,
16251 .namespace = namespace,
16252 .owner = owner,
16253 .description = "USER MAPPING",
16254 .section = SECTION_PRE_DATA,
16255 .createStmt = q->data,
16256 .dropStmt = delq->data));
16257 }
16258
16259 PQclear(res);
16260
16261 destroyPQExpBuffer(query);
16263 destroyPQExpBuffer(tag);
16265}
16266
16267/*
16268 * Write out default privileges information
16269 */
16270static void
16272{
16273 DumpOptions *dopt = fout->dopt;
16274 PQExpBuffer q;
16275 PQExpBuffer tag;
16276 const char *type;
16277
16278 /* Do nothing if not dumping schema, or if we're skipping ACLs */
16279 if (!dopt->dumpSchema || dopt->aclsSkip)
16280 return;
16281
16282 q = createPQExpBuffer();
16283 tag = createPQExpBuffer();
16284
16285 switch (daclinfo->defaclobjtype)
16286 {
16287 case DEFACLOBJ_RELATION:
16288 type = "TABLES";
16289 break;
16290 case DEFACLOBJ_SEQUENCE:
16291 type = "SEQUENCES";
16292 break;
16293 case DEFACLOBJ_FUNCTION:
16294 type = "FUNCTIONS";
16295 break;
16296 case DEFACLOBJ_TYPE:
16297 type = "TYPES";
16298 break;
16300 type = "SCHEMAS";
16301 break;
16303 type = "LARGE OBJECTS";
16304 break;
16305 default:
16306 /* shouldn't get here */
16307 pg_fatal("unrecognized object type in default privileges: %d",
16308 (int) daclinfo->defaclobjtype);
16309 type = ""; /* keep compiler quiet */
16310 }
16311
16312 appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
16313
16314 /* build the actual command(s) for this tuple */
16316 daclinfo->dobj.namespace != NULL ?
16317 daclinfo->dobj.namespace->dobj.name : NULL,
16318 daclinfo->dacl.acl,
16319 daclinfo->dacl.acldefault,
16320 daclinfo->defaclrole,
16321 fout->remoteVersion,
16322 q))
16323 pg_fatal("could not parse default ACL list (%s)",
16324 daclinfo->dacl.acl);
16325
16326 if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
16327 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
16328 ARCHIVE_OPTS(.tag = tag->data,
16329 .namespace = daclinfo->dobj.namespace ?
16330 daclinfo->dobj.namespace->dobj.name : NULL,
16331 .owner = daclinfo->defaclrole,
16332 .description = "DEFAULT ACL",
16333 .section = SECTION_POST_DATA,
16334 .createStmt = q->data));
16335
16336 destroyPQExpBuffer(tag);
16338}
16339
16340/*----------
16341 * Write out grant/revoke information
16342 *
16343 * 'objDumpId' is the dump ID of the underlying object.
16344 * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
16345 * or InvalidDumpId if there is no need for a second dependency.
16346 * 'type' must be one of
16347 * TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
16348 * FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
16349 * 'name' is the formatted name of the object. Must be quoted etc. already.
16350 * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
16351 * (Currently we assume that subname is only provided for table columns.)
16352 * 'nspname' is the namespace the object is in (NULL if none).
16353 * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
16354 * to use the default for the object type.
16355 * 'owner' is the owner, NULL if there is no owner (for languages).
16356 * 'dacl' is the DumpableAcl struct for the object.
16357 *
16358 * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
16359 * no ACL entry was created.
16360 *----------
16361 */
16362static DumpId
16364 const char *type, const char *name, const char *subname,
16365 const char *nspname, const char *tag, const char *owner,
16366 const DumpableAcl *dacl)
16367{
16369 DumpOptions *dopt = fout->dopt;
16370 const char *acls = dacl->acl;
16371 const char *acldefault = dacl->acldefault;
16372 char privtype = dacl->privtype;
16373 const char *initprivs = dacl->initprivs;
16374 const char *baseacls;
16375 PQExpBuffer sql;
16376
16377 /* Do nothing if ACL dump is not enabled */
16378 if (dopt->aclsSkip)
16379 return InvalidDumpId;
16380
16381 /* --data-only skips ACLs *except* large object ACLs */
16382 if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
16383 return InvalidDumpId;
16384
16385 sql = createPQExpBuffer();
16386
16387 /*
16388 * In binary upgrade mode, we don't run an extension's script but instead
16389 * dump out the objects independently and then recreate them. To preserve
16390 * any initial privileges which were set on extension objects, we need to
16391 * compute the set of GRANT and REVOKE commands necessary to get from the
16392 * default privileges of an object to its initial privileges as recorded
16393 * in pg_init_privs.
16394 *
16395 * At restore time, we apply these commands after having called
16396 * binary_upgrade_set_record_init_privs(true). That tells the backend to
16397 * copy the results into pg_init_privs. This is how we preserve the
16398 * contents of that catalog across binary upgrades.
16399 */
16400 if (dopt->binary_upgrade && privtype == 'e' &&
16401 initprivs && *initprivs != '\0')
16402 {
16403 appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
16404 if (!buildACLCommands(name, subname, nspname, type,
16405 initprivs, acldefault, owner,
16406 "", fout->remoteVersion, sql))
16407 pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
16408 initprivs, acldefault, name, type);
16409 appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
16410 }
16411
16412 /*
16413 * Now figure the GRANT and REVOKE commands needed to get to the object's
16414 * actual current ACL, starting from the initprivs if given, else from the
16415 * object-type-specific default. Also, while buildACLCommands will assume
16416 * that a NULL/empty acls string means it needn't do anything, what that
16417 * actually represents is the object-type-specific default; so we need to
16418 * substitute the acldefault string to get the right results in that case.
16419 */
16420 if (initprivs && *initprivs != '\0')
16421 {
16422 baseacls = initprivs;
16423 if (acls == NULL || *acls == '\0')
16424 acls = acldefault;
16425 }
16426 else
16428
16429 if (!buildACLCommands(name, subname, nspname, type,
16430 acls, baseacls, owner,
16431 "", fout->remoteVersion, sql))
16432 pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
16433 acls, baseacls, name, type);
16434
16435 if (sql->len > 0)
16436 {
16438 DumpId aclDeps[2];
16439 int nDeps = 0;
16440
16441 if (tag)
16443 else if (subname)
16444 appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
16445 else
16446 appendPQExpBuffer(tagbuf, "%s %s", type, name);
16447
16448 aclDeps[nDeps++] = objDumpId;
16449 if (altDumpId != InvalidDumpId)
16450 aclDeps[nDeps++] = altDumpId;
16451
16453
16455 ARCHIVE_OPTS(.tag = tagbuf->data,
16456 .namespace = nspname,
16457 .owner = owner,
16458 .description = "ACL",
16459 .section = SECTION_NONE,
16460 .createStmt = sql->data,
16461 .deps = aclDeps,
16462 .nDeps = nDeps));
16463
16465 }
16466
16467 destroyPQExpBuffer(sql);
16468
16469 return aclDumpId;
16470}
16471
16472/*
16473 * dumpSecLabel
16474 *
16475 * This routine is used to dump any security labels associated with the
16476 * object handed to this routine. The routine takes the object type
16477 * and object name (ready to print, except for schema decoration), plus
16478 * the namespace and owner of the object (for labeling the ArchiveEntry),
16479 * plus catalog ID and subid which are the lookup key for pg_seclabel,
16480 * plus the dump ID for the object (for setting a dependency).
16481 * If a matching pg_seclabel entry is found, it is dumped.
16482 *
16483 * Note: although this routine takes a dumpId for dependency purposes,
16484 * that purpose is just to mark the dependency in the emitted dump file
16485 * for possible future use by pg_restore. We do NOT use it for determining
16486 * ordering of the label in the dump file, because this routine is called
16487 * after dependency sorting occurs. This routine should be called just after
16488 * calling ArchiveEntry() for the specified object.
16489 */
16490static void
16491dumpSecLabel(Archive *fout, const char *type, const char *name,
16492 const char *namespace, const char *owner,
16493 CatalogId catalogId, int subid, DumpId dumpId)
16494{
16495 DumpOptions *dopt = fout->dopt;
16496 SecLabelItem *labels;
16497 int nlabels;
16498 int i;
16499 PQExpBuffer query;
16500
16501 /* do nothing, if --no-security-labels is supplied */
16502 if (dopt->no_security_labels)
16503 return;
16504
16505 /*
16506 * Security labels are schema not data ... except large object labels are
16507 * data
16508 */
16509 if (strcmp(type, "LARGE OBJECT") != 0)
16510 {
16511 if (!dopt->dumpSchema)
16512 return;
16513 }
16514 else
16515 {
16516 /* We do dump large object security labels in binary-upgrade mode */
16517 if (!dopt->dumpData && !dopt->binary_upgrade)
16518 return;
16519 }
16520
16521 /* Search for security labels associated with catalogId, using table */
16522 nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
16523
16524 query = createPQExpBuffer();
16525
16526 for (i = 0; i < nlabels; i++)
16527 {
16528 /*
16529 * Ignore label entries for which the subid doesn't match.
16530 */
16531 if (labels[i].objsubid != subid)
16532 continue;
16533
16534 appendPQExpBuffer(query,
16535 "SECURITY LABEL FOR %s ON %s ",
16536 fmtId(labels[i].provider), type);
16537 if (namespace && *namespace)
16538 appendPQExpBuffer(query, "%s.", fmtId(namespace));
16539 appendPQExpBuffer(query, "%s IS ", name);
16540 appendStringLiteralAH(query, labels[i].label, fout);
16541 appendPQExpBufferStr(query, ";\n");
16542 }
16543
16544 if (query->len > 0)
16545 {
16547
16548 appendPQExpBuffer(tag, "%s %s", type, name);
16550 ARCHIVE_OPTS(.tag = tag->data,
16551 .namespace = namespace,
16552 .owner = owner,
16553 .description = "SECURITY LABEL",
16554 .section = SECTION_NONE,
16555 .createStmt = query->data,
16556 .deps = &dumpId,
16557 .nDeps = 1));
16558 destroyPQExpBuffer(tag);
16559 }
16560
16561 destroyPQExpBuffer(query);
16562}
16563
16564/*
16565 * dumpTableSecLabel
16566 *
16567 * As above, but dump security label for both the specified table (or view)
16568 * and its columns.
16569 */
16570static void
16572{
16573 DumpOptions *dopt = fout->dopt;
16574 SecLabelItem *labels;
16575 int nlabels;
16576 int i;
16577 PQExpBuffer query;
16578 PQExpBuffer target;
16579
16580 /* do nothing, if --no-security-labels is supplied */
16581 if (dopt->no_security_labels)
16582 return;
16583
16584 /* SecLabel are SCHEMA not data */
16585 if (!dopt->dumpSchema)
16586 return;
16587
16588 /* Search for comments associated with relation, using table */
16589 nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
16590 tbinfo->dobj.catId.oid,
16591 &labels);
16592
16593 /* If security labels exist, build SECURITY LABEL statements */
16594 if (nlabels <= 0)
16595 return;
16596
16597 query = createPQExpBuffer();
16598 target = createPQExpBuffer();
16599
16600 for (i = 0; i < nlabels; i++)
16601 {
16602 const char *colname;
16603 const char *provider = labels[i].provider;
16604 const char *label = labels[i].label;
16605 int objsubid = labels[i].objsubid;
16606
16607 resetPQExpBuffer(target);
16608 if (objsubid == 0)
16609 {
16610 appendPQExpBuffer(target, "%s %s", reltypename,
16612 }
16613 else
16614 {
16615 colname = getAttrName(objsubid, tbinfo);
16616 /* first fmtXXX result must be consumed before calling again */
16617 appendPQExpBuffer(target, "COLUMN %s",
16619 appendPQExpBuffer(target, ".%s", fmtId(colname));
16620 }
16621 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
16622 fmtId(provider), target->data);
16624 appendPQExpBufferStr(query, ";\n");
16625 }
16626 if (query->len > 0)
16627 {
16628 resetPQExpBuffer(target);
16629 appendPQExpBuffer(target, "%s %s", reltypename,
16630 fmtId(tbinfo->dobj.name));
16632 ARCHIVE_OPTS(.tag = target->data,
16633 .namespace = tbinfo->dobj.namespace->dobj.name,
16634 .owner = tbinfo->rolname,
16635 .description = "SECURITY LABEL",
16636 .section = SECTION_NONE,
16637 .createStmt = query->data,
16638 .deps = &(tbinfo->dobj.dumpId),
16639 .nDeps = 1));
16640 }
16641 destroyPQExpBuffer(query);
16642 destroyPQExpBuffer(target);
16643}
16644
16645/*
16646 * findSecLabels
16647 *
16648 * Find the security label(s), if any, associated with the given object.
16649 * All the objsubid values associated with the given classoid/objoid are
16650 * found with one search.
16651 */
16652static int
16653findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
16654{
16656 SecLabelItem *low;
16657 SecLabelItem *high;
16658 int nmatch;
16659
16660 if (nseclabels <= 0) /* no labels, so no match is possible */
16661 {
16662 *items = NULL;
16663 return 0;
16664 }
16665
16666 /*
16667 * Do binary search to find some item matching the object.
16668 */
16669 low = &seclabels[0];
16670 high = &seclabels[nseclabels - 1];
16671 while (low <= high)
16672 {
16673 middle = low + (high - low) / 2;
16674
16675 if (classoid < middle->classoid)
16676 high = middle - 1;
16677 else if (classoid > middle->classoid)
16678 low = middle + 1;
16679 else if (objoid < middle->objoid)
16680 high = middle - 1;
16681 else if (objoid > middle->objoid)
16682 low = middle + 1;
16683 else
16684 break; /* found a match */
16685 }
16686
16687 if (low > high) /* no matches */
16688 {
16689 *items = NULL;
16690 return 0;
16691 }
16692
16693 /*
16694 * Now determine how many items match the object. The search loop
16695 * invariant still holds: only items between low and high inclusive could
16696 * match.
16697 */
16698 nmatch = 1;
16699 while (middle > low)
16700 {
16701 if (classoid != middle[-1].classoid ||
16702 objoid != middle[-1].objoid)
16703 break;
16704 middle--;
16705 nmatch++;
16706 }
16707
16708 *items = middle;
16709
16710 middle += nmatch;
16711 while (middle <= high)
16712 {
16713 if (classoid != middle->classoid ||
16714 objoid != middle->objoid)
16715 break;
16716 middle++;
16717 nmatch++;
16718 }
16719
16720 return nmatch;
16721}
16722
16723/*
16724 * collectSecLabels
16725 *
16726 * Construct a table of all security labels available for database objects;
16727 * also set the has-seclabel component flag for each relevant object.
16728 *
16729 * The table is sorted by classoid/objid/objsubid for speed in lookup.
16730 */
16731static void
16733{
16734 PGresult *res;
16735 PQExpBuffer query;
16736 int i_label;
16737 int i_provider;
16738 int i_classoid;
16739 int i_objoid;
16740 int i_objsubid;
16741 int ntups;
16742 int i;
16743 DumpableObject *dobj;
16744
16745 query = createPQExpBuffer();
16746
16748 "SELECT label, provider, classoid, objoid, objsubid "
16749 "FROM pg_catalog.pg_seclabels "
16750 "ORDER BY classoid, objoid, objsubid");
16751
16752 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16753
16754 /* Construct lookup table containing OIDs in numeric form */
16755 i_label = PQfnumber(res, "label");
16756 i_provider = PQfnumber(res, "provider");
16757 i_classoid = PQfnumber(res, "classoid");
16758 i_objoid = PQfnumber(res, "objoid");
16759 i_objsubid = PQfnumber(res, "objsubid");
16760
16761 ntups = PQntuples(res);
16762
16764 nseclabels = 0;
16765 dobj = NULL;
16766
16767 for (i = 0; i < ntups; i++)
16768 {
16769 CatalogId objId;
16770 int subid;
16771
16772 objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
16773 objId.oid = atooid(PQgetvalue(res, i, i_objoid));
16774 subid = atoi(PQgetvalue(res, i, i_objsubid));
16775
16776 /* We needn't remember labels that don't match any dumpable object */
16777 if (dobj == NULL ||
16778 dobj->catId.tableoid != objId.tableoid ||
16779 dobj->catId.oid != objId.oid)
16780 dobj = findObjectByCatalogId(objId);
16781 if (dobj == NULL)
16782 continue;
16783
16784 /*
16785 * Labels on columns of composite types are linked to the type's
16786 * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
16787 * in the type's own DumpableObject.
16788 */
16789 if (subid != 0 && dobj->objType == DO_TABLE &&
16790 ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
16791 {
16793
16794 cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
16795 if (cTypeInfo)
16796 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
16797 }
16798 else
16799 dobj->components |= DUMP_COMPONENT_SECLABEL;
16800
16804 seclabels[nseclabels].objoid = objId.oid;
16805 seclabels[nseclabels].objsubid = subid;
16806 nseclabels++;
16807 }
16808
16809 PQclear(res);
16810 destroyPQExpBuffer(query);
16811}
16812
16813/*
16814 * dumpTable
16815 * write out to fout the declarations (not data) of a user-defined table
16816 */
16817static void
16819{
16820 DumpOptions *dopt = fout->dopt;
16822 char *namecopy;
16823
16824 /* Do nothing if not dumping schema */
16825 if (!dopt->dumpSchema)
16826 return;
16827
16828 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16829 {
16830 if (tbinfo->relkind == RELKIND_SEQUENCE)
16832 else
16834 }
16835
16836 /* Handle the ACL here */
16837 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
16838 if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
16839 {
16840 const char *objtype;
16841
16842 switch (tbinfo->relkind)
16843 {
16844 case RELKIND_SEQUENCE:
16845 objtype = "SEQUENCE";
16846 break;
16847 case RELKIND_PROPGRAPH:
16848 objtype = "PROPERTY GRAPH";
16849 break;
16850 default:
16851 objtype = "TABLE";
16852 break;
16853 }
16854
16856 dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
16857 objtype, namecopy, NULL,
16858 tbinfo->dobj.namespace->dobj.name,
16859 NULL, tbinfo->rolname, &tbinfo->dacl);
16860 }
16861
16862 /*
16863 * Handle column ACLs, if any. Note: we pull these with a separate query
16864 * rather than trying to fetch them during getTableAttrs, so that we won't
16865 * miss ACLs on system columns. Doing it this way also allows us to dump
16866 * ACLs for catalogs that we didn't mark "interesting" back in getTables.
16867 */
16868 if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
16869 {
16871 PGresult *res;
16872 int i;
16873
16874 if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
16875 {
16876 /* Set up query for column ACLs */
16878 "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
16879
16880 /*
16881 * In principle we should call acldefault('c', relowner) to get
16882 * the default ACL for a column. However, we don't currently
16883 * store the numeric OID of the relowner in TableInfo. We could
16884 * convert the owner name using regrole, but that creates a risk
16885 * of failure due to concurrent role renames. Given that the
16886 * default ACL for columns is empty and is likely to stay that
16887 * way, it's not worth extra cycles and risk to avoid hard-wiring
16888 * that knowledge here.
16889 */
16891 "SELECT at.attname, "
16892 "at.attacl, "
16893 "'{}' AS acldefault, "
16894 "pip.privtype, pip.initprivs "
16895 "FROM pg_catalog.pg_attribute at "
16896 "LEFT JOIN pg_catalog.pg_init_privs pip ON "
16897 "(at.attrelid = pip.objoid "
16898 "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
16899 "AND at.attnum = pip.objsubid) "
16900 "WHERE at.attrelid = $1 AND "
16901 "NOT at.attisdropped "
16902 "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
16903 "ORDER BY at.attnum");
16904
16905 ExecuteSqlStatement(fout, query->data);
16906
16907 fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
16908 }
16909
16910 printfPQExpBuffer(query,
16911 "EXECUTE getColumnACLs('%u')",
16912 tbinfo->dobj.catId.oid);
16913
16914 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16915
16916 for (i = 0; i < PQntuples(res); i++)
16917 {
16918 char *attname = PQgetvalue(res, i, 0);
16919 char *attacl = PQgetvalue(res, i, 1);
16920 char *acldefault = PQgetvalue(res, i, 2);
16921 char privtype = *(PQgetvalue(res, i, 3));
16922 char *initprivs = PQgetvalue(res, i, 4);
16924 char *attnamecopy;
16925
16926 coldacl.acl = attacl;
16927 coldacl.acldefault = acldefault;
16928 coldacl.privtype = privtype;
16929 coldacl.initprivs = initprivs;
16931
16932 /*
16933 * Column's GRANT type is always TABLE. Each column ACL depends
16934 * on the table-level ACL, since we can restore column ACLs in
16935 * parallel but the table-level ACL has to be done first.
16936 */
16937 dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
16938 "TABLE", namecopy, attnamecopy,
16939 tbinfo->dobj.namespace->dobj.name,
16940 NULL, tbinfo->rolname, &coldacl);
16942 }
16943 PQclear(res);
16944 destroyPQExpBuffer(query);
16945 }
16946
16948}
16949
16950/*
16951 * Create the AS clause for a view or materialized view. The semicolon is
16952 * stripped because a materialized view must add a WITH NO DATA clause.
16953 *
16954 * This returns a new buffer which must be freed by the caller.
16955 */
16956static PQExpBuffer
16958{
16961 PGresult *res;
16962 int len;
16963
16964 /* Fetch the view definition */
16965 appendPQExpBuffer(query,
16966 "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
16967 tbinfo->dobj.catId.oid);
16968
16969 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16970
16971 if (PQntuples(res) != 1)
16972 {
16973 if (PQntuples(res) < 1)
16974 pg_fatal("query to obtain definition of view \"%s\" returned no data",
16975 tbinfo->dobj.name);
16976 else
16977 pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
16978 tbinfo->dobj.name);
16979 }
16980
16981 len = PQgetlength(res, 0, 0);
16982
16983 if (len == 0)
16984 pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
16985 tbinfo->dobj.name);
16986
16987 /* Strip off the trailing semicolon so that other things may follow. */
16988 Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
16989 appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
16990
16991 PQclear(res);
16992 destroyPQExpBuffer(query);
16993
16994 return result;
16995}
16996
16997/*
16998 * Create a dummy AS clause for a view. This is used when the real view
16999 * definition has to be postponed because of circular dependencies.
17000 * We must duplicate the view's external properties -- column names and types
17001 * (including collation) -- so that it works for subsequent references.
17002 *
17003 * This returns a new buffer which must be freed by the caller.
17004 */
17005static PQExpBuffer
17007{
17009 int j;
17010
17011 appendPQExpBufferStr(result, "SELECT");
17012
17013 for (j = 0; j < tbinfo->numatts; j++)
17014 {
17015 if (j > 0)
17018
17019 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
17020
17021 /*
17022 * Must add collation if not default for the type, because CREATE OR
17023 * REPLACE VIEW won't change it
17024 */
17025 if (OidIsValid(tbinfo->attcollation[j]))
17026 {
17027 CollInfo *coll;
17028
17029 coll = findCollationByOid(tbinfo->attcollation[j]);
17030 if (coll)
17031 appendPQExpBuffer(result, " COLLATE %s",
17032 fmtQualifiedDumpable(coll));
17033 }
17034
17035 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
17036 }
17037
17038 return result;
17039}
17040
17041/*
17042 * dumpTableSchema
17043 * write the declaration (not data) of one user-defined table or view
17044 */
17045static void
17047{
17048 DumpOptions *dopt = fout->dopt;
17052 char *qrelname;
17053 char *qualrelname;
17054 int numParents;
17055 TableInfo **parents;
17056 int actual_atts; /* number of attrs in this CREATE statement */
17057 const char *reltypename;
17058 char *storage;
17059 int j,
17060 k;
17061
17062 /* We had better have loaded per-column details about this table */
17063 Assert(tbinfo->interesting);
17064
17065 qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
17067
17068 if (tbinfo->hasoids)
17069 pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
17070 qrelname);
17071
17072 if (dopt->binary_upgrade)
17074
17075 /* Is it a table or a view? */
17076 if (tbinfo->relkind == RELKIND_VIEW)
17077 {
17079
17080 /*
17081 * Note: keep this code in sync with the is_view case in dumpRule()
17082 */
17083
17084 reltypename = "VIEW";
17085
17086 if (dopt->binary_upgrade)
17088 tbinfo->dobj.catId.oid);
17089
17090 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
17091
17092 if (tbinfo->dummy_view)
17094 else
17095 {
17096 if (nonemptyReloptions(tbinfo->reloptions))
17097 {
17098 appendPQExpBufferStr(q, " WITH (");
17099 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
17100 appendPQExpBufferChar(q, ')');
17101 }
17103 }
17104 appendPQExpBuffer(q, " AS\n%s", result->data);
17106
17107 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
17108 appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
17109 appendPQExpBufferStr(q, ";\n");
17110 }
17111 else if (tbinfo->relkind == RELKIND_PROPGRAPH)
17112 {
17114 PGresult *res;
17115 int len;
17116
17117 reltypename = "PROPERTY GRAPH";
17118
17119 if (dopt->binary_upgrade)
17121 tbinfo->dobj.catId.oid);
17122
17123 appendPQExpBuffer(query,
17124 "SELECT pg_catalog.pg_get_propgraphdef('%u'::pg_catalog.oid) AS pgdef",
17125 tbinfo->dobj.catId.oid);
17126
17127 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17128
17129 if (PQntuples(res) != 1)
17130 {
17131 if (PQntuples(res) < 1)
17132 pg_fatal("query to obtain definition of property graph \"%s\" returned no data",
17133 tbinfo->dobj.name);
17134 else
17135 pg_fatal("query to obtain definition of property graph \"%s\" returned more than one definition",
17136 tbinfo->dobj.name);
17137 }
17138
17139 len = PQgetlength(res, 0, 0);
17140
17141 if (len == 0)
17142 pg_fatal("definition of property graph \"%s\" appears to be empty (length zero)",
17143 tbinfo->dobj.name);
17144
17145 appendPQExpBufferStr(q, PQgetvalue(res, 0, 0));
17146
17147 PQclear(res);
17148 destroyPQExpBuffer(query);
17149
17150 appendPQExpBufferStr(q, ";\n");
17151 }
17152 else
17153 {
17154 char *partkeydef = NULL;
17155 char *ftoptions = NULL;
17156 char *srvname = NULL;
17157 const char *foreign = "";
17158
17159 /*
17160 * Set reltypename, and collect any relkind-specific data that we
17161 * didn't fetch during getTables().
17162 */
17163 switch (tbinfo->relkind)
17164 {
17166 {
17168 PGresult *res;
17169
17170 reltypename = "TABLE";
17171
17172 /* retrieve partition key definition */
17173 appendPQExpBuffer(query,
17174 "SELECT pg_get_partkeydef('%u')",
17175 tbinfo->dobj.catId.oid);
17176 res = ExecuteSqlQueryForSingleRow(fout, query->data);
17177 partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
17178 PQclear(res);
17179 destroyPQExpBuffer(query);
17180 break;
17181 }
17183 {
17185 PGresult *res;
17186 int i_srvname;
17187 int i_ftoptions;
17188
17189 reltypename = "FOREIGN TABLE";
17190
17191 /* retrieve name of foreign server and generic options */
17192 appendPQExpBuffer(query,
17193 "SELECT fs.srvname, "
17194 "pg_catalog.array_to_string(ARRAY("
17195 "SELECT pg_catalog.quote_ident(option_name) || "
17196 "' ' || pg_catalog.quote_literal(option_value) "
17197 "FROM pg_catalog.pg_options_to_table(ftoptions) "
17198 "ORDER BY option_name"
17199 "), E',\n ') AS ftoptions "
17200 "FROM pg_catalog.pg_foreign_table ft "
17201 "JOIN pg_catalog.pg_foreign_server fs "
17202 "ON (fs.oid = ft.ftserver) "
17203 "WHERE ft.ftrelid = '%u'",
17204 tbinfo->dobj.catId.oid);
17205 res = ExecuteSqlQueryForSingleRow(fout, query->data);
17206 i_srvname = PQfnumber(res, "srvname");
17207 i_ftoptions = PQfnumber(res, "ftoptions");
17210 PQclear(res);
17211 destroyPQExpBuffer(query);
17212
17213 foreign = "FOREIGN ";
17214 break;
17215 }
17216 case RELKIND_MATVIEW:
17217 reltypename = "MATERIALIZED VIEW";
17218 break;
17219 default:
17220 reltypename = "TABLE";
17221 break;
17222 }
17223
17224 numParents = tbinfo->numParents;
17225 parents = tbinfo->parents;
17226
17227 if (dopt->binary_upgrade)
17229 tbinfo->dobj.catId.oid);
17230
17231 /*
17232 * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
17233 * ignore it when dumping if it was set in this case.
17234 */
17235 appendPQExpBuffer(q, "CREATE %s%s %s",
17236 (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
17237 tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
17238 "UNLOGGED " : "",
17240 qualrelname);
17241
17242 /*
17243 * Attach to type, if reloftype; except in case of a binary upgrade,
17244 * we dump the table normally and attach it to the type afterward.
17245 */
17246 if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
17247 appendPQExpBuffer(q, " OF %s",
17248 getFormattedTypeName(fout, tbinfo->reloftype,
17249 zeroIsError));
17250
17251 if (tbinfo->relkind != RELKIND_MATVIEW)
17252 {
17253 /* Dump the attributes */
17254 actual_atts = 0;
17255 for (j = 0; j < tbinfo->numatts; j++)
17256 {
17257 /*
17258 * Normally, dump if it's locally defined in this table, and
17259 * not dropped. But for binary upgrade, we'll dump all the
17260 * columns, and then fix up the dropped and nonlocal cases
17261 * below.
17262 */
17263 if (shouldPrintColumn(dopt, tbinfo, j))
17264 {
17265 bool print_default;
17266 bool print_notnull;
17267
17268 /*
17269 * Default value --- suppress if to be printed separately
17270 * or not at all.
17271 */
17272 print_default = (tbinfo->attrdefs[j] != NULL &&
17273 tbinfo->attrdefs[j]->dobj.dump &&
17274 !tbinfo->attrdefs[j]->separate);
17275
17276 /*
17277 * Not Null constraint --- print it if it is locally
17278 * defined, or if binary upgrade. (In the latter case, we
17279 * reset conislocal below.)
17280 */
17281 print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
17282 (tbinfo->notnull_islocal[j] ||
17283 dopt->binary_upgrade ||
17284 tbinfo->ispartition));
17285
17286 /*
17287 * Skip column if fully defined by reloftype, except in
17288 * binary upgrade
17289 */
17290 if (OidIsValid(tbinfo->reloftype) &&
17292 !dopt->binary_upgrade)
17293 continue;
17294
17295 /* Format properly if not first attr */
17296 if (actual_atts == 0)
17297 appendPQExpBufferStr(q, " (");
17298 else
17299 appendPQExpBufferChar(q, ',');
17300 appendPQExpBufferStr(q, "\n ");
17301 actual_atts++;
17302
17303 /* Attribute name */
17304 appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
17305
17306 if (tbinfo->attisdropped[j])
17307 {
17308 /*
17309 * ALTER TABLE DROP COLUMN clears
17310 * pg_attribute.atttypid, so we will not have gotten a
17311 * valid type name; insert INTEGER as a stopgap. We'll
17312 * clean things up later.
17313 */
17314 appendPQExpBufferStr(q, " INTEGER /* dummy */");
17315 /* and skip to the next column */
17316 continue;
17317 }
17318
17319 /*
17320 * Attribute type; print it except when creating a typed
17321 * table ('OF type_name'), but in binary-upgrade mode,
17322 * print it in that case too.
17323 */
17324 if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
17325 {
17326 appendPQExpBuffer(q, " %s",
17327 tbinfo->atttypnames[j]);
17328 }
17329
17330 if (print_default)
17331 {
17332 if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
17333 appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
17334 tbinfo->attrdefs[j]->adef_expr);
17335 else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
17336 appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
17337 tbinfo->attrdefs[j]->adef_expr);
17338 else
17339 appendPQExpBuffer(q, " DEFAULT %s",
17340 tbinfo->attrdefs[j]->adef_expr);
17341 }
17342
17343 if (print_notnull)
17344 {
17345 if (tbinfo->notnull_constrs[j][0] == '\0')
17346 appendPQExpBufferStr(q, " NOT NULL");
17347 else
17348 appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
17349 fmtId(tbinfo->notnull_constrs[j]));
17350
17351 if (tbinfo->notnull_noinh[j])
17352 appendPQExpBufferStr(q, " NO INHERIT");
17353 }
17354
17355 /* Add collation if not default for the type */
17356 if (OidIsValid(tbinfo->attcollation[j]))
17357 {
17358 CollInfo *coll;
17359
17360 coll = findCollationByOid(tbinfo->attcollation[j]);
17361 if (coll)
17362 appendPQExpBuffer(q, " COLLATE %s",
17363 fmtQualifiedDumpable(coll));
17364 }
17365 }
17366
17367 /*
17368 * On the other hand, if we choose not to print a column
17369 * (likely because it is created by inheritance), but the
17370 * column has a locally-defined not-null constraint, we need
17371 * to dump the constraint as a standalone object.
17372 *
17373 * This syntax isn't SQL-conforming, but if you wanted
17374 * standard output you wouldn't be creating non-standard
17375 * objects to begin with.
17376 */
17377 if (!shouldPrintColumn(dopt, tbinfo, j) &&
17378 !tbinfo->attisdropped[j] &&
17379 tbinfo->notnull_constrs[j] != NULL &&
17380 tbinfo->notnull_islocal[j])
17381 {
17382 /* Format properly if not first attr */
17383 if (actual_atts == 0)
17384 appendPQExpBufferStr(q, " (");
17385 else
17386 appendPQExpBufferChar(q, ',');
17387 appendPQExpBufferStr(q, "\n ");
17388 actual_atts++;
17389
17390 if (tbinfo->notnull_constrs[j][0] == '\0')
17391 appendPQExpBuffer(q, "NOT NULL %s",
17392 fmtId(tbinfo->attnames[j]));
17393 else
17394 appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
17395 tbinfo->notnull_constrs[j],
17396 fmtId(tbinfo->attnames[j]));
17397
17398 if (tbinfo->notnull_noinh[j])
17399 appendPQExpBufferStr(q, " NO INHERIT");
17400 }
17401 }
17402
17403 /*
17404 * Add non-inherited CHECK constraints, if any.
17405 *
17406 * For partitions, we need to include check constraints even if
17407 * they're not defined locally, because the ALTER TABLE ATTACH
17408 * PARTITION that we'll emit later expects the constraint to be
17409 * there. (No need to fix conislocal: ATTACH PARTITION does that)
17410 */
17411 for (j = 0; j < tbinfo->ncheck; j++)
17412 {
17413 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
17414
17415 if (constr->separate ||
17416 (!constr->conislocal && !tbinfo->ispartition))
17417 continue;
17418
17419 if (actual_atts == 0)
17420 appendPQExpBufferStr(q, " (\n ");
17421 else
17422 appendPQExpBufferStr(q, ",\n ");
17423
17424 appendPQExpBuffer(q, "CONSTRAINT %s ",
17425 fmtId(constr->dobj.name));
17426 appendPQExpBufferStr(q, constr->condef);
17427
17428 actual_atts++;
17429 }
17430
17431 if (actual_atts)
17432 appendPQExpBufferStr(q, "\n)");
17433 else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
17434 {
17435 /*
17436 * No attributes? we must have a parenthesized attribute list,
17437 * even though empty, when not using the OF TYPE syntax.
17438 */
17439 appendPQExpBufferStr(q, " (\n)");
17440 }
17441
17442 /*
17443 * Emit the INHERITS clause (not for partitions), except in
17444 * binary-upgrade mode.
17445 */
17446 if (numParents > 0 && !tbinfo->ispartition &&
17447 !dopt->binary_upgrade)
17448 {
17449 appendPQExpBufferStr(q, "\nINHERITS (");
17450 for (k = 0; k < numParents; k++)
17451 {
17452 TableInfo *parentRel = parents[k];
17453
17454 if (k > 0)
17455 appendPQExpBufferStr(q, ", ");
17457 }
17458 appendPQExpBufferChar(q, ')');
17459 }
17460
17461 if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
17462 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
17463
17464 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
17465 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
17466 }
17467
17468 if (nonemptyReloptions(tbinfo->reloptions) ||
17469 nonemptyReloptions(tbinfo->toast_reloptions))
17470 {
17471 bool addcomma = false;
17472
17473 appendPQExpBufferStr(q, "\nWITH (");
17474 if (nonemptyReloptions(tbinfo->reloptions))
17475 {
17476 addcomma = true;
17477 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
17478 }
17479 if (nonemptyReloptions(tbinfo->toast_reloptions))
17480 {
17481 if (addcomma)
17482 appendPQExpBufferStr(q, ", ");
17483 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
17484 fout);
17485 }
17486 appendPQExpBufferChar(q, ')');
17487 }
17488
17489 /* Dump generic options if any */
17490 if (ftoptions && ftoptions[0])
17491 appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
17492
17493 /*
17494 * For materialized views, create the AS clause just like a view. At
17495 * this point, we always mark the view as not populated.
17496 */
17497 if (tbinfo->relkind == RELKIND_MATVIEW)
17498 {
17500
17502 appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
17503 result->data);
17505 }
17506 else
17507 appendPQExpBufferStr(q, ";\n");
17508
17509 /* Materialized views can depend on extensions */
17510 if (tbinfo->relkind == RELKIND_MATVIEW)
17512 "pg_catalog.pg_class",
17513 "MATERIALIZED VIEW",
17514 qualrelname);
17515
17516 /*
17517 * in binary upgrade mode, update the catalog with any missing values
17518 * that might be present.
17519 */
17520 if (dopt->binary_upgrade)
17521 {
17522 for (j = 0; j < tbinfo->numatts; j++)
17523 {
17524 if (tbinfo->attmissingval[j][0] != '\0')
17525 {
17526 appendPQExpBufferStr(q, "\n-- set missing value.\n");
17528 "SELECT pg_catalog.binary_upgrade_set_missing_value(");
17530 appendPQExpBufferStr(q, "::pg_catalog.regclass,");
17531 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17532 appendPQExpBufferChar(q, ',');
17533 appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
17534 appendPQExpBufferStr(q, ");\n\n");
17535 }
17536 }
17537 }
17538
17539 /*
17540 * To create binary-compatible heap files, we have to ensure the same
17541 * physical column order, including dropped columns, as in the
17542 * original. Therefore, we create dropped columns above and drop them
17543 * here, also updating their attlen/attalign values so that the
17544 * dropped column can be skipped properly. (We do not bother with
17545 * restoring the original attbyval setting.) Also, inheritance
17546 * relationships are set up by doing ALTER TABLE INHERIT rather than
17547 * using an INHERITS clause --- the latter would possibly mess up the
17548 * column order. That also means we have to take care about setting
17549 * attislocal correctly, plus fix up any inherited CHECK constraints.
17550 * Analogously, we set up typed tables using ALTER TABLE / OF here.
17551 *
17552 * We process foreign and partitioned tables here, even though they
17553 * lack heap storage, because they can participate in inheritance
17554 * relationships and we want this stuff to be consistent across the
17555 * inheritance tree. We can exclude indexes, toast tables, sequences
17556 * and matviews, even though they have storage, because we don't
17557 * support altering or dropping columns in them, nor can they be part
17558 * of inheritance trees.
17559 */
17560 if (dopt->binary_upgrade &&
17561 (tbinfo->relkind == RELKIND_RELATION ||
17562 tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
17563 tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
17564 {
17565 bool firstitem;
17566 bool firstitem_extra;
17567
17568 /*
17569 * Drop any dropped columns. Merge the pg_attribute manipulations
17570 * into a single SQL command, so that we don't cause repeated
17571 * relcache flushes on the target table. Otherwise we risk O(N^2)
17572 * relcache bloat while dropping N columns.
17573 */
17574 resetPQExpBuffer(extra);
17575 firstitem = true;
17576 for (j = 0; j < tbinfo->numatts; j++)
17577 {
17578 if (tbinfo->attisdropped[j])
17579 {
17580 if (firstitem)
17581 {
17582 appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
17583 "UPDATE pg_catalog.pg_attribute\n"
17584 "SET attlen = v.dlen, "
17585 "attalign = v.dalign, "
17586 "attbyval = false\n"
17587 "FROM (VALUES ");
17588 firstitem = false;
17589 }
17590 else
17591 appendPQExpBufferStr(q, ",\n ");
17592 appendPQExpBufferChar(q, '(');
17593 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17594 appendPQExpBuffer(q, ", %d, '%c')",
17595 tbinfo->attlen[j],
17596 tbinfo->attalign[j]);
17597 /* The ALTER ... DROP COLUMN commands must come after */
17598 appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
17600 appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
17601 fmtId(tbinfo->attnames[j]));
17602 }
17603 }
17604 if (!firstitem)
17605 {
17606 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
17607 "WHERE attrelid = ");
17609 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
17610 " AND attname = v.dname;\n");
17611 /* Now we can issue the actual DROP COLUMN commands */
17612 appendBinaryPQExpBuffer(q, extra->data, extra->len);
17613 }
17614
17615 /*
17616 * Fix up inherited columns. As above, do the pg_attribute
17617 * manipulations in a single SQL command.
17618 */
17619 firstitem = true;
17620 for (j = 0; j < tbinfo->numatts; j++)
17621 {
17622 if (!tbinfo->attisdropped[j] &&
17623 !tbinfo->attislocal[j])
17624 {
17625 if (firstitem)
17626 {
17627 appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
17628 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
17629 "SET attislocal = false\n"
17630 "WHERE attrelid = ");
17632 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
17633 " AND attname IN (");
17634 firstitem = false;
17635 }
17636 else
17637 appendPQExpBufferStr(q, ", ");
17638 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17639 }
17640 }
17641 if (!firstitem)
17642 appendPQExpBufferStr(q, ");\n");
17643
17644 /*
17645 * Fix up not-null constraints that come from inheritance. As
17646 * above, do the pg_constraint manipulations in a single SQL
17647 * command. (Actually, two in special cases, if we're doing an
17648 * upgrade from < 18).
17649 */
17650 firstitem = true;
17651 firstitem_extra = true;
17652 resetPQExpBuffer(extra);
17653 for (j = 0; j < tbinfo->numatts; j++)
17654 {
17655 /*
17656 * If a not-null constraint comes from inheritance, reset
17657 * conislocal. The inhcount is fixed by ALTER TABLE INHERIT,
17658 * below. Special hack: in versions < 18, columns with no
17659 * local definition need their constraint to be matched by
17660 * column number in conkeys instead of by constraint name,
17661 * because the latter is not available. (We distinguish the
17662 * case because the constraint name is the empty string.)
17663 */
17664 if (tbinfo->notnull_constrs[j] != NULL &&
17665 !tbinfo->notnull_islocal[j])
17666 {
17667 if (tbinfo->notnull_constrs[j][0] != '\0')
17668 {
17669 if (firstitem)
17670 {
17671 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
17672 "SET conislocal = false\n"
17673 "WHERE contype = 'n' AND conrelid = ");
17675 appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
17676 "conname IN (");
17677 firstitem = false;
17678 }
17679 else
17680 appendPQExpBufferStr(q, ", ");
17681 appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
17682 }
17683 else
17684 {
17685 if (firstitem_extra)
17686 {
17687 appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
17688 "SET conislocal = false\n"
17689 "WHERE contype = 'n' AND conrelid = ");
17691 appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
17692 "conkey IN (");
17693 firstitem_extra = false;
17694 }
17695 else
17696 appendPQExpBufferStr(extra, ", ");
17697 appendPQExpBuffer(extra, "'{%d}'", j + 1);
17698 }
17699 }
17700 }
17701 if (!firstitem)
17702 appendPQExpBufferStr(q, ");\n");
17703 if (!firstitem_extra)
17704 appendPQExpBufferStr(extra, ");\n");
17705
17706 if (extra->len > 0)
17707 appendBinaryPQExpBuffer(q, extra->data, extra->len);
17708
17709 /*
17710 * Add inherited CHECK constraints, if any.
17711 *
17712 * For partitions, they were already dumped, and conislocal
17713 * doesn't need fixing.
17714 *
17715 * As above, issue only one direct manipulation of pg_constraint.
17716 * Although it is tempting to merge the ALTER ADD CONSTRAINT
17717 * commands into one as well, refrain for now due to concern about
17718 * possible backend memory bloat if there are many such
17719 * constraints.
17720 */
17721 resetPQExpBuffer(extra);
17722 firstitem = true;
17723 for (k = 0; k < tbinfo->ncheck; k++)
17724 {
17725 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
17726
17727 if (constr->separate || constr->conislocal || tbinfo->ispartition)
17728 continue;
17729
17730 if (firstitem)
17731 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
17732 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
17734 fmtId(constr->dobj.name),
17735 constr->condef);
17736 /* Update pg_constraint after all the ALTER TABLEs */
17737 if (firstitem)
17738 {
17739 appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
17740 "SET conislocal = false\n"
17741 "WHERE contype = 'c' AND conrelid = ");
17743 appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
17744 appendPQExpBufferStr(extra, " AND conname IN (");
17745 firstitem = false;
17746 }
17747 else
17748 appendPQExpBufferStr(extra, ", ");
17749 appendStringLiteralAH(extra, constr->dobj.name, fout);
17750 }
17751 if (!firstitem)
17752 {
17753 appendPQExpBufferStr(extra, ");\n");
17754 appendBinaryPQExpBuffer(q, extra->data, extra->len);
17755 }
17756
17757 if (numParents > 0 && !tbinfo->ispartition)
17758 {
17759 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
17760 for (k = 0; k < numParents; k++)
17761 {
17762 TableInfo *parentRel = parents[k];
17763
17764 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
17767 }
17768 }
17769
17770 if (OidIsValid(tbinfo->reloftype))
17771 {
17772 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
17773 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
17775 getFormattedTypeName(fout, tbinfo->reloftype,
17776 zeroIsError));
17777 }
17778 }
17779
17780 /*
17781 * In binary_upgrade mode, arrange to restore the old relfrozenxid and
17782 * relminmxid of all vacuumable relations. (While vacuum.c processes
17783 * TOAST tables semi-independently, here we see them only as children
17784 * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
17785 * child toast table is handled below.)
17786 */
17787 if (dopt->binary_upgrade &&
17788 (tbinfo->relkind == RELKIND_RELATION ||
17789 tbinfo->relkind == RELKIND_MATVIEW))
17790 {
17791 appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
17792 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
17793 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
17794 "WHERE oid = ",
17795 tbinfo->frozenxid, tbinfo->minmxid);
17797 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
17798
17799 if (tbinfo->toast_oid)
17800 {
17801 /*
17802 * The toast table will have the same OID at restore, so we
17803 * can safely target it by OID.
17804 */
17805 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
17806 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
17807 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
17808 "WHERE oid = '%u';\n",
17809 tbinfo->toast_frozenxid,
17810 tbinfo->toast_minmxid, tbinfo->toast_oid);
17811 }
17812 }
17813
17814 /*
17815 * In binary_upgrade mode, restore matviews' populated status by
17816 * poking pg_class directly. This is pretty ugly, but we can't use
17817 * REFRESH MATERIALIZED VIEW since it's possible that some underlying
17818 * matview is not populated even though this matview is; in any case,
17819 * we want to transfer the matview's heap storage, not run REFRESH.
17820 */
17821 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
17822 tbinfo->relispopulated)
17823 {
17824 appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
17825 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
17826 "SET relispopulated = 't'\n"
17827 "WHERE oid = ");
17829 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
17830 }
17831
17832 /*
17833 * Dump additional per-column properties that we can't handle in the
17834 * main CREATE TABLE command.
17835 */
17836 for (j = 0; j < tbinfo->numatts; j++)
17837 {
17838 /* None of this applies to dropped columns */
17839 if (tbinfo->attisdropped[j])
17840 continue;
17841
17842 /*
17843 * Dump per-column statistics information. We only issue an ALTER
17844 * TABLE statement if the attstattarget entry for this column is
17845 * not the default value.
17846 */
17847 if (tbinfo->attstattarget[j] >= 0)
17848 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
17850 fmtId(tbinfo->attnames[j]),
17851 tbinfo->attstattarget[j]);
17852
17853 /*
17854 * Dump per-column storage information. The statement is only
17855 * dumped if the storage has been changed from the type's default.
17856 */
17857 if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
17858 {
17859 switch (tbinfo->attstorage[j])
17860 {
17861 case TYPSTORAGE_PLAIN:
17862 storage = "PLAIN";
17863 break;
17865 storage = "EXTERNAL";
17866 break;
17868 storage = "EXTENDED";
17869 break;
17870 case TYPSTORAGE_MAIN:
17871 storage = "MAIN";
17872 break;
17873 default:
17874 storage = NULL;
17875 }
17876
17877 /*
17878 * Only dump the statement if it's a storage type we recognize
17879 */
17880 if (storage != NULL)
17881 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
17883 fmtId(tbinfo->attnames[j]),
17884 storage);
17885 }
17886
17887 /*
17888 * Dump per-column compression, if it's been set.
17889 */
17890 if (!dopt->no_toast_compression)
17891 {
17892 const char *cmname;
17893
17894 switch (tbinfo->attcompression[j])
17895 {
17896 case 'p':
17897 cmname = "pglz";
17898 break;
17899 case 'l':
17900 cmname = "lz4";
17901 break;
17902 default:
17903 cmname = NULL;
17904 break;
17905 }
17906
17907 if (cmname != NULL)
17908 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
17910 fmtId(tbinfo->attnames[j]),
17911 cmname);
17912 }
17913
17914 /*
17915 * Dump per-column attributes.
17916 */
17917 if (tbinfo->attoptions[j][0] != '\0')
17918 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
17920 fmtId(tbinfo->attnames[j]),
17921 tbinfo->attoptions[j]);
17922
17923 /*
17924 * Dump per-column fdw options.
17925 */
17926 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
17927 tbinfo->attfdwoptions[j][0] != '\0')
17929 "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
17930 " %s\n"
17931 ");\n",
17933 fmtId(tbinfo->attnames[j]),
17934 tbinfo->attfdwoptions[j]);
17935 } /* end loop over columns */
17936
17940 }
17941
17942 /*
17943 * dump properties we only have ALTER TABLE syntax for
17944 */
17945 if ((tbinfo->relkind == RELKIND_RELATION ||
17946 tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
17947 tbinfo->relkind == RELKIND_MATVIEW) &&
17948 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
17949 {
17950 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
17951 {
17952 /* nothing to do, will be set when the index is dumped */
17953 }
17954 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
17955 {
17956 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
17957 qualrelname);
17958 }
17959 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
17960 {
17961 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
17962 qualrelname);
17963 }
17964 }
17965
17966 if (tbinfo->forcerowsec)
17967 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
17968 qualrelname);
17969
17970 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
17971
17972 if (dopt->binary_upgrade)
17975 tbinfo->dobj.namespace->dobj.name);
17976
17977 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17978 {
17979 char *tablespace = NULL;
17980 char *tableam = NULL;
17981
17982 /*
17983 * _selectTablespace() relies on tablespace-enabled objects in the
17984 * default tablespace to have a tablespace of "" (empty string) versus
17985 * non-tablespace-enabled objects to have a tablespace of NULL.
17986 * getTables() sets tbinfo->reltablespace to "" for the default
17987 * tablespace (not NULL).
17988 */
17989 if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
17990 tablespace = tbinfo->reltablespace;
17991
17992 if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
17994 tableam = tbinfo->amname;
17995
17996 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
17997 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17998 .namespace = tbinfo->dobj.namespace->dobj.name,
17999 .tablespace = tablespace,
18000 .tableam = tableam,
18001 .relkind = tbinfo->relkind,
18002 .owner = tbinfo->rolname,
18003 .description = reltypename,
18004 .section = tbinfo->postponed_def ?
18006 .createStmt = q->data,
18007 .dropStmt = delq->data));
18008 }
18009
18010 /* Dump Table Comments */
18011 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18013
18014 /* Dump Table Security Labels */
18015 if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
18017
18018 /*
18019 * Dump comments for not-null constraints that aren't to be dumped
18020 * separately (those are processed by collectComments/dumpComment).
18021 */
18022 if (!fout->dopt->no_comments && dopt->dumpSchema &&
18023 fout->remoteVersion >= 180000)
18024 {
18026 PQExpBuffer tag = NULL;
18027
18028 for (j = 0; j < tbinfo->numatts; j++)
18029 {
18030 if (tbinfo->notnull_constrs[j] != NULL &&
18031 tbinfo->notnull_comment[j] != NULL)
18032 {
18033 if (comment == NULL)
18034 {
18036 tag = createPQExpBuffer();
18037 }
18038 else
18039 {
18041 resetPQExpBuffer(tag);
18042 }
18043
18044 appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
18045 fmtId(tbinfo->notnull_constrs[j]), qualrelname);
18046 appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
18048
18049 appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
18050 fmtId(tbinfo->notnull_constrs[j]), qrelname);
18051
18053 ARCHIVE_OPTS(.tag = tag->data,
18054 .namespace = tbinfo->dobj.namespace->dobj.name,
18055 .owner = tbinfo->rolname,
18056 .description = "COMMENT",
18057 .section = SECTION_NONE,
18058 .createStmt = comment->data,
18059 .deps = &(tbinfo->dobj.dumpId),
18060 .nDeps = 1));
18061 }
18062 }
18063
18065 destroyPQExpBuffer(tag);
18066 }
18067
18068 /* Dump comments on inlined table constraints */
18069 for (j = 0; j < tbinfo->ncheck; j++)
18070 {
18071 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
18072
18073 if (constr->separate || !constr->conislocal)
18074 continue;
18075
18076 if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
18078 }
18079
18082 destroyPQExpBuffer(extra);
18085}
18086
18087/*
18088 * dumpTableAttach
18089 * write to fout the commands to attach a child partition
18090 *
18091 * Child partitions are always made by creating them separately
18092 * and then using ATTACH PARTITION, rather than using
18093 * CREATE TABLE ... PARTITION OF. This is important for preserving
18094 * any possible discrepancy in column layout, to allow assigning the
18095 * correct tablespace if different, and so that it's possible to restore
18096 * a partition without restoring its parent. (You'll get an error from
18097 * the ATTACH PARTITION command, but that can be ignored, or skipped
18098 * using "pg_restore -L" if you prefer.) The last point motivates
18099 * treating ATTACH PARTITION as a completely separate ArchiveEntry
18100 * rather than emitting it within the child partition's ArchiveEntry.
18101 */
18102static void
18104{
18105 DumpOptions *dopt = fout->dopt;
18106 PQExpBuffer q;
18107 PGresult *res;
18108 char *partbound;
18109
18110 /* Do nothing if not dumping schema */
18111 if (!dopt->dumpSchema)
18112 return;
18113
18114 q = createPQExpBuffer();
18115
18116 if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
18117 {
18118 /* Set up query for partbound details */
18120 "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
18121
18123 "SELECT pg_get_expr(c.relpartbound, c.oid) "
18124 "FROM pg_class c "
18125 "WHERE c.oid = $1");
18126
18128
18129 fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
18130 }
18131
18133 "EXECUTE dumpTableAttach('%u')",
18134 attachinfo->partitionTbl->dobj.catId.oid);
18135
18137 partbound = PQgetvalue(res, 0, 0);
18138
18139 /* Perform ALTER TABLE on the parent */
18141 "ALTER TABLE ONLY %s ",
18142 fmtQualifiedDumpable(attachinfo->parentTbl));
18144 "ATTACH PARTITION %s %s;\n",
18145 fmtQualifiedDumpable(attachinfo->partitionTbl),
18146 partbound);
18147
18148 /*
18149 * There is no point in creating a drop query as the drop is done by table
18150 * drop. (If you think to change this, see also _printTocEntry().)
18151 * Although this object doesn't really have ownership as such, set the
18152 * owner field anyway to ensure that the command is run by the correct
18153 * role at restore time.
18154 */
18155 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
18156 ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
18157 .namespace = attachinfo->dobj.namespace->dobj.name,
18158 .owner = attachinfo->partitionTbl->rolname,
18159 .description = "TABLE ATTACH",
18160 .section = SECTION_PRE_DATA,
18161 .createStmt = q->data));
18162
18163 PQclear(res);
18165}
18166
18167/*
18168 * dumpAttrDef --- dump an attribute's default-value declaration
18169 */
18170static void
18172{
18173 DumpOptions *dopt = fout->dopt;
18174 TableInfo *tbinfo = adinfo->adtable;
18175 int adnum = adinfo->adnum;
18176 PQExpBuffer q;
18178 char *qualrelname;
18179 char *tag;
18180 char *foreign;
18181
18182 /* Do nothing if not dumping schema */
18183 if (!dopt->dumpSchema)
18184 return;
18185
18186 /* Skip if not "separate"; it was dumped in the table's definition */
18187 if (!adinfo->separate)
18188 return;
18189
18190 q = createPQExpBuffer();
18192
18194
18195 foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
18196
18198 "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
18199 foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
18200 adinfo->adef_expr);
18201
18202 appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
18204 fmtId(tbinfo->attnames[adnum - 1]));
18205
18206 tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
18207
18208 if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18209 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
18210 ARCHIVE_OPTS(.tag = tag,
18211 .namespace = tbinfo->dobj.namespace->dobj.name,
18212 .owner = tbinfo->rolname,
18213 .description = "DEFAULT",
18214 .section = SECTION_PRE_DATA,
18215 .createStmt = q->data,
18216 .dropStmt = delq->data));
18217
18218 pfree(tag);
18222}
18223
18224/*
18225 * getAttrName: extract the correct name for an attribute
18226 *
18227 * The array tblInfo->attnames[] only provides names of user attributes;
18228 * if a system attribute number is supplied, we have to fake it.
18229 * We also do a little bit of bounds checking for safety's sake.
18230 */
18231static const char *
18232getAttrName(int attrnum, const TableInfo *tblInfo)
18233{
18234 if (attrnum > 0 && attrnum <= tblInfo->numatts)
18235 return tblInfo->attnames[attrnum - 1];
18236 switch (attrnum)
18237 {
18239 return "ctid";
18241 return "xmin";
18243 return "cmin";
18245 return "xmax";
18247 return "cmax";
18249 return "tableoid";
18250 }
18251 pg_fatal("invalid column number %d for table \"%s\"",
18252 attrnum, tblInfo->dobj.name);
18253 return NULL; /* keep compiler quiet */
18254}
18255
18256/*
18257 * dumpIndex
18258 * write out to fout a user-defined index
18259 */
18260static void
18262{
18263 DumpOptions *dopt = fout->dopt;
18264 TableInfo *tbinfo = indxinfo->indextable;
18265 bool is_constraint = (indxinfo->indexconstraint != 0);
18266 PQExpBuffer q;
18268 char *qindxname;
18269 char *qqindxname;
18270
18271 /* Do nothing if not dumping schema */
18272 if (!dopt->dumpSchema)
18273 return;
18274
18275 q = createPQExpBuffer();
18277
18278 qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
18280
18281 /*
18282 * If there's an associated constraint, don't dump the index per se, but
18283 * do dump any comment for it. (This is safe because dependency ordering
18284 * will have ensured the constraint is emitted first.) Note that the
18285 * emitted comment has to be shown as depending on the constraint, not the
18286 * index, in such cases.
18287 */
18288 if (!is_constraint)
18289 {
18290 char *indstatcols = indxinfo->indstatcols;
18291 char *indstatvals = indxinfo->indstatvals;
18292 char **indstatcolsarray = NULL;
18293 char **indstatvalsarray = NULL;
18294 int nstatcols = 0;
18295 int nstatvals = 0;
18296
18297 if (dopt->binary_upgrade)
18299 indxinfo->dobj.catId.oid);
18300
18301 /* Plain secondary index */
18302 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
18303
18304 /*
18305 * Append ALTER TABLE commands as needed to set properties that we
18306 * only have ALTER TABLE syntax for. Keep this in sync with the
18307 * similar code in dumpConstraint!
18308 */
18309
18310 /* If the index is clustered, we need to record that. */
18311 if (indxinfo->indisclustered)
18312 {
18313 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
18315 /* index name is not qualified in this syntax */
18316 appendPQExpBuffer(q, " ON %s;\n",
18317 qindxname);
18318 }
18319
18320 /*
18321 * If the index has any statistics on some of its columns, generate
18322 * the associated ALTER INDEX queries.
18323 */
18324 if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
18325 {
18326 int j;
18327
18328 if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
18329 pg_fatal("could not parse index statistic columns");
18330 if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
18331 pg_fatal("could not parse index statistic values");
18332 if (nstatcols != nstatvals)
18333 pg_fatal("mismatched number of columns and values for index statistics");
18334
18335 for (j = 0; j < nstatcols; j++)
18336 {
18337 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
18338
18339 /*
18340 * Note that this is a column number, so no quotes should be
18341 * used.
18342 */
18343 appendPQExpBuffer(q, "ALTER COLUMN %s ",
18345 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
18347 }
18348 }
18349
18350 /* Indexes can depend on extensions */
18352 "pg_catalog.pg_class",
18353 "INDEX", qqindxname);
18354
18355 /* If the index defines identity, we need to record that. */
18356 if (indxinfo->indisreplident)
18357 {
18358 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
18360 /* index name is not qualified in this syntax */
18361 appendPQExpBuffer(q, " INDEX %s;\n",
18362 qindxname);
18363 }
18364
18365 /*
18366 * If this index is a member of a partitioned index, the backend will
18367 * not allow us to drop it separately, so don't try. It will go away
18368 * automatically when we drop either the index's table or the
18369 * partitioned index. (If, in a selective restore with --clean, we
18370 * drop neither of those, then this index will not be dropped either.
18371 * But that's fine, and even if you think it's not, the backend won't
18372 * let us do differently.)
18373 */
18374 if (indxinfo->parentidx == 0)
18375 appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
18376
18377 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18378 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
18379 ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
18380 .namespace = tbinfo->dobj.namespace->dobj.name,
18381 .tablespace = indxinfo->tablespace,
18382 .owner = tbinfo->rolname,
18383 .description = "INDEX",
18384 .section = SECTION_POST_DATA,
18385 .createStmt = q->data,
18386 .dropStmt = delq->data));
18387
18390 }
18391
18392 /* Dump Index Comments */
18393 if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18394 dumpComment(fout, "INDEX", qindxname,
18395 tbinfo->dobj.namespace->dobj.name,
18396 tbinfo->rolname,
18397 indxinfo->dobj.catId, 0,
18398 is_constraint ? indxinfo->indexconstraint :
18399 indxinfo->dobj.dumpId);
18400
18405}
18406
18407/*
18408 * dumpIndexAttach
18409 * write out to fout a partitioned-index attachment clause
18410 */
18411static void
18413{
18414 /* Do nothing if not dumping schema */
18415 if (!fout->dopt->dumpSchema)
18416 return;
18417
18418 if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
18419 {
18421
18422 appendPQExpBuffer(q, "ALTER INDEX %s ",
18423 fmtQualifiedDumpable(attachinfo->parentIdx));
18424 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
18425 fmtQualifiedDumpable(attachinfo->partitionIdx));
18426
18427 /*
18428 * There is no need for a dropStmt since the drop is done implicitly
18429 * when we drop either the index's table or the partitioned index.
18430 * Moreover, since there's no ALTER INDEX DETACH PARTITION command,
18431 * there's no way to do it anyway. (If you think to change this,
18432 * consider also what to do with --if-exists.)
18433 *
18434 * Although this object doesn't really have ownership as such, set the
18435 * owner field anyway to ensure that the command is run by the correct
18436 * role at restore time.
18437 */
18438 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
18439 ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
18440 .namespace = attachinfo->dobj.namespace->dobj.name,
18441 .owner = attachinfo->parentIdx->indextable->rolname,
18442 .description = "INDEX ATTACH",
18443 .section = SECTION_POST_DATA,
18444 .createStmt = q->data));
18445
18447 }
18448}
18449
18450/*
18451 * dumpStatisticsExt
18452 * write out to fout an extended statistics object
18453 */
18454static void
18456{
18457 DumpOptions *dopt = fout->dopt;
18458 PQExpBuffer q;
18460 PQExpBuffer query;
18461 char *qstatsextname;
18462 PGresult *res;
18463 char *stxdef;
18464
18465 /* Do nothing if not dumping schema */
18466 if (!dopt->dumpSchema)
18467 return;
18468
18469 q = createPQExpBuffer();
18471 query = createPQExpBuffer();
18472
18474
18475 appendPQExpBuffer(query, "SELECT "
18476 "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
18477 statsextinfo->dobj.catId.oid);
18478
18479 res = ExecuteSqlQueryForSingleRow(fout, query->data);
18480
18481 stxdef = PQgetvalue(res, 0, 0);
18482
18483 /* Result of pg_get_statisticsobjdef is complete except for semicolon */
18484 appendPQExpBuffer(q, "%s;\n", stxdef);
18485
18486 /*
18487 * We only issue an ALTER STATISTICS statement if the stxstattarget entry
18488 * for this statistics object is not the default value.
18489 */
18490 if (statsextinfo->stattarget >= 0)
18491 {
18492 appendPQExpBuffer(q, "ALTER STATISTICS %s ",
18494 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
18495 statsextinfo->stattarget);
18496 }
18497
18498 appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
18500
18501 if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18502 ArchiveEntry(fout, statsextinfo->dobj.catId,
18503 statsextinfo->dobj.dumpId,
18504 ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
18505 .namespace = statsextinfo->dobj.namespace->dobj.name,
18506 .owner = statsextinfo->rolname,
18507 .description = "STATISTICS",
18508 .section = SECTION_POST_DATA,
18509 .createStmt = q->data,
18510 .dropStmt = delq->data));
18511
18512 /* Dump Statistics Comments */
18513 if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18514 dumpComment(fout, "STATISTICS", qstatsextname,
18515 statsextinfo->dobj.namespace->dobj.name,
18516 statsextinfo->rolname,
18517 statsextinfo->dobj.catId, 0,
18518 statsextinfo->dobj.dumpId);
18519
18520 PQclear(res);
18523 destroyPQExpBuffer(query);
18525}
18526
18527/*
18528 * dumpStatisticsExtStats
18529 * write out to fout the stats for an extended statistics object
18530 */
18531static void
18533{
18534 DumpOptions *dopt = fout->dopt;
18535 PQExpBuffer query;
18536 PGresult *res;
18537 int nstats;
18538
18539 /* Do nothing if not dumping statistics */
18540 if (!dopt->dumpStatistics)
18541 return;
18542
18543 if (!fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS])
18544 {
18546
18547 /*---------
18548 * Set up query for details about extended statistics objects.
18549 *
18550 * The query depends on the backend version:
18551 * - In v19 and newer versions, query directly the pg_stats_ext*
18552 * catalogs.
18553 * - In v18 and older versions, ndistinct and dependencies have a
18554 * different format that needs translation.
18555 * - In v14 and older versions, inherited does not exist.
18556 * - In v11 and older versions, there is no pg_stats_ext, hence
18557 * the logic joins pg_statistic_ext and pg_namespace.
18558 *---------
18559 */
18560
18562 "PREPARE getExtStatsStats(pg_catalog.name, pg_catalog.name) AS\n"
18563 "SELECT ");
18564
18565 /*
18566 * Versions 15 and newer have inherited stats.
18567 *
18568 * Create this column in all versions because we need to order by it
18569 * later.
18570 */
18571 if (fout->remoteVersion >= 150000)
18572 appendPQExpBufferStr(pq, "e.inherited, ");
18573 else
18574 appendPQExpBufferStr(pq, "false AS inherited, ");
18575
18576 /*--------
18577 * The ndistinct and dependencies formats changed in v19, so
18578 * everything before that needs to be translated.
18579 *
18580 * The ndistinct translation converts this kind of data:
18581 * {"3, 4": 11, "3, 6": 11, "4, 6": 11, "3, 4, 6": 11}
18582 *
18583 * to this:
18584 * [ {"attributes": [3,4], "ndistinct": 11},
18585 * {"attributes": [3,6], "ndistinct": 11},
18586 * {"attributes": [4,6], "ndistinct": 11},
18587 * {"attributes": [3,4,6], "ndistinct": 11} ]
18588 *
18589 * The dependencies translation converts this kind of data:
18590 * {"3 => 4": 1.000000, "3 => 6": 1.000000,
18591 * "4 => 6": 1.000000, "3, 4 => 6": 1.000000,
18592 * "3, 6 => 4": 1.000000}
18593 *
18594 * to this:
18595 * [ {"attributes": [3], "dependency": 4, "degree": 1.000000},
18596 * {"attributes": [3], "dependency": 6, "degree": 1.000000},
18597 * {"attributes": [4], "dependency": 6, "degree": 1.000000},
18598 * {"attributes": [3,4], "dependency": 6, "degree": 1.000000},
18599 * {"attributes": [3,6], "dependency": 4, "degree": 1.000000} ]
18600 *--------
18601 */
18602 if (fout->remoteVersion >= 190000)
18603 appendPQExpBufferStr(pq, "e.n_distinct, e.dependencies, ");
18604 else
18606 "( "
18607 "SELECT json_agg( "
18608 " json_build_object( "
18610 " string_to_array(kv.key, ', ')::integer[], "
18612 " kv.value::bigint )) "
18613 "FROM json_each_text(e.n_distinct::text::json) AS kv"
18614 ") AS n_distinct, "
18615 "( "
18616 "SELECT json_agg( "
18617 " json_build_object( "
18619 " string_to_array( "
18620 " split_part(kv.key, ' => ', 1), "
18621 " ', ')::integer[], "
18623 " split_part(kv.key, ' => ', 2)::integer, "
18625 " kv.value::double precision )) "
18626 "FROM json_each_text(e.dependencies::text::json) AS kv "
18627 ") AS dependencies, ");
18628
18629 /* MCV was introduced v13 */
18630 if (fout->remoteVersion >= 130000)
18632 "e.most_common_vals, e.most_common_freqs, "
18633 "e.most_common_base_freqs, ");
18634 else
18636 "NULL AS most_common_vals, NULL AS most_common_freqs, "
18637 "NULL AS most_common_base_freqs, ");
18638
18639 /* Expressions were introduced in v14 */
18640 if (fout->remoteVersion >= 140000)
18641 {
18642 /*
18643 * There is no ordering column in pg_stats_ext_exprs. However, we
18644 * can rely on the unnesting of pg_statistic_ext_data.stxdexpr to
18645 * maintain the desired order of expression elements.
18646 */
18648 "( "
18649 "SELECT jsonb_pretty(jsonb_agg("
18650 "nullif(j.obj, '{}'::jsonb))) "
18651 "FROM pg_stats_ext_exprs AS ee "
18652 "CROSS JOIN LATERAL jsonb_strip_nulls("
18653 " jsonb_build_object( "
18654 " 'null_frac', ee.null_frac::text, "
18655 " 'avg_width', ee.avg_width::text, "
18656 " 'n_distinct', ee.n_distinct::text, "
18657 " 'most_common_vals', ee.most_common_vals::text, "
18658 " 'most_common_freqs', ee.most_common_freqs::text, "
18659 " 'histogram_bounds', ee.histogram_bounds::text, "
18660 " 'correlation', ee.correlation::text, "
18661 " 'most_common_elems', ee.most_common_elems::text, "
18662 " 'most_common_elem_freqs', ee.most_common_elem_freqs::text, "
18663 " 'elem_count_histogram', ee.elem_count_histogram::text");
18664
18665 /* These three have been added to pg_stats_ext_exprs in v19. */
18666 if (fout->remoteVersion >= 190000)
18668 ", "
18669 " 'range_length_histogram', ee.range_length_histogram::text, "
18670 " 'range_empty_frac', ee.range_empty_frac::text, "
18671 " 'range_bounds_histogram', ee.range_bounds_histogram::text");
18672
18674 " )) AS j(obj)"
18675 "WHERE ee.statistics_schemaname = $1 "
18676 "AND ee.statistics_name = $2 ");
18677 /* Inherited expressions introduced in v15 */
18678 if (fout->remoteVersion >= 150000)
18679 appendPQExpBufferStr(pq, "AND ee.inherited = e.inherited");
18680
18681 appendPQExpBufferStr(pq, ") AS exprs ");
18682 }
18683 else
18684 appendPQExpBufferStr(pq, "NULL AS exprs ");
18685
18686 /* pg_stats_ext introduced in v12 */
18687 if (fout->remoteVersion >= 120000)
18689 "FROM pg_catalog.pg_stats_ext AS e "
18690 "WHERE e.statistics_schemaname = $1 "
18691 "AND e.statistics_name = $2 ");
18692 else
18694 "FROM ( "
18695 "SELECT s.stxndistinct AS n_distinct, "
18696 " s.stxdependencies AS dependencies "
18697 "FROM pg_catalog.pg_statistic_ext AS s "
18698 "JOIN pg_catalog.pg_namespace AS n "
18699 "ON n.oid = s.stxnamespace "
18700 "WHERE n.nspname = $1 "
18701 "AND s.stxname = $2 "
18702 ") AS e ");
18703
18704 /* we always have an inherited column, but it may be a constant */
18705 appendPQExpBufferStr(pq, "ORDER BY inherited");
18706
18707 ExecuteSqlStatement(fout, pq->data);
18708
18709 fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS] = true;
18710
18712 }
18713
18714 query = createPQExpBuffer();
18715
18716 appendPQExpBufferStr(query, "EXECUTE getExtStatsStats(");
18717 appendStringLiteralAH(query, statsextinfo->dobj.namespace->dobj.name, fout);
18718 appendPQExpBufferStr(query, "::pg_catalog.name, ");
18719 appendStringLiteralAH(query, statsextinfo->dobj.name, fout);
18720 appendPQExpBufferStr(query, "::pg_catalog.name)");
18721
18722 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18723
18724 destroyPQExpBuffer(query);
18725
18726 nstats = PQntuples(res);
18727
18728 if (nstats > 0)
18729 {
18731
18732 int i_inherited = PQfnumber(res, "inherited");
18733 int i_ndistinct = PQfnumber(res, "n_distinct");
18734 int i_dependencies = PQfnumber(res, "dependencies");
18735 int i_mcv = PQfnumber(res, "most_common_vals");
18736 int i_mcf = PQfnumber(res, "most_common_freqs");
18737 int i_mcbf = PQfnumber(res, "most_common_base_freqs");
18738 int i_exprs = PQfnumber(res, "exprs");
18739
18740 for (int i = 0; i < nstats; i++)
18741 {
18742 TableInfo *tbinfo = statsextinfo->stattable;
18743
18744 if (PQgetisnull(res, i, i_inherited))
18745 pg_fatal("inherited cannot be NULL");
18746
18748 "SELECT * FROM pg_catalog.pg_restore_extended_stats(\n");
18749 appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
18750 fout->remoteVersion);
18751
18752 /* Relation information */
18753 appendPQExpBufferStr(out, "\t'schemaname', ");
18754 appendStringLiteralAH(out, tbinfo->dobj.namespace->dobj.name, fout);
18755 appendPQExpBufferStr(out, ",\n\t'relname', ");
18756 appendStringLiteralAH(out, tbinfo->dobj.name, fout);
18757
18758 /* Extended statistics information */
18759 appendPQExpBufferStr(out, ",\n\t'statistics_schemaname', ");
18760 appendStringLiteralAH(out, statsextinfo->dobj.namespace->dobj.name, fout);
18761 appendPQExpBufferStr(out, ",\n\t'statistics_name', ");
18762 appendStringLiteralAH(out, statsextinfo->dobj.name, fout);
18763 appendNamedArgument(out, fout, "inherited", "boolean",
18764 PQgetvalue(res, i, i_inherited));
18765
18766 if (!PQgetisnull(res, i, i_ndistinct))
18767 appendNamedArgument(out, fout, "n_distinct", "pg_ndistinct",
18768 PQgetvalue(res, i, i_ndistinct));
18769
18770 if (!PQgetisnull(res, i, i_dependencies))
18771 appendNamedArgument(out, fout, "dependencies", "pg_dependencies",
18772 PQgetvalue(res, i, i_dependencies));
18773
18774 if (!PQgetisnull(res, i, i_mcv))
18775 appendNamedArgument(out, fout, "most_common_vals", "text[]",
18776 PQgetvalue(res, i, i_mcv));
18777
18778 if (!PQgetisnull(res, i, i_mcf))
18779 appendNamedArgument(out, fout, "most_common_freqs", "double precision[]",
18780 PQgetvalue(res, i, i_mcf));
18781
18782 if (!PQgetisnull(res, i, i_mcbf))
18783 appendNamedArgument(out, fout, "most_common_base_freqs", "double precision[]",
18784 PQgetvalue(res, i, i_mcbf));
18785
18786 if (!PQgetisnull(res, i, i_exprs))
18787 appendNamedArgument(out, fout, "exprs", "jsonb",
18788 PQgetvalue(res, i, i_exprs));
18789
18790 appendPQExpBufferStr(out, "\n);\n");
18791 }
18792
18794 ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
18795 .namespace = statsextinfo->dobj.namespace->dobj.name,
18796 .owner = statsextinfo->rolname,
18797 .description = "EXTENDED STATISTICS DATA",
18798 .section = SECTION_POST_DATA,
18799 .createStmt = out->data,
18800 .deps = &statsextinfo->dobj.dumpId,
18801 .nDeps = 1));
18802 destroyPQExpBuffer(out);
18803 }
18804 PQclear(res);
18805}
18806
18807/*
18808 * dumpConstraint
18809 * write out to fout a user-defined constraint
18810 */
18811static void
18813{
18814 DumpOptions *dopt = fout->dopt;
18815 TableInfo *tbinfo = coninfo->contable;
18816 PQExpBuffer q;
18818 char *tag = NULL;
18819 char *foreign;
18820
18821 /* Do nothing if not dumping schema */
18822 if (!dopt->dumpSchema)
18823 return;
18824
18825 q = createPQExpBuffer();
18827
18828 foreign = tbinfo &&
18829 tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
18830
18831 if (coninfo->contype == 'p' ||
18832 coninfo->contype == 'u' ||
18833 coninfo->contype == 'x')
18834 {
18835 /* Index-related constraint */
18837 int k;
18838
18840
18841 if (indxinfo == NULL)
18842 pg_fatal("missing index for constraint \"%s\"",
18843 coninfo->dobj.name);
18844
18845 if (dopt->binary_upgrade)
18847 indxinfo->dobj.catId.oid);
18848
18849 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
18851 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
18852 fmtId(coninfo->dobj.name));
18853
18854 if (coninfo->condef)
18855 {
18856 /* pg_get_constraintdef should have provided everything */
18857 appendPQExpBuffer(q, "%s;\n", coninfo->condef);
18858 }
18859 else
18860 {
18862 coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
18863
18864 /*
18865 * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
18866 * indexes. Being able to create this was fixed, but we need to
18867 * make the index distinct in order to be able to restore the
18868 * dump.
18869 */
18870 if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
18871 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
18872 appendPQExpBufferStr(q, " (");
18873 for (k = 0; k < indxinfo->indnkeyattrs; k++)
18874 {
18875 int indkey = (int) indxinfo->indkeys[k];
18876 const char *attname;
18877
18879 break;
18881
18882 appendPQExpBuffer(q, "%s%s",
18883 (k == 0) ? "" : ", ",
18884 fmtId(attname));
18885 }
18886 if (coninfo->conperiod)
18887 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
18888
18889 if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
18890 appendPQExpBufferStr(q, ") INCLUDE (");
18891
18892 for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
18893 {
18894 int indkey = (int) indxinfo->indkeys[k];
18895 const char *attname;
18896
18898 break;
18900
18901 appendPQExpBuffer(q, "%s%s",
18902 (k == indxinfo->indnkeyattrs) ? "" : ", ",
18903 fmtId(attname));
18904 }
18905
18906 appendPQExpBufferChar(q, ')');
18907
18908 if (nonemptyReloptions(indxinfo->indreloptions))
18909 {
18910 appendPQExpBufferStr(q, " WITH (");
18911 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
18912 appendPQExpBufferChar(q, ')');
18913 }
18914
18915 if (coninfo->condeferrable)
18916 {
18917 appendPQExpBufferStr(q, " DEFERRABLE");
18918 if (coninfo->condeferred)
18919 appendPQExpBufferStr(q, " INITIALLY DEFERRED");
18920 }
18921
18922 appendPQExpBufferStr(q, ";\n");
18923 }
18924
18925 /*
18926 * Append ALTER TABLE commands as needed to set properties that we
18927 * only have ALTER TABLE syntax for. Keep this in sync with the
18928 * similar code in dumpIndex!
18929 */
18930
18931 /* If the index is clustered, we need to record that. */
18932 if (indxinfo->indisclustered)
18933 {
18934 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
18936 /* index name is not qualified in this syntax */
18937 appendPQExpBuffer(q, " ON %s;\n",
18938 fmtId(indxinfo->dobj.name));
18939 }
18940
18941 /* If the index defines identity, we need to record that. */
18942 if (indxinfo->indisreplident)
18943 {
18944 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
18946 /* index name is not qualified in this syntax */
18947 appendPQExpBuffer(q, " INDEX %s;\n",
18948 fmtId(indxinfo->dobj.name));
18949 }
18950
18951 /* Indexes can depend on extensions */
18953 "pg_catalog.pg_class", "INDEX",
18955
18956 appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
18958 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
18959 fmtId(coninfo->dobj.name));
18960
18961 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18962
18963 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18964 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
18965 ARCHIVE_OPTS(.tag = tag,
18966 .namespace = tbinfo->dobj.namespace->dobj.name,
18967 .tablespace = indxinfo->tablespace,
18968 .owner = tbinfo->rolname,
18969 .description = "CONSTRAINT",
18970 .section = SECTION_POST_DATA,
18971 .createStmt = q->data,
18972 .dropStmt = delq->data));
18973 }
18974 else if (coninfo->contype == 'f')
18975 {
18976 char *only;
18977
18978 /*
18979 * Foreign keys on partitioned tables are always declared as
18980 * inheriting to partitions; for all other cases, emit them as
18981 * applying ONLY directly to the named table, because that's how they
18982 * work for regular inherited tables.
18983 */
18984 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
18985
18986 /*
18987 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
18988 * current table data is not processed
18989 */
18990 appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
18992 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
18993 fmtId(coninfo->dobj.name),
18994 coninfo->condef);
18995
18996 appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
18998 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
18999 fmtId(coninfo->dobj.name));
19000
19001 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
19002
19003 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19004 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
19005 ARCHIVE_OPTS(.tag = tag,
19006 .namespace = tbinfo->dobj.namespace->dobj.name,
19007 .owner = tbinfo->rolname,
19008 .description = "FK CONSTRAINT",
19009 .section = SECTION_POST_DATA,
19010 .createStmt = q->data,
19011 .dropStmt = delq->data));
19012 }
19013 else if ((coninfo->contype == 'c' || coninfo->contype == 'n') && tbinfo)
19014 {
19015 /* CHECK or invalid not-null constraint on a table */
19016
19017 /* Ignore if not to be dumped separately, or if it was inherited */
19018 if (coninfo->separate && coninfo->conislocal)
19019 {
19020 const char *keyword;
19021
19022 if (coninfo->contype == 'c')
19023 keyword = "CHECK CONSTRAINT";
19024 else
19025 keyword = "CONSTRAINT";
19026
19027 /* not ONLY since we want it to propagate to children */
19028 appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
19030 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
19031 fmtId(coninfo->dobj.name),
19032 coninfo->condef);
19033
19034 appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
19036 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
19037 fmtId(coninfo->dobj.name));
19038
19039 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
19040
19041 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19042 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
19043 ARCHIVE_OPTS(.tag = tag,
19044 .namespace = tbinfo->dobj.namespace->dobj.name,
19045 .owner = tbinfo->rolname,
19046 .description = keyword,
19047 .section = SECTION_POST_DATA,
19048 .createStmt = q->data,
19049 .dropStmt = delq->data));
19050 }
19051 }
19052 else if (tbinfo == NULL)
19053 {
19054 /* CHECK, NOT NULL constraint on a domain */
19055 TypeInfo *tyinfo = coninfo->condomain;
19056
19057 Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
19058
19059 /* Ignore if not to be dumped separately */
19060 if (coninfo->separate)
19061 {
19062 const char *keyword;
19063
19064 if (coninfo->contype == 'c')
19065 keyword = "CHECK CONSTRAINT";
19066 else
19067 keyword = "CONSTRAINT";
19068
19069 appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
19071 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
19072 fmtId(coninfo->dobj.name),
19073 coninfo->condef);
19074
19075 appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
19077 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
19078 fmtId(coninfo->dobj.name));
19079
19080 tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
19081
19082 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19083 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
19084 ARCHIVE_OPTS(.tag = tag,
19085 .namespace = tyinfo->dobj.namespace->dobj.name,
19086 .owner = tyinfo->rolname,
19087 .description = keyword,
19088 .section = SECTION_POST_DATA,
19089 .createStmt = q->data,
19090 .dropStmt = delq->data));
19091
19092 if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19093 {
19095 char *qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
19096
19097 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
19098 fmtId(coninfo->dobj.name));
19099
19101 tyinfo->dobj.namespace->dobj.name,
19102 tyinfo->rolname,
19103 coninfo->dobj.catId, 0, coninfo->dobj.dumpId);
19106 }
19107 }
19108 }
19109 else
19110 {
19111 pg_fatal("unrecognized constraint type: %c",
19112 coninfo->contype);
19113 }
19114
19115 /* Dump Constraint Comments --- only works for table constraints */
19116 if (tbinfo && coninfo->separate &&
19117 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19119
19120 pfree(tag);
19123}
19124
19125/*
19126 * dumpTableConstraintComment --- dump a constraint's comment if any
19127 *
19128 * This is split out because we need the function in two different places
19129 * depending on whether the constraint is dumped as part of CREATE TABLE
19130 * or as a separate ALTER command.
19131 */
19132static void
19134{
19135 TableInfo *tbinfo = coninfo->contable;
19137 char *qtabname;
19138
19139 qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19140
19141 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
19142 fmtId(coninfo->dobj.name));
19143
19144 if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19146 tbinfo->dobj.namespace->dobj.name,
19147 tbinfo->rolname,
19148 coninfo->dobj.catId, 0,
19149 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
19150
19153}
19154
19155static inline SeqType
19156parse_sequence_type(const char *name)
19157{
19158 for (size_t i = 0; i < lengthof(SeqTypeNames); i++)
19159 {
19160 if (strcmp(SeqTypeNames[i], name) == 0)
19161 return (SeqType) i;
19162 }
19163
19164 pg_fatal("unrecognized sequence type: %s", name);
19165 return (SeqType) 0; /* keep compiler quiet */
19166}
19167
19168/*
19169 * bsearch() comparator for SequenceItem
19170 */
19171static int
19172SequenceItemCmp(const void *p1, const void *p2)
19173{
19174 SequenceItem v1 = *((const SequenceItem *) p1);
19175 SequenceItem v2 = *((const SequenceItem *) p2);
19176
19177 return pg_cmp_u32(v1.oid, v2.oid);
19178}
19179
19180/*
19181 * collectSequences
19182 *
19183 * Construct a table of sequence information. This table is sorted by OID for
19184 * speed in lookup.
19185 */
19186static void
19188{
19189 PGresult *res;
19190 const char *query;
19191
19192 /*
19193 * Since version 18, we can gather the sequence data in this query with
19194 * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
19195 */
19196 if (fout->remoteVersion < 180000 ||
19197 (!fout->dopt->dumpData && !fout->dopt->sequence_data))
19198 query = "SELECT seqrelid, format_type(seqtypid, NULL), "
19199 "seqstart, seqincrement, "
19200 "seqmax, seqmin, "
19201 "seqcache, seqcycle, "
19202 "NULL, 'f' "
19203 "FROM pg_catalog.pg_sequence "
19204 "ORDER BY seqrelid";
19205 else
19206 query = "SELECT seqrelid, format_type(seqtypid, NULL), "
19207 "seqstart, seqincrement, "
19208 "seqmax, seqmin, "
19209 "seqcache, seqcycle, "
19210 "last_value, is_called "
19211 "FROM pg_catalog.pg_sequence, "
19212 "pg_get_sequence_data(seqrelid) "
19213 "ORDER BY seqrelid;";
19214
19215 res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
19216
19217 nsequences = PQntuples(res);
19219
19220 for (int i = 0; i < nsequences; i++)
19221 {
19222 sequences[i].oid = atooid(PQgetvalue(res, i, 0));
19224 sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
19225 sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
19226 sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
19227 sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
19228 sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
19229 sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
19230 sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
19231 sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
19232 sequences[i].null_seqtuple = (PQgetisnull(res, i, 8) || PQgetisnull(res, i, 9));
19233 }
19234
19235 PQclear(res);
19236}
19237
19238/*
19239 * dumpSequence
19240 * write the declaration (not data) of one user-defined sequence
19241 */
19242static void
19244{
19245 DumpOptions *dopt = fout->dopt;
19247 bool is_ascending;
19252 char *qseqname;
19253 TableInfo *owning_tab = NULL;
19254 SequenceItem key = {0};
19255
19256 qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
19257
19258 /*
19259 * The sequence information is gathered in a sorted table before any calls
19260 * to dumpSequence(). See collectSequences() for more information.
19261 */
19263
19264 key.oid = tbinfo->dobj.catId.oid;
19266 sizeof(SequenceItem), SequenceItemCmp);
19267
19268 /* Calculate default limits for a sequence of this type */
19269 is_ascending = (seq->incby >= 0);
19270 if (seq->seqtype == SEQTYPE_SMALLINT)
19271 {
19274 }
19275 else if (seq->seqtype == SEQTYPE_INTEGER)
19276 {
19279 }
19280 else if (seq->seqtype == SEQTYPE_BIGINT)
19281 {
19284 }
19285 else
19286 {
19287 pg_fatal("unrecognized sequence type: %d", seq->seqtype);
19288 default_minv = default_maxv = 0; /* keep compiler quiet */
19289 }
19290
19291 /*
19292 * Identity sequences are not to be dropped separately.
19293 */
19294 if (!tbinfo->is_identity_sequence)
19295 {
19296 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
19298 }
19299
19300 resetPQExpBuffer(query);
19301
19302 if (dopt->binary_upgrade)
19303 {
19305 tbinfo->dobj.catId.oid);
19306
19307 /*
19308 * In older PG versions a sequence will have a pg_type entry, but v14
19309 * and up don't use that, so don't attempt to preserve the type OID.
19310 */
19311 }
19312
19313 if (tbinfo->is_identity_sequence)
19314 {
19315 owning_tab = findTableByOid(tbinfo->owning_tab);
19316
19317 appendPQExpBuffer(query,
19318 "ALTER TABLE %s ",
19319 fmtQualifiedDumpable(owning_tab));
19320 appendPQExpBuffer(query,
19321 "ALTER COLUMN %s ADD GENERATED ",
19322 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
19323 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
19324 appendPQExpBufferStr(query, "ALWAYS");
19325 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
19326 appendPQExpBufferStr(query, "BY DEFAULT");
19327 appendPQExpBuffer(query, " AS IDENTITY (\n SEQUENCE NAME %s\n",
19329
19330 /*
19331 * Emit persistence option only if it's different from the owning
19332 * table's. This avoids using this new syntax unnecessarily.
19333 */
19334 if (tbinfo->relpersistence != owning_tab->relpersistence)
19335 appendPQExpBuffer(query, " %s\n",
19336 tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
19337 "UNLOGGED" : "LOGGED");
19338 }
19339 else
19340 {
19341 appendPQExpBuffer(query,
19342 "CREATE %sSEQUENCE %s\n",
19343 tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
19344 "UNLOGGED " : "",
19346
19347 if (seq->seqtype != SEQTYPE_BIGINT)
19348 appendPQExpBuffer(query, " AS %s\n", SeqTypeNames[seq->seqtype]);
19349 }
19350
19351 appendPQExpBuffer(query, " START WITH " INT64_FORMAT "\n", seq->startv);
19352
19353 appendPQExpBuffer(query, " INCREMENT BY " INT64_FORMAT "\n", seq->incby);
19354
19355 if (seq->minv != default_minv)
19356 appendPQExpBuffer(query, " MINVALUE " INT64_FORMAT "\n", seq->minv);
19357 else
19358 appendPQExpBufferStr(query, " NO MINVALUE\n");
19359
19360 if (seq->maxv != default_maxv)
19361 appendPQExpBuffer(query, " MAXVALUE " INT64_FORMAT "\n", seq->maxv);
19362 else
19363 appendPQExpBufferStr(query, " NO MAXVALUE\n");
19364
19365 appendPQExpBuffer(query,
19366 " CACHE " INT64_FORMAT "%s",
19367 seq->cache, (seq->cycled ? "\n CYCLE" : ""));
19368
19369 if (tbinfo->is_identity_sequence)
19370 appendPQExpBufferStr(query, "\n);\n");
19371 else
19372 appendPQExpBufferStr(query, ";\n");
19373
19374 /* binary_upgrade: no need to clear TOAST table oid */
19375
19376 if (dopt->binary_upgrade)
19378 "SEQUENCE", qseqname,
19379 tbinfo->dobj.namespace->dobj.name);
19380
19381 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19382 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
19383 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19384 .namespace = tbinfo->dobj.namespace->dobj.name,
19385 .owner = tbinfo->rolname,
19386 .description = "SEQUENCE",
19387 .section = SECTION_PRE_DATA,
19388 .createStmt = query->data,
19389 .dropStmt = delqry->data));
19390
19391 /*
19392 * If the sequence is owned by a table column, emit the ALTER for it as a
19393 * separate TOC entry immediately following the sequence's own entry. It's
19394 * OK to do this rather than using full sorting logic, because the
19395 * dependency that tells us it's owned will have forced the table to be
19396 * created first. We can't just include the ALTER in the TOC entry
19397 * because it will fail if we haven't reassigned the sequence owner to
19398 * match the table's owner.
19399 *
19400 * We need not schema-qualify the table reference because both sequence
19401 * and table must be in the same schema.
19402 */
19403 if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
19404 {
19405 owning_tab = findTableByOid(tbinfo->owning_tab);
19406
19407 if (owning_tab == NULL)
19408 pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
19409 tbinfo->owning_tab, tbinfo->dobj.catId.oid);
19410
19411 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
19412 {
19413 resetPQExpBuffer(query);
19414 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
19416 appendPQExpBuffer(query, " OWNED BY %s",
19417 fmtQualifiedDumpable(owning_tab));
19418 appendPQExpBuffer(query, ".%s;\n",
19419 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
19420
19421 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19423 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19424 .namespace = tbinfo->dobj.namespace->dobj.name,
19425 .owner = tbinfo->rolname,
19426 .description = "SEQUENCE OWNED BY",
19427 .section = SECTION_PRE_DATA,
19428 .createStmt = query->data,
19429 .deps = &(tbinfo->dobj.dumpId),
19430 .nDeps = 1));
19431 }
19432 }
19433
19434 /* Dump Sequence Comments and Security Labels */
19435 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19436 dumpComment(fout, "SEQUENCE", qseqname,
19437 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19438 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
19439
19440 if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
19441 dumpSecLabel(fout, "SEQUENCE", qseqname,
19442 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19443 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
19444
19445 destroyPQExpBuffer(query);
19448}
19449
19450/*
19451 * dumpSequenceData
19452 * write the data of one user-defined sequence
19453 */
19454static void
19456{
19457 TableInfo *tbinfo = tdinfo->tdtable;
19458 int64 last;
19459 bool called;
19460 PQExpBuffer query;
19461
19462 /* needn't bother if not dumping sequence data */
19463 if (!fout->dopt->dumpData && !fout->dopt->sequence_data)
19464 return;
19465
19466 query = createPQExpBuffer();
19467
19468 /*
19469 * For versions >= 18, the sequence information is gathered in the sorted
19470 * array before any calls to dumpSequenceData(). See collectSequences()
19471 * for more information.
19472 *
19473 * For older versions, we have to query the sequence relations
19474 * individually.
19475 */
19476 if (fout->remoteVersion < 180000)
19477 {
19478 PGresult *res;
19479
19480 appendPQExpBuffer(query,
19481 "SELECT last_value, is_called FROM %s",
19483
19484 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19485
19486 if (PQntuples(res) != 1)
19487 pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
19488 "query to get data of sequence \"%s\" returned %d rows (expected 1)",
19489 PQntuples(res)),
19490 tbinfo->dobj.name, PQntuples(res));
19491
19492 last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
19493 called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
19494
19495 PQclear(res);
19496 }
19497 else
19498 {
19499 SequenceItem key = {0};
19500 SequenceItem *entry;
19501
19503 Assert(tbinfo->dobj.catId.oid);
19504
19505 key.oid = tbinfo->dobj.catId.oid;
19506 entry = bsearch(&key, sequences, nsequences,
19507 sizeof(SequenceItem), SequenceItemCmp);
19508
19509 if (entry->null_seqtuple)
19510 pg_fatal("failed to get data for sequence \"%s\"; user may lack "
19511 "SELECT privilege on the sequence or the sequence may "
19512 "have been concurrently dropped",
19513 tbinfo->dobj.name);
19514
19515 last = entry->last_value;
19516 called = entry->is_called;
19517 }
19518
19519 resetPQExpBuffer(query);
19520 appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
19522 appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
19523 last, (called ? "true" : "false"));
19524
19525 if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
19527 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19528 .namespace = tbinfo->dobj.namespace->dobj.name,
19529 .owner = tbinfo->rolname,
19530 .description = "SEQUENCE SET",
19531 .section = SECTION_DATA,
19532 .createStmt = query->data,
19533 .deps = &(tbinfo->dobj.dumpId),
19534 .nDeps = 1));
19535
19536 destroyPQExpBuffer(query);
19537}
19538
19539/*
19540 * dumpTrigger
19541 * write the declaration of one user-defined table trigger
19542 */
19543static void
19545{
19546 DumpOptions *dopt = fout->dopt;
19547 TableInfo *tbinfo = tginfo->tgtable;
19548 PQExpBuffer query;
19552 char *qtabname;
19553 char *tag;
19554
19555 /* Do nothing if not dumping schema */
19556 if (!dopt->dumpSchema)
19557 return;
19558
19559 query = createPQExpBuffer();
19563
19564 qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19565
19566 appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
19568
19569 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
19570 appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
19571
19572 /* Triggers can depend on extensions */
19574 "pg_catalog.pg_trigger", "TRIGGER",
19575 trigidentity->data);
19576
19577 if (tginfo->tgispartition)
19578 {
19579 Assert(tbinfo->ispartition);
19580
19581 /*
19582 * Partition triggers only appear here because their 'tgenabled' flag
19583 * differs from its parent's. The trigger is created already, so
19584 * remove the CREATE and replace it with an ALTER. (Clear out the
19585 * DROP query too, so that pg_dump --create does not cause errors.)
19586 */
19587 resetPQExpBuffer(query);
19589 appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
19590 tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
19592 switch (tginfo->tgenabled)
19593 {
19594 case 'f':
19595 case 'D':
19596 appendPQExpBufferStr(query, "DISABLE");
19597 break;
19598 case 't':
19599 case 'O':
19600 appendPQExpBufferStr(query, "ENABLE");
19601 break;
19602 case 'R':
19603 appendPQExpBufferStr(query, "ENABLE REPLICA");
19604 break;
19605 case 'A':
19606 appendPQExpBufferStr(query, "ENABLE ALWAYS");
19607 break;
19608 }
19609 appendPQExpBuffer(query, " TRIGGER %s;\n",
19610 fmtId(tginfo->dobj.name));
19611 }
19612 else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
19613 {
19614 appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
19615 tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
19617 switch (tginfo->tgenabled)
19618 {
19619 case 'D':
19620 case 'f':
19621 appendPQExpBufferStr(query, "DISABLE");
19622 break;
19623 case 'A':
19624 appendPQExpBufferStr(query, "ENABLE ALWAYS");
19625 break;
19626 case 'R':
19627 appendPQExpBufferStr(query, "ENABLE REPLICA");
19628 break;
19629 default:
19630 appendPQExpBufferStr(query, "ENABLE");
19631 break;
19632 }
19633 appendPQExpBuffer(query, " TRIGGER %s;\n",
19634 fmtId(tginfo->dobj.name));
19635 }
19636
19637 appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
19638 fmtId(tginfo->dobj.name));
19639
19640 tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
19641
19642 if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19643 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
19644 ARCHIVE_OPTS(.tag = tag,
19645 .namespace = tbinfo->dobj.namespace->dobj.name,
19646 .owner = tbinfo->rolname,
19647 .description = "TRIGGER",
19648 .section = SECTION_POST_DATA,
19649 .createStmt = query->data,
19650 .dropStmt = delqry->data));
19651
19652 if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19654 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19655 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
19656
19657 pfree(tag);
19658 destroyPQExpBuffer(query);
19663}
19664
19665/*
19666 * dumpEventTrigger
19667 * write the declaration of one user-defined event trigger
19668 */
19669static void
19671{
19672 DumpOptions *dopt = fout->dopt;
19673 PQExpBuffer query;
19675 char *qevtname;
19676
19677 /* Do nothing if not dumping schema */
19678 if (!dopt->dumpSchema)
19679 return;
19680
19681 query = createPQExpBuffer();
19683
19684 qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
19685
19686 appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
19688 appendPQExpBufferStr(query, " ON ");
19689 appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
19690
19691 if (strcmp("", evtinfo->evttags) != 0)
19692 {
19693 appendPQExpBufferStr(query, "\n WHEN TAG IN (");
19694 appendPQExpBufferStr(query, evtinfo->evttags);
19695 appendPQExpBufferChar(query, ')');
19696 }
19697
19698 appendPQExpBufferStr(query, "\n EXECUTE FUNCTION ");
19699 appendPQExpBufferStr(query, evtinfo->evtfname);
19700 appendPQExpBufferStr(query, "();\n");
19701
19702 if (evtinfo->evtenabled != 'O')
19703 {
19704 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
19705 qevtname);
19706 switch (evtinfo->evtenabled)
19707 {
19708 case 'D':
19709 appendPQExpBufferStr(query, "DISABLE");
19710 break;
19711 case 'A':
19712 appendPQExpBufferStr(query, "ENABLE ALWAYS");
19713 break;
19714 case 'R':
19715 appendPQExpBufferStr(query, "ENABLE REPLICA");
19716 break;
19717 default:
19718 appendPQExpBufferStr(query, "ENABLE");
19719 break;
19720 }
19721 appendPQExpBufferStr(query, ";\n");
19722 }
19723
19724 appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
19725 qevtname);
19726
19727 if (dopt->binary_upgrade)
19729 "EVENT TRIGGER", qevtname, NULL);
19730
19731 if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19732 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
19733 ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
19734 .owner = evtinfo->evtowner,
19735 .description = "EVENT TRIGGER",
19736 .section = SECTION_POST_DATA,
19737 .createStmt = query->data,
19738 .dropStmt = delqry->data));
19739
19740 if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19741 dumpComment(fout, "EVENT TRIGGER", qevtname,
19742 NULL, evtinfo->evtowner,
19743 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
19744
19745 if (evtinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
19746 dumpSecLabel(fout, "EVENT TRIGGER", qevtname,
19747 NULL, evtinfo->evtowner,
19748 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
19749
19750 destroyPQExpBuffer(query);
19753}
19754
19755/*
19756 * dumpRule
19757 * Dump a rule
19758 */
19759static void
19760dumpRule(Archive *fout, const RuleInfo *rinfo)
19761{
19762 DumpOptions *dopt = fout->dopt;
19763 TableInfo *tbinfo = rinfo->ruletable;
19764 bool is_view;
19765 PQExpBuffer query;
19766 PQExpBuffer cmd;
19769 char *qtabname;
19770 PGresult *res;
19771 char *tag;
19772
19773 /* Do nothing if not dumping schema */
19774 if (!dopt->dumpSchema)
19775 return;
19776
19777 /*
19778 * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
19779 * we do not want to dump it as a separate object.
19780 */
19781 if (!rinfo->separate)
19782 return;
19783
19784 /*
19785 * If it's an ON SELECT rule, we want to print it as a view definition,
19786 * instead of a rule.
19787 */
19788 is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
19789
19790 query = createPQExpBuffer();
19791 cmd = createPQExpBuffer();
19794
19795 qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19796
19797 if (is_view)
19798 {
19800
19801 /*
19802 * We need OR REPLACE here because we'll be replacing a dummy view.
19803 * Otherwise this should look largely like the regular view dump code.
19804 */
19805 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
19807 if (nonemptyReloptions(tbinfo->reloptions))
19808 {
19809 appendPQExpBufferStr(cmd, " WITH (");
19810 appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
19811 appendPQExpBufferChar(cmd, ')');
19812 }
19814 appendPQExpBuffer(cmd, " AS\n%s", result->data);
19816 if (tbinfo->checkoption != NULL)
19817 appendPQExpBuffer(cmd, "\n WITH %s CHECK OPTION",
19818 tbinfo->checkoption);
19819 appendPQExpBufferStr(cmd, ";\n");
19820 }
19821 else
19822 {
19823 /* In the rule case, just print pg_get_ruledef's result verbatim */
19824 appendPQExpBuffer(query,
19825 "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
19826 rinfo->dobj.catId.oid);
19827
19828 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19829
19830 if (PQntuples(res) != 1)
19831 pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
19832 rinfo->dobj.name, tbinfo->dobj.name);
19833
19834 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
19835
19836 PQclear(res);
19837 }
19838
19839 /*
19840 * Add the command to alter the rules replication firing semantics if it
19841 * differs from the default.
19842 */
19843 if (rinfo->ev_enabled != 'O')
19844 {
19845 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
19846 switch (rinfo->ev_enabled)
19847 {
19848 case 'A':
19849 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
19850 fmtId(rinfo->dobj.name));
19851 break;
19852 case 'R':
19853 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
19854 fmtId(rinfo->dobj.name));
19855 break;
19856 case 'D':
19857 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
19858 fmtId(rinfo->dobj.name));
19859 break;
19860 }
19861 }
19862
19863 if (is_view)
19864 {
19865 /*
19866 * We can't DROP a view's ON SELECT rule. Instead, use CREATE OR
19867 * REPLACE VIEW to replace the rule with something with minimal
19868 * dependencies.
19869 */
19871
19872 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
19875 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
19877 }
19878 else
19879 {
19880 appendPQExpBuffer(delcmd, "DROP RULE %s ",
19881 fmtId(rinfo->dobj.name));
19882 appendPQExpBuffer(delcmd, "ON %s;\n",
19884 }
19885
19886 appendPQExpBuffer(ruleprefix, "RULE %s ON",
19887 fmtId(rinfo->dobj.name));
19888
19889 tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
19890
19891 if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19892 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
19893 ARCHIVE_OPTS(.tag = tag,
19894 .namespace = tbinfo->dobj.namespace->dobj.name,
19895 .owner = tbinfo->rolname,
19896 .description = "RULE",
19897 .section = SECTION_POST_DATA,
19898 .createStmt = cmd->data,
19899 .dropStmt = delcmd->data));
19900
19901 /* Dump rule comments */
19902 if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19904 tbinfo->dobj.namespace->dobj.name,
19905 tbinfo->rolname,
19906 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
19907
19908 pfree(tag);
19909 destroyPQExpBuffer(query);
19910 destroyPQExpBuffer(cmd);
19914}
19915
19916/*
19917 * getExtensionMembership --- obtain extension membership data
19918 *
19919 * We need to identify objects that are extension members as soon as they're
19920 * loaded, so that we can correctly determine whether they need to be dumped.
19921 * Generally speaking, extension member objects will get marked as *not* to
19922 * be dumped, as they will be recreated by the single CREATE EXTENSION
19923 * command. However, in binary upgrade mode we still need to dump the members
19924 * individually.
19925 */
19926void
19928 int numExtensions)
19929{
19930 PQExpBuffer query;
19931 PGresult *res;
19932 int ntups,
19933 i;
19934 int i_classid,
19935 i_objid,
19936 i_refobjid;
19937 ExtensionInfo *ext;
19938
19939 /* Nothing to do if no extensions */
19940 if (numExtensions == 0)
19941 return;
19942
19943 query = createPQExpBuffer();
19944
19945 /* refclassid constraint is redundant but may speed the search */
19946 appendPQExpBufferStr(query, "SELECT "
19947 "classid, objid, refobjid "
19948 "FROM pg_depend "
19949 "WHERE refclassid = 'pg_extension'::regclass "
19950 "AND deptype = 'e' "
19951 "ORDER BY 3");
19952
19953 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19954
19955 ntups = PQntuples(res);
19956
19957 i_classid = PQfnumber(res, "classid");
19958 i_objid = PQfnumber(res, "objid");
19959 i_refobjid = PQfnumber(res, "refobjid");
19960
19961 /*
19962 * Since we ordered the SELECT by referenced ID, we can expect that
19963 * multiple entries for the same extension will appear together; this
19964 * saves on searches.
19965 */
19966 ext = NULL;
19967
19968 for (i = 0; i < ntups; i++)
19969 {
19970 CatalogId objId;
19971 Oid extId;
19972
19973 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
19974 objId.oid = atooid(PQgetvalue(res, i, i_objid));
19976
19977 if (ext == NULL ||
19978 ext->dobj.catId.oid != extId)
19980
19981 if (ext == NULL)
19982 {
19983 /* shouldn't happen */
19984 pg_log_warning("could not find referenced extension %u", extId);
19985 continue;
19986 }
19987
19988 recordExtensionMembership(objId, ext);
19989 }
19990
19991 PQclear(res);
19992
19993 destroyPQExpBuffer(query);
19994}
19995
19996/*
19997 * processExtensionTables --- deal with extension configuration tables
19998 *
19999 * There are two parts to this process:
20000 *
20001 * 1. Identify and create dump records for extension configuration tables.
20002 *
20003 * Extensions can mark tables as "configuration", which means that the user
20004 * is able and expected to modify those tables after the extension has been
20005 * loaded. For these tables, we dump out only the data- the structure is
20006 * expected to be handled at CREATE EXTENSION time, including any indexes or
20007 * foreign keys, which brings us to-
20008 *
20009 * 2. Record FK dependencies between configuration tables.
20010 *
20011 * Due to the FKs being created at CREATE EXTENSION time and therefore before
20012 * the data is loaded, we have to work out what the best order for reloading
20013 * the data is, to avoid FK violations when the tables are restored. This is
20014 * not perfect- we can't handle circular dependencies and if any exist they
20015 * will cause an invalid dump to be produced (though at least all of the data
20016 * is included for a user to manually restore). This is currently documented
20017 * but perhaps we can provide a better solution in the future.
20018 */
20019void
20021 int numExtensions)
20022{
20023 DumpOptions *dopt = fout->dopt;
20024 PQExpBuffer query;
20025 PGresult *res;
20026 int ntups,
20027 i;
20028 int i_conrelid,
20030
20031 /* Nothing to do if no extensions */
20032 if (numExtensions == 0)
20033 return;
20034
20035 /*
20036 * Identify extension configuration tables and create TableDataInfo
20037 * objects for them, ensuring their data will be dumped even though the
20038 * tables themselves won't be.
20039 *
20040 * Note that we create TableDataInfo objects even in schema-only mode, ie,
20041 * user data in a configuration table is treated like schema data. This
20042 * seems appropriate since system data in a config table would get
20043 * reloaded by CREATE EXTENSION. If the extension is not listed in the
20044 * list of extensions to be included, none of its data is dumped.
20045 */
20046 for (i = 0; i < numExtensions; i++)
20047 {
20049 char *extconfig = curext->extconfig;
20050 char *extcondition = curext->extcondition;
20051 char **extconfigarray = NULL;
20052 char **extconditionarray = NULL;
20053 int nconfigitems = 0;
20054 int nconditionitems = 0;
20055
20056 /*
20057 * Check if this extension is listed as to include in the dump. If
20058 * not, any table data associated with it is discarded.
20059 */
20062 curext->dobj.catId.oid))
20063 continue;
20064
20065 /*
20066 * Check if this extension is listed as to exclude in the dump. If
20067 * yes, any table data associated with it is discarded.
20068 */
20071 curext->dobj.catId.oid))
20072 continue;
20073
20074 if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
20075 {
20076 int j;
20077
20078 if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
20079 pg_fatal("could not parse %s array", "extconfig");
20080 if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
20081 pg_fatal("could not parse %s array", "extcondition");
20083 pg_fatal("mismatched number of configurations and conditions for extension");
20084
20085 for (j = 0; j < nconfigitems; j++)
20086 {
20089 bool dumpobj =
20090 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
20091
20093 if (configtbl == NULL)
20094 continue;
20095
20096 /*
20097 * Tables of not-to-be-dumped extensions shouldn't be dumped
20098 * unless the table or its schema is explicitly included
20099 */
20100 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
20101 {
20102 /* check table explicitly requested */
20103 if (table_include_oids.head != NULL &&
20105 configtbloid))
20106 dumpobj = true;
20107
20108 /* check table's schema explicitly requested */
20109 if (configtbl->dobj.namespace->dobj.dump &
20111 dumpobj = true;
20112 }
20113
20114 /* check table excluded by an exclusion switch */
20115 if (table_exclude_oids.head != NULL &&
20117 configtbloid))
20118 dumpobj = false;
20119
20120 /* check schema excluded by an exclusion switch */
20122 configtbl->dobj.namespace->dobj.catId.oid))
20123 dumpobj = false;
20124
20125 if (dumpobj)
20126 {
20128 if (configtbl->dataObj != NULL)
20129 {
20130 if (strlen(extconditionarray[j]) > 0)
20131 configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
20132 }
20133 }
20134 }
20135 }
20136 if (extconfigarray)
20140 }
20141
20142 /*
20143 * Now that all the TableDataInfo objects have been created for all the
20144 * extensions, check their FK dependencies and register them to try and
20145 * dump the data out in an order that they can be restored in.
20146 *
20147 * Note that this is not a problem for user tables as their FKs are
20148 * recreated after the data has been loaded.
20149 */
20150
20151 query = createPQExpBuffer();
20152
20153 printfPQExpBuffer(query,
20154 "SELECT conrelid, confrelid "
20155 "FROM pg_constraint "
20156 "JOIN pg_depend ON (objid = confrelid) "
20157 "WHERE contype = 'f' "
20158 "AND refclassid = 'pg_extension'::regclass "
20159 "AND classid = 'pg_class'::regclass;");
20160
20161 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
20162 ntups = PQntuples(res);
20163
20164 i_conrelid = PQfnumber(res, "conrelid");
20165 i_confrelid = PQfnumber(res, "confrelid");
20166
20167 /* Now get the dependencies and register them */
20168 for (i = 0; i < ntups; i++)
20169 {
20170 Oid conrelid,
20171 confrelid;
20173 *contable;
20174
20175 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
20176 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
20177 contable = findTableByOid(conrelid);
20178 reftable = findTableByOid(confrelid);
20179
20180 if (reftable == NULL ||
20181 reftable->dataObj == NULL ||
20182 contable == NULL ||
20183 contable->dataObj == NULL)
20184 continue;
20185
20186 /*
20187 * Make referencing TABLE_DATA object depend on the referenced table's
20188 * TABLE_DATA object.
20189 */
20190 addObjectDependency(&contable->dataObj->dobj,
20191 reftable->dataObj->dobj.dumpId);
20192 }
20193 PQclear(res);
20194 destroyPQExpBuffer(query);
20195}
20196
20197/*
20198 * getDependencies --- obtain available dependency data
20199 */
20200static void
20202{
20203 PQExpBuffer query;
20204 PGresult *res;
20205 int ntups,
20206 i;
20207 int i_classid,
20208 i_objid,
20210 i_refobjid,
20211 i_deptype;
20212 DumpableObject *dobj,
20213 *refdobj;
20214
20215 pg_log_info("reading dependency data");
20216
20217 query = createPQExpBuffer();
20218
20219 /*
20220 * Messy query to collect the dependency data we need. Note that we
20221 * ignore the sub-object column, so that dependencies of or on a column
20222 * look the same as dependencies of or on a whole table.
20223 *
20224 * PIN dependencies aren't interesting, and EXTENSION dependencies were
20225 * already processed by getExtensionMembership.
20226 */
20227 appendPQExpBufferStr(query, "SELECT "
20228 "classid, objid, refclassid, refobjid, deptype "
20229 "FROM pg_depend "
20230 "WHERE deptype != 'p' AND deptype != 'e'\n");
20231
20232 /*
20233 * Since we don't treat pg_amop entries as separate DumpableObjects, we
20234 * have to translate their dependencies into dependencies of their parent
20235 * opfamily. Ignore internal dependencies though, as those will point to
20236 * their parent opclass, which we needn't consider here (and if we did,
20237 * it'd just result in circular dependencies). Also, "loose" opfamily
20238 * entries will have dependencies on their parent opfamily, which we
20239 * should drop since they'd likewise become useless self-dependencies.
20240 * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
20241 */
20242 appendPQExpBufferStr(query, "UNION ALL\n"
20243 "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
20244 "FROM pg_depend d, pg_amop o "
20245 "WHERE deptype NOT IN ('p', 'e', 'i') AND "
20246 "classid = 'pg_amop'::regclass AND objid = o.oid "
20247 "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
20248
20249 /* Likewise for pg_amproc entries */
20250 appendPQExpBufferStr(query, "UNION ALL\n"
20251 "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
20252 "FROM pg_depend d, pg_amproc p "
20253 "WHERE deptype NOT IN ('p', 'e', 'i') AND "
20254 "classid = 'pg_amproc'::regclass AND objid = p.oid "
20255 "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
20256
20257 /*
20258 * Translate dependencies of pg_propgraph_element entries into
20259 * dependencies of their parent pg_class entry.
20260 */
20261 if (fout->remoteVersion >= 190000)
20262 appendPQExpBufferStr(query, "UNION ALL\n"
20263 "SELECT 'pg_class'::regclass AS classid, pgepgid AS objid, refclassid, refobjid, deptype "
20264 "FROM pg_depend d, pg_propgraph_element pge "
20265 "WHERE deptype NOT IN ('p', 'e', 'i') AND "
20266 "classid = 'pg_propgraph_element'::regclass AND objid = pge.oid\n");
20267
20268 /* Sort the output for efficiency below */
20269 appendPQExpBufferStr(query, "ORDER BY 1,2");
20270
20271 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
20272
20273 ntups = PQntuples(res);
20274
20275 i_classid = PQfnumber(res, "classid");
20276 i_objid = PQfnumber(res, "objid");
20277 i_refclassid = PQfnumber(res, "refclassid");
20278 i_refobjid = PQfnumber(res, "refobjid");
20279 i_deptype = PQfnumber(res, "deptype");
20280
20281 /*
20282 * Since we ordered the SELECT by referencing ID, we can expect that
20283 * multiple entries for the same object will appear together; this saves
20284 * on searches.
20285 */
20286 dobj = NULL;
20287
20288 for (i = 0; i < ntups; i++)
20289 {
20290 CatalogId objId;
20292 char deptype;
20293
20294 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
20295 objId.oid = atooid(PQgetvalue(res, i, i_objid));
20296 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
20297 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
20298 deptype = *(PQgetvalue(res, i, i_deptype));
20299
20300 if (dobj == NULL ||
20301 dobj->catId.tableoid != objId.tableoid ||
20302 dobj->catId.oid != objId.oid)
20303 dobj = findObjectByCatalogId(objId);
20304
20305 /*
20306 * Failure to find objects mentioned in pg_depend is not unexpected,
20307 * since for example we don't collect info about TOAST tables.
20308 */
20309 if (dobj == NULL)
20310 {
20311#ifdef NOT_USED
20312 pg_log_warning("no referencing object %u %u",
20313 objId.tableoid, objId.oid);
20314#endif
20315 continue;
20316 }
20317
20319
20320 if (refdobj == NULL)
20321 {
20322#ifdef NOT_USED
20323 pg_log_warning("no referenced object %u %u",
20324 refobjId.tableoid, refobjId.oid);
20325#endif
20326 continue;
20327 }
20328
20329 /*
20330 * For 'x' dependencies, mark the object for later; we still add the
20331 * normal dependency, for possible ordering purposes. Currently
20332 * pg_dump_sort.c knows to put extensions ahead of all object types
20333 * that could possibly depend on them, but this is safer.
20334 */
20335 if (deptype == 'x')
20336 dobj->depends_on_ext = true;
20337
20338 /*
20339 * Ordinarily, table rowtypes have implicit dependencies on their
20340 * tables. However, for a composite type the implicit dependency goes
20341 * the other way in pg_depend; which is the right thing for DROP but
20342 * it doesn't produce the dependency ordering we need. So in that one
20343 * case, we reverse the direction of the dependency.
20344 */
20345 if (deptype == 'i' &&
20346 dobj->objType == DO_TABLE &&
20347 refdobj->objType == DO_TYPE)
20349 else
20350 /* normal case */
20351 addObjectDependency(dobj, refdobj->dumpId);
20352 }
20353
20354 PQclear(res);
20355
20356 destroyPQExpBuffer(query);
20357}
20358
20359
20360/*
20361 * createBoundaryObjects - create dummy DumpableObjects to represent
20362 * dump section boundaries.
20363 */
20364static DumpableObject *
20366{
20368
20370
20371 dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
20372 dobjs[0].catId = nilCatalogId;
20373 AssignDumpId(dobjs + 0);
20374 dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
20375
20376 dobjs[1].objType = DO_POST_DATA_BOUNDARY;
20377 dobjs[1].catId = nilCatalogId;
20378 AssignDumpId(dobjs + 1);
20379 dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
20380
20381 return dobjs;
20382}
20383
20384/*
20385 * addBoundaryDependencies - add dependencies as needed to enforce the dump
20386 * section boundaries.
20387 */
20388static void
20391{
20394 int i;
20395
20396 for (i = 0; i < numObjs; i++)
20397 {
20398 DumpableObject *dobj = dobjs[i];
20399
20400 /*
20401 * The classification of object types here must match the SECTION_xxx
20402 * values assigned during subsequent ArchiveEntry calls!
20403 */
20404 switch (dobj->objType)
20405 {
20406 case DO_NAMESPACE:
20407 case DO_EXTENSION:
20408 case DO_TYPE:
20409 case DO_SHELL_TYPE:
20410 case DO_FUNC:
20411 case DO_AGG:
20412 case DO_OPERATOR:
20413 case DO_ACCESS_METHOD:
20414 case DO_OPCLASS:
20415 case DO_OPFAMILY:
20416 case DO_COLLATION:
20417 case DO_CONVERSION:
20418 case DO_TABLE:
20419 case DO_TABLE_ATTACH:
20420 case DO_ATTRDEF:
20421 case DO_PROCLANG:
20422 case DO_CAST:
20423 case DO_DUMMY_TYPE:
20424 case DO_TSPARSER:
20425 case DO_TSDICT:
20426 case DO_TSTEMPLATE:
20427 case DO_TSCONFIG:
20428 case DO_FDW:
20429 case DO_FOREIGN_SERVER:
20430 case DO_TRANSFORM:
20431 /* Pre-data objects: must come before the pre-data boundary */
20433 break;
20434 case DO_TABLE_DATA:
20435 case DO_SEQUENCE_SET:
20436 case DO_LARGE_OBJECT:
20438 /* Data objects: must come between the boundaries */
20439 addObjectDependency(dobj, preDataBound->dumpId);
20441 break;
20442 case DO_INDEX:
20443 case DO_INDEX_ATTACH:
20444 case DO_STATSEXT:
20445 case DO_REFRESH_MATVIEW:
20446 case DO_TRIGGER:
20447 case DO_EVENT_TRIGGER:
20448 case DO_DEFAULT_ACL:
20449 case DO_POLICY:
20450 case DO_PUBLICATION:
20451 case DO_PUBLICATION_REL:
20453 case DO_SUBSCRIPTION:
20455 /* Post-data objects: must come after the post-data boundary */
20456 addObjectDependency(dobj, postDataBound->dumpId);
20457 break;
20458 case DO_RULE:
20459 /* Rules are post-data, but only if dumped separately */
20460 if (((RuleInfo *) dobj)->separate)
20461 addObjectDependency(dobj, postDataBound->dumpId);
20462 break;
20463 case DO_CONSTRAINT:
20464 case DO_FK_CONSTRAINT:
20465 /* Constraints are post-data, but only if dumped separately */
20466 if (((ConstraintInfo *) dobj)->separate)
20467 addObjectDependency(dobj, postDataBound->dumpId);
20468 break;
20470 /* nothing to do */
20471 break;
20473 /* must come after the pre-data boundary */
20474 addObjectDependency(dobj, preDataBound->dumpId);
20475 break;
20476 case DO_REL_STATS:
20477 /* stats section varies by parent object type, DATA or POST */
20478 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
20479 {
20480 addObjectDependency(dobj, preDataBound->dumpId);
20481 addObjectDependency(postDataBound, dobj->dumpId);
20482 }
20483 else
20484 addObjectDependency(dobj, postDataBound->dumpId);
20485 break;
20486 }
20487 }
20488}
20489
20490
20491/*
20492 * BuildArchiveDependencies - create dependency data for archive TOC entries
20493 *
20494 * The raw dependency data obtained by getDependencies() is not terribly
20495 * useful in an archive dump, because in many cases there are dependency
20496 * chains linking through objects that don't appear explicitly in the dump.
20497 * For example, a view will depend on its _RETURN rule while the _RETURN rule
20498 * will depend on other objects --- but the rule will not appear as a separate
20499 * object in the dump. We need to adjust the view's dependencies to include
20500 * whatever the rule depends on that is included in the dump.
20501 *
20502 * Just to make things more complicated, there are also "special" dependencies
20503 * such as the dependency of a TABLE DATA item on its TABLE, which we must
20504 * not rearrange because pg_restore knows that TABLE DATA only depends on
20505 * its table. In these cases we must leave the dependencies strictly as-is
20506 * even if they refer to not-to-be-dumped objects.
20507 *
20508 * To handle this, the convention is that "special" dependencies are created
20509 * during ArchiveEntry calls, and an archive TOC item that has any such
20510 * entries will not be touched here. Otherwise, we recursively search the
20511 * DumpableObject data structures to build the correct dependencies for each
20512 * archive TOC item.
20513 */
20514static void
20516{
20518 TocEntry *te;
20519
20520 /* Scan all TOC entries in the archive */
20521 for (te = AH->toc->next; te != AH->toc; te = te->next)
20522 {
20523 DumpableObject *dobj;
20524 DumpId *dependencies;
20525 int nDeps;
20526 int allocDeps;
20527
20528 /* No need to process entries that will not be dumped */
20529 if (te->reqs == 0)
20530 continue;
20531 /* Ignore entries that already have "special" dependencies */
20532 if (te->nDeps > 0)
20533 continue;
20534 /* Otherwise, look up the item's original DumpableObject, if any */
20535 dobj = findObjectByDumpId(te->dumpId);
20536 if (dobj == NULL)
20537 continue;
20538 /* No work if it has no dependencies */
20539 if (dobj->nDeps <= 0)
20540 continue;
20541 /* Set up work array */
20542 allocDeps = 64;
20543 dependencies = pg_malloc_array(DumpId, allocDeps);
20544 nDeps = 0;
20545 /* Recursively find all dumpable dependencies */
20546 findDumpableDependencies(AH, dobj,
20547 &dependencies, &nDeps, &allocDeps);
20548 /* And save 'em ... */
20549 if (nDeps > 0)
20550 {
20551 dependencies = pg_realloc_array(dependencies, DumpId, nDeps);
20552 te->dependencies = dependencies;
20553 te->nDeps = nDeps;
20554 }
20555 else
20556 pg_free(dependencies);
20557 }
20558}
20559
20560/* Recursive search subroutine for BuildArchiveDependencies */
20561static void
20563 DumpId **dependencies, int *nDeps, int *allocDeps)
20564{
20565 int i;
20566
20567 /*
20568 * Ignore section boundary objects: if we search through them, we'll
20569 * report lots of bogus dependencies.
20570 */
20571 if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
20573 return;
20574
20575 for (i = 0; i < dobj->nDeps; i++)
20576 {
20577 DumpId depid = dobj->dependencies[i];
20578
20579 if (TocIDRequired(AH, depid) != 0)
20580 {
20581 /* Object will be dumped, so just reference it as a dependency */
20582 if (*nDeps >= *allocDeps)
20583 {
20584 *allocDeps *= 2;
20585 *dependencies = pg_realloc_array(*dependencies, DumpId, *allocDeps);
20586 }
20587 (*dependencies)[*nDeps] = depid;
20588 (*nDeps)++;
20589 }
20590 else
20591 {
20592 /*
20593 * Object will not be dumped, so recursively consider its deps. We
20594 * rely on the assumption that sortDumpableObjects already broke
20595 * any dependency loops, else we might recurse infinitely.
20596 */
20598
20599 if (otherdobj)
20601 dependencies, nDeps, allocDeps);
20602 }
20603 }
20604}
20605
20606
20607/*
20608 * getFormattedTypeName - retrieve a nicely-formatted type name for the
20609 * given type OID.
20610 *
20611 * This does not guarantee to schema-qualify the output, so it should not
20612 * be used to create the target object name for CREATE or ALTER commands.
20613 *
20614 * Note that the result is cached and must not be freed by the caller.
20615 */
20616static const char *
20618{
20620 char *result;
20621 PQExpBuffer query;
20622 PGresult *res;
20623
20624 if (oid == 0)
20625 {
20626 if ((opts & zeroAsStar) != 0)
20627 return "*";
20628 else if ((opts & zeroAsNone) != 0)
20629 return "NONE";
20630 }
20631
20632 /* see if we have the result cached in the type's TypeInfo record */
20633 typeInfo = findTypeByOid(oid);
20634 if (typeInfo && typeInfo->ftypname)
20635 return typeInfo->ftypname;
20636
20637 query = createPQExpBuffer();
20638 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
20639 oid);
20640
20641 res = ExecuteSqlQueryForSingleRow(fout, query->data);
20642
20643 /* result of format_type is already quoted */
20644 result = pg_strdup(PQgetvalue(res, 0, 0));
20645
20646 PQclear(res);
20647 destroyPQExpBuffer(query);
20648
20649 /*
20650 * Cache the result for re-use in later requests, if possible. If we
20651 * don't have a TypeInfo for the type, the string will be leaked once the
20652 * caller is done with it ... but that case really should not happen, so
20653 * leaking if it does seems acceptable.
20654 */
20655 if (typeInfo)
20656 typeInfo->ftypname = result;
20657
20658 return result;
20659}
20660
20661/*
20662 * Return a column list clause for the given relation.
20663 *
20664 * Special case: if there are no undropped columns in the relation, return
20665 * "", not an invalid "()" column list.
20666 */
20667static const char *
20669{
20670 int numatts = ti->numatts;
20671 char **attnames = ti->attnames;
20672 bool *attisdropped = ti->attisdropped;
20673 char *attgenerated = ti->attgenerated;
20674 bool needComma;
20675 int i;
20676
20677 appendPQExpBufferChar(buffer, '(');
20678 needComma = false;
20679 for (i = 0; i < numatts; i++)
20680 {
20681 if (attisdropped[i])
20682 continue;
20683 if (attgenerated[i])
20684 continue;
20685 if (needComma)
20686 appendPQExpBufferStr(buffer, ", ");
20687 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
20688 needComma = true;
20689 }
20690
20691 if (!needComma)
20692 return ""; /* no undropped columns */
20693
20694 appendPQExpBufferChar(buffer, ')');
20695 return buffer->data;
20696}
20697
20698/*
20699 * Check if a reloptions array is nonempty.
20700 */
20701static bool
20702nonemptyReloptions(const char *reloptions)
20703{
20704 /* Don't want to print it if it's just "{}" */
20705 return (reloptions != NULL && strlen(reloptions) > 2);
20706}
20707
20708/*
20709 * Format a reloptions array and append it to the given buffer.
20710 *
20711 * "prefix" is prepended to the option names; typically it's "" or "toast.".
20712 */
20713static void
20714appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
20715 const char *prefix, Archive *fout)
20716{
20717 bool res;
20718
20719 res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
20720 fout->std_strings);
20721 if (!res)
20722 pg_log_warning("could not parse %s array", "reloptions");
20723}
20724
20725/*
20726 * read_dump_filters - retrieve object identifier patterns from file
20727 *
20728 * Parse the specified filter file for include and exclude patterns, and add
20729 * them to the relevant lists. If the filename is "-" then filters will be
20730 * read from STDIN rather than a file.
20731 */
20732static void
20733read_dump_filters(const char *filename, DumpOptions *dopt)
20734{
20736 char *objname;
20738 FilterObjectType objtype;
20739
20741
20742 while (filter_read_item(&fstate, &objname, &comtype, &objtype))
20743 {
20745 {
20746 switch (objtype)
20747 {
20749 break;
20756 pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
20757 "include",
20758 filter_object_type_name(objtype));
20759 exit_nicely(1);
20760 break; /* unreachable */
20761
20764 break;
20767 break;
20770 dopt->include_everything = false;
20771 break;
20774 dopt->include_everything = false;
20775 break;
20778 objname);
20779 dopt->include_everything = false;
20780 break;
20781 }
20782 }
20784 {
20785 switch (objtype)
20786 {
20788 break;
20794 pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
20795 "exclude",
20796 filter_object_type_name(objtype));
20797 exit_nicely(1);
20798 break;
20799
20802 break;
20805 objname);
20806 break;
20809 objname);
20810 break;
20813 break;
20816 break;
20819 objname);
20820 break;
20821 }
20822 }
20823 else
20824 {
20826 Assert(objtype == FILTER_OBJECT_TYPE_NONE);
20827 }
20828
20829 if (objname)
20830 free(objname);
20831 }
20832
20834}
Acl * acldefault(ObjectType objtype, Oid ownerId)
Definition acl.c:827
#define InvalidAttrNumber
Definition attnum.h:23
int lo_read(int fd, char *buf, int len)
Definition be-fsstubs.c:154
static void help(void)
Definition pg_config.c:71
void recordAdditionalCatalogID(CatalogId catId, DumpableObject *dobj)
Definition common.c:722
void recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
Definition common.c:1066
FuncInfo * findFuncByOid(Oid oid)
Definition common.c:921
TableInfo * findTableByOid(Oid oid)
Definition common.c:866
ExtensionInfo * findExtensionByOid(Oid oid)
Definition common.c:1011
CollInfo * findCollationByOid(Oid oid)
Definition common.c:975
SubscriptionInfo * findSubscriptionByOid(Oid oid)
Definition common.c:1047
OprInfo * findOprByOid(Oid oid)
Definition common.c:939
NamespaceInfo * findNamespaceByOid(Oid oid)
Definition common.c:993
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition common.c:821
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition common.c:768
void parseOidArray(const char *str, Oid *array, int arraysize)
Definition common.c:1114
ExtensionInfo * findOwningExtension(CatalogId catalogId)
Definition common.c:1090
TableInfo * getSchemaData(Archive *fout, int *numTablesPtr)
Definition common.c:98
TypeInfo * findTypeByOid(Oid oid)
Definition common.c:902
DumpId createDumpId(void)
Definition common.c:748
DumpableObject * findObjectByCatalogId(CatalogId catalogId)
Definition common.c:781
void AssignDumpId(DumpableObject *dobj)
Definition common.c:660
void getDumpableObjects(DumpableObject ***objs, int *numObjs)
Definition common.c:800
PublicationInfo * findPublicationByOid(Oid oid)
Definition common.c:1029
void on_exit_close_archive(Archive *AHX)
Definition parallel.c:330
void init_parallel_dump_utils(void)
Definition parallel.c:238
#define PG_MAX_JOBS
Definition parallel.h:48
bool is_superuser(void)
Definition common.c:2522
uint32 BlockNumber
Definition block.h:31
static void cleanup(void)
Definition bootstrap.c:886
static const gbtree_vinfo tinfo
Definition btree_bit.c:136
#define PG_INT32_MAX
Definition c.h:732
#define ngettext(s, p, n)
Definition c.h:1310
#define INT64_FORMAT
Definition c.h:693
#define Assert(condition)
Definition c.h:1002
#define PG_TEXTDOMAIN(domain)
Definition c.h:1343
int64_t int64
Definition c.h:680
#define PG_INT16_MIN
Definition c.h:728
#define CppAsString2(x)
Definition c.h:565
int32_t int32
Definition c.h:679
#define PG_INT64_MAX
Definition c.h:735
#define PG_INT64_MIN
Definition c.h:734
uint32_t uint32
Definition c.h:683
#define lengthof(array)
Definition c.h:932
#define PG_INT32_MIN
Definition c.h:731
#define PG_INT16_MAX
Definition c.h:729
#define OidIsValid(objectId)
Definition c.h:917
uint32 result
int nspid
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition exec.c:430
char * supports_compression(const pg_compress_specification compression_spec)
Definition compress_io.c:87
char * validate_compress_specification(pg_compress_specification *spec)
bool parse_compress_algorithm(char *name, pg_compress_algorithm *algorithm)
Definition compression.c:79
void parse_compress_specification(pg_compress_algorithm algorithm, char *specification, pg_compress_specification *result)
#define PG_COMPRESSION_OPTION_WORKERS
Definition compression.h:29
void parse_compress_options(const char *option, char **algorithm, char **detail)
#define ALWAYS_SECURE_SEARCH_PATH_SQL
Definition connect.h:25
char * generate_restrict_key(void)
Definition dumputils.c:976
bool buildACLCommands(const char *name, const char *subname, const char *nspname, const char *type, const char *acls, const char *baseacls, const char *owner, const char *prefix, int remoteVersion, PQExpBuffer sql)
Definition dumputils.c:104
bool valid_restrict_key(const char *restrict_key)
Definition dumputils.c:1000
void buildShSecLabelQuery(const char *catalog_name, Oid objectId, PQExpBuffer sql)
Definition dumputils.c:681
void makeAlterConfigCommand(PGconn *conn, const char *configitem, const char *type, const char *name, const char *type2, const char *name2, PQExpBuffer buf)
Definition dumputils.c:868
bool buildDefaultACLCommands(const char *type, const char *nspname, const char *acls, const char *acldefault, const char *owner, int remoteVersion, PQExpBuffer sql)
Definition dumputils.c:366
char * sanitize_line(const char *str, bool want_hyphen)
Definition dumputils.c:52
bool variable_is_guc_list_quote(const char *name)
Definition dumputils.c:733
void quoteAclUserName(PQExpBuffer output, const char *input)
Definition dumputils.c:588
void emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer, const char *objtype, const char *objname)
Definition dumputils.c:699
Datum arg
Definition elog.c:1323
#define _(x)
Definition elog.c:96
char * PQdb(const PGconn *conn)
const char * PQparameterStatus(const PGconn *conn, const char *paramName)
int PQclientEncoding(const PGconn *conn)
char * PQerrorMessage(const PGconn *conn)
int PQsetClientEncoding(PGconn *conn, const char *encoding)
void PQfreemem(void *ptr)
Definition fe-exec.c:4068
Oid PQftype(const PGresult *res, int field_num)
Definition fe-exec.c:3750
int PQfnumber(const PGresult *res, const char *field_name)
Definition fe-exec.c:3620
int PQgetCopyData(PGconn *conn, char **buffer, int async)
Definition fe-exec.c:2833
int lo_close(PGconn *conn, int fd)
Definition fe-lobj.c:96
int lo_open(PGconn *conn, Oid lobjId, int mode)
Definition fe-lobj.c:57
void * pg_malloc(size_t size)
Definition fe_memutils.c:53
char * pg_strdup(const char *in)
Definition fe_memutils.c:91
void pg_free(void *ptr)
#define pg_realloc_array(pointer, type, count)
Definition fe_memutils.h:74
#define pg_malloc_array(type, count)
Definition fe_memutils.h:66
#define pg_malloc0_object(type)
Definition fe_memutils.h:61
#define pg_malloc_object(type)
Definition fe_memutils.h:60
#define pg_malloc0_array(type, count)
Definition fe_memutils.h:67
DataDirSyncMethod
Definition file_utils.h:28
@ DATA_DIR_SYNC_METHOD_FSYNC
Definition file_utils.h:29
void filter_init(FilterStateData *fstate, const char *filename, exit_function f_exit)
Definition filter.c:36
void filter_free(FilterStateData *fstate)
Definition filter.c:60
const char * filter_object_type_name(FilterObjectType fot)
Definition filter.c:82
bool filter_read_item(FilterStateData *fstate, char **objname, FilterCommandType *comtype, FilterObjectType *objtype)
Definition filter.c:392
void pg_log_filter_error(FilterStateData *fstate, const char *fmt,...)
Definition filter.c:154
FilterObjectType
Definition filter.h:48
@ FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN
Definition filter.h:51
@ FILTER_OBJECT_TYPE_SCHEMA
Definition filter.h:57
@ FILTER_OBJECT_TYPE_INDEX
Definition filter.h:56
@ FILTER_OBJECT_TYPE_TRIGGER
Definition filter.h:60
@ FILTER_OBJECT_TYPE_FOREIGN_DATA
Definition filter.h:54
@ FILTER_OBJECT_TYPE_DATABASE
Definition filter.h:52
@ FILTER_OBJECT_TYPE_FUNCTION
Definition filter.h:55
@ FILTER_OBJECT_TYPE_TABLE_DATA
Definition filter.h:50
@ FILTER_OBJECT_TYPE_NONE
Definition filter.h:49
@ FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN
Definition filter.h:59
@ FILTER_OBJECT_TYPE_EXTENSION
Definition filter.h:53
@ FILTER_OBJECT_TYPE_TABLE
Definition filter.h:58
FilterCommandType
Definition filter.h:38
@ FILTER_COMMAND_TYPE_NONE
Definition filter.h:39
@ FILTER_COMMAND_TYPE_EXCLUDE
Definition filter.h:41
@ FILTER_COMMAND_TYPE_INCLUDE
Definition filter.h:40
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition getopt_long.c:60
#define no_argument
Definition getopt_long.h:25
#define required_argument
Definition getopt_long.h:26
#define comment
#define storage
long val
Definition informix.c:689
static struct @175 value
static char * encoding
Definition initdb.c:139
static DataDirSyncMethod sync_method
Definition initdb.c:170
static int pg_cmp_u32(uint32 a, uint32 b)
Definition int.h:719
int j
Definition isn.c:78
int i
Definition isn.c:77
#define PQgetvalue
#define PQgetResult
#define PQgetlength
#define PQclear
#define PQnfields
#define PQresultStatus
#define PQgetisnull
#define PQfname
#define PQntuples
@ PGRES_COMMAND_OK
Definition libpq-fe.h:131
@ PGRES_COPY_OUT
Definition libpq-fe.h:137
@ PGRES_TUPLES_OK
Definition libpq-fe.h:134
#define INV_READ
Definition libpq-fs.h:22
void pg_logging_increase_verbosity(void)
Definition logging.c:187
void pg_logging_init(const char *argv0)
Definition logging.c:85
void pg_logging_set_level(enum pg_log_level new_level)
Definition logging.c:178
#define pg_log_error(...)
Definition logging.h:108
#define pg_log_error_hint(...)
Definition logging.h:114
#define pg_log_info(...)
Definition logging.h:126
@ PG_LOG_WARNING
Definition logging.h:38
#define pg_log_error_detail(...)
Definition logging.h:111
const char * progname
Definition main.c:44
char * pstrdup(const char *in)
Definition mcxt.c:1910
void pfree(void *pointer)
Definition mcxt.c:1619
bool option_parse_int(const char *optarg, const char *optname, int min_range, int max_range, int *result)
bool parse_sync_method(const char *optarg, DataDirSyncMethod *sync_method)
#define check_mut_excl_opts(set, opt,...)
Oid oprid(Operator op)
Definition parse_oper.c:241
static AmcheckOptions opts
Definition pg_amcheck.c:112
NameData attname
char attalign
int16 attlen
NameData rolname
Definition pg_authid.h:36
@ SECTION_NONE
Definition pg_backup.h:57
@ SECTION_POST_DATA
Definition pg_backup.h:60
@ SECTION_PRE_DATA
Definition pg_backup.h:58
@ SECTION_DATA
Definition pg_backup.h:59
int DumpId
Definition pg_backup.h:285
int EndLO(Archive *AHX, Oid oid)
void ProcessArchiveRestoreOptions(Archive *AHX)
RestoreOptions * NewRestoreOptions(void)
#define InvalidDumpId
Definition pg_backup.h:287
#define appendStringLiteralAH(buf, str, AH)
Definition pg_backup.h:344
int StartLO(Archive *AHX, Oid oid)
enum _archiveFormat ArchiveFormat
void ConnectDatabaseAhx(Archive *AHX, const ConnParams *cparams, bool isReconnect)
void CloseArchive(Archive *AHX)
Archive * CreateArchive(const char *FileSpec, const ArchiveFormat fmt, const pg_compress_specification compression_spec, bool dosync, ArchiveMode mode, SetupWorkerPtrType setupDumpWorker, DataDirSyncMethod sync_method)
@ archModeWrite
Definition pg_backup.h:51
@ archModeAppend
Definition pg_backup.h:50
@ PREPQUERY_DUMPFUNC
Definition pg_backup.h:72
@ PREPQUERY_DUMPTABLEATTACH
Definition pg_backup.h:75
@ PREPQUERY_DUMPBASETYPE
Definition pg_backup.h:67
@ PREPQUERY_DUMPRANGETYPE
Definition pg_backup.h:74
@ PREPQUERY_DUMPOPR
Definition pg_backup.h:73
@ PREPQUERY_DUMPEXTSTATSOBJSTATS
Definition pg_backup.h:71
@ PREPQUERY_GETATTRIBUTESTATS
Definition pg_backup.h:76
@ PREPQUERY_DUMPDOMAIN
Definition pg_backup.h:69
@ PREPQUERY_DUMPCOMPOSITETYPE
Definition pg_backup.h:68
@ PREPQUERY_DUMPAGG
Definition pg_backup.h:66
@ PREPQUERY_GETCOLUMNACLS
Definition pg_backup.h:77
@ PREPQUERY_GETDOMAINCONSTRAINTS
Definition pg_backup.h:78
@ PREPQUERY_DUMPENUMTYPE
Definition pg_backup.h:70
int archprintf(Archive *AH, const char *fmt,...) pg_attribute_printf(2
void SetArchiveOptions(Archive *AH, DumpOptions *dopt, RestoreOptions *ropt)
#define NUM_PREP_QUERIES
Definition pg_backup.h:81
void RestoreArchive(Archive *AHX)
void archputs(const char *s, Archive *AH)
@ archUnknown
Definition pg_backup.h:41
@ archTar
Definition pg_backup.h:43
@ archCustom
Definition pg_backup.h:42
@ archDirectory
Definition pg_backup.h:45
@ archNull
Definition pg_backup.h:44
void InitDumpOptions(DumpOptions *opts)
void WriteData(Archive *AHX, const void *data, size_t dLen)
int TocIDRequired(ArchiveHandle *AH, DumpId id)
TocEntry * ArchiveEntry(Archive *AHX, CatalogId catalogId, DumpId dumpId, ArchiveOpts *opts)
#define ARCHIVE_OPTS(...)
#define LOBBUFSIZE
#define REQ_STATS
int(* DataDumperPtr)(Archive *AH, const void *userArg)
void ExecuteSqlStatement(Archive *AHX, const char *query)
PGresult * ExecuteSqlQuery(Archive *AHX, const char *query, ExecStatusType status)
PGresult * ExecuteSqlQueryForSingleRow(Archive *fout, const char *query)
void exit_nicely(int code)
void set_dump_section(const char *arg, int *dumpSections)
#define pg_fatal(...)
static char format
static char * label
static PgChecksumMode mode
#define FUNC_MAX_ARGS
const void size_t len
const void * data
char datlocprovider
Definition pg_database.h:46
NameData datname
Definition pg_database.h:37
bool datistemplate
Definition pg_database.h:49
int32 datconnlimit
Definition pg_database.h:61
static void expand_schema_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names)
Definition pg_dump.c:1638
static const CatalogId nilCatalogId
Definition pg_dump.c:191
static void dumpEncoding(Archive *AH)
Definition pg_dump.c:3786
void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:8250
static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId, const char *type, const char *name, const char *subname, const char *nspname, const char *tag, const char *owner, const DumpableAcl *dacl)
Definition pg_dump.c:16364
static SimpleStringList schema_include_patterns
Definition pg_dump.c:167
static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
Definition pg_dump.c:18172
ExtensionInfo * getExtensions(Archive *fout, int *numExtensions)
Definition pg_dump.c:6169
static void selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
Definition pg_dump.c:2181
static void collectBinaryUpgradeClassOids(Archive *fout)
Definition pg_dump.c:5869
static PQExpBuffer createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
Definition pg_dump.c:17007
static void dumpUserMappings(Archive *fout, const char *servername, const char *namespace, const char *owner, CatalogId catalogId, DumpId dumpId)
Definition pg_dump.c:16178
static void dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
Definition pg_dump.c:4969
static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs, DumpableObject *boundaryObjs)
Definition pg_dump.c:20390
void getPublicationNamespaces(Archive *fout)
Definition pg_dump.c:4758
static void dumpSearchPath(Archive *AH)
Definition pg_dump.c:3835
static int ncomments
Definition pg_dump.c:203
static void selectDumpableTable(TableInfo *tbinfo, Archive *fout)
Definition pg_dump.c:2050
static DumpableObject * createBoundaryObjects(void)
Definition pg_dump.c:20366
static char * convertTSFunction(Archive *fout, Oid funcOid)
Definition pg_dump.c:14373
static void dumpDatabase(Archive *fout)
Definition pg_dump.c:3242
static SimpleStringList table_include_patterns
Definition pg_dump.c:172
static void append_depends_on_extension(Archive *fout, PQExpBuffer create, const DumpableObject *dobj, const char *catalog, const char *keyword, const char *objname)
Definition pg_dump.c:5682
static Oid get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
Definition pg_dump.c:5727
static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
Definition pg_dump.c:11843
static bool forcePartitionRootLoad(const TableInfo *tbinfo)
Definition pg_dump.c:2803
static void dumpCast(Archive *fout, const CastInfo *cast)
Definition pg_dump.c:13849
static SimpleOidList schema_exclude_oids
Definition pg_dump.c:170
static bool have_extra_float_digits
Definition pg_dump.c:194
static void dumpIndex(Archive *fout, const IndxInfo *indxinfo)
Definition pg_dump.c:18262
void getPartitioningInfo(Archive *fout)
Definition pg_dump.c:7747
static int nbinaryUpgradeClassOids
Definition pg_dump.c:211
static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12436
OidOptions
Definition pg_dump.c:145
@ zeroIsError
Definition pg_dump.c:146
@ zeroAsStar
Definition pg_dump.c:147
@ zeroAsNone
Definition pg_dump.c:148
static char * dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
Definition pg_dump.c:11084
static SimpleOidList extension_include_oids
Definition pg_dump.c:186
static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
Definition pg_dump.c:15747
static void dumpAgg(Archive *fout, const AggInfo *agginfo)
Definition pg_dump.c:15343
static int extra_float_digits
Definition pg_dump.c:195
static int SequenceItemCmp(const void *p1, const void *p2)
Definition pg_dump.c:19173
static void dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
Definition pg_dump.c:11360
static void dumpTableComment(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
Definition pg_dump.c:11386
static SimpleStringList extension_include_patterns
Definition pg_dump.c:185
static void selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
Definition pg_dump.c:1965
InhInfo * getInherits(Archive *fout, int *numInherits)
Definition pg_dump.c:7691
void getForeignDataWrappers(Archive *fout)
Definition pg_dump.c:10369
static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
Definition pg_dump.c:19545
static void binary_upgrade_set_type_oids_by_rel(Archive *fout, PQExpBuffer upgrade_buffer, const TableInfo *tbinfo)
Definition pg_dump.c:5838
static void dumpTable(Archive *fout, const TableInfo *tbinfo)
Definition pg_dump.c:16819
static SimpleOidList extension_exclude_oids
Definition pg_dump.c:189
static SimpleStringList table_exclude_patterns
Definition pg_dump.c:175
static PQExpBuffer createViewAsClause(Archive *fout, const TableInfo *tbinfo)
Definition pg_dump.c:16958
static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
Definition pg_dump.c:18456
void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:4187
static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12214
void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition pg_dump.c:19928
static void dumpComment(Archive *fout, const char *type, const char *name, const char *namespace, const char *owner, CatalogId catalogId, int subid, DumpId dumpId)
Definition pg_dump.c:10945
static char * getFormattedOperatorName(const char *oproid)
Definition pg_dump.c:14343
static char * format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
Definition pg_dump.c:13406
static int nseclabels
Definition pg_dump.c:207
static pg_compress_algorithm compression_algorithm
Definition pg_dump.c:159
static void dumpStdStrings(Archive *AH)
Definition pg_dump.c:3811
static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
Definition pg_dump.c:18813
static void dumpType(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12043
static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
Definition pg_dump.c:18104
void getTypes(Archive *fout)
Definition pg_dump.c:6244
static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
Definition pg_dump.c:14395
static void dumpOpr(Archive *fout, const OprInfo *oprinfo)
Definition pg_dump.c:14083
static void selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
Definition pg_dump.c:2298
static void selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
Definition pg_dump.c:2280
static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
Definition pg_dump.c:19456
static void dumpFunc(Archive *fout, const FuncInfo *finfo)
Definition pg_dump.c:13435
static void selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
Definition pg_dump.c:2134
static void BuildArchiveDependencies(Archive *fout)
Definition pg_dump.c:20516
static RelStatsInfo * getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages, char *reltuples, int32 relallvisible, int32 relallfrozen, char relkind, char **indAttNames, int nindAttNames)
Definition pg_dump.c:7073
static const char *const SeqTypeNames[]
Definition pg_dump.c:119
void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:7626
static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
Definition pg_dump.c:3000
static int nsequences
Definition pg_dump.c:215
static const char * getAttrName(int attrnum, const TableInfo *tblInfo)
Definition pg_dump.c:18233
static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
Definition pg_dump.c:16078
static RoleNameItem * rolenames
Definition pg_dump.c:198
static void collectRoleNames(Archive *fout)
Definition pg_dump.c:10684
static PGresult * fetchAttributeStats(Archive *fout)
Definition pg_dump.c:10979
static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions, const char *prefix, Archive *fout)
Definition pg_dump.c:20715
void getOpclasses(Archive *fout)
Definition pg_dump.c:6678
void getForeignServers(Archive *fout)
Definition pg_dump.c:10463
void getFuncs(Archive *fout)
Definition pg_dump.c:6921
static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
Definition pg_dump.c:2831
static void prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
Definition pg_dump.c:1898
static bool dosync
Definition pg_dump.c:152
static int dumpTableData_copy(Archive *fout, const void *dcontext)
Definition pg_dump.c:2338
#define MAX_BLOBS_PER_ARCHIVE_ENTRY
Definition pg_dump.c:231
static const char * getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
Definition pg_dump.c:20618
static void getDependencies(Archive *fout)
Definition pg_dump.c:20202
static void buildMatViewRefreshDependencies(Archive *fout)
Definition pg_dump.c:3090
void getTSDictionaries(Archive *fout)
Definition pg_dump.c:10185
static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_type_oid, bool force_array_type, bool include_multirange_type)
Definition pg_dump.c:5758
#define DUMP_DEFAULT_ROWS_PER_INSERT
Definition pg_dump.c:224
void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:4838
static SeqType parse_sequence_type(const char *name)
Definition pg_dump.c:19157
static const char * getRoleName(const char *roleoid_str)
Definition pg_dump.c:10648
static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
Definition pg_dump.c:13205
static SequenceItem * sequences
Definition pg_dump.c:214
static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
Definition pg_dump.c:2946
static int findComments(Oid classoid, Oid objoid, CommentItem **items)
Definition pg_dump.c:11484
static SimpleStringList foreign_servers_include_patterns
Definition pg_dump.c:182
static void selectDumpableCast(CastInfo *cast, Archive *fout)
Definition pg_dump.c:2156
void getCasts(Archive *fout)
Definition pg_dump.c:8995
static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
Definition pg_dump.c:4636
static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
Definition pg_dump.c:4352
void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:7807
static void setupDumpWorker(Archive *AH)
Definition pg_dump.c:1571
static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
Definition pg_dump.c:8409
void getTSConfigurations(Archive *fout)
Definition pg_dump.c:10310
static int nrolenames
Definition pg_dump.c:199
static int findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
Definition pg_dump.c:16654
static SimpleStringList table_include_patterns_and_children
Definition pg_dump.c:173
static char * convertRegProcReference(const char *proc)
Definition pg_dump.c:14302
static void getAdditionalACLs(Archive *fout)
Definition pg_dump.c:10719
static void getTableDataFKConstraints(void)
Definition pg_dump.c:3201
static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
Definition pg_dump.c:2981
static SimpleOidList table_exclude_oids
Definition pg_dump.c:177
SeqType
Definition pg_dump.c:113
@ SEQTYPE_BIGINT
Definition pg_dump.c:116
@ SEQTYPE_INTEGER
Definition pg_dump.c:115
@ SEQTYPE_SMALLINT
Definition pg_dump.c:114
void getAccessMethods(Archive *fout)
Definition pg_dump.c:6616
void getConversions(Archive *fout)
Definition pg_dump.c:6554
void getRules(Archive *fout)
Definition pg_dump.c:8544
static void dumpDomain(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12685
void getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition pg_dump.c:9185
static void collectComments(Archive *fout)
Definition pg_dump.c:11561
static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
Definition pg_dump.c:8432
static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
Definition pg_dump.c:14744
static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
Definition pg_dump.c:16272
static void selectDumpableObject(DumpableObject *dobj, Archive *fout)
Definition pg_dump.c:2316
static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
Definition pg_dump.c:15827
static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
Definition pg_dump.c:18413
static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
Definition pg_dump.c:5448
void getCollations(Archive *fout)
Definition pg_dump.c:6488
static char * format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
Definition pg_dump.c:13383
static int strict_names
Definition pg_dump.c:157
static void dumpTransform(Archive *fout, const TransformInfo *transform)
Definition pg_dump.c:13954
void getAggregates(Archive *fout)
Definition pg_dump.c:6806
static void dumpLO(Archive *fout, const LoInfo *loinfo)
Definition pg_dump.c:4051
void getNamespaces(Archive *fout)
Definition pg_dump.c:6037
static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
Definition pg_dump.c:5012
void getPublications(Archive *fout)
Definition pg_dump.c:4470
static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer, const DumpableObject *dobj, const char *objtype, const char *objname, const char *objnamespace)
Definition pg_dump.c:5993
static void dumpDumpableObject(Archive *fout, DumpableObject *dobj)
Definition pg_dump.c:11646
static void getLOs(Archive *fout)
Definition pg_dump.c:3897
static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf, const char *dbname, Oid dboid)
Definition pg_dump.c:3742
void getTSParsers(Archive *fout)
Definition pg_dump.c:10111
static void setup_connection(Archive *AH, const char *dumpencoding, const char *dumpsnapshot, char *use_role)
Definition pg_dump.c:1399
static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
Definition pg_dump.c:19134
static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12372
static void selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
Definition pg_dump.c:2213
static const char * fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
Definition pg_dump.c:20669
static void expand_table_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names, bool with_child_tables)
Definition pg_dump.c:1802
static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj, DumpId **dependencies, int *nDeps, int *allocDeps)
Definition pg_dump.c:20563
static void determineNotNullFlags(Archive *fout, PGresult *res, int r, TableInfo *tbinfo, int j, int i_notnull_name, int i_notnull_comment, int i_notnull_invalidoid, int i_notnull_noinherit, int i_notnull_islocal, PQExpBuffer *invalidnotnulloids)
Definition pg_dump.c:9969
static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
Definition pg_dump.c:17047
static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
Definition pg_dump.c:15683
static void expand_foreign_server_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids)
Definition pg_dump.c:1750
TableInfo * getTables(Archive *fout, int *numTables)
Definition pg_dump.c:7151
static void dumpRule(Archive *fout, const RuleInfo *rinfo)
Definition pg_dump.c:19761
static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12910
static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12074
static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
Definition pg_dump.c:11920
#define fmtQualifiedDumpable(obj)
Definition pg_dump.c:236
static bool nonemptyReloptions(const char *reloptions)
Definition pg_dump.c:20703
static SimpleStringList extension_exclude_patterns
Definition pg_dump.c:188
static BinaryUpgradeClassOidItem * binaryUpgradeClassOids
Definition pg_dump.c:210
static SimpleOidList table_include_oids
Definition pg_dump.c:174
static void dumpStatisticsExtStats(Archive *fout, const StatsExtInfo *statsextinfo)
Definition pg_dump.c:18533
void getExtendedStatistics(Archive *fout)
Definition pg_dump.c:8172
static NamespaceInfo * findNamespace(Oid nsoid)
Definition pg_dump.c:6151
static char * get_synchronized_snapshot(Archive *fout)
Definition pg_dump.c:1586
static int dumpLOs(Archive *fout, const void *arg)
Definition pg_dump.c:4141
static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
Definition pg_dump.c:5517
static void appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname, const char *argtype, const char *argval)
Definition pg_dump.c:10961
void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition pg_dump.c:20021
static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
Definition pg_dump.c:19671
static int BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
Definition pg_dump.c:5853
static void dumpCommentExtended(Archive *fout, const char *type, const char *name, const char *namespace, const char *owner, CatalogId catalogId, int subid, DumpId dumpId, const char *initdb_comment)
Definition pg_dump.c:10845
void getDefaultACLs(Archive *fout)
Definition pg_dump.c:10551
static SimpleStringList tabledata_exclude_patterns
Definition pg_dump.c:178
static void dumpConversion(Archive *fout, const ConvInfo *convinfo)
Definition pg_dump.c:15215
static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
Definition pg_dump.c:16005
static void dumpProcLang(Archive *fout, const ProcLangInfo *plang)
Definition pg_dump.c:13251
static void dumpSecLabel(Archive *fout, const char *type, const char *name, const char *namespace, const char *owner, CatalogId catalogId, int subid, DumpId dumpId)
Definition pg_dump.c:16492
void getSubscriptions(Archive *fout)
Definition pg_dump.c:5113
static void collectSecLabels(Archive *fout)
Definition pg_dump.c:16733
static void selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
Definition pg_dump.c:2241
static void collectSequences(Archive *fout)
Definition pg_dump.c:19188
static Oid g_last_builtin_oid
Definition pg_dump.c:154
#define MAX_ATTR_STATS_RELS
Definition pg_dump.c:218
void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:8641
void getTransforms(Archive *fout)
Definition pg_dump.c:9105
void getEventTriggers(Archive *fout)
Definition pg_dump.c:8837
static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode)
Definition pg_dump.c:1600
static void read_dump_filters(const char *filename, DumpOptions *dopt)
Definition pg_dump.c:20734
static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
Definition pg_dump.c:15885
static SecLabelItem * seclabels
Definition pg_dump.c:206
static SimpleStringList tabledata_exclude_patterns_and_children
Definition pg_dump.c:179
static char * get_language_name(Archive *fout, Oid langid)
Definition pg_dump.c:9084
static bool checkExtensionMembership(DumpableObject *dobj, Archive *fout)
Definition pg_dump.c:1923
static CommentItem * comments
Definition pg_dump.c:202
static int dumpTableData_insert(Archive *fout, const void *dcontext)
Definition pg_dump.c:2509
static SimpleOidList tabledata_exclude_oids
Definition pg_dump.c:180
static SimpleStringList table_exclude_patterns_and_children
Definition pg_dump.c:176
static void binary_upgrade_set_pg_class_oids(Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_class_oid)
Definition pg_dump.c:5903
void getTSTemplates(Archive *fout)
Definition pg_dump.c:10251
static void set_restrict_relation_kind(Archive *AH, const char *value)
Definition pg_dump.c:5092
static char * format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
Definition pg_dump.c:15311
void getProcLangs(Archive *fout)
Definition pg_dump.c:8911
static void dumpSequence(Archive *fout, const TableInfo *tbinfo)
Definition pg_dump.c:19244
bool shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
Definition pg_dump.c:10096
static TableInfo * getRootTableInfo(const TableInfo *tbinfo)
Definition pg_dump.c:2778
void getSubscriptionRelations(Archive *fout)
Definition pg_dump.c:5362
void getOperators(Archive *fout)
Definition pg_dump.c:6412
static SimpleOidList foreign_servers_include_oids
Definition pg_dump.c:183
static void dumpCollation(Archive *fout, const CollInfo *collinfo)
Definition pg_dump.c:14963
static void dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
Definition pg_dump.c:16572
static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo, PGresult *res)
Definition pg_dump.c:13116
static void expand_extension_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names)
Definition pg_dump.c:1697
void getOpfamilies(Archive *fout)
Definition pg_dump.c:6741
static void selectDumpableType(TypeInfo *tyinfo, Archive *fout)
Definition pg_dump.c:2089
static SimpleOidList schema_include_oids
Definition pg_dump.c:168
static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
Definition pg_dump.c:14463
static SimpleStringList schema_exclude_patterns
Definition pg_dump.c:169
#define DUMP_COMPONENT_COMMENT
Definition pg_dump.h:111
#define DUMP_COMPONENT_DATA
Definition pg_dump.h:110
#define DUMP_COMPONENT_USERMAP
Definition pg_dump.h:115
#define DUMP_COMPONENT_POLICY
Definition pg_dump.h:114
#define DUMP_COMPONENT_SECLABEL
Definition pg_dump.h:112
#define DUMP_COMPONENT_ALL
Definition pg_dump.h:117
#define DUMP_COMPONENT_ACL
Definition pg_dump.h:113
#define DUMP_COMPONENT_NONE
Definition pg_dump.h:108
#define DUMP_COMPONENTS_REQUIRING_LOCK
Definition pg_dump.h:141
void sortDumpableObjects(DumpableObject **objs, int numObjs, DumpId preBoundaryId, DumpId postBoundaryId)
#define DUMP_COMPONENT_DEFINITION
Definition pg_dump.h:109
@ DO_EVENT_TRIGGER
Definition pg_dump.h:80
@ DO_REFRESH_MATVIEW
Definition pg_dump.h:81
@ DO_POLICY
Definition pg_dump.h:82
@ DO_CAST
Definition pg_dump.h:64
@ DO_FOREIGN_SERVER
Definition pg_dump.h:73
@ DO_PRE_DATA_BOUNDARY
Definition pg_dump.h:78
@ DO_PROCLANG
Definition pg_dump.h:63
@ DO_TYPE
Definition pg_dump.h:43
@ DO_INDEX
Definition pg_dump.h:56
@ DO_COLLATION
Definition pg_dump.h:51
@ DO_LARGE_OBJECT
Definition pg_dump.h:76
@ DO_TSCONFIG
Definition pg_dump.h:71
@ DO_OPERATOR
Definition pg_dump.h:47
@ DO_FK_CONSTRAINT
Definition pg_dump.h:62
@ DO_CONSTRAINT
Definition pg_dump.h:61
@ DO_SUBSCRIPTION
Definition pg_dump.h:87
@ DO_DEFAULT_ACL
Definition pg_dump.h:74
@ DO_FDW
Definition pg_dump.h:72
@ DO_SUBSCRIPTION_REL
Definition pg_dump.h:88
@ DO_REL_STATS
Definition pg_dump.h:86
@ DO_SEQUENCE_SET
Definition pg_dump.h:66
@ DO_ATTRDEF
Definition pg_dump.h:55
@ DO_PUBLICATION_REL
Definition pg_dump.h:84
@ DO_TABLE_ATTACH
Definition pg_dump.h:54
@ DO_OPCLASS
Definition pg_dump.h:49
@ DO_INDEX_ATTACH
Definition pg_dump.h:57
@ DO_TSTEMPLATE
Definition pg_dump.h:70
@ DO_STATSEXT
Definition pg_dump.h:58
@ DO_FUNC
Definition pg_dump.h:45
@ DO_POST_DATA_BOUNDARY
Definition pg_dump.h:79
@ DO_LARGE_OBJECT_DATA
Definition pg_dump.h:77
@ DO_OPFAMILY
Definition pg_dump.h:50
@ DO_TRANSFORM
Definition pg_dump.h:75
@ DO_ACCESS_METHOD
Definition pg_dump.h:48
@ DO_PUBLICATION_TABLE_IN_SCHEMA
Definition pg_dump.h:85
@ DO_CONVERSION
Definition pg_dump.h:52
@ DO_TRIGGER
Definition pg_dump.h:60
@ DO_RULE
Definition pg_dump.h:59
@ DO_DUMMY_TYPE
Definition pg_dump.h:67
@ DO_TSDICT
Definition pg_dump.h:69
@ DO_TSPARSER
Definition pg_dump.h:68
@ DO_EXTENSION
Definition pg_dump.h:42
@ DO_TABLE_DATA
Definition pg_dump.h:65
@ DO_PUBLICATION
Definition pg_dump.h:83
@ DO_TABLE
Definition pg_dump.h:53
@ DO_NAMESPACE
Definition pg_dump.h:41
@ DO_AGG
Definition pg_dump.h:46
@ DO_SHELL_TYPE
Definition pg_dump.h:44
void sortDumpableObjectsByTypeName(DumpableObject **objs, int numObjs)
#define DUMP_COMPONENT_STATISTICS
Definition pg_dump.h:116
static int statistics_only
Definition pg_dumpall.c:112
static int no_statistics
Definition pg_dumpall.c:103
static int no_data
Definition pg_dumpall.c:101
static int no_schema
Definition pg_dumpall.c:102
static char * filename
Definition pg_dumpall.c:120
static int with_statistics
Definition pg_dumpall.c:108
PGDLLIMPORT int optind
Definition getopt.c:47
PGDLLIMPORT char * optarg
Definition getopt.c:49
NameData subname
static char buf[DEFAULT_XLOG_SEG_SIZE]
char typalign
Definition pg_type.h:178
#define pg_encoding_to_char
Definition pg_wchar.h:483
static char * tablespace
Definition pgbench.c:217
#define pg_log_warning(...)
Definition pgfnames.c:24
int pg_strcasecmp(const char *s1, const char *s2)
#define sprintf
Definition port.h:263
#define snprintf
Definition port.h:261
const char * get_progname(const char *argv0)
Definition path.c:669
#define printf(...)
Definition port.h:267
off_t pgoff_t
Definition port.h:422
#define InvalidOid
unsigned int Oid
#define atooid(x)
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
PQExpBuffer createPQExpBuffer(void)
Definition pqexpbuffer.c:72
void initPQExpBuffer(PQExpBuffer str)
Definition pqexpbuffer.c:90
void resetPQExpBuffer(PQExpBuffer str)
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
void appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
void destroyPQExpBuffer(PQExpBuffer str)
void appendPQExpBufferChar(PQExpBuffer str, char ch)
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
void termPQExpBuffer(PQExpBuffer str)
char * c
static int fb(int x)
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
Oid RelFileNumber
Definition relpath.h:25
#define RelFileNumberIsValid(relnumber)
Definition relpath.h:27
bool quote_all_identifiers
Definition ruleutils.c:344
void simple_string_list_append(SimpleStringList *list, const char *val)
Definition simple_list.c:63
void simple_ptr_list_append(SimplePtrList *list, void *ptr)
bool simple_oid_list_member(SimpleOidList *list, Oid val)
Definition simple_list.c:45
void simple_oid_list_append(SimpleOidList *list, Oid val)
Definition simple_list.c:26
#define free(a)
#define PG_DEPENDENCIES_KEY_ATTRIBUTES
#define PG_DEPENDENCIES_KEY_DEGREE
#define PG_DEPENDENCIES_KEY_DEPENDENCY
#define PG_NDISTINCT_KEY_ATTRIBUTES
#define PG_NDISTINCT_KEY_NDISTINCT
PGconn * GetConnection(void)
Definition streamutil.c:60
char * dbname
Definition streamutil.c:49
PGconn * conn
Definition streamutil.c:52
const char * fmtId(const char *rawid)
void setFmtEncoding(int encoding)
void appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
void appendPGArray(PQExpBuffer buffer, const char *value)
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule, PQExpBuffer dbnamebuf, int *dotcnt)
bool parsePGArray(const char *atext, char ***itemarray, int *nitems)
bool appendReloptionsArray(PQExpBuffer buffer, const char *reloptions, const char *prefix, int encoding, bool std_strings)
void appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
int remoteVersion
Definition pg_backup.h:234
DumpOptions * dopt
Definition pg_backup.h:229
bool * is_prepared
Definition pg_backup.h:256
char * searchpath
Definition pg_backup.h:248
bool std_strings
Definition pg_backup.h:245
int numWorkers
Definition pg_backup.h:240
int encoding
Definition pg_backup.h:244
char * use_role
Definition pg_backup.h:249
char * sync_snapshot_id
Definition pg_backup.h:241
RelFileNumber toast_index_relfilenumber
Definition pg_dump.c:108
RelFileNumber toast_relfilenumber
Definition pg_dump.c:106
RelFileNumber relfilenumber
Definition pg_dump.c:104
Oid tableoid
Definition pg_backup.h:281
Oid classoid
Definition pg_dump.c:86
Oid objoid
Definition pg_dump.c:87
int objsubid
Definition pg_dump.c:88
const char * descr
Definition pg_dump.c:85
const char * rolename
Definition pg_dump.c:80
Oid roleoid
Definition pg_dump.c:79
const char * provider
Definition pg_dump.c:93
Oid classoid
Definition pg_dump.c:95
int objsubid
Definition pg_dump.c:97
const char * label
Definition pg_dump.c:94
int64 minv
Definition pg_dump.c:134
int64 cache
Definition pg_dump.c:138
int64 startv
Definition pg_dump.c:136
int64 maxv
Definition pg_dump.c:135
bool is_called
Definition pg_dump.c:140
int64 incby
Definition pg_dump.c:137
int64 last_value
Definition pg_dump.c:139
SeqType seqtype
Definition pg_dump.c:132
bool cycled
Definition pg_dump.c:133
bool null_seqtuple
Definition pg_dump.c:141
SimpleOidListCell * head
Definition simple_list.h:28
struct SimplePtrListCell * next
Definition simple_list.h:48
char val[FLEXIBLE_ARRAY_MEMBER]
Definition simple_list.h:37
struct SimpleStringListCell * next
Definition simple_list.h:34
SimpleStringListCell * head
Definition simple_list.h:42
char * suboriginremotelsn
Definition pg_dump.h:732
bool subpasswordrequired
Definition pg_dump.h:720
const char * rolname
Definition pg_dump.h:714
char * subservername
Definition pg_dump.h:725
char * subsynccommit
Definition pg_dump.h:728
char * subpublications
Definition pg_dump.h:730
char * subwalrcvtimeout
Definition pg_dump.h:729
char * subslotname
Definition pg_dump.h:727
char subtwophasestate
Definition pg_dump.h:718
bool subretaindeadtuples
Definition pg_dump.h:723
char * subconninfo
Definition pg_dump.h:726
DumpableObject dobj
Definition pg_dump.h:713
DumpableObject dobj
Definition pg_dump.h:270
ArchiveFormat format
struct _tocEntry * toc
DumpableObject dobj
Definition pg_dump.h:404
char * adef_expr
Definition pg_dump.h:407
TableInfo * adtable
Definition pg_dump.h:405
bool separate
Definition pg_dump.h:408
char * pgport
Definition pg_backup.h:88
char * pghost
Definition pg_backup.h:89
trivalue promptPassword
Definition pg_backup.h:91
char * username
Definition pg_backup.h:90
char * dbname
Definition pg_backup.h:87
TypeInfo * condomain
Definition pg_dump.h:520
TableInfo * contable
Definition pg_dump.h:519
DumpableObject dobj
Definition pg_dump.h:518
DumpId conindex
Definition pg_dump.h:524
bool condeferrable
Definition pg_dump.h:525
char * condef
Definition pg_dump.h:522
int no_toast_compression
Definition pg_backup.h:192
char * restrict_key
Definition pg_backup.h:220
int column_inserts
Definition pg_backup.h:185
bool dontOutputLOs
Definition pg_backup.h:208
int use_setsessauth
Definition pg_backup.h:198
int outputCreateDB
Definition pg_backup.h:206
bool include_everything
Definition pg_backup.h:203
int sequence_data
Definition pg_backup.h:212
int disable_dollar_quoting
Definition pg_backup.h:184
bool dumpSchema
Definition pg_backup.h:216
int serializable_deferrable
Definition pg_backup.h:194
int outputNoTableAm
Definition pg_backup.h:196
int enable_row_security
Definition pg_backup.h:199
char * outputSuperuser
Definition pg_backup.h:210
int no_security_labels
Definition pg_backup.h:190
int no_unlogged_table_data
Definition pg_backup.h:193
bool dumpStatistics
Definition pg_backup.h:218
int no_publications
Definition pg_backup.h:189
ConnParams cparams
Definition pg_backup.h:173
const char * lockWaitTimeout
Definition pg_backup.h:180
int no_subscriptions
Definition pg_backup.h:191
int load_via_partition_root
Definition pg_backup.h:200
int outputNoTablespaces
Definition pg_backup.h:197
int disable_triggers
Definition pg_backup.h:195
int outputNoOwner
Definition pg_backup.h:209
int binary_upgrade
Definition pg_backup.h:175
char privtype
Definition pg_dump.h:173
char * acldefault
Definition pg_dump.h:171
char * acl
Definition pg_dump.h:170
char * initprivs
Definition pg_dump.h:174
DumpComponents dump
Definition pg_dump.h:153
DumpId * dependencies
Definition pg_dump.h:159
DumpId dumpId
Definition pg_dump.h:151
DumpComponents components
Definition pg_dump.h:156
DumpableObjectType objType
Definition pg_dump.h:149
CatalogId catId
Definition pg_dump.h:150
DumpComponents dump_contains
Definition pg_dump.h:155
bool depends_on_ext
Definition pg_dump.h:158
DumpableObject dobj
Definition pg_dump.h:195
char * extconfig
Definition pg_dump.h:199
bool postponed_def
Definition pg_dump.h:248
Oid lang
Definition pg_dump.h:244
const char * rolname
Definition pg_dump.h:243
Oid * argtypes
Definition pg_dump.h:246
Oid prorettype
Definition pg_dump.h:247
DumpableObject dobj
Definition pg_dump.h:241
int nargs
Definition pg_dump.h:245
DumpableAcl dacl
Definition pg_dump.h:242
int32 nindAttNames
Definition pg_dump.h:463
char ** indAttNames
Definition pg_dump.h:462
int32 relpages
Definition pg_dump.h:452
int32 relallfrozen
Definition pg_dump.h:455
char * reltuples
Definition pg_dump.h:453
teSection section
Definition pg_dump.h:464
int32 relallvisible
Definition pg_dump.h:454
DumpableObject dobj
Definition pg_dump.h:450
int suppressDumpWarnings
Definition pg_backup.h:152
ConnParams cparams
Definition pg_backup.h:146
pg_compress_specification compression_spec
Definition pg_backup.h:150
int disable_dollar_quoting
Definition pg_backup.h:110
char * restrict_key
Definition pg_backup.h:168
const char * filename
Definition pg_backup.h:121
const char * lockWaitTimeout
Definition pg_backup.h:125
int enable_row_security
Definition pg_backup.h:159
DumpableObject dobj
Definition pg_dump.h:477
bool separate
Definition pg_dump.h:482
char ev_enabled
Definition pg_dump.h:481
bool is_instead
Definition pg_dump.h:480
TableInfo * ruletable
Definition pg_dump.h:478
char ev_type
Definition pg_dump.h:479
DumpableObject dobj
Definition pg_dump.h:413
char * attidentity
Definition pg_dump.h:361
char * reltablespace
Definition pg_dump.h:314
struct _relStatsInfo * stats
Definition pg_dump.h:381
int ncheck
Definition pg_dump.h:330
bool ispartition
Definition pg_dump.h:344
DumpableObject dobj
Definition pg_dump.h:307
bool is_identity_sequence
Definition pg_dump.h:337
Oid reloftype
Definition pg_dump.h:332
bool interesting
Definition pg_dump.h:341
char * toast_reloptions
Definition pg_dump.h:317
struct _tableInfo ** parents
Definition pg_dump.h:348
DumpableAcl dacl
Definition pg_dump.h:308
bool relispopulated
Definition pg_dump.h:312
Oid reltype
Definition pg_dump.h:331
bool hasoids
Definition pg_dump.h:324
Oid toast_oid
Definition pg_dump.h:327
Oid foreign_server
Definition pg_dump.h:333
bool hasrules
Definition pg_dump.h:319
uint32 frozenxid
Definition pg_dump.h:325
int owning_col
Definition pg_dump.h:336
char * checkoption
Definition pg_dump.h:316
bool hastriggers
Definition pg_dump.h:320
const char * rolname
Definition pg_dump.h:309
char relreplident
Definition pg_dump.h:313
uint32 minmxid
Definition pg_dump.h:326
int toastpages
Definition pg_dump.h:339
Oid owning_tab
Definition pg_dump.h:335
struct _tableDataInfo * dataObj
Definition pg_dump.h:390
char * amname
Definition pg_dump.h:383
bool dummy_view
Definition pg_dump.h:342
int32 relpages
Definition pg_dump.h:338
bool forcerowsec
Definition pg_dump.h:323
bool hascolumnACLs
Definition pg_dump.h:321
char relpersistence
Definition pg_dump.h:311
char ** attnames
Definition pg_dump.h:355
char relkind
Definition pg_dump.h:310
bool hasindex
Definition pg_dump.h:318
char * reloptions
Definition pg_dump.h:315
uint32 toast_frozenxid
Definition pg_dump.h:328
uint32 toast_minmxid
Definition pg_dump.h:329
bool postponed_def
Definition pg_dump.h:343
bool rowsec
Definition pg_dump.h:322
struct _tocEntry * next
const void * defnDumperArg
DumpId * dependencies
DumpableObject dobj
Definition pg_dump.h:555
DumpableObject dobj
Definition pg_dump.h:205
char data[NAMEDATALEN]
Definition c.h:890
#define MinTransactionIdAttributeNumber
Definition sysattr.h:22
#define MaxCommandIdAttributeNumber
Definition sysattr.h:25
#define MaxTransactionIdAttributeNumber
Definition sysattr.h:24
#define TableOidAttributeNumber
Definition sysattr.h:26
#define SelfItemPointerAttributeNumber
Definition sysattr.h:21
#define MinCommandIdAttributeNumber
Definition sysattr.h:23
static StringInfo copybuf
Definition tablesync.c:129
static ItemArray items
static void * fn(void *arg)
#define FirstNormalObjectId
Definition transam.h:197
@ TRI_YES
Definition vacuumlo.c:38
@ TRI_NO
Definition vacuumlo.c:37
static char * error_detail
Definition validator.c:43
bool SplitGUCList(char *rawstring, char separator, List **namelist)
Definition varlena.c:3063
const char * description
const char * type
const char * name
ArchiveMode
Definition xlog.h:66

◆ MAX_ATTR_STATS_RELS

#define MAX_ATTR_STATS_RELS   64

Definition at line 218 of file pg_dump.c.

◆ MAX_BLOBS_PER_ARCHIVE_ENTRY

#define MAX_BLOBS_PER_ARCHIVE_ENTRY   1000

Definition at line 231 of file pg_dump.c.

Typedef Documentation

◆ OidOptions

◆ SeqType

Enumeration Type Documentation

◆ OidOptions

Enumerator
zeroIsError 
zeroAsStar 
zeroAsNone 

Definition at line 144 of file pg_dump.c.

145{
146 zeroIsError = 1,
147 zeroAsStar = 2,
148 zeroAsNone = 4,
149} OidOptions;

◆ SeqType

Enumerator
SEQTYPE_SMALLINT 
SEQTYPE_INTEGER 
SEQTYPE_BIGINT 

Definition at line 112 of file pg_dump.c.

Function Documentation

◆ addBoundaryDependencies()

static void addBoundaryDependencies ( DumpableObject **  dobjs,
int  numObjs,
DumpableObject boundaryObjs 
)
static

Definition at line 20390 of file pg_dump.c.

20392{
20395 int i;
20396
20397 for (i = 0; i < numObjs; i++)
20398 {
20399 DumpableObject *dobj = dobjs[i];
20400
20401 /*
20402 * The classification of object types here must match the SECTION_xxx
20403 * values assigned during subsequent ArchiveEntry calls!
20404 */
20405 switch (dobj->objType)
20406 {
20407 case DO_NAMESPACE:
20408 case DO_EXTENSION:
20409 case DO_TYPE:
20410 case DO_SHELL_TYPE:
20411 case DO_FUNC:
20412 case DO_AGG:
20413 case DO_OPERATOR:
20414 case DO_ACCESS_METHOD:
20415 case DO_OPCLASS:
20416 case DO_OPFAMILY:
20417 case DO_COLLATION:
20418 case DO_CONVERSION:
20419 case DO_TABLE:
20420 case DO_TABLE_ATTACH:
20421 case DO_ATTRDEF:
20422 case DO_PROCLANG:
20423 case DO_CAST:
20424 case DO_DUMMY_TYPE:
20425 case DO_TSPARSER:
20426 case DO_TSDICT:
20427 case DO_TSTEMPLATE:
20428 case DO_TSCONFIG:
20429 case DO_FDW:
20430 case DO_FOREIGN_SERVER:
20431 case DO_TRANSFORM:
20432 /* Pre-data objects: must come before the pre-data boundary */
20434 break;
20435 case DO_TABLE_DATA:
20436 case DO_SEQUENCE_SET:
20437 case DO_LARGE_OBJECT:
20439 /* Data objects: must come between the boundaries */
20440 addObjectDependency(dobj, preDataBound->dumpId);
20442 break;
20443 case DO_INDEX:
20444 case DO_INDEX_ATTACH:
20445 case DO_STATSEXT:
20446 case DO_REFRESH_MATVIEW:
20447 case DO_TRIGGER:
20448 case DO_EVENT_TRIGGER:
20449 case DO_DEFAULT_ACL:
20450 case DO_POLICY:
20451 case DO_PUBLICATION:
20452 case DO_PUBLICATION_REL:
20454 case DO_SUBSCRIPTION:
20456 /* Post-data objects: must come after the post-data boundary */
20457 addObjectDependency(dobj, postDataBound->dumpId);
20458 break;
20459 case DO_RULE:
20460 /* Rules are post-data, but only if dumped separately */
20461 if (((RuleInfo *) dobj)->separate)
20462 addObjectDependency(dobj, postDataBound->dumpId);
20463 break;
20464 case DO_CONSTRAINT:
20465 case DO_FK_CONSTRAINT:
20466 /* Constraints are post-data, but only if dumped separately */
20467 if (((ConstraintInfo *) dobj)->separate)
20468 addObjectDependency(dobj, postDataBound->dumpId);
20469 break;
20471 /* nothing to do */
20472 break;
20474 /* must come after the pre-data boundary */
20475 addObjectDependency(dobj, preDataBound->dumpId);
20476 break;
20477 case DO_REL_STATS:
20478 /* stats section varies by parent object type, DATA or POST */
20479 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
20480 {
20481 addObjectDependency(dobj, preDataBound->dumpId);
20482 addObjectDependency(postDataBound, dobj->dumpId);
20483 }
20484 else
20485 addObjectDependency(dobj, postDataBound->dumpId);
20486 break;
20487 }
20488 }
20489}

References addObjectDependency(), DO_ACCESS_METHOD, DO_AGG, DO_ATTRDEF, DO_CAST, DO_COLLATION, DO_CONSTRAINT, DO_CONVERSION, DO_DEFAULT_ACL, DO_DUMMY_TYPE, DO_EVENT_TRIGGER, DO_EXTENSION, DO_FDW, DO_FK_CONSTRAINT, DO_FOREIGN_SERVER, DO_FUNC, DO_INDEX, DO_INDEX_ATTACH, DO_LARGE_OBJECT, DO_LARGE_OBJECT_DATA, DO_NAMESPACE, DO_OPCLASS, DO_OPERATOR, DO_OPFAMILY, DO_POLICY, DO_POST_DATA_BOUNDARY, DO_PRE_DATA_BOUNDARY, DO_PROCLANG, DO_PUBLICATION, DO_PUBLICATION_REL, DO_PUBLICATION_TABLE_IN_SCHEMA, DO_REFRESH_MATVIEW, DO_REL_STATS, DO_RULE, DO_SEQUENCE_SET, DO_SHELL_TYPE, DO_STATSEXT, DO_SUBSCRIPTION, DO_SUBSCRIPTION_REL, DO_TABLE, DO_TABLE_ATTACH, DO_TABLE_DATA, DO_TRANSFORM, DO_TRIGGER, DO_TSCONFIG, DO_TSDICT, DO_TSPARSER, DO_TSTEMPLATE, DO_TYPE, _dumpableObject::dumpId, fb(), i, _dumpableObject::objType, and SECTION_DATA.

Referenced by main().

◆ addConstrChildIdxDeps()

static void addConstrChildIdxDeps ( DumpableObject dobj,
const IndxInfo refidx 
)
static

Definition at line 8409 of file pg_dump.c.

8410{
8411 SimplePtrListCell *cell;
8412
8414
8415 for (cell = refidx->partattaches.head; cell; cell = cell->next)
8416 {
8418
8419 addObjectDependency(dobj, attach->dobj.dumpId);
8420
8421 if (attach->partitionIdx->partattaches.head != NULL)
8422 addConstrChildIdxDeps(dobj, attach->partitionIdx);
8423 }
8424}

References addConstrChildIdxDeps(), addObjectDependency(), Assert, DO_FK_CONSTRAINT, _dumpableObject::dumpId, fb(), SimplePtrListCell::next, _dumpableObject::objType, and SimplePtrListCell::ptr.

Referenced by addConstrChildIdxDeps(), and getConstraints().

◆ append_depends_on_extension()

static void append_depends_on_extension ( Archive fout,
PQExpBuffer  create,
const DumpableObject dobj,
const char catalog,
const char keyword,
const char objname 
)
static

Definition at line 5682 of file pg_dump.c.

5688{
5689 if (dobj->depends_on_ext)
5690 {
5691 char *nm;
5692 PGresult *res;
5693 PQExpBuffer query;
5694 int ntups;
5695 int i_extname;
5696 int i;
5697
5698 /* dodge fmtId() non-reentrancy */
5699 nm = pg_strdup(objname);
5700
5701 query = createPQExpBuffer();
5702 appendPQExpBuffer(query,
5703 "SELECT e.extname "
5704 "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
5705 "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
5706 "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
5707 "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
5708 catalog,
5709 dobj->catId.oid);
5710 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5711 ntups = PQntuples(res);
5712 i_extname = PQfnumber(res, "extname");
5713 for (i = 0; i < ntups; i++)
5714 {
5715 appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
5716 keyword, nm,
5717 fmtId(PQgetvalue(res, i, i_extname)));
5718 }
5719
5720 PQclear(res);
5721 destroyPQExpBuffer(query);
5722 pg_free(nm);
5723 }
5724}

References appendPQExpBuffer(), _dumpableObject::catId, createPQExpBuffer(), PQExpBufferData::data, _dumpableObject::depends_on_ext, destroyPQExpBuffer(), ExecuteSqlQuery(), fb(), fmtId(), i, CatalogId::oid, pg_free(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, and PQntuples.

Referenced by dumpConstraint(), dumpFunc(), dumpIndex(), dumpTableSchema(), and dumpTrigger().

◆ appendNamedArgument()

static void appendNamedArgument ( PQExpBuffer  out,
Archive fout,
const char argname,
const char argtype,
const char argval 
)
static

Definition at line 10961 of file pg_dump.c.

10963{
10964 appendPQExpBufferStr(out, ",\n\t");
10965
10966 appendStringLiteralAH(out, argname, fout);
10967 appendPQExpBufferStr(out, ", ");
10968
10970 appendPQExpBuffer(out, "::%s", argtype);
10971}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, and fb().

Referenced by dumpRelationStats_dumper(), and dumpStatisticsExtStats().

◆ appendReloptionsArrayAH()

static void appendReloptionsArrayAH ( PQExpBuffer  buffer,
const char reloptions,
const char prefix,
Archive fout 
)
static

Definition at line 20715 of file pg_dump.c.

20717{
20718 bool res;
20719
20720 res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
20721 fout->std_strings);
20722 if (!res)
20723 pg_log_warning("could not parse %s array", "reloptions");
20724}

References appendReloptionsArray(), fb(), and pg_log_warning.

Referenced by dumpConstraint(), dumpRule(), and dumpTableSchema().

◆ binary_upgrade_extension_member()

static void binary_upgrade_extension_member ( PQExpBuffer  upgrade_buffer,
const DumpableObject dobj,
const char objtype,
const char objname,
const char objnamespace 
)
static

Definition at line 5993 of file pg_dump.c.

5998{
6000 int i;
6001
6002 if (!dobj->ext_member)
6003 return;
6004
6005 /*
6006 * Find the parent extension. We could avoid this search if we wanted to
6007 * add a link field to DumpableObject, but the space costs of that would
6008 * be considerable. We assume that member objects could only have a
6009 * direct dependency on their own extension, not any others.
6010 */
6011 for (i = 0; i < dobj->nDeps; i++)
6012 {
6014 if (extobj && extobj->objType == DO_EXTENSION)
6015 break;
6016 extobj = NULL;
6017 }
6018 if (extobj == NULL)
6019 pg_fatal("could not find parent extension for %s %s",
6020 objtype, objname);
6021
6023 "\n-- For binary upgrade, handle extension membership the hard way\n");
6024 appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
6025 fmtId(extobj->name),
6026 objtype);
6027 if (objnamespace && *objnamespace)
6029 appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
6030}

References appendPQExpBuffer(), appendPQExpBufferStr(), _dumpableObject::dependencies, DO_EXTENSION, _dumpableObject::ext_member, fb(), findObjectByDumpId(), fmtId(), i, _dumpableObject::nDeps, and pg_fatal.

Referenced by dumpAccessMethod(), dumpAgg(), dumpBaseType(), dumpCast(), dumpCollation(), dumpCompositeType(), dumpConversion(), dumpDomain(), dumpEnumType(), dumpEventTrigger(), dumpForeignDataWrapper(), dumpForeignServer(), dumpFunc(), dumpNamespace(), dumpOpclass(), dumpOpfamily(), dumpOpr(), dumpProcLang(), dumpRangeType(), dumpSequence(), dumpTableSchema(), dumpTransform(), dumpTSConfig(), dumpTSDictionary(), dumpTSParser(), dumpTSTemplate(), and dumpUndefinedType().

◆ binary_upgrade_set_pg_class_oids()

static void binary_upgrade_set_pg_class_oids ( Archive fout,
PQExpBuffer  upgrade_buffer,
Oid  pg_class_oid 
)
static

Definition at line 5903 of file pg_dump.c.

5905{
5908
5910
5911 /*
5912 * Preserve the OID and relfilenumber of the table, table's index, table's
5913 * toast table and toast table's index if any.
5914 *
5915 * One complexity is that the current table definition might not require
5916 * the creation of a TOAST table, but the old database might have a TOAST
5917 * table that was created earlier, before some wide columns were dropped.
5918 * By setting the TOAST oid we force creation of the TOAST heap and index
5919 * by the new backend, so we can copy the files during binary upgrade
5920 * without worrying about this case.
5921 */
5922 key.oid = pg_class_oid;
5926
5928 "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
5929
5930 if (entry->relkind != RELKIND_INDEX &&
5932 {
5934 "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
5935 pg_class_oid);
5936
5937 /*
5938 * Not every relation has storage. Also, in a pre-v12 database,
5939 * partitioned tables have a relfilenumber, which should not be
5940 * preserved when upgrading.
5941 */
5942 if (RelFileNumberIsValid(entry->relfilenumber) &&
5945 "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
5946 entry->relfilenumber);
5947
5948 /*
5949 * In a pre-v12 database, partitioned tables might be marked as having
5950 * toast tables, but we should ignore them if so.
5951 */
5952 if (OidIsValid(entry->toast_oid) &&
5954 {
5956 "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
5957 entry->toast_oid);
5959 "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
5960 entry->toast_relfilenumber);
5961
5962 /* every toast table has an index */
5964 "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5965 entry->toast_index_oid);
5967 "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5969 }
5970 }
5971 else
5972 {
5973 /* Preserve the OID and relfilenumber of the index */
5975 "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5976 pg_class_oid);
5978 "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5979 entry->relfilenumber);
5980 }
5981
5983}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), Assert, BinaryUpgradeClassOidItemCmp(), binaryUpgradeClassOids, fb(), nbinaryUpgradeClassOids, OidIsValid, BinaryUpgradeClassOidItem::relfilenumber, RelFileNumberIsValid, BinaryUpgradeClassOidItem::relkind, BinaryUpgradeClassOidItem::toast_index_oid, BinaryUpgradeClassOidItem::toast_index_relfilenumber, BinaryUpgradeClassOidItem::toast_oid, and BinaryUpgradeClassOidItem::toast_relfilenumber.

Referenced by dumpCompositeType(), dumpConstraint(), dumpIndex(), dumpSequence(), and dumpTableSchema().

◆ binary_upgrade_set_type_oids_by_rel()

static void binary_upgrade_set_type_oids_by_rel ( Archive fout,
PQExpBuffer  upgrade_buffer,
const TableInfo tbinfo 
)
static

Definition at line 5838 of file pg_dump.c.

5841{
5842 Oid pg_type_oid = tbinfo->reltype;
5843
5846 pg_type_oid, false, false);
5847}

References binary_upgrade_set_type_oids_by_type_oid(), fb(), and OidIsValid.

Referenced by dumpTableSchema().

◆ binary_upgrade_set_type_oids_by_type_oid()

static void binary_upgrade_set_type_oids_by_type_oid ( Archive fout,
PQExpBuffer  upgrade_buffer,
Oid  pg_type_oid,
bool  force_array_type,
bool  include_multirange_type 
)
static

Definition at line 5758 of file pg_dump.c.

5763{
5765 PGresult *res;
5769 TypeInfo *tinfo;
5770
5771 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
5773 "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5774 pg_type_oid);
5775
5777 if (tinfo)
5778 pg_type_array_oid = tinfo->typarray;
5779 else
5781
5784
5786 {
5788 "\n-- For binary upgrade, must preserve pg_type array oid\n");
5790 "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5792 }
5793
5794 /*
5795 * Pre-set the multirange type oid and its own array type oid.
5796 */
5798 {
5799 if (fout->remoteVersion >= 140000)
5800 {
5802 "SELECT t.oid, t.typarray "
5803 "FROM pg_catalog.pg_type t "
5804 "JOIN pg_catalog.pg_range r "
5805 "ON t.oid = r.rngmultitypid "
5806 "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
5807 pg_type_oid);
5808
5810
5811 pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
5812 pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
5813
5814 PQclear(res);
5815 }
5816 else
5817 {
5820 }
5821
5823 "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
5825 "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5828 "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
5830 "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5832 }
5833
5835}

References appendPQExpBuffer(), appendPQExpBufferStr(), atooid, createPQExpBuffer(), destroyPQExpBuffer(), ExecuteSqlQueryForSingleRow(), fb(), findTypeByOid(), get_next_possible_free_pg_type_oid(), InvalidOid, OidIsValid, PQclear, PQfnumber(), PQgetvalue, printfPQExpBuffer(), and tinfo.

Referenced by binary_upgrade_set_type_oids_by_rel(), dumpBaseType(), dumpCompositeType(), dumpDomain(), dumpEnumType(), dumpRangeType(), dumpShellType(), and dumpUndefinedType().

◆ BinaryUpgradeClassOidItemCmp()

static int BinaryUpgradeClassOidItemCmp ( const void p1,
const void p2 
)
static

Definition at line 5853 of file pg_dump.c.

5854{
5857
5858 return pg_cmp_u32(v1.oid, v2.oid);
5859}

References fb(), BinaryUpgradeClassOidItem::oid, and pg_cmp_u32().

Referenced by binary_upgrade_set_pg_class_oids().

◆ BuildArchiveDependencies()

static void BuildArchiveDependencies ( Archive fout)
static

Definition at line 20516 of file pg_dump.c.

20517{
20519 TocEntry *te;
20520
20521 /* Scan all TOC entries in the archive */
20522 for (te = AH->toc->next; te != AH->toc; te = te->next)
20523 {
20524 DumpableObject *dobj;
20525 DumpId *dependencies;
20526 int nDeps;
20527 int allocDeps;
20528
20529 /* No need to process entries that will not be dumped */
20530 if (te->reqs == 0)
20531 continue;
20532 /* Ignore entries that already have "special" dependencies */
20533 if (te->nDeps > 0)
20534 continue;
20535 /* Otherwise, look up the item's original DumpableObject, if any */
20536 dobj = findObjectByDumpId(te->dumpId);
20537 if (dobj == NULL)
20538 continue;
20539 /* No work if it has no dependencies */
20540 if (dobj->nDeps <= 0)
20541 continue;
20542 /* Set up work array */
20543 allocDeps = 64;
20544 dependencies = pg_malloc_array(DumpId, allocDeps);
20545 nDeps = 0;
20546 /* Recursively find all dumpable dependencies */
20547 findDumpableDependencies(AH, dobj,
20548 &dependencies, &nDeps, &allocDeps);
20549 /* And save 'em ... */
20550 if (nDeps > 0)
20551 {
20552 dependencies = pg_realloc_array(dependencies, DumpId, nDeps);
20553 te->dependencies = dependencies;
20554 te->nDeps = nDeps;
20555 }
20556 else
20557 pg_free(dependencies);
20558 }
20559}

References _tocEntry::dependencies, _tocEntry::dumpId, fb(), findDumpableDependencies(), findObjectByDumpId(), _tocEntry::nDeps, _dumpableObject::nDeps, _tocEntry::next, pg_free(), pg_malloc_array, pg_realloc_array, _tocEntry::reqs, and _archiveHandle::toc.

Referenced by main().

◆ buildMatViewRefreshDependencies()

static void buildMatViewRefreshDependencies ( Archive fout)
static

Definition at line 3090 of file pg_dump.c.

3091{
3092 PQExpBuffer query;
3093 PGresult *res;
3094 int ntups,
3095 i;
3096 int i_classid,
3097 i_objid,
3098 i_refobjid;
3099
3100 query = createPQExpBuffer();
3101
3102 appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
3103 "( "
3104 "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
3105 "FROM pg_depend d1 "
3106 "JOIN pg_class c1 ON c1.oid = d1.objid "
3107 "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
3108 " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
3109 "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
3110 "AND d2.objid = r1.oid "
3111 "AND d2.refobjid <> d1.objid "
3112 "JOIN pg_class c2 ON c2.oid = d2.refobjid "
3113 "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
3115 "WHERE d1.classid = 'pg_class'::regclass "
3116 "UNION "
3117 "SELECT w.objid, d3.refobjid, c3.relkind "
3118 "FROM w "
3119 "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
3120 "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
3121 "AND d3.objid = r3.oid "
3122 "AND d3.refobjid <> w.refobjid "
3123 "JOIN pg_class c3 ON c3.oid = d3.refobjid "
3124 "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
3126 ") "
3127 "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
3128 "FROM w "
3129 "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
3130
3131 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3132
3133 ntups = PQntuples(res);
3134
3135 i_classid = PQfnumber(res, "classid");
3136 i_objid = PQfnumber(res, "objid");
3137 i_refobjid = PQfnumber(res, "refobjid");
3138
3139 for (i = 0; i < ntups; i++)
3140 {
3141 CatalogId objId;
3143 DumpableObject *dobj;
3147
3148 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
3149 objId.oid = atooid(PQgetvalue(res, i, i_objid));
3150 refobjId.tableoid = objId.tableoid;
3151 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
3152
3153 dobj = findObjectByCatalogId(objId);
3154 if (dobj == NULL)
3155 continue;
3156
3157 Assert(dobj->objType == DO_TABLE);
3158 tbinfo = (TableInfo *) dobj;
3159 Assert(tbinfo->relkind == RELKIND_MATVIEW);
3160 dobj = (DumpableObject *) tbinfo->dataObj;
3161 if (dobj == NULL)
3162 continue;
3164
3166 if (refdobj == NULL)
3167 continue;
3168
3169 Assert(refdobj->objType == DO_TABLE);
3171 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
3172 refdobj = (DumpableObject *) reftbinfo->dataObj;
3173 if (refdobj == NULL)
3174 continue;
3175 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
3176
3177 addObjectDependency(dobj, refdobj->dumpId);
3178
3179 if (!reftbinfo->relispopulated)
3180 tbinfo->relispopulated = false;
3181 }
3182
3183 PQclear(res);
3184
3185 destroyPQExpBuffer(query);
3186}

References addObjectDependency(), appendPQExpBufferStr(), Assert, atooid, CppAsString2, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_REFRESH_MATVIEW, DO_TABLE, _dumpableObject::dumpId, ExecuteSqlQuery(), fb(), findObjectByCatalogId(), i, _dumpableObject::objType, CatalogId::oid, PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and CatalogId::tableoid.

Referenced by main().

◆ checkExtensionMembership()

static bool checkExtensionMembership ( DumpableObject dobj,
Archive fout 
)
static

Definition at line 1923 of file pg_dump.c.

1924{
1926
1927 if (ext == NULL)
1928 return false;
1929
1930 dobj->ext_member = true;
1931
1932 /* Record dependency so that getDependencies needn't deal with that */
1933 addObjectDependency(dobj, ext->dobj.dumpId);
1934
1935 /*
1936 * Mark the member object to have any non-initial ACLs dumped. (Any
1937 * initial ACLs will be removed later, using data from pg_init_privs, so
1938 * that we'll dump only the delta from the extension's initial setup.)
1939 *
1940 * In binary upgrades, we still dump all components of the members
1941 * individually, since the idea is to exactly reproduce the database
1942 * contents rather than replace the extension contents with something
1943 * different.
1944 *
1945 * Note: it might be interesting someday to implement storage and delta
1946 * dumping of extension members' RLS policies and/or security labels.
1947 * However there is a pitfall for RLS policies: trying to dump them
1948 * requires getting a lock on their tables, and the calling user might not
1949 * have privileges for that. We need no lock to examine a table's ACLs,
1950 * so the current feature doesn't have a problem of that sort.
1951 */
1952 if (fout->dopt->binary_upgrade)
1953 dobj->dump = ext->dobj.dump;
1954 else
1955 dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
1956
1957 return true;
1958}

References addObjectDependency(), _dumpableObject::catId, _extensionInfo::dobj, _dumpableObject::dump, DUMP_COMPONENT_ACL, _dumpableObject::dump_contains, _dumpableObject::dumpId, _dumpableObject::ext_member, fb(), and findOwningExtension().

Referenced by selectDumpableAccessMethod(), selectDumpableCast(), selectDumpableNamespace(), selectDumpableObject(), selectDumpableProcLang(), selectDumpablePublicationObject(), selectDumpableStatisticsObject(), selectDumpableTable(), and selectDumpableType().

◆ collectBinaryUpgradeClassOids()

static void collectBinaryUpgradeClassOids ( Archive fout)
static

Definition at line 5869 of file pg_dump.c.

5870{
5871 PGresult *res;
5872 const char *query;
5873
5874 query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
5875 "ct.relfilenode, i.indexrelid, cti.relfilenode "
5876 "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
5877 "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
5878 "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
5879 "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
5880 "ORDER BY c.oid;";
5881
5882 res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
5883
5887
5888 for (int i = 0; i < nbinaryUpgradeClassOids; i++)
5889 {
5897 }
5898
5899 PQclear(res);
5900}

References atooid, binaryUpgradeClassOids, ExecuteSqlQuery(), fb(), i, nbinaryUpgradeClassOids, BinaryUpgradeClassOidItem::oid, pg_malloc_array, PGRES_TUPLES_OK, PQclear, PQgetvalue, PQntuples, BinaryUpgradeClassOidItem::relfilenumber, BinaryUpgradeClassOidItem::relkind, BinaryUpgradeClassOidItem::toast_index_oid, BinaryUpgradeClassOidItem::toast_index_relfilenumber, BinaryUpgradeClassOidItem::toast_oid, and BinaryUpgradeClassOidItem::toast_relfilenumber.

Referenced by main().

◆ collectComments()

static void collectComments ( Archive fout)
static

Definition at line 11561 of file pg_dump.c.

11562{
11563 PGresult *res;
11564 PQExpBuffer query;
11565 int i_description;
11566 int i_classoid;
11567 int i_objoid;
11568 int i_objsubid;
11569 int ntups;
11570 int i;
11571 DumpableObject *dobj;
11572
11573 query = createPQExpBuffer();
11574
11575 appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
11576 "FROM pg_catalog.pg_description "
11577 "ORDER BY classoid, objoid, objsubid");
11578
11579 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11580
11581 /* Construct lookup table containing OIDs in numeric form */
11582
11583 i_description = PQfnumber(res, "description");
11584 i_classoid = PQfnumber(res, "classoid");
11585 i_objoid = PQfnumber(res, "objoid");
11586 i_objsubid = PQfnumber(res, "objsubid");
11587
11588 ntups = PQntuples(res);
11589
11591 ncomments = 0;
11592 dobj = NULL;
11593
11594 for (i = 0; i < ntups; i++)
11595 {
11596 CatalogId objId;
11597 int subid;
11598
11599 objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
11600 objId.oid = atooid(PQgetvalue(res, i, i_objoid));
11601 subid = atoi(PQgetvalue(res, i, i_objsubid));
11602
11603 /* We needn't remember comments that don't match any dumpable object */
11604 if (dobj == NULL ||
11605 dobj->catId.tableoid != objId.tableoid ||
11606 dobj->catId.oid != objId.oid)
11607 dobj = findObjectByCatalogId(objId);
11608 if (dobj == NULL)
11609 continue;
11610
11611 /*
11612 * Comments on columns of composite types are linked to the type's
11613 * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
11614 * in the type's own DumpableObject.
11615 */
11616 if (subid != 0 && dobj->objType == DO_TABLE &&
11617 ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
11618 {
11620
11621 cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
11622 if (cTypeInfo)
11623 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
11624 }
11625 else
11626 dobj->components |= DUMP_COMPONENT_COMMENT;
11627
11630 comments[ncomments].objoid = objId.oid;
11631 comments[ncomments].objsubid = subid;
11632 ncomments++;
11633 }
11634
11635 PQclear(res);
11636 destroyPQExpBuffer(query);
11637}

References appendPQExpBufferStr(), atooid, _dumpableObject::catId, CommentItem::classoid, comments, createPQExpBuffer(), PQExpBufferData::data, CommentItem::descr, destroyPQExpBuffer(), DO_TABLE, DUMP_COMPONENT_COMMENT, ExecuteSqlQuery(), fb(), findObjectByCatalogId(), findTypeByOid(), i, ncomments, CommentItem::objoid, CommentItem::objsubid, _dumpableObject::objType, CatalogId::oid, pg_malloc_array, pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and CatalogId::tableoid.

Referenced by main().

◆ collectRoleNames()

static void collectRoleNames ( Archive fout)
static

Definition at line 10684 of file pg_dump.c.

10685{
10686 PGresult *res;
10687 const char *query;
10688 int i;
10689
10690 query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
10691
10692 res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
10693
10694 nrolenames = PQntuples(res);
10695
10697
10698 for (i = 0; i < nrolenames; i++)
10699 {
10700 rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
10702 }
10703
10704 PQclear(res);
10705}

References atooid, ExecuteSqlQuery(), fb(), i, nrolenames, pg_malloc_array, pg_strdup(), PGRES_TUPLES_OK, PQclear, PQgetvalue, PQntuples, RoleNameItem::rolename, rolenames, and RoleNameItem::roleoid.

Referenced by main().

◆ collectSecLabels()

static void collectSecLabels ( Archive fout)
static

Definition at line 16733 of file pg_dump.c.

16734{
16735 PGresult *res;
16736 PQExpBuffer query;
16737 int i_label;
16738 int i_provider;
16739 int i_classoid;
16740 int i_objoid;
16741 int i_objsubid;
16742 int ntups;
16743 int i;
16744 DumpableObject *dobj;
16745
16746 query = createPQExpBuffer();
16747
16749 "SELECT label, provider, classoid, objoid, objsubid "
16750 "FROM pg_catalog.pg_seclabels "
16751 "ORDER BY classoid, objoid, objsubid");
16752
16753 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16754
16755 /* Construct lookup table containing OIDs in numeric form */
16756 i_label = PQfnumber(res, "label");
16757 i_provider = PQfnumber(res, "provider");
16758 i_classoid = PQfnumber(res, "classoid");
16759 i_objoid = PQfnumber(res, "objoid");
16760 i_objsubid = PQfnumber(res, "objsubid");
16761
16762 ntups = PQntuples(res);
16763
16765 nseclabels = 0;
16766 dobj = NULL;
16767
16768 for (i = 0; i < ntups; i++)
16769 {
16770 CatalogId objId;
16771 int subid;
16772
16773 objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
16774 objId.oid = atooid(PQgetvalue(res, i, i_objoid));
16775 subid = atoi(PQgetvalue(res, i, i_objsubid));
16776
16777 /* We needn't remember labels that don't match any dumpable object */
16778 if (dobj == NULL ||
16779 dobj->catId.tableoid != objId.tableoid ||
16780 dobj->catId.oid != objId.oid)
16781 dobj = findObjectByCatalogId(objId);
16782 if (dobj == NULL)
16783 continue;
16784
16785 /*
16786 * Labels on columns of composite types are linked to the type's
16787 * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
16788 * in the type's own DumpableObject.
16789 */
16790 if (subid != 0 && dobj->objType == DO_TABLE &&
16791 ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
16792 {
16794
16795 cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
16796 if (cTypeInfo)
16797 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
16798 }
16799 else
16800 dobj->components |= DUMP_COMPONENT_SECLABEL;
16801
16805 seclabels[nseclabels].objoid = objId.oid;
16806 seclabels[nseclabels].objsubid = subid;
16807 nseclabels++;
16808 }
16809
16810 PQclear(res);
16811 destroyPQExpBuffer(query);
16812}

References appendPQExpBufferStr(), atooid, _dumpableObject::catId, SecLabelItem::classoid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_TABLE, DUMP_COMPONENT_SECLABEL, ExecuteSqlQuery(), fb(), findObjectByCatalogId(), findTypeByOid(), i, SecLabelItem::label, nseclabels, SecLabelItem::objoid, SecLabelItem::objsubid, _dumpableObject::objType, CatalogId::oid, pg_malloc_array, pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, SecLabelItem::provider, seclabels, and CatalogId::tableoid.

Referenced by main().

◆ collectSequences()

static void collectSequences ( Archive fout)
static

Definition at line 19188 of file pg_dump.c.

19189{
19190 PGresult *res;
19191 const char *query;
19192
19193 /*
19194 * Since version 18, we can gather the sequence data in this query with
19195 * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
19196 */
19197 if (fout->remoteVersion < 180000 ||
19198 (!fout->dopt->dumpData && !fout->dopt->sequence_data))
19199 query = "SELECT seqrelid, format_type(seqtypid, NULL), "
19200 "seqstart, seqincrement, "
19201 "seqmax, seqmin, "
19202 "seqcache, seqcycle, "
19203 "NULL, 'f' "
19204 "FROM pg_catalog.pg_sequence "
19205 "ORDER BY seqrelid";
19206 else
19207 query = "SELECT seqrelid, format_type(seqtypid, NULL), "
19208 "seqstart, seqincrement, "
19209 "seqmax, seqmin, "
19210 "seqcache, seqcycle, "
19211 "last_value, is_called "
19212 "FROM pg_catalog.pg_sequence, "
19213 "pg_get_sequence_data(seqrelid) "
19214 "ORDER BY seqrelid;";
19215
19216 res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
19217
19218 nsequences = PQntuples(res);
19220
19221 for (int i = 0; i < nsequences; i++)
19222 {
19223 sequences[i].oid = atooid(PQgetvalue(res, i, 0));
19225 sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
19226 sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
19227 sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
19228 sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
19229 sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
19230 sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
19231 sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
19232 sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
19233 sequences[i].null_seqtuple = (PQgetisnull(res, i, 8) || PQgetisnull(res, i, 9));
19234 }
19235
19236 PQclear(res);
19237}

References atooid, SequenceItem::cache, SequenceItem::cycled, ExecuteSqlQuery(), fb(), i, SequenceItem::incby, SequenceItem::is_called, SequenceItem::last_value, SequenceItem::maxv, SequenceItem::minv, nsequences, SequenceItem::null_seqtuple, SequenceItem::oid, parse_sequence_type(), pg_malloc_array, PGRES_TUPLES_OK, PQclear, PQgetisnull, PQgetvalue, PQntuples, SequenceItem::seqtype, sequences, and SequenceItem::startv.

Referenced by main().

◆ convertRegProcReference()

static char * convertRegProcReference ( const char proc)
static

Definition at line 14302 of file pg_dump.c.

14303{
14304 char *name;
14305 char *paren;
14306 bool inquote;
14307
14308 /* In all cases "-" means a null reference */
14309 if (strcmp(proc, "-") == 0)
14310 return NULL;
14311
14312 name = pg_strdup(proc);
14313 /* find non-double-quoted left paren */
14314 inquote = false;
14315 for (paren = name; *paren; paren++)
14316 {
14317 if (*paren == '(' && !inquote)
14318 {
14319 *paren = '\0';
14320 break;
14321 }
14322 if (*paren == '"')
14323 inquote = !inquote;
14324 }
14325 return name;
14326}

References fb(), name, and pg_strdup().

Referenced by dumpOpr().

◆ convertTSFunction()

static char * convertTSFunction ( Archive fout,
Oid  funcOid 
)
static

Definition at line 14373 of file pg_dump.c.

14374{
14375 char *result;
14376 char query[128];
14377 PGresult *res;
14378
14379 snprintf(query, sizeof(query),
14380 "SELECT '%u'::pg_catalog.regproc", funcOid);
14381 res = ExecuteSqlQueryForSingleRow(fout, query);
14382
14383 result = pg_strdup(PQgetvalue(res, 0, 0));
14384
14385 PQclear(res);
14386
14387 return result;
14388}

References ExecuteSqlQueryForSingleRow(), fb(), pg_strdup(), PQclear, PQgetvalue, result, and snprintf.

Referenced by dumpTSParser(), and dumpTSTemplate().

◆ createBoundaryObjects()

static DumpableObject * createBoundaryObjects ( void  )
static

Definition at line 20366 of file pg_dump.c.

20367{
20369
20371
20372 dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
20373 dobjs[0].catId = nilCatalogId;
20374 AssignDumpId(dobjs + 0);
20375 dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
20376
20377 dobjs[1].objType = DO_POST_DATA_BOUNDARY;
20378 dobjs[1].catId = nilCatalogId;
20379 AssignDumpId(dobjs + 1);
20380 dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
20381
20382 return dobjs;
20383}

References AssignDumpId(), DO_POST_DATA_BOUNDARY, DO_PRE_DATA_BOUNDARY, fb(), nilCatalogId, pg_malloc_array, and pg_strdup().

Referenced by main().

◆ createDummyViewAsClause()

static PQExpBuffer createDummyViewAsClause ( Archive fout,
const TableInfo tbinfo 
)
static

Definition at line 17007 of file pg_dump.c.

17008{
17010 int j;
17011
17012 appendPQExpBufferStr(result, "SELECT");
17013
17014 for (j = 0; j < tbinfo->numatts; j++)
17015 {
17016 if (j > 0)
17019
17020 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
17021
17022 /*
17023 * Must add collation if not default for the type, because CREATE OR
17024 * REPLACE VIEW won't change it
17025 */
17026 if (OidIsValid(tbinfo->attcollation[j]))
17027 {
17028 CollInfo *coll;
17029
17030 coll = findCollationByOid(tbinfo->attcollation[j]);
17031 if (coll)
17032 appendPQExpBuffer(result, " COLLATE %s",
17033 fmtQualifiedDumpable(coll));
17034 }
17035
17036 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
17037 }
17038
17039 return result;
17040}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), createPQExpBuffer(), fb(), findCollationByOid(), fmtId(), fmtQualifiedDumpable, j, OidIsValid, and result.

Referenced by dumpRule(), and dumpTableSchema().

◆ createViewAsClause()

static PQExpBuffer createViewAsClause ( Archive fout,
const TableInfo tbinfo 
)
static

Definition at line 16958 of file pg_dump.c.

16959{
16962 PGresult *res;
16963 int len;
16964
16965 /* Fetch the view definition */
16966 appendPQExpBuffer(query,
16967 "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
16968 tbinfo->dobj.catId.oid);
16969
16970 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16971
16972 if (PQntuples(res) != 1)
16973 {
16974 if (PQntuples(res) < 1)
16975 pg_fatal("query to obtain definition of view \"%s\" returned no data",
16976 tbinfo->dobj.name);
16977 else
16978 pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
16979 tbinfo->dobj.name);
16980 }
16981
16982 len = PQgetlength(res, 0, 0);
16983
16984 if (len == 0)
16985 pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
16986 tbinfo->dobj.name);
16987
16988 /* Strip off the trailing semicolon so that other things may follow. */
16989 Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
16990 appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
16991
16992 PQclear(res);
16993 destroyPQExpBuffer(query);
16994
16995 return result;
16996}

References appendBinaryPQExpBuffer(), appendPQExpBuffer(), Assert, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), ExecuteSqlQuery(), fb(), len, pg_fatal, PGRES_TUPLES_OK, PQclear, PQgetlength, PQgetvalue, PQntuples, and result.

Referenced by dumpRule(), and dumpTableSchema().

◆ determineNotNullFlags()

static void determineNotNullFlags ( Archive fout,
PGresult res,
int  r,
TableInfo tbinfo,
int  j,
int  i_notnull_name,
int  i_notnull_comment,
int  i_notnull_invalidoid,
int  i_notnull_noinherit,
int  i_notnull_islocal,
PQExpBuffer invalidnotnulloids 
)
static

Definition at line 9969 of file pg_dump.c.

9977{
9978 DumpOptions *dopt = fout->dopt;
9979
9980 /*
9981 * If this not-null constraint is not valid, list its OID in
9982 * invalidnotnulloids and do nothing further. It'll be processed
9983 * elsewhere later.
9984 *
9985 * Because invalid not-null constraints are rare, we don't want to malloc
9986 * invalidnotnulloids until we're sure we're going it need it, which
9987 * happens here.
9988 */
9989 if (!PQgetisnull(res, r, i_notnull_invalidoid))
9990 {
9991 char *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
9992
9993 if (*invalidnotnulloids == NULL)
9994 {
9998 }
9999 else
10001
10002 /*
10003 * Track when a parent constraint is invalid for the cases where a
10004 * child constraint has been validated independenly.
10005 */
10006 tbinfo->notnull_invalid[j] = true;
10007
10008 /* nothing else to do */
10009 tbinfo->notnull_constrs[j] = NULL;
10010 return;
10011 }
10012
10013 /*
10014 * notnull_noinh is straight from the query result. notnull_islocal also,
10015 * though flagInhAttrs may change that one later.
10016 */
10017 tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
10018 tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
10019 tbinfo->notnull_invalid[j] = false;
10020
10021 /*
10022 * Determine a constraint name to use. If the column is not marked not-
10023 * null, we set NULL which cues ... to do nothing. An empty string says
10024 * to print an unnamed NOT NULL, and anything else is a constraint name to
10025 * use.
10026 */
10027 if (fout->remoteVersion < 180000)
10028 {
10029 /*
10030 * < 18 doesn't have not-null names, so an unnamed constraint is
10031 * sufficient.
10032 */
10033 if (PQgetisnull(res, r, i_notnull_name))
10034 tbinfo->notnull_constrs[j] = NULL;
10035 else
10036 tbinfo->notnull_constrs[j] = "";
10037 }
10038 else
10039 {
10040 if (PQgetisnull(res, r, i_notnull_name))
10041 tbinfo->notnull_constrs[j] = NULL;
10042 else
10043 {
10044 /*
10045 * In binary upgrade of inheritance child tables, must have a
10046 * constraint name that we can UPDATE later; same if there's a
10047 * comment on the constraint.
10048 */
10049 if ((dopt->binary_upgrade &&
10050 !tbinfo->ispartition &&
10051 !tbinfo->notnull_islocal[j]) ||
10053 {
10054 tbinfo->notnull_constrs[j] =
10056 }
10057 else
10058 {
10059 char *default_name;
10060
10061 /* XXX should match ChooseConstraintName better */
10062 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
10063 tbinfo->attnames[j]);
10064 if (strcmp(default_name,
10065 PQgetvalue(res, r, i_notnull_name)) == 0)
10066 tbinfo->notnull_constrs[j] = "";
10067 else
10068 {
10069 tbinfo->notnull_constrs[j] =
10071 }
10073 }
10074 }
10075 }
10076}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), _dumpOptions::binary_upgrade, createPQExpBuffer(), fb(), j, pfree(), PQgetisnull, PQgetvalue, psprintf(), and pstrdup().

Referenced by getTableAttrs().

◆ dumpAccessMethod()

static void dumpAccessMethod ( Archive fout,
const AccessMethodInfo aminfo 
)
static

Definition at line 14395 of file pg_dump.c.

14396{
14397 DumpOptions *dopt = fout->dopt;
14398 PQExpBuffer q;
14400 char *qamname;
14401
14402 /* Do nothing if not dumping schema */
14403 if (!dopt->dumpSchema)
14404 return;
14405
14406 q = createPQExpBuffer();
14408
14409 qamname = pg_strdup(fmtId(aminfo->dobj.name));
14410
14411 appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
14412
14413 switch (aminfo->amtype)
14414 {
14415 case AMTYPE_INDEX:
14416 appendPQExpBufferStr(q, "TYPE INDEX ");
14417 break;
14418 case AMTYPE_TABLE:
14419 appendPQExpBufferStr(q, "TYPE TABLE ");
14420 break;
14421 default:
14422 pg_log_warning("invalid type \"%c\" of access method \"%s\"",
14423 aminfo->amtype, qamname);
14427 return;
14428 }
14429
14430 appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
14431
14432 appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
14433 qamname);
14434
14435 if (dopt->binary_upgrade)
14437 "ACCESS METHOD", qamname, NULL);
14438
14439 if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14440 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
14441 ARCHIVE_OPTS(.tag = aminfo->dobj.name,
14442 .description = "ACCESS METHOD",
14443 .section = SECTION_PRE_DATA,
14444 .createStmt = q->data,
14445 .dropStmt = delq->data));
14446
14447 /* Dump Access Method Comments */
14448 if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14449 dumpComment(fout, "ACCESS METHOD", qamname,
14450 NULL, "",
14451 aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
14452
14456}

References appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, fb(), fmtId(), pg_free(), pg_log_warning, pg_strdup(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpACL()

static DumpId dumpACL ( Archive fout,
DumpId  objDumpId,
DumpId  altDumpId,
const char type,
const char name,
const char subname,
const char nspname,
const char tag,
const char owner,
const DumpableAcl dacl 
)
static

Definition at line 16364 of file pg_dump.c.

16368{
16370 DumpOptions *dopt = fout->dopt;
16371 const char *acls = dacl->acl;
16372 const char *acldefault = dacl->acldefault;
16373 char privtype = dacl->privtype;
16374 const char *initprivs = dacl->initprivs;
16375 const char *baseacls;
16376 PQExpBuffer sql;
16377
16378 /* Do nothing if ACL dump is not enabled */
16379 if (dopt->aclsSkip)
16380 return InvalidDumpId;
16381
16382 /* --data-only skips ACLs *except* large object ACLs */
16383 if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
16384 return InvalidDumpId;
16385
16386 sql = createPQExpBuffer();
16387
16388 /*
16389 * In binary upgrade mode, we don't run an extension's script but instead
16390 * dump out the objects independently and then recreate them. To preserve
16391 * any initial privileges which were set on extension objects, we need to
16392 * compute the set of GRANT and REVOKE commands necessary to get from the
16393 * default privileges of an object to its initial privileges as recorded
16394 * in pg_init_privs.
16395 *
16396 * At restore time, we apply these commands after having called
16397 * binary_upgrade_set_record_init_privs(true). That tells the backend to
16398 * copy the results into pg_init_privs. This is how we preserve the
16399 * contents of that catalog across binary upgrades.
16400 */
16401 if (dopt->binary_upgrade && privtype == 'e' &&
16402 initprivs && *initprivs != '\0')
16403 {
16404 appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
16405 if (!buildACLCommands(name, subname, nspname, type,
16406 initprivs, acldefault, owner,
16407 "", fout->remoteVersion, sql))
16408 pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
16409 initprivs, acldefault, name, type);
16410 appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
16411 }
16412
16413 /*
16414 * Now figure the GRANT and REVOKE commands needed to get to the object's
16415 * actual current ACL, starting from the initprivs if given, else from the
16416 * object-type-specific default. Also, while buildACLCommands will assume
16417 * that a NULL/empty acls string means it needn't do anything, what that
16418 * actually represents is the object-type-specific default; so we need to
16419 * substitute the acldefault string to get the right results in that case.
16420 */
16421 if (initprivs && *initprivs != '\0')
16422 {
16423 baseacls = initprivs;
16424 if (acls == NULL || *acls == '\0')
16425 acls = acldefault;
16426 }
16427 else
16429
16430 if (!buildACLCommands(name, subname, nspname, type,
16431 acls, baseacls, owner,
16432 "", fout->remoteVersion, sql))
16433 pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
16434 acls, baseacls, name, type);
16435
16436 if (sql->len > 0)
16437 {
16439 DumpId aclDeps[2];
16440 int nDeps = 0;
16441
16442 if (tag)
16444 else if (subname)
16445 appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
16446 else
16447 appendPQExpBuffer(tagbuf, "%s %s", type, name);
16448
16449 aclDeps[nDeps++] = objDumpId;
16450 if (altDumpId != InvalidDumpId)
16451 aclDeps[nDeps++] = altDumpId;
16452
16454
16456 ARCHIVE_OPTS(.tag = tagbuf->data,
16457 .namespace = nspname,
16458 .owner = owner,
16459 .description = "ACL",
16460 .section = SECTION_NONE,
16461 .createStmt = sql->data,
16462 .deps = aclDeps,
16463 .nDeps = nDeps));
16464
16466 }
16467
16468 destroyPQExpBuffer(sql);
16469
16470 return aclDumpId;
16471}

References _dumpableAcl::acl, acldefault(), _dumpableAcl::acldefault, _dumpOptions::aclsSkip, appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, buildACLCommands(), createDumpId(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), _dumpOptions::dumpSchema, fb(), _dumpableAcl::initprivs, InvalidDumpId, PQExpBufferData::len, name, nilCatalogId, pg_fatal, _dumpableAcl::privtype, SECTION_NONE, subname, and type.

Referenced by dumpAgg(), dumpBaseType(), dumpCompositeType(), dumpDatabase(), dumpDomain(), dumpEnumType(), dumpForeignDataWrapper(), dumpForeignServer(), dumpFunc(), dumpLO(), dumpNamespace(), dumpProcLang(), dumpRangeType(), dumpTable(), and dumpUndefinedType().

◆ dumpAgg()

static void dumpAgg ( Archive fout,
const AggInfo agginfo 
)
static

Definition at line 15343 of file pg_dump.c.

15344{
15345 DumpOptions *dopt = fout->dopt;
15346 PQExpBuffer query;
15347 PQExpBuffer q;
15349 PQExpBuffer details;
15350 char *aggsig; /* identity signature */
15351 char *aggfullsig = NULL; /* full signature */
15352 char *aggsig_tag;
15353 PGresult *res;
15354 int i_agginitval;
15355 int i_aggminitval;
15356 const char *aggtransfn;
15357 const char *aggfinalfn;
15358 const char *aggcombinefn;
15359 const char *aggserialfn;
15360 const char *aggdeserialfn;
15361 const char *aggmtransfn;
15362 const char *aggminvtransfn;
15363 const char *aggmfinalfn;
15364 bool aggfinalextra;
15365 bool aggmfinalextra;
15366 char aggfinalmodify;
15367 char aggmfinalmodify;
15368 const char *aggsortop;
15369 char *aggsortconvop;
15370 char aggkind;
15371 const char *aggtranstype;
15372 const char *aggtransspace;
15373 const char *aggmtranstype;
15374 const char *aggmtransspace;
15375 const char *agginitval;
15376 const char *aggminitval;
15377 const char *proparallel;
15378 char defaultfinalmodify;
15379
15380 /* Do nothing if not dumping schema */
15381 if (!dopt->dumpSchema)
15382 return;
15383
15384 query = createPQExpBuffer();
15385 q = createPQExpBuffer();
15387 details = createPQExpBuffer();
15388
15389 if (!fout->is_prepared[PREPQUERY_DUMPAGG])
15390 {
15391 /* Set up query for aggregate-specific details */
15393 "PREPARE dumpAgg(pg_catalog.oid) AS\n");
15394
15396 "SELECT "
15397 "aggtransfn,\n"
15398 "aggfinalfn,\n"
15399 "aggtranstype::pg_catalog.regtype,\n"
15400 "agginitval,\n"
15401 "aggsortop,\n"
15402 "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
15403 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
15404
15406 "aggkind,\n"
15407 "aggmtransfn,\n"
15408 "aggminvtransfn,\n"
15409 "aggmfinalfn,\n"
15410 "aggmtranstype::pg_catalog.regtype,\n"
15411 "aggfinalextra,\n"
15412 "aggmfinalextra,\n"
15413 "aggtransspace,\n"
15414 "aggmtransspace,\n"
15415 "aggminitval,\n");
15416
15418 "aggcombinefn,\n"
15419 "aggserialfn,\n"
15420 "aggdeserialfn,\n"
15421 "proparallel,\n");
15422
15423 if (fout->remoteVersion >= 110000)
15425 "aggfinalmodify,\n"
15426 "aggmfinalmodify\n");
15427 else
15429 "'0' AS aggfinalmodify,\n"
15430 "'0' AS aggmfinalmodify\n");
15431
15433 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
15434 "WHERE a.aggfnoid = p.oid "
15435 "AND p.oid = $1");
15436
15437 ExecuteSqlStatement(fout, query->data);
15438
15439 fout->is_prepared[PREPQUERY_DUMPAGG] = true;
15440 }
15441
15442 printfPQExpBuffer(query,
15443 "EXECUTE dumpAgg('%u')",
15444 agginfo->aggfn.dobj.catId.oid);
15445
15446 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15447
15448 i_agginitval = PQfnumber(res, "agginitval");
15449 i_aggminitval = PQfnumber(res, "aggminitval");
15450
15451 aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
15452 aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
15453 aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
15454 aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
15455 aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
15456 aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
15457 aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
15458 aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
15459 aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
15460 aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
15461 aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
15462 aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
15463 aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
15464 aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
15465 aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
15466 aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
15467 aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
15468 aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
15471 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
15472
15473 {
15474 char *funcargs;
15475 char *funciargs;
15476
15477 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
15478 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
15481 }
15482
15484
15485 /* identify default modify flag for aggkind (must match DefineAggregate) */
15487 /* replace omitted flags for old versions */
15488 if (aggfinalmodify == '0')
15490 if (aggmfinalmodify == '0')
15492
15493 /* regproc and regtype output is already sufficiently quoted */
15494 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
15495 aggtransfn, aggtranstype);
15496
15497 if (strcmp(aggtransspace, "0") != 0)
15498 {
15499 appendPQExpBuffer(details, ",\n SSPACE = %s",
15500 aggtransspace);
15501 }
15502
15503 if (!PQgetisnull(res, 0, i_agginitval))
15504 {
15505 appendPQExpBufferStr(details, ",\n INITCOND = ");
15507 }
15508
15509 if (strcmp(aggfinalfn, "-") != 0)
15510 {
15511 appendPQExpBuffer(details, ",\n FINALFUNC = %s",
15512 aggfinalfn);
15513 if (aggfinalextra)
15514 appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
15516 {
15517 switch (aggfinalmodify)
15518 {
15520 appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_ONLY");
15521 break;
15523 appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = SHAREABLE");
15524 break;
15526 appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_WRITE");
15527 break;
15528 default:
15529 pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
15530 agginfo->aggfn.dobj.name);
15531 break;
15532 }
15533 }
15534 }
15535
15536 if (strcmp(aggcombinefn, "-") != 0)
15537 appendPQExpBuffer(details, ",\n COMBINEFUNC = %s", aggcombinefn);
15538
15539 if (strcmp(aggserialfn, "-") != 0)
15540 appendPQExpBuffer(details, ",\n SERIALFUNC = %s", aggserialfn);
15541
15542 if (strcmp(aggdeserialfn, "-") != 0)
15543 appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
15544
15545 if (strcmp(aggmtransfn, "-") != 0)
15546 {
15547 appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
15551 }
15552
15553 if (strcmp(aggmtransspace, "0") != 0)
15554 {
15555 appendPQExpBuffer(details, ",\n MSSPACE = %s",
15557 }
15558
15559 if (!PQgetisnull(res, 0, i_aggminitval))
15560 {
15561 appendPQExpBufferStr(details, ",\n MINITCOND = ");
15563 }
15564
15565 if (strcmp(aggmfinalfn, "-") != 0)
15566 {
15567 appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
15568 aggmfinalfn);
15569 if (aggmfinalextra)
15570 appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
15572 {
15573 switch (aggmfinalmodify)
15574 {
15576 appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_ONLY");
15577 break;
15579 appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = SHAREABLE");
15580 break;
15582 appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_WRITE");
15583 break;
15584 default:
15585 pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
15586 agginfo->aggfn.dobj.name);
15587 break;
15588 }
15589 }
15590 }
15591
15593 if (aggsortconvop)
15594 {
15595 appendPQExpBuffer(details, ",\n SORTOP = %s",
15598 }
15599
15601 appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
15602
15604 {
15605 if (proparallel[0] == PROPARALLEL_SAFE)
15606 appendPQExpBufferStr(details, ",\n PARALLEL = safe");
15607 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
15608 appendPQExpBufferStr(details, ",\n PARALLEL = restricted");
15609 else if (proparallel[0] != PROPARALLEL_UNSAFE)
15610 pg_fatal("unrecognized proparallel value for function \"%s\"",
15611 agginfo->aggfn.dobj.name);
15612 }
15613
15614 appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
15615 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
15616 aggsig);
15617
15618 appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
15619 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
15620 aggfullsig ? aggfullsig : aggsig, details->data);
15621
15622 if (dopt->binary_upgrade)
15624 "AGGREGATE", aggsig,
15625 agginfo->aggfn.dobj.namespace->dobj.name);
15626
15627 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
15628 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
15629 agginfo->aggfn.dobj.dumpId,
15630 ARCHIVE_OPTS(.tag = aggsig_tag,
15631 .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
15632 .owner = agginfo->aggfn.rolname,
15633 .description = "AGGREGATE",
15634 .section = SECTION_PRE_DATA,
15635 .createStmt = q->data,
15636 .dropStmt = delq->data));
15637
15638 /* Dump Aggregate Comments */
15639 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
15640 dumpComment(fout, "AGGREGATE", aggsig,
15641 agginfo->aggfn.dobj.namespace->dobj.name,
15642 agginfo->aggfn.rolname,
15643 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
15644
15645 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
15646 dumpSecLabel(fout, "AGGREGATE", aggsig,
15647 agginfo->aggfn.dobj.namespace->dobj.name,
15648 agginfo->aggfn.rolname,
15649 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
15650
15651 /*
15652 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
15653 * command look like a function's GRANT; in particular this affects the
15654 * syntax for zero-argument aggregates and ordered-set aggregates.
15655 */
15656 free(aggsig);
15657
15658 aggsig = format_function_signature(fout, &agginfo->aggfn, true);
15659
15660 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
15661 dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
15662 "FUNCTION", aggsig, NULL,
15663 agginfo->aggfn.dobj.namespace->dobj.name,
15664 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
15665
15666 free(aggsig);
15669
15670 PQclear(res);
15671
15672 destroyPQExpBuffer(query);
15675 destroyPQExpBuffer(details);
15676}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_ACL, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpACL(), dumpComment(), _dumpOptions::dumpSchema, dumpSecLabel(), ExecuteSqlQueryForSingleRow(), ExecuteSqlStatement(), fb(), fmtId(), format_aggregate_signature(), format_function_arguments(), format_function_signature(), free, getFormattedOperatorName(), InvalidDumpId, pg_fatal, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PREPQUERY_DUMPAGG, printfPQExpBuffer(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpAttrDef()

static void dumpAttrDef ( Archive fout,
const AttrDefInfo adinfo 
)
static

Definition at line 18172 of file pg_dump.c.

18173{
18174 DumpOptions *dopt = fout->dopt;
18175 TableInfo *tbinfo = adinfo->adtable;
18176 int adnum = adinfo->adnum;
18177 PQExpBuffer q;
18179 char *qualrelname;
18180 char *tag;
18181 char *foreign;
18182
18183 /* Do nothing if not dumping schema */
18184 if (!dopt->dumpSchema)
18185 return;
18186
18187 /* Skip if not "separate"; it was dumped in the table's definition */
18188 if (!adinfo->separate)
18189 return;
18190
18191 q = createPQExpBuffer();
18193
18195
18196 foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
18197
18199 "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
18200 foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
18201 adinfo->adef_expr);
18202
18203 appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
18205 fmtId(tbinfo->attnames[adnum - 1]));
18206
18207 tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
18208
18209 if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18210 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
18211 ARCHIVE_OPTS(.tag = tag,
18212 .namespace = tbinfo->dobj.namespace->dobj.name,
18213 .owner = tbinfo->rolname,
18214 .description = "DEFAULT",
18215 .section = SECTION_PRE_DATA,
18216 .createStmt = q->data,
18217 .dropStmt = delq->data));
18218
18219 pfree(tag);
18223}

References appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_DEFINITION, _dumpOptions::dumpSchema, fb(), fmtId(), fmtQualifiedDumpable, pfree(), pg_free(), pg_strdup(), psprintf(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpBaseType()

static void dumpBaseType ( Archive fout,
const TypeInfo tyinfo 
)
static

Definition at line 12436 of file pg_dump.c.

12437{
12438 DumpOptions *dopt = fout->dopt;
12442 PGresult *res;
12443 char *qtypname;
12444 char *qualtypname;
12445 char *typlen;
12446 char *typinput;
12447 char *typoutput;
12448 char *typreceive;
12449 char *typsend;
12450 char *typmodin;
12451 char *typmodout;
12452 char *typanalyze;
12453 char *typsubscript;
12460 char *typcategory;
12461 char *typispreferred;
12462 char *typdelim;
12463 char *typbyval;
12464 char *typalign;
12465 char *typstorage;
12466 char *typcollatable;
12467 char *typdefault;
12468 bool typdefault_is_literal = false;
12469
12470 if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
12471 {
12472 /* Set up query for type-specific details */
12474 "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
12475 "SELECT typlen, "
12476 "typinput, typoutput, typreceive, typsend, "
12477 "typreceive::pg_catalog.oid AS typreceiveoid, "
12478 "typsend::pg_catalog.oid AS typsendoid, "
12479 "typanalyze, "
12480 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
12481 "typdelim, typbyval, typalign, typstorage, "
12482 "typmodin, typmodout, "
12483 "typmodin::pg_catalog.oid AS typmodinoid, "
12484 "typmodout::pg_catalog.oid AS typmodoutoid, "
12485 "typcategory, typispreferred, "
12486 "(typcollation <> 0) AS typcollatable, "
12487 "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
12488
12489 if (fout->remoteVersion >= 140000)
12491 "typsubscript, "
12492 "typsubscript::pg_catalog.oid AS typsubscriptoid ");
12493 else
12495 "'-' AS typsubscript, 0 AS typsubscriptoid ");
12496
12497 appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
12498 "WHERE oid = $1");
12499
12500 ExecuteSqlStatement(fout, query->data);
12501
12502 fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
12503 }
12504
12505 printfPQExpBuffer(query,
12506 "EXECUTE dumpBaseType('%u')",
12507 tyinfo->dobj.catId.oid);
12508
12509 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12510
12511 typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
12512 typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
12513 typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
12514 typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
12515 typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
12516 typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
12517 typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
12518 typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
12519 typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
12520