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
 
static DumpId lo_metadata_dumpId
 

Macro Definition Documentation

◆ DUMP_DEFAULT_ROWS_PER_INSERT

#define DUMP_DEFAULT_ROWS_PER_INSERT   1

Definition at line 230 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 242 of file pg_dump.c.

424{
425 int c;
426 const char *filename = NULL;
427 const char *format = "p";
428 TableInfo *tblinfo;
429 int numTables;
431 int numObjs;
433 int i;
434 int optindex;
435 RestoreOptions *ropt;
436 Archive *fout; /* the script file */
437 bool g_verbose = false;
438 const char *dumpencoding = NULL;
439 const char *dumpsnapshot = NULL;
440 char *use_role = NULL;
441 int numWorkers = 1;
442 int plainText = 0;
445 pg_compress_specification compression_spec = {0};
446 char *compression_detail = NULL;
447 char *compression_algorithm_str = "none";
448 char *error_detail = NULL;
449 bool user_compression_defined = false;
451 bool data_only = false;
452 bool schema_only = false;
453 bool statistics_only = false;
454 bool with_statistics = false;
455 bool no_data = false;
456 bool no_schema = false;
457 bool no_statistics = false;
458
459 static DumpOptions dopt;
460
461 static struct option long_options[] = {
462 {"data-only", no_argument, NULL, 'a'},
463 {"blobs", no_argument, NULL, 'b'},
464 {"large-objects", no_argument, NULL, 'b'},
465 {"no-blobs", no_argument, NULL, 'B'},
466 {"no-large-objects", no_argument, NULL, 'B'},
467 {"clean", no_argument, NULL, 'c'},
468 {"create", no_argument, NULL, 'C'},
469 {"dbname", required_argument, NULL, 'd'},
470 {"extension", required_argument, NULL, 'e'},
471 {"file", required_argument, NULL, 'f'},
472 {"format", required_argument, NULL, 'F'},
473 {"host", required_argument, NULL, 'h'},
474 {"jobs", 1, NULL, 'j'},
475 {"no-reconnect", no_argument, NULL, 'R'},
476 {"no-owner", no_argument, NULL, 'O'},
477 {"port", required_argument, NULL, 'p'},
478 {"schema", required_argument, NULL, 'n'},
479 {"exclude-schema", required_argument, NULL, 'N'},
480 {"schema-only", no_argument, NULL, 's'},
481 {"superuser", required_argument, NULL, 'S'},
482 {"table", required_argument, NULL, 't'},
483 {"exclude-table", required_argument, NULL, 'T'},
484 {"no-password", no_argument, NULL, 'w'},
485 {"password", no_argument, NULL, 'W'},
486 {"username", required_argument, NULL, 'U'},
487 {"verbose", no_argument, NULL, 'v'},
488 {"no-privileges", no_argument, NULL, 'x'},
489 {"no-acl", no_argument, NULL, 'x'},
490 {"compress", required_argument, NULL, 'Z'},
491 {"encoding", required_argument, NULL, 'E'},
492 {"help", no_argument, NULL, '?'},
493 {"version", no_argument, NULL, 'V'},
494
495 /*
496 * the following options don't have an equivalent short option letter
497 */
498 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
499 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
500 {"column-inserts", no_argument, &dopt.column_inserts, 1},
501 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
502 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
503 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
504 {"exclude-table-data", required_argument, NULL, 4},
505 {"extra-float-digits", required_argument, NULL, 8},
506 {"if-exists", no_argument, &dopt.if_exists, 1},
507 {"inserts", no_argument, NULL, 9},
508 {"lock-wait-timeout", required_argument, NULL, 2},
509 {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
510 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
511 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
512 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
513 {"role", required_argument, NULL, 3},
514 {"section", required_argument, NULL, 5},
515 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
516 {"snapshot", required_argument, NULL, 6},
517 {"statistics", no_argument, NULL, 22},
518 {"statistics-only", no_argument, NULL, 18},
519 {"strict-names", no_argument, &strict_names, 1},
520 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
521 {"no-comments", no_argument, &dopt.no_comments, 1},
522 {"no-data", no_argument, NULL, 19},
523 {"no-policies", no_argument, &dopt.no_policies, 1},
524 {"no-publications", no_argument, &dopt.no_publications, 1},
525 {"no-schema", no_argument, NULL, 20},
526 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
527 {"no-statistics", no_argument, NULL, 21},
528 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
529 {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
530 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
531 {"no-sync", no_argument, NULL, 7},
532 {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
533 {"rows-per-insert", required_argument, NULL, 10},
534 {"include-foreign-data", required_argument, NULL, 11},
535 {"table-and-children", required_argument, NULL, 12},
536 {"exclude-table-and-children", required_argument, NULL, 13},
537 {"exclude-table-data-and-children", required_argument, NULL, 14},
538 {"sync-method", required_argument, NULL, 15},
539 {"filter", required_argument, NULL, 16},
540 {"exclude-extension", required_argument, NULL, 17},
541 {"sequence-data", no_argument, &dopt.sequence_data, 1},
542 {"restrict-key", required_argument, NULL, 25},
543
544 {NULL, 0, NULL, 0}
545 };
546
547 pg_logging_init(argv[0]);
549 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
550
551 /*
552 * Initialize what we need for parallel execution, especially for thread
553 * support on Windows.
554 */
556
557 progname = get_progname(argv[0]);
558
559 if (argc > 1)
560 {
561 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
562 {
563 help(progname);
564 exit_nicely(0);
565 }
566 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
567 {
568 puts("pg_dump (PostgreSQL) " PG_VERSION);
569 exit_nicely(0);
570 }
571 }
572
573 InitDumpOptions(&dopt);
574
575 while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
576 long_options, &optindex)) != -1)
577 {
578 switch (c)
579 {
580 case 'a': /* Dump data only */
581 data_only = true;
582 break;
583
584 case 'b': /* Dump LOs */
585 dopt.outputLOs = true;
586 break;
587
588 case 'B': /* Don't dump LOs */
589 dopt.dontOutputLOs = true;
590 break;
591
592 case 'c': /* clean (i.e., drop) schema prior to create */
593 dopt.outputClean = 1;
594 break;
595
596 case 'C': /* Create DB */
597 dopt.outputCreateDB = 1;
598 break;
599
600 case 'd': /* database name */
602 break;
603
604 case 'e': /* include extension(s) */
606 dopt.include_everything = false;
607 break;
608
609 case 'E': /* Dump encoding */
611 break;
612
613 case 'f':
615 break;
616
617 case 'F':
619 break;
620
621 case 'h': /* server host */
623 break;
624
625 case 'j': /* number of dump jobs */
626 if (!option_parse_int(optarg, "-j/--jobs", 1,
628 &numWorkers))
629 exit_nicely(1);
630 break;
631
632 case 'n': /* include schema(s) */
634 dopt.include_everything = false;
635 break;
636
637 case 'N': /* exclude schema(s) */
639 break;
640
641 case 'O': /* Don't reconnect to match owner */
642 dopt.outputNoOwner = 1;
643 break;
644
645 case 'p': /* server port */
647 break;
648
649 case 'R':
650 /* no-op, still accepted for backwards compatibility */
651 break;
652
653 case 's': /* dump schema only */
654 schema_only = true;
655 break;
656
657 case 'S': /* Username for superuser in plain text output */
659 break;
660
661 case 't': /* include table(s) */
663 dopt.include_everything = false;
664 break;
665
666 case 'T': /* exclude table(s) */
668 break;
669
670 case 'U':
672 break;
673
674 case 'v': /* verbose */
675 g_verbose = true;
677 break;
678
679 case 'w':
681 break;
682
683 case 'W':
685 break;
686
687 case 'x': /* skip ACL dump */
688 dopt.aclsSkip = true;
689 break;
690
691 case 'Z': /* Compression */
695 break;
696
697 case 0:
698 /* This covers the long options. */
699 break;
700
701 case 2: /* lock-wait-timeout */
703 break;
704
705 case 3: /* SET ROLE */
706 use_role = pg_strdup(optarg);
707 break;
708
709 case 4: /* exclude table(s) data */
711 break;
712
713 case 5: /* section */
715 break;
716
717 case 6: /* snapshot */
719 break;
720
721 case 7: /* no-sync */
722 dosync = false;
723 break;
724
725 case 8:
727 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
729 exit_nicely(1);
730 break;
731
732 case 9: /* inserts */
733
734 /*
735 * dump_inserts also stores --rows-per-insert, careful not to
736 * overwrite that.
737 */
738 if (dopt.dump_inserts == 0)
740 break;
741
742 case 10: /* rows per insert */
743 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
744 &dopt.dump_inserts))
745 exit_nicely(1);
746 break;
747
748 case 11: /* include foreign data */
750 optarg);
751 break;
752
753 case 12: /* include table(s) and their children */
755 optarg);
756 dopt.include_everything = false;
757 break;
758
759 case 13: /* exclude table(s) and their children */
761 optarg);
762 break;
763
764 case 14: /* exclude data of table(s) and children */
766 optarg);
767 break;
768
769 case 15:
771 exit_nicely(1);
772 break;
773
774 case 16: /* read object filters from file */
776 break;
777
778 case 17: /* exclude extension(s) */
780 optarg);
781 break;
782
783 case 18:
784 statistics_only = true;
785 break;
786
787 case 19:
788 no_data = true;
789 break;
790
791 case 20:
792 no_schema = true;
793 break;
794
795 case 21:
796 no_statistics = true;
797 break;
798
799 case 22:
800 with_statistics = true;
801 break;
802
803 case 25:
805 break;
806
807 default:
808 /* getopt_long already emitted a complaint */
809 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
810 exit_nicely(1);
811 }
812 }
813
814 /*
815 * Non-option argument specifies database name as long as it wasn't
816 * already specified with -d / --dbname
817 */
818 if (optind < argc && dopt.cparams.dbname == NULL)
819 dopt.cparams.dbname = argv[optind++];
820
821 /* Complain if any arguments remain */
822 if (optind < argc)
823 {
824 pg_log_error("too many command-line arguments (first is \"%s\")",
825 argv[optind]);
826 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
827 exit_nicely(1);
828 }
829
830 /* --column-inserts implies --inserts */
831 if (dopt.column_inserts && dopt.dump_inserts == 0)
833
834 /* reject conflicting "-only" options */
835 if (data_only && schema_only)
836 pg_fatal("options %s and %s cannot be used together",
837 "-s/--schema-only", "-a/--data-only");
839 pg_fatal("options %s and %s cannot be used together",
840 "-s/--schema-only", "--statistics-only");
842 pg_fatal("options %s and %s cannot be used together",
843 "-a/--data-only", "--statistics-only");
844
845 /* reject conflicting "-only" and "no-" options */
846 if (data_only && no_data)
847 pg_fatal("options %s and %s cannot be used together",
848 "-a/--data-only", "--no-data");
849 if (schema_only && no_schema)
850 pg_fatal("options %s and %s cannot be used together",
851 "-s/--schema-only", "--no-schema");
853 pg_fatal("options %s and %s cannot be used together",
854 "--statistics-only", "--no-statistics");
855
856 /* reject conflicting "no-" options */
858 pg_fatal("options %s and %s cannot be used together",
859 "--statistics", "--no-statistics");
860
861 /* reject conflicting "-only" options */
863 pg_fatal("options %s and %s cannot be used together",
864 "-a/--data-only", "--statistics");
866 pg_fatal("options %s and %s cannot be used together",
867 "-s/--schema-only", "--statistics");
868
870 pg_fatal("options %s and %s cannot be used together",
871 "-s/--schema-only", "--include-foreign-data");
872
873 if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
874 pg_fatal("option %s is not supported with parallel backup",
875 "--include-foreign-data");
876
877 if (data_only && dopt.outputClean)
878 pg_fatal("options %s and %s cannot be used together",
879 "-c/--clean", "-a/--data-only");
880
881 if (dopt.if_exists && !dopt.outputClean)
882 pg_fatal("option %s requires option %s",
883 "--if-exists", "-c/--clean");
884
885 /*
886 * Set derivative flags. Ambiguous or nonsensical combinations, e.g.
887 * "--schema-only --no-schema", will have already caused an error in one
888 * of the checks above.
889 */
890 dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
891 data_only) && !no_data;
892 dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
894 dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
896
897
898 /*
899 * --inserts are already implied above if --column-inserts or
900 * --rows-per-insert were specified.
901 */
902 if (dopt.do_nothing && dopt.dump_inserts == 0)
903 pg_fatal("option %s requires option %s, %s, or %s",
904 "--on-conflict-do-nothing",
905 "--inserts", "--rows-per-insert", "--column-inserts");
906
907 /* Identify archive format to emit */
909
910 /* archiveFormat specific setup */
911 if (archiveFormat == archNull)
912 {
913 plainText = 1;
914
915 /*
916 * If you don't provide a restrict key, one will be appointed for you.
917 */
918 if (!dopt.restrict_key)
920 if (!dopt.restrict_key)
921 pg_fatal("could not generate restrict key");
923 pg_fatal("invalid restrict key");
924 }
925 else if (dopt.restrict_key)
926 pg_fatal("option %s can only be used with %s",
927 "--restrict-key", "--format=plain");
928
929 /*
930 * Custom and directory formats are compressed by default with gzip when
931 * available, not the others. If gzip is not available, no compression is
932 * done by default.
933 */
936 {
937#ifdef HAVE_LIBZ
939#else
941#endif
942 }
943
944 /*
945 * Compression options
946 */
949 pg_fatal("unrecognized compression algorithm: \"%s\"",
951
953 &compression_spec);
955 if (error_detail != NULL)
956 pg_fatal("invalid compression specification: %s",
958
959 error_detail = supports_compression(compression_spec);
960 if (error_detail != NULL)
961 pg_fatal("%s", error_detail);
962
963 /*
964 * Disable support for zstd workers for now - these are based on
965 * threading, and it's unclear how it interacts with parallel dumps on
966 * platforms where that relies on threads too (e.g. Windows).
967 */
968 if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
969 pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
970 "workers");
971
972 /*
973 * If emitting an archive format, we always want to emit a DATABASE item,
974 * in case --create is specified at pg_restore time.
975 */
976 if (!plainText)
977 dopt.outputCreateDB = 1;
978
979 /* Parallel backup only in the directory archive format so far */
980 if (archiveFormat != archDirectory && numWorkers > 1)
981 pg_fatal("parallel backup only supported by the directory format");
982
983 /* Open the output file */
984 fout = CreateArchive(filename, archiveFormat, compression_spec,
986
987 /* Make dump options accessible right away */
988 SetArchiveOptions(fout, &dopt, NULL);
989
990 /* Register the cleanup hook */
992
993 /* Let the archiver know how noisy to be */
994 fout->verbose = g_verbose;
995
996
997 /*
998 * We allow the server to be back to 9.2, and up to any minor release of
999 * our own major version. (See also version check in pg_dumpall.c.)
1000 */
1001 fout->minRemoteVersion = 90200;
1002 fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
1003
1004 fout->numWorkers = numWorkers;
1005
1006 /*
1007 * Open the database using the Archiver, so it knows about it. Errors mean
1008 * death.
1009 */
1010 ConnectDatabaseAhx(fout, &dopt.cparams, false);
1012
1013 /*
1014 * On hot standbys, never try to dump unlogged table data, since it will
1015 * just throw an error.
1016 */
1017 if (fout->isStandby)
1018 dopt.no_unlogged_table_data = true;
1019
1020 /*
1021 * Find the last built-in OID, if needed (prior to 8.1)
1022 *
1023 * With 8.1 and above, we can just use FirstNormalObjectId - 1.
1024 */
1026
1027 pg_log_info("last built-in OID is %u", g_last_builtin_oid);
1028
1029 /* Expand schema selection patterns into OID lists */
1031 {
1034 strict_names);
1036 pg_fatal("no matching schemas were found");
1037 }
1040 false);
1041 /* non-matching exclusion patterns aren't an error */
1042
1043 /* Expand table selection patterns into OID lists */
1046 strict_names, false);
1049 strict_names, true);
1053 pg_fatal("no matching tables were found");
1054
1057 false, false);
1060 false, true);
1061
1064 false, false);
1067 false, true);
1068
1071
1072 /* non-matching exclusion patterns aren't an error */
1073
1074 /* Expand extension selection patterns into OID lists */
1076 {
1079 strict_names);
1081 pg_fatal("no matching extensions were found");
1082 }
1085 false);
1086 /* non-matching exclusion patterns aren't an error */
1087
1088 /*
1089 * Dumping LOs is the default for dumps where an inclusion switch is not
1090 * used (an "include everything" dump). -B can be used to exclude LOs
1091 * from those dumps. -b can be used to include LOs even when an inclusion
1092 * switch is used.
1093 *
1094 * -s means "schema only" and LOs are data, not schema, so we never
1095 * include LOs when -s is used.
1096 */
1097 if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
1098 dopt.outputLOs = true;
1099
1100 /*
1101 * Collect role names so we can map object owner OIDs to names.
1102 */
1104
1105 /*
1106 * Now scan the database and create DumpableObject structs for all the
1107 * objects we intend to dump.
1108 */
1109 tblinfo = getSchemaData(fout, &numTables);
1110
1111 if (dopt.dumpData)
1112 {
1113 getTableData(&dopt, tblinfo, numTables, 0);
1115 if (!dopt.dumpSchema)
1117 }
1118
1119 if (!dopt.dumpData && dopt.sequence_data)
1120 getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
1121
1122 /*
1123 * For binary upgrade mode, dump pg_largeobject_metadata and the
1124 * associated pg_shdepend rows. This is faster to restore than the
1125 * equivalent set of large object commands. We can only do this for
1126 * upgrades from v12 and newer; in older versions, pg_largeobject_metadata
1127 * was created WITH OIDS, so the OID column is hidden and won't be dumped.
1128 */
1129 if (dopt.binary_upgrade && fout->remoteVersion >= 120000)
1130 {
1133
1136
1137 /*
1138 * Save pg_largeobject_metadata's dump ID for use as a dependency for
1139 * pg_shdepend and any large object comments/seclabels.
1140 */
1141 lo_metadata_dumpId = lo_metadata->dataObj->dobj.dumpId;
1143
1144 /*
1145 * Only dump large object shdepend rows for this database.
1146 */
1147 shdepend->dataObj->filtercond = "WHERE classid = 'pg_largeobject'::regclass "
1148 "AND dbid = (SELECT oid FROM pg_database "
1149 " WHERE datname = current_database())";
1150
1151 /*
1152 * If upgrading from v16 or newer, only dump large objects with
1153 * comments/seclabels. For these upgrades, pg_upgrade can copy/link
1154 * pg_largeobject_metadata's files (which is usually faster) but we
1155 * still need to dump LOs with comments/seclabels here so that the
1156 * subsequent COMMENT and SECURITY LABEL commands work. pg_upgrade
1157 * can't copy/link the files from older versions because aclitem
1158 * (needed by pg_largeobject_metadata.lomacl) changed its storage
1159 * format in v16.
1160 */
1161 if (fout->remoteVersion >= 160000)
1162 lo_metadata->dataObj->filtercond = "WHERE oid IN "
1163 "(SELECT objoid FROM pg_description "
1164 "WHERE classoid = " CppAsString2(LargeObjectRelationId) " "
1165 "UNION SELECT objoid FROM pg_seclabel "
1166 "WHERE classoid = " CppAsString2(LargeObjectRelationId) ")";
1167 }
1168
1169 /*
1170 * In binary-upgrade mode, we do not have to worry about the actual LO
1171 * data or the associated metadata that resides in the pg_largeobject and
1172 * pg_largeobject_metadata tables, respectively.
1173 *
1174 * However, we do need to collect LO information as there may be comments
1175 * or other information on LOs that we do need to dump out.
1176 */
1177 if (dopt.outputLOs || dopt.binary_upgrade)
1178 getLOs(fout);
1179
1180 /*
1181 * Collect dependency data to assist in ordering the objects.
1182 */
1184
1185 /*
1186 * Collect ACLs, comments, and security labels, if wanted.
1187 */
1188 if (!dopt.aclsSkip)
1190 if (!dopt.no_comments)
1192 if (!dopt.no_security_labels)
1194
1195 /* For binary upgrade mode, collect required pg_class information. */
1196 if (dopt.binary_upgrade)
1198
1199 /* Collect sequence information. */
1201
1202 /* Lastly, create dummy objects to represent the section boundaries */
1204
1205 /* Get pointers to all the known DumpableObjects */
1207
1208 /*
1209 * Add dummy dependencies to enforce the dump section ordering.
1210 */
1212
1213 /*
1214 * Sort the objects into a safe dump order (no forward references).
1215 *
1216 * We rely on dependency information to help us determine a safe order, so
1217 * the initial sort is mostly for cosmetic purposes: we sort by name to
1218 * ensure that logically identical schemas will dump identically.
1219 */
1221
1223 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
1224
1225 /*
1226 * Create archive TOC entries for all the objects to be dumped, in a safe
1227 * order.
1228 */
1229
1230 /*
1231 * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
1232 */
1236
1237 /* The database items are always next, unless we don't want them at all */
1238 if (dopt.outputCreateDB)
1240
1241 /* Now the rearrangeable objects. */
1242 for (i = 0; i < numObjs; i++)
1244
1245 /*
1246 * Set up options info to ensure we dump what we want.
1247 */
1248 ropt = NewRestoreOptions();
1249 ropt->filename = filename;
1250
1251 /* if you change this list, see dumpOptionsFromRestoreOptions */
1252 ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
1253 ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
1254 ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
1257 ropt->dropSchema = dopt.outputClean;
1258 ropt->dumpData = dopt.dumpData;
1259 ropt->dumpSchema = dopt.dumpSchema;
1260 ropt->dumpStatistics = dopt.dumpStatistics;
1261 ropt->if_exists = dopt.if_exists;
1262 ropt->column_inserts = dopt.column_inserts;
1263 ropt->dumpSections = dopt.dumpSections;
1264 ropt->aclsSkip = dopt.aclsSkip;
1265 ropt->superuser = dopt.outputSuperuser;
1266 ropt->createDB = dopt.outputCreateDB;
1267 ropt->noOwner = dopt.outputNoOwner;
1268 ropt->noTableAm = dopt.outputNoTableAm;
1269 ropt->noTablespace = dopt.outputNoTablespaces;
1271 ropt->use_setsessauth = dopt.use_setsessauth;
1273 ropt->dump_inserts = dopt.dump_inserts;
1274 ropt->no_comments = dopt.no_comments;
1275 ropt->no_policies = dopt.no_policies;
1276 ropt->no_publications = dopt.no_publications;
1279 ropt->lockWaitTimeout = dopt.lockWaitTimeout;
1282 ropt->sequence_data = dopt.sequence_data;
1283 ropt->binary_upgrade = dopt.binary_upgrade;
1284 ropt->restrict_key = dopt.restrict_key ? pg_strdup(dopt.restrict_key) : NULL;
1285
1286 ropt->compression_spec = compression_spec;
1287
1288 ropt->suppressDumpWarnings = true; /* We've already shown them */
1289
1290 SetArchiveOptions(fout, &dopt, ropt);
1291
1292 /* Mark which entries should be output */
1294
1295 /*
1296 * The archive's TOC entries are now marked as to which ones will actually
1297 * be output, so we can set up their dependency lists properly. This isn't
1298 * necessary for plain-text output, though.
1299 */
1300 if (!plainText)
1302
1303 /*
1304 * And finally we can do the actual output.
1305 *
1306 * Note: for non-plain-text output formats, the output file is written
1307 * inside CloseArchive(). This is, um, bizarre; but not worth changing
1308 * right now.
1309 */
1310 if (plainText)
1312
1314
1315 exit_nicely(0);
1316}
1317
1318
1319static void
1320help(const char *progname)
1321{
1322 printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
1323 printf(_("Usage:\n"));
1324 printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
1325
1326 printf(_("\nGeneral options:\n"));
1327 printf(_(" -f, --file=FILENAME output file or directory name\n"));
1328 printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
1329 " plain text (default))\n"));
1330 printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
1331 printf(_(" -v, --verbose verbose mode\n"));
1332 printf(_(" -V, --version output version information, then exit\n"));
1333 printf(_(" -Z, --compress=METHOD[:DETAIL]\n"
1334 " compress as specified\n"));
1335 printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
1336 printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
1337 printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
1338 printf(_(" -?, --help show this help, then exit\n"));
1339
1340 printf(_("\nOptions controlling the output content:\n"));
1341 printf(_(" -a, --data-only dump only the data, not the schema or statistics\n"));
1342 printf(_(" -b, --large-objects include large objects in dump\n"));
1343 printf(_(" --blobs (same as --large-objects, deprecated)\n"));
1344 printf(_(" -B, --no-large-objects exclude large objects in dump\n"));
1345 printf(_(" --no-blobs (same as --no-large-objects, deprecated)\n"));
1346 printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
1347 printf(_(" -C, --create include commands to create database in dump\n"));
1348 printf(_(" -e, --extension=PATTERN dump the specified extension(s) only\n"));
1349 printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
1350 printf(_(" -n, --schema=PATTERN dump the specified schema(s) only\n"));
1351 printf(_(" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
1352 printf(_(" -O, --no-owner skip restoration of object ownership in\n"
1353 " plain-text format\n"));
1354 printf(_(" -s, --schema-only dump only the schema, no data or statistics\n"));
1355 printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
1356 printf(_(" -t, --table=PATTERN dump only the specified table(s)\n"));
1357 printf(_(" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n"));
1358 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
1359 printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
1360 printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
1361 printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
1362 printf(_(" --disable-triggers disable triggers during data-only restore\n"));
1363 printf(_(" --enable-row-security enable row security (dump only content user has\n"
1364 " access to)\n"));
1365 printf(_(" --exclude-extension=PATTERN do NOT dump the specified extension(s)\n"));
1366 printf(_(" --exclude-table-and-children=PATTERN\n"
1367 " do NOT dump the specified table(s), including\n"
1368 " child and partition tables\n"));
1369 printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
1370 printf(_(" --exclude-table-data-and-children=PATTERN\n"
1371 " do NOT dump data for the specified table(s),\n"
1372 " including child and partition tables\n"));
1373 printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
1374 printf(_(" --filter=FILENAME include or exclude objects and data from dump\n"
1375 " based on expressions in FILENAME\n"));
1376 printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
1377 printf(_(" --include-foreign-data=PATTERN\n"
1378 " include data of foreign tables on foreign\n"
1379 " servers matching PATTERN\n"));
1380 printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
1381 printf(_(" --load-via-partition-root load partitions via the root table\n"));
1382 printf(_(" --no-comments do not dump comment commands\n"));
1383 printf(_(" --no-data do not dump data\n"));
1384 printf(_(" --no-policies do not dump row security policies\n"));
1385 printf(_(" --no-publications do not dump publications\n"));
1386 printf(_(" --no-schema do not dump schema\n"));
1387 printf(_(" --no-security-labels do not dump security label assignments\n"));
1388 printf(_(" --no-statistics do not dump statistics\n"));
1389 printf(_(" --no-subscriptions do not dump subscriptions\n"));
1390 printf(_(" --no-table-access-method do not dump table access methods\n"));
1391 printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
1392 printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
1393 printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
1394 printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
1395 printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
1396 printf(_(" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n"));
1397 printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
1398 printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
1399 printf(_(" --sequence-data include sequence data in dump\n"));
1400 printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
1401 printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
1402 printf(_(" --statistics dump the statistics\n"));
1403 printf(_(" --statistics-only dump only the statistics, not schema or data\n"));
1404 printf(_(" --strict-names require table and/or schema include patterns to\n"
1405 " match at least one entity each\n"));
1406 printf(_(" --table-and-children=PATTERN dump only the specified table(s), including\n"
1407 " child and partition tables\n"));
1408 printf(_(" --use-set-session-authorization\n"
1409 " use SET SESSION AUTHORIZATION commands instead of\n"
1410 " ALTER OWNER commands to set ownership\n"));
1411
1412 printf(_("\nConnection options:\n"));
1413 printf(_(" -d, --dbname=DBNAME database to dump\n"));
1414 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
1415 printf(_(" -p, --port=PORT database server port number\n"));
1416 printf(_(" -U, --username=NAME connect as specified database user\n"));
1417 printf(_(" -w, --no-password never prompt for password\n"));
1418 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
1419 printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
1420
1421 printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1422 "variable value is used.\n\n"));
1423 printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1424 printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
1425}
1426
1427static void
1428setup_connection(Archive *AH, const char *dumpencoding,
1429 const char *dumpsnapshot, char *use_role)
1430{
1431 DumpOptions *dopt = AH->dopt;
1432 PGconn *conn = GetConnection(AH);
1433
1435
1436 /*
1437 * Set the client encoding if requested.
1438 */
1439 if (dumpencoding)
1440 {
1442 pg_fatal("invalid client encoding \"%s\" specified",
1443 dumpencoding);
1444 }
1445
1446 /*
1447 * Force standard_conforming_strings on, just in case we are dumping from
1448 * an old server that has it disabled. Without this, literals in views,
1449 * expressions, etc, would be incorrect for modern servers.
1450 */
1451 ExecuteSqlStatement(AH, "SET standard_conforming_strings = on");
1452
1453 /*
1454 * And reflect that to AH->std_strings. You might think that we should
1455 * just delete that variable and the code that checks it, but that would
1456 * be problematic for pg_restore, which at least for now should still cope
1457 * with archives containing the other setting (cf. processStdStringsEntry
1458 * in pg_backup_archiver.c).
1459 */
1460 AH->std_strings = true;
1461
1462 /*
1463 * Get the active encoding, so we know how to escape strings.
1464 */
1467
1468 /*
1469 * Set the role if requested. In a parallel dump worker, we'll be passed
1470 * use_role == NULL, but AH->use_role is already set (if user specified it
1471 * originally) and we should use that.
1472 */
1473 if (!use_role && AH->use_role)
1474 use_role = AH->use_role;
1475
1476 /* Set the role if requested */
1477 if (use_role)
1478 {
1480
1481 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1482 ExecuteSqlStatement(AH, query->data);
1483 destroyPQExpBuffer(query);
1484
1485 /* save it for possible later use by parallel workers */
1486 if (!AH->use_role)
1487 AH->use_role = pg_strdup(use_role);
1488 }
1489
1490 /* Set the datestyle to ISO to ensure the dump's portability */
1491 ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1492
1493 /* Likewise, avoid using sql_standard intervalstyle */
1494 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1495
1496 /*
1497 * Use an explicitly specified extra_float_digits if it has been provided.
1498 * Otherwise, set extra_float_digits so that we can dump float data
1499 * exactly (given correctly implemented float I/O code, anyway).
1500 */
1502 {
1504
1505 appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1507 ExecuteSqlStatement(AH, q->data);
1509 }
1510 else
1511 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1512
1513 /*
1514 * Disable synchronized scanning, to prevent unpredictable changes in row
1515 * ordering across a dump and reload.
1516 */
1517 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1518
1519 /*
1520 * Disable timeouts if supported.
1521 */
1522 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1523 if (AH->remoteVersion >= 90300)
1524 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1525 if (AH->remoteVersion >= 90600)
1526 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1527 if (AH->remoteVersion >= 170000)
1528 ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
1529
1530 /*
1531 * Quote all identifiers, if requested.
1532 */
1534 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1535
1536 /*
1537 * Adjust row-security mode, if supported.
1538 */
1539 if (AH->remoteVersion >= 90500)
1540 {
1541 if (dopt->enable_row_security)
1542 ExecuteSqlStatement(AH, "SET row_security = on");
1543 else
1544 ExecuteSqlStatement(AH, "SET row_security = off");
1545 }
1546
1547 /*
1548 * For security reasons, we restrict the expansion of non-system views and
1549 * access to foreign tables during the pg_dump process. This restriction
1550 * is adjusted when dumping foreign table data.
1551 */
1552 set_restrict_relation_kind(AH, "view, foreign-table");
1553
1554 /*
1555 * Initialize prepared-query state to "nothing prepared". We do this here
1556 * so that a parallel dump worker will have its own state.
1557 */
1558 AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
1559
1560 /*
1561 * Start transaction-snapshot mode transaction to dump consistent data.
1562 */
1563 ExecuteSqlStatement(AH, "BEGIN");
1564
1565 /*
1566 * To support the combination of serializable_deferrable with the jobs
1567 * option we use REPEATABLE READ for the worker connections that are
1568 * passed a snapshot. As long as the snapshot is acquired in a
1569 * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1570 * REPEATABLE READ transaction provides the appropriate integrity
1571 * guarantees. This is a kluge, but safe for back-patching.
1572 */
1573 if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1575 "SET TRANSACTION ISOLATION LEVEL "
1576 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1577 else
1579 "SET TRANSACTION ISOLATION LEVEL "
1580 "REPEATABLE READ, READ ONLY");
1581
1582 /*
1583 * If user specified a snapshot to use, select that. In a parallel dump
1584 * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1585 * is already set (if the server can handle it) and we should use that.
1586 */
1587 if (dumpsnapshot)
1589
1590 if (AH->sync_snapshot_id)
1591 {
1593
1594 appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
1596 ExecuteSqlStatement(AH, query->data);
1597 destroyPQExpBuffer(query);
1598 }
1599 else if (AH->numWorkers > 1)
1600 {
1601 if (AH->isStandby && AH->remoteVersion < 100000)
1602 pg_fatal("parallel dumps from standby servers are not supported by this server version");
1604 }
1605}
1606
1607/* Set up connection for a parallel worker process */
1608static void
1610{
1611 /*
1612 * We want to re-select all the same values the leader connection is
1613 * using. We'll have inherited directly-usable values in
1614 * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1615 * inherited encoding value back to a string to pass to setup_connection.
1616 */
1619 NULL,
1620 NULL);
1621}
1622
1623static char *
1625{
1626 char *query = "SELECT pg_catalog.pg_export_snapshot()";
1627 char *result;
1628 PGresult *res;
1629
1630 res = ExecuteSqlQueryForSingleRow(fout, query);
1631 result = pg_strdup(PQgetvalue(res, 0, 0));
1632 PQclear(res);
1633
1634 return result;
1635}
1636
1637static ArchiveFormat
1639{
1641
1643
1644 if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1645 {
1646 /* This is used by pg_dumpall, and is not documented */
1649 }
1650 else if (pg_strcasecmp(format, "c") == 0)
1652 else if (pg_strcasecmp(format, "custom") == 0)
1654 else if (pg_strcasecmp(format, "d") == 0)
1656 else if (pg_strcasecmp(format, "directory") == 0)
1658 else if (pg_strcasecmp(format, "p") == 0)
1660 else if (pg_strcasecmp(format, "plain") == 0)
1662 else if (pg_strcasecmp(format, "t") == 0)
1664 else if (pg_strcasecmp(format, "tar") == 0)
1666 else
1667 pg_fatal("invalid output format \"%s\" specified", format);
1668 return archiveFormat;
1669}
1670
1671/*
1672 * Find the OIDs of all schemas matching the given list of patterns,
1673 * and append them to the given OID list.
1674 */
1675static void
1678 SimpleOidList *oids,
1679 bool strict_names)
1680{
1681 PQExpBuffer query;
1682 PGresult *res;
1684 int i;
1685
1686 if (patterns->head == NULL)
1687 return; /* nothing to do */
1688
1689 query = createPQExpBuffer();
1690
1691 /*
1692 * The loop below runs multiple SELECTs might sometimes result in
1693 * duplicate entries in the OID list, but we don't care.
1694 */
1695
1696 for (cell = patterns->head; cell; cell = cell->next)
1697 {
1699 int dotcnt;
1700
1702 "SELECT oid FROM pg_catalog.pg_namespace n\n");
1704 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1705 false, NULL, "n.nspname", NULL, NULL, &dbbuf,
1706 &dotcnt);
1707 if (dotcnt > 1)
1708 pg_fatal("improper qualified name (too many dotted names): %s",
1709 cell->val);
1710 else if (dotcnt == 1)
1713
1714 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1715 if (strict_names && PQntuples(res) == 0)
1716 pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
1717
1718 for (i = 0; i < PQntuples(res); i++)
1719 {
1720 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1721 }
1722
1723 PQclear(res);
1724 resetPQExpBuffer(query);
1725 }
1726
1727 destroyPQExpBuffer(query);
1728}
1729
1730/*
1731 * Find the OIDs of all extensions matching the given list of patterns,
1732 * and append them to the given OID list.
1733 */
1734static void
1737 SimpleOidList *oids,
1738 bool strict_names)
1739{
1740 PQExpBuffer query;
1741 PGresult *res;
1743 int i;
1744
1745 if (patterns->head == NULL)
1746 return; /* nothing to do */
1747
1748 query = createPQExpBuffer();
1749
1750 /*
1751 * The loop below runs multiple SELECTs might sometimes result in
1752 * duplicate entries in the OID list, but we don't care.
1753 */
1754 for (cell = patterns->head; cell; cell = cell->next)
1755 {
1756 int dotcnt;
1757
1759 "SELECT oid FROM pg_catalog.pg_extension e\n");
1760 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1761 false, NULL, "e.extname", NULL, NULL, NULL,
1762 &dotcnt);
1763 if (dotcnt > 0)
1764 pg_fatal("improper qualified name (too many dotted names): %s",
1765 cell->val);
1766
1767 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1768 if (strict_names && PQntuples(res) == 0)
1769 pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
1770
1771 for (i = 0; i < PQntuples(res); i++)
1772 {
1773 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1774 }
1775
1776 PQclear(res);
1777 resetPQExpBuffer(query);
1778 }
1779
1780 destroyPQExpBuffer(query);
1781}
1782
1783/*
1784 * Find the OIDs of all foreign servers matching the given list of patterns,
1785 * and append them to the given OID list.
1786 */
1787static void
1790 SimpleOidList *oids)
1791{
1792 PQExpBuffer query;
1793 PGresult *res;
1795 int i;
1796
1797 if (patterns->head == NULL)
1798 return; /* nothing to do */
1799
1800 query = createPQExpBuffer();
1801
1802 /*
1803 * The loop below runs multiple SELECTs might sometimes result in
1804 * duplicate entries in the OID list, but we don't care.
1805 */
1806
1807 for (cell = patterns->head; cell; cell = cell->next)
1808 {
1809 int dotcnt;
1810
1812 "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
1813 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1814 false, NULL, "s.srvname", NULL, NULL, NULL,
1815 &dotcnt);
1816 if (dotcnt > 0)
1817 pg_fatal("improper qualified name (too many dotted names): %s",
1818 cell->val);
1819
1820 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1821 if (PQntuples(res) == 0)
1822 pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
1823
1824 for (i = 0; i < PQntuples(res); i++)
1825 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1826
1827 PQclear(res);
1828 resetPQExpBuffer(query);
1829 }
1830
1831 destroyPQExpBuffer(query);
1832}
1833
1834/*
1835 * Find the OIDs of all tables matching the given list of patterns,
1836 * and append them to the given OID list. See also expand_dbname_patterns()
1837 * in pg_dumpall.c
1838 */
1839static void
1843{
1844 PQExpBuffer query;
1845 PGresult *res;
1847 int i;
1848
1849 if (patterns->head == NULL)
1850 return; /* nothing to do */
1851
1852 query = createPQExpBuffer();
1853
1854 /*
1855 * this might sometimes result in duplicate entries in the OID list, but
1856 * we don't care.
1857 */
1858
1859 for (cell = patterns->head; cell; cell = cell->next)
1860 {
1862 int dotcnt;
1863
1864 /*
1865 * Query must remain ABSOLUTELY devoid of unqualified names. This
1866 * would be unnecessary given a pg_table_is_visible() variant taking a
1867 * search_path argument.
1868 *
1869 * For with_child_tables, we start with the basic query's results and
1870 * recursively search the inheritance tree to add child tables.
1871 */
1873 {
1874 appendPQExpBufferStr(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
1875 }
1876
1877 appendPQExpBuffer(query,
1878 "SELECT c.oid"
1879 "\nFROM pg_catalog.pg_class c"
1880 "\n LEFT JOIN pg_catalog.pg_namespace n"
1881 "\n ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1882 "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1883 "\n (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1888 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1889 false, "n.nspname", "c.relname", NULL,
1890 "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
1891 &dotcnt);
1892 if (dotcnt > 2)
1893 pg_fatal("improper relation name (too many dotted names): %s",
1894 cell->val);
1895 else if (dotcnt == 2)
1898
1900 {
1901 appendPQExpBufferStr(query, "UNION"
1902 "\nSELECT i.inhrelid"
1903 "\nFROM partition_tree p"
1904 "\n JOIN pg_catalog.pg_inherits i"
1905 "\n ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
1906 "\n)"
1907 "\nSELECT relid FROM partition_tree");
1908 }
1909
1910 ExecuteSqlStatement(fout, "RESET search_path");
1911 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1914 if (strict_names && PQntuples(res) == 0)
1915 pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
1916
1917 for (i = 0; i < PQntuples(res); i++)
1918 {
1919 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1920 }
1921
1922 PQclear(res);
1923 resetPQExpBuffer(query);
1924 }
1925
1926 destroyPQExpBuffer(query);
1927}
1928
1929/*
1930 * Verifies that the connected database name matches the given database name,
1931 * and if not, dies with an error about the given pattern.
1932 *
1933 * The 'dbname' argument should be a literal name parsed from 'pattern'.
1934 */
1935static void
1936prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
1937{
1938 const char *db;
1939
1940 db = PQdb(conn);
1941 if (db == NULL)
1942 pg_fatal("You are currently not connected to a database.");
1943
1944 if (strcmp(db, dbname) != 0)
1945 pg_fatal("cross-database references are not implemented: %s",
1946 pattern);
1947}
1948
1949/*
1950 * checkExtensionMembership
1951 * Determine whether object is an extension member, and if so,
1952 * record an appropriate dependency and set the object's dump flag.
1953 *
1954 * It's important to call this for each object that could be an extension
1955 * member. Generally, we integrate this with determining the object's
1956 * to-be-dumped-ness, since extension membership overrides other rules for that.
1957 *
1958 * Returns true if object is an extension member, else false.
1959 */
1960static bool
1962{
1964
1965 if (ext == NULL)
1966 return false;
1967
1968 dobj->ext_member = true;
1969
1970 /* Record dependency so that getDependencies needn't deal with that */
1971 addObjectDependency(dobj, ext->dobj.dumpId);
1972
1973 /*
1974 * In 9.6 and above, mark the member object to have any non-initial ACLs
1975 * dumped. (Any initial ACLs will be removed later, using data from
1976 * pg_init_privs, so that we'll dump only the delta from the extension's
1977 * initial setup.)
1978 *
1979 * Prior to 9.6, we do not include any extension member components.
1980 *
1981 * In binary upgrades, we still dump all components of the members
1982 * individually, since the idea is to exactly reproduce the database
1983 * contents rather than replace the extension contents with something
1984 * different.
1985 *
1986 * Note: it might be interesting someday to implement storage and delta
1987 * dumping of extension members' RLS policies and/or security labels.
1988 * However there is a pitfall for RLS policies: trying to dump them
1989 * requires getting a lock on their tables, and the calling user might not
1990 * have privileges for that. We need no lock to examine a table's ACLs,
1991 * so the current feature doesn't have a problem of that sort.
1992 */
1993 if (fout->dopt->binary_upgrade)
1994 dobj->dump = ext->dobj.dump;
1995 else
1996 {
1997 if (fout->remoteVersion < 90600)
1998 dobj->dump = DUMP_COMPONENT_NONE;
1999 else
2000 dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
2001 }
2002
2003 return true;
2004}
2005
2006/*
2007 * selectDumpableNamespace: policy-setting subroutine
2008 * Mark a namespace as to be dumped or not
2009 */
2010static void
2012{
2013 /*
2014 * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
2015 * and (for --clean) a DROP SCHEMA statement. (In the absence of
2016 * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
2017 */
2018 nsinfo->create = true;
2019
2020 /*
2021 * If specific tables are being dumped, do not dump any complete
2022 * namespaces. If specific namespaces are being dumped, dump just those
2023 * namespaces. Otherwise, dump all non-system namespaces.
2024 */
2026 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
2027 else if (schema_include_oids.head != NULL)
2028 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
2030 nsinfo->dobj.catId.oid) ?
2032 else if (fout->remoteVersion >= 90600 &&
2033 strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
2034 {
2035 /*
2036 * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
2037 * they are interesting (and not the original ACLs which were set at
2038 * initdb time, see pg_init_privs).
2039 */
2040 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
2041 }
2042 else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
2043 strcmp(nsinfo->dobj.name, "information_schema") == 0)
2044 {
2045 /* Other system schemas don't get dumped */
2046 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
2047 }
2048 else if (strcmp(nsinfo->dobj.name, "public") == 0)
2049 {
2050 /*
2051 * The public schema is a strange beast that sits in a sort of
2052 * no-mans-land between being a system object and a user object.
2053 * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
2054 * a comment and an indication of ownership. If the owner is the
2055 * default, omit that superfluous DUMP_COMPONENT_DEFINITION. Before
2056 * v15, the default owner was BOOTSTRAP_SUPERUSERID.
2057 */
2058 nsinfo->create = false;
2059 nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
2060 if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
2061 nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
2062 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
2063
2064 /*
2065 * Also, make like it has a comment even if it doesn't; this is so
2066 * that we'll emit a command to drop the comment, if appropriate.
2067 * (Without this, we'd not call dumpCommentExtended for it.)
2068 */
2069 nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
2070 }
2071 else
2072 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
2073
2074 /*
2075 * In any case, a namespace can be excluded by an exclusion switch
2076 */
2077 if (nsinfo->dobj.dump_contains &&
2079 nsinfo->dobj.catId.oid))
2080 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
2081
2082 /*
2083 * If the schema belongs to an extension, allow extension membership to
2084 * override the dump decision for the schema itself. However, this does
2085 * not change dump_contains, so this won't change what we do with objects
2086 * within the schema. (If they belong to the extension, they'll get
2087 * suppressed by it, otherwise not.)
2088 */
2090}
2091
2092/*
2093 * selectDumpableTable: policy-setting subroutine
2094 * Mark a table as to be dumped or not
2095 */
2096static void
2098{
2100 return; /* extension membership overrides all else */
2101
2102 /*
2103 * If specific tables are being dumped, dump just those tables; else, dump
2104 * according to the parent namespace's dump flag.
2105 */
2108 tbinfo->dobj.catId.oid) ?
2110 else
2111 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
2112
2113 /*
2114 * In any case, a table can be excluded by an exclusion switch
2115 */
2116 if (tbinfo->dobj.dump &&
2118 tbinfo->dobj.catId.oid))
2119 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
2120}
2121
2122/*
2123 * selectDumpableType: policy-setting subroutine
2124 * Mark a type as to be dumped or not
2125 *
2126 * If it's a table's rowtype or an autogenerated array type, we also apply a
2127 * special type code to facilitate sorting into the desired order. (We don't
2128 * want to consider those to be ordinary types because that would bring tables
2129 * up into the datatype part of the dump order.) We still set the object's
2130 * dump flag; that's not going to cause the dummy type to be dumped, but we
2131 * need it so that casts involving such types will be dumped correctly -- see
2132 * dumpCast. This means the flag should be set the same as for the underlying
2133 * object (the table or base type).
2134 */
2135static void
2137{
2138 /* skip complex types, except for standalone composite types */
2139 if (OidIsValid(tyinfo->typrelid) &&
2140 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
2141 {
2142 TableInfo *tytable = findTableByOid(tyinfo->typrelid);
2143
2144 tyinfo->dobj.objType = DO_DUMMY_TYPE;
2145 if (tytable != NULL)
2146 tyinfo->dobj.dump = tytable->dobj.dump;
2147 else
2148 tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
2149 return;
2150 }
2151
2152 /* skip auto-generated array and multirange types */
2153 if (tyinfo->isArray || tyinfo->isMultirange)
2154 {
2155 tyinfo->dobj.objType = DO_DUMMY_TYPE;
2156
2157 /*
2158 * Fall through to set the dump flag; we assume that the subsequent
2159 * rules will do the same thing as they would for the array's base
2160 * type or multirange's range type. (We cannot reliably look up the
2161 * base type here, since getTypes may not have processed it yet.)
2162 */
2163 }
2164
2166 return; /* extension membership overrides all else */
2167
2168 /* Dump based on if the contents of the namespace are being dumped */
2169 tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
2170}
2171
2172/*
2173 * selectDumpableDefaultACL: policy-setting subroutine
2174 * Mark a default ACL as to be dumped or not
2175 *
2176 * For per-schema default ACLs, dump if the schema is to be dumped.
2177 * Otherwise dump if we are dumping "everything". Note that dumpSchema
2178 * and aclsSkip are checked separately.
2179 */
2180static void
2182{
2183 /* Default ACLs can't be extension members */
2184
2185 if (dinfo->dobj.namespace)
2186 /* default ACLs are considered part of the namespace */
2187 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
2188 else
2189 dinfo->dobj.dump = dopt->include_everything ?
2191}
2192
2193/*
2194 * selectDumpableCast: policy-setting subroutine
2195 * Mark a cast as to be dumped or not
2196 *
2197 * Casts do not belong to any particular namespace (since they haven't got
2198 * names), nor do they have identifiable owners. To distinguish user-defined
2199 * casts from built-in ones, we must resort to checking whether the cast's
2200 * OID is in the range reserved for initdb.
2201 */
2202static void
2204{
2205 if (checkExtensionMembership(&cast->dobj, fout))
2206 return; /* extension membership overrides all else */
2207
2208 /*
2209 * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
2210 * support ACLs currently.
2211 */
2212 if (cast->dobj.catId.oid <= g_last_builtin_oid)
2213 cast->dobj.dump = DUMP_COMPONENT_NONE;
2214 else
2215 cast->dobj.dump = fout->dopt->include_everything ?
2217}
2218
2219/*
2220 * selectDumpableProcLang: policy-setting subroutine
2221 * Mark a procedural language as to be dumped or not
2222 *
2223 * Procedural languages do not belong to any particular namespace. To
2224 * identify built-in languages, we must resort to checking whether the
2225 * language's OID is in the range reserved for initdb.
2226 */
2227static void
2229{
2230 if (checkExtensionMembership(&plang->dobj, fout))
2231 return; /* extension membership overrides all else */
2232
2233 /*
2234 * Only include procedural languages when we are dumping everything.
2235 *
2236 * For from-initdb procedural languages, only include ACLs, as we do for
2237 * the pg_catalog namespace. We need this because procedural languages do
2238 * not live in any namespace.
2239 */
2240 if (!fout->dopt->include_everything)
2241 plang->dobj.dump = DUMP_COMPONENT_NONE;
2242 else
2243 {
2244 if (plang->dobj.catId.oid <= g_last_builtin_oid)
2245 plang->dobj.dump = fout->remoteVersion < 90600 ?
2247 else
2248 plang->dobj.dump = DUMP_COMPONENT_ALL;
2249 }
2250}
2251
2252/*
2253 * selectDumpableAccessMethod: policy-setting subroutine
2254 * Mark an access method as to be dumped or not
2255 *
2256 * Access methods do not belong to any particular namespace. To identify
2257 * built-in access methods, we must resort to checking whether the
2258 * method's OID is in the range reserved for initdb.
2259 */
2260static void
2262{
2263 /* see getAccessMethods() comment about v9.6. */
2264 if (fout->remoteVersion < 90600)
2265 {
2266 method->dobj.dump = DUMP_COMPONENT_NONE;
2267 return;
2268 }
2269
2270 if (checkExtensionMembership(&method->dobj, fout))
2271 return; /* extension membership overrides all else */
2272
2273 /*
2274 * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
2275 * they do not support ACLs currently.
2276 */
2277 if (method->dobj.catId.oid <= g_last_builtin_oid)
2278 method->dobj.dump = DUMP_COMPONENT_NONE;
2279 else
2280 method->dobj.dump = fout->dopt->include_everything ?
2282}
2283
2284/*
2285 * selectDumpableExtension: policy-setting subroutine
2286 * Mark an extension as to be dumped or not
2287 *
2288 * Built-in extensions should be skipped except for checking ACLs, since we
2289 * assume those will already be installed in the target database. We identify
2290 * such extensions by their having OIDs in the range reserved for initdb.
2291 * We dump all user-added extensions by default. No extensions are dumped
2292 * if include_everything is false (i.e., a --schema or --table switch was
2293 * given), except if --extension specifies a list of extensions to dump.
2294 */
2295static void
2297{
2298 /*
2299 * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
2300 * change permissions on their member objects, if they wish to, and have
2301 * those changes preserved.
2302 */
2303 if (extinfo->dobj.catId.oid <= g_last_builtin_oid)
2304 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
2305 else
2306 {
2307 /* check if there is a list of extensions to dump */
2309 extinfo->dobj.dump = extinfo->dobj.dump_contains =
2311 extinfo->dobj.catId.oid) ?
2313 else
2314 extinfo->dobj.dump = extinfo->dobj.dump_contains =
2315 dopt->include_everything ?
2317
2318 /* check that the extension is not explicitly excluded */
2319 if (extinfo->dobj.dump &&
2321 extinfo->dobj.catId.oid))
2322 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
2323 }
2324}
2325
2326/*
2327 * selectDumpablePublicationObject: policy-setting subroutine
2328 * Mark a publication object as to be dumped or not
2329 *
2330 * A publication can have schemas and tables which have schemas, but those are
2331 * ignored in decision making, because publications are only dumped when we are
2332 * dumping everything.
2333 */
2334static void
2336{
2337 if (checkExtensionMembership(dobj, fout))
2338 return; /* extension membership overrides all else */
2339
2340 dobj->dump = fout->dopt->include_everything ?
2342}
2343
2344/*
2345 * selectDumpableStatisticsObject: policy-setting subroutine
2346 * Mark an extended statistics object as to be dumped or not
2347 *
2348 * We dump an extended statistics object if the schema it's in and the table
2349 * it's for are being dumped. (This'll need more thought if statistics
2350 * objects ever support cross-table stats.)
2351 */
2352static void
2354{
2355 if (checkExtensionMembership(&sobj->dobj, fout))
2356 return; /* extension membership overrides all else */
2357
2358 sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
2359 if (sobj->stattable == NULL ||
2360 !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
2361 sobj->dobj.dump = DUMP_COMPONENT_NONE;
2362}
2363
2364/*
2365 * selectDumpableObject: policy-setting subroutine
2366 * Mark a generic dumpable object as to be dumped or not
2367 *
2368 * Use this only for object types without a special-case routine above.
2369 */
2370static void
2372{
2373 if (checkExtensionMembership(dobj, fout))
2374 return; /* extension membership overrides all else */
2375
2376 /*
2377 * Default policy is to dump if parent namespace is dumpable, or for
2378 * non-namespace-associated items, dump if we're dumping "everything".
2379 */
2380 if (dobj->namespace)
2381 dobj->dump = dobj->namespace->dobj.dump_contains;
2382 else
2383 dobj->dump = fout->dopt->include_everything ?
2385}
2386
2387/*
2388 * Dump a table's contents for loading using the COPY command
2389 * - this routine is called by the Archiver when it wants the table
2390 * to be dumped.
2391 */
2392static int
2394{
2395 const TableDataInfo *tdinfo = dcontext;
2396 const TableInfo *tbinfo = tdinfo->tdtable;
2397 const char *classname = tbinfo->dobj.name;
2399
2400 /*
2401 * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
2402 * which uses it already.
2403 */
2406 PGresult *res;
2407 int ret;
2408 char *copybuf;
2409 const char *column_list;
2410
2411 pg_log_info("dumping contents of table \"%s.%s\"",
2412 tbinfo->dobj.namespace->dobj.name, classname);
2413
2414 /*
2415 * Specify the column list explicitly so that we have no possibility of
2416 * retrieving data in the wrong column order. (The default column
2417 * ordering of COPY will not be what we want in certain corner cases
2418 * involving ADD COLUMN and inheritance.)
2419 */
2421
2422 /*
2423 * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
2424 * a filter condition was specified. For other cases a simple COPY
2425 * suffices.
2426 */
2427 if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2428 {
2429 /* Temporary allows to access to foreign tables to dump data */
2430 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2432
2433 appendPQExpBufferStr(q, "COPY (SELECT ");
2434 /* klugery to get rid of parens in column list */
2435 if (strlen(column_list) > 2)
2436 {
2438 q->data[q->len - 1] = ' ';
2439 }
2440 else
2441 appendPQExpBufferStr(q, "* ");
2442
2443 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
2445 tdinfo->filtercond ? tdinfo->filtercond : "");
2446 }
2447 else
2448 {
2449 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
2451 column_list);
2452 }
2454 PQclear(res);
2456
2457 for (;;)
2458 {
2459 ret = PQgetCopyData(conn, &copybuf, 0);
2460
2461 if (ret < 0)
2462 break; /* done or error */
2463
2464 if (copybuf)
2465 {
2466 WriteData(fout, copybuf, ret);
2468 }
2469
2470 /* ----------
2471 * THROTTLE:
2472 *
2473 * There was considerable discussion in late July, 2000 regarding
2474 * slowing down pg_dump when backing up large tables. Users with both
2475 * slow & fast (multi-processor) machines experienced performance
2476 * degradation when doing a backup.
2477 *
2478 * Initial attempts based on sleeping for a number of ms for each ms
2479 * of work were deemed too complex, then a simple 'sleep in each loop'
2480 * implementation was suggested. The latter failed because the loop
2481 * was too tight. Finally, the following was implemented:
2482 *
2483 * If throttle is non-zero, then
2484 * See how long since the last sleep.
2485 * Work out how long to sleep (based on ratio).
2486 * If sleep is more than 100ms, then
2487 * sleep
2488 * reset timer
2489 * EndIf
2490 * EndIf
2491 *
2492 * where the throttle value was the number of ms to sleep per ms of
2493 * work. The calculation was done in each loop.
2494 *
2495 * Most of the hard work is done in the backend, and this solution
2496 * still did not work particularly well: on slow machines, the ratio
2497 * was 50:1, and on medium paced machines, 1:1, and on fast
2498 * multi-processor machines, it had little or no effect, for reasons
2499 * that were unclear.
2500 *
2501 * Further discussion ensued, and the proposal was dropped.
2502 *
2503 * For those people who want this feature, it can be implemented using
2504 * gettimeofday in each loop, calculating the time since last sleep,
2505 * multiplying that by the sleep ratio, then if the result is more
2506 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
2507 * function to sleep for a subsecond period ie.
2508 *
2509 * select(0, NULL, NULL, NULL, &tvi);
2510 *
2511 * This will return after the interval specified in the structure tvi.
2512 * Finally, call gettimeofday again to save the 'last sleep time'.
2513 * ----------
2514 */
2515 }
2516 archprintf(fout, "\\.\n\n\n");
2517
2518 if (ret == -2)
2519 {
2520 /* copy data transfer failed */
2521 pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
2522 pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2523 pg_log_error_detail("Command was: %s", q->data);
2524 exit_nicely(1);
2525 }
2526
2527 /* Check command status and return to normal libpq state */
2528 res = PQgetResult(conn);
2529 if (PQresultStatus(res) != PGRES_COMMAND_OK)
2530 {
2531 pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
2532 pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2533 pg_log_error_detail("Command was: %s", q->data);
2534 exit_nicely(1);
2535 }
2536 PQclear(res);
2537
2538 /* Do this to ensure we've pumped libpq back to idle state */
2539 if (PQgetResult(conn) != NULL)
2540 pg_log_warning("unexpected extra results during COPY of table \"%s\"",
2541 classname);
2542
2544
2545 /* Revert back the setting */
2546 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2547 set_restrict_relation_kind(fout, "view, foreign-table");
2548
2549 return 1;
2550}
2551
2552/*
2553 * Dump table data using INSERT commands.
2554 *
2555 * Caution: when we restore from an archive file direct to database, the
2556 * INSERT commands emitted by this function have to be parsed by
2557 * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
2558 * E'' strings, or dollar-quoted strings. So don't emit anything like that.
2559 */
2560static int
2562{
2563 const TableDataInfo *tdinfo = dcontext;
2564 const TableInfo *tbinfo = tdinfo->tdtable;
2565 DumpOptions *dopt = fout->dopt;
2568 char *attgenerated;
2569 PGresult *res;
2570 int nfields,
2571 i;
2572 int rows_per_statement = dopt->dump_inserts;
2573 int rows_this_statement = 0;
2574
2575 /* Temporary allows to access to foreign tables to dump data */
2576 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2578
2579 /*
2580 * If we're going to emit INSERTs with column names, the most efficient
2581 * way to deal with generated columns is to exclude them entirely. For
2582 * INSERTs without column names, we have to emit DEFAULT rather than the
2583 * actual column value --- but we can save a few cycles by fetching nulls
2584 * rather than the uninteresting-to-us value.
2585 */
2586 attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
2587 appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
2588 nfields = 0;
2589 for (i = 0; i < tbinfo->numatts; i++)
2590 {
2591 if (tbinfo->attisdropped[i])
2592 continue;
2593 if (tbinfo->attgenerated[i] && dopt->column_inserts)
2594 continue;
2595 if (nfields > 0)
2596 appendPQExpBufferStr(q, ", ");
2597 if (tbinfo->attgenerated[i])
2598 appendPQExpBufferStr(q, "NULL");
2599 else
2600 appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
2601 attgenerated[nfields] = tbinfo->attgenerated[i];
2602 nfields++;
2603 }
2604 /* Servers before 9.4 will complain about zero-column SELECT */
2605 if (nfields == 0)
2606 appendPQExpBufferStr(q, "NULL");
2607 appendPQExpBuffer(q, " FROM ONLY %s",
2609 if (tdinfo->filtercond)
2610 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
2611
2613
2614 while (1)
2615 {
2616 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
2618
2619 /* cross-check field count, allowing for dummy NULL if any */
2620 if (nfields != PQnfields(res) &&
2621 !(nfields == 0 && PQnfields(res) == 1))
2622 pg_fatal("wrong number of fields retrieved from table \"%s\"",
2623 tbinfo->dobj.name);
2624
2625 /*
2626 * First time through, we build as much of the INSERT statement as
2627 * possible in "insertStmt", which we can then just print for each
2628 * statement. If the table happens to have zero dumpable columns then
2629 * this will be a complete statement, otherwise it will end in
2630 * "VALUES" and be ready to have the row's column values printed.
2631 */
2632 if (insertStmt == NULL)
2633 {
2634 const TableInfo *targettab;
2635
2637
2638 /*
2639 * When load-via-partition-root is set or forced, get the root
2640 * table name for the partition table, so that we can reload data
2641 * through the root table.
2642 */
2643 if (tbinfo->ispartition &&
2644 (dopt->load_via_partition_root ||
2647 else
2648 targettab = tbinfo;
2649
2650 appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
2652
2653 /* corner case for zero-column table */
2654 if (nfields == 0)
2655 {
2656 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
2657 }
2658 else
2659 {
2660 /* append the list of column names if required */
2661 if (dopt->column_inserts)
2662 {
2664 for (int field = 0; field < nfields; field++)
2665 {
2666 if (field > 0)
2669 fmtId(PQfname(res, field)));
2670 }
2672 }
2673
2674 if (tbinfo->needs_override)
2675 appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
2676
2678 }
2679 }
2680
2681 for (int tuple = 0; tuple < PQntuples(res); tuple++)
2682 {
2683 /* Write the INSERT if not in the middle of a multi-row INSERT. */
2684 if (rows_this_statement == 0)
2685 archputs(insertStmt->data, fout);
2686
2687 /*
2688 * If it is zero-column table then we've already written the
2689 * complete statement, which will mean we've disobeyed
2690 * --rows-per-insert when it's set greater than 1. We do support
2691 * a way to make this multi-row with: SELECT UNION ALL SELECT
2692 * UNION ALL ... but that's non-standard so we should avoid it
2693 * given that using INSERTs is mostly only ever needed for
2694 * cross-database exports.
2695 */
2696 if (nfields == 0)
2697 continue;
2698
2699 /* Emit a row heading */
2700 if (rows_per_statement == 1)
2701 archputs(" (", fout);
2702 else if (rows_this_statement > 0)
2703 archputs(",\n\t(", fout);
2704 else
2705 archputs("\n\t(", fout);
2706
2707 for (int field = 0; field < nfields; field++)
2708 {
2709 if (field > 0)
2710 archputs(", ", fout);
2711 if (attgenerated[field])
2712 {
2713 archputs("DEFAULT", fout);
2714 continue;
2715 }
2716 if (PQgetisnull(res, tuple, field))
2717 {
2718 archputs("NULL", fout);
2719 continue;
2720 }
2721
2722 /* XXX This code is partially duplicated in ruleutils.c */
2723 switch (PQftype(res, field))
2724 {
2725 case INT2OID:
2726 case INT4OID:
2727 case INT8OID:
2728 case OIDOID:
2729 case FLOAT4OID:
2730 case FLOAT8OID:
2731 case NUMERICOID:
2732 {
2733 /*
2734 * These types are printed without quotes unless
2735 * they contain values that aren't accepted by the
2736 * scanner unquoted (e.g., 'NaN'). Note that
2737 * strtod() and friends might accept NaN, so we
2738 * can't use that to test.
2739 *
2740 * In reality we only need to defend against
2741 * infinity and NaN, so we need not get too crazy
2742 * about pattern matching here.
2743 */
2744 const char *s = PQgetvalue(res, tuple, field);
2745
2746 if (strspn(s, "0123456789 +-eE.") == strlen(s))
2747 archputs(s, fout);
2748 else
2749 archprintf(fout, "'%s'", s);
2750 }
2751 break;
2752
2753 case BITOID:
2754 case VARBITOID:
2755 archprintf(fout, "B'%s'",
2756 PQgetvalue(res, tuple, field));
2757 break;
2758
2759 case BOOLOID:
2760 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2761 archputs("true", fout);
2762 else
2763 archputs("false", fout);
2764 break;
2765
2766 default:
2767 /* All other types are printed as string literals. */
2770 PQgetvalue(res, tuple, field),
2771 fout);
2772 archputs(q->data, fout);
2773 break;
2774 }
2775 }
2776
2777 /* Terminate the row ... */
2778 archputs(")", fout);
2779
2780 /* ... and the statement, if the target no. of rows is reached */
2782 {
2783 if (dopt->do_nothing)
2784 archputs(" ON CONFLICT DO NOTHING;\n", fout);
2785 else
2786 archputs(";\n", fout);
2787 /* Reset the row counter */
2789 }
2790 }
2791
2792 if (PQntuples(res) <= 0)
2793 {
2794 PQclear(res);
2795 break;
2796 }
2797 PQclear(res);
2798 }
2799
2800 /* Terminate any statements that didn't make the row count. */
2801 if (rows_this_statement > 0)
2802 {
2803 if (dopt->do_nothing)
2804 archputs(" ON CONFLICT DO NOTHING;\n", fout);
2805 else
2806 archputs(";\n", fout);
2807 }
2808
2809 archputs("\n\n", fout);
2810
2811 ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2812
2814 if (insertStmt != NULL)
2816 free(attgenerated);
2817
2818 /* Revert back the setting */
2819 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2820 set_restrict_relation_kind(fout, "view, foreign-table");
2821
2822 return 1;
2823}
2824
2825/*
2826 * getRootTableInfo:
2827 * get the root TableInfo for the given partition table.
2828 */
2829static TableInfo *
2831{
2833
2834 Assert(tbinfo->ispartition);
2835 Assert(tbinfo->numParents == 1);
2836
2837 parentTbinfo = tbinfo->parents[0];
2838 while (parentTbinfo->ispartition)
2839 {
2840 Assert(parentTbinfo->numParents == 1);
2841 parentTbinfo = parentTbinfo->parents[0];
2842 }
2843
2844 return parentTbinfo;
2845}
2846
2847/*
2848 * forcePartitionRootLoad
2849 * Check if we must force load_via_partition_root for this partition.
2850 *
2851 * This is required if any level of ancestral partitioned table has an
2852 * unsafe partitioning scheme.
2853 */
2854static bool
2856{
2858
2859 Assert(tbinfo->ispartition);
2860 Assert(tbinfo->numParents == 1);
2861
2862 parentTbinfo = tbinfo->parents[0];
2863 if (parentTbinfo->unsafe_partitions)
2864 return true;
2865 while (parentTbinfo->ispartition)
2866 {
2867 Assert(parentTbinfo->numParents == 1);
2868 parentTbinfo = parentTbinfo->parents[0];
2869 if (parentTbinfo->unsafe_partitions)
2870 return true;
2871 }
2872
2873 return false;
2874}
2875
2876/*
2877 * dumpTableData -
2878 * dump the contents of a single table
2879 *
2880 * Actually, this just makes an ArchiveEntry for the table contents.
2881 */
2882static void
2884{
2885 DumpOptions *dopt = fout->dopt;
2886 const TableInfo *tbinfo = tdinfo->tdtable;
2889 DataDumperPtr dumpFn;
2890 char *tdDefn = NULL;
2891 char *copyStmt;
2892 const char *copyFrom;
2893
2894 /* We had better have loaded per-column details about this table */
2895 Assert(tbinfo->interesting);
2896
2897 /*
2898 * When load-via-partition-root is set or forced, get the root table name
2899 * for the partition table, so that we can reload data through the root
2900 * table. Then construct a comment to be inserted into the TOC entry's
2901 * defn field, so that such cases can be identified reliably.
2902 */
2903 if (tbinfo->ispartition &&
2904 (dopt->load_via_partition_root ||
2906 {
2907 const TableInfo *parentTbinfo;
2908 char *sanitized;
2909
2913 printfPQExpBuffer(copyBuf, "-- load via partition root %s",
2914 sanitized);
2915 free(sanitized);
2916 tdDefn = pg_strdup(copyBuf->data);
2917 }
2918 else
2920
2921 if (dopt->dump_inserts == 0)
2922 {
2923 /* Dump/restore using COPY */
2924 dumpFn = dumpTableData_copy;
2925 /* must use 2 steps here 'cause fmtId is nonreentrant */
2926 printfPQExpBuffer(copyBuf, "COPY %s ",
2927 copyFrom);
2928 appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2930 copyStmt = copyBuf->data;
2931 }
2932 else
2933 {
2934 /* Restore using INSERT */
2935 dumpFn = dumpTableData_insert;
2936 copyStmt = NULL;
2937 }
2938
2939 /*
2940 * Note: although the TableDataInfo is a full DumpableObject, we treat its
2941 * dependency on its table as "special" and pass it to ArchiveEntry now.
2942 * See comments for BuildArchiveDependencies.
2943 */
2944 if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2945 {
2946 TocEntry *te;
2947
2948 te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2949 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2950 .namespace = tbinfo->dobj.namespace->dobj.name,
2951 .owner = tbinfo->rolname,
2952 .description = "TABLE DATA",
2953 .section = SECTION_DATA,
2954 .createStmt = tdDefn,
2955 .copyStmt = copyStmt,
2956 .deps = &(tbinfo->dobj.dumpId),
2957 .nDeps = 1,
2958 .dumpFn = dumpFn,
2959 .dumpArg = tdinfo));
2960
2961 /*
2962 * Set the TocEntry's dataLength in case we are doing a parallel dump
2963 * and want to order dump jobs by table size. We choose to measure
2964 * dataLength in table pages (including TOAST pages) during dump, so
2965 * no scaling is needed.
2966 *
2967 * However, relpages is declared as "integer" in pg_class, and hence
2968 * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2969 * Cast so that we get the right interpretation of table sizes
2970 * exceeding INT_MAX pages.
2971 */
2972 te->dataLength = (BlockNumber) tbinfo->relpages;
2973 te->dataLength += (BlockNumber) tbinfo->toastpages;
2974
2975 /*
2976 * If pgoff_t is only 32 bits wide, the above refinement is useless,
2977 * and instead we'd better worry about integer overflow. Clamp to
2978 * INT_MAX if the correct result exceeds that.
2979 */
2980 if (sizeof(te->dataLength) == 4 &&
2981 (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
2982 te->dataLength < 0))
2983 te->dataLength = INT_MAX;
2984 }
2985
2988}
2989
2990/*
2991 * refreshMatViewData -
2992 * load or refresh the contents of a single materialized view
2993 *
2994 * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2995 * statement.
2996 */
2997static void
2999{
3000 TableInfo *tbinfo = tdinfo->tdtable;
3001 PQExpBuffer q;
3002
3003 /* If the materialized view is not flagged as populated, skip this. */
3004 if (!tbinfo->relispopulated)
3005 return;
3006
3007 q = createPQExpBuffer();
3008
3009 appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
3011
3012 if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
3014 tdinfo->dobj.catId, /* catalog ID */
3015 tdinfo->dobj.dumpId, /* dump ID */
3016 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
3017 .namespace = tbinfo->dobj.namespace->dobj.name,
3018 .owner = tbinfo->rolname,
3019 .description = "MATERIALIZED VIEW DATA",
3020 .section = SECTION_POST_DATA,
3021 .createStmt = q->data,
3022 .deps = tdinfo->dobj.dependencies,
3023 .nDeps = tdinfo->dobj.nDeps));
3024
3026}
3027
3028/*
3029 * getTableData -
3030 * set up dumpable objects representing the contents of tables
3031 */
3032static void
3033getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
3034{
3035 int i;
3036
3037 for (i = 0; i < numTables; i++)
3038 {
3039 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
3040 (!relkind || tblinfo[i].relkind == relkind))
3041 makeTableDataInfo(dopt, &(tblinfo[i]));
3042 }
3043}
3044
3045/*
3046 * Make a dumpable object for the data of this specific table
3047 *
3048 * Note: we make a TableDataInfo if and only if we are going to dump the
3049 * table data; the "dump" field in such objects isn't very interesting.
3050 */
3051static void
3053{
3055
3056 /*
3057 * Nothing to do if we already decided to dump the table. This will
3058 * happen for "config" tables.
3059 */
3060 if (tbinfo->dataObj != NULL)
3061 return;
3062
3063 /* Skip VIEWs (no data to dump) */
3064 if (tbinfo->relkind == RELKIND_VIEW)
3065 return;
3066 /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
3067 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
3070 tbinfo->foreign_server)))
3071 return;
3072 /* Skip partitioned tables (data in partitions) */
3073 if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
3074 return;
3075
3076 /* Don't dump data in unlogged tables, if so requested */
3077 if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
3079 return;
3080
3081 /* Check that the data is not explicitly excluded */
3083 tbinfo->dobj.catId.oid))
3084 return;
3085
3086 /* OK, let's dump it */
3088
3089 if (tbinfo->relkind == RELKIND_MATVIEW)
3091 else if (tbinfo->relkind == RELKIND_SEQUENCE)
3092 tdinfo->dobj.objType = DO_SEQUENCE_SET;
3093 else
3094 tdinfo->dobj.objType = DO_TABLE_DATA;
3095
3096 /*
3097 * Note: use tableoid 0 so that this object won't be mistaken for
3098 * something that pg_depend entries apply to.
3099 */
3100 tdinfo->dobj.catId.tableoid = 0;
3101 tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3102 AssignDumpId(&tdinfo->dobj);
3103 tdinfo->dobj.name = tbinfo->dobj.name;
3104 tdinfo->dobj.namespace = tbinfo->dobj.namespace;
3105 tdinfo->tdtable = tbinfo;
3106 tdinfo->filtercond = NULL; /* might get set later */
3107 addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
3108
3109 /* A TableDataInfo contains data, of course */
3110 tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
3111
3112 tbinfo->dataObj = tdinfo;
3113
3114 /*
3115 * Materialized view statistics must be restored after the data, because
3116 * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
3117 *
3118 * The dependency is added here because the statistics objects are created
3119 * first.
3120 */
3121 if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
3122 {
3123 tbinfo->stats->section = SECTION_POST_DATA;
3124 addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
3125 }
3126
3127 /* Make sure that we'll collect per-column info for this table. */
3128 tbinfo->interesting = true;
3129}
3130
3131/*
3132 * The refresh for a materialized view must be dependent on the refresh for
3133 * any materialized view that this one is dependent on.
3134 *
3135 * This must be called after all the objects are created, but before they are
3136 * sorted.
3137 */
3138static void
3140{
3141 PQExpBuffer query;
3142 PGresult *res;
3143 int ntups,
3144 i;
3145 int i_classid,
3146 i_objid,
3147 i_refobjid;
3148
3149 /* No Mat Views before 9.3. */
3150 if (fout->remoteVersion < 90300)
3151 return;
3152
3153 query = createPQExpBuffer();
3154
3155 appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
3156 "( "
3157 "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
3158 "FROM pg_depend d1 "
3159 "JOIN pg_class c1 ON c1.oid = d1.objid "
3160 "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
3161 " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
3162 "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
3163 "AND d2.objid = r1.oid "
3164 "AND d2.refobjid <> d1.objid "
3165 "JOIN pg_class c2 ON c2.oid = d2.refobjid "
3166 "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
3168 "WHERE d1.classid = 'pg_class'::regclass "
3169 "UNION "
3170 "SELECT w.objid, d3.refobjid, c3.relkind "
3171 "FROM w "
3172 "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
3173 "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
3174 "AND d3.objid = r3.oid "
3175 "AND d3.refobjid <> w.refobjid "
3176 "JOIN pg_class c3 ON c3.oid = d3.refobjid "
3177 "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
3179 ") "
3180 "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
3181 "FROM w "
3182 "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
3183
3184 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3185
3186 ntups = PQntuples(res);
3187
3188 i_classid = PQfnumber(res, "classid");
3189 i_objid = PQfnumber(res, "objid");
3190 i_refobjid = PQfnumber(res, "refobjid");
3191
3192 for (i = 0; i < ntups; i++)
3193 {
3194 CatalogId objId;
3196 DumpableObject *dobj;
3200
3201 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
3202 objId.oid = atooid(PQgetvalue(res, i, i_objid));
3203 refobjId.tableoid = objId.tableoid;
3204 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
3205
3206 dobj = findObjectByCatalogId(objId);
3207 if (dobj == NULL)
3208 continue;
3209
3210 Assert(dobj->objType == DO_TABLE);
3211 tbinfo = (TableInfo *) dobj;
3212 Assert(tbinfo->relkind == RELKIND_MATVIEW);
3213 dobj = (DumpableObject *) tbinfo->dataObj;
3214 if (dobj == NULL)
3215 continue;
3217
3219 if (refdobj == NULL)
3220 continue;
3221
3222 Assert(refdobj->objType == DO_TABLE);
3224 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
3225 refdobj = (DumpableObject *) reftbinfo->dataObj;
3226 if (refdobj == NULL)
3227 continue;
3228 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
3229
3230 addObjectDependency(dobj, refdobj->dumpId);
3231
3232 if (!reftbinfo->relispopulated)
3233 tbinfo->relispopulated = false;
3234 }
3235
3236 PQclear(res);
3237
3238 destroyPQExpBuffer(query);
3239}
3240
3241/*
3242 * getTableDataFKConstraints -
3243 * add dump-order dependencies reflecting foreign key constraints
3244 *
3245 * This code is executed only in a data-only dump --- in schema+data dumps
3246 * we handle foreign key issues by not creating the FK constraints until
3247 * after the data is loaded. In a data-only dump, however, we want to
3248 * order the table data objects in such a way that a table's referenced
3249 * tables are restored first. (In the presence of circular references or
3250 * self-references this may be impossible; we'll detect and complain about
3251 * that during the dependency sorting step.)
3252 */
3253static void
3255{
3257 int numObjs;
3258 int i;
3259
3260 /* Search through all the dumpable objects for FK constraints */
3262 for (i = 0; i < numObjs; i++)
3263 {
3264 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
3265 {
3268
3269 /* Not interesting unless both tables are to be dumped */
3270 if (cinfo->contable == NULL ||
3271 cinfo->contable->dataObj == NULL)
3272 continue;
3273 ftable = findTableByOid(cinfo->confrelid);
3274 if (ftable == NULL ||
3275 ftable->dataObj == NULL)
3276 continue;
3277
3278 /*
3279 * Okay, make referencing table's TABLE_DATA object depend on the
3280 * referenced table's TABLE_DATA object.
3281 */
3282 addObjectDependency(&cinfo->contable->dataObj->dobj,
3283 ftable->dataObj->dobj.dumpId);
3284 }
3285 }
3286 free(dobjs);
3287}
3288
3289
3290/*
3291 * dumpDatabase:
3292 * dump the database definition
3293 */
3294static void
3296{
3297 DumpOptions *dopt = fout->dopt;
3303 PGresult *res;
3304 int i_tableoid,
3305 i_oid,
3306 i_datname,
3307 i_datdba,
3308 i_encoding,
3310 i_collate,
3311 i_ctype,
3315 i_minmxid,
3316 i_datacl,
3325 const char *datname,
3326 *dba,
3327 *encoding,
3329 *collate,
3330 *ctype,
3331 *locale,
3332 *icurules,
3334 *datconnlimit,
3335 *tablespace;
3336 uint32 frozenxid,
3337 minmxid;
3338 char *qdatname;
3339
3340 pg_log_info("saving database definition");
3341
3342 /*
3343 * Fetch the database-level properties for this database.
3344 */
3345 appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
3346 "datdba, "
3347 "pg_encoding_to_char(encoding) AS encoding, "
3348 "datcollate, datctype, datfrozenxid, "
3349 "datacl, acldefault('d', datdba) AS acldefault, "
3350 "datistemplate, datconnlimit, ");
3351 if (fout->remoteVersion >= 90300)
3352 appendPQExpBufferStr(dbQry, "datminmxid, ");
3353 else
3354 appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
3355 if (fout->remoteVersion >= 170000)
3356 appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
3357 else if (fout->remoteVersion >= 150000)
3358 appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
3359 else
3360 appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
3361 if (fout->remoteVersion >= 160000)
3362 appendPQExpBufferStr(dbQry, "daticurules, ");
3363 else
3364 appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
3366 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
3367 "shobj_description(oid, 'pg_database') AS description "
3368 "FROM pg_database "
3369 "WHERE datname = current_database()");
3370
3372
3373 i_tableoid = PQfnumber(res, "tableoid");
3374 i_oid = PQfnumber(res, "oid");
3375 i_datname = PQfnumber(res, "datname");
3376 i_datdba = PQfnumber(res, "datdba");
3377 i_encoding = PQfnumber(res, "encoding");
3378 i_datlocprovider = PQfnumber(res, "datlocprovider");
3379 i_collate = PQfnumber(res, "datcollate");
3380 i_ctype = PQfnumber(res, "datctype");
3381 i_datlocale = PQfnumber(res, "datlocale");
3382 i_daticurules = PQfnumber(res, "daticurules");
3383 i_frozenxid = PQfnumber(res, "datfrozenxid");
3384 i_minmxid = PQfnumber(res, "datminmxid");
3385 i_datacl = PQfnumber(res, "datacl");
3386 i_acldefault = PQfnumber(res, "acldefault");
3387 i_datistemplate = PQfnumber(res, "datistemplate");
3388 i_datconnlimit = PQfnumber(res, "datconnlimit");
3389 i_datcollversion = PQfnumber(res, "datcollversion");
3390 i_tablespace = PQfnumber(res, "tablespace");
3391
3392 dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
3393 dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
3394 datname = PQgetvalue(res, 0, i_datname);
3395 dba = getRoleName(PQgetvalue(res, 0, i_datdba));
3396 encoding = PQgetvalue(res, 0, i_encoding);
3398 collate = PQgetvalue(res, 0, i_collate);
3399 ctype = PQgetvalue(res, 0, i_ctype);
3400 if (!PQgetisnull(res, 0, i_datlocale))
3401 locale = PQgetvalue(res, 0, i_datlocale);
3402 else
3403 locale = NULL;
3404 if (!PQgetisnull(res, 0, i_daticurules))
3406 else
3407 icurules = NULL;
3408 frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
3409 minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
3410 dbdacl.acl = PQgetvalue(res, 0, i_datacl);
3411 dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
3415
3417
3418 /*
3419 * Prepare the CREATE DATABASE command. We must specify OID (if we want
3420 * to preserve that), as well as the encoding, locale, and tablespace
3421 * since those can't be altered later. Other DB properties are left to
3422 * the DATABASE PROPERTIES entry, so that they can be applied after
3423 * reconnecting to the target DB.
3424 *
3425 * For binary upgrade, we use the FILE_COPY strategy because testing has
3426 * shown it to be faster. When the server is in binary upgrade mode, it
3427 * will also skip the checkpoints this strategy ordinarily performs.
3428 */
3429 if (dopt->binary_upgrade)
3430 {
3432 "CREATE DATABASE %s WITH TEMPLATE = template0 "
3433 "OID = %u STRATEGY = FILE_COPY",
3434 qdatname, dbCatId.oid);
3435 }
3436 else
3437 {
3438 appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
3439 qdatname);
3440 }
3441 if (strlen(encoding) > 0)
3442 {
3443 appendPQExpBufferStr(creaQry, " ENCODING = ");
3445 }
3446
3447 appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
3448 if (datlocprovider[0] == 'b')
3449 appendPQExpBufferStr(creaQry, "builtin");
3450 else if (datlocprovider[0] == 'c')
3452 else if (datlocprovider[0] == 'i')
3454 else
3455 pg_fatal("unrecognized locale provider: %s",
3457
3458 if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
3459 {
3460 appendPQExpBufferStr(creaQry, " LOCALE = ");
3462 }
3463 else
3464 {
3465 if (strlen(collate) > 0)
3466 {
3467 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
3469 }
3470 if (strlen(ctype) > 0)
3471 {
3472 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
3474 }
3475 }
3476 if (locale)
3477 {
3478 if (datlocprovider[0] == 'b')
3479 appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
3480 else
3481 appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
3482
3484 }
3485
3486 if (icurules)
3487 {
3488 appendPQExpBufferStr(creaQry, " ICU_RULES = ");
3490 }
3491
3492 /*
3493 * For binary upgrade, carry over the collation version. For normal
3494 * dump/restore, omit the version, so that it is computed upon restore.
3495 */
3496 if (dopt->binary_upgrade)
3497 {
3498 if (!PQgetisnull(res, 0, i_datcollversion))
3499 {
3500 appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
3503 fout);
3504 }
3505 }
3506
3507 /*
3508 * Note: looking at dopt->outputNoTablespaces here is completely the wrong
3509 * thing; the decision whether to specify a tablespace should be left till
3510 * pg_restore, so that pg_restore --no-tablespaces applies. Ideally we'd
3511 * label the DATABASE entry with the tablespace and let the normal
3512 * tablespace selection logic work ... but CREATE DATABASE doesn't pay
3513 * attention to default_tablespace, so that won't work.
3514 */
3515 if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
3516 !dopt->outputNoTablespaces)
3517 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
3518 fmtId(tablespace));
3520
3521 appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
3522 qdatname);
3523
3525
3527 dbCatId, /* catalog ID */
3528 dbDumpId, /* dump ID */
3529 ARCHIVE_OPTS(.tag = datname,
3530 .owner = dba,
3531 .description = "DATABASE",
3532 .section = SECTION_PRE_DATA,
3533 .createStmt = creaQry->data,
3534 .dropStmt = delQry->data));
3535
3536 /* Compute correct tag for archive entry */
3537 appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
3538
3539 /* Dump DB comment if any */
3540 {
3541 /*
3542 * 8.2 and up keep comments on shared objects in a shared table, so we
3543 * cannot use the dumpComment() code used for other database objects.
3544 * Be careful that the ArchiveEntry parameters match that function.
3545 */
3546 char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
3547
3548 if (comment && *comment && !dopt->no_comments)
3549 {
3551
3552 /*
3553 * Generates warning when loaded into a differently-named
3554 * database.
3555 */
3556 appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
3559
3561 ARCHIVE_OPTS(.tag = labelq->data,
3562 .owner = dba,
3563 .description = "COMMENT",
3564 .section = SECTION_NONE,
3565 .createStmt = dbQry->data,
3566 .deps = &dbDumpId,
3567 .nDeps = 1));
3568 }
3569 }
3570
3571 /* Dump DB security label, if enabled */
3572 if (!dopt->no_security_labels)
3573 {
3574 PGresult *shres;
3576
3578
3579 buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
3583 if (seclabelQry->len > 0)
3585 ARCHIVE_OPTS(.tag = labelq->data,
3586 .owner = dba,
3587 .description = "SECURITY LABEL",
3588 .section = SECTION_NONE,
3589 .createStmt = seclabelQry->data,
3590 .deps = &dbDumpId,
3591 .nDeps = 1));
3593 PQclear(shres);
3594 }
3595
3596 /*
3597 * Dump ACL if any. Note that we do not support initial privileges
3598 * (pg_init_privs) on databases.
3599 */
3600 dbdacl.privtype = 0;
3601 dbdacl.initprivs = NULL;
3602
3603 dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
3604 qdatname, NULL, NULL,
3605 NULL, dba, &dbdacl);
3606
3607 /*
3608 * Now construct a DATABASE PROPERTIES archive entry to restore any
3609 * non-default database-level properties. (The reason this must be
3610 * separate is that we cannot put any additional commands into the TOC
3611 * entry that has CREATE DATABASE. pg_restore would execute such a group
3612 * in an implicit transaction block, and the backend won't allow CREATE
3613 * DATABASE in that context.)
3614 */
3617
3618 if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
3619 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
3621
3622 if (strcmp(datistemplate, "t") == 0)
3623 {
3624 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
3625 qdatname);
3626
3627 /*
3628 * The backend won't accept DROP DATABASE on a template database. We
3629 * can deal with that by removing the template marking before the DROP
3630 * gets issued. We'd prefer to use ALTER DATABASE IF EXISTS here, but
3631 * since no such command is currently supported, fake it with a direct
3632 * UPDATE on pg_database.
3633 */
3634 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
3635 "SET datistemplate = false WHERE datname = ");
3638 }
3639
3640 /*
3641 * We do not restore pg_database.dathasloginevt because it is set
3642 * automatically on login event trigger creation.
3643 */
3644
3645 /* Add database-specific SET options */
3647
3648 /*
3649 * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
3650 * entry, too, for lack of a better place.
3651 */
3652 if (dopt->binary_upgrade)
3653 {
3654 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
3655 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
3656 "SET datfrozenxid = '%u', datminmxid = '%u'\n"
3657 "WHERE datname = ",
3658 frozenxid, minmxid);
3661 }
3662
3663 if (creaQry->len > 0)
3665 ARCHIVE_OPTS(.tag = datname,
3666 .owner = dba,
3667 .description = "DATABASE PROPERTIES",
3668 .section = SECTION_PRE_DATA,
3669 .createStmt = creaQry->data,
3670 .dropStmt = delQry->data,
3671 .deps = &dbDumpId));
3672
3673 /*
3674 * pg_largeobject comes from the old system intact, so set its
3675 * relfrozenxids, relminmxids and relfilenode.
3676 *
3677 * pg_largeobject_metadata also comes from the old system intact for
3678 * upgrades from v16 and newer, so set its relfrozenxids, relminmxids, and
3679 * relfilenode, too. pg_upgrade can't copy/link the files from older
3680 * versions because aclitem (needed by pg_largeobject_metadata.lomacl)
3681 * changed its storage format in v16.
3682 */
3683 if (dopt->binary_upgrade)
3684 {
3691 int ii_relfrozenxid,
3693 ii_oid,
3695
3696 if (fout->remoteVersion >= 90300)
3697 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
3698 "FROM pg_catalog.pg_class\n"
3699 "WHERE oid IN (%u, %u, %u, %u);\n",
3702 else
3703 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
3704 "FROM pg_catalog.pg_class\n"
3705 "WHERE oid IN (%u, %u);\n",
3707
3709
3710 ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
3711 ii_relminmxid = PQfnumber(lo_res, "relminmxid");
3712 ii_relfilenode = PQfnumber(lo_res, "relfilenode");
3713 ii_oid = PQfnumber(lo_res, "oid");
3714
3715 appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3716 appendPQExpBufferStr(lomHorizonQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
3717 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
3718 appendPQExpBufferStr(lomOutQry, "\n-- For binary upgrade, preserve pg_largeobject_metadata and index relfilenodes\n");
3719 for (int i = 0; i < PQntuples(lo_res); ++i)
3720 {
3721 Oid oid;
3722 RelFileNumber relfilenumber;
3725
3726 oid = atooid(PQgetvalue(lo_res, i, ii_oid));
3727 relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
3728
3729 if (oid == LargeObjectRelationId ||
3731 {
3733 outQry = loOutQry;
3734 }
3735 else
3736 {
3738 outQry = lomOutQry;
3739 }
3740
3741 appendPQExpBuffer(horizonQry, "UPDATE pg_catalog.pg_class\n"
3742 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3743 "WHERE oid = %u;\n",
3747
3748 if (oid == LargeObjectRelationId ||
3751 "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
3752 relfilenumber);
3753 else if (oid == LargeObjectLOidPNIndexId ||
3756 "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
3757 relfilenumber);
3758 }
3759
3761 "TRUNCATE pg_catalog.pg_largeobject;\n");
3763 "TRUNCATE pg_catalog.pg_largeobject_metadata;\n");
3764
3767
3769 ARCHIVE_OPTS(.tag = "pg_largeobject",
3770 .description = "pg_largeobject",
3771 .section = SECTION_PRE_DATA,
3772 .createStmt = loOutQry->data));
3773
3774 if (fout->remoteVersion >= 160000)
3776 ARCHIVE_OPTS(.tag = "pg_largeobject_metadata",
3777 .description = "pg_largeobject_metadata",
3778 .section = SECTION_PRE_DATA,
3779 .createStmt = lomOutQry->data));
3780
3781 PQclear(lo_res);
3782
3788 }
3789
3790 PQclear(res);
3791
3792 free(qdatname);
3797}
3798
3799/*
3800 * Collect any database-specific or role-and-database-specific SET options
3801 * for this database, and append them to outbuf.
3802 */
3803static void
3805 const char *dbname, Oid dboid)
3806{
3807 PGconn *conn = GetConnection(AH);
3809 PGresult *res;
3810
3811 /* First collect database-specific options */
3812 printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
3813 "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3814 dboid);
3815
3816 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3817
3818 for (int i = 0; i < PQntuples(res); i++)
3820 "DATABASE", dbname, NULL, NULL,
3821 outbuf);
3822
3823 PQclear(res);
3824
3825 /* Now look for role-and-database-specific options */
3826 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3827 "FROM pg_db_role_setting s, pg_roles r "
3828 "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3829 dboid);
3830
3831 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3832
3833 for (int i = 0; i < PQntuples(res); i++)
3835 "ROLE", PQgetvalue(res, i, 0),
3836 "DATABASE", dbname,
3837 outbuf);
3838
3839 PQclear(res);
3840
3842}
3843
3844/*
3845 * dumpEncoding: put the correct encoding into the archive
3846 */
3847static void
3849{
3850 const char *encname = pg_encoding_to_char(AH->encoding);
3852
3853 pg_log_info("saving encoding = %s", encname);
3854
3855 appendPQExpBufferStr(qry, "SET client_encoding = ");
3857 appendPQExpBufferStr(qry, ";\n");
3858
3860 ARCHIVE_OPTS(.tag = "ENCODING",
3861 .description = "ENCODING",
3862 .section = SECTION_PRE_DATA,
3863 .createStmt = qry->data));
3864
3865 destroyPQExpBuffer(qry);
3866}
3867
3868
3869/*
3870 * dumpStdStrings: put the correct escape string behavior into the archive
3871 */
3872static void
3874{
3875 const char *stdstrings = AH->std_strings ? "on" : "off";
3877
3878 pg_log_info("saving \"standard_conforming_strings = %s\"",
3879 stdstrings);
3880
3881 appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3882 stdstrings);
3883
3885 ARCHIVE_OPTS(.tag = "STDSTRINGS",
3886 .description = "STDSTRINGS",
3887 .section = SECTION_PRE_DATA,
3888 .createStmt = qry->data));
3889
3890 destroyPQExpBuffer(qry);
3891}
3892
3893/*
3894 * dumpSearchPath: record the active search_path in the archive
3895 */
3896static void
3898{
3901 PGresult *res;
3902 char **schemanames = NULL;
3903 int nschemanames = 0;
3904 int i;
3905
3906 /*
3907 * We use the result of current_schemas(), not the search_path GUC,
3908 * because that might contain wildcards such as "$user", which won't
3909 * necessarily have the same value during restore. Also, this way avoids
3910 * listing schemas that may appear in search_path but not actually exist,
3911 * which seems like a prudent exclusion.
3912 */
3914 "SELECT pg_catalog.current_schemas(false)");
3915
3916 if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3917 pg_fatal("could not parse result of current_schemas()");
3918
3919 /*
3920 * We use set_config(), not a simple "SET search_path" command, because
3921 * the latter has less-clean behavior if the search path is empty. While
3922 * that's likely to get fixed at some point, it seems like a good idea to
3923 * be as backwards-compatible as possible in what we put into archives.
3924 */
3925 for (i = 0; i < nschemanames; i++)
3926 {
3927 if (i > 0)
3928 appendPQExpBufferStr(path, ", ");
3930 }
3931
3932 appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3933 appendStringLiteralAH(qry, path->data, AH);
3934 appendPQExpBufferStr(qry, ", false);\n");
3935
3936 pg_log_info("saving \"search_path = %s\"", path->data);
3937
3939 ARCHIVE_OPTS(.tag = "SEARCHPATH",
3940 .description = "SEARCHPATH",
3941 .section = SECTION_PRE_DATA,
3942 .createStmt = qry->data));
3943
3944 /* Also save it in AH->searchpath, in case we're doing plain text dump */
3945 AH->searchpath = pg_strdup(qry->data);
3946
3948 PQclear(res);
3949 destroyPQExpBuffer(qry);
3950 destroyPQExpBuffer(path);
3951}
3952
3953
3954/*
3955 * getLOs:
3956 * Collect schema-level data about large objects
3957 */
3958static void
3960{
3961 DumpOptions *dopt = fout->dopt;
3963 PGresult *res;
3964 int ntups;
3965 int i;
3966 int n;
3967 int i_oid;
3968 int i_lomowner;
3969 int i_lomacl;
3970 int i_acldefault;
3971
3972 pg_log_info("reading large objects");
3973
3974 /*
3975 * Fetch LO OIDs and owner/ACL data. Order the data so that all the blobs
3976 * with the same owner/ACL appear together.
3977 */
3979 "SELECT oid, lomowner, lomacl, "
3980 "acldefault('L', lomowner) AS acldefault "
3981 "FROM pg_largeobject_metadata "
3982 "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
3983
3985
3986 i_oid = PQfnumber(res, "oid");
3987 i_lomowner = PQfnumber(res, "lomowner");
3988 i_lomacl = PQfnumber(res, "lomacl");
3989 i_acldefault = PQfnumber(res, "acldefault");
3990
3991 ntups = PQntuples(res);
3992
3993 /*
3994 * Group the blobs into suitably-sized groups that have the same owner and
3995 * ACL setting, and build a metadata and a data DumpableObject for each
3996 * group. (If we supported initprivs for blobs, we'd have to insist that
3997 * groups also share initprivs settings, since the DumpableObject only has
3998 * room for one.) i is the index of the first tuple in the current group,
3999 * and n is the number of tuples we include in the group.
4000 */
4001 for (i = 0; i < ntups; i += n)
4002 {
4003 Oid thisoid = atooid(PQgetvalue(res, i, i_oid));
4004 char *thisowner = PQgetvalue(res, i, i_lomowner);
4005 char *thisacl = PQgetvalue(res, i, i_lomacl);
4006 LoInfo *loinfo;
4008 char namebuf[64];
4009
4010 /* Scan to find first tuple not to be included in group */
4011 n = 1;
4012 while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
4013 {
4014 if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
4015 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
4016 break;
4017 n++;
4018 }
4019
4020 /* Build the metadata DumpableObject */
4021 loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
4022
4024 loinfo->dobj.catId.tableoid = LargeObjectRelationId;
4025 loinfo->dobj.catId.oid = thisoid;
4026 AssignDumpId(&loinfo->dobj);
4027
4028 if (n > 1)
4029 snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
4030 atooid(PQgetvalue(res, i + n - 1, i_oid)));
4031 else
4032 snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
4033 loinfo->dobj.name = pg_strdup(namebuf);
4034 loinfo->dacl.acl = pg_strdup(thisacl);
4035 loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
4036 loinfo->dacl.privtype = 0;
4037 loinfo->dacl.initprivs = NULL;
4038 loinfo->rolname = getRoleName(thisowner);
4039 loinfo->numlos = n;
4040 loinfo->looids[0] = thisoid;
4041 /* Collect OIDs of the remaining blobs in this group */
4042 for (int k = 1; k < n; k++)
4043 {
4045
4046 loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
4047
4048 /* Make sure we can look up loinfo by any of the blobs' OIDs */
4049 extraID.tableoid = LargeObjectRelationId;
4050 extraID.oid = loinfo->looids[k];
4052 }
4053
4054 /* LOs have data */
4055 loinfo->dobj.components |= DUMP_COMPONENT_DATA;
4056
4057 /* Mark whether LO group has a non-empty ACL */
4058 if (!PQgetisnull(res, i, i_lomacl))
4059 loinfo->dobj.components |= DUMP_COMPONENT_ACL;
4060
4061 /*
4062 * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
4063 * as it will be copied by pg_upgrade, which simply copies the
4064 * pg_largeobject table. We *do* however dump out anything but the
4065 * data, as pg_upgrade copies just pg_largeobject, but not
4066 * pg_largeobject_metadata, after the dump is restored. In versions
4067 * before v12, this is done via proper large object commands. In
4068 * newer versions, we dump the content of pg_largeobject_metadata and
4069 * any associated pg_shdepend rows, which is faster to restore. (On
4070 * <v12, pg_largeobject_metadata was created WITH OIDS, so the OID
4071 * column is hidden and won't be dumped.)
4072 */
4073 if (dopt->binary_upgrade)
4074 {
4075 if (fout->remoteVersion >= 120000)
4076 {
4077 /*
4078 * We should've saved pg_largeobject_metadata's dump ID before
4079 * this point.
4080 */
4082
4084
4085 /*
4086 * Mark the large object as dependent on
4087 * pg_largeobject_metadata so that any large object
4088 * comments/seclables are dumped after it.
4089 */
4090 loinfo->dobj.dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
4091 loinfo->dobj.dependencies[0] = lo_metadata_dumpId;
4092 loinfo->dobj.nDeps = loinfo->dobj.allocDeps = 1;
4093 }
4094 else
4095 loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
4096 }
4097
4098 /*
4099 * Create a "BLOBS" data item for the group, too. This is just a
4100 * placeholder for sorting; it carries no data now.
4101 */
4103 lodata->objType = DO_LARGE_OBJECT_DATA;
4104 lodata->catId = nilCatalogId;
4106 lodata->name = pg_strdup(namebuf);
4107 lodata->components |= DUMP_COMPONENT_DATA;
4108 /* Set up explicit dependency from data to metadata */
4109 lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
4110 lodata->dependencies[0] = loinfo->dobj.dumpId;
4111 lodata->nDeps = lodata->allocDeps = 1;
4112 }
4113
4114 PQclear(res);
4116}
4117
4118/*
4119 * dumpLO
4120 *
4121 * dump the definition (metadata) of the given large object group
4122 */
4123static void
4125{
4127
4128 /*
4129 * The "definition" is just a newline-separated list of OIDs. We need to
4130 * put something into the dropStmt too, but it can just be a comment.
4131 */
4132 for (int i = 0; i < loinfo->numlos; i++)
4133 appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
4134
4135 if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4136 ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
4137 ARCHIVE_OPTS(.tag = loinfo->dobj.name,
4138 .owner = loinfo->rolname,
4139 .description = "BLOB METADATA",
4140 .section = SECTION_DATA,
4141 .createStmt = cquery->data,
4142 .dropStmt = "-- dummy"));
4143
4144 /*
4145 * Dump per-blob comments and seclabels if any. We assume these are rare
4146 * enough that it's okay to generate retail TOC entries for them.
4147 */
4148 if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
4150 {
4151 for (int i = 0; i < loinfo->numlos; i++)
4152 {
4153 CatalogId catId;
4154 char namebuf[32];
4155
4156 /* Build identifying info for this blob */
4157 catId.tableoid = loinfo->dobj.catId.tableoid;
4158 catId.oid = loinfo->looids[i];
4159 snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
4160
4161 if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4162 dumpComment(fout, "LARGE OBJECT", namebuf,
4163 NULL, loinfo->rolname,
4164 catId, 0, loinfo->dobj.dumpId);
4165
4166 if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4167 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
4168 NULL, loinfo->rolname,
4169 catId, 0, loinfo->dobj.dumpId);
4170 }
4171 }
4172
4173 /*
4174 * Dump the ACLs if any (remember that all blobs in the group will have
4175 * the same ACL). If there's just one blob, dump a simple ACL entry; if
4176 * there's more, make a "LARGE OBJECTS" entry that really contains only
4177 * the ACL for the first blob. _printTocEntry() will be cued by the tag
4178 * string to emit a mutated version for each blob.
4179 */
4180 if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
4181 {
4182 char namebuf[32];
4183
4184 /* Build identifying info for the first blob */
4185 snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
4186
4187 if (loinfo->numlos > 1)
4188 {
4189 char tagbuf[64];
4190
4191 snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
4192 loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
4193
4194 dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
4195 "LARGE OBJECT", namebuf, NULL, NULL,
4196 tagbuf, loinfo->rolname, &loinfo->dacl);
4197 }
4198 else
4199 {
4200 dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
4201 "LARGE OBJECT", namebuf, NULL, NULL,
4202 NULL, loinfo->rolname, &loinfo->dacl);
4203 }
4204 }
4205
4207}
4208
4209/*
4210 * dumpLOs:
4211 * dump the data contents of the large objects in the given group
4212 */
4213static int
4214dumpLOs(Archive *fout, const void *arg)
4215{
4216 const LoInfo *loinfo = (const LoInfo *) arg;
4218 char buf[LOBBUFSIZE];
4219
4220 pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
4221
4222 for (int i = 0; i < loinfo->numlos; i++)
4223 {
4224 Oid loOid = loinfo->looids[i];
4225 int loFd;
4226 int cnt;
4227
4228 /* Open the LO */
4229 loFd = lo_open(conn, loOid, INV_READ);
4230 if (loFd == -1)
4231 pg_fatal("could not open large object %u: %s",
4233
4234 StartLO(fout, loOid);
4235
4236 /* Now read it in chunks, sending data to archive */
4237 do
4238 {
4239 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
4240 if (cnt < 0)
4241 pg_fatal("error reading large object %u: %s",
4243
4244 WriteData(fout, buf, cnt);
4245 } while (cnt > 0);
4246
4247 lo_close(conn, loFd);
4248
4249 EndLO(fout, loOid);
4250 }
4251
4252 return 1;
4253}
4254
4255/*
4256 * getPolicies
4257 * get information about all RLS policies on dumpable tables.
4258 */
4259void
4260getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
4261{
4262 DumpOptions *dopt = fout->dopt;
4263 PQExpBuffer query;
4265 PGresult *res;
4267 int i_oid;
4268 int i_tableoid;
4269 int i_polrelid;
4270 int i_polname;
4271 int i_polcmd;
4272 int i_polpermissive;
4273 int i_polroles;
4274 int i_polqual;
4275 int i_polwithcheck;
4276 int i,
4277 j,
4278 ntups;
4279
4280 /* No policies before 9.5 */
4281 if (fout->remoteVersion < 90500)
4282 return;
4283
4284 /* Skip if --no-policies was specified */
4285 if (dopt->no_policies)
4286 return;
4287
4288 query = createPQExpBuffer();
4290
4291 /*
4292 * Identify tables of interest, and check which ones have RLS enabled.
4293 */
4295 for (i = 0; i < numTables; i++)
4296 {
4297 TableInfo *tbinfo = &tblinfo[i];
4298
4299 /* Ignore row security on tables not to be dumped */
4300 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
4301 continue;
4302
4303 /* It can't have RLS or policies if it's not a table */
4304 if (tbinfo->relkind != RELKIND_RELATION &&
4306 continue;
4307
4308 /* Add it to the list of table OIDs to be probed below */
4309 if (tbloids->len > 1) /* do we have more than the '{'? */
4311 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
4312
4313 /* Is RLS enabled? (That's separate from whether it has policies) */
4314 if (tbinfo->rowsec)
4315 {
4316 tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
4317
4318 /*
4319 * We represent RLS being enabled on a table by creating a
4320 * PolicyInfo object with null polname.
4321 *
4322 * Note: use tableoid 0 so that this object won't be mistaken for
4323 * something that pg_depend entries apply to.
4324 */
4325 polinfo = pg_malloc(sizeof(PolicyInfo));
4326 polinfo->dobj.objType = DO_POLICY;
4327 polinfo->dobj.catId.tableoid = 0;
4328 polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
4329 AssignDumpId(&polinfo->dobj);
4330 polinfo->dobj.namespace = tbinfo->dobj.namespace;
4331 polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
4332 polinfo->poltable = tbinfo;
4333 polinfo->polname = NULL;
4334 polinfo->polcmd = '\0';
4335 polinfo->polpermissive = 0;
4336 polinfo->polroles = NULL;
4337 polinfo->polqual = NULL;
4338 polinfo->polwithcheck = NULL;
4339 }
4340 }
4342
4343 /*
4344 * Now, read all RLS policies belonging to the tables of interest, and
4345 * create PolicyInfo objects for them. (Note that we must filter the
4346 * results server-side not locally, because we dare not apply pg_get_expr
4347 * to tables we don't have lock on.)
4348 */
4349 pg_log_info("reading row-level security policies");
4350
4351 printfPQExpBuffer(query,
4352 "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
4353 if (fout->remoteVersion >= 100000)
4354 appendPQExpBufferStr(query, "pol.polpermissive, ");
4355 else
4356 appendPQExpBufferStr(query, "'t' as polpermissive, ");
4357 appendPQExpBuffer(query,
4358 "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
4359 " 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, "
4360 "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
4361 "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
4362 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
4363 "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
4364 tbloids->data);
4365
4366 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4367
4368 ntups = PQntuples(res);
4369 if (ntups > 0)
4370 {
4371 i_oid = PQfnumber(res, "oid");
4372 i_tableoid = PQfnumber(res, "tableoid");
4373 i_polrelid = PQfnumber(res, "polrelid");
4374 i_polname = PQfnumber(res, "polname");
4375 i_polcmd = PQfnumber(res, "polcmd");
4376 i_polpermissive = PQfnumber(res, "polpermissive");
4377 i_polroles = PQfnumber(res, "polroles");
4378 i_polqual = PQfnumber(res, "polqual");
4379 i_polwithcheck = PQfnumber(res, "polwithcheck");
4380
4381 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
4382
4383 for (j = 0; j < ntups; j++)
4384 {
4387
4388 tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
4389
4390 polinfo[j].dobj.objType = DO_POLICY;
4391 polinfo[j].dobj.catId.tableoid =
4392 atooid(PQgetvalue(res, j, i_tableoid));
4393 polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4394 AssignDumpId(&polinfo[j].dobj);
4395 polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4396 polinfo[j].poltable = tbinfo;
4397 polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
4398 polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
4399
4400 polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
4401 polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
4402
4403 if (PQgetisnull(res, j, i_polroles))
4404 polinfo[j].polroles = NULL;
4405 else
4406 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
4407
4408 if (PQgetisnull(res, j, i_polqual))
4409 polinfo[j].polqual = NULL;
4410 else
4411 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
4412
4413 if (PQgetisnull(res, j, i_polwithcheck))
4414 polinfo[j].polwithcheck = NULL;
4415 else
4416 polinfo[j].polwithcheck
4418 }
4419 }
4420
4421 PQclear(res);
4422
4423 destroyPQExpBuffer(query);
4425}
4426
4427/*
4428 * dumpPolicy
4429 * dump the definition of the given policy
4430 */
4431static void
4433{
4434 DumpOptions *dopt = fout->dopt;
4435 TableInfo *tbinfo = polinfo->poltable;
4436 PQExpBuffer query;
4439 char *qtabname;
4440 const char *cmd;
4441 char *tag;
4442
4443 /* Do nothing if not dumping schema */
4444 if (!dopt->dumpSchema)
4445 return;
4446
4447 /*
4448 * If polname is NULL, then this record is just indicating that ROW LEVEL
4449 * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
4450 * ROW LEVEL SECURITY.
4451 */
4452 if (polinfo->polname == NULL)
4453 {
4454 query = createPQExpBuffer();
4455
4456 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
4458
4459 /*
4460 * We must emit the ROW SECURITY object's dependency on its table
4461 * explicitly, because it will not match anything in pg_depend (unlike
4462 * the case for other PolicyInfo objects).
4463 */
4464 if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4465 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
4466 ARCHIVE_OPTS(.tag = polinfo->dobj.name,
4467 .namespace = polinfo->dobj.namespace->dobj.name,
4468 .owner = tbinfo->rolname,
4469 .description = "ROW SECURITY",
4470 .section = SECTION_POST_DATA,
4471 .createStmt = query->data,
4472 .deps = &(tbinfo->dobj.dumpId),
4473 .nDeps = 1));
4474
4475 destroyPQExpBuffer(query);
4476 return;
4477 }
4478
4479 if (polinfo->polcmd == '*')
4480 cmd = "";
4481 else if (polinfo->polcmd == 'r')
4482 cmd = " FOR SELECT";
4483 else if (polinfo->polcmd == 'a')
4484 cmd = " FOR INSERT";
4485 else if (polinfo->polcmd == 'w')
4486 cmd = " FOR UPDATE";
4487 else if (polinfo->polcmd == 'd')
4488 cmd = " FOR DELETE";
4489 else
4490 pg_fatal("unexpected policy command type: %c",
4491 polinfo->polcmd);
4492
4493 query = createPQExpBuffer();
4496
4497 qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
4498
4499 appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
4500
4501 appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
4502 !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
4503
4504 if (polinfo->polroles != NULL)
4505 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
4506
4507 if (polinfo->polqual != NULL)
4508 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
4509
4510 if (polinfo->polwithcheck != NULL)
4511 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
4512
4513 appendPQExpBufferStr(query, ";\n");
4514
4515 appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
4517
4518 appendPQExpBuffer(polprefix, "POLICY %s ON",
4519 fmtId(polinfo->polname));
4520
4521 tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
4522
4523 if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4524 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
4525 ARCHIVE_OPTS(.tag = tag,
4526 .namespace = polinfo->dobj.namespace->dobj.name,
4527 .owner = tbinfo->rolname,
4528 .description = "POLICY",
4529 .section = SECTION_POST_DATA,
4530 .createStmt = query->data,
4531 .dropStmt = delqry->data));
4532
4533 if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4535 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
4536 polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
4537
4538 free(tag);
4539 destroyPQExpBuffer(query);
4542 free(qtabname);
4543}
4544
4545/*
4546 * getPublications
4547 * get information about publications
4548 */
4549void
4551{
4552 DumpOptions *dopt = fout->dopt;
4553 PQExpBuffer query;
4554 PGresult *res;
4556 int i_tableoid;
4557 int i_oid;
4558 int i_pubname;
4559 int i_pubowner;
4560 int i_puballtables;
4562 int i_pubinsert;
4563 int i_pubupdate;
4564 int i_pubdelete;
4565 int i_pubtruncate;
4566 int i_pubviaroot;
4567 int i_pubgencols;
4568 int i,
4569 ntups;
4570
4571 if (dopt->no_publications || fout->remoteVersion < 100000)
4572 return;
4573
4574 query = createPQExpBuffer();
4575
4576 /* Get the publications. */
4577 appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
4578 "p.pubowner, p.puballtables, p.pubinsert, "
4579 "p.pubupdate, p.pubdelete, ");
4580
4581 if (fout->remoteVersion >= 110000)
4582 appendPQExpBufferStr(query, "p.pubtruncate, ");
4583 else
4584 appendPQExpBufferStr(query, "false AS pubtruncate, ");
4585
4586 if (fout->remoteVersion >= 130000)
4587 appendPQExpBufferStr(query, "p.pubviaroot, ");
4588 else
4589 appendPQExpBufferStr(query, "false AS pubviaroot, ");
4590
4591 if (fout->remoteVersion >= 180000)
4592 appendPQExpBufferStr(query, "p.pubgencols, ");
4593 else
4594 appendPQExpBuffer(query, "'%c' AS pubgencols, ", PUBLISH_GENCOLS_NONE);
4595
4596 if (fout->remoteVersion >= 190000)
4597 appendPQExpBufferStr(query, "p.puballsequences ");
4598 else
4599 appendPQExpBufferStr(query, "false AS puballsequences ");
4600
4601 appendPQExpBufferStr(query, "FROM pg_publication p");
4602
4603 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4604
4605 ntups = PQntuples(res);
4606
4607 if (ntups == 0)
4608 goto cleanup;
4609
4610 i_tableoid = PQfnumber(res, "tableoid");
4611 i_oid = PQfnumber(res, "oid");
4612 i_pubname = PQfnumber(res, "pubname");
4613 i_pubowner = PQfnumber(res, "pubowner");
4614 i_puballtables = PQfnumber(res, "puballtables");
4615 i_puballsequences = PQfnumber(res, "puballsequences");
4616 i_pubinsert = PQfnumber(res, "pubinsert");
4617 i_pubupdate = PQfnumber(res, "pubupdate");
4618 i_pubdelete = PQfnumber(res, "pubdelete");
4619 i_pubtruncate = PQfnumber(res, "pubtruncate");
4620 i_pubviaroot = PQfnumber(res, "pubviaroot");
4621 i_pubgencols = PQfnumber(res, "pubgencols");
4622
4623 pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
4624
4625 for (i = 0; i < ntups; i++)
4626 {
4627 pubinfo[i].dobj.objType = DO_PUBLICATION;
4628 pubinfo[i].dobj.catId.tableoid =
4629 atooid(PQgetvalue(res, i, i_tableoid));
4630 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4631 AssignDumpId(&pubinfo[i].dobj);
4632 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
4633 pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
4634 pubinfo[i].puballtables =
4635 (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
4636 pubinfo[i].puballsequences =
4637 (strcmp(PQgetvalue(res, i, i_puballsequences), "t") == 0);
4638 pubinfo[i].pubinsert =
4639 (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
4640 pubinfo[i].pubupdate =
4641 (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
4642 pubinfo[i].pubdelete =
4643 (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
4644 pubinfo[i].pubtruncate =
4645 (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
4646 pubinfo[i].pubviaroot =
4647 (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
4648 pubinfo[i].pubgencols_type =
4649 *(PQgetvalue(res, i, i_pubgencols));
4650
4651 /* Decide whether we want to dump it */
4653 }
4654
4655cleanup:
4656 PQclear(res);
4657
4658 destroyPQExpBuffer(query);
4659}
4660
4661/*
4662 * dumpPublication
4663 * dump the definition of the given publication
4664 */
4665static void
4667{
4668 DumpOptions *dopt = fout->dopt;
4670 PQExpBuffer query;
4671 char *qpubname;
4672 bool first = true;
4673
4674 /* Do nothing if not dumping schema */
4675 if (!dopt->dumpSchema)
4676 return;
4677
4679 query = createPQExpBuffer();
4680
4681 qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
4682
4683 appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
4684 qpubname);
4685
4686 appendPQExpBuffer(query, "CREATE PUBLICATION %s",
4687 qpubname);
4688
4689 if (pubinfo->puballtables && pubinfo->puballsequences)
4690 appendPQExpBufferStr(query, " FOR ALL TABLES, ALL SEQUENCES");
4691 else if (pubinfo->puballtables)
4692 appendPQExpBufferStr(query, " FOR ALL TABLES");
4693 else if (pubinfo->puballsequences)
4694 appendPQExpBufferStr(query, " FOR ALL SEQUENCES");
4695
4696 appendPQExpBufferStr(query, " WITH (publish = '");
4697 if (pubinfo->pubinsert)
4698 {
4699 appendPQExpBufferStr(query, "insert");
4700 first = false;
4701 }
4702
4703 if (pubinfo->pubupdate)
4704 {
4705 if (!first)
4706 appendPQExpBufferStr(query, ", ");
4707
4708 appendPQExpBufferStr(query, "update");
4709 first = false;
4710 }
4711
4712 if (pubinfo->pubdelete)
4713 {
4714 if (!first)
4715 appendPQExpBufferStr(query, ", ");
4716
4717 appendPQExpBufferStr(query, "delete");
4718 first = false;
4719 }
4720
4721 if (pubinfo->pubtruncate)
4722 {
4723 if (!first)
4724 appendPQExpBufferStr(query, ", ");
4725
4726 appendPQExpBufferStr(query, "truncate");
4727 first = false;
4728 }
4729
4730 appendPQExpBufferChar(query, '\'');
4731
4732 if (pubinfo->pubviaroot)
4733 appendPQExpBufferStr(query, ", publish_via_partition_root = true");
4734
4735 if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
4736 appendPQExpBufferStr(query, ", publish_generated_columns = stored");
4737
4738 appendPQExpBufferStr(query, ");\n");
4739
4740 if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4741 ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
4742 ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
4743 .owner = pubinfo->rolname,
4744 .description = "PUBLICATION",
4745 .section = SECTION_POST_DATA,
4746 .createStmt = query->data,
4747 .dropStmt = delq->data));
4748
4749 if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4750 dumpComment(fout, "PUBLICATION", qpubname,
4751 NULL, pubinfo->rolname,
4752 pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4753
4754 if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4755 dumpSecLabel(fout, "PUBLICATION", qpubname,
4756 NULL, pubinfo->rolname,
4757 pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4758
4760 destroyPQExpBuffer(query);
4761 free(qpubname);
4762}
4763
4764/*
4765 * getPublicationNamespaces
4766 * get information about publication membership for dumpable schemas.
4767 */
4768void
4770{
4771 PQExpBuffer query;
4772 PGresult *res;
4774 DumpOptions *dopt = fout->dopt;
4775 int i_tableoid;
4776 int i_oid;
4777 int i_pnpubid;
4778 int i_pnnspid;
4779 int i,
4780 j,
4781 ntups;
4782
4783 if (dopt->no_publications || fout->remoteVersion < 150000)
4784 return;
4785
4786 query = createPQExpBuffer();
4787
4788 /* Collect all publication membership info. */
4790 "SELECT tableoid, oid, pnpubid, pnnspid "
4791 "FROM pg_catalog.pg_publication_namespace");
4792 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4793
4794 ntups = PQntuples(res);
4795
4796 i_tableoid = PQfnumber(res, "tableoid");
4797 i_oid = PQfnumber(res, "oid");
4798 i_pnpubid = PQfnumber(res, "pnpubid");
4799 i_pnnspid = PQfnumber(res, "pnnspid");
4800
4801 /* this allocation may be more than we need */
4802 pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
4803 j = 0;
4804
4805 for (i = 0; i < ntups; i++)
4806 {
4811
4812 /*
4813 * Ignore any entries for which we aren't interested in either the
4814 * publication or the rel.
4815 */
4817 if (pubinfo == NULL)
4818 continue;
4820 if (nspinfo == NULL)
4821 continue;
4822
4823 /* OK, make a DumpableObject for this relationship */
4825 pubsinfo[j].dobj.catId.tableoid =
4826 atooid(PQgetvalue(res, i, i_tableoid));
4827 pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4828 AssignDumpId(&pubsinfo[j].dobj);
4829 pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
4830 pubsinfo[j].dobj.name = nspinfo->dobj.name;
4831 pubsinfo[j].publication = pubinfo;
4832 pubsinfo[j].pubschema = nspinfo;
4833
4834 /* Decide whether we want to dump it */
4836
4837 j++;
4838 }
4839
4840 PQclear(res);
4841 destroyPQExpBuffer(query);
4842}
4843
4844/*
4845 * getPublicationTables
4846 * get information about publication membership for dumpable tables.
4847 */
4848void
4850{
4851 PQExpBuffer query;
4852 PGresult *res;
4854 DumpOptions *dopt = fout->dopt;
4855 int i_tableoid;
4856 int i_oid;
4857 int i_prpubid;
4858 int i_prrelid;
4859 int i_prrelqual;
4860 int i_prattrs;
4861 int i,
4862 j,
4863 ntups;
4864
4865 if (dopt->no_publications || fout->remoteVersion < 100000)
4866 return;
4867
4868 query = createPQExpBuffer();
4869
4870 /* Collect all publication membership info. */
4871 if (fout->remoteVersion >= 150000)
4873 "SELECT tableoid, oid, prpubid, prrelid, "
4874 "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
4875 "(CASE\n"
4876 " WHEN pr.prattrs IS NOT NULL THEN\n"
4877 " (SELECT array_agg(attname)\n"
4878 " FROM\n"
4879 " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
4880 " pg_catalog.pg_attribute\n"
4881 " WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
4882 " ELSE NULL END) prattrs "
4883 "FROM pg_catalog.pg_publication_rel pr");
4884 else
4886 "SELECT tableoid, oid, prpubid, prrelid, "
4887 "NULL AS prrelqual, NULL AS prattrs "
4888 "FROM pg_catalog.pg_publication_rel");
4889 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4890
4891 ntups = PQntuples(res);
4892
4893 i_tableoid = PQfnumber(res, "tableoid");
4894 i_oid = PQfnumber(res, "oid");
4895 i_prpubid = PQfnumber(res, "prpubid");
4896 i_prrelid = PQfnumber(res, "prrelid");
4897 i_prrelqual = PQfnumber(res, "prrelqual");
4898 i_prattrs = PQfnumber(res, "prattrs");
4899
4900 /* this allocation may be more than we need */
4901 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
4902 j = 0;
4903
4904 for (i = 0; i < ntups; i++)
4905 {
4910
4911 /*
4912 * Ignore any entries for which we aren't interested in either the
4913 * publication or the rel.
4914 */
4916 if (pubinfo == NULL)
4917 continue;
4919 if (tbinfo == NULL)
4920 continue;
4921
4922 /* OK, make a DumpableObject for this relationship */
4923 pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
4924 pubrinfo[j].dobj.catId.tableoid =
4925 atooid(PQgetvalue(res, i, i_tableoid));
4926 pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4927 AssignDumpId(&pubrinfo[j].dobj);
4928 pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4929 pubrinfo[j].dobj.name = tbinfo->dobj.name;
4930 pubrinfo[j].publication = pubinfo;
4931 pubrinfo[j].pubtable = tbinfo;
4932 if (PQgetisnull(res, i, i_prrelqual))
4933 pubrinfo[j].pubrelqual = NULL;
4934 else
4935 pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
4936
4937 if (!PQgetisnull(res, i, i_prattrs))
4938 {
4939 char **attnames;
4940 int nattnames;
4942
4943 if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
4944 &attnames, &nattnames))
4945 pg_fatal("could not parse %s array", "prattrs");
4947 for (int k = 0; k < nattnames; k++)
4948 {
4949 if (k > 0)
4951
4952 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
4953 }
4954 pubrinfo[j].pubrattrs = attribs->data;
4955 free(attribs); /* but not attribs->data */
4956 free(attnames);
4957 }
4958 else
4959 pubrinfo[j].pubrattrs = NULL;
4960
4961 /* Decide whether we want to dump it */
4963
4964 j++;
4965 }
4966
4967 PQclear(res);
4968 destroyPQExpBuffer(query);
4969}
4970
4971/*
4972 * dumpPublicationNamespace
4973 * dump the definition of the given publication schema mapping.
4974 */
4975static void
4977{
4978 DumpOptions *dopt = fout->dopt;
4979 NamespaceInfo *schemainfo = pubsinfo->pubschema;
4980 PublicationInfo *pubinfo = pubsinfo->publication;
4981 PQExpBuffer query;
4982 char *tag;
4983
4984 /* Do nothing if not dumping schema */
4985 if (!dopt->dumpSchema)
4986 return;
4987
4988 tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
4989
4990 query = createPQExpBuffer();
4991
4992 appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
4993 appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
4994
4995 /*
4996 * There is no point in creating drop query as the drop is done by schema
4997 * drop.
4998 */
4999 if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5000 ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
5001 ARCHIVE_OPTS(.tag = tag,
5002 .namespace = schemainfo->dobj.name,
5003 .owner = pubinfo->rolname,
5004 .description = "PUBLICATION TABLES IN SCHEMA",
5005 .section = SECTION_POST_DATA,
5006 .createStmt = query->data));
5007
5008 /* These objects can't currently have comments or seclabels */
5009
5010 free(tag);
5011 destroyPQExpBuffer(query);
5012}
5013
5014/*
5015 * dumpPublicationTable
5016 * dump the definition of the given publication table mapping
5017 */
5018static void
5020{
5021 DumpOptions *dopt = fout->dopt;
5022 PublicationInfo *pubinfo = pubrinfo->publication;
5023 TableInfo *tbinfo = pubrinfo->pubtable;
5024 PQExpBuffer query;
5025 char *tag;
5026
5027 /* Do nothing if not dumping schema */
5028 if (!dopt->dumpSchema)
5029 return;
5030
5031 tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
5032
5033 query = createPQExpBuffer();
5034
5035 appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
5036 fmtId(pubinfo->dobj.name));
5037 appendPQExpBuffer(query, " %s",
5039
5040 if (pubrinfo->pubrattrs)
5041 appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
5042
5043 if (pubrinfo->pubrelqual)
5044 {
5045 /*
5046 * It's necessary to add parentheses around the expression because
5047 * pg_get_expr won't supply the parentheses for things like WHERE
5048 * TRUE.
5049 */
5050 appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
5051 }
5052 appendPQExpBufferStr(query, ";\n");
5053
5054 /*
5055 * There is no point in creating a drop query as the drop is done by table
5056 * drop. (If you think to change this, see also _printTocEntry().)
5057 * Although this object doesn't really have ownership as such, set the
5058 * owner field anyway to ensure that the command is run by the correct
5059 * role at restore time.
5060 */
5061 if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5062 ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
5063 ARCHIVE_OPTS(.tag = tag,
5064 .namespace = tbinfo->dobj.namespace->dobj.name,
5065 .owner = pubinfo->rolname,
5066 .description = "PUBLICATION TABLE",
5067 .section = SECTION_POST_DATA,
5068 .createStmt = query->data));
5069
5070 /* These objects can't currently have comments or seclabels */
5071
5072 free(tag);
5073 destroyPQExpBuffer(query);
5074}
5075
5076/*
5077 * Is the currently connected user a superuser?
5078 */
5079static bool
5081{
5083 const char *val;
5084
5085 val = PQparameterStatus(AH->connection, "is_superuser");
5086
5087 if (val && strcmp(val, "on") == 0)
5088 return true;
5089
5090 return false;
5091}
5092
5093/*
5094 * Set the given value to restrict_nonsystem_relation_kind value. Since
5095 * restrict_nonsystem_relation_kind is introduced in minor version releases,
5096 * the setting query is effective only where available.
5097 */
5098static void
5100{
5102 PGresult *res;
5103
5104 appendPQExpBuffer(query,
5105 "SELECT set_config(name, '%s', false) "
5106 "FROM pg_settings "
5107 "WHERE name = 'restrict_nonsystem_relation_kind'",
5108 value);
5109 res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
5110
5111 PQclear(res);
5112 destroyPQExpBuffer(query);
5113}
5114
5115/*
5116 * getSubscriptions
5117 * get information about subscriptions
5118 */
5119void
5121{
5122 DumpOptions *dopt = fout->dopt;
5123 PQExpBuffer query;
5124 PGresult *res;
5125 SubscriptionInfo *subinfo;
5126 int i_tableoid;
5127 int i_oid;
5128 int i_subname;
5129 int i_subowner;
5130 int i_subbinary;
5131 int i_substream;
5135 int i_subrunasowner;
5136 int i_subconninfo;
5137 int i_subslotname;
5138 int i_subsynccommit;
5140 int i_suborigin;
5142 int i_subenabled;
5143 int i_subfailover;
5146 int i,
5147 ntups;
5148
5149 if (dopt->no_subscriptions || fout->remoteVersion < 100000)
5150 return;
5151
5152 if (!is_superuser(fout))
5153 {
5154 int n;
5155
5156 res = ExecuteSqlQuery(fout,
5157 "SELECT count(*) FROM pg_subscription "
5158 "WHERE subdbid = (SELECT oid FROM pg_database"
5159 " WHERE datname = current_database())",
5161 n = atoi(PQgetvalue(res, 0, 0));
5162 if (n > 0)
5163 pg_log_warning("subscriptions not dumped because current user is not a superuser");
5164 PQclear(res);
5165 return;
5166 }
5167
5168 query = createPQExpBuffer();
5169
5170 /* Get the subscriptions in current database. */
5172 "SELECT s.tableoid, s.oid, s.subname,\n"
5173 " s.subowner,\n"
5174 " s.subconninfo, s.subslotname, s.subsynccommit,\n"
5175 " s.subpublications,\n");
5176
5177 if (fout->remoteVersion >= 140000)
5178 appendPQExpBufferStr(query, " s.subbinary,\n");
5179 else
5180 appendPQExpBufferStr(query, " false AS subbinary,\n");
5181
5182 if (fout->remoteVersion >= 140000)
5183 appendPQExpBufferStr(query, " s.substream,\n");
5184 else
5185 appendPQExpBufferStr(query, " 'f' AS substream,\n");
5186
5187 if (fout->remoteVersion >= 150000)
5189 " s.subtwophasestate,\n"
5190 " s.subdisableonerr,\n");
5191 else
5192 appendPQExpBuffer(query,
5193 " '%c' AS subtwophasestate,\n"
5194 " false AS subdisableonerr,\n",
5196
5197 if (fout->remoteVersion >= 160000)
5199 " s.subpasswordrequired,\n"
5200 " s.subrunasowner,\n"
5201 " s.suborigin,\n");
5202 else
5203 appendPQExpBuffer(query,
5204 " 't' AS subpasswordrequired,\n"
5205 " 't' AS subrunasowner,\n"
5206 " '%s' AS suborigin,\n",
5208
5209 if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5210 appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
5211 " s.subenabled,\n");
5212 else
5213 appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
5214 " false AS subenabled,\n");
5215
5216 if (fout->remoteVersion >= 170000)
5218 " s.subfailover,\n");
5219 else
5221 " false AS subfailover,\n");
5222
5223 if (fout->remoteVersion >= 190000)
5225 " s.subretaindeadtuples,\n");
5226 else
5228 " false AS subretaindeadtuples,\n");
5229
5230 if (fout->remoteVersion >= 190000)
5232 " s.submaxretention\n");
5233 else
5234 appendPQExpBuffer(query,
5235 " 0 AS submaxretention\n");
5236
5238 "FROM pg_subscription s\n");
5239
5240 if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5242 "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
5243 " ON o.external_id = 'pg_' || s.oid::text \n");
5244
5246 "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
5247 " WHERE datname = current_database())");
5248
5249 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5250
5251 ntups = PQntuples(res);
5252
5253 /*
5254 * Get subscription fields. We don't include subskiplsn in the dump as
5255 * after restoring the dump this value may no longer be relevant.
5256 */
5257 i_tableoid = PQfnumber(res, "tableoid");
5258 i_oid = PQfnumber(res, "oid");
5259 i_subname = PQfnumber(res, "subname");
5260 i_subowner = PQfnumber(res, "subowner");
5261 i_subenabled = PQfnumber(res, "subenabled");
5262 i_subbinary = PQfnumber(res, "subbinary");
5263 i_substream = PQfnumber(res, "substream");
5264 i_subtwophasestate = PQfnumber(res, "subtwophasestate");
5265 i_subdisableonerr = PQfnumber(res, "subdisableonerr");
5266 i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
5267 i_subrunasowner = PQfnumber(res, "subrunasowner");
5268 i_subfailover = PQfnumber(res, "subfailover");
5269 i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
5270 i_submaxretention = PQfnumber(res, "submaxretention");
5271 i_subconninfo = PQfnumber(res, "subconninfo");
5272 i_subslotname = PQfnumber(res, "subslotname");
5273 i_subsynccommit = PQfnumber(res, "subsynccommit");
5274 i_subpublications = PQfnumber(res, "subpublications");
5275 i_suborigin = PQfnumber(res, "suborigin");
5276 i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
5277
5278 subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
5279
5280 for (i = 0; i < ntups; i++)
5281 {
5282 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
5283 subinfo[i].dobj.catId.tableoid =
5284 atooid(PQgetvalue(res, i, i_tableoid));
5285 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5286 AssignDumpId(&subinfo[i].dobj);
5287 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
5288 subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
5289
5290 subinfo[i].subenabled =
5291 (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
5292 subinfo[i].subbinary =
5293 (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
5294 subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
5295 subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
5296 subinfo[i].subdisableonerr =
5297 (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
5298 subinfo[i].subpasswordrequired =
5299 (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
5300 subinfo[i].subrunasowner =
5301 (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
5302 subinfo[i].subfailover =
5303 (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
5304 subinfo[i].subretaindeadtuples =
5305 (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
5306 subinfo[i].submaxretention =
5308 subinfo[i].subconninfo =
5310 if (PQgetisnull(res, i, i_subslotname))
5311 subinfo[i].subslotname = NULL;
5312 else
5313 subinfo[i].subslotname =
5315 subinfo[i].subsynccommit =
5317 subinfo[i].subpublications =
5319 subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
5321 subinfo[i].suboriginremotelsn = NULL;
5322 else
5323 subinfo[i].suboriginremotelsn =
5325
5326 /* Decide whether we want to dump it */
5327 selectDumpableObject(&(subinfo[i].dobj), fout);
5328 }
5329 PQclear(res);
5330
5331 destroyPQExpBuffer(query);
5332}
5333
5334/*
5335 * getSubscriptionRelations
5336 * Get information about subscription membership for dumpable relations. This
5337 * will be used only in binary-upgrade mode for PG17 or later versions.
5338 */
5339void
5341{
5342 DumpOptions *dopt = fout->dopt;
5343 SubscriptionInfo *subinfo = NULL;
5345 PGresult *res;
5346 int i_srsubid;
5347 int i_srrelid;
5348 int i_srsubstate;
5349 int i_srsublsn;
5350 int ntups;
5352
5353 if (dopt->no_subscriptions || !dopt->binary_upgrade ||
5354 fout->remoteVersion < 170000)
5355 return;
5356
5357 res = ExecuteSqlQuery(fout,
5358 "SELECT srsubid, srrelid, srsubstate, srsublsn "
5359 "FROM pg_catalog.pg_subscription_rel "
5360 "ORDER BY srsubid",
5362 ntups = PQntuples(res);
5363 if (ntups == 0)
5364 goto cleanup;
5365
5366 /* Get pg_subscription_rel attributes */
5367 i_srsubid = PQfnumber(res, "srsubid");
5368 i_srrelid = PQfnumber(res, "srrelid");
5369 i_srsubstate = PQfnumber(res, "srsubstate");
5370 i_srsublsn = PQfnumber(res, "srsublsn");
5371
5372 subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
5373 for (int i = 0; i < ntups; i++)
5374 {
5376 Oid relid = atooid(PQgetvalue(res, i, i_srrelid));
5377 TableInfo *tblinfo;
5378
5379 /*
5380 * If we switched to a new subscription, check if the subscription
5381 * exists.
5382 */
5384 {
5386 if (subinfo == NULL)
5387 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
5388
5390 }
5391
5392 tblinfo = findTableByOid(relid);
5393 if (tblinfo == NULL)
5394 pg_fatal("failed sanity check, relation with OID %u not found",
5395 relid);
5396
5397 /* OK, make a DumpableObject for this relationship */
5398 subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
5399 subrinfo[i].dobj.catId.tableoid = relid;
5400 subrinfo[i].dobj.catId.oid = cur_srsubid;
5401 AssignDumpId(&subrinfo[i].dobj);
5402 subrinfo[i].dobj.namespace = tblinfo->dobj.namespace;
5403 subrinfo[i].dobj.name = tblinfo->dobj.name;
5404 subrinfo[i].subinfo = subinfo;
5405 subrinfo[i].tblinfo = tblinfo;
5406 subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
5407 if (PQgetisnull(res, i, i_srsublsn))
5408 subrinfo[i].srsublsn = NULL;
5409 else
5410 subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
5411
5412 /* Decide whether we want to dump it */
5414 }
5415
5416cleanup:
5417 PQclear(res);
5418}
5419
5420/*
5421 * dumpSubscriptionTable
5422 * Dump the definition of the given subscription table mapping. This will be
5423 * used only in binary-upgrade mode for PG17 or later versions.
5424 */
5425static void
5427{
5428 DumpOptions *dopt = fout->dopt;
5429 SubscriptionInfo *subinfo = subrinfo->subinfo;
5430 PQExpBuffer query;
5431 char *tag;
5432
5433 /* Do nothing if not dumping schema */
5434 if (!dopt->dumpSchema)
5435 return;
5436
5437 Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
5438
5439 tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->tblinfo->dobj.name);
5440
5441 query = createPQExpBuffer();
5442
5443 if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5444 {
5445 /*
5446 * binary_upgrade_add_sub_rel_state will add the subscription relation
5447 * to pg_subscription_rel table. This will be used only in
5448 * binary-upgrade mode.
5449 */
5451 "\n-- For binary upgrade, must preserve the subscriber table.\n");
5453 "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
5454 appendStringLiteralAH(query, subinfo->dobj.name, fout);
5455 appendPQExpBuffer(query,
5456 ", %u, '%c'",
5457 subrinfo->tblinfo->dobj.catId.oid,
5458 subrinfo->srsubstate);
5459
5460 if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
5461 appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
5462 else
5463 appendPQExpBufferStr(query, ", NULL");
5464
5465 appendPQExpBufferStr(query, ");\n");
5466 }
5467
5468 /*
5469 * There is no point in creating a drop query as the drop is done by table
5470 * drop. (If you think to change this, see also _printTocEntry().)
5471 * Although this object doesn't really have ownership as such, set the
5472 * owner field anyway to ensure that the command is run by the correct
5473 * role at restore time.
5474 */
5475 if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5476 ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
5477 ARCHIVE_OPTS(.tag = tag,
5478 .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
5479 .owner = subinfo->rolname,
5480 .description = "SUBSCRIPTION TABLE",
5481 .section = SECTION_POST_DATA,
5482 .createStmt = query->data));
5483
5484 /* These objects can't currently have comments or seclabels */
5485
5486 free(tag);
5487 destroyPQExpBuffer(query);
5488}
5489
5490/*
5491 * dumpSubscription
5492 * dump the definition of the given subscription
5493 */
5494static void
5496{
5497 DumpOptions *dopt = fout->dopt;
5499 PQExpBuffer query;
5500 PQExpBuffer publications;
5501 char *qsubname;
5502 char **pubnames = NULL;
5503 int npubnames = 0;
5504 int i;
5505
5506 /* Do nothing if not dumping schema */
5507 if (!dopt->dumpSchema)
5508 return;
5509
5511 query = createPQExpBuffer();
5512
5513 qsubname = pg_strdup(fmtId(subinfo->dobj.name));
5514
5515 appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
5516 qsubname);
5517
5518 appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
5519 qsubname);
5520 appendStringLiteralAH(query, subinfo->subconninfo, fout);
5521
5522 /* Build list of quoted publications and append them to query. */
5524 pg_fatal("could not parse %s array", "subpublications");
5525
5526 publications = createPQExpBuffer();
5527 for (i = 0; i < npubnames; i++)
5528 {
5529 if (i > 0)
5530 appendPQExpBufferStr(publications, ", ");
5531
5532 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
5533 }
5534
5535 appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
5536 if (subinfo->subslotname)
5537 appendStringLiteralAH(query, subinfo->subslotname, fout);
5538 else
5539 appendPQExpBufferStr(query, "NONE");
5540
5541 if (subinfo->subbinary)
5542 appendPQExpBufferStr(query, ", binary = true");
5543
5544 if (subinfo->substream == LOGICALREP_STREAM_ON)
5545 appendPQExpBufferStr(query, ", streaming = on");
5546 else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
5547 appendPQExpBufferStr(query, ", streaming = parallel");
5548 else
5549 appendPQExpBufferStr(query, ", streaming = off");
5550
5552 appendPQExpBufferStr(query, ", two_phase = on");
5553
5554 if (subinfo->subdisableonerr)
5555 appendPQExpBufferStr(query, ", disable_on_error = true");
5556
5557 if (!subinfo->subpasswordrequired)
5558 appendPQExpBufferStr(query, ", password_required = false");
5559
5560 if (subinfo->subrunasowner)
5561 appendPQExpBufferStr(query, ", run_as_owner = true");
5562
5563 if (subinfo->subfailover)
5564 appendPQExpBufferStr(query, ", failover = true");
5565
5566 if (subinfo->subretaindeadtuples)
5567 appendPQExpBufferStr(query, ", retain_dead_tuples = true");
5568
5569 if (subinfo->submaxretention)
5570 appendPQExpBuffer(query, ", max_retention_duration = %d", subinfo->submaxretention);
5571
5572 if (strcmp(subinfo->subsynccommit, "off") != 0)
5573 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
5574
5575 if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
5576 appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
5577
5578 appendPQExpBufferStr(query, ");\n");
5579
5580 /*
5581 * In binary-upgrade mode, we allow the replication to continue after the
5582 * upgrade.
5583 */
5584 if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5585 {
5586 if (subinfo->suboriginremotelsn)
5587 {
5588 /*
5589 * Preserve the remote_lsn for the subscriber's replication
5590 * origin. This value is required to start the replication from
5591 * the position before the upgrade. This value will be stale if
5592 * the publisher gets upgraded before the subscriber node.
5593 * However, this shouldn't be a problem as the upgrade of the
5594 * publisher ensures that all the transactions were replicated
5595 * before upgrading it.
5596 */
5598 "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
5600 "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
5601 appendStringLiteralAH(query, subinfo->dobj.name, fout);
5602 appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
5603 }
5604
5605 if (subinfo->subenabled)
5606 {
5607 /*
5608 * Enable the subscription to allow the replication to continue
5609 * after the upgrade.
5610 */
5612 "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
5613 appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
5614 }
5615 }
5616
5617 if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5618 ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
5619 ARCHIVE_OPTS(.tag = subinfo->dobj.name,
5620 .owner = subinfo->rolname,
5621 .description = "SUBSCRIPTION",
5622 .section = SECTION_POST_DATA,
5623 .createStmt = query->data,
5624 .dropStmt = delq->data));
5625
5626 if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
5627 dumpComment(fout, "SUBSCRIPTION", qsubname,
5628 NULL, subinfo->rolname,
5629 subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5630
5631 if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
5632 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
5633 NULL, subinfo->rolname,
5634 subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5635
5636 destroyPQExpBuffer(publications);
5637 free(pubnames);
5638
5640 destroyPQExpBuffer(query);
5641 free(qsubname);
5642}
5643
5644/*
5645 * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
5646 * the object needs.
5647 */
5648static void
5650 PQExpBuffer create,
5651 const DumpableObject *dobj,
5652 const char *catalog,
5653 const char *keyword,
5654 const char *objname)
5655{
5656 if (dobj->depends_on_ext)
5657 {
5658 char *nm;
5659 PGresult *res;
5660 PQExpBuffer query;
5661 int ntups;
5662 int i_extname;
5663 int i;
5664
5665 /* dodge fmtId() non-reentrancy */
5666 nm = pg_strdup(objname);
5667
5668 query = createPQExpBuffer();
5669 appendPQExpBuffer(query,
5670 "SELECT e.extname "
5671 "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
5672 "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
5673 "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
5674 "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
5675 catalog,
5676 dobj->catId.oid);
5677 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5678 ntups = PQntuples(res);
5679 i_extname = PQfnumber(res, "extname");
5680 for (i = 0; i < ntups; i++)
5681 {
5682 appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
5683 keyword, nm,
5684 fmtId(PQgetvalue(res, i, i_extname)));
5685 }
5686
5687 PQclear(res);
5688 destroyPQExpBuffer(query);
5689 pg_free(nm);
5690 }
5691}
5692
5693static Oid
5695{
5696 /*
5697 * If the old version didn't assign an array type, but the new version
5698 * does, we must select an unused type OID to assign. This currently only
5699 * happens for domains, when upgrading pre-v11 to v11 and up.
5700 *
5701 * Note: local state here is kind of ugly, but we must have some, since we
5702 * mustn't choose the same unused OID more than once.
5703 */
5705 PGresult *res;
5706 bool is_dup;
5707
5708 do
5709 {
5712 "SELECT EXISTS(SELECT 1 "
5713 "FROM pg_catalog.pg_type "
5714 "WHERE oid = '%u'::pg_catalog.oid);",
5717 is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
5718 PQclear(res);
5719 } while (is_dup);
5720
5722}
5723
5724static void
5728 bool force_array_type,
5730{
5732 PGresult *res;
5736 TypeInfo *tinfo;
5737
5738 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
5740 "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5741 pg_type_oid);
5742
5744 if (tinfo)
5745 pg_type_array_oid = tinfo->typarray;
5746 else
5748
5751
5753 {
5755 "\n-- For binary upgrade, must preserve pg_type array oid\n");
5757 "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5759 }
5760
5761 /*
5762 * Pre-set the multirange type oid and its own array type oid.
5763 */
5765 {
5766 if (fout->remoteVersion >= 140000)
5767 {
5769 "SELECT t.oid, t.typarray "
5770 "FROM pg_catalog.pg_type t "
5771 "JOIN pg_catalog.pg_range r "
5772 "ON t.oid = r.rngmultitypid "
5773 "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
5774 pg_type_oid);
5775
5777
5778 pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
5779 pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
5780
5781 PQclear(res);
5782 }
5783 else
5784 {
5787 }
5788
5790 "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
5792 "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5795 "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
5797 "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5799 }
5800
5802}
5803
5804static void
5807 const TableInfo *tbinfo)
5808{
5809 Oid pg_type_oid = tbinfo->reltype;
5810
5813 pg_type_oid, false, false);
5814}
5815
5816/*
5817 * bsearch() comparator for BinaryUpgradeClassOidItem
5818 */
5819static int
5820BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
5821{
5824
5825 return pg_cmp_u32(v1.oid, v2.oid);
5826}
5827
5828/*
5829 * collectBinaryUpgradeClassOids
5830 *
5831 * Construct a table of pg_class information required for
5832 * binary_upgrade_set_pg_class_oids(). The table is sorted by OID for speed in
5833 * lookup.
5834 */
5835static void
5837{
5838 PGresult *res;
5839 const char *query;
5840
5841 query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
5842 "ct.relfilenode, i.indexrelid, cti.relfilenode "
5843 "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
5844 "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
5845 "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
5846 "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
5847 "ORDER BY c.oid;";
5848
5849 res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
5850
5854
5855 for (int i = 0; i < nbinaryUpgradeClassOids; i++)
5856 {
5864 }
5865
5866 PQclear(res);
5867}
5868
5869static void
5872{
5875
5877
5878 /*
5879 * Preserve the OID and relfilenumber of the table, table's index, table's
5880 * toast table and toast table's index if any.
5881 *
5882 * One complexity is that the current table definition might not require
5883 * the creation of a TOAST table, but the old database might have a TOAST
5884 * table that was created earlier, before some wide columns were dropped.
5885 * By setting the TOAST oid we force creation of the TOAST heap and index
5886 * by the new backend, so we can copy the files during binary upgrade
5887 * without worrying about this case.
5888 */
5889 key.oid = pg_class_oid;
5893
5895 "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
5896
5897 if (entry->relkind != RELKIND_INDEX &&
5899 {
5901 "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
5902 pg_class_oid);
5903
5904 /*
5905 * Not every relation has storage. Also, in a pre-v12 database,
5906 * partitioned tables have a relfilenumber, which should not be
5907 * preserved when upgrading.
5908 */
5909 if (RelFileNumberIsValid(entry->relfilenumber) &&
5912 "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
5913 entry->relfilenumber);
5914
5915 /*
5916 * In a pre-v12 database, partitioned tables might be marked as having
5917 * toast tables, but we should ignore them if so.
5918 */
5919 if (OidIsValid(entry->toast_oid) &&
5921 {
5923 "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
5924 entry->toast_oid);
5926 "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
5927 entry->toast_relfilenumber);
5928
5929 /* every toast table has an index */
5931 "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5932 entry->toast_index_oid);
5934 "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5936 }
5937 }
5938 else
5939 {
5940 /* Preserve the OID and relfilenumber of the index */
5942 "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5943 pg_class_oid);
5945 "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5946 entry->relfilenumber);
5947 }
5948
5950}
5951
5952/*
5953 * If the DumpableObject is a member of an extension, add a suitable
5954 * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
5955 *
5956 * For somewhat historical reasons, objname should already be quoted,
5957 * but not objnamespace (if any).
5958 */
5959static void
5961 const DumpableObject *dobj,
5962 const char *objtype,
5963 const char *objname,
5964 const char *objnamespace)
5965{
5967 int i;
5968
5969 if (!dobj->ext_member)
5970 return;
5971
5972 /*
5973 * Find the parent extension. We could avoid this search if we wanted to
5974 * add a link field to DumpableObject, but the space costs of that would
5975 * be considerable. We assume that member objects could only have a
5976 * direct dependency on their own extension, not any others.
5977 */
5978 for (i = 0; i < dobj->nDeps; i++)
5979 {
5981 if (extobj && extobj->objType == DO_EXTENSION)
5982 break;
5983 extobj = NULL;
5984 }
5985 if (extobj == NULL)
5986 pg_fatal("could not find parent extension for %s %s",
5987 objtype, objname);
5988
5990 "\n-- For binary upgrade, handle extension membership the hard way\n");
5991 appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
5992 fmtId(extobj->name),
5993 objtype);
5994 if (objnamespace && *objnamespace)
5996 appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
5997}
5998
5999/*
6000 * getNamespaces:
6001 * get information about all namespaces in the system catalogs
6002 */
6003void
6005{
6006 PGresult *res;
6007 int ntups;
6008 int i;
6009 PQExpBuffer query;
6011 int i_tableoid;
6012 int i_oid;
6013 int i_nspname;
6014 int i_nspowner;
6015 int i_nspacl;
6016 int i_acldefault;
6017
6018 query = createPQExpBuffer();
6019
6020 /*
6021 * we fetch all namespaces including system ones, so that every object we
6022 * read in can be linked to a containing namespace.
6023 */
6024 appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
6025 "n.nspowner, "
6026 "n.nspacl, "
6027 "acldefault('n', n.nspowner) AS acldefault "
6028 "FROM pg_namespace n");
6029
6030 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6031
6032 ntups = PQntuples(res);
6033
6034 nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
6035
6036 i_tableoid = PQfnumber(res, "tableoid");
6037 i_oid = PQfnumber(res, "oid");
6038 i_nspname = PQfnumber(res, "nspname");
6039 i_nspowner = PQfnumber(res, "nspowner");
6040 i_nspacl = PQfnumber(res, "nspacl");
6041 i_acldefault = PQfnumber(res, "acldefault");
6042
6043 for (i = 0; i < ntups; i++)
6044 {
6045 const char *nspowner;
6046
6047 nsinfo[i].dobj.objType = DO_NAMESPACE;
6048 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6049 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6050 AssignDumpId(&nsinfo[i].dobj);
6051 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
6052 nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
6053 nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6054 nsinfo[i].dacl.privtype = 0;
6055 nsinfo[i].dacl.initprivs = NULL;
6056 nspowner = PQgetvalue(res, i, i_nspowner);
6057 nsinfo[i].nspowner = atooid(nspowner);
6058 nsinfo[i].rolname = getRoleName(nspowner);
6059
6060 /* Decide whether to dump this namespace */
6062
6063 /* Mark whether namespace has an ACL */
6064 if (!PQgetisnull(res, i, i_nspacl))
6065 nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6066
6067 /*
6068 * We ignore any pg_init_privs.initprivs entry for the public schema
6069 * and assume a predetermined default, for several reasons. First,
6070 * dropping and recreating the schema removes its pg_init_privs entry,
6071 * but an empty destination database starts with this ACL nonetheless.
6072 * Second, we support dump/reload of public schema ownership changes.
6073 * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
6074 * initprivs continues to reflect the initial owner. Hence,
6075 * synthesize the value that nspacl will have after the restore's
6076 * ALTER SCHEMA OWNER. Third, this makes the destination database
6077 * match the source's ACL, even if the latter was an initdb-default
6078 * ACL, which changed in v15. An upgrade pulls in changes to most
6079 * system object ACLs that the DBA had not customized. We've made the
6080 * public schema depart from that, because changing its ACL so easily
6081 * breaks applications.
6082 */
6083 if (strcmp(nsinfo[i].dobj.name, "public") == 0)
6084 {
6087
6088 /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
6099
6100 nsinfo[i].dacl.privtype = 'i';
6101 nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
6102 nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6103
6106 }
6107 }
6108
6109 PQclear(res);
6110 destroyPQExpBuffer(query);
6111}
6112
6113/*
6114 * findNamespace:
6115 * given a namespace OID, look up the info read by getNamespaces
6116 */
6117static NamespaceInfo *
6119{
6121
6123 if (nsinfo == NULL)
6124 pg_fatal("schema with OID %u does not exist", nsoid);
6125 return nsinfo;
6126}
6127
6128/*
6129 * getExtensions:
6130 * read all extensions in the system catalogs and return them in the
6131 * ExtensionInfo* structure
6132 *
6133 * numExtensions is set to the number of extensions read in
6134 */
6137{
6138 DumpOptions *dopt = fout->dopt;
6139 PGresult *res;
6140 int ntups;
6141 int i;
6142 PQExpBuffer query;
6144 int i_tableoid;
6145 int i_oid;
6146 int i_extname;
6147 int i_nspname;
6148 int i_extrelocatable;
6149 int i_extversion;
6150 int i_extconfig;
6151 int i_extcondition;
6152
6153 query = createPQExpBuffer();
6154
6155 appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
6156 "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
6157 "FROM pg_extension x "
6158 "JOIN pg_namespace n ON n.oid = x.extnamespace");
6159
6160 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6161
6162 ntups = PQntuples(res);
6163 if (ntups == 0)
6164 goto cleanup;
6165
6166 extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
6167
6168 i_tableoid = PQfnumber(res, "tableoid");
6169 i_oid = PQfnumber(res, "oid");
6170 i_extname = PQfnumber(res, "extname");
6171 i_nspname = PQfnumber(res, "nspname");
6172 i_extrelocatable = PQfnumber(res, "extrelocatable");
6173 i_extversion = PQfnumber(res, "extversion");
6174 i_extconfig = PQfnumber(res, "extconfig");
6175 i_extcondition = PQfnumber(res, "extcondition");
6176
6177 for (i = 0; i < ntups; i++)
6178 {
6179 extinfo[i].dobj.objType = DO_EXTENSION;
6180 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6181 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6182 AssignDumpId(&extinfo[i].dobj);
6183 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
6184 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
6185 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
6186 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
6187 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
6188 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
6189
6190 /* Decide whether we want to dump it */
6192 }
6193
6194cleanup:
6195 PQclear(res);
6196 destroyPQExpBuffer(query);
6197
6198 *numExtensions = ntups;
6199
6200 return extinfo;
6201}
6202
6203/*
6204 * getTypes:
6205 * get information about all types in the system catalogs
6206 *
6207 * NB: this must run after getFuncs() because we assume we can do
6208 * findFuncByOid().
6209 */
6210void
6212{
6213 PGresult *res;
6214 int ntups;
6215 int i;
6219 int i_tableoid;
6220 int i_oid;
6221 int i_typname;
6222 int i_typnamespace;
6223 int i_typacl;
6224 int i_acldefault;
6225 int i_typowner;
6226 int i_typelem;
6227 int i_typrelid;
6228 int i_typrelkind;
6229 int i_typtype;
6230 int i_typisdefined;
6231 int i_isarray;
6232 int i_typarray;
6233
6234 /*
6235 * we include even the built-in types because those may be used as array
6236 * elements by user-defined types
6237 *
6238 * we filter out the built-in types when we dump out the types
6239 *
6240 * same approach for undefined (shell) types and array types
6241 *
6242 * Note: as of 8.3 we can reliably detect whether a type is an
6243 * auto-generated array type by checking the element type's typarray.
6244 * (Before that the test is capable of generating false positives.) We
6245 * still check for name beginning with '_', though, so as to avoid the
6246 * cost of the subselect probe for all standard types. This would have to
6247 * be revisited if the backend ever allows renaming of array types.
6248 */
6249 appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
6250 "typnamespace, typacl, "
6251 "acldefault('T', typowner) AS acldefault, "
6252 "typowner, "
6253 "typelem, typrelid, typarray, "
6254 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
6255 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
6256 "typtype, typisdefined, "
6257 "typname[0] = '_' AND typelem != 0 AND "
6258 "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
6259 "FROM pg_type");
6260
6261 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6262
6263 ntups = PQntuples(res);
6264
6265 tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
6266
6267 i_tableoid = PQfnumber(res, "tableoid");
6268 i_oid = PQfnumber(res, "oid");
6269 i_typname = PQfnumber(res, "typname");
6270 i_typnamespace = PQfnumber(res, "typnamespace");
6271 i_typacl = PQfnumber(res, "typacl");
6272 i_acldefault = PQfnumber(res, "acldefault");
6273 i_typowner = PQfnumber(res, "typowner");
6274 i_typelem = PQfnumber(res, "typelem");
6275 i_typrelid = PQfnumber(res, "typrelid");
6276 i_typrelkind = PQfnumber(res, "typrelkind");
6277 i_typtype = PQfnumber(res, "typtype");
6278 i_typisdefined = PQfnumber(res, "typisdefined");
6279 i_isarray = PQfnumber(res, "isarray");
6280 i_typarray = PQfnumber(res, "typarray");
6281
6282 for (i = 0; i < ntups; i++)
6283 {
6284 tyinfo[i].dobj.objType = DO_TYPE;
6285 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6286 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6287 AssignDumpId(&tyinfo[i].dobj);
6288 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
6289 tyinfo[i].dobj.namespace =
6291 tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
6292 tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6293 tyinfo[i].dacl.privtype = 0;
6294 tyinfo[i].dacl.initprivs = NULL;
6295 tyinfo[i].ftypname = NULL; /* may get filled later */
6296 tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
6297 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
6298 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
6299 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
6300 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
6301 tyinfo[i].shellType = NULL;
6302
6303 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
6304 tyinfo[i].isDefined = true;
6305 else
6306 tyinfo[i].isDefined = false;
6307
6308 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
6309 tyinfo[i].isArray = true;
6310 else
6311 tyinfo[i].isArray = false;
6312
6313 tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
6314
6315 if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
6316 tyinfo[i].isMultirange = true;
6317 else
6318 tyinfo[i].isMultirange = false;
6319
6320 /* Decide whether we want to dump it */
6322
6323 /* Mark whether type has an ACL */
6324 if (!PQgetisnull(res, i, i_typacl))
6325 tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6326
6327 /*
6328 * If it's a domain, fetch info about its constraints, if any
6329 */
6330 tyinfo[i].nDomChecks = 0;
6331 tyinfo[i].domChecks = NULL;
6332 tyinfo[i].notnull = NULL;
6333 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6334 tyinfo[i].typtype == TYPTYPE_DOMAIN)
6336
6337 /*
6338 * If it's a base type, make a DumpableObject representing a shell
6339 * definition of the type. We will need to dump that ahead of the I/O
6340 * functions for the type. Similarly, range types need a shell
6341 * definition in case they have a canonicalize function.
6342 *
6343 * Note: the shell type doesn't have a catId. You might think it
6344 * should copy the base type's catId, but then it might capture the
6345 * pg_depend entries for the type, which we don't want.
6346 */
6347 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6348 (tyinfo[i].typtype == TYPTYPE_BASE ||
6349 tyinfo[i].typtype == TYPTYPE_RANGE))
6350 {
6352 stinfo->dobj.objType = DO_SHELL_TYPE;
6353 stinfo->dobj.catId = nilCatalogId;
6354 AssignDumpId(&stinfo->dobj);
6355 stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
6356 stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
6357 stinfo->baseType = &(tyinfo[i]);
6358 tyinfo[i].shellType = stinfo;
6359
6360 /*
6361 * Initially mark the shell type as not to be dumped. We'll only
6362 * dump it if the I/O or canonicalize functions need to be dumped;
6363 * this is taken care of while sorting dependencies.
6364 */
6365 stinfo->dobj.dump = DUMP_COMPONENT_NONE;
6366 }
6367 }
6368
6369 PQclear(res);
6370
6371 destroyPQExpBuffer(query);
6372}
6373
6374/*
6375 * getOperators:
6376 * get information about all operators in the system catalogs
6377 */
6378void
6380{
6381 PGresult *res;
6382 int ntups;
6383 int i;
6386 int i_tableoid;
6387 int i_oid;
6388 int i_oprname;
6389 int i_oprnamespace;
6390 int i_oprowner;
6391 int i_oprkind;
6392 int i_oprleft;
6393 int i_oprright;
6394 int i_oprcode;
6395
6396 /*
6397 * find all operators, including builtin operators; we filter out
6398 * system-defined operators at dump-out time.
6399 */
6400
6401 appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
6402 "oprnamespace, "
6403 "oprowner, "
6404 "oprkind, "
6405 "oprleft, "
6406 "oprright, "
6407 "oprcode::oid AS oprcode "
6408 "FROM pg_operator");
6409
6410 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6411
6412 ntups = PQntuples(res);
6413
6414 oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
6415
6416 i_tableoid = PQfnumber(res, "tableoid");
6417 i_oid = PQfnumber(res, "oid");
6418 i_oprname = PQfnumber(res, "oprname");
6419 i_oprnamespace = PQfnumber(res, "oprnamespace");
6420 i_oprowner = PQfnumber(res, "oprowner");
6421 i_oprkind = PQfnumber(res, "oprkind");
6422 i_oprleft = PQfnumber(res, "oprleft");
6423 i_oprright = PQfnumber(res, "oprright");
6424 i_oprcode = PQfnumber(res, "oprcode");
6425
6426 for (i = 0; i < ntups; i++)
6427 {
6428 oprinfo[i].dobj.objType = DO_OPERATOR;
6429 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6430 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6431 AssignDumpId(&oprinfo[i].dobj);
6432 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
6433 oprinfo[i].dobj.namespace =
6435 oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
6436 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
6437 oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
6438 oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
6439 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
6440
6441 /* Decide whether we want to dump it */
6443 }
6444
6445 PQclear(res);
6446
6447 destroyPQExpBuffer(query);
6448}
6449
6450/*
6451 * getCollations:
6452 * get information about all collations in the system catalogs
6453 */
6454void
6456{
6457 PGresult *res;
6458 int ntups;
6459 int i;
6460 PQExpBuffer query;
6462 int i_tableoid;
6463 int i_oid;
6464 int i_collname;
6465 int i_collnamespace;
6466 int i_collowner;
6467 int i_collencoding;
6468
6469 query = createPQExpBuffer();
6470
6471 /*
6472 * find all collations, including builtin collations; we filter out
6473 * system-defined collations at dump-out time.
6474 */
6475
6476 appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
6477 "collnamespace, "
6478 "collowner, "
6479 "collencoding "
6480 "FROM pg_collation");
6481
6482 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6483
6484 ntups = PQntuples(res);
6485
6486 collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
6487
6488 i_tableoid = PQfnumber(res, "tableoid");
6489 i_oid = PQfnumber(res, "oid");
6490 i_collname = PQfnumber(res, "collname");
6491 i_collnamespace = PQfnumber(res, "collnamespace");
6492 i_collowner = PQfnumber(res, "collowner");
6493 i_collencoding = PQfnumber(res, "collencoding");
6494
6495 for (i = 0; i < ntups; i++)
6496 {
6497 collinfo[i].dobj.objType = DO_COLLATION;
6498 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6499 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6500 AssignDumpId(&collinfo[i].dobj);
6501 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
6502 collinfo[i].dobj.namespace =
6504 collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
6505 collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
6506
6507 /* Decide whether we want to dump it */
6509 }
6510
6511 PQclear(res);
6512
6513 destroyPQExpBuffer(query);
6514}
6515
6516/*
6517 * getConversions:
6518 * get information about all conversions in the system catalogs
6519 */
6520void
6522{
6523 PGresult *res;
6524 int ntups;
6525 int i;
6526 PQExpBuffer query;
6528 int i_tableoid;
6529 int i_oid;
6530 int i_conname;
6531 int i_connamespace;
6532 int i_conowner;
6533
6534 query = createPQExpBuffer();
6535
6536 /*
6537 * find all conversions, including builtin conversions; we filter out
6538 * system-defined conversions at dump-out time.
6539 */
6540
6541 appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
6542 "connamespace, "
6543 "conowner "
6544 "FROM pg_conversion");
6545
6546 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6547
6548 ntups = PQntuples(res);
6549
6550 convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
6551
6552 i_tableoid = PQfnumber(res, "tableoid");
6553 i_oid = PQfnumber(res, "oid");
6554 i_conname = PQfnumber(res, "conname");
6555 i_connamespace = PQfnumber(res, "connamespace");
6556 i_conowner = PQfnumber(res, "conowner");
6557
6558 for (i = 0; i < ntups; i++)
6559 {
6560 convinfo[i].dobj.objType = DO_CONVERSION;
6561 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6562 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6563 AssignDumpId(&convinfo[i].dobj);
6564 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
6565 convinfo[i].dobj.namespace =
6567 convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
6568
6569 /* Decide whether we want to dump it */
6571 }
6572
6573 PQclear(res);
6574
6575 destroyPQExpBuffer(query);
6576}
6577
6578/*
6579 * getAccessMethods:
6580 * get information about all user-defined access methods
6581 */
6582void
6584{
6585 PGresult *res;
6586 int ntups;
6587 int i;
6588 PQExpBuffer query;
6590 int i_tableoid;
6591 int i_oid;
6592 int i_amname;
6593 int i_amhandler;
6594 int i_amtype;
6595
6596 query = createPQExpBuffer();
6597
6598 /*
6599 * Select all access methods from pg_am table. v9.6 introduced CREATE
6600 * ACCESS METHOD, so earlier versions usually have only built-in access
6601 * methods. v9.6 also changed the access method API, replacing dozens of
6602 * pg_am columns with amhandler. Even if a user created an access method
6603 * by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am
6604 * columns to a v9.6+ CREATE ACCESS METHOD. Hence, before v9.6, read
6605 * pg_am just to facilitate findAccessMethodByOid() providing the
6606 * OID-to-name mapping.
6607 */
6608 appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
6609 if (fout->remoteVersion >= 90600)
6611 "amtype, "
6612 "amhandler::pg_catalog.regproc AS amhandler ");
6613 else
6615 "'i'::pg_catalog.\"char\" AS amtype, "
6616 "'-'::pg_catalog.regproc AS amhandler ");
6617 appendPQExpBufferStr(query, "FROM pg_am");
6618
6619 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6620
6621 ntups = PQntuples(res);
6622
6623 aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
6624
6625 i_tableoid = PQfnumber(res, "tableoid");
6626 i_oid = PQfnumber(res, "oid");
6627 i_amname = PQfnumber(res, "amname");
6628 i_amhandler = PQfnumber(res, "amhandler");
6629 i_amtype = PQfnumber(res, "amtype");
6630
6631 for (i = 0; i < ntups; i++)
6632 {
6633 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
6634 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6635 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6636 AssignDumpId(&aminfo[i].dobj);
6637 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
6638 aminfo[i].dobj.namespace = NULL;
6639 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
6640 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
6641
6642 /* Decide whether we want to dump it */
6644 }
6645
6646 PQclear(res);
6647
6648 destroyPQExpBuffer(query);
6649}
6650
6651
6652/*
6653 * getOpclasses:
6654 * get information about all opclasses in the system catalogs
6655 */
6656void
6658{
6659 PGresult *res;
6660 int ntups;
6661 int i;
6664 int i_tableoid;
6665 int i_oid;
6666 int i_opcmethod;
6667 int i_opcname;
6668 int i_opcnamespace;
6669 int i_opcowner;
6670
6671 /*
6672 * find all opclasses, including builtin opclasses; we filter out
6673 * system-defined opclasses at dump-out time.
6674 */
6675
6676 appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
6677 "opcnamespace, "
6678 "opcowner "
6679 "FROM pg_opclass");
6680
6681 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6682
6683 ntups = PQntuples(res);
6684
6685 opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
6686
6687 i_tableoid = PQfnumber(res, "tableoid");
6688 i_oid = PQfnumber(res, "oid");
6689 i_opcmethod = PQfnumber(res, "opcmethod");
6690 i_opcname = PQfnumber(res, "opcname");
6691 i_opcnamespace = PQfnumber(res, "opcnamespace");
6692 i_opcowner = PQfnumber(res, "opcowner");
6693
6694 for (i = 0; i < ntups; i++)
6695 {
6696 opcinfo[i].dobj.objType = DO_OPCLASS;
6697 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6698 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6699 AssignDumpId(&opcinfo[i].dobj);
6700 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
6701 opcinfo[i].dobj.namespace =
6703 opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
6704 opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
6705
6706 /* Decide whether we want to dump it */
6708 }
6709
6710 PQclear(res);
6711
6712 destroyPQExpBuffer(query);
6713}
6714
6715/*
6716 * getOpfamilies:
6717 * get information about all opfamilies in the system catalogs
6718 */
6719void
6721{
6722 PGresult *res;
6723 int ntups;
6724 int i;
6725 PQExpBuffer query;
6727 int i_tableoid;
6728 int i_oid;
6729 int i_opfmethod;
6730 int i_opfname;
6731 int i_opfnamespace;
6732 int i_opfowner;
6733
6734 query = createPQExpBuffer();
6735
6736 /*
6737 * find all opfamilies, including builtin opfamilies; we filter out
6738 * system-defined opfamilies at dump-out time.
6739 */
6740
6741 appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
6742 "opfnamespace, "
6743 "opfowner "
6744 "FROM pg_opfamily");
6745
6746 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6747
6748 ntups = PQntuples(res);
6749
6750 opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
6751
6752 i_tableoid = PQfnumber(res, "tableoid");
6753 i_oid = PQfnumber(res, "oid");
6754 i_opfname = PQfnumber(res, "opfname");
6755 i_opfmethod = PQfnumber(res, "opfmethod");
6756 i_opfnamespace = PQfnumber(res, "opfnamespace");
6757 i_opfowner = PQfnumber(res, "opfowner");
6758
6759 for (i = 0; i < ntups; i++)
6760 {
6761 opfinfo[i].dobj.objType = DO_OPFAMILY;
6762 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6763 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6764 AssignDumpId(&opfinfo[i].dobj);
6765 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
6766 opfinfo[i].dobj.namespace =
6768 opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
6769 opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
6770
6771 /* Decide whether we want to dump it */
6773 }
6774
6775 PQclear(res);
6776
6777 destroyPQExpBuffer(query);
6778}
6779
6780/*
6781 * getAggregates:
6782 * get information about all user-defined aggregates in the system catalogs
6783 */
6784void
6786{
6787 DumpOptions *dopt = fout->dopt;
6788 PGresult *res;
6789 int ntups;
6790 int i;
6793 int i_tableoid;
6794 int i_oid;
6795 int i_aggname;
6796 int i_aggnamespace;
6797 int i_pronargs;
6798 int i_proargtypes;
6799 int i_proowner;
6800 int i_aggacl;
6801 int i_acldefault;
6802
6803 /*
6804 * Find all interesting aggregates. See comment in getFuncs() for the
6805 * rationale behind the filtering logic.
6806 */
6807 if (fout->remoteVersion >= 90600)
6808 {
6809 const char *agg_check;
6810
6811 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
6812 : "p.proisagg");
6813
6814 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
6815 "p.proname AS aggname, "
6816 "p.pronamespace AS aggnamespace, "
6817 "p.pronargs, p.proargtypes, "
6818 "p.proowner, "
6819 "p.proacl AS aggacl, "
6820 "acldefault('f', p.proowner) AS acldefault "
6821 "FROM pg_proc p "
6822 "LEFT JOIN pg_init_privs pip ON "
6823 "(p.oid = pip.objoid "
6824 "AND pip.classoid = 'pg_proc'::regclass "
6825 "AND pip.objsubid = 0) "
6826 "WHERE %s AND ("
6827 "p.pronamespace != "
6828 "(SELECT oid FROM pg_namespace "
6829 "WHERE nspname = 'pg_catalog') OR "
6830 "p.proacl IS DISTINCT FROM pip.initprivs",
6831 agg_check);
6832 if (dopt->binary_upgrade)
6834 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6835 "classid = 'pg_proc'::regclass AND "
6836 "objid = p.oid AND "
6837 "refclassid = 'pg_extension'::regclass AND "
6838 "deptype = 'e')");
6839 appendPQExpBufferChar(query, ')');
6840 }
6841 else
6842 {
6843 appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
6844 "pronamespace AS aggnamespace, "
6845 "pronargs, proargtypes, "
6846 "proowner, "
6847 "proacl AS aggacl, "
6848 "acldefault('f', proowner) AS acldefault "
6849 "FROM pg_proc p "
6850 "WHERE proisagg AND ("
6851 "pronamespace != "
6852 "(SELECT oid FROM pg_namespace "
6853 "WHERE nspname = 'pg_catalog')");
6854 if (dopt->binary_upgrade)
6856 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6857 "classid = 'pg_proc'::regclass AND "
6858 "objid = p.oid AND "
6859 "refclassid = 'pg_extension'::regclass AND "
6860 "deptype = 'e')");
6861 appendPQExpBufferChar(query, ')');
6862 }
6863
6864 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6865
6866 ntups = PQntuples(res);
6867
6868 agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
6869
6870 i_tableoid = PQfnumber(res, "tableoid");
6871 i_oid = PQfnumber(res, "oid");
6872 i_aggname = PQfnumber(res, "aggname");
6873 i_aggnamespace = PQfnumber(res, "aggnamespace");
6874 i_pronargs = PQfnumber(res, "pronargs");
6875 i_proargtypes = PQfnumber(res, "proargtypes");
6876 i_proowner = PQfnumber(res, "proowner");
6877 i_aggacl = PQfnumber(res, "aggacl");
6878 i_acldefault = PQfnumber(res, "acldefault");
6879
6880 for (i = 0; i < ntups; i++)
6881 {
6882 agginfo[i].aggfn.dobj.objType = DO_AGG;
6883 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6884 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6885 AssignDumpId(&agginfo[i].aggfn.dobj);
6886 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
6887 agginfo[i].aggfn.dobj.namespace =
6889 agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
6890 agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6891 agginfo[i].aggfn.dacl.privtype = 0;
6892 agginfo[i].aggfn.dacl.initprivs = NULL;
6893 agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
6894 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
6895 agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
6896 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
6897 if (agginfo[i].aggfn.nargs == 0)
6898 agginfo[i].aggfn.argtypes = NULL;
6899 else
6900 {
6901 agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
6903 agginfo[i].aggfn.argtypes,
6904 agginfo[i].aggfn.nargs);
6905 }
6906 agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
6907
6908 /* Decide whether we want to dump it */
6909 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
6910
6911 /* Mark whether aggregate has an ACL */
6912 if (!PQgetisnull(res, i, i_aggacl))
6913 agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
6914 }
6915
6916 PQclear(res);
6917
6918 destroyPQExpBuffer(query);
6919}
6920
6921/*
6922 * getFuncs:
6923 * get information about all user-defined functions in the system catalogs
6924 */
6925void
6927{
6928 DumpOptions *dopt = fout->dopt;
6929 PGresult *res;
6930 int ntups;
6931 int i;
6933 FuncInfo *finfo;
6934 int i_tableoid;
6935 int i_oid;
6936 int i_proname;
6937 int i_pronamespace;
6938 int i_proowner;
6939 int i_prolang;
6940 int i_pronargs;
6941 int i_proargtypes;
6942 int i_prorettype;
6943 int i_proacl;
6944 int i_acldefault;
6945
6946 /*
6947 * Find all interesting functions. This is a bit complicated:
6948 *
6949 * 1. Always exclude aggregates; those are handled elsewhere.
6950 *
6951 * 2. Always exclude functions that are internally dependent on something
6952 * else, since presumably those will be created as a result of creating
6953 * the something else. This currently acts only to suppress constructor
6954 * functions for range types. Note this is OK only because the
6955 * constructors don't have any dependencies the range type doesn't have;
6956 * otherwise we might not get creation ordering correct.
6957 *
6958 * 3. Otherwise, we normally exclude functions in pg_catalog. However, if
6959 * they're members of extensions and we are in binary-upgrade mode then
6960 * include them, since we want to dump extension members individually in
6961 * that mode. Also, if they are used by casts or transforms then we need
6962 * to gather the information about them, though they won't be dumped if
6963 * they are built-in. Also, in 9.6 and up, include functions in
6964 * pg_catalog if they have an ACL different from what's shown in
6965 * pg_init_privs (so we have to join to pg_init_privs; annoying).
6966 */
6967 if (fout->remoteVersion >= 90600)
6968 {
6969 const char *not_agg_check;
6970
6971 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
6972 : "NOT p.proisagg");
6973
6974 appendPQExpBuffer(query,
6975 "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
6976 "p.pronargs, p.proargtypes, p.prorettype, "
6977 "p.proacl, "
6978 "acldefault('f', p.proowner) AS acldefault, "
6979 "p.pronamespace, "
6980 "p.proowner "
6981 "FROM pg_proc p "
6982 "LEFT JOIN pg_init_privs pip ON "
6983 "(p.oid = pip.objoid "
6984 "AND pip.classoid = 'pg_proc'::regclass "
6985 "AND pip.objsubid = 0) "
6986 "WHERE %s"
6987 "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6988 "WHERE classid = 'pg_proc'::regclass AND "
6989 "objid = p.oid AND deptype = 'i')"
6990 "\n AND ("
6991 "\n pronamespace != "
6992 "(SELECT oid FROM pg_namespace "
6993 "WHERE nspname = 'pg_catalog')"
6994 "\n OR EXISTS (SELECT 1 FROM pg_cast"
6995 "\n WHERE pg_cast.oid > %u "
6996 "\n AND p.oid = pg_cast.castfunc)"
6997 "\n OR EXISTS (SELECT 1 FROM pg_transform"
6998 "\n WHERE pg_transform.oid > %u AND "
6999 "\n (p.oid = pg_transform.trffromsql"
7000 "\n OR p.oid = pg_transform.trftosql))",
7004 if (dopt->binary_upgrade)
7006 "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
7007 "classid = 'pg_proc'::regclass AND "
7008 "objid = p.oid AND "
7009 "refclassid = 'pg_extension'::regclass AND "
7010 "deptype = 'e')");
7012 "\n OR p.proacl IS DISTINCT FROM pip.initprivs");
7013 appendPQExpBufferChar(query, ')');
7014 }
7015 else
7016 {
7017 appendPQExpBuffer(query,
7018 "SELECT tableoid, oid, proname, prolang, "
7019 "pronargs, proargtypes, prorettype, proacl, "
7020 "acldefault('f', proowner) AS acldefault, "
7021 "pronamespace, "
7022 "proowner "
7023 "FROM pg_proc p "
7024 "WHERE NOT proisagg"
7025 "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
7026 "WHERE classid = 'pg_proc'::regclass AND "
7027 "objid = p.oid AND deptype = 'i')"
7028 "\n AND ("
7029 "\n pronamespace != "
7030 "(SELECT oid FROM pg_namespace "
7031 "WHERE nspname = 'pg_catalog')"
7032 "\n OR EXISTS (SELECT 1 FROM pg_cast"
7033 "\n WHERE pg_cast.oid > '%u'::oid"
7034 "\n AND p.oid = pg_cast.castfunc)",
7036
7037 if (fout->remoteVersion >= 90500)
7038 appendPQExpBuffer(query,
7039 "\n OR EXISTS (SELECT 1 FROM pg_transform"
7040 "\n WHERE pg_transform.oid > '%u'::oid"
7041 "\n AND (p.oid = pg_transform.trffromsql"
7042 "\n OR p.oid = pg_transform.trftosql))",
7044
7045 if (dopt->binary_upgrade)
7047 "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
7048 "classid = 'pg_proc'::regclass AND "
7049 "objid = p.oid AND "
7050 "refclassid = 'pg_extension'::regclass AND "
7051 "deptype = 'e')");
7052 appendPQExpBufferChar(query, ')');
7053 }
7054
7055 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7056
7057 ntups = PQntuples(res);
7058
7059 finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
7060
7061 i_tableoid = PQfnumber(res, "tableoid");
7062 i_oid = PQfnumber(res, "oid");
7063 i_proname = PQfnumber(res, "proname");
7064 i_pronamespace = PQfnumber(res, "pronamespace");
7065 i_proowner = PQfnumber(res, "proowner");
7066 i_prolang = PQfnumber(res, "prolang");
7067 i_pronargs = PQfnumber(res, "pronargs");
7068 i_proargtypes = PQfnumber(res, "proargtypes");
7069 i_prorettype = PQfnumber(res, "prorettype");
7070 i_proacl = PQfnumber(res, "proacl");
7071 i_acldefault = PQfnumber(res, "acldefault");
7072
7073 for (i = 0; i < ntups; i++)
7074 {
7075 finfo[i].dobj.objType = DO_FUNC;
7076 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7077 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7078 AssignDumpId(&finfo[i].dobj);
7079 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
7080 finfo[i].dobj.namespace =
7082 finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
7084 finfo[i].dacl.privtype = 0;
7085 finfo[i].dacl.initprivs = NULL;
7086 finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
7087 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
7088 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
7089 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
7090 if (finfo[i].nargs == 0)
7091 finfo[i].argtypes = NULL;
7092 else
7093 {
7094 finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
7096 finfo[i].argtypes, finfo[i].nargs);
7097 }
7098 finfo[i].postponed_def = false; /* might get set during sort */
7099
7100 /* Decide whether we want to dump it */
7101 selectDumpableObject(&(finfo[i].dobj), fout);
7102
7103 /* Mark whether function has an ACL */
7104 if (!PQgetisnull(res, i, i_proacl))
7106 }
7107
7108 PQclear(res);
7109
7110 destroyPQExpBuffer(query);
7111}
7112
7113/*
7114 * getRelationStatistics
7115 * register the statistics object as a dependent of the relation.
7116 *
7117 * reltuples is passed as a string to avoid complexities in converting from/to
7118 * floating point.
7119 */
7120static RelStatsInfo *
7122 char *reltuples, int32 relallvisible,
7123 int32 relallfrozen, char relkind,
7124 char **indAttNames, int nindAttNames)
7125{
7126 if (!fout->dopt->dumpStatistics)
7127 return NULL;
7128
7129 if ((relkind == RELKIND_RELATION) ||
7130 (relkind == RELKIND_PARTITIONED_TABLE) ||
7131 (relkind == RELKIND_INDEX) ||
7132 (relkind == RELKIND_PARTITIONED_INDEX) ||
7133 (relkind == RELKIND_MATVIEW ||
7134 relkind == RELKIND_FOREIGN_TABLE))
7135 {
7136 RelStatsInfo *info = pg_malloc0(sizeof(RelStatsInfo));
7137 DumpableObject *dobj = &info->dobj;
7138
7139 dobj->objType = DO_REL_STATS;
7140 dobj->catId.tableoid = 0;
7141 dobj->catId.oid = 0;
7142 AssignDumpId(dobj);
7143 dobj->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
7144 dobj->dependencies[0] = rel->dumpId;
7145 dobj->nDeps = 1;
7146 dobj->allocDeps = 1;
7148 dobj->name = pg_strdup(rel->name);
7149 dobj->namespace = rel->namespace;
7150 info->relpages = relpages;
7151 info->reltuples = pstrdup(reltuples);
7152 info->relallvisible = relallvisible;
7153 info->relallfrozen = relallfrozen;
7154 info->relkind = relkind;
7155 info->indAttNames = indAttNames;
7156 info->nindAttNames = nindAttNames;
7157
7158 /*
7159 * Ordinarily, stats go in SECTION_DATA for tables and
7160 * SECTION_POST_DATA for indexes.
7161 *
7162 * However, the section may be updated later for materialized view
7163 * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
7164 * the stats, so the stats must be restored after the data. Also, the
7165 * materialized view definition may be postponed to SECTION_POST_DATA
7166 * (see repairMatViewBoundaryMultiLoop()).
7167 */
7168 switch (info->relkind)
7169 {
7170 case RELKIND_RELATION:
7172 case RELKIND_MATVIEW:
7174 info->section = SECTION_DATA;
7175 break;
7176 case RELKIND_INDEX:
7178 info->section = SECTION_POST_DATA;
7179 break;
7180 default:
7181 pg_fatal("cannot dump statistics for relation kind \"%c\"",
7182 info->relkind);
7183 }
7184
7185 return info;
7186 }
7187 return NULL;
7188}
7189
7190/*
7191 * getTables
7192 * read all the tables (no indexes) in the system catalogs,
7193 * and return them as an array of TableInfo structures
7194 *
7195 * *numTables is set to the number of tables read in
7196 */
7197TableInfo *
7199{
7200 DumpOptions *dopt = fout->dopt;
7201 PGresult *res;
7202 int ntups;
7203 int i;
7205 TableInfo *tblinfo;
7206 int i_reltableoid;
7207 int i_reloid;
7208 int i_relname;
7209 int i_relnamespace;
7210 int i_relkind;
7211 int i_reltype;
7212 int i_relowner;
7213 int i_relchecks;
7214 int i_relhasindex;
7215 int i_relhasrules;
7216 int i_relpages;
7217 int i_reltuples;
7218 int i_relallvisible;
7219 int i_relallfrozen;
7220 int i_toastpages;
7221 int i_owning_tab;
7222 int i_owning_col;
7223 int i_reltablespace;
7224 int i_relhasoids;
7225 int i_relhastriggers;
7226 int i_relpersistence;
7227 int i_relispopulated;
7228 int i_relreplident;
7229 int i_relrowsec;
7230 int i_relforcerowsec;
7231 int i_relfrozenxid;
7232 int i_toastfrozenxid;
7233 int i_toastoid;
7234 int i_relminmxid;
7235 int i_toastminmxid;
7236 int i_reloptions;
7237 int i_checkoption;
7239 int i_reloftype;
7240 int i_foreignserver;
7241 int i_amname;
7243 int i_relacl;
7244 int i_acldefault;
7245 int i_ispartition;
7246
7247 /*
7248 * Find all the tables and table-like objects.
7249 *
7250 * We must fetch all tables in this phase because otherwise we cannot
7251 * correctly identify inherited columns, owned sequences, etc.
7252 *
7253 * We include system catalogs, so that we can work if a user table is
7254 * defined to inherit from a system catalog (pretty weird, but...)
7255 *
7256 * Note: in this phase we should collect only a minimal amount of
7257 * information about each table, basically just enough to decide if it is
7258 * interesting. In particular, since we do not yet have lock on any user
7259 * table, we MUST NOT invoke any server-side data collection functions
7260 * (for instance, pg_get_partkeydef()). Those are likely to fail or give
7261 * wrong answers if any concurrent DDL is happening.
7262 */
7263
7265 "SELECT c.tableoid, c.oid, c.relname, "
7266 "c.relnamespace, c.relkind, c.reltype, "
7267 "c.relowner, "
7268 "c.relchecks, "
7269 "c.relhasindex, c.relhasrules, c.relpages, "
7270 "c.reltuples, c.relallvisible, ");
7271
7272 if (fout->remoteVersion >= 180000)
7273 appendPQExpBufferStr(query, "c.relallfrozen, ");
7274 else
7275 appendPQExpBufferStr(query, "0 AS relallfrozen, ");
7276
7278 "c.relhastriggers, c.relpersistence, "
7279 "c.reloftype, "
7280 "c.relacl, "
7281 "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
7282 " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
7283 "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
7284 "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
7285 "ELSE 0 END AS foreignserver, "
7286 "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
7287 "tc.oid AS toid, "
7288 "tc.relpages AS toastpages, "
7289 "tc.reloptions AS toast_reloptions, "
7290 "d.refobjid AS owning_tab, "
7291 "d.refobjsubid AS owning_col, "
7292 "tsp.spcname AS reltablespace, ");
7293
7294 if (fout->remoteVersion >= 120000)
7296 "false AS relhasoids, ");
7297 else
7299 "c.relhasoids, ");
7300
7301 if (fout->remoteVersion >= 90300)
7303 "c.relispopulated, ");
7304 else
7306 "'t' as relispopulated, ");
7307
7308 if (fout->remoteVersion >= 90400)
7310 "c.relreplident, ");
7311 else
7313 "'d' AS relreplident, ");
7314
7315 if (fout->remoteVersion >= 90500)
7317 "c.relrowsecurity, c.relforcerowsecurity, ");
7318 else
7320 "false AS relrowsecurity, "
7321 "false AS relforcerowsecurity, ");
7322
7323 if (fout->remoteVersion >= 90300)
7325 "c.relminmxid, tc.relminmxid AS tminmxid, ");
7326 else
7328 "0 AS relminmxid, 0 AS tminmxid, ");
7329
7330 if (fout->remoteVersion >= 90300)
7332 "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
7333 "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
7334 "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
7335 else
7337 "c.reloptions, NULL AS checkoption, ");
7338
7339 if (fout->remoteVersion >= 90600)
7341 "am.amname, ");
7342 else
7344 "NULL AS amname, ");
7345
7346 if (fout->remoteVersion >= 90600)
7348 "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
7349 else
7351 "false AS is_identity_sequence, ");
7352
7353 if (fout->remoteVersion >= 100000)
7355 "c.relispartition AS ispartition ");
7356 else
7358 "false AS ispartition ");
7359
7360 /*
7361 * Left join to pg_depend to pick up dependency info linking sequences to
7362 * their owning column, if any (note this dependency is AUTO except for
7363 * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
7364 * collect the spcname.
7365 */
7367 "\nFROM pg_class c\n"
7368 "LEFT JOIN pg_depend d ON "
7369 "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
7370 "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
7371 "d.objsubid = 0 AND "
7372 "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
7373 "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
7374
7375 /*
7376 * In 9.6 and up, left join to pg_am to pick up the amname.
7377 */
7378 if (fout->remoteVersion >= 90600)
7380 "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
7381
7382 /*
7383 * We purposefully ignore toast OIDs for partitioned tables; the reason is
7384 * that versions 10 and 11 have them, but later versions do not, so
7385 * emitting them causes the upgrade to fail.
7386 */
7388 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
7389 " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
7390 " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
7391
7392 /*
7393 * Restrict to interesting relkinds (in particular, not indexes). Not all
7394 * relkinds are possible in older servers, but it's not worth the trouble
7395 * to emit a version-dependent list.
7396 *
7397 * Composite-type table entries won't be dumped as such, but we have to
7398 * make a DumpableObject for them so that we can track dependencies of the
7399 * composite type (pg_depend entries for columns of the composite type
7400 * link to the pg_class entry not the pg_type entry).
7401 */
7403 "WHERE c.relkind IN ("
7411 "ORDER BY c.oid");
7412
7413 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7414
7415 ntups = PQntuples(res);
7416
7417 *numTables = ntups;
7418
7419 /*
7420 * Extract data from result and lock dumpable tables. We do the locking
7421 * before anything else, to minimize the window wherein a table could
7422 * disappear under us.
7423 *
7424 * Note that we have to save info about all tables here, even when dumping
7425 * only one, because we don't yet know which tables might be inheritance
7426 * ancestors of the target table.
7427 */
7428 tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
7429
7430 i_reltableoid = PQfnumber(res, "tableoid");
7431 i_reloid = PQfnumber(res, "oid");
7432 i_relname = PQfnumber(res, "relname");
7433 i_relnamespace = PQfnumber(res, "relnamespace");
7434 i_relkind = PQfnumber(res, "relkind");
7435 i_reltype = PQfnumber(res, "reltype");
7436 i_relowner = PQfnumber(res, "relowner");
7437 i_relchecks = PQfnumber(res, "relchecks");
7438 i_relhasindex = PQfnumber(res, "relhasindex");
7439 i_relhasrules = PQfnumber(res, "relhasrules");
7440 i_relpages = PQfnumber(res, "relpages");
7441 i_reltuples = PQfnumber(res, "reltuples");
7442 i_relallvisible = PQfnumber(res, "relallvisible");
7443 i_relallfrozen = PQfnumber(res, "relallfrozen");
7444 i_toastpages = PQfnumber(res, "toastpages");
7445 i_owning_tab = PQfnumber(res, "owning_tab");
7446 i_owning_col = PQfnumber(res, "owning_col");
7447 i_reltablespace = PQfnumber(res, "reltablespace");
7448 i_relhasoids = PQfnumber(res, "relhasoids");
7449 i_relhastriggers = PQfnumber(res, "relhastriggers");
7450 i_relpersistence = PQfnumber(res, "relpersistence");
7451 i_relispopulated = PQfnumber(res, "relispopulated");
7452 i_relreplident = PQfnumber(res, "relreplident");
7453 i_relrowsec = PQfnumber(res, "relrowsecurity");
7454 i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
7455 i_relfrozenxid = PQfnumber(res, "relfrozenxid");
7456 i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
7457 i_toastoid = PQfnumber(res, "toid");
7458 i_relminmxid = PQfnumber(res, "relminmxid");
7459 i_toastminmxid = PQfnumber(res, "tminmxid");
7460 i_reloptions = PQfnumber(res, "reloptions");
7461 i_checkoption = PQfnumber(res, "checkoption");
7462 i_toastreloptions = PQfnumber(res, "toast_reloptions");
7463 i_reloftype = PQfnumber(res, "reloftype");
7464 i_foreignserver = PQfnumber(res, "foreignserver");
7465 i_amname = PQfnumber(res, "amname");
7466 i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
7467 i_relacl = PQfnumber(res, "relacl");
7468 i_acldefault = PQfnumber(res, "acldefault");
7469 i_ispartition = PQfnumber(res, "ispartition");
7470
7471 if (dopt->lockWaitTimeout)
7472 {
7473 /*
7474 * Arrange to fail instead of waiting forever for a table lock.
7475 *
7476 * NB: this coding assumes that the only queries issued within the
7477 * following loop are LOCK TABLEs; else the timeout may be undesirably
7478 * applied to other things too.
7479 */
7480 resetPQExpBuffer(query);
7481 appendPQExpBufferStr(query, "SET statement_timeout = ");
7483 ExecuteSqlStatement(fout, query->data);
7484 }
7485
7486 resetPQExpBuffer(query);
7487
7488 for (i = 0; i < ntups; i++)
7489 {
7490 int32 relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
7491 int32 relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
7492
7493 tblinfo[i].dobj.objType = DO_TABLE;
7494 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
7495 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
7496 AssignDumpId(&tblinfo[i].dobj);
7497 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
7498 tblinfo[i].dobj.namespace =
7500 tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
7501 tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
7502 tblinfo[i].dacl.privtype = 0;
7503 tblinfo[i].dacl.initprivs = NULL;
7504 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
7505 tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
7506 tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
7507 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
7508 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
7509 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
7510 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
7511 if (PQgetisnull(res, i, i_toastpages))
7512 tblinfo[i].toastpages = 0;
7513 else
7514 tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
7515 if (PQgetisnull(res, i, i_owning_tab))
7516 {
7517 tblinfo[i].owning_tab = InvalidOid;
7518 tblinfo[i].owning_col = 0;
7519 }
7520 else
7521 {
7522 tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
7523 tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
7524 }
7526 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
7527 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
7528 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
7529 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
7530 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
7531 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
7532 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
7533 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
7535 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
7536 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
7537 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
7538 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
7539 if (PQgetisnull(res, i, i_checkoption))
7540 tblinfo[i].checkoption = NULL;
7541 else
7542 tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
7544 tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
7546 if (PQgetisnull(res, i, i_amname))
7547 tblinfo[i].amname = NULL;
7548 else
7549 tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
7550 tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
7551 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
7552
7553 /* other fields were zeroed above */
7554
7555 /*
7556 * Decide whether we want to dump this table.
7557 */
7558 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
7559 tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
7560 else
7561 selectDumpableTable(&tblinfo[i], fout);
7562
7563 /*
7564 * Now, consider the table "interesting" if we need to dump its
7565 * definition, data or its statistics. Later on, we'll skip a lot of
7566 * data collection for uninteresting tables.
7567 *
7568 * Note: the "interesting" flag will also be set by flagInhTables for
7569 * parents of interesting tables, so that we collect necessary
7570 * inheritance info even when the parents are not themselves being
7571 * dumped. This is the main reason why we need an "interesting" flag
7572 * that's separate from the components-to-dump bitmask.
7573 */
7574 tblinfo[i].interesting = (tblinfo[i].dobj.dump &
7578
7579 tblinfo[i].dummy_view = false; /* might get set during sort */
7580 tblinfo[i].postponed_def = false; /* might get set during sort */
7581
7582 /* Tables have data */
7584
7585 /* Mark whether table has an ACL */
7586 if (!PQgetisnull(res, i, i_relacl))
7587 tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
7588 tblinfo[i].hascolumnACLs = false; /* may get set later */
7589
7590 /* Add statistics */
7591 if (tblinfo[i].interesting)
7592 {
7593 RelStatsInfo *stats;
7594
7595 stats = getRelationStatistics(fout, &tblinfo[i].dobj,
7596 tblinfo[i].relpages,
7597 PQgetvalue(res, i, i_reltuples),
7598 relallvisible, relallfrozen,
7599 tblinfo[i].relkind, NULL, 0);
7600 if (tblinfo[i].relkind == RELKIND_MATVIEW)
7601 tblinfo[i].stats = stats;
7602 }
7603
7604 /*
7605 * Read-lock target tables to make sure they aren't DROPPED or altered
7606 * in schema before we get around to dumping them.
7607 *
7608 * Note that we don't explicitly lock parents of the target tables; we
7609 * assume our lock on the child is enough to prevent schema
7610 * alterations to parent tables.
7611 *
7612 * NOTE: it'd be kinda nice to lock other relations too, not only
7613 * plain or partitioned tables, but the backend doesn't presently
7614 * allow that.
7615 *
7616 * We only need to lock the table for certain components; see
7617 * pg_dump.h
7618 */
7619 if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
7620 (tblinfo[i].relkind == RELKIND_RELATION ||
7621 tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
7622 {
7623 /*
7624 * Tables are locked in batches. When dumping from a remote
7625 * server this can save a significant amount of time by reducing
7626 * the number of round trips.
7627 */
7628 if (query->len == 0)
7629 appendPQExpBuffer(query, "LOCK TABLE %s",
7630 fmtQualifiedDumpable(&tblinfo[i]));
7631 else
7632 {
7633 appendPQExpBuffer(query, ", %s",
7634 fmtQualifiedDumpable(&tblinfo[i]));
7635
7636 /* Arbitrarily end a batch when query length reaches 100K. */
7637 if (query->len >= 100000)
7638 {
7639 /* Lock another batch of tables. */
7640 appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7641 ExecuteSqlStatement(fout, query->data);
7642 resetPQExpBuffer(query);
7643 }
7644 }
7645 }
7646 }
7647
7648 if (query->len != 0)
7649 {
7650 /* Lock the tables in the last batch. */
7651 appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7652 ExecuteSqlStatement(fout, query->data);
7653 }
7654
7655 if (dopt->lockWaitTimeout)
7656 {
7657 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
7658 }
7659
7660 PQclear(res);
7661
7662 destroyPQExpBuffer(query);
7663
7664 return tblinfo;
7665}
7666
7667/*
7668 * getOwnedSeqs
7669 * identify owned sequences and mark them as dumpable if owning table is
7670 *
7671 * We used to do this in getTables(), but it's better to do it after the
7672 * index used by findTableByOid() has been set up.
7673 */
7674void
7676{
7677 int i;
7678
7679 /*
7680 * Force sequences that are "owned" by table columns to be dumped whenever
7681 * their owning table is being dumped.
7682 */
7683 for (i = 0; i < numTables; i++)
7684 {
7685 TableInfo *seqinfo = &tblinfo[i];
7686 TableInfo *owning_tab;
7687
7688 if (!OidIsValid(seqinfo->owning_tab))
7689 continue; /* not an owned sequence */
7690
7691 owning_tab = findTableByOid(seqinfo->owning_tab);
7692 if (owning_tab == NULL)
7693 pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
7694 seqinfo->owning_tab, seqinfo->dobj.catId.oid);
7695
7696 /*
7697 * For an identity sequence, dump exactly the same components for the
7698 * sequence as for the owning table. This is important because we
7699 * treat the identity sequence as an integral part of the table. For
7700 * example, there is not any DDL command that allows creation of such
7701 * a sequence independently of the table.
7702 *
7703 * For other owned sequences such as serial sequences, we need to dump
7704 * the components that are being dumped for the table and any
7705 * components that the sequence is explicitly marked with.
7706 *
7707 * We can't simply use the set of components which are being dumped
7708 * for the table as the table might be in an extension (and only the
7709 * non-extension components, eg: ACLs if changed, security labels, and
7710 * policies, are being dumped) while the sequence is not (and
7711 * therefore the definition and other components should also be
7712 * dumped).
7713 *
7714 * If the sequence is part of the extension then it should be properly
7715 * marked by checkExtensionMembership() and this will be a no-op as
7716 * the table will be equivalently marked.
7717 */
7718 if (seqinfo->is_identity_sequence)
7719 seqinfo->dobj.dump = owning_tab->dobj.dump;
7720 else
7721 seqinfo->dobj.dump |= owning_tab->dobj.dump;
7722
7723 /* Make sure that necessary data is available if we're dumping it */
7724 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
7725 {
7726 seqinfo->interesting = true;
7727 owning_tab->interesting = true;
7728 }
7729 }
7730}
7731
7732/*
7733 * getInherits
7734 * read all the inheritance information
7735 * from the system catalogs return them in the InhInfo* structure
7736 *
7737 * numInherits is set to the number of pairs read in
7738 */
7739InhInfo *
7741{
7742 PGresult *res;
7743 int ntups;
7744 int i;
7747
7748 int i_inhrelid;
7749 int i_inhparent;
7750
7751 /* find all the inheritance information */
7752 appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
7753
7754 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7755
7756 ntups = PQntuples(res);
7757
7758 *numInherits = ntups;
7759
7760 inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
7761
7762 i_inhrelid = PQfnumber(res, "inhrelid");
7763 i_inhparent = PQfnumber(res, "inhparent");
7764
7765 for (i = 0; i < ntups; i++)
7766 {
7767 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
7768 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
7769 }
7770
7771 PQclear(res);
7772
7773 destroyPQExpBuffer(query);
7774
7775 return inhinfo;
7776}
7777
7778/*
7779 * getPartitioningInfo
7780 * get information about partitioning
7781 *
7782 * For the most part, we only collect partitioning info about tables we
7783 * intend to dump. However, this function has to consider all partitioned
7784 * tables in the database, because we need to know about parents of partitions
7785 * we are going to dump even if the parents themselves won't be dumped.
7786 *
7787 * Specifically, what we need to know is whether each partitioned table
7788 * has an "unsafe" partitioning scheme that requires us to force
7789 * load-via-partition-root mode for its children. Currently the only case
7790 * for which we force that is hash partitioning on enum columns, since the
7791 * hash codes depend on enum value OIDs which won't be replicated across
7792 * dump-and-reload. There are other cases in which load-via-partition-root
7793 * might be necessary, but we expect users to cope with them.
7794 */
7795void
7797{
7798 PQExpBuffer query;
7799 PGresult *res;
7800 int ntups;
7801
7802 /* hash partitioning didn't exist before v11 */
7803 if (fout->remoteVersion < 110000)
7804 return;
7805 /* needn't bother if not dumping data */
7806 if (!fout->dopt->dumpData)
7807 return;
7808
7809 query = createPQExpBuffer();
7810
7811 /*
7812 * Unsafe partitioning schemes are exactly those for which hash enum_ops
7813 * appears among the partition opclasses. We needn't check partstrat.
7814 *
7815 * Note that this query may well retrieve info about tables we aren't
7816 * going to dump and hence have no lock on. That's okay since we need not
7817 * invoke any unsafe server-side functions.
7818 */
7820 "SELECT partrelid FROM pg_partitioned_table WHERE\n"
7821 "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
7822 "ON c.opcmethod = a.oid\n"
7823 "WHERE opcname = 'enum_ops' "
7824 "AND opcnamespace = 'pg_catalog'::regnamespace "
7825 "AND amname = 'hash') = ANY(partclass)");
7826
7827 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7828
7829 ntups = PQntuples(res);
7830
7831 for (int i = 0; i < ntups; i++)
7832 {
7833 Oid tabrelid = atooid(PQgetvalue(res, i, 0));
7835
7837 if (tbinfo == NULL)
7838 pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
7839 tabrelid);
7840 tbinfo->unsafe_partitions = true;
7841 }
7842
7843 PQclear(res);
7844
7845 destroyPQExpBuffer(query);
7846}
7847
7848/*
7849 * getIndexes
7850 * get information about every index on a dumpable table
7851 *
7852 * Note: index data is not returned directly to the caller, but it
7853 * does get entered into the DumpableObject tables.
7854 */
7855void
7856getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
7857{
7860 PGresult *res;
7861 int ntups;
7862 int curtblindx;
7864 int i_tableoid,
7865 i_oid,
7866 i_indrelid,
7868 i_relpages,
7873 i_indexdef,
7875 i_indnatts,
7876 i_indkey,
7880 i_contype,
7881 i_conname,
7886 i_conoid,
7887 i_condef,
7893
7894 /*
7895 * We want to perform just one query against pg_index. However, we
7896 * mustn't try to select every row of the catalog and then sort it out on
7897 * the client side, because some of the server-side functions we need
7898 * would be unsafe to apply to tables we don't have lock on. Hence, we
7899 * build an array of the OIDs of tables we care about (and now have lock
7900 * on!), and use a WHERE clause to constrain which rows are selected.
7901 */
7903 for (int i = 0; i < numTables; i++)
7904 {
7905 TableInfo *tbinfo = &tblinfo[i];
7906
7907 if (!tbinfo->hasindex)
7908 continue;
7909
7910 /*
7911 * We can ignore indexes of uninteresting tables.
7912 */
7913 if (!tbinfo->interesting)
7914 continue;
7915
7916 /* OK, we need info for this table */
7917 if (tbloids->len > 1) /* do we have more than the '{'? */
7919 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
7920 }
7922
7924 "SELECT t.tableoid, t.oid, i.indrelid, "
7925 "t.relname AS indexname, "
7926 "t.relpages, t.reltuples, t.relallvisible, ");
7927
7928 if (fout->remoteVersion >= 180000)
7929 appendPQExpBufferStr(query, "t.relallfrozen, ");
7930 else
7931 appendPQExpBufferStr(query, "0 AS relallfrozen, ");
7932
7934 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7935 "i.indkey, i.indisclustered, "
7936 "c.contype, c.conname, "
7937 "c.condeferrable, c.condeferred, "
7938 "c.tableoid AS contableoid, "
7939 "c.oid AS conoid, "
7940 "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
7941 "CASE WHEN i.indexprs IS NOT NULL THEN "
7942 "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
7943 " FROM pg_catalog.pg_attribute "
7944 " WHERE attrelid = i.indexrelid) "
7945 "ELSE NULL END AS indattnames, "
7946 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7947 "t.reloptions AS indreloptions, ");
7948
7949
7950 if (fout->remoteVersion >= 90400)
7952 "i.indisreplident, ");
7953 else
7955 "false AS indisreplident, ");
7956
7957 if (fout->remoteVersion >= 110000)
7959 "inh.inhparent AS parentidx, "
7960 "i.indnkeyatts AS indnkeyatts, "
7961 "i.indnatts AS indnatts, "
7962 "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
7963 " FROM pg_catalog.pg_attribute "
7964 " WHERE attrelid = i.indexrelid AND "
7965 " attstattarget >= 0) AS indstatcols, "
7966 "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
7967 " FROM pg_catalog.pg_attribute "
7968 " WHERE attrelid = i.indexrelid AND "
7969 " attstattarget >= 0) AS indstatvals, ");
7970 else
7972 "0 AS parentidx, "
7973 "i.indnatts AS indnkeyatts, "
7974 "i.indnatts AS indnatts, "
7975 "'' AS indstatcols, "
7976 "'' AS indstatvals, ");
7977
7978 if (fout->remoteVersion >= 150000)
7980 "i.indnullsnotdistinct, ");
7981 else
7983 "false AS indnullsnotdistinct, ");
7984
7985 if (fout->remoteVersion >= 180000)
7987 "c.conperiod ");
7988 else
7990 "NULL AS conperiod ");
7991
7992 /*
7993 * The point of the messy-looking outer join is to find a constraint that
7994 * is related by an internal dependency link to the index. If we find one,
7995 * create a CONSTRAINT entry linked to the INDEX entry. We assume an
7996 * index won't have more than one internal dependency.
7997 *
7998 * Note: the check on conrelid is redundant, but useful because that
7999 * column is indexed while conindid is not.
8000 */
8001 if (fout->remoteVersion >= 110000)
8002 {
8003 appendPQExpBuffer(query,
8004 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8005 "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
8006 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
8007 "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
8008 "LEFT JOIN pg_catalog.pg_constraint c "
8009 "ON (i.indrelid = c.conrelid AND "
8010 "i.indexrelid = c.conindid AND "
8011 "c.contype IN ('p','u','x')) "
8012 "LEFT JOIN pg_catalog.pg_inherits inh "
8013 "ON (inh.inhrelid = indexrelid) "
8014 "WHERE (i.indisvalid OR t2.relkind = 'p') "
8015 "AND i.indisready "
8016 "ORDER BY i.indrelid, indexname",
8017 tbloids->data);
8018 }
8019 else
8020 {
8021 /*
8022 * the test on indisready is necessary in 9.2, and harmless in
8023 * earlier/later versions
8024 */
8025 appendPQExpBuffer(query,
8026 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8027 "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
8028 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
8029 "LEFT JOIN pg_catalog.pg_constraint c "
8030 "ON (i.indrelid = c.conrelid AND "
8031 "i.indexrelid = c.conindid AND "
8032 "c.contype IN ('p','u','x')) "
8033 "WHERE i.indisvalid AND i.indisready "
8034 "ORDER BY i.indrelid, indexname",
8035 tbloids->data);
8036 }
8037
8038 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8039
8040 ntups = PQntuples(res);
8041
8042 i_tableoid = PQfnumber(res, "tableoid");
8043 i_oid = PQfnumber(res, "oid");
8044 i_indrelid = PQfnumber(res, "indrelid");
8045 i_indexname = PQfnumber(res, "indexname");
8046 i_relpages = PQfnumber(res, "relpages");
8047 i_reltuples = PQfnumber(res, "reltuples");
8048 i_relallvisible = PQfnumber(res, "relallvisible");
8049 i_relallfrozen = PQfnumber(res, "relallfrozen");
8050 i_parentidx = PQfnumber(res, "parentidx");
8051 i_indexdef = PQfnumber(res, "indexdef");
8052 i_indnkeyatts = PQfnumber(res, "indnkeyatts");
8053 i_indnatts = PQfnumber(res, "indnatts");
8054 i_indkey = PQfnumber(res, "indkey");
8055 i_indisclustered = PQfnumber(res, "indisclustered");
8056 i_indisreplident = PQfnumber(res, "indisreplident");
8057 i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
8058 i_contype = PQfnumber(res, "contype");
8059 i_conname = PQfnumber(res, "conname");
8060 i_condeferrable = PQfnumber(res, "condeferrable");
8061 i_condeferred = PQfnumber(res, "condeferred");
8062 i_conperiod = PQfnumber(res, "conperiod");
8063 i_contableoid = PQfnumber(res, "contableoid");
8064 i_conoid = PQfnumber(res, "conoid");
8065 i_condef = PQfnumber(res, "condef");
8066 i_indattnames = PQfnumber(res, "indattnames");
8067 i_tablespace = PQfnumber(res, "tablespace");
8068 i_indreloptions = PQfnumber(res, "indreloptions");
8069 i_indstatcols = PQfnumber(res, "indstatcols");
8070 i_indstatvals = PQfnumber(res, "indstatvals");
8071
8072 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
8073
8074 /*
8075 * Outer loop iterates once per table, not once per row. Incrementing of
8076 * j is handled by the inner loop.
8077 */
8078 curtblindx = -1;
8079 for (int j = 0; j < ntups;)
8080 {
8083 char **indAttNames = NULL;
8084 int nindAttNames = 0;
8085 int numinds;
8086
8087 /* Count rows for this table */
8088 for (numinds = 1; numinds < ntups - j; numinds++)
8089 if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
8090 break;
8091
8092 /*
8093 * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8094 * order.
8095 */
8096 while (++curtblindx < numTables)
8097 {
8098 tbinfo = &tblinfo[curtblindx];
8099 if (tbinfo->dobj.catId.oid == indrelid)
8100 break;
8101 }
8102 if (curtblindx >= numTables)
8103 pg_fatal("unrecognized table OID %u", indrelid);
8104 /* cross-check that we only got requested tables */
8105 if (!tbinfo->hasindex ||
8106 !tbinfo->interesting)
8107 pg_fatal("unexpected index data for table \"%s\"",
8108 tbinfo->dobj.name);
8109
8110 /* Save data for this table */
8111 tbinfo->indexes = indxinfo + j;
8112 tbinfo->numIndexes = numinds;
8113
8114 for (int c = 0; c < numinds; c++, j++)
8115 {
8116 char contype;
8117 char indexkind;
8119 int32 relpages = atoi(PQgetvalue(res, j, i_relpages));
8120 int32 relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
8121 int32 relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
8122
8123 indxinfo[j].dobj.objType = DO_INDEX;
8124 indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8125 indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8126 AssignDumpId(&indxinfo[j].dobj);
8127 indxinfo[j].dobj.dump = tbinfo->dobj.dump;
8128 indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
8129 indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
8130 indxinfo[j].indextable = tbinfo;
8131 indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
8132 indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
8133 indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
8134 indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
8135 indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
8136 indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
8137 indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
8138 indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
8140 indxinfo[j].indkeys, indxinfo[j].indnattrs);
8141 indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
8142 indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
8143 indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
8144 indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
8145 indxinfo[j].partattaches = (SimplePtrList)
8146 {
8147 NULL, NULL
8148 };
8149
8150 if (indxinfo[j].parentidx == 0)
8152 else
8154
8155 if (!PQgetisnull(res, j, i_indattnames))
8156 {
8158 &indAttNames, &nindAttNames))
8159 pg_fatal("could not parse %s array", "indattnames");
8160 }
8161
8162 relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
8163 PQgetvalue(res, j, i_reltuples),
8164 relallvisible, relallfrozen, indexkind,
8165 indAttNames, nindAttNames);
8166
8167 contype = *(PQgetvalue(res, j, i_contype));
8168 if (contype == 'p' || contype == 'u' || contype == 'x')
8169 {
8170 /*
8171 * If we found a constraint matching the index, create an
8172 * entry for it.
8173 */
8175
8178 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
8179 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
8180 AssignDumpId(&constrinfo->dobj);
8181 constrinfo->dobj.dump = tbinfo->dobj.dump;
8182 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
8183 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
8184 constrinfo->contable = tbinfo;
8185 constrinfo->condomain = NULL;
8186 constrinfo->contype = contype;
8187 if (contype == 'x')
8188 constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
8189 else
8190 constrinfo->condef = NULL;
8191 constrinfo->confrelid = InvalidOid;
8192 constrinfo->conindex = indxinfo[j].dobj.dumpId;
8193 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
8194 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
8195 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
8196 constrinfo->conislocal = true;
8197 constrinfo->separate = true;
8198
8199 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
8200 if (relstats != NULL)
8201 addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
8202 }
8203 else
8204 {
8205 /* Plain secondary index */
8206 indxinfo[j].indexconstraint = 0;
8207 }
8208 }
8209 }
8210
8211 PQclear(res);
8212
8213 destroyPQExpBuffer(query);
8215}
8216
8217/*
8218 * getExtendedStatistics
8219 * get information about extended-statistics objects.
8220 *
8221 * Note: extended statistics data is not returned directly to the caller, but
8222 * it does get entered into the DumpableObject tables.
8223 */
8224void
8226{
8227 PQExpBuffer query;
8228 PGresult *res;
8230 int ntups;
8231 int i_tableoid;
8232 int i_oid;
8233 int i_stxname;
8234 int i_stxnamespace;
8235 int i_stxowner;
8236 int i_stxrelid;
8237 int i_stattarget;
8238 int i;
8239
8240 /* Extended statistics were new in v10 */
8241 if (fout->remoteVersion < 100000)
8242 return;
8243
8244 query = createPQExpBuffer();
8245
8246 if (fout->remoteVersion < 130000)
8247 appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
8248 "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
8249 "FROM pg_catalog.pg_statistic_ext");
8250 else
8251 appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
8252 "stxnamespace, stxowner, stxrelid, stxstattarget "
8253 "FROM pg_catalog.pg_statistic_ext");
8254
8255 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8256
8257 ntups = PQntuples(res);
8258
8259 i_tableoid = PQfnumber(res, "tableoid");
8260 i_oid = PQfnumber(res, "oid");
8261 i_stxname = PQfnumber(res, "stxname");
8262 i_stxnamespace = PQfnumber(res, "stxnamespace");
8263 i_stxowner = PQfnumber(res, "stxowner");
8264 i_stxrelid = PQfnumber(res, "stxrelid");
8265 i_stattarget = PQfnumber(res, "stxstattarget");
8266
8267 statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
8268
8269 for (i = 0; i < ntups; i++)
8270 {
8271 statsextinfo[i].dobj.objType = DO_STATSEXT;
8272 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8273 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8274 AssignDumpId(&statsextinfo[i].dobj);
8275 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
8276 statsextinfo[i].dobj.namespace =
8278 statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
8279 statsextinfo[i].stattable =
8281 if (PQgetisnull(res, i, i_stattarget))
8282 statsextinfo[i].stattarget = -1;
8283 else
8284 statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
8285
8286 /* Decide whether we want to dump it */
8288
8289 if (fout->dopt->dumpStatistics)
8290 statsextinfo[i].dobj.components |= DUMP_COMPONENT_STATISTICS;
8291 }
8292
8293 PQclear(res);
8294 destroyPQExpBuffer(query);
8295}
8296
8297/*
8298 * getConstraints
8299 *
8300 * Get info about constraints on dumpable tables.
8301 *
8302 * Currently handles foreign keys only.
8303 * Unique and primary key constraints are handled with indexes,
8304 * while check constraints are processed in getTableAttrs().
8305 */
8306void
8308{
8311 PGresult *res;
8312 int ntups;
8313 int curtblindx;
8316 int i_contableoid,
8317 i_conoid,
8318 i_conrelid,
8319 i_conname,
8321 i_conindid,
8322 i_condef;
8323
8324 /*
8325 * We want to perform just one query against pg_constraint. However, we
8326 * mustn't try to select every row of the catalog and then sort it out on
8327 * the client side, because some of the server-side functions we need
8328 * would be unsafe to apply to tables we don't have lock on. Hence, we
8329 * build an array of the OIDs of tables we care about (and now have lock
8330 * on!), and use a WHERE clause to constrain which rows are selected.
8331 */
8333 for (int i = 0; i < numTables; i++)
8334 {
8335 TableInfo *tinfo = &tblinfo[i];
8336
8337 if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
8338 continue;
8339
8340 /* OK, we need info for this table */
8341 if (tbloids->len > 1) /* do we have more than the '{'? */
8343 appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
8344 }
8346
8348 "SELECT c.tableoid, c.oid, "
8349 "conrelid, conname, confrelid, ");
8350 if (fout->remoteVersion >= 110000)
8351 appendPQExpBufferStr(query, "conindid, ");
8352 else
8353 appendPQExpBufferStr(query, "0 AS conindid, ");
8354 appendPQExpBuffer(query,
8355 "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
8356 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8357 "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
8358 "WHERE contype = 'f' ",
8359 tbloids->data);
8360 if (fout->remoteVersion >= 110000)
8362 "AND conparentid = 0 ");
8364 "ORDER BY conrelid, conname");
8365
8366 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8367
8368 ntups = PQntuples(res);
8369
8370 i_contableoid = PQfnumber(res, "tableoid");
8371 i_conoid = PQfnumber(res, "oid");
8372 i_conrelid = PQfnumber(res, "conrelid");
8373 i_conname = PQfnumber(res, "conname");
8374 i_confrelid = PQfnumber(res, "confrelid");
8375 i_conindid = PQfnumber(res, "conindid");
8376 i_condef = PQfnumber(res, "condef");
8377
8378 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
8379
8380 curtblindx = -1;
8381 for (int j = 0; j < ntups; j++)
8382 {
8383 Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
8385
8386 /*
8387 * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8388 * order.
8389 */
8390 if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
8391 {
8392 while (++curtblindx < numTables)
8393 {
8394 tbinfo = &tblinfo[curtblindx];
8395 if (tbinfo->dobj.catId.oid == conrelid)
8396 break;
8397 }
8398 if (curtblindx >= numTables)
8399 pg_fatal("unrecognized table OID %u", conrelid);
8400 }
8401
8402 constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
8403 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
8404 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
8405 AssignDumpId(&constrinfo[j].dobj);
8406 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
8407 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
8408 constrinfo[j].contable = tbinfo;
8409 constrinfo[j].condomain = NULL;
8410 constrinfo[j].contype = 'f';
8411 constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
8412 constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
8413 constrinfo[j].conindex = 0;
8414 constrinfo[j].condeferrable = false;
8415 constrinfo[j].condeferred = false;
8416 constrinfo[j].conislocal = true;
8417 constrinfo[j].separate = true;
8418
8419 /*
8420 * Restoring an FK that points to a partitioned table requires that
8421 * all partition indexes have been attached beforehand. Ensure that
8422 * happens by making the constraint depend on each index partition
8423 * attach object.
8424 */
8425 reftable = findTableByOid(constrinfo[j].confrelid);
8426 if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
8427 {
8428 Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));
8429
8430 if (indexOid != InvalidOid)
8431 {
8432 for (int k = 0; k < reftable->numIndexes; k++)
8433 {
8435
8436 /* not our index? */
8437 if (reftable->indexes[k].dobj.catId.oid != indexOid)
8438 continue;
8439
8440 refidx = &reftable->indexes[k];
8442 break;
8443 }
8444 }
8445 }
8446 }
8447
8448 PQclear(res);
8449
8450 destroyPQExpBuffer(query);
8452}
8453
8454/*
8455 * addConstrChildIdxDeps
8456 *
8457 * Recursive subroutine for getConstraints
8458 *
8459 * Given an object representing a foreign key constraint and an index on the
8460 * partitioned table it references, mark the constraint object as dependent
8461 * on the DO_INDEX_ATTACH object of each index partition, recursively
8462 * drilling down to their partitions if any. This ensures that the FK is not
8463 * restored until the index is fully marked valid.
8464 */
8465static void
8467{
8468 SimplePtrListCell *cell;
8469
8471
8472 for (cell = refidx->partattaches.head; cell; cell = cell->next)
8473 {
8475
8476 addObjectDependency(dobj, attach->dobj.dumpId);
8477
8478 if (attach->partitionIdx->partattaches.head != NULL)
8479 addConstrChildIdxDeps(dobj, attach->partitionIdx);
8480 }
8481}
8482
8483/*
8484 * getDomainConstraints
8485 *
8486 * Get info about constraints on a domain.
8487 */
8488static void
8490{
8493 PGresult *res;
8494 int i_tableoid,
8495 i_oid,
8496 i_conname,
8497 i_consrc,
8499 i_contype;
8500 int ntups;
8501
8502 if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
8503 {
8504 /*
8505 * Set up query for constraint-specific details. For servers 17 and
8506 * up, domains have constraints of type 'n' as well as 'c', otherwise
8507 * just the latter.
8508 */
8509 appendPQExpBuffer(query,
8510 "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
8511 "SELECT tableoid, oid, conname, "
8512 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8513 "convalidated, contype "
8514 "FROM pg_catalog.pg_constraint "
8515 "WHERE contypid = $1 AND contype IN (%s) "
8516 "ORDER BY conname",
8517 fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
8518
8519 ExecuteSqlStatement(fout, query->data);
8520
8521 fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
8522 }
8523
8524 printfPQExpBuffer(query,
8525 "EXECUTE getDomainConstraints('%u')",
8526 tyinfo->dobj.catId.oid);
8527
8528 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8529
8530 ntups = PQntuples(res);
8531
8532 i_tableoid = PQfnumber(res, "tableoid");
8533 i_oid = PQfnumber(res, "oid");
8534 i_conname = PQfnumber(res, "conname");
8535 i_consrc = PQfnumber(res, "consrc");
8536 i_convalidated = PQfnumber(res, "convalidated");
8537 i_contype = PQfnumber(res, "contype");
8538
8539 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
8540 tyinfo->domChecks = constrinfo;
8541
8542 /* 'i' tracks result rows; 'j' counts CHECK constraints */
8543 for (int i = 0, j = 0; i < ntups; i++)
8544 {
8545 bool validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
8546 char contype = (PQgetvalue(res, i, i_contype))[0];
8547 ConstraintInfo *constraint;
8548
8549 if (contype == CONSTRAINT_CHECK)
8550 {
8551 constraint = &constrinfo[j++];
8552 tyinfo->nDomChecks++;
8553 }
8554 else
8555 {
8556 Assert(contype == CONSTRAINT_NOTNULL);
8557 Assert(tyinfo->notnull == NULL);
8558 /* use last item in array for the not-null constraint */
8559 tyinfo->notnull = &(constrinfo[ntups - 1]);
8560 constraint = tyinfo->notnull;
8561 }
8562
8563 constraint->dobj.objType = DO_CONSTRAINT;
8564 constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8565 constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8566 AssignDumpId(&(constraint->dobj));
8567 constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
8568 constraint->dobj.namespace = tyinfo->dobj.namespace;
8569 constraint->contable = NULL;
8570 constraint->condomain = tyinfo;
8571 constraint->contype = contype;
8572 constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
8573 constraint->confrelid = InvalidOid;
8574 constraint->conindex = 0;
8575 constraint->condeferrable = false;
8576 constraint->condeferred = false;
8577 constraint->conislocal = true;
8578
8579 constraint->separate = !validated;
8580
8581 /*
8582 * Make the domain depend on the constraint, ensuring it won't be
8583 * output till any constraint dependencies are OK. If the constraint
8584 * has not been validated, it's going to be dumped after the domain
8585 * anyway, so this doesn't matter.
8586 */
8587 if (validated)
8588 addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
8589 }
8590
8591 PQclear(res);
8592
8593 destroyPQExpBuffer(query);
8594}
8595
8596/*
8597 * getRules
8598 * get basic information about every rule in the system
8599 */
8600void
8602{
8603 PGresult *res;
8604 int ntups;
8605 int i;
8608 int i_tableoid;
8609 int i_oid;
8610 int i_rulename;
8611 int i_ruletable;
8612 int i_ev_type;
8613 int i_is_instead;
8614 int i_ev_enabled;
8615
8616 appendPQExpBufferStr(query, "SELECT "
8617 "tableoid, oid, rulename, "
8618 "ev_class AS ruletable, ev_type, is_instead, "
8619 "ev_enabled "
8620 "FROM pg_rewrite "
8621 "ORDER BY oid");
8622
8623 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8624
8625 ntups = PQntuples(res);
8626
8627 ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
8628
8629 i_tableoid = PQfnumber(res, "tableoid");
8630 i_oid = PQfnumber(res, "oid");
8631 i_rulename = PQfnumber(res, "rulename");
8632 i_ruletable = PQfnumber(res, "ruletable");
8633 i_ev_type = PQfnumber(res, "ev_type");
8634 i_is_instead = PQfnumber(res, "is_instead");
8635 i_ev_enabled = PQfnumber(res, "ev_enabled");
8636
8637 for (i = 0; i < ntups; i++)
8638 {
8640
8641 ruleinfo[i].dobj.objType = DO_RULE;
8642 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8643 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8644 AssignDumpId(&ruleinfo[i].dobj);
8645 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
8647 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
8648 if (ruleinfo[i].ruletable == NULL)
8649 pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
8650 ruletableoid, ruleinfo[i].dobj.catId.oid);
8651 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
8652 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
8653 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
8654 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
8655 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
8656 if (ruleinfo[i].ruletable)
8657 {
8658 /*
8659 * If the table is a view or materialized view, force its ON
8660 * SELECT rule to be sorted before the view itself --- this
8661 * ensures that any dependencies for the rule affect the table's
8662 * positioning. Other rules are forced to appear after their
8663 * table.
8664 */
8665 if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
8666 ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
8667 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
8668 {
8669 addObjectDependency(&ruleinfo[i].ruletable->dobj,
8670 ruleinfo[i].dobj.dumpId);
8671 /* We'll merge the rule into CREATE VIEW, if possible */
8672 ruleinfo[i].separate = false;
8673 }
8674 else
8675 {
8677 ruleinfo[i].ruletable->dobj.dumpId);
8678 ruleinfo[i].separate = true;
8679 }
8680 }
8681 else
8682 ruleinfo[i].separate = true;
8683 }
8684
8685 PQclear(res);
8686
8687 destroyPQExpBuffer(query);
8688}
8689
8690/*
8691 * getTriggers
8692 * get information about every trigger on a dumpable table
8693 *
8694 * Note: trigger data is not returned directly to the caller, but it
8695 * does get entered into the DumpableObject tables.
8696 */
8697void
8698getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
8699{
8702 PGresult *res;
8703 int ntups;
8704 int curtblindx;
8706 int i_tableoid,
8707 i_oid,
8708 i_tgrelid,
8709 i_tgname,
8712 i_tgdef;
8713
8714 /*
8715 * We want to perform just one query against pg_trigger. However, we
8716 * mustn't try to select every row of the catalog and then sort it out on
8717 * the client side, because some of the server-side functions we need
8718 * would be unsafe to apply to tables we don't have lock on. Hence, we
8719 * build an array of the OIDs of tables we care about (and now have lock
8720 * on!), and use a WHERE clause to constrain which rows are selected.
8721 */
8723 for (int i = 0; i < numTables; i++)
8724 {
8725 TableInfo *tbinfo = &tblinfo[i];
8726
8727 if (!tbinfo->hastriggers ||
8728 !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
8729 continue;
8730
8731 /* OK, we need info for this table */
8732 if (tbloids->len > 1) /* do we have more than the '{'? */
8734 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8735 }
8737
8738 if (fout->remoteVersion >= 150000)
8739 {
8740 /*
8741 * NB: think not to use pretty=true in pg_get_triggerdef. It could
8742 * result in non-forward-compatible dumps of WHEN clauses due to
8743 * under-parenthesization.
8744 *
8745 * NB: We need to see partition triggers in case the tgenabled flag
8746 * has been changed from the parent.
8747 */
8748 appendPQExpBuffer(query,
8749 "SELECT t.tgrelid, t.tgname, "
8750 "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8751 "t.tgenabled, t.tableoid, t.oid, "
8752 "t.tgparentid <> 0 AS tgispartition\n"
8753 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8754 "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8755 "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8756 "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
8757 "OR t.tgenabled != u.tgenabled) "
8758 "ORDER BY t.tgrelid, t.tgname",
8759 tbloids->data);
8760 }
8761 else if (fout->remoteVersion >= 130000)
8762 {
8763 /*
8764 * NB: think not to use pretty=true in pg_get_triggerdef. It could
8765 * result in non-forward-compatible dumps of WHEN clauses due to
8766 * under-parenthesization.
8767 *
8768 * NB: We need to see tgisinternal triggers in partitions, in case the
8769 * tgenabled flag has been changed from the parent.
8770 */
8771 appendPQExpBuffer(query,
8772 "SELECT t.tgrelid, t.tgname, "
8773 "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8774 "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
8775 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8776 "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8777 "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8778 "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
8779 "ORDER BY t.tgrelid, t.tgname",
8780 tbloids->data);
8781 }
8782 else if (fout->remoteVersion >= 110000)
8783 {
8784 /*
8785 * NB: We need to see tgisinternal triggers in partitions, in case the
8786 * tgenabled flag has been changed from the parent. No tgparentid in
8787 * version 11-12, so we have to match them via pg_depend.
8788 *
8789 * See above about pretty=true in pg_get_triggerdef.
8790 */
8791 appendPQExpBuffer(query,
8792 "SELECT t.tgrelid, t.tgname, "
8793 "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8794 "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
8795 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8796 "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8797 "LEFT JOIN pg_catalog.pg_depend AS d ON "
8798 " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8799 " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8800 " d.objid = t.oid "
8801 "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
8802 "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
8803 "ORDER BY t.tgrelid, t.tgname",
8804 tbloids->data);
8805 }
8806 else
8807 {
8808 /* See above about pretty=true in pg_get_triggerdef */
8809 appendPQExpBuffer(query,
8810 "SELECT t.tgrelid, t.tgname, "
8811 "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8812 "t.tgenabled, false as tgispartition, "
8813 "t.tableoid, t.oid "
8814 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8815 "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8816 "WHERE NOT tgisinternal "
8817 "ORDER BY t.tgrelid, t.tgname",
8818 tbloids->data);
8819 }
8820
8821 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8822
8823 ntups = PQntuples(res);
8824
8825 i_tableoid = PQfnumber(res, "tableoid");
8826 i_oid = PQfnumber(res, "oid");
8827 i_tgrelid = PQfnumber(res, "tgrelid");
8828 i_tgname = PQfnumber(res, "tgname");
8829 i_tgenabled = PQfnumber(res, "tgenabled");
8830 i_tgispartition = PQfnumber(res, "tgispartition");
8831 i_tgdef = PQfnumber(res, "tgdef");
8832
8833 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
8834
8835 /*
8836 * Outer loop iterates once per table, not once per row. Incrementing of
8837 * j is handled by the inner loop.
8838 */
8839 curtblindx = -1;
8840 for (int j = 0; j < ntups;)
8841 {
8844 int numtrigs;
8845
8846 /* Count rows for this table */
8847 for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
8848 if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
8849 break;
8850
8851 /*
8852 * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8853 * order.
8854 */
8855 while (++curtblindx < numTables)
8856 {
8857 tbinfo = &tblinfo[curtblindx];
8858 if (tbinfo->dobj.catId.oid == tgrelid)
8859 break;
8860 }
8861 if (curtblindx >= numTables)
8862 pg_fatal("unrecognized table OID %u", tgrelid);
8863
8864 /* Save data for this table */
8865 tbinfo->triggers = tginfo + j;
8866 tbinfo->numTriggers = numtrigs;
8867
8868 for (int c = 0; c < numtrigs; c++, j++)
8869 {
8870 tginfo[j].dobj.objType = DO_TRIGGER;
8871 tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8872 tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8873 AssignDumpId(&tginfo[j].dobj);
8874 tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
8875 tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
8876 tginfo[j].tgtable = tbinfo;
8877 tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
8878 tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
8879 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
8880 }
8881 }
8882
8883 PQclear(res);
8884
8885 destroyPQExpBuffer(query);
8887}
8888
8889/*
8890 * getEventTriggers
8891 * get information about event triggers
8892 */
8893void
8895{
8896 int i;
8897 PQExpBuffer query;
8898 PGresult *res;
8900 int i_tableoid,
8901 i_oid,
8902 i_evtname,
8903 i_evtevent,
8904 i_evtowner,
8905 i_evttags,
8906 i_evtfname,
8908 int ntups;
8909
8910 /* Before 9.3, there are no event triggers */
8911 if (fout->remoteVersion < 90300)
8912 return;
8913
8914 query = createPQExpBuffer();
8915
8917 "SELECT e.tableoid, e.oid, evtname, evtenabled, "
8918 "evtevent, evtowner, "
8919 "array_to_string(array("
8920 "select quote_literal(x) "
8921 " from unnest(evttags) as t(x)), ', ') as evttags, "
8922 "e.evtfoid::regproc as evtfname "
8923 "FROM pg_event_trigger e "
8924 "ORDER BY e.oid");
8925
8926 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8927
8928 ntups = PQntuples(res);
8929
8930 evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
8931
8932 i_tableoid = PQfnumber(res, "tableoid");
8933 i_oid = PQfnumber(res, "oid");
8934 i_evtname = PQfnumber(res, "evtname");
8935 i_evtevent = PQfnumber(res, "evtevent");
8936 i_evtowner = PQfnumber(res, "evtowner");
8937 i_evttags = PQfnumber(res, "evttags");
8938 i_evtfname = PQfnumber(res, "evtfname");
8939 i_evtenabled = PQfnumber(res, "evtenabled");
8940
8941 for (i = 0; i < ntups; i++)
8942 {
8943 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
8944 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8945 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8946 AssignDumpId(&evtinfo[i].dobj);
8947 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
8948 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
8949 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
8950 evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
8951 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
8952 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
8953 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
8954
8955 /* Decide whether we want to dump it */
8957 }
8958
8959 PQclear(res);
8960
8961 destroyPQExpBuffer(query);
8962}
8963
8964/*
8965 * getProcLangs
8966 * get basic information about every procedural language in the system
8967 *
8968 * NB: this must run after getFuncs() because we assume we can do
8969 * findFuncByOid().
8970 */
8971void
8973{
8974 PGresult *res;
8975 int ntups;
8976 int i;
8979 int i_tableoid;
8980 int i_oid;
8981 int i_lanname;
8982 int i_lanpltrusted;
8983 int i_lanplcallfoid;
8984 int i_laninline;
8985 int i_lanvalidator;
8986 int i_lanacl;
8987 int i_acldefault;
8988 int i_lanowner;
8989
8990 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8991 "lanname, lanpltrusted, lanplcallfoid, "
8992 "laninline, lanvalidator, "
8993 "lanacl, "
8994 "acldefault('l', lanowner) AS acldefault, "
8995 "lanowner "
8996 "FROM pg_language "
8997 "WHERE lanispl "
8998 "ORDER BY oid");
8999
9000 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9001
9002 ntups = PQntuples(res);
9003
9004 planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
9005
9006 i_tableoid = PQfnumber(res, "tableoid");
9007 i_oid = PQfnumber(res, "oid");
9008 i_lanname = PQfnumber(res, "lanname");
9009 i_lanpltrusted = PQfnumber(res, "lanpltrusted");
9010 i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
9011 i_laninline = PQfnumber(res, "laninline");
9012 i_lanvalidator = PQfnumber(res, "lanvalidator");
9013 i_lanacl = PQfnumber(res, "lanacl");
9014 i_acldefault = PQfnumber(res, "acldefault");
9015 i_lanowner = PQfnumber(res, "lanowner");
9016
9017 for (i = 0; i < ntups; i++)
9018 {
9019 planginfo[i].dobj.objType = DO_PROCLANG;
9020 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9021 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9022 AssignDumpId(&planginfo[i].dobj);
9023
9024 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
9025 planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
9026 planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9027 planginfo[i].dacl.privtype = 0;
9028 planginfo[i].dacl.initprivs = NULL;
9029 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
9030 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
9031 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
9032 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
9033 planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
9034
9035 /* Decide whether we want to dump it */
9037
9038 /* Mark whether language has an ACL */
9039 if (!PQgetisnull(res, i, i_lanacl))
9040 planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9041 }
9042
9043 PQclear(res);
9044
9045 destroyPQExpBuffer(query);
9046}
9047
9048/*
9049 * getCasts
9050 * get basic information about most casts in the system
9051 *
9052 * Skip casts from a range to its multirange, since we'll create those
9053 * automatically.
9054 */
9055void
9057{
9058 PGresult *res;
9059 int ntups;
9060 int i;
9063 int i_tableoid;
9064 int i_oid;
9065 int i_castsource;
9066 int i_casttarget;
9067 int i_castfunc;
9068 int i_castcontext;
9069 int i_castmethod;
9070
9071 if (fout->remoteVersion >= 140000)
9072 {
9073 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9074 "castsource, casttarget, castfunc, castcontext, "
9075 "castmethod "
9076 "FROM pg_cast c "
9077 "WHERE NOT EXISTS ( "
9078 "SELECT 1 FROM pg_range r "
9079 "WHERE c.castsource = r.rngtypid "
9080 "AND c.casttarget = r.rngmultitypid "
9081 ") "
9082 "ORDER BY 3,4");
9083 }
9084 else
9085 {
9086 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9087 "castsource, casttarget, castfunc, castcontext, "
9088 "castmethod "
9089 "FROM pg_cast ORDER BY 3,4");
9090 }
9091
9092 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9093
9094 ntups = PQntuples(res);
9095
9096 castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
9097
9098 i_tableoid = PQfnumber(res, "tableoid");
9099 i_oid = PQfnumber(res, "oid");
9100 i_castsource = PQfnumber(res, "castsource");
9101 i_casttarget = PQfnumber(res, "casttarget");
9102 i_castfunc = PQfnumber(res, "castfunc");
9103 i_castcontext = PQfnumber(res, "castcontext");
9104 i_castmethod = PQfnumber(res, "castmethod");
9105
9106 for (i = 0; i < ntups; i++)
9107 {
9111
9113 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9114 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9115 AssignDumpId(&castinfo[i].dobj);
9116 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
9117 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
9118 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
9119 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
9120 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
9121
9122 /*
9123 * Try to name cast as concatenation of typnames. This is only used
9124 * for purposes of sorting. If we fail to find either type, the name
9125 * will be an empty string.
9126 */
9128 sTypeInfo = findTypeByOid(castinfo[i].castsource);
9129 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
9130 if (sTypeInfo && tTypeInfo)
9131 appendPQExpBuffer(&namebuf, "%s %s",
9132 sTypeInfo->dobj.name, tTypeInfo->dobj.name);
9133 castinfo[i].dobj.name = namebuf.data;
9134
9135 /* Decide whether we want to dump it */
9137 }
9138
9139 PQclear(res);
9140
9141 destroyPQExpBuffer(query);
9142}
9143
9144static char *
9146{
9147 PQExpBuffer query;
9148 PGresult *res;
9149 char *lanname;
9150
9151 query = createPQExpBuffer();
9152 appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
9153 res = ExecuteSqlQueryForSingleRow(fout, query->data);
9154 lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
9155 destroyPQExpBuffer(query);
9156 PQclear(res);
9157
9158 return lanname;
9159}
9160
9161/*
9162 * getTransforms
9163 * get basic information about every transform in the system
9164 */
9165void
9167{
9168 PGresult *res;
9169 int ntups;
9170 int i;
9171 PQExpBuffer query;
9173 int i_tableoid;
9174 int i_oid;
9175 int i_trftype;
9176 int i_trflang;
9177 int i_trffromsql;
9178 int i_trftosql;
9179
9180 /* Transforms didn't exist pre-9.5 */
9181 if (fout->remoteVersion < 90500)
9182 return;
9183
9184 query = createPQExpBuffer();
9185
9186 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9187 "trftype, trflang, trffromsql::oid, trftosql::oid "
9188 "FROM pg_transform "
9189 "ORDER BY 3,4");
9190
9191 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9192
9193 ntups = PQntuples(res);
9194
9195 transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
9196
9197 i_tableoid = PQfnumber(res, "tableoid");
9198 i_oid = PQfnumber(res, "oid");
9199 i_trftype = PQfnumber(res, "trftype");
9200 i_trflang = PQfnumber(res, "trflang");
9201 i_trffromsql = PQfnumber(res, "trffromsql");
9202 i_trftosql = PQfnumber(res, "trftosql");
9203
9204 for (i = 0; i < ntups; i++)
9205 {
9208 char *lanname;
9209
9211 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9212 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9214 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
9215 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
9216 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
9217 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
9218
9219 /*
9220 * Try to name transform as concatenation of type and language name.
9221 * This is only used for purposes of sorting. If we fail to find
9222 * either, the name will be an empty string.
9223 */
9227 if (typeInfo && lanname)
9228 appendPQExpBuffer(&namebuf, "%s %s",
9229 typeInfo->dobj.name, lanname);
9230 transforminfo[i].dobj.name = namebuf.data;
9231 free(lanname);
9232
9233 /* Decide whether we want to dump it */
9235 }
9236
9237 PQclear(res);
9238
9239 destroyPQExpBuffer(query);
9240}
9241
9242/*
9243 * getTableAttrs -
9244 * for each interesting table, read info about its attributes
9245 * (names, types, default values, CHECK constraints, etc)
9246 *
9247 * modifies tblinfo
9248 */
9249void
9251{
9252 DumpOptions *dopt = fout->dopt;
9257 PGresult *res;
9258 int ntups;
9259 int curtblindx;
9260 int i_attrelid;
9261 int i_attnum;
9262 int i_attname;
9263 int i_atttypname;
9264 int i_attstattarget;
9265 int i_attstorage;
9266 int i_typstorage;
9267 int i_attidentity;
9268 int i_attgenerated;
9269 int i_attisdropped;
9270 int i_attlen;
9271 int i_attalign;
9272 int i_attislocal;
9273 int i_notnull_name;
9278 int i_attoptions;
9279 int i_attcollation;
9280 int i_attcompression;
9281 int i_attfdwoptions;
9282 int i_attmissingval;
9283 int i_atthasdef;
9284
9285 /*
9286 * We want to perform just one query against pg_attribute, and then just
9287 * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
9288 * (for CHECK constraints and for NOT NULL constraints). However, we
9289 * mustn't try to select every row of those catalogs and then sort it out
9290 * on the client side, because some of the server-side functions we need
9291 * would be unsafe to apply to tables we don't have lock on. Hence, we
9292 * build an array of the OIDs of tables we care about (and now have lock
9293 * on!), and use a WHERE clause to constrain which rows are selected.
9294 */
9297 for (int i = 0; i < numTables; i++)
9298 {
9299 TableInfo *tbinfo = &tblinfo[i];
9300
9301 /* Don't bother to collect info for sequences */
9302 if (tbinfo->relkind == RELKIND_SEQUENCE)
9303 continue;
9304
9305 /*
9306 * Don't bother with uninteresting tables, either. For binary
9307 * upgrades, this is bypassed for pg_largeobject_metadata and
9308 * pg_shdepend so that the columns names are collected for the
9309 * corresponding COPY commands. Restoring the data for those catalogs
9310 * is faster than restoring the equivalent set of large object
9311 * commands. We can only do this for upgrades from v12 and newer; in
9312 * older versions, pg_largeobject_metadata was created WITH OIDS, so
9313 * the OID column is hidden and won't be dumped.
9314 */
9315 if (!tbinfo->interesting &&
9316 !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
9317 (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
9318 tbinfo->dobj.catId.oid == SharedDependRelationId)))
9319 continue;
9320
9321 /* OK, we need info for this table */
9322 if (tbloids->len > 1) /* do we have more than the '{'? */
9324 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
9325
9326 if (tbinfo->ncheck > 0)
9327 {
9328 /* Also make a list of the ones with check constraints */
9329 if (checkoids->len > 1) /* do we have more than the '{'? */
9331 appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
9332 }
9333 }
9336
9337 /*
9338 * Find all the user attributes and their types.
9339 *
9340 * Since we only want to dump COLLATE clauses for attributes whose
9341 * collation is different from their type's default, we use a CASE here to
9342 * suppress uninteresting attcollations cheaply.
9343 */
9345 "SELECT\n"
9346 "a.attrelid,\n"
9347 "a.attnum,\n"
9348 "a.attname,\n"
9349 "a.attstattarget,\n"
9350 "a.attstorage,\n"
9351 "t.typstorage,\n"
9352 "a.atthasdef,\n"
9353 "a.attisdropped,\n"
9354 "a.attlen,\n"
9355 "a.attalign,\n"
9356 "a.attislocal,\n"
9357 "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
9358 "array_to_string(a.attoptions, ', ') AS attoptions,\n"
9359 "CASE WHEN a.attcollation <> t.typcollation "
9360 "THEN a.attcollation ELSE 0 END AS attcollation,\n"
9361 "pg_catalog.array_to_string(ARRAY("
9362 "SELECT pg_catalog.quote_ident(option_name) || "
9363 "' ' || pg_catalog.quote_literal(option_value) "
9364 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
9365 "ORDER BY option_name"
9366 "), E',\n ') AS attfdwoptions,\n");
9367
9368 /*
9369 * Find out any NOT NULL markings for each column. In 18 and up we read
9370 * pg_constraint to obtain the constraint name, and for valid constraints
9371 * also pg_description to obtain its comment. notnull_noinherit is set
9372 * according to the NO INHERIT property. For versions prior to 18, we
9373 * store an empty string as the name when a constraint is marked as
9374 * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
9375 * without a name); also, such cases are never NO INHERIT.
9376 *
9377 * For invalid constraints, we need to store their OIDs for processing
9378 * elsewhere, so we bring the pg_constraint.oid value when the constraint
9379 * is invalid, and NULL otherwise. Their comments are handled not here
9380 * but by collectComments, because they're their own dumpable object.
9381 *
9382 * We track in notnull_islocal whether the constraint was defined directly
9383 * in this table or via an ancestor, for binary upgrade. flagInhAttrs
9384 * might modify this later.
9385 */
9386 if (fout->remoteVersion >= 180000)
9388 "co.conname AS notnull_name,\n"
9389 "CASE WHEN co.convalidated THEN pt.description"
9390 " ELSE NULL END AS notnull_comment,\n"
9391 "CASE WHEN NOT co.convalidated THEN co.oid "
9392 "ELSE NULL END AS notnull_invalidoid,\n"
9393 "co.connoinherit AS notnull_noinherit,\n"
9394 "co.conislocal AS notnull_islocal,\n");
9395 else
9397 "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
9398 "NULL AS notnull_comment,\n"
9399 "NULL AS notnull_invalidoid,\n"
9400 "false AS notnull_noinherit,\n"
9401 "CASE WHEN a.attislocal THEN true\n"
9402 " WHEN a.attnotnull AND NOT a.attislocal THEN true\n"
9403 " ELSE false\n"
9404 "END AS notnull_islocal,\n");
9405
9406 if (fout->remoteVersion >= 140000)
9408 "a.attcompression AS attcompression,\n");
9409 else
9411 "'' AS attcompression,\n");
9412
9413 if (fout->remoteVersion >= 100000)
9415 "a.attidentity,\n");
9416 else
9418 "'' AS attidentity,\n");
9419
9420 if (fout->remoteVersion >= 110000)
9422 "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
9423 "THEN a.attmissingval ELSE null END AS attmissingval,\n");
9424 else
9426 "NULL AS attmissingval,\n");
9427
9428 if (fout->remoteVersion >= 120000)
9430 "a.attgenerated\n");
9431 else
9433 "'' AS attgenerated\n");
9434
9435 /* need left join to pg_type to not fail on dropped columns ... */
9437 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9438 "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
9439 "LEFT JOIN pg_catalog.pg_type t "
9440 "ON (a.atttypid = t.oid)\n",
9441 tbloids->data);
9442
9443 /*
9444 * In versions 18 and up, we need pg_constraint for explicit NOT NULL
9445 * entries and pg_description to get their comments.
9446 */
9447 if (fout->remoteVersion >= 180000)
9449 " LEFT JOIN pg_catalog.pg_constraint co ON "
9450 "(a.attrelid = co.conrelid\n"
9451 " AND co.contype = 'n' AND "
9452 "co.conkey = array[a.attnum])\n"
9453 " LEFT JOIN pg_catalog.pg_description pt ON "
9454 "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
9455
9457 "WHERE a.attnum > 0::pg_catalog.int2\n"
9458 "ORDER BY a.attrelid, a.attnum");
9459
9461
9462 ntups = PQntuples(res);
9463
9464 i_attrelid = PQfnumber(res, "attrelid");
9465 i_attnum = PQfnumber(res, "attnum");
9466 i_attname = PQfnumber(res, "attname");
9467 i_atttypname = PQfnumber(res, "atttypname");
9468 i_attstattarget = PQfnumber(res, "attstattarget");
9469 i_attstorage = PQfnumber(res, "attstorage");
9470 i_typstorage = PQfnumber(res, "typstorage");
9471 i_attidentity = PQfnumber(res, "attidentity");
9472 i_attgenerated = PQfnumber(res, "attgenerated");
9473 i_attisdropped = PQfnumber(res, "attisdropped");
9474 i_attlen = PQfnumber(res, "attlen");
9475 i_attalign = PQfnumber(res, "attalign");
9476 i_attislocal = PQfnumber(res, "attislocal");
9477 i_notnull_name = PQfnumber(res, "notnull_name");
9478 i_notnull_comment = PQfnumber(res, "notnull_comment");
9479 i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
9480 i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
9481 i_notnull_islocal = PQfnumber(res, "notnull_islocal");
9482 i_attoptions = PQfnumber(res, "attoptions");
9483 i_attcollation = PQfnumber(res, "attcollation");
9484 i_attcompression = PQfnumber(res, "attcompression");
9485 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
9486 i_attmissingval = PQfnumber(res, "attmissingval");
9487 i_atthasdef = PQfnumber(res, "atthasdef");
9488
9489 /* Within the next loop, we'll accumulate OIDs of tables with defaults */
9492
9493 /*
9494 * Outer loop iterates once per table, not once per row. Incrementing of
9495 * r is handled by the inner loop.
9496 */
9497 curtblindx = -1;
9498 for (int r = 0; r < ntups;)
9499 {
9500 Oid attrelid = atooid(PQgetvalue(res, r, i_attrelid));
9502 int numatts;
9503 bool hasdefaults;
9504
9505 /* Count rows for this table */
9506 for (numatts = 1; numatts < ntups - r; numatts++)
9507 if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
9508 break;
9509
9510 /*
9511 * Locate the associated TableInfo; we rely on tblinfo[] being in OID
9512 * order.
9513 */
9514 while (++curtblindx < numTables)
9515 {
9516 tbinfo = &tblinfo[curtblindx];
9517 if (tbinfo->dobj.catId.oid == attrelid)
9518 break;
9519 }
9520 if (curtblindx >= numTables)
9521 pg_fatal("unrecognized table OID %u", attrelid);
9522 /* cross-check that we only got requested tables */
9523 if (tbinfo->relkind == RELKIND_SEQUENCE ||
9524 (!tbinfo->interesting &&
9525 !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
9526 (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
9527 tbinfo->dobj.catId.oid == SharedDependRelationId))))
9528 pg_fatal("unexpected column data for table \"%s\"",
9529 tbinfo->dobj.name);
9530
9531 /* Save data for this table */
9532 tbinfo->numatts = numatts;
9533 tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
9534 tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
9535 tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
9536 tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
9537 tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
9538 tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
9539 tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
9540 tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
9541 tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
9542 tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
9543 tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
9544 tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
9545 tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
9546 tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
9547 tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
9548 tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
9549 tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
9550 tbinfo->notnull_comment = (char **) pg_malloc(numatts * sizeof(char *));
9551 tbinfo->notnull_invalid = (bool *) pg_malloc(numatts * sizeof(bool));
9552 tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
9553 tbinfo->notnull_islocal = (bool *) pg_malloc(numatts * sizeof(bool));
9554 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
9555 hasdefaults = false;
9556
9557 for (int j = 0; j < numatts; j++, r++)
9558 {
9559 if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
9560 pg_fatal("invalid column numbering in table \"%s\"",
9561 tbinfo->dobj.name);
9562 tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
9563 tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
9564 if (PQgetisnull(res, r, i_attstattarget))
9565 tbinfo->attstattarget[j] = -1;
9566 else
9567 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
9568 tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
9569 tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
9570 tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
9571 tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
9572 tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
9573 tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
9574 tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
9575 tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
9576 tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
9577
9578 /* Handle not-null constraint name and flags */
9580 tbinfo, j,
9587
9588 tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
9590 tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
9591 tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
9592 tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
9593 tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
9594 tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
9595 tbinfo->attrdefs[j] = NULL; /* fix below */
9596 if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
9597 hasdefaults = true;
9598 }
9599
9600 if (hasdefaults)
9601 {
9602 /* Collect OIDs of interesting tables that have defaults */
9603 if (tbloids->len > 1) /* do we have more than the '{'? */
9605 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
9606 }
9607 }
9608
9609 /* If invalidnotnulloids has any data, finalize it */
9610 if (invalidnotnulloids != NULL)
9612
9613 PQclear(res);
9614
9615 /*
9616 * Now get info about column defaults. This is skipped for a data-only
9617 * dump, as it is only needed for table schemas.
9618 */
9619 if (dopt->dumpSchema && tbloids->len > 1)
9620 {
9621 AttrDefInfo *attrdefs;
9622 int numDefaults;
9624
9625 pg_log_info("finding table default expressions");
9626
9628
9629 printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
9630 "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
9631 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9632 "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
9633 "ORDER BY a.adrelid, a.adnum",
9634 tbloids->data);
9635
9637
9638 numDefaults = PQntuples(res);
9639 attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
9640
9641 curtblindx = -1;
9642 for (int j = 0; j < numDefaults; j++)
9643 {
9644 Oid adtableoid = atooid(PQgetvalue(res, j, 0));
9645 Oid adoid = atooid(PQgetvalue(res, j, 1));
9646 Oid adrelid = atooid(PQgetvalue(res, j, 2));
9647 int adnum = atoi(PQgetvalue(res, j, 3));
9648 char *adsrc = PQgetvalue(res, j, 4);
9649
9650 /*
9651 * Locate the associated TableInfo; we rely on tblinfo[] being in
9652 * OID order.
9653 */
9654 if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
9655 {
9656 while (++curtblindx < numTables)
9657 {
9658 tbinfo = &tblinfo[curtblindx];
9659 if (tbinfo->dobj.catId.oid == adrelid)
9660 break;
9661 }
9662 if (curtblindx >= numTables)
9663 pg_fatal("unrecognized table OID %u", adrelid);
9664 }
9665
9666 if (adnum <= 0 || adnum > tbinfo->numatts)
9667 pg_fatal("invalid adnum value %d for table \"%s\"",
9668 adnum, tbinfo->dobj.name);
9669
9670 /*
9671 * dropped columns shouldn't have defaults, but just in case,
9672 * ignore 'em
9673 */
9674 if (tbinfo->attisdropped[adnum - 1])
9675 continue;
9676
9677 attrdefs[j].dobj.objType = DO_ATTRDEF;
9678 attrdefs[j].dobj.catId.tableoid = adtableoid;
9679 attrdefs[j].dobj.catId.oid = adoid;
9680 AssignDumpId(&attrdefs[j].dobj);
9681 attrdefs[j].adtable = tbinfo;
9682 attrdefs[j].adnum = adnum;
9683 attrdefs[j].adef_expr = pg_strdup(adsrc);
9684
9685 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
9686 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
9687
9688 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
9689
9690 /*
9691 * Figure out whether the default/generation expression should be
9692 * dumped as part of the main CREATE TABLE (or similar) command or
9693 * as a separate ALTER TABLE (or similar) command. The preference
9694 * is to put it into the CREATE command, but in some cases that's
9695 * not possible.
9696 */
9697 if (tbinfo->attgenerated[adnum - 1])
9698 {
9699 /*
9700 * Column generation expressions cannot be dumped separately,
9701 * because there is no syntax for it. By setting separate to
9702 * false here we prevent the "default" from being processed as
9703 * its own dumpable object. Later, flagInhAttrs() will mark
9704 * it as not to be dumped at all, if possible (that is, if it
9705 * can be inherited from a parent).
9706 */
9707 attrdefs[j].separate = false;
9708 }
9709 else if (tbinfo->relkind == RELKIND_VIEW)
9710 {
9711 /*
9712 * Defaults on a VIEW must always be dumped as separate ALTER
9713 * TABLE commands.
9714 */
9715 attrdefs[j].separate = true;
9716 }
9717 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
9718 {
9719 /* column will be suppressed, print default separately */
9720 attrdefs[j].separate = true;
9721 }
9722 else
9723 {
9724 attrdefs[j].separate = false;
9725 }
9726
9727 if (!attrdefs[j].separate)
9728 {
9729 /*
9730 * Mark the default as needing to appear before the table, so
9731 * that any dependencies it has must be emitted before the
9732 * CREATE TABLE. If this is not possible, we'll change to
9733 * "separate" mode while sorting dependencies.
9734 */
9736 attrdefs[j].dobj.dumpId);
9737 }
9738
9739 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
9740 }
9741
9742 PQclear(res);
9743 }
9744
9745 /*
9746 * Get info about NOT NULL NOT VALID constraints. This is skipped for a
9747 * data-only dump, as it is only needed for table schemas.
9748 */
9749 if (dopt->dumpSchema && invalidnotnulloids)
9750 {
9752 int numConstrs;
9753 int i_tableoid;
9754 int i_oid;
9755 int i_conrelid;
9756 int i_conname;
9757 int i_consrc;
9758 int i_conislocal;
9759
9760 pg_log_info("finding invalid not-null constraints");
9761
9764 "SELECT c.tableoid, c.oid, conrelid, conname, "
9765 "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9766 "conislocal, convalidated "
9767 "FROM unnest('%s'::pg_catalog.oid[]) AS src(conoid)\n"
9768 "JOIN pg_catalog.pg_constraint c ON (src.conoid = c.oid)\n"
9769 "ORDER BY c.conrelid, c.conname",
9770 invalidnotnulloids->data);
9771
9773
9774 numConstrs = PQntuples(res);
9776
9777 i_tableoid = PQfnumber(res, "tableoid");
9778 i_oid = PQfnumber(res, "oid");
9779 i_conrelid = PQfnumber(res, "conrelid");
9780 i_conname = PQfnumber(res, "conname");
9781 i_consrc = PQfnumber(res, "consrc");
9782 i_conislocal = PQfnumber(res, "conislocal");
9783
9784 /* As above, this loop iterates once per table, not once per row */
9785 curtblindx = -1;
9786 for (int j = 0; j < numConstrs;)
9787 {
9788 Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9790 int numcons;
9791
9792 /* Count rows for this table */
9793 for (numcons = 1; numcons < numConstrs - j; numcons++)
9794 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9795 break;
9796
9797 /*
9798 * Locate the associated TableInfo; we rely on tblinfo[] being in
9799 * OID order.
9800 */
9801 while (++curtblindx < numTables)
9802 {
9803 tbinfo = &tblinfo[curtblindx];
9804 if (tbinfo->dobj.catId.oid == conrelid)
9805 break;
9806 }
9807 if (curtblindx >= numTables)
9808 pg_fatal("unrecognized table OID %u", conrelid);
9809
9810 for (int c = 0; c < numcons; c++, j++)
9811 {
9812 constrs[j].dobj.objType = DO_CONSTRAINT;
9813 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9814 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
9815 AssignDumpId(&constrs[j].dobj);
9816 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
9817 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
9818 constrs[j].contable = tbinfo;
9819 constrs[j].condomain = NULL;
9820 constrs[j].contype = 'n';
9821 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
9822 constrs[j].confrelid = InvalidOid;
9823 constrs[j].conindex = 0;
9824 constrs[j].condeferrable = false;
9825 constrs[j].condeferred = false;
9826 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9827
9828 /*
9829 * All invalid not-null constraints must be dumped separately,
9830 * because CREATE TABLE would not create them as invalid, and
9831 * also because they must be created after potentially
9832 * violating data has been loaded.
9833 */
9834 constrs[j].separate = true;
9835
9836 constrs[j].dobj.dump = tbinfo->dobj.dump;
9837 }
9838 }
9839 PQclear(res);
9840 }
9841
9842 /*
9843 * Get info about table CHECK constraints. This is skipped for a
9844 * data-only dump, as it is only needed for table schemas.
9845 */
9846 if (dopt->dumpSchema && checkoids->len > 2)
9847 {
9849 int numConstrs;
9850 int i_tableoid;
9851 int i_oid;
9852 int i_conrelid;
9853 int i_conname;
9854 int i_consrc;
9855 int i_conislocal;
9856 int i_convalidated;
9857
9858 pg_log_info("finding table check constraints");
9859
9862 "SELECT c.tableoid, c.oid, conrelid, conname, "
9863 "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9864 "conislocal, convalidated "
9865 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9866 "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
9867 "WHERE contype = 'c' "
9868 "ORDER BY c.conrelid, c.conname",
9869 checkoids->data);
9870
9872
9873 numConstrs = PQntuples(res);
9875
9876 i_tableoid = PQfnumber(res, "tableoid");
9877 i_oid = PQfnumber(res, "oid");
9878 i_conrelid = PQfnumber(res, "conrelid");
9879 i_conname = PQfnumber(res, "conname");
9880 i_consrc = PQfnumber(res, "consrc");
9881 i_conislocal = PQfnumber(res, "conislocal");
9882 i_convalidated = PQfnumber(res, "convalidated");
9883
9884 /* As above, this loop iterates once per table, not once per row */
9885 curtblindx = -1;
9886 for (int j = 0; j < numConstrs;)
9887 {
9888 Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9890 int numcons;
9891
9892 /* Count rows for this table */
9893 for (numcons = 1; numcons < numConstrs - j; numcons++)
9894 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9895 break;
9896
9897 /*
9898 * Locate the associated TableInfo; we rely on tblinfo[] being in
9899 * OID order.
9900 */
9901 while (++curtblindx < numTables)
9902 {
9903 tbinfo = &tblinfo[curtblindx];
9904 if (tbinfo->dobj.catId.oid == conrelid)
9905 break;
9906 }
9907 if (curtblindx >= numTables)
9908 pg_fatal("unrecognized table OID %u", conrelid);
9909
9910 if (numcons != tbinfo->ncheck)
9911 {
9912 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
9913 "expected %d check constraints on table \"%s\" but found %d",
9914 tbinfo->ncheck),
9915 tbinfo->ncheck, tbinfo->dobj.name, numcons);
9916 pg_log_error_hint("The system catalogs might be corrupted.");
9917 exit_nicely(1);
9918 }
9919
9920 tbinfo->checkexprs = constrs + j;
9921
9922 for (int c = 0; c < numcons; c++, j++)
9923 {
9924 bool validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
9925
9926 constrs[j].dobj.objType = DO_CONSTRAINT;
9927 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9928 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
9929 AssignDumpId(&constrs[j].dobj);
9930 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
9931 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
9932 constrs[j].contable = tbinfo;
9933 constrs[j].condomain = NULL;
9934 constrs[j].contype = 'c';
9935 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
9936 constrs[j].confrelid = InvalidOid;
9937 constrs[j].conindex = 0;
9938 constrs[j].condeferrable = false;
9939 constrs[j].condeferred = false;
9940 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9941
9942 /*
9943 * An unvalidated constraint needs to be dumped separately, so
9944 * that potentially-violating existing data is loaded before
9945 * the constraint.
9946 */
9947 constrs[j].separate = !validated;
9948
9949 constrs[j].dobj.dump = tbinfo->dobj.dump;
9950
9951 /*
9952 * Mark the constraint as needing to appear before the table
9953 * --- this is so that any other dependencies of the
9954 * constraint will be emitted before we try to create the
9955 * table. If the constraint is to be dumped separately, it
9956 * will be dumped after data is loaded anyway, so don't do it.
9957 * (There's an automatic dependency in the opposite direction
9958 * anyway, so don't need to add one manually here.)
9959 */
9960 if (!constrs[j].separate)
9962 constrs[j].dobj.dumpId);
9963
9964 /*
9965 * We will detect later whether the constraint must be split
9966 * out from the table definition.
9967 */
9968 }
9969 }
9970
9971 PQclear(res);
9972 }
9973
9977}
9978
9979/*
9980 * Based on the getTableAttrs query's row corresponding to one column, set
9981 * the name and flags to handle a not-null constraint for that column in
9982 * the tbinfo struct.
9983 *
9984 * Result row 'r' is for tbinfo's attribute 'j'.
9985 *
9986 * There are four possibilities:
9987 * 1) the column has no not-null constraints. In that case, ->notnull_constrs
9988 * (the constraint name) remains NULL.
9989 * 2) The column has a constraint with no name (this is the case when
9990 * constraints come from pre-18 servers). In this case, ->notnull_constrs
9991 * is set to the empty string; dumpTableSchema will print just "NOT NULL".
9992 * 3) The column has an invalid not-null constraint. This must be treated
9993 * as a separate object (because it must be created after the table data
9994 * is loaded). So we add its OID to invalidnotnulloids for processing
9995 * elsewhere and do nothing further with it here. We distinguish this
9996 * case because the "notnull_invalidoid" column has been set to a non-NULL
9997 * value, which is the constraint OID. Valid constraints have a null OID.
9998 * 4) The column has a constraint with a known name; in that case
9999 * notnull_constrs carries that name and dumpTableSchema will print
10000 * "CONSTRAINT the_name NOT NULL". However, if the name is the default
10001 * (table_column_not_null) and there's no comment on the constraint,
10002 * there's no need to print that name in the dump, so notnull_constrs
10003 * is set to the empty string and it behaves as case 2.
10004 *
10005 * In a child table that inherits from a parent already containing NOT NULL
10006 * constraints and the columns in the child don't have their own NOT NULL
10007 * declarations, we suppress printing constraints in the child: the
10008 * constraints are acquired at the point where the child is attached to the
10009 * parent. This is tracked in ->notnull_islocal; for servers pre-18 this is
10010 * set not here but in flagInhAttrs. That flag is also used when the
10011 * constraint was validated in a child but all its parent have it as NOT
10012 * VALID.
10013 *
10014 * Any of these constraints might have the NO INHERIT bit. If so we set
10015 * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
10016 *
10017 * In case 4 above, the name comparison is a bit of a hack; it actually fails
10018 * to do the right thing in all but the trivial case. However, the downside
10019 * of getting it wrong is simply that the name is printed rather than
10020 * suppressed, so it's not a big deal.
10021 *
10022 * invalidnotnulloids is expected to be given as NULL; if any invalid not-null
10023 * constraints are found, it is initialized and filled with the array of
10024 * OIDs of such constraints, for later processing.
10025 */
10026static void
10028 TableInfo *tbinfo, int j,
10029 int i_notnull_name,
10035{
10036 DumpOptions *dopt = fout->dopt;
10037
10038 /*
10039 * If this not-null constraint is not valid, list its OID in
10040 * invalidnotnulloids and do nothing further. It'll be processed
10041 * elsewhere later.
10042 *
10043 * Because invalid not-null constraints are rare, we don't want to malloc
10044 * invalidnotnulloids until we're sure we're going it need it, which
10045 * happens here.
10046 */
10047 if (!PQgetisnull(res, r, i_notnull_invalidoid))
10048 {
10049 char *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
10050
10051 if (*invalidnotnulloids == NULL)
10052 {
10056 }
10057 else
10059
10060 /*
10061 * Track when a parent constraint is invalid for the cases where a
10062 * child constraint has been validated independenly.
10063 */
10064 tbinfo->notnull_invalid[j] = true;
10065
10066 /* nothing else to do */
10067 tbinfo->notnull_constrs[j] = NULL;
10068 return;
10069 }
10070
10071 /*
10072 * notnull_noinh is straight from the query result. notnull_islocal also,
10073 * though flagInhAttrs may change that one later.
10074 */
10075 tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
10076 tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
10077 tbinfo->notnull_invalid[j] = false;
10078
10079 /*
10080 * Determine a constraint name to use. If the column is not marked not-
10081 * null, we set NULL which cues ... to do nothing. An empty string says
10082 * to print an unnamed NOT NULL, and anything else is a constraint name to
10083 * use.
10084 */
10085 if (fout->remoteVersion < 180000)
10086 {
10087 /*
10088 * < 18 doesn't have not-null names, so an unnamed constraint is
10089 * sufficient.
10090 */
10091 if (PQgetisnull(res, r, i_notnull_name))
10092 tbinfo->notnull_constrs[j] = NULL;
10093 else
10094 tbinfo->notnull_constrs[j] = "";
10095 }
10096 else
10097 {
10098 if (PQgetisnull(res, r, i_notnull_name))
10099 tbinfo->notnull_constrs[j] = NULL;
10100 else
10101 {
10102 /*
10103 * In binary upgrade of inheritance child tables, must have a
10104 * constraint name that we can UPDATE later; same if there's a
10105 * comment on the constraint.
10106 */
10107 if ((dopt->binary_upgrade &&
10108 !tbinfo->ispartition &&
10109 !tbinfo->notnull_islocal) ||
10111 {
10112 tbinfo->notnull_constrs[j] =
10114 }
10115 else
10116 {
10117 char *default_name;
10118
10119 /* XXX should match ChooseConstraintName better */
10120 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
10121 tbinfo->attnames[j]);
10122 if (strcmp(default_name,
10123 PQgetvalue(res, r, i_notnull_name)) == 0)
10124 tbinfo->notnull_constrs[j] = "";
10125 else
10126 {
10127 tbinfo->notnull_constrs[j] =
10129 }
10131 }
10132 }
10133 }
10134}
10135
10136/*
10137 * Test whether a column should be printed as part of table's CREATE TABLE.
10138 * Column number is zero-based.
10139 *
10140 * Normally this is always true, but it's false for dropped columns, as well
10141 * as those that were inherited without any local definition. (If we print
10142 * such a column it will mistakenly get pg_attribute.attislocal set to true.)
10143 * For partitions, it's always true, because we want the partitions to be
10144 * created independently and ATTACH PARTITION used afterwards.
10145 *
10146 * In binary_upgrade mode, we must print all columns and fix the attislocal/
10147 * attisdropped state later, so as to keep control of the physical column
10148 * order.
10149 *
10150 * This function exists because there are scattered nonobvious places that
10151 * must be kept in sync with this decision.
10152 */
10153bool
10154shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
10155{
10156 if (dopt->binary_upgrade)
10157 return true;
10158 if (tbinfo->attisdropped[colno])
10159 return false;
10160 return (tbinfo->attislocal[colno] || tbinfo->ispartition);
10161}
10162
10163
10164/*
10165 * getTSParsers:
10166 * get information about all text search parsers in the system catalogs
10167 */
10168void
10170{
10171 PGresult *res;
10172 int ntups;
10173 int i;
10174 PQExpBuffer query;
10176 int i_tableoid;
10177 int i_oid;
10178 int i_prsname;
10179 int i_prsnamespace;
10180 int i_prsstart;
10181 int i_prstoken;
10182 int i_prsend;
10183 int i_prsheadline;
10184 int i_prslextype;
10185
10186 query = createPQExpBuffer();
10187
10188 /*
10189 * find all text search objects, including builtin ones; we filter out
10190 * system-defined objects at dump-out time.
10191 */
10192
10193 appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
10194 "prsstart::oid, prstoken::oid, "
10195 "prsend::oid, prsheadline::oid, prslextype::oid "
10196 "FROM pg_ts_parser");
10197
10198 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10199
10200 ntups = PQntuples(res);
10201
10202 prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
10203
10204 i_tableoid = PQfnumber(res, "tableoid");
10205 i_oid = PQfnumber(res, "oid");
10206 i_prsname = PQfnumber(res, "prsname");
10207 i_prsnamespace = PQfnumber(res, "prsnamespace");
10208 i_prsstart = PQfnumber(res, "prsstart");
10209 i_prstoken = PQfnumber(res, "prstoken");
10210 i_prsend = PQfnumber(res, "prsend");
10211 i_prsheadline = PQfnumber(res, "prsheadline");
10212 i_prslextype = PQfnumber(res, "prslextype");
10213
10214 for (i = 0; i < ntups; i++)
10215 {
10216 prsinfo[i].dobj.objType = DO_TSPARSER;
10217 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10218 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10219 AssignDumpId(&prsinfo[i].dobj);
10220 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
10221 prsinfo[i].dobj.namespace =
10223 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
10224 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
10225 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
10226 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
10227 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
10228
10229 /* Decide whether we want to dump it */
10231 }
10232
10233 PQclear(res);
10234
10235 destroyPQExpBuffer(query);
10236}
10237
10238/*
10239 * getTSDictionaries:
10240 * get information about all text search dictionaries in the system catalogs
10241 */
10242void
10244{
10245 PGresult *res;
10246 int ntups;
10247 int i;
10248 PQExpBuffer query;
10250 int i_tableoid;
10251 int i_oid;
10252 int i_dictname;
10253 int i_dictnamespace;
10254 int i_dictowner;
10255 int i_dicttemplate;
10256 int i_dictinitoption;
10257
10258 query = createPQExpBuffer();
10259
10260 appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
10261 "dictnamespace, dictowner, "
10262 "dicttemplate, dictinitoption "
10263 "FROM pg_ts_dict");
10264
10265 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10266
10267 ntups = PQntuples(res);
10268
10269 dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
10270
10271 i_tableoid = PQfnumber(res, "tableoid");
10272 i_oid = PQfnumber(res, "oid");
10273 i_dictname = PQfnumber(res, "dictname");
10274 i_dictnamespace = PQfnumber(res, "dictnamespace");
10275 i_dictowner = PQfnumber(res, "dictowner");
10276 i_dictinitoption = PQfnumber(res, "dictinitoption");
10277 i_dicttemplate = PQfnumber(res, "dicttemplate");
10278
10279 for (i = 0; i < ntups; i++)
10280 {
10281 dictinfo[i].dobj.objType = DO_TSDICT;
10282 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10283 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10284 AssignDumpId(&dictinfo[i].dobj);
10285 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
10286 dictinfo[i].dobj.namespace =
10288 dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
10289 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
10290 if (PQgetisnull(res, i, i_dictinitoption))
10291 dictinfo[i].dictinitoption = NULL;
10292 else
10293 dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
10294
10295 /* Decide whether we want to dump it */
10297 }
10298
10299 PQclear(res);
10300
10301 destroyPQExpBuffer(query);
10302}
10303
10304/*
10305 * getTSTemplates:
10306 * get information about all text search templates in the system catalogs
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_tmplname;
10319 int i_tmplnamespace;
10320 int i_tmplinit;
10321 int i_tmpllexize;
10322
10323 query = createPQExpBuffer();
10324
10325 appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
10326 "tmplnamespace, tmplinit::oid, tmpllexize::oid "
10327 "FROM pg_ts_template");
10328
10329 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10330
10331 ntups = PQntuples(res);
10332
10333 tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
10334
10335 i_tableoid = PQfnumber(res, "tableoid");
10336 i_oid = PQfnumber(res, "oid");
10337 i_tmplname = PQfnumber(res, "tmplname");
10338 i_tmplnamespace = PQfnumber(res, "tmplnamespace");
10339 i_tmplinit = PQfnumber(res, "tmplinit");
10340 i_tmpllexize = PQfnumber(res, "tmpllexize");
10341
10342 for (i = 0; i < ntups; i++)
10343 {
10344 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
10345 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10346 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10347 AssignDumpId(&tmplinfo[i].dobj);
10348 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
10349 tmplinfo[i].dobj.namespace =
10351 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
10352 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
10353
10354 /* Decide whether we want to dump it */
10356 }
10357
10358 PQclear(res);
10359
10360 destroyPQExpBuffer(query);
10361}
10362
10363/*
10364 * getTSConfigurations:
10365 * get information about all text search configurations
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_cfgname;
10378 int i_cfgnamespace;
10379 int i_cfgowner;
10380 int i_cfgparser;
10381
10382 query = createPQExpBuffer();
10383
10384 appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
10385 "cfgnamespace, cfgowner, cfgparser "
10386 "FROM pg_ts_config");
10387
10388 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10389
10390 ntups = PQntuples(res);
10391
10392 cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
10393
10394 i_tableoid = PQfnumber(res, "tableoid");
10395 i_oid = PQfnumber(res, "oid");
10396 i_cfgname = PQfnumber(res, "cfgname");
10397 i_cfgnamespace = PQfnumber(res, "cfgnamespace");
10398 i_cfgowner = PQfnumber(res, "cfgowner");
10399 i_cfgparser = PQfnumber(res, "cfgparser");
10400
10401 for (i = 0; i < ntups; i++)
10402 {
10403 cfginfo[i].dobj.objType = DO_TSCONFIG;
10404 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10405 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10406 AssignDumpId(&cfginfo[i].dobj);
10407 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
10408 cfginfo[i].dobj.namespace =
10410 cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
10411 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
10412
10413 /* Decide whether we want to dump it */
10415 }
10416
10417 PQclear(res);
10418
10419 destroyPQExpBuffer(query);
10420}
10421
10422/*
10423 * getForeignDataWrappers:
10424 * get information about all foreign-data wrappers in the system catalogs
10425 */
10426void
10428{
10429 PGresult *res;
10430 int ntups;
10431 int i;
10432 PQExpBuffer query;
10434 int i_tableoid;
10435 int i_oid;
10436 int i_fdwname;
10437 int i_fdwowner;
10438 int i_fdwhandler;
10439 int i_fdwvalidator;
10440 int i_fdwacl;
10441 int i_acldefault;
10442 int i_fdwoptions;
10443
10444 query = createPQExpBuffer();
10445
10446 appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
10447 "fdwowner, "
10448 "fdwhandler::pg_catalog.regproc, "
10449 "fdwvalidator::pg_catalog.regproc, "
10450 "fdwacl, "
10451 "acldefault('F', fdwowner) AS acldefault, "
10452 "array_to_string(ARRAY("
10453 "SELECT quote_ident(option_name) || ' ' || "
10454 "quote_literal(option_value) "
10455 "FROM pg_options_to_table(fdwoptions) "
10456 "ORDER BY option_name"
10457 "), E',\n ') AS fdwoptions "
10458 "FROM pg_foreign_data_wrapper");
10459
10460 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10461
10462 ntups = PQntuples(res);
10463
10464 fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
10465
10466 i_tableoid = PQfnumber(res, "tableoid");
10467 i_oid = PQfnumber(res, "oid");
10468 i_fdwname = PQfnumber(res, "fdwname");
10469 i_fdwowner = PQfnumber(res, "fdwowner");
10470 i_fdwhandler = PQfnumber(res, "fdwhandler");
10471 i_fdwvalidator = PQfnumber(res, "fdwvalidator");
10472 i_fdwacl = PQfnumber(res, "fdwacl");
10473 i_acldefault = PQfnumber(res, "acldefault");
10474 i_fdwoptions = PQfnumber(res, "fdwoptions");
10475
10476 for (i = 0; i < ntups; i++)
10477 {
10478 fdwinfo[i].dobj.objType = DO_FDW;
10479 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10480 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10481 AssignDumpId(&fdwinfo[i].dobj);
10482 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
10483 fdwinfo[i].dobj.namespace = NULL;
10484 fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
10485 fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10486 fdwinfo[i].dacl.privtype = 0;
10487 fdwinfo[i].dacl.initprivs = NULL;
10488 fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
10489 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
10490 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
10491 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
10492
10493 /* Decide whether we want to dump it */
10495
10496 /* Mark whether FDW has an ACL */
10497 if (!PQgetisnull(res, i, i_fdwacl))
10498 fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10499 }
10500
10501 PQclear(res);
10502
10503 destroyPQExpBuffer(query);
10504}
10505
10506/*
10507 * getForeignServers:
10508 * get information about all foreign servers in the system catalogs
10509 */
10510void
10512{
10513 PGresult *res;
10514 int ntups;
10515 int i;
10516 PQExpBuffer query;
10518 int i_tableoid;
10519 int i_oid;
10520 int i_srvname;
10521 int i_srvowner;
10522 int i_srvfdw;
10523 int i_srvtype;
10524 int i_srvversion;
10525 int i_srvacl;
10526 int i_acldefault;
10527 int i_srvoptions;
10528
10529 query = createPQExpBuffer();
10530
10531 appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
10532 "srvowner, "
10533 "srvfdw, srvtype, srvversion, srvacl, "
10534 "acldefault('S', srvowner) AS acldefault, "
10535 "array_to_string(ARRAY("
10536 "SELECT quote_ident(option_name) || ' ' || "
10537 "quote_literal(option_value) "
10538 "FROM pg_options_to_table(srvoptions) "
10539 "ORDER BY option_name"
10540 "), E',\n ') AS srvoptions "
10541 "FROM pg_foreign_server");
10542
10543 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10544
10545 ntups = PQntuples(res);
10546
10548
10549 i_tableoid = PQfnumber(res, "tableoid");
10550 i_oid = PQfnumber(res, "oid");
10551 i_srvname = PQfnumber(res, "srvname");
10552 i_srvowner = PQfnumber(res, "srvowner");
10553 i_srvfdw = PQfnumber(res, "srvfdw");
10554 i_srvtype = PQfnumber(res, "srvtype");
10555 i_srvversion = PQfnumber(res, "srvversion");
10556 i_srvacl = PQfnumber(res, "srvacl");
10557 i_acldefault = PQfnumber(res, "acldefault");
10558 i_srvoptions = PQfnumber(res, "srvoptions");
10559
10560 for (i = 0; i < ntups; i++)
10561 {
10562 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
10563 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10564 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10565 AssignDumpId(&srvinfo[i].dobj);
10566 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
10567 srvinfo[i].dobj.namespace = NULL;
10568 srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
10569 srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10570 srvinfo[i].dacl.privtype = 0;
10571 srvinfo[i].dacl.initprivs = NULL;
10572 srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
10573 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
10574 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
10575 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
10576 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
10577
10578 /* Decide whether we want to dump it */
10580
10581 /* Servers have user mappings */
10582 srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
10583
10584 /* Mark whether server has an ACL */
10585 if (!PQgetisnull(res, i, i_srvacl))
10586 srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10587 }
10588
10589 PQclear(res);
10590
10591 destroyPQExpBuffer(query);
10592}
10593
10594/*
10595 * getDefaultACLs:
10596 * get information about all default ACL information in the system catalogs
10597 */
10598void
10600{
10601 DumpOptions *dopt = fout->dopt;
10603 PQExpBuffer query;
10604 PGresult *res;
10605 int i_oid;
10606 int i_tableoid;
10607 int i_defaclrole;
10609 int i_defaclobjtype;
10610 int i_defaclacl;
10611 int i_acldefault;
10612 int i,
10613 ntups;
10614
10615 query = createPQExpBuffer();
10616
10617 /*
10618 * Global entries (with defaclnamespace=0) replace the hard-wired default
10619 * ACL for their object type. We should dump them as deltas from the
10620 * default ACL, since that will be used as a starting point for
10621 * interpreting the ALTER DEFAULT PRIVILEGES commands. On the other hand,
10622 * non-global entries can only add privileges not revoke them. We must
10623 * dump those as-is (i.e., as deltas from an empty ACL).
10624 *
10625 * We can use defaclobjtype as the object type for acldefault(), except
10626 * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
10627 * 's'.
10628 */
10630 "SELECT oid, tableoid, "
10631 "defaclrole, "
10632 "defaclnamespace, "
10633 "defaclobjtype, "
10634 "defaclacl, "
10635 "CASE WHEN defaclnamespace = 0 THEN "
10636 "acldefault(CASE WHEN defaclobjtype = 'S' "
10637 "THEN 's'::\"char\" ELSE defaclobjtype END, "
10638 "defaclrole) ELSE '{}' END AS acldefault "
10639 "FROM pg_default_acl");
10640
10641 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10642
10643 ntups = PQntuples(res);
10644
10645 daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
10646
10647 i_oid = PQfnumber(res, "oid");
10648 i_tableoid = PQfnumber(res, "tableoid");
10649 i_defaclrole = PQfnumber(res, "defaclrole");
10650 i_defaclnamespace = PQfnumber(res, "defaclnamespace");
10651 i_defaclobjtype = PQfnumber(res, "defaclobjtype");
10652 i_defaclacl = PQfnumber(res, "defaclacl");
10653 i_acldefault = PQfnumber(res, "acldefault");
10654
10655 for (i = 0; i < ntups; i++)
10656 {
10658
10659 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
10660 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10661 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10662 AssignDumpId(&daclinfo[i].dobj);
10663 /* cheesy ... is it worth coming up with a better object name? */
10664 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
10665
10666 if (nspid != InvalidOid)
10667 daclinfo[i].dobj.namespace = findNamespace(nspid);
10668 else
10669 daclinfo[i].dobj.namespace = NULL;
10670
10671 daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
10672 daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10673 daclinfo[i].dacl.privtype = 0;
10674 daclinfo[i].dacl.initprivs = NULL;
10675 daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
10676 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
10677
10678 /* Default ACLs are ACLs, of course */
10679 daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10680
10681 /* Decide whether we want to dump it */
10683 }
10684
10685 PQclear(res);
10686
10687 destroyPQExpBuffer(query);
10688}
10689
10690/*
10691 * getRoleName -- look up the name of a role, given its OID
10692 *
10693 * In current usage, we don't expect failures, so error out for a bad OID.
10694 */
10695static const char *
10696getRoleName(const char *roleoid_str)
10697{
10698 Oid roleoid = atooid(roleoid_str);
10699
10700 /*
10701 * Do binary search to find the appropriate item.
10702 */
10703 if (nrolenames > 0)
10704 {
10705 RoleNameItem *low = &rolenames[0];
10706 RoleNameItem *high = &rolenames[nrolenames - 1];
10707
10708 while (low <= high)
10709 {
10710 RoleNameItem *middle = low + (high - low) / 2;
10711
10712 if (roleoid < middle->roleoid)
10713 high = middle - 1;
10714 else if (roleoid > middle->roleoid)
10715 low = middle + 1;
10716 else
10717 return middle->rolename; /* found a match */
10718 }
10719 }
10720
10721 pg_fatal("role with OID %u does not exist", roleoid);
10722 return NULL; /* keep compiler quiet */
10723}
10724
10725/*
10726 * collectRoleNames --
10727 *
10728 * Construct a table of all known roles.
10729 * The table is sorted by OID for speed in lookup.
10730 */
10731static void
10733{
10734 PGresult *res;
10735 const char *query;
10736 int i;
10737
10738 query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
10739
10740 res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
10741
10742 nrolenames = PQntuples(res);
10743
10745
10746 for (i = 0; i < nrolenames; i++)
10747 {
10748 rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
10750 }
10751
10752 PQclear(res);
10753}
10754
10755/*
10756 * getAdditionalACLs
10757 *
10758 * We have now created all the DumpableObjects, and collected the ACL data
10759 * that appears in the directly-associated catalog entries. However, there's
10760 * more ACL-related info to collect. If any of a table's columns have ACLs,
10761 * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
10762 * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
10763 * Also, in versions having the pg_init_privs catalog, read that and load the
10764 * information into the relevant DumpableObjects.
10765 */
10766static void
10768{
10770 PGresult *res;
10771 int ntups,
10772 i;
10773
10774 /* Check for per-column ACLs */
10776 "SELECT DISTINCT attrelid FROM pg_attribute "
10777 "WHERE attacl IS NOT NULL");
10778
10779 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10780
10781 ntups = PQntuples(res);
10782 for (i = 0; i < ntups; i++)
10783 {
10784 Oid relid = atooid(PQgetvalue(res, i, 0));
10785 TableInfo *tblinfo;
10786
10787 tblinfo = findTableByOid(relid);
10788 /* OK to ignore tables we haven't got a DumpableObject for */
10789 if (tblinfo)
10790 {
10792 tblinfo->hascolumnACLs = true;
10793 }
10794 }
10795 PQclear(res);
10796
10797 /* Fetch initial-privileges data */
10798 if (fout->remoteVersion >= 90600)
10799 {
10800 printfPQExpBuffer(query,
10801 "SELECT objoid, classoid, objsubid, privtype, initprivs "
10802 "FROM pg_init_privs");
10803
10804 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10805
10806 ntups = PQntuples(res);
10807 for (i = 0; i < ntups; i++)
10808 {
10809 Oid objoid = atooid(PQgetvalue(res, i, 0));
10810 Oid classoid = atooid(PQgetvalue(res, i, 1));
10811 int objsubid = atoi(PQgetvalue(res, i, 2));
10812 char privtype = *(PQgetvalue(res, i, 3));
10813 char *initprivs = PQgetvalue(res, i, 4);
10814 CatalogId objId;
10815 DumpableObject *dobj;
10816
10817 objId.tableoid = classoid;
10818 objId.oid = objoid;
10819 dobj = findObjectByCatalogId(objId);
10820 /* OK to ignore entries we haven't got a DumpableObject for */
10821 if (dobj)
10822 {
10823 /* Cope with sub-object initprivs */
10824 if (objsubid != 0)
10825 {
10826 if (dobj->objType == DO_TABLE)
10827 {
10828 /* For a column initprivs, set the table's ACL flags */
10830 ((TableInfo *) dobj)->hascolumnACLs = true;
10831 }
10832 else
10833 pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10834 classoid, objoid, objsubid);
10835 continue;
10836 }
10837
10838 /*
10839 * We ignore any pg_init_privs.initprivs entry for the public
10840 * schema, as explained in getNamespaces().
10841 */
10842 if (dobj->objType == DO_NAMESPACE &&
10843 strcmp(dobj->name, "public") == 0)
10844 continue;
10845
10846 /* Else it had better be of a type we think has ACLs */
10847 if (dobj->objType == DO_NAMESPACE ||
10848 dobj->objType == DO_TYPE ||
10849 dobj->objType == DO_FUNC ||
10850 dobj->objType == DO_AGG ||
10851 dobj->objType == DO_TABLE ||
10852 dobj->objType == DO_PROCLANG ||
10853 dobj->objType == DO_FDW ||
10854 dobj->objType == DO_FOREIGN_SERVER)
10855 {
10857
10858 daobj->dacl.privtype = privtype;
10859 daobj->dacl.initprivs = pstrdup(initprivs);
10860 }
10861 else
10862 pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10863 classoid, objoid, objsubid);
10864 }
10865 }
10866 PQclear(res);
10867 }
10868
10869 destroyPQExpBuffer(query);
10870}
10871
10872/*
10873 * dumpCommentExtended --
10874 *
10875 * This routine is used to dump any comments associated with the
10876 * object handed to this routine. The routine takes the object type
10877 * and object name (ready to print, except for schema decoration), plus
10878 * the namespace and owner of the object (for labeling the ArchiveEntry),
10879 * plus catalog ID and subid which are the lookup key for pg_description,
10880 * plus the dump ID for the object (for setting a dependency).
10881 * If a matching pg_description entry is found, it is dumped.
10882 *
10883 * Note: in some cases, such as comments for triggers and rules, the "type"
10884 * string really looks like, e.g., "TRIGGER name ON". This is a bit of a hack
10885 * but it doesn't seem worth complicating the API for all callers to make
10886 * it cleaner.
10887 *
10888 * Note: although this routine takes a dumpId for dependency purposes,
10889 * that purpose is just to mark the dependency in the emitted dump file
10890 * for possible future use by pg_restore. We do NOT use it for determining
10891 * ordering of the comment in the dump file, because this routine is called
10892 * after dependency sorting occurs. This routine should be called just after
10893 * calling ArchiveEntry() for the specified object.
10894 */
10895static void
10896dumpCommentExtended(Archive *fout, const char *type,
10897 const char *name, const char *namespace,
10898 const char *owner, CatalogId catalogId,
10899 int subid, DumpId dumpId,
10900 const char *initdb_comment)
10901{
10902 DumpOptions *dopt = fout->dopt;
10904 int ncomments;
10905
10906 /* do nothing, if --no-comments is supplied */
10907 if (dopt->no_comments)
10908 return;
10909
10910 /* Comments are schema not data ... except LO comments are data */
10911 if (strcmp(type, "LARGE OBJECT") != 0)
10912 {
10913 if (!dopt->dumpSchema)
10914 return;
10915 }
10916 else
10917 {
10918 /* We do dump LO comments in binary-upgrade mode */
10919 if (!dopt->dumpData && !dopt->binary_upgrade)
10920 return;
10921 }
10922
10923 /* Search for comments associated with catalogId, using table */
10924 ncomments = findComments(catalogId.tableoid, catalogId.oid,
10925 &comments);
10926
10927 /* Is there one matching the subid? */
10928 while (ncomments > 0)
10929 {
10930 if (comments->objsubid == subid)
10931 break;
10932 comments++;
10933 ncomments--;
10934 }
10935
10936 if (initdb_comment != NULL)
10937 {
10938 static CommentItem empty_comment = {.descr = ""};
10939
10940 /*
10941 * initdb creates this object with a comment. Skip dumping the
10942 * initdb-provided comment, which would complicate matters for
10943 * non-superuser use of pg_dump. When the DBA has removed initdb's
10944 * comment, replicate that.
10945 */
10946 if (ncomments == 0)
10947 {
10949 ncomments = 1;
10950 }
10951 else if (strcmp(comments->descr, initdb_comment) == 0)
10952 ncomments = 0;
10953 }
10954
10955 /* If a comment exists, build COMMENT ON statement */
10956 if (ncomments > 0)
10957 {
10960
10961 appendPQExpBuffer(query, "COMMENT ON %s ", type);
10962 if (namespace && *namespace)
10963 appendPQExpBuffer(query, "%s.", fmtId(namespace));
10964 appendPQExpBuffer(query, "%s IS ", name);
10966 appendPQExpBufferStr(query, ";\n");
10967
10968 appendPQExpBuffer(tag, "%s %s", type, name);
10969
10970 /*
10971 * We mark comments as SECTION_NONE because they really belong in the
10972 * same section as their parent, whether that is pre-data or
10973 * post-data.
10974 */
10976 ARCHIVE_OPTS(.tag = tag->data,
10977 .namespace = namespace,
10978 .owner = owner,
10979 .description = "COMMENT",
10980 .section = SECTION_NONE,
10981 .createStmt = query->data,
10982 .deps = &dumpId,
10983 .nDeps = 1));
10984
10985 destroyPQExpBuffer(query);
10986 destroyPQExpBuffer(tag);
10987 }
10988}
10989
10990/*
10991 * dumpComment --
10992 *
10993 * Typical simplification of the above function.
10994 */
10995static inline void
10996dumpComment(Archive *fout, const char *type,
10997 const char *name, const char *namespace,
10998 const char *owner, CatalogId catalogId,
10999 int subid, DumpId dumpId)
11000{
11001 dumpCommentExtended(fout, type, name, namespace, owner,
11002 catalogId, subid, dumpId, NULL);
11003}
11004
11005/*
11006 * appendNamedArgument --
11007 *
11008 * Convenience routine for constructing parameters of the form:
11009 * 'paraname', 'value'::type
11010 */
11011static void
11012appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
11013 const char *argtype, const char *argval)
11014{
11015 appendPQExpBufferStr(out, ",\n\t");
11016
11017 appendStringLiteralAH(out, argname, fout);
11018 appendPQExpBufferStr(out, ", ");
11019
11021 appendPQExpBuffer(out, "::%s", argtype);
11022}
11023
11024/*
11025 * fetchAttributeStats --
11026 *
11027 * Fetch next batch of attribute statistics for dumpRelationStats_dumper().
11028 */
11029static PGresult *
11031{
11035 int count = 0;
11036 PGresult *res = NULL;
11037 static TocEntry *te;
11038 static bool restarted;
11040
11041 /*
11042 * Our query for retrieving statistics for multiple relations uses WITH
11043 * ORDINALITY and multi-argument UNNEST(), both of which were introduced
11044 * in v9.4. For older versions, we resort to gathering statistics for a
11045 * single relation at a time.
11046 */
11047 if (fout->remoteVersion < 90400)
11048 max_rels = 1;
11049
11050 /* If we're just starting, set our TOC pointer. */
11051 if (!te)
11052 te = AH->toc->next;
11053
11054 /*
11055 * We can't easily avoid a second TOC scan for the tar format because it
11056 * writes restore.sql separately, which means we must execute the queries
11057 * twice. This feels risky, but there is no known reason it should
11058 * generate different output than the first pass. Even if it does, the
11059 * worst-case scenario is that restore.sql might have different statistics
11060 * data than the archive.
11061 */
11062 if (!restarted && te == AH->toc && AH->format == archTar)
11063 {
11064 te = AH->toc->next;
11065 restarted = true;
11066 }
11067
11070
11071 /*
11072 * Scan the TOC for the next set of relevant stats entries. We assume
11073 * that statistics are dumped in the order they are listed in the TOC.
11074 * This is perhaps not the sturdiest assumption, so we verify it matches
11075 * reality in dumpRelationStats_dumper().
11076 */
11077 for (; te != AH->toc && count < max_rels; te = te->next)
11078 {
11079 if ((te->reqs & REQ_STATS) != 0 &&
11080 strcmp(te->desc, "STATISTICS DATA") == 0)
11081 {
11082 appendPGArray(nspnames, te->namespace);
11084 count++;
11085 }
11086 }
11087
11090
11091 /* Execute the query for the next batch of relations. */
11092 if (count > 0)
11093 {
11095
11096 appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
11097 appendStringLiteralAH(query, nspnames->data, fout);
11098 appendPQExpBufferStr(query, "::pg_catalog.name[],");
11099 appendStringLiteralAH(query, relnames->data, fout);
11100 appendPQExpBufferStr(query, "::pg_catalog.name[])");
11101 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11102 destroyPQExpBuffer(query);
11103 }
11104
11107 return res;
11108}
11109
11110/*
11111 * dumpRelationStats_dumper --
11112 *
11113 * Generate command to import stats into the relation on the new database.
11114 * This routine is called by the Archiver when it wants the statistics to be
11115 * dumped.
11116 */
11117static char *
11118dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
11119{
11120 const RelStatsInfo *rsinfo = userArg;
11121 static PGresult *res;
11122 static int rownum;
11123 PQExpBuffer query;
11125 PQExpBuffer out = &out_data;
11126 int i_schemaname;
11127 int i_tablename;
11128 int i_attname;
11129 int i_inherited;
11130 int i_null_frac;
11131 int i_avg_width;
11132 int i_n_distinct;
11136 int i_correlation;
11143 static TocEntry *expected_te;
11144
11145 /*
11146 * fetchAttributeStats() assumes that the statistics are dumped in the
11147 * order they are listed in the TOC. We verify that here for safety.
11148 */
11149 if (!expected_te)
11150 expected_te = ((ArchiveHandle *) fout)->toc;
11151
11153 while ((expected_te->reqs & REQ_STATS) == 0 ||
11154 strcmp(expected_te->desc, "STATISTICS DATA") != 0)
11156
11157 if (te != expected_te)
11158 pg_fatal("statistics dumped out of order (current: %d %s %s, expected: %d %s %s)",
11159 te->dumpId, te->desc, te->tag,
11160 expected_te->dumpId, expected_te->desc, expected_te->tag);
11161
11162 query = createPQExpBuffer();
11163 if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
11164 {
11166 "PREPARE getAttributeStats(pg_catalog.name[], pg_catalog.name[]) AS\n"
11167 "SELECT s.schemaname, s.tablename, s.attname, s.inherited, "
11168 "s.null_frac, s.avg_width, s.n_distinct, "
11169 "s.most_common_vals, s.most_common_freqs, "
11170 "s.histogram_bounds, s.correlation, "
11171 "s.most_common_elems, s.most_common_elem_freqs, "
11172 "s.elem_count_histogram, ");
11173
11174 if (fout->remoteVersion >= 170000)
11176 "s.range_length_histogram, "
11177 "s.range_empty_frac, "
11178 "s.range_bounds_histogram ");
11179 else
11181 "NULL AS range_length_histogram,"
11182 "NULL AS range_empty_frac,"
11183 "NULL AS range_bounds_histogram ");
11184
11185 /*
11186 * The results must be in the order of the relations supplied in the
11187 * parameters to ensure we remain in sync as we walk through the TOC.
11188 * The redundant filter clause on s.tablename = ANY(...) seems
11189 * sufficient to convince the planner to use
11190 * pg_class_relname_nsp_index, which avoids a full scan of pg_stats.
11191 * This may not work for all versions.
11192 *
11193 * Our query for retrieving statistics for multiple relations uses
11194 * WITH ORDINALITY and multi-argument UNNEST(), both of which were
11195 * introduced in v9.4. For older versions, we resort to gathering
11196 * statistics for a single relation at a time.
11197 */
11198 if (fout->remoteVersion >= 90400)
11200 "FROM pg_catalog.pg_stats s "
11201 "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) "
11202 "ON s.schemaname = u.schemaname "
11203 "AND s.tablename = u.tablename "
11204 "WHERE s.tablename = ANY($2) "
11205 "ORDER BY u.ord, s.attname, s.inherited");
11206 else
11208 "FROM pg_catalog.pg_stats s "
11209 "WHERE s.schemaname = $1[1] "
11210 "AND s.tablename = $2[1] "
11211 "ORDER BY s.attname, s.inherited");
11212
11213 ExecuteSqlStatement(fout, query->data);
11214
11215 fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
11216 resetPQExpBuffer(query);
11217 }
11218
11219 initPQExpBuffer(out);
11220
11221 /* restore relation stats */
11222 appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
11223 appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
11224 fout->remoteVersion);
11225 appendPQExpBufferStr(out, "\t'schemaname', ");
11226 appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
11227 appendPQExpBufferStr(out, ",\n");
11228 appendPQExpBufferStr(out, "\t'relname', ");
11229 appendStringLiteralAH(out, rsinfo->dobj.name, fout);
11230 appendPQExpBufferStr(out, ",\n");
11231 appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
11232
11233 /*
11234 * Before v14, a reltuples value of 0 was ambiguous: it could either mean
11235 * the relation is empty, or it could mean that it hadn't yet been
11236 * vacuumed or analyzed. (Newer versions use -1 for the latter case.)
11237 * This ambiguity allegedly can cause the planner to choose inefficient
11238 * plans after restoring to v18 or newer. To deal with this, let's just
11239 * set reltuples to -1 in that case.
11240 */
11241 if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
11242 appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
11243 else
11244 appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
11245
11246 appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
11247 rsinfo->relallvisible);
11248
11249 if (fout->remoteVersion >= 180000)
11250 appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
11251
11252 appendPQExpBufferStr(out, "\n);\n");
11253
11254 /* Fetch the next batch of attribute statistics if needed. */
11255 if (rownum >= PQntuples(res))
11256 {
11257 PQclear(res);
11259 rownum = 0;
11260 }
11261
11262 i_schemaname = PQfnumber(res, "schemaname");
11263 i_tablename = PQfnumber(res, "tablename");
11264 i_attname = PQfnumber(res, "attname");
11265 i_inherited = PQfnumber(res, "inherited");
11266 i_null_frac = PQfnumber(res, "null_frac");
11267 i_avg_width = PQfnumber(res, "avg_width");
11268 i_n_distinct = PQfnumber(res, "n_distinct");
11269 i_most_common_vals = PQfnumber(res, "most_common_vals");
11270 i_most_common_freqs = PQfnumber(res, "most_common_freqs");
11271 i_histogram_bounds = PQfnumber(res, "histogram_bounds");
11272 i_correlation = PQfnumber(res, "correlation");
11273 i_most_common_elems = PQfnumber(res, "most_common_elems");
11274 i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
11275 i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
11276 i_range_length_histogram = PQfnumber(res, "range_length_histogram");
11277 i_range_empty_frac = PQfnumber(res, "range_empty_frac");
11278 i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
11279
11280 /* restore attribute stats */
11281 for (; rownum < PQntuples(res); rownum++)
11282 {
11283 const char *attname;
11284
11285 /* Stop if the next stat row in our cache isn't for this relation. */
11286 if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
11287 strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
11288 break;
11289
11290 appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
11291 appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
11292 fout->remoteVersion);
11293 appendPQExpBufferStr(out, "\t'schemaname', ");
11294 appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
11295 appendPQExpBufferStr(out, ",\n\t'relname', ");
11296 appendStringLiteralAH(out, rsinfo->dobj.name, fout);
11297
11298 if (PQgetisnull(res, rownum, i_attname))
11299 pg_fatal("unexpected null attname");
11300 attname = PQgetvalue(res, rownum, i_attname);
11301
11302 /*
11303 * Indexes look up attname in indAttNames to derive attnum, all others
11304 * use attname directly. We must specify attnum for indexes, since
11305 * their attnames are not necessarily stable across dump/reload.
11306 */
11307 if (rsinfo->nindAttNames == 0)
11308 {
11309 appendPQExpBufferStr(out, ",\n\t'attname', ");
11311 }
11312 else
11313 {
11314 bool found = false;
11315
11316 for (int i = 0; i < rsinfo->nindAttNames; i++)
11317 {
11318 if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
11319 {
11320 appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
11321 i + 1);
11322 found = true;
11323 break;
11324 }
11325 }
11326
11327 if (!found)
11328 pg_fatal("could not find index attname \"%s\"", attname);
11329 }
11330
11331 if (!PQgetisnull(res, rownum, i_inherited))
11332 appendNamedArgument(out, fout, "inherited", "boolean",
11333 PQgetvalue(res, rownum, i_inherited));
11334 if (!PQgetisnull(res, rownum, i_null_frac))
11335 appendNamedArgument(out, fout, "null_frac", "real",
11336 PQgetvalue(res, rownum, i_null_frac));
11337 if (!PQgetisnull(res, rownum, i_avg_width))
11338 appendNamedArgument(out, fout, "avg_width", "integer",
11339 PQgetvalue(res, rownum, i_avg_width));
11340 if (!PQgetisnull(res, rownum, i_n_distinct))
11341 appendNamedArgument(out, fout, "n_distinct", "real",
11342 PQgetvalue(res, rownum, i_n_distinct));
11343 if (!PQgetisnull(res, rownum, i_most_common_vals))
11344 appendNamedArgument(out, fout, "most_common_vals", "text",
11345 PQgetvalue(res, rownum, i_most_common_vals));
11346 if (!PQgetisnull(res, rownum, i_most_common_freqs))
11347 appendNamedArgument(out, fout, "most_common_freqs", "real[]",
11348 PQgetvalue(res, rownum, i_most_common_freqs));
11349 if (!PQgetisnull(res, rownum, i_histogram_bounds))
11350 appendNamedArgument(out, fout, "histogram_bounds", "text",
11351 PQgetvalue(res, rownum, i_histogram_bounds));
11352 if (!PQgetisnull(res, rownum, i_correlation))
11353 appendNamedArgument(out, fout, "correlation", "real",
11354 PQgetvalue(res, rownum, i_correlation));
11355 if (!PQgetisnull(res, rownum, i_most_common_elems))
11356 appendNamedArgument(out, fout, "most_common_elems", "text",
11357 PQgetvalue(res, rownum, i_most_common_elems));
11358 if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
11359 appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
11360 PQgetvalue(res, rownum, i_most_common_elem_freqs));
11361 if (!PQgetisnull(res, rownum, i_elem_count_histogram))
11362 appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
11363 PQgetvalue(res, rownum, i_elem_count_histogram));
11364 if (fout->remoteVersion >= 170000)
11365 {
11366 if (!PQgetisnull(res, rownum, i_range_length_histogram))
11367 appendNamedArgument(out, fout, "range_length_histogram", "text",
11368 PQgetvalue(res, rownum, i_range_length_histogram));
11369 if (!PQgetisnull(res, rownum, i_range_empty_frac))
11370 appendNamedArgument(out, fout, "range_empty_frac", "real",
11371 PQgetvalue(res, rownum, i_range_empty_frac));
11372 if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
11373 appendNamedArgument(out, fout, "range_bounds_histogram", "text",
11374 PQgetvalue(res, rownum, i_range_bounds_histogram));
11375 }
11376 appendPQExpBufferStr(out, "\n);\n");
11377 }
11378
11379 destroyPQExpBuffer(query);
11380 return out->data;
11381}
11382
11383/*
11384 * dumpRelationStats --
11385 *
11386 * Make an ArchiveEntry for the relation statistics. The Archiver will take
11387 * care of gathering the statistics and generating the restore commands when
11388 * they are needed.
11389 */
11390static void
11392{
11393 const DumpableObject *dobj = &rsinfo->dobj;
11394
11395 /* nothing to do if we are not dumping statistics */
11396 if (!fout->dopt->dumpStatistics)
11397 return;
11398
11400 ARCHIVE_OPTS(.tag = dobj->name,
11401 .namespace = dobj->namespace->dobj.name,
11402 .description = "STATISTICS DATA",
11403 .section = rsinfo->section,
11404 .defnFn = dumpRelationStats_dumper,
11405 .defnArg = rsinfo,
11406 .deps = dobj->dependencies,
11407 .nDeps = dobj->nDeps));
11408}
11409
11410/*
11411 * dumpTableComment --
11412 *
11413 * As above, but dump comments for both the specified table (or view)
11414 * and its columns.
11415 */
11416static void
11418 const char *reltypename)
11419{
11420 DumpOptions *dopt = fout->dopt;
11422 int ncomments;
11423 PQExpBuffer query;
11424 PQExpBuffer tag;
11425
11426 /* do nothing, if --no-comments is supplied */
11427 if (dopt->no_comments)
11428 return;
11429
11430 /* Comments are SCHEMA not data */
11431 if (!dopt->dumpSchema)
11432 return;
11433
11434 /* Search for comments associated with relation, using table */
11435 ncomments = findComments(tbinfo->dobj.catId.tableoid,
11436 tbinfo->dobj.catId.oid,
11437 &comments);
11438
11439 /* If comments exist, build COMMENT ON statements */
11440 if (ncomments <= 0)
11441 return;
11442
11443 query = createPQExpBuffer();
11444 tag = createPQExpBuffer();
11445
11446 while (ncomments > 0)
11447 {
11448 const char *descr = comments->descr;
11449 int objsubid = comments->objsubid;
11450
11451 if (objsubid == 0)
11452 {
11453 resetPQExpBuffer(tag);
11454 appendPQExpBuffer(tag, "%s %s", reltypename,
11455 fmtId(tbinfo->dobj.name));
11456
11457 resetPQExpBuffer(query);
11458 appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
11460 appendStringLiteralAH(query, descr, fout);
11461 appendPQExpBufferStr(query, ";\n");
11462
11464 ARCHIVE_OPTS(.tag = tag->data,
11465 .namespace = tbinfo->dobj.namespace->dobj.name,
11466 .owner = tbinfo->rolname,
11467 .description = "COMMENT",
11468 .section = SECTION_NONE,
11469 .createStmt = query->data,
11470 .deps = &(tbinfo->dobj.dumpId),
11471 .nDeps = 1));
11472 }
11473 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
11474 {
11475 resetPQExpBuffer(tag);
11476 appendPQExpBuffer(tag, "COLUMN %s.",
11477 fmtId(tbinfo->dobj.name));
11478 appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
11479
11480 resetPQExpBuffer(query);
11481 appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11483 appendPQExpBuffer(query, "%s IS ",
11484 fmtId(tbinfo->attnames[objsubid - 1]));
11485 appendStringLiteralAH(query, descr, fout);
11486 appendPQExpBufferStr(query, ";\n");
11487
11489 ARCHIVE_OPTS(.tag = tag->data,
11490 .namespace = tbinfo->dobj.namespace->dobj.name,
11491 .owner = tbinfo->rolname,
11492 .description = "COMMENT",
11493 .section = SECTION_NONE,
11494 .createStmt = query->data,
11495 .deps = &(tbinfo->dobj.dumpId),
11496 .nDeps = 1));
11497 }
11498
11499 comments++;
11500 ncomments--;
11501 }
11502
11503 destroyPQExpBuffer(query);
11504 destroyPQExpBuffer(tag);
11505}
11506
11507/*
11508 * findComments --
11509 *
11510 * Find the comment(s), if any, associated with the given object. All the
11511 * objsubid values associated with the given classoid/objoid are found with
11512 * one search.
11513 */
11514static int
11515findComments(Oid classoid, Oid objoid, CommentItem **items)
11516{
11518 CommentItem *low;
11519 CommentItem *high;
11520 int nmatch;
11521
11522 /*
11523 * Do binary search to find some item matching the object.
11524 */
11525 low = &comments[0];
11526 high = &comments[ncomments - 1];
11527 while (low <= high)
11528 {
11529 middle = low + (high - low) / 2;
11530
11531 if (classoid < middle->classoid)
11532 high = middle - 1;
11533 else if (classoid > middle->classoid)
11534 low = middle + 1;
11535 else if (objoid < middle->objoid)
11536 high = middle - 1;
11537 else if (objoid > middle->objoid)
11538 low = middle + 1;
11539 else
11540 break; /* found a match */
11541 }
11542
11543 if (low > high) /* no matches */
11544 {
11545 *items = NULL;
11546 return 0;
11547 }
11548
11549 /*
11550 * Now determine how many items match the object. The search loop
11551 * invariant still holds: only items between low and high inclusive could
11552 * match.
11553 */
11554 nmatch = 1;
11555 while (middle > low)
11556 {
11557 if (classoid != middle[-1].classoid ||
11558 objoid != middle[-1].objoid)
11559 break;
11560 middle--;
11561 nmatch++;
11562 }
11563
11564 *items = middle;
11565
11566 middle += nmatch;
11567 while (middle <= high)
11568 {
11569 if (classoid != middle->classoid ||
11570 objoid != middle->objoid)
11571 break;
11572 middle++;
11573 nmatch++;
11574 }
11575
11576 return nmatch;
11577}
11578
11579/*
11580 * collectComments --
11581 *
11582 * Construct a table of all comments available for database objects;
11583 * also set the has-comment component flag for each relevant object.
11584 *
11585 * We used to do per-object queries for the comments, but it's much faster
11586 * to pull them all over at once, and on most databases the memory cost
11587 * isn't high.
11588 *
11589 * The table is sorted by classoid/objid/objsubid for speed in lookup.
11590 */
11591static void
11593{
11594 PGresult *res;
11595 PQExpBuffer query;
11596 int i_description;
11597 int i_classoid;
11598 int i_objoid;
11599 int i_objsubid;
11600 int ntups;
11601 int i;
11602 DumpableObject *dobj;
11603
11604 query = createPQExpBuffer();
11605
11606 appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
11607 "FROM pg_catalog.pg_description "
11608 "ORDER BY classoid, objoid, objsubid");
11609
11610 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11611
11612 /* Construct lookup table containing OIDs in numeric form */
11613
11614 i_description = PQfnumber(res, "description");
11615 i_classoid = PQfnumber(res, "classoid");
11616 i_objoid = PQfnumber(res, "objoid");
11617 i_objsubid = PQfnumber(res, "objsubid");
11618
11619 ntups = PQntuples(res);
11620
11621 comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
11622 ncomments = 0;
11623 dobj = NULL;
11624
11625 for (i = 0; i < ntups; i++)
11626 {
11627 CatalogId objId;
11628 int subid;
11629
11630 objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
11631 objId.oid = atooid(PQgetvalue(res, i, i_objoid));
11632 subid = atoi(PQgetvalue(res, i, i_objsubid));
11633
11634 /* We needn't remember comments that don't match any dumpable object */
11635 if (dobj == NULL ||
11636 dobj->catId.tableoid != objId.tableoid ||
11637 dobj->catId.oid != objId.oid)
11638 dobj = findObjectByCatalogId(objId);
11639 if (dobj == NULL)
11640 continue;
11641
11642 /*
11643 * Comments on columns of composite types are linked to the type's
11644 * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
11645 * in the type's own DumpableObject.
11646 */
11647 if (subid != 0 && dobj->objType == DO_TABLE &&
11648 ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
11649 {
11651
11652 cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
11653 if (cTypeInfo)
11654 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
11655 }
11656 else
11657 dobj->components |= DUMP_COMPONENT_COMMENT;
11658
11661 comments[ncomments].objoid = objId.oid;
11662 comments[ncomments].objsubid = subid;
11663 ncomments++;
11664 }
11665
11666 PQclear(res);
11667 destroyPQExpBuffer(query);
11668}
11669
11670/*
11671 * dumpDumpableObject
11672 *
11673 * This routine and its subsidiaries are responsible for creating
11674 * ArchiveEntries (TOC objects) for each object to be dumped.
11675 */
11676static void
11678{
11679 /*
11680 * Clear any dump-request bits for components that don't exist for this
11681 * object. (This makes it safe to initially use DUMP_COMPONENT_ALL as the
11682 * request for every kind of object.)
11683 */
11684 dobj->dump &= dobj->components;
11685
11686 /* Now, short-circuit if there's nothing to be done here. */
11687 if (dobj->dump == 0)
11688 return;
11689
11690 switch (dobj->objType)
11691 {
11692 case DO_NAMESPACE:
11693 dumpNamespace(fout, (const NamespaceInfo *) dobj);
11694 break;
11695 case DO_EXTENSION:
11696 dumpExtension(fout, (const ExtensionInfo *) dobj);
11697 break;
11698 case DO_TYPE:
11699 dumpType(fout, (const TypeInfo *) dobj);
11700 break;
11701 case DO_SHELL_TYPE:
11702 dumpShellType(fout, (const ShellTypeInfo *) dobj);
11703 break;
11704 case DO_FUNC:
11705 dumpFunc(fout, (const FuncInfo *) dobj);
11706 break;
11707 case DO_AGG:
11708 dumpAgg(fout, (const AggInfo *) dobj);
11709 break;
11710 case DO_OPERATOR:
11711 dumpOpr(fout, (const OprInfo *) dobj);
11712 break;
11713 case DO_ACCESS_METHOD:
11714 dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
11715 break;
11716 case DO_OPCLASS:
11717 dumpOpclass(fout, (const OpclassInfo *) dobj);
11718 break;
11719 case DO_OPFAMILY:
11720 dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
11721 break;
11722 case DO_COLLATION:
11723 dumpCollation(fout, (const CollInfo *) dobj);
11724 break;
11725 case DO_CONVERSION:
11726 dumpConversion(fout, (const ConvInfo *) dobj);
11727 break;
11728 case DO_TABLE:
11729 dumpTable(fout, (const TableInfo *) dobj);
11730 break;
11731 case DO_TABLE_ATTACH:
11732 dumpTableAttach(fout, (const TableAttachInfo *) dobj);
11733 break;
11734 case DO_ATTRDEF:
11735 dumpAttrDef(fout, (const AttrDefInfo *) dobj);
11736 break;
11737 case DO_INDEX:
11738 dumpIndex(fout, (const IndxInfo *) dobj);
11739 break;
11740 case DO_INDEX_ATTACH:
11741 dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
11742 break;
11743 case DO_STATSEXT:
11744 dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
11745 dumpStatisticsExtStats(fout, (const StatsExtInfo *) dobj);
11746 break;
11747 case DO_REFRESH_MATVIEW:
11748 refreshMatViewData(fout, (const TableDataInfo *) dobj);
11749 break;
11750 case DO_RULE:
11751 dumpRule(fout, (const RuleInfo *) dobj);
11752 break;
11753 case DO_TRIGGER:
11754 dumpTrigger(fout, (const TriggerInfo *) dobj);
11755 break;
11756 case DO_EVENT_TRIGGER:
11757 dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
11758 break;
11759 case DO_CONSTRAINT:
11760 dumpConstraint(fout, (const ConstraintInfo *) dobj);
11761 break;
11762 case DO_FK_CONSTRAINT:
11763 dumpConstraint(fout, (const ConstraintInfo *) dobj);
11764 break;
11765 case DO_PROCLANG:
11766 dumpProcLang(fout, (const ProcLangInfo *) dobj);
11767 break;
11768 case DO_CAST:
11769 dumpCast(fout, (const CastInfo *) dobj);
11770 break;
11771 case DO_TRANSFORM:
11772 dumpTransform(fout, (const TransformInfo *) dobj);
11773 break;
11774 case DO_SEQUENCE_SET:
11775 dumpSequenceData(fout, (const TableDataInfo *) dobj);
11776 break;
11777 case DO_TABLE_DATA:
11778 dumpTableData(fout, (const TableDataInfo *) dobj);
11779 break;
11780 case DO_DUMMY_TYPE:
11781 /* table rowtypes and array types are never dumped separately */
11782 break;
11783 case DO_TSPARSER:
11784 dumpTSParser(fout, (const TSParserInfo *) dobj);
11785 break;
11786 case DO_TSDICT:
11787 dumpTSDictionary(fout, (const TSDictInfo *) dobj);
11788 break;
11789 case DO_TSTEMPLATE:
11790 dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
11791 break;
11792 case DO_TSCONFIG:
11793 dumpTSConfig(fout, (const TSConfigInfo *) dobj);
11794 break;
11795 case DO_FDW:
11796 dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
11797 break;
11798 case DO_FOREIGN_SERVER:
11799 dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
11800 break;
11801 case DO_DEFAULT_ACL:
11802 dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
11803 break;
11804 case DO_LARGE_OBJECT:
11805 dumpLO(fout, (const LoInfo *) dobj);
11806 break;
11808 if (dobj->dump & DUMP_COMPONENT_DATA)
11809 {
11810 LoInfo *loinfo;
11811 TocEntry *te;
11812
11814 if (loinfo == NULL)
11815 pg_fatal("missing metadata for large objects \"%s\"",
11816 dobj->name);
11817
11818 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
11819 ARCHIVE_OPTS(.tag = dobj->name,
11820 .owner = loinfo->rolname,
11821 .description = "BLOBS",
11822 .section = SECTION_DATA,
11823 .deps = dobj->dependencies,
11824 .nDeps = dobj->nDeps,
11825 .dumpFn = dumpLOs,
11826 .dumpArg = loinfo));
11827
11828 /*
11829 * Set the TocEntry's dataLength in case we are doing a
11830 * parallel dump and want to order dump jobs by table size.
11831 * (We need some size estimate for every TocEntry with a
11832 * DataDumper function.) We don't currently have any cheap
11833 * way to estimate the size of LOs, but fortunately it doesn't
11834 * matter too much as long as we get large batches of LOs
11835 * processed reasonably early. Assume 8K per blob.
11836 */
11837 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
11838 }
11839 break;
11840 case DO_POLICY:
11841 dumpPolicy(fout, (const PolicyInfo *) dobj);
11842 break;
11843 case DO_PUBLICATION:
11844 dumpPublication(fout, (const PublicationInfo *) dobj);
11845 break;
11846 case DO_PUBLICATION_REL:
11848 break;
11851 (const PublicationSchemaInfo *) dobj);
11852 break;
11853 case DO_SUBSCRIPTION:
11854 dumpSubscription(fout, (const SubscriptionInfo *) dobj);
11855 break;
11857 dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
11858 break;
11859 case DO_REL_STATS:
11860 dumpRelationStats(fout, (const RelStatsInfo *) dobj);
11861 break;
11864 /* never dumped, nothing to do */
11865 break;
11866 }
11867}
11868
11869/*
11870 * dumpNamespace
11871 * writes out to fout the queries to recreate a user-defined namespace
11872 */
11873static void
11875{
11876 DumpOptions *dopt = fout->dopt;
11877 PQExpBuffer q;
11879 char *qnspname;
11880
11881 /* Do nothing if not dumping schema */
11882 if (!dopt->dumpSchema)
11883 return;
11884
11885 q = createPQExpBuffer();
11887
11888 qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
11889
11890 if (nspinfo->create)
11891 {
11892 appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
11893 appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
11894 }
11895 else
11896 {
11897 /* see selectDumpableNamespace() */
11899 "-- *not* dropping schema, since initdb creates it\n");
11901 "-- *not* creating schema, since initdb creates it\n");
11902 }
11903
11904 if (dopt->binary_upgrade)
11906 "SCHEMA", qnspname, NULL);
11907
11908 if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11909 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
11910 ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
11911 .owner = nspinfo->rolname,
11912 .description = "SCHEMA",
11913 .section = SECTION_PRE_DATA,
11914 .createStmt = q->data,
11915 .dropStmt = delq->data));
11916
11917 /* Dump Schema Comments and Security Labels */
11918 if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11919 {
11920 const char *initdb_comment = NULL;
11921
11922 if (!nspinfo->create && strcmp(qnspname, "public") == 0)
11923 initdb_comment = "standard public schema";
11925 NULL, nspinfo->rolname,
11926 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
11928 }
11929
11930 if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11931 dumpSecLabel(fout, "SCHEMA", qnspname,
11932 NULL, nspinfo->rolname,
11933 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
11934
11935 if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
11936 dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
11937 qnspname, NULL, NULL,
11938 NULL, nspinfo->rolname, &nspinfo->dacl);
11939
11940 free(qnspname);
11941
11944}
11945
11946/*
11947 * dumpExtension
11948 * writes out to fout the queries to recreate an extension
11949 */
11950static void
11952{
11953 DumpOptions *dopt = fout->dopt;
11954 PQExpBuffer q;
11956 char *qextname;
11957
11958 /* Do nothing if not dumping schema */
11959 if (!dopt->dumpSchema)
11960 return;
11961
11962 q = createPQExpBuffer();
11964
11965 qextname = pg_strdup(fmtId(extinfo->dobj.name));
11966
11967 appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
11968
11969 if (!dopt->binary_upgrade)
11970 {
11971 /*
11972 * In a regular dump, we simply create the extension, intentionally
11973 * not specifying a version, so that the destination installation's
11974 * default version is used.
11975 *
11976 * Use of IF NOT EXISTS here is unlike our behavior for other object
11977 * types; but there are various scenarios in which it's convenient to
11978 * manually create the desired extension before restoring, so we
11979 * prefer to allow it to exist already.
11980 */
11981 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
11982 qextname, fmtId(extinfo->namespace));
11983 }
11984 else
11985 {
11986 /*
11987 * In binary-upgrade mode, it's critical to reproduce the state of the
11988 * database exactly, so our procedure is to create an empty extension,
11989 * restore all the contained objects normally, and add them to the
11990 * extension one by one. This function performs just the first of
11991 * those steps. binary_upgrade_extension_member() takes care of
11992 * adding member objects as they're created.
11993 */
11994 int i;
11995 int n;
11996
11997 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
11998
11999 /*
12000 * We unconditionally create the extension, so we must drop it if it
12001 * exists. This could happen if the user deleted 'plpgsql' and then
12002 * readded it, causing its oid to be greater than g_last_builtin_oid.
12003 */
12004 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
12005
12007 "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
12008 appendStringLiteralAH(q, extinfo->dobj.name, fout);
12009 appendPQExpBufferStr(q, ", ");
12010 appendStringLiteralAH(q, extinfo->namespace, fout);
12011 appendPQExpBufferStr(q, ", ");
12012 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
12013 appendStringLiteralAH(q, extinfo->extversion, fout);
12014 appendPQExpBufferStr(q, ", ");
12015
12016 /*
12017 * Note that we're pushing extconfig (an OID array) back into
12018 * pg_extension exactly as-is. This is OK because pg_class OIDs are
12019 * preserved in binary upgrade.
12020 */
12021 if (strlen(extinfo->extconfig) > 2)
12022 appendStringLiteralAH(q, extinfo->extconfig, fout);
12023 else
12024 appendPQExpBufferStr(q, "NULL");
12025 appendPQExpBufferStr(q, ", ");
12026 if (strlen(extinfo->extcondition) > 2)
12027 appendStringLiteralAH(q, extinfo->extcondition, fout);
12028 else
12029 appendPQExpBufferStr(q, "NULL");
12030 appendPQExpBufferStr(q, ", ");
12031 appendPQExpBufferStr(q, "ARRAY[");
12032 n = 0;
12033 for (i = 0; i < extinfo->dobj.nDeps; i++)
12034 {
12036
12037 extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
12038 if (extobj && extobj->objType == DO_EXTENSION)
12039 {
12040 if (n++ > 0)
12041 appendPQExpBufferChar(q, ',');
12043 }
12044 }
12045 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
12046 appendPQExpBufferStr(q, ");\n");
12047 }
12048
12049 if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12050 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
12051 ARCHIVE_OPTS(.tag = extinfo->dobj.name,
12052 .description = "EXTENSION",
12053 .section = SECTION_PRE_DATA,
12054 .createStmt = q->data,
12055 .dropStmt = delq->data));
12056
12057 /* Dump Extension Comments */
12058 if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12059 dumpComment(fout, "EXTENSION", qextname,
12060 NULL, "",
12061 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
12062
12063 free(qextname);
12064
12067}
12068
12069/*
12070 * dumpType
12071 * writes out to fout the queries to recreate a user-defined type
12072 */
12073static void
12075{
12076 DumpOptions *dopt = fout->dopt;
12077
12078 /* Do nothing if not dumping schema */
12079 if (!dopt->dumpSchema)
12080 return;
12081
12082 /* Dump out in proper style */
12083 if (tyinfo->typtype == TYPTYPE_BASE)
12085 else if (tyinfo->typtype == TYPTYPE_DOMAIN)
12087 else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
12089 else if (tyinfo->typtype == TYPTYPE_ENUM)
12091 else if (tyinfo->typtype == TYPTYPE_RANGE)
12093 else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
12095 else
12096 pg_log_warning("typtype of data type \"%s\" appears to be invalid",
12097 tyinfo->dobj.name);
12098}
12099
12100/*
12101 * dumpEnumType
12102 * writes out to fout the queries to recreate a user-defined enum type
12103 */
12104static void
12106{
12107 DumpOptions *dopt = fout->dopt;
12111 PGresult *res;
12112 int num,
12113 i;
12114 Oid enum_oid;
12115 char *qtypname;
12116 char *qualtypname;
12117 char *label;
12118 int i_enumlabel;
12119 int i_oid;
12120
12121 if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
12122 {
12123 /* Set up query for enum-specific details */
12125 "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
12126 "SELECT oid, enumlabel "
12127 "FROM pg_catalog.pg_enum "
12128 "WHERE enumtypid = $1 "
12129 "ORDER BY enumsortorder");
12130
12131 ExecuteSqlStatement(fout, query->data);
12132
12133 fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
12134 }
12135
12136 printfPQExpBuffer(query,
12137 "EXECUTE dumpEnumType('%u')",
12138 tyinfo->dobj.catId.oid);
12139
12140 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12141
12142 num = PQntuples(res);
12143
12144 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12146
12147 /*
12148 * CASCADE shouldn't be required here as for normal types since the I/O
12149 * functions are generic and do not get dropped.
12150 */
12151 appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12152
12153 if (dopt->binary_upgrade)
12155 tyinfo->dobj.catId.oid,
12156 false, false);
12157
12158 appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
12159 qualtypname);
12160
12161 if (!dopt->binary_upgrade)
12162 {
12163 i_enumlabel = PQfnumber(res, "enumlabel");
12164
12165 /* Labels with server-assigned oids */
12166 for (i = 0; i < num; i++)
12167 {
12168 label = PQgetvalue(res, i, i_enumlabel);
12169 if (i > 0)
12170 appendPQExpBufferChar(q, ',');
12171 appendPQExpBufferStr(q, "\n ");
12173 }
12174 }
12175
12176 appendPQExpBufferStr(q, "\n);\n");
12177
12178 if (dopt->binary_upgrade)
12179 {
12180 i_oid = PQfnumber(res, "oid");
12181 i_enumlabel = PQfnumber(res, "enumlabel");
12182
12183 /* Labels with dump-assigned (preserved) oids */
12184 for (i = 0; i < num; i++)
12185 {
12186 enum_oid = atooid(PQgetvalue(res, i, i_oid));
12187 label = PQgetvalue(res, i, i_enumlabel);
12188
12189 if (i == 0)
12190 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
12192 "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
12193 enum_oid);
12194 appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
12196 appendPQExpBufferStr(q, ";\n\n");
12197 }
12198 }
12199
12200 if (dopt->binary_upgrade)
12202 "TYPE", qtypname,
12203 tyinfo->dobj.namespace->dobj.name);
12204
12205 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12206 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12207 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12208 .namespace = tyinfo->dobj.namespace->dobj.name,
12209 .owner = tyinfo->rolname,
12210 .description = "TYPE",
12211 .section = SECTION_PRE_DATA,
12212 .createStmt = q->data,
12213 .dropStmt = delq->data));
12214
12215 /* Dump Type Comments and Security Labels */
12216 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12217 dumpComment(fout, "TYPE", qtypname,
12218 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12219 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12220
12221 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12222 dumpSecLabel(fout, "TYPE", qtypname,
12223 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12224 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12225
12226 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12227 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12228 qtypname, NULL,
12229 tyinfo->dobj.namespace->dobj.name,
12230 NULL, tyinfo->rolname, &tyinfo->dacl);
12231
12232 PQclear(res);
12235 destroyPQExpBuffer(query);
12236 free(qtypname);
12238}
12239
12240/*
12241 * dumpRangeType
12242 * writes out to fout the queries to recreate a user-defined range type
12243 */
12244static void
12246{
12247 DumpOptions *dopt = fout->dopt;
12251 PGresult *res;
12253 char *qtypname;
12254 char *qualtypname;
12255 char *procname;
12256
12257 if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
12258 {
12259 /* Set up query for range-specific details */
12261 "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
12262
12264 "SELECT ");
12265
12266 if (fout->remoteVersion >= 140000)
12268 "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
12269 else
12271 "NULL AS rngmultitype, ");
12272
12274 "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
12275 "opc.opcname AS opcname, "
12276 "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
12277 " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
12278 "opc.opcdefault, "
12279 "CASE WHEN rngcollation = st.typcollation THEN 0 "
12280 " ELSE rngcollation END AS collation, "
12281 "rngcanonical, rngsubdiff "
12282 "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
12283 " pg_catalog.pg_opclass opc "
12284 "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
12285 "rngtypid = $1");
12286
12287 ExecuteSqlStatement(fout, query->data);
12288
12289 fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
12290 }
12291
12292 printfPQExpBuffer(query,
12293 "EXECUTE dumpRangeType('%u')",
12294 tyinfo->dobj.catId.oid);
12295
12296 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12297
12298 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12300
12301 /*
12302 * CASCADE shouldn't be required here as for normal types since the I/O
12303 * functions are generic and do not get dropped.
12304 */
12305 appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12306
12307 if (dopt->binary_upgrade)
12309 tyinfo->dobj.catId.oid,
12310 false, true);
12311
12312 appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
12313 qualtypname);
12314
12315 appendPQExpBuffer(q, "\n subtype = %s",
12316 PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
12317
12318 if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
12319 appendPQExpBuffer(q, ",\n multirange_type_name = %s",
12320 PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
12321
12322 /* print subtype_opclass only if not default for subtype */
12323 if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
12324 {
12325 char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
12326 char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
12327
12328 appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
12329 fmtId(nspname));
12331 }
12332
12333 collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
12335 {
12337
12338 if (coll)
12339 appendPQExpBuffer(q, ",\n collation = %s",
12341 }
12342
12343 procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
12344 if (strcmp(procname, "-") != 0)
12345 appendPQExpBuffer(q, ",\n canonical = %s", procname);
12346
12347 procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
12348 if (strcmp(procname, "-") != 0)
12349 appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
12350
12351 appendPQExpBufferStr(q, "\n);\n");
12352
12353 if (dopt->binary_upgrade)
12355 "TYPE", qtypname,
12356 tyinfo->dobj.namespace->dobj.name);
12357
12358 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12359 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12360 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12361 .namespace = tyinfo->dobj.namespace->dobj.name,
12362 .owner = tyinfo->rolname,
12363 .description = "TYPE",
12364 .section = SECTION_PRE_DATA,
12365 .createStmt = q->data,
12366 .dropStmt = delq->data));
12367
12368 /* Dump Type Comments and Security Labels */
12369 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12370 dumpComment(fout, "TYPE", qtypname,
12371 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12372 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12373
12374 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12375 dumpSecLabel(fout, "TYPE", qtypname,
12376 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12377 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12378
12379 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12380 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12381 qtypname, NULL,
12382 tyinfo->dobj.namespace->dobj.name,
12383 NULL, tyinfo->rolname, &tyinfo->dacl);
12384
12385 PQclear(res);
12388 destroyPQExpBuffer(query);
12389 free(qtypname);
12391}
12392
12393/*
12394 * dumpUndefinedType
12395 * writes out to fout the queries to recreate a !typisdefined type
12396 *
12397 * This is a shell type, but we use different terminology to distinguish
12398 * this case from where we have to emit a shell type definition to break
12399 * circular dependencies. An undefined type shouldn't ever have anything
12400 * depending on it.
12401 */
12402static void
12404{
12405 DumpOptions *dopt = fout->dopt;
12408 char *qtypname;
12409 char *qualtypname;
12410
12411 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12413
12414 appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12415
12416 if (dopt->binary_upgrade)
12418 tyinfo->dobj.catId.oid,
12419 false, false);
12420
12421 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
12422 qualtypname);
12423
12424 if (dopt->binary_upgrade)
12426 "TYPE", qtypname,
12427 tyinfo->dobj.namespace->dobj.name);
12428
12429 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12430 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12431 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12432 .namespace = tyinfo->dobj.namespace->dobj.name,
12433 .owner = tyinfo->rolname,
12434 .description = "TYPE",
12435 .section = SECTION_PRE_DATA,
12436 .createStmt = q->data,
12437 .dropStmt = delq->data));
12438
12439 /* Dump Type Comments and Security Labels */
12440 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12441 dumpComment(fout, "TYPE", qtypname,
12442 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12443 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12444
12445 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12446 dumpSecLabel(fout, "TYPE", qtypname,
12447 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12448 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12449
12450 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12451 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12452 qtypname, NULL,
12453 tyinfo->dobj.namespace->dobj.name,
12454 NULL, tyinfo->rolname, &tyinfo->dacl);
12455
12458 free(qtypname);
12460}
12461
12462/*
12463 * dumpBaseType
12464 * writes out to fout the queries to recreate a user-defined base type
12465 */
12466static void
12468{
12469 DumpOptions *dopt = fout->dopt;
12473 PGresult *res;
12474 char *qtypname;
12475 char *qualtypname;
12476 char *typlen;
12477 char *typinput;
12478 char *typoutput;
12479 char *typreceive;
12480 char *typsend;
12481 char *typmodin;
12482 char *typmodout;
12483 char *typanalyze;
12484 char *typsubscript;
12491 char *typcategory;
12492 char *typispreferred;
12493 char *typdelim;
12494 char *typbyval;
12495 char *typalign;
12496 char *typstorage;
12497 char *typcollatable;
12498 char *typdefault;
12499 bool typdefault_is_literal = false;
12500
12501 if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
12502 {
12503 /* Set up query for type-specific details */
12505 "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
12506 "SELECT typlen, "
12507 "typinput, typoutput, typreceive, typsend, "
12508 "typreceive::pg_catalog.oid AS typreceiveoid, "
12509 "typsend::pg_catalog.oid AS typsendoid, "
12510 "typanalyze, "
12511 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
12512 "typdelim, typbyval, typalign, typstorage, "
12513 "typmodin, typmodout, "
12514 "typmodin::pg_catalog.oid AS typmodinoid, "
12515 "typmodout::pg_catalog.oid AS typmodoutoid, "
12516 "typcategory, typispreferred, "
12517 "(typcollation <> 0) AS typcollatable, "
12518 "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
12519
12520 if (fout->remoteVersion >= 140000)
12522 "typsubscript, "
12523 "typsubscript::pg_catalog.oid AS typsubscriptoid ");
12524 else
12526 "'-' AS typsubscript, 0 AS typsubscriptoid ");
12527
12528 appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
12529 "WHERE oid = $1");
12530
12531 ExecuteSqlStatement(fout, query->data);
12532
12533 fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
12534 }
12535
12536 printfPQExpBuffer(query,
12537 "EXECUTE dumpBaseType('%u')",
12538 tyinfo->dobj.catId.oid);
12539
12540 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12541
12542 typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
12543 typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
12544 typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
12545 typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
12546 typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
12547 typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
12548 typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
12549 typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
12550 typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
12551 typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
12552 typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
12553 typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
12554 typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
12555 typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
12556 typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
12557 typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
12558 typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
12559 typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
12560 typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
12561 typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
12562 typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
12563 typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
12564 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
12565 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
12566 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
12567 {
12568 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
12569 typdefault_is_literal = true; /* it needs quotes */
12570 }
12571 else
12572 typdefault = NULL;
12573
12574 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12576
12577 /*
12578 * The reason we include CASCADE is that the circular dependency between
12579 * the type and its I/O functions makes it impossible to drop the type any
12580 * other way.
12581 */
12582 appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
12583
12584 /*
12585 * We might already have a shell type, but setting pg_type_oid is
12586 * harmless, and in any case we'd better set the array type OID.
12587 */
12588 if (dopt->binary_upgrade)
12590 tyinfo->dobj.catId.oid,
12591 false, false);
12592
12594 "CREATE TYPE %s (\n"
12595 " INTERNALLENGTH = %s",
12597 (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
12598
12599 /* regproc result is sufficiently quoted already */
12600 appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
12601 appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
12603 appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
12605 appendPQExpBuffer(q, ",\n SEND = %s", typsend);
12607 appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
12609 appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
12611 appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
12612
12613 if (strcmp(typcollatable, "t") == 0)
12614 appendPQExpBufferStr(q, ",\n COLLATABLE = true");
12615
12616 if (typdefault != NULL)
12617 {
12618 appendPQExpBufferStr(q, ",\n DEFAULT = ");
12621 else
12623 }
12624
12626 appendPQExpBuffer(q, ",\n SUBSCRIPT = %s", typsubscript);
12627
12628 if (OidIsValid(tyinfo->typelem))
12629 appendPQExpBuffer(q, ",\n ELEMENT = %s",
12631 zeroIsError));
12632
12633 if (strcmp(typcategory, "U") != 0)
12634 {
12635 appendPQExpBufferStr(q, ",\n CATEGORY = ");
12637 }
12638
12639 if (strcmp(typispreferred, "t") == 0)
12640 appendPQExpBufferStr(q, ",\n PREFERRED = true");
12641
12642 if (typdelim && strcmp(typdelim, ",") != 0)
12643 {
12644 appendPQExpBufferStr(q, ",\n DELIMITER = ");
12645 appendStringLiteralAH(q, typdelim, fout);
12646 }
12647
12648 if (*typalign == TYPALIGN_CHAR)
12649 appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
12650 else if (*typalign == TYPALIGN_SHORT)
12651 appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
12652 else if (*typalign == TYPALIGN_INT)
12653 appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
12654 else if (*typalign == TYPALIGN_DOUBLE)
12655 appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
12656
12657 if (*typstorage == TYPSTORAGE_PLAIN)
12658 appendPQExpBufferStr(q, ",\n STORAGE = plain");
12659 else if (*typstorage == TYPSTORAGE_EXTERNAL)
12660 appendPQExpBufferStr(q, ",\n STORAGE = external");
12661 else if (*typstorage == TYPSTORAGE_EXTENDED)
12662 appendPQExpBufferStr(q, ",\n STORAGE = extended");
12663 else if (*typstorage == TYPSTORAGE_MAIN)
12664 appendPQExpBufferStr(q, ",\n STORAGE = main");
12665
12666 if (strcmp(typbyval, "t") == 0)
12667 appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
12668
12669 appendPQExpBufferStr(q, "\n);\n");
12670
12671 if (dopt->binary_upgrade)
12673 "TYPE", qtypname,
12674 tyinfo->dobj.namespace->dobj.name);
12675
12676 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12677 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12678 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12679 .namespace = tyinfo->dobj.namespace->dobj.name,
12680 .owner = tyinfo->rolname,
12681 .description = "TYPE",
12682 .section = SECTION_PRE_DATA,
12683 .createStmt = q->data,
12684 .dropStmt = delq->data));
12685
12686 /* Dump Type Comments and Security Labels */
12687 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12688 dumpComment(fout, "TYPE", qtypname,
12689 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12690 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12691
12692 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12693 dumpSecLabel(fout, "TYPE", qtypname,
12694 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12695 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12696
12697 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12698 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12699 qtypname, NULL,
12700 tyinfo->dobj.namespace->dobj.name,
12701 NULL, tyinfo->rolname, &tyinfo->dacl);
12702
12703 PQclear(res);
12706 destroyPQExpBuffer(query);
12707 free(qtypname);
12709}
12710
12711/*
12712 * dumpDomain
12713 * writes out to fout the queries to recreate a user-defined domain
12714 */
12715static void
12717{
12718 DumpOptions *dopt = fout->dopt;
12722 PGresult *res;
12723 int i;
12724 char *qtypname;
12725 char *qualtypname;
12726 char *typnotnull;
12727 char *typdefn;
12728 char *typdefault;
12729 Oid typcollation;
12730 bool typdefault_is_literal = false;
12731
12732 if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
12733 {
12734 /* Set up query for domain-specific details */
12736 "PREPARE dumpDomain(pg_catalog.oid) AS\n");
12737
12738 appendPQExpBufferStr(query, "SELECT t.typnotnull, "
12739 "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
12740 "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
12741 "t.typdefault, "
12742 "CASE WHEN t.typcollation <> u.typcollation "
12743 "THEN t.typcollation ELSE 0 END AS typcollation "
12744 "FROM pg_catalog.pg_type t "
12745 "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
12746 "WHERE t.oid = $1");
12747
12748 ExecuteSqlStatement(fout, query->data);
12749
12750 fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
12751 }
12752
12753 printfPQExpBuffer(query,
12754 "EXECUTE dumpDomain('%u')",
12755 tyinfo->dobj.catId.oid);
12756
12757 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12758
12759 typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
12760 typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
12761 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
12762 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
12763 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
12764 {
12765 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
12766 typdefault_is_literal = true; /* it needs quotes */
12767 }
12768 else
12769 typdefault = NULL;
12770 typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
12771
12772 if (dopt->binary_upgrade)
12774 tyinfo->dobj.catId.oid,
12775 true, /* force array type */
12776 false); /* force multirange type */
12777
12778 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12780
12782 "CREATE DOMAIN %s AS %s",
12784 typdefn);
12785
12786 /* Print collation only if different from base type's collation */
12787 if (OidIsValid(typcollation))
12788 {
12789 CollInfo *coll;
12790
12791 coll = findCollationByOid(typcollation);
12792 if (coll)
12793 appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
12794 }
12795
12796 /*
12797 * Print a not-null constraint if there's one. In servers older than 17
12798 * these don't have names, so just print it unadorned; in newer ones they
12799 * do, but most of the time it's going to be the standard generated one,
12800 * so omit the name in that case also.
12801 */
12802 if (typnotnull[0] == 't')
12803 {
12804 if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
12805 appendPQExpBufferStr(q, " NOT NULL");
12806 else
12807 {
12808 ConstraintInfo *notnull = tyinfo->notnull;
12809
12810 if (!notnull->separate)
12811 {
12812 char *default_name;
12813
12814 /* XXX should match ChooseConstraintName better */
12815 default_name = psprintf("%s_not_null", tyinfo->dobj.name);
12816
12817 if (strcmp(default_name, notnull->dobj.name) == 0)
12818 appendPQExpBufferStr(q, " NOT NULL");
12819 else
12820 appendPQExpBuffer(q, " CONSTRAINT %s %s",
12821 fmtId(notnull->dobj.name), notnull->condef);
12823 }
12824 }
12825 }
12826
12827 if (typdefault != NULL)
12828 {
12829 appendPQExpBufferStr(q, " DEFAULT ");
12832 else
12834 }
12835
12836 PQclear(res);
12837
12838 /*
12839 * Add any CHECK constraints for the domain
12840 */
12841 for (i = 0; i < tyinfo->nDomChecks; i++)
12842 {
12843 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
12844
12845 if (!domcheck->separate && domcheck->contype == 'c')
12846 appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
12847 fmtId(domcheck->dobj.name), domcheck->condef);
12848 }
12849
12850 appendPQExpBufferStr(q, ";\n");
12851
12852 appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
12853
12854 if (dopt->binary_upgrade)
12856 "DOMAIN", qtypname,
12857 tyinfo->dobj.namespace->dobj.name);
12858
12859 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12860 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12861 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12862 .namespace = tyinfo->dobj.namespace->dobj.name,
12863 .owner = tyinfo->rolname,
12864 .description = "DOMAIN",
12865 .section = SECTION_PRE_DATA,
12866 .createStmt = q->data,
12867 .dropStmt = delq->data));
12868
12869 /* Dump Domain Comments and Security Labels */
12870 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12871 dumpComment(fout, "DOMAIN", qtypname,
12872 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12873 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12874
12875 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12876 dumpSecLabel(fout, "DOMAIN", qtypname,
12877 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12878 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12879
12880 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12881 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12882 qtypname, NULL,
12883 tyinfo->dobj.namespace->dobj.name,
12884 NULL, tyinfo->rolname, &tyinfo->dacl);
12885
12886 /* Dump any per-constraint comments */
12887 for (i = 0; i < tyinfo->nDomChecks; i++)
12888 {
12889 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
12891
12892 /* but only if the constraint itself was dumped here */
12893 if (domcheck->separate)
12894 continue;
12895
12897 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
12898 fmtId(domcheck->dobj.name));
12899
12900 if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
12902 tyinfo->dobj.namespace->dobj.name,
12903 tyinfo->rolname,
12904 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
12905
12907 }
12908
12909 /*
12910 * And a comment on the not-null constraint, if there's one -- but only if
12911 * the constraint itself was dumped here
12912 */
12913 if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
12914 {
12916
12917 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
12918 fmtId(tyinfo->notnull->dobj.name));
12919
12920 if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
12922 tyinfo->dobj.namespace->dobj.name,
12923 tyinfo->rolname,
12924 tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
12926 }
12927
12930 destroyPQExpBuffer(query);
12931 free(qtypname);
12933}
12934
12935/*
12936 * dumpCompositeType
12937 * writes out to fout the queries to recreate a user-defined stand-alone
12938 * composite type
12939 */
12940static void
12942{
12943 DumpOptions *dopt = fout->dopt;
12945 PQExpBuffer dropped = createPQExpBuffer();
12948 PGresult *res;
12949 char *qtypname;
12950 char *qualtypname;
12951 int ntups;
12952 int i_attname;
12953 int i_atttypdefn;
12954 int i_attlen;
12955 int i_attalign;
12956 int i_attisdropped;
12957 int i_attcollation;
12958 int i;
12959 int actual_atts;
12960
12961 if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
12962 {
12963 /*
12964 * Set up query for type-specific details.
12965 *
12966 * Since we only want to dump COLLATE clauses for attributes whose
12967 * collation is different from their type's default, we use a CASE
12968 * here to suppress uninteresting attcollations cheaply. atttypid
12969 * will be 0 for dropped columns; collation does not matter for those.
12970 */
12972 "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
12973 "SELECT a.attname, a.attnum, "
12974 "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
12975 "a.attlen, a.attalign, a.attisdropped, "
12976 "CASE WHEN a.attcollation <> at.typcollation "
12977 "THEN a.attcollation ELSE 0 END AS attcollation "
12978 "FROM pg_catalog.pg_type ct "
12979 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
12980 "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
12981 "WHERE ct.oid = $1 "
12982 "ORDER BY a.attnum");
12983
12984 ExecuteSqlStatement(fout, query->data);
12985
12986 fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
12987 }
12988
12989 printfPQExpBuffer(query,
12990 "EXECUTE dumpCompositeType('%u')",
12991 tyinfo->dobj.catId.oid);
12992
12993 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12994
12995 ntups = PQntuples(res);
12996
12997 i_attname = PQfnumber(res, "attname");
12998 i_atttypdefn = PQfnumber(res, "atttypdefn");
12999 i_attlen = PQfnumber(res, "attlen");
13000 i_attalign = PQfnumber(res, "attalign");
13001 i_attisdropped = PQfnumber(res, "attisdropped");
13002 i_attcollation = PQfnumber(res, "attcollation");
13003
13004 if (dopt->binary_upgrade)
13005 {
13007 tyinfo->dobj.catId.oid,
13008 false, false);
13010 }
13011
13012 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
13014
13015 appendPQExpBuffer(q, "CREATE TYPE %s AS (",
13016 qualtypname);
13017
13018 actual_atts = 0;
13019 for (i = 0; i < ntups; i++)
13020 {
13021 char *attname;
13022 char *atttypdefn;
13023 char *attlen;
13024 char *attalign;
13025 bool attisdropped;
13026 Oid attcollation;
13027
13028 attname = PQgetvalue(res, i, i_attname);
13030 attlen = PQgetvalue(res, i, i_attlen);
13032 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
13033 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
13034
13035 if (attisdropped && !dopt->binary_upgrade)
13036 continue;
13037
13038 /* Format properly if not first attr */
13039 if (actual_atts++ > 0)
13040 appendPQExpBufferChar(q, ',');
13041 appendPQExpBufferStr(q, "\n\t");
13042
13043 if (!attisdropped)
13044 {
13046
13047 /* Add collation if not default for the column type */
13048 if (OidIsValid(attcollation))
13049 {
13050 CollInfo *coll;
13051
13052 coll = findCollationByOid(attcollation);
13053 if (coll)
13054 appendPQExpBuffer(q, " COLLATE %s",
13056 }
13057 }
13058 else
13059 {
13060 /*
13061 * This is a dropped attribute and we're in binary_upgrade mode.
13062 * Insert a placeholder for it in the CREATE TYPE command, and set
13063 * length and alignment with direct UPDATE to the catalogs
13064 * afterwards. See similar code in dumpTableSchema().
13065 */
13066 appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
13067
13068 /* stash separately for insertion after the CREATE TYPE */
13069 appendPQExpBufferStr(dropped,
13070 "\n-- For binary upgrade, recreate dropped column.\n");
13071 appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
13072 "SET attlen = %s, "
13073 "attalign = '%s', attbyval = false\n"
13074 "WHERE attname = ", attlen, attalign);
13076 appendPQExpBufferStr(dropped, "\n AND attrelid = ");
13078 appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
13079
13080 appendPQExpBuffer(dropped, "ALTER TYPE %s ",
13081 qualtypname);
13082 appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
13083 fmtId(attname));
13084 }
13085 }
13086 appendPQExpBufferStr(q, "\n);\n");
13087 appendPQExpBufferStr(q, dropped->data);
13088
13089 appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
13090
13091 if (dopt->binary_upgrade)
13093 "TYPE", qtypname,
13094 tyinfo->dobj.namespace->dobj.name);
13095
13096 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13097 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
13098 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
13099 .namespace = tyinfo->dobj.namespace->dobj.name,
13100 .owner = tyinfo->rolname,
13101 .description = "TYPE",
13102 .section = SECTION_PRE_DATA,
13103 .createStmt = q->data,
13104 .dropStmt = delq->data));
13105
13106
13107 /* Dump Type Comments and Security Labels */
13108 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13109 dumpComment(fout, "TYPE", qtypname,
13110 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
13111 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
13112
13113 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
13114 dumpSecLabel(fout, "TYPE", qtypname,
13115 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
13116 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
13117
13118 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
13119 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
13120 qtypname, NULL,
13121 tyinfo->dobj.namespace->dobj.name,
13122 NULL, tyinfo->rolname, &tyinfo->dacl);
13123
13124 /* Dump any per-column comments */
13125 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13127
13128 PQclear(res);
13130 destroyPQExpBuffer(dropped);
13132 destroyPQExpBuffer(query);
13133 free(qtypname);
13135}
13136
13137/*
13138 * dumpCompositeTypeColComments
13139 * writes out to fout the queries to recreate comments on the columns of
13140 * a user-defined stand-alone composite type.
13141 *
13142 * The caller has already made a query to collect the names and attnums
13143 * of the type's columns, so we just pass that result into here rather
13144 * than reading them again.
13145 */
13146static void
13148 PGresult *res)
13149{
13151 int ncomments;
13152 PQExpBuffer query;
13153 PQExpBuffer target;
13154 int i;
13155 int ntups;
13156 int i_attname;
13157 int i_attnum;
13158 int i_attisdropped;
13159
13160 /* do nothing, if --no-comments is supplied */
13161 if (fout->dopt->no_comments)
13162 return;
13163
13164 /* Search for comments associated with type's pg_class OID */
13166 &comments);
13167
13168 /* If no comments exist, we're done */
13169 if (ncomments <= 0)
13170 return;
13171
13172 /* Build COMMENT ON statements */
13173 query = createPQExpBuffer();
13174 target = createPQExpBuffer();
13175
13176 ntups = PQntuples(res);
13177 i_attnum = PQfnumber(res, "attnum");
13178 i_attname = PQfnumber(res, "attname");
13179 i_attisdropped = PQfnumber(res, "attisdropped");
13180 while (ncomments > 0)
13181 {
13182 const char *attname;
13183
13184 attname = NULL;
13185 for (i = 0; i < ntups; i++)
13186 {
13187 if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
13188 PQgetvalue(res, i, i_attisdropped)[0] != 't')
13189 {
13190 attname = PQgetvalue(res, i, i_attname);
13191 break;
13192 }
13193 }
13194 if (attname) /* just in case we don't find it */
13195 {
13196 const char *descr = comments->descr;
13197
13198 resetPQExpBuffer(target);
13199 appendPQExpBuffer(target, "COLUMN %s.",
13200 fmtId(tyinfo->dobj.name));
13202
13203 resetPQExpBuffer(query);
13204 appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
13206 appendPQExpBuffer(query, "%s IS ", fmtId(attname));
13207 appendStringLiteralAH(query, descr, fout);
13208 appendPQExpBufferStr(query, ";\n");
13209
13211 ARCHIVE_OPTS(.tag = target->data,
13212 .namespace = tyinfo->dobj.namespace->dobj.name,
13213 .owner = tyinfo->rolname,
13214 .description = "COMMENT",
13215 .section = SECTION_NONE,
13216 .createStmt = query->data,
13217 .deps = &(tyinfo->dobj.dumpId),
13218 .nDeps = 1));
13219 }
13220
13221 comments++;
13222 ncomments--;
13223 }
13224
13225 destroyPQExpBuffer(query);
13226 destroyPQExpBuffer(target);
13227}
13228
13229/*
13230 * dumpShellType
13231 * writes out to fout the queries to create a shell type
13232 *
13233 * We dump a shell definition in advance of the I/O functions for the type.
13234 */
13235static void
13237{
13238 DumpOptions *dopt = fout->dopt;
13239 PQExpBuffer q;
13240
13241 /* Do nothing if not dumping schema */
13242 if (!dopt->dumpSchema)
13243 return;
13244
13245 q = createPQExpBuffer();
13246
13247 /*
13248 * Note the lack of a DROP command for the shell type; any required DROP
13249 * is driven off the base type entry, instead. This interacts with
13250 * _printTocEntry()'s use of the presence of a DROP command to decide
13251 * whether an entry needs an ALTER OWNER command. We don't want to alter
13252 * the shell type's owner immediately on creation; that should happen only
13253 * after it's filled in, otherwise the backend complains.
13254 */
13255
13256 if (dopt->binary_upgrade)
13258 stinfo->baseType->dobj.catId.oid,
13259 false, false);
13260
13261 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
13263
13264 if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13265 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
13266 ARCHIVE_OPTS(.tag = stinfo->dobj.name,
13267 .namespace = stinfo->dobj.namespace->dobj.name,
13268 .owner = stinfo->baseType->rolname,
13269 .description = "SHELL TYPE",
13270 .section = SECTION_PRE_DATA,
13271 .createStmt = q->data));
13272
13274}
13275
13276/*
13277 * dumpProcLang
13278 * writes out to fout the queries to recreate a user-defined
13279 * procedural language
13280 */
13281static void
13283{
13284 DumpOptions *dopt = fout->dopt;
13287 bool useParams;
13288 char *qlanname;
13292
13293 /* Do nothing if not dumping schema */
13294 if (!dopt->dumpSchema)
13295 return;
13296
13297 /*
13298 * Try to find the support function(s). It is not an error if we don't
13299 * find them --- if the functions are in the pg_catalog schema, as is
13300 * standard in 8.1 and up, then we won't have loaded them. (In this case
13301 * we will emit a parameterless CREATE LANGUAGE command, which will
13302 * require PL template knowledge in the backend to reload.)
13303 */
13304
13305 funcInfo = findFuncByOid(plang->lanplcallfoid);
13306 if (funcInfo != NULL && !funcInfo->dobj.dump)
13307 funcInfo = NULL; /* treat not-dumped same as not-found */
13308
13309 if (OidIsValid(plang->laninline))
13310 {
13311 inlineInfo = findFuncByOid(plang->laninline);
13312 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
13313 inlineInfo = NULL;
13314 }
13315
13316 if (OidIsValid(plang->lanvalidator))
13317 {
13318 validatorInfo = findFuncByOid(plang->lanvalidator);
13319 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
13321 }
13322
13323 /*
13324 * If the functions are dumpable then emit a complete CREATE LANGUAGE with
13325 * parameters. Otherwise, we'll write a parameterless command, which will
13326 * be interpreted as CREATE EXTENSION.
13327 */
13328 useParams = (funcInfo != NULL &&
13329 (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
13330 (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
13331
13334
13335 qlanname = pg_strdup(fmtId(plang->dobj.name));
13336
13337 appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
13338 qlanname);
13339
13340 if (useParams)
13341 {
13342 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
13343 plang->lanpltrusted ? "TRUSTED " : "",
13344 qlanname);
13345 appendPQExpBuffer(defqry, " HANDLER %s",
13347 if (OidIsValid(plang->laninline))
13348 appendPQExpBuffer(defqry, " INLINE %s",
13350 if (OidIsValid(plang->lanvalidator))
13351 appendPQExpBuffer(defqry, " VALIDATOR %s",
13353 }
13354 else
13355 {
13356 /*
13357 * If not dumping parameters, then use CREATE OR REPLACE so that the
13358 * command will not fail if the language is preinstalled in the target
13359 * database.
13360 *
13361 * Modern servers will interpret this as CREATE EXTENSION IF NOT
13362 * EXISTS; perhaps we should emit that instead? But it might just add
13363 * confusion.
13364 */
13365 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
13366 qlanname);
13367 }
13369
13370 if (dopt->binary_upgrade)
13372 "LANGUAGE", qlanname, NULL);
13373
13374 if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
13375 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
13376 ARCHIVE_OPTS(.tag = plang->dobj.name,
13377 .owner = plang->lanowner,
13378 .description = "PROCEDURAL LANGUAGE",
13379 .section = SECTION_PRE_DATA,
13380 .createStmt = defqry->data,
13381 .dropStmt = delqry->data,
13382 ));
13383
13384 /* Dump Proc Lang Comments and Security Labels */
13385 if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
13386 dumpComment(fout, "LANGUAGE", qlanname,
13387 NULL, plang->lanowner,
13388 plang->dobj.catId, 0, plang->dobj.dumpId);
13389
13390 if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
13391 dumpSecLabel(fout, "LANGUAGE", qlanname,
13392 NULL, plang->lanowner,
13393 plang->dobj.catId, 0, plang->dobj.dumpId);
13394
13395 if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
13396 dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
13397 qlanname, NULL, NULL,
13398 NULL, plang->lanowner, &plang->dacl);
13399
13400 free(qlanname);
13401
13404}
13405
13406/*
13407 * format_function_arguments: generate function name and argument list
13408 *
13409 * This is used when we can rely on pg_get_function_arguments to format
13410 * the argument list. Note, however, that pg_get_function_arguments
13411 * does not special-case zero-argument aggregates.
13412 */
13413static char *
13414format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
13415{
13417
13420 if (is_agg && finfo->nargs == 0)
13421 appendPQExpBufferStr(&fn, "(*)");
13422 else
13423 appendPQExpBuffer(&fn, "(%s)", funcargs);
13424 return fn.data;
13425}
13426
13427/*
13428 * format_function_signature: generate function name and argument list
13429 *
13430 * Only a minimal list of input argument types is generated; this is
13431 * sufficient to reference the function, but not to define it.
13432 *
13433 * If honor_quotes is false then the function name is never quoted.
13434 * This is appropriate for use in TOC tags, but not in SQL commands.
13435 */
13436static char *
13438{
13440 int j;
13441
13443 if (honor_quotes)
13444 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
13445 else
13446 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
13447 for (j = 0; j < finfo->nargs; j++)
13448 {
13449 if (j > 0)
13450 appendPQExpBufferStr(&fn, ", ");
13451
13454 zeroIsError));
13455 }
13457 return fn.data;
13458}
13459
13460
13461/*
13462 * dumpFunc:
13463 * dump out one function
13464 */
13465static void
13466dumpFunc(Archive *fout, const FuncInfo *finfo)
13467{
13468 DumpOptions *dopt = fout->dopt;
13469 PQExpBuffer query;
13470 PQExpBuffer q;
13473 PGresult *res;
13474 char *funcsig; /* identity signature */
13475 char *funcfullsig = NULL; /* full signature */
13476 char *funcsig_tag;
13477 char *qual_funcsig;
13478 char *proretset;
13479 char *prosrc;
13480 char *probin;
13481 char *prosqlbody;
13482 char *funcargs;
13483 char *funciargs;
13484 char *funcresult;
13485 char *protrftypes;
13486 char *prokind;
13487 char *provolatile;
13488 char *proisstrict;
13489 char *prosecdef;
13490 char *proleakproof;
13491 char *proconfig;
13492 char *procost;
13493 char *prorows;
13494 char *prosupport;
13495 char *proparallel;
13496 char *lanname;
13497 char **configitems = NULL;
13498 int nconfigitems = 0;
13499 const char *keyword;
13500
13501 /* Do nothing if not dumping schema */
13502 if (!dopt->dumpSchema)
13503 return;
13504
13505 query = createPQExpBuffer();
13506 q = createPQExpBuffer();
13509
13510 if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
13511 {
13512 /* Set up query for function-specific details */
13514 "PREPARE dumpFunc(pg_catalog.oid) AS\n");
13515
13517 "SELECT\n"
13518 "proretset,\n"
13519 "prosrc,\n"
13520 "probin,\n"
13521 "provolatile,\n"
13522 "proisstrict,\n"
13523 "prosecdef,\n"
13524 "lanname,\n"
13525 "proconfig,\n"
13526 "procost,\n"
13527 "prorows,\n"
13528 "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
13529 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
13530 "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
13531 "proleakproof,\n");
13532
13533 if (fout->remoteVersion >= 90500)
13535 "array_to_string(protrftypes, ' ') AS protrftypes,\n");
13536 else
13538 "NULL AS protrftypes,\n");
13539
13540 if (fout->remoteVersion >= 90600)
13542 "proparallel,\n");
13543 else
13545 "'u' AS proparallel,\n");
13546
13547 if (fout->remoteVersion >= 110000)
13549 "prokind,\n");
13550 else
13552 "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
13553
13554 if (fout->remoteVersion >= 120000)
13556 "prosupport,\n");
13557 else
13559 "'-' AS prosupport,\n");
13560
13561 if (fout->remoteVersion >= 140000)
13563 "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
13564 else
13566 "NULL AS prosqlbody\n");
13567
13569 "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
13570 "WHERE p.oid = $1 "
13571 "AND l.oid = p.prolang");
13572
13573 ExecuteSqlStatement(fout, query->data);
13574
13575 fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
13576 }
13577
13578 printfPQExpBuffer(query,
13579 "EXECUTE dumpFunc('%u')",
13580 finfo->dobj.catId.oid);
13581
13582 res = ExecuteSqlQueryForSingleRow(fout, query->data);
13583
13584 proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
13585 if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
13586 {
13587 prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
13588 probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
13589 prosqlbody = NULL;
13590 }
13591 else
13592 {
13593 prosrc = NULL;
13594 probin = NULL;
13595 prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
13596 }
13597 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13598 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13599 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
13600 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
13601 prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
13602 provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
13603 proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
13604 prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
13605 proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
13606 proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
13607 procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
13608 prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
13609 prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
13610 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13611 lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
13612
13613 /*
13614 * See backend/commands/functioncmds.c for details of how the 'AS' clause
13615 * is used.
13616 */
13617 if (prosqlbody)
13618 {
13620 }
13621 else if (probin[0] != '\0')
13622 {
13625 if (prosrc[0] != '\0')
13626 {
13628
13629 /*
13630 * where we have bin, use dollar quoting if allowed and src
13631 * contains quote or backslash; else use regular quoting.
13632 */
13633 if (dopt->disable_dollar_quoting ||
13634 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
13636 else
13638 }
13639 }
13640 else
13641 {
13643 /* with no bin, dollar quote src unconditionally if allowed */
13644 if (dopt->disable_dollar_quoting)
13646 else
13648 }
13649
13650 if (*proconfig)
13651 {
13653 pg_fatal("could not parse %s array", "proconfig");
13654 }
13655 else
13656 {
13657 configitems = NULL;
13658 nconfigitems = 0;
13659 }
13660
13663
13665
13666 qual_funcsig = psprintf("%s.%s",
13667 fmtId(finfo->dobj.namespace->dobj.name),
13668 funcsig);
13669
13670 if (prokind[0] == PROKIND_PROCEDURE)
13671 keyword = "PROCEDURE";
13672 else
13673 keyword = "FUNCTION"; /* works for window functions too */
13674
13675 appendPQExpBuffer(delqry, "DROP %s %s;\n",
13676 keyword, qual_funcsig);
13677
13678 appendPQExpBuffer(q, "CREATE %s %s.%s",
13679 keyword,
13680 fmtId(finfo->dobj.namespace->dobj.name),
13682 funcsig);
13683
13684 if (prokind[0] == PROKIND_PROCEDURE)
13685 /* no result type to output */ ;
13686 else if (funcresult)
13687 appendPQExpBuffer(q, " RETURNS %s", funcresult);
13688 else
13689 appendPQExpBuffer(q, " RETURNS %s%s",
13690 (proretset[0] == 't') ? "SETOF " : "",
13691 getFormattedTypeName(fout, finfo->prorettype,
13692 zeroIsError));
13693
13694 appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
13695
13696 if (*protrftypes)
13697 {
13698 Oid *typeids = pg_malloc(FUNC_MAX_ARGS * sizeof(Oid));
13699 int i;
13700
13701 appendPQExpBufferStr(q, " TRANSFORM ");
13703 for (i = 0; typeids[i]; i++)
13704 {
13705 if (i != 0)
13706 appendPQExpBufferStr(q, ", ");
13707 appendPQExpBuffer(q, "FOR TYPE %s",
13709 }
13710
13711 free(typeids);
13712 }
13713
13714 if (prokind[0] == PROKIND_WINDOW)
13715 appendPQExpBufferStr(q, " WINDOW");
13716
13718 {
13720 appendPQExpBufferStr(q, " IMMUTABLE");
13721 else if (provolatile[0] == PROVOLATILE_STABLE)
13722 appendPQExpBufferStr(q, " STABLE");
13723 else if (provolatile[0] != PROVOLATILE_VOLATILE)
13724 pg_fatal("unrecognized provolatile value for function \"%s\"",
13725 finfo->dobj.name);
13726 }
13727
13728 if (proisstrict[0] == 't')
13729 appendPQExpBufferStr(q, " STRICT");
13730
13731 if (prosecdef[0] == 't')
13732 appendPQExpBufferStr(q, " SECURITY DEFINER");
13733
13734 if (proleakproof[0] == 't')
13735 appendPQExpBufferStr(q, " LEAKPROOF");
13736
13737 /*
13738 * COST and ROWS are emitted only if present and not default, so as not to
13739 * break backwards-compatibility of the dump without need. Keep this code
13740 * in sync with the defaults in functioncmds.c.
13741 */
13742 if (strcmp(procost, "0") != 0)
13743 {
13744 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
13745 {
13746 /* default cost is 1 */
13747 if (strcmp(procost, "1") != 0)
13748 appendPQExpBuffer(q, " COST %s", procost);
13749 }
13750 else
13751 {
13752 /* default cost is 100 */
13753 if (strcmp(procost, "100") != 0)
13754 appendPQExpBuffer(q, " COST %s", procost);
13755 }
13756 }
13757 if (proretset[0] == 't' &&
13758 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
13759 appendPQExpBuffer(q, " ROWS %s", prorows);
13760
13761 if (strcmp(prosupport, "-") != 0)
13762 {
13763 /* We rely on regprocout to provide quoting and qualification */
13764 appendPQExpBuffer(q, " SUPPORT %s", prosupport);
13765 }
13766
13768 {
13769 if (proparallel[0] == PROPARALLEL_SAFE)
13770 appendPQExpBufferStr(q, " PARALLEL SAFE");
13771 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
13772 appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
13773 else if (proparallel[0] != PROPARALLEL_UNSAFE)
13774 pg_fatal("unrecognized proparallel value for function \"%s\"",
13775 finfo->dobj.name);
13776 }
13777
13778 for (int i = 0; i < nconfigitems; i++)
13779 {
13780 /* we feel free to scribble on configitems[] here */
13781 char *configitem = configitems[i];
13782 char *pos;
13783
13784 pos = strchr(configitem, '=');
13785 if (pos == NULL)
13786 continue;
13787 *pos++ = '\0';
13788 appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
13789
13790 /*
13791 * Variables that are marked GUC_LIST_QUOTE were already fully quoted
13792 * by flatten_set_variable_args() before they were put into the
13793 * proconfig array. However, because the quoting rules used there
13794 * aren't exactly like SQL's, we have to break the list value apart
13795 * and then quote the elements as string literals. (The elements may
13796 * be double-quoted as-is, but we can't just feed them to the SQL
13797 * parser; it would do the wrong thing with elements that are
13798 * zero-length or longer than NAMEDATALEN.) Also, we need a special
13799 * case for empty lists.
13800 *
13801 * Variables that are not so marked should just be emitted as simple
13802 * string literals. If the variable is not known to
13803 * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
13804 * to use GUC_LIST_QUOTE for extension variables.
13805 */
13807 {
13808 char **namelist;
13809 char **nameptr;
13810
13811 /* Parse string into list of identifiers */
13812 /* this shouldn't fail really */
13813 if (SplitGUCList(pos, ',', &namelist))
13814 {
13815 /* Special case: represent an empty list as NULL */
13816 if (*namelist == NULL)
13817 appendPQExpBufferStr(q, "NULL");
13818 for (nameptr = namelist; *nameptr; nameptr++)
13819 {
13820 if (nameptr != namelist)
13821 appendPQExpBufferStr(q, ", ");
13823 }
13824 }
13826 }
13827 else
13828 appendStringLiteralAH(q, pos, fout);
13829 }
13830
13831 appendPQExpBuffer(q, "\n %s;\n", asPart->data);
13832
13834 "pg_catalog.pg_proc", keyword,
13835 qual_funcsig);
13836
13837 if (dopt->binary_upgrade)
13839 keyword, funcsig,
13840 finfo->dobj.namespace->dobj.name);
13841
13842 if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13843 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
13845 .namespace = finfo->dobj.namespace->dobj.name,
13846 .owner = finfo->rolname,
13847 .description = keyword,
13848 .section = finfo->postponed_def ?
13850 .createStmt = q->data,
13851 .dropStmt = delqry->data));
13852
13853 /* Dump Function Comments and Security Labels */
13854 if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13855 dumpComment(fout, keyword, funcsig,
13856 finfo->dobj.namespace->dobj.name, finfo->rolname,
13857 finfo->dobj.catId, 0, finfo->dobj.dumpId);
13858
13859 if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
13860 dumpSecLabel(fout, keyword, funcsig,
13861 finfo->dobj.namespace->dobj.name, finfo->rolname,
13862 finfo->dobj.catId, 0, finfo->dobj.dumpId);
13863
13864 if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
13865 dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
13866 funcsig, NULL,
13867 finfo->dobj.namespace->dobj.name,
13868 NULL, finfo->rolname, &finfo->dacl);
13869
13870 PQclear(res);
13871
13872 destroyPQExpBuffer(query);
13876 free(funcsig);
13881}
13882
13883
13884/*
13885 * Dump a user-defined cast
13886 */
13887static void
13889{
13890 DumpOptions *dopt = fout->dopt;
13896 const char *sourceType;
13897 const char *targetType;
13898
13899 /* Do nothing if not dumping schema */
13900 if (!dopt->dumpSchema)
13901 return;
13902
13903 /* Cannot dump if we don't have the cast function's info */
13904 if (OidIsValid(cast->castfunc))
13905 {
13906 funcInfo = findFuncByOid(cast->castfunc);
13907 if (funcInfo == NULL)
13908 pg_fatal("could not find function definition for function with OID %u",
13909 cast->castfunc);
13910 }
13911
13916
13919 appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
13921
13922 appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
13924
13925 switch (cast->castmethod)
13926 {
13928 appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
13929 break;
13931 appendPQExpBufferStr(defqry, "WITH INOUT");
13932 break;
13934 if (funcInfo)
13935 {
13937
13938 /*
13939 * Always qualify the function name (format_function_signature
13940 * won't qualify it).
13941 */
13942 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
13943 fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
13944 free(fsig);
13945 }
13946 else
13947 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
13948 break;
13949 default:
13950 pg_log_warning("bogus value in pg_cast.castmethod field");
13951 }
13952
13953 if (cast->castcontext == 'a')
13954 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
13955 else if (cast->castcontext == 'i')
13956 appendPQExpBufferStr(defqry, " AS IMPLICIT");
13958
13959 appendPQExpBuffer(labelq, "CAST (%s AS %s)",
13961
13962 appendPQExpBuffer(castargs, "(%s AS %s)",
13964
13965 if (dopt->binary_upgrade)
13967 "CAST", castargs->data, NULL);
13968
13969 if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
13970 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
13971 ARCHIVE_OPTS(.tag = labelq->data,
13972 .description = "CAST",
13973 .section = SECTION_PRE_DATA,
13974 .createStmt = defqry->data,
13975 .dropStmt = delqry->data));
13976
13977 /* Dump Cast Comments */
13978 if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
13979 dumpComment(fout, "CAST", castargs->data,
13980 NULL, "",
13981 cast->dobj.catId, 0, cast->dobj.dumpId);
13982
13987}
13988
13989/*
13990 * Dump a transform
13991 */
13992static void
13993dumpTransform(Archive *fout, const TransformInfo *transform)
13994{
13995 DumpOptions *dopt = fout->dopt;
14002 char *lanname;
14003 const char *transformType;
14004
14005 /* Do nothing if not dumping schema */
14006 if (!dopt->dumpSchema)
14007 return;
14008
14009 /* Cannot dump if we don't have the transform functions' info */
14010 if (OidIsValid(transform->trffromsql))
14011 {
14013 if (fromsqlFuncInfo == NULL)
14014 pg_fatal("could not find function definition for function with OID %u",
14015 transform->trffromsql);
14016 }
14017 if (OidIsValid(transform->trftosql))
14018 {
14019 tosqlFuncInfo = findFuncByOid(transform->trftosql);
14020 if (tosqlFuncInfo == NULL)
14021 pg_fatal("could not find function definition for function with OID %u",
14022 transform->trftosql);
14023 }
14024
14029
14030 lanname = get_language_name(fout, transform->trflang);
14032
14033 appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
14035
14036 appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
14038
14039 if (!transform->trffromsql && !transform->trftosql)
14040 pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
14041
14042 if (transform->trffromsql)
14043 {
14044 if (fromsqlFuncInfo)
14045 {
14047
14048 /*
14049 * Always qualify the function name (format_function_signature
14050 * won't qualify it).
14051 */
14052 appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
14053 fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
14054 free(fsig);
14055 }
14056 else
14057 pg_log_warning("bogus value in pg_transform.trffromsql field");
14058 }
14059
14060 if (transform->trftosql)
14061 {
14062 if (transform->trffromsql)
14064
14065 if (tosqlFuncInfo)
14066 {
14068
14069 /*
14070 * Always qualify the function name (format_function_signature
14071 * won't qualify it).
14072 */
14073 appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
14074 fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
14075 free(fsig);
14076 }
14077 else
14078 pg_log_warning("bogus value in pg_transform.trftosql field");
14079 }
14080
14082
14083 appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
14085
14086 appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
14088
14089 if (dopt->binary_upgrade)
14091 "TRANSFORM", transformargs->data, NULL);
14092
14093 if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
14094 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
14095 ARCHIVE_OPTS(.tag = labelq->data,
14096 .description = "TRANSFORM",
14097 .section = SECTION_PRE_DATA,
14098 .createStmt = defqry->data,
14099 .dropStmt = delqry->data,
14100 .deps = transform->dobj.dependencies,
14101 .nDeps = transform->dobj.nDeps));
14102
14103 /* Dump Transform Comments */
14104 if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
14105 dumpComment(fout, "TRANSFORM", transformargs->data,
14106 NULL, "",
14107 transform->dobj.catId, 0, transform->dobj.dumpId);
14108
14109 free(lanname);
14114}
14115
14116
14117/*
14118 * dumpOpr
14119 * write out a single operator definition
14120 */
14121static void
14123{
14124 DumpOptions *dopt = fout->dopt;
14125 PQExpBuffer query;
14126 PQExpBuffer q;
14129 PQExpBuffer details;
14130 PGresult *res;
14131 int i_oprkind;
14132 int i_oprcode;
14133 int i_oprleft;
14134 int i_oprright;
14135 int i_oprcom;
14136 int i_oprnegate;
14137 int i_oprrest;
14138 int i_oprjoin;
14139 int i_oprcanmerge;
14140 int i_oprcanhash;
14141 char *oprkind;
14142 char *oprcode;
14143 char *oprleft;
14144 char *oprright;
14145 char *oprcom;
14146 char *oprnegate;
14147 char *oprrest;
14148 char *oprjoin;
14149 char *oprcanmerge;
14150 char *oprcanhash;
14151 char *oprregproc;
14152 char *oprref;
14153
14154 /* Do nothing if not dumping schema */
14155 if (!dopt->dumpSchema)
14156 return;
14157
14158 /*
14159 * some operators are invalid because they were the result of user
14160 * defining operators before commutators exist
14161 */
14162 if (!OidIsValid(oprinfo->oprcode))
14163 return;
14164
14165 query = createPQExpBuffer();
14166 q = createPQExpBuffer();
14169 details = createPQExpBuffer();
14170
14171 if (!fout->is_prepared[PREPQUERY_DUMPOPR])
14172 {
14173 /* Set up query for operator-specific details */
14175 "PREPARE dumpOpr(pg_catalog.oid) AS\n"
14176 "SELECT oprkind, "
14177 "oprcode::pg_catalog.regprocedure, "
14178 "oprleft::pg_catalog.regtype, "
14179 "oprright::pg_catalog.regtype, "
14180 "oprcom, "
14181 "oprnegate, "
14182 "oprrest::pg_catalog.regprocedure, "
14183 "oprjoin::pg_catalog.regprocedure, "
14184 "oprcanmerge, oprcanhash "
14185 "FROM pg_catalog.pg_operator "
14186 "WHERE oid = $1");
14187
14188 ExecuteSqlStatement(fout, query->data);
14189
14190 fout->is_prepared[PREPQUERY_DUMPOPR] = true;
14191 }
14192
14193 printfPQExpBuffer(query,
14194 "EXECUTE dumpOpr('%u')",
14195 oprinfo->dobj.catId.oid);
14196
14197 res = ExecuteSqlQueryForSingleRow(fout, query->data);
14198
14199 i_oprkind = PQfnumber(res, "oprkind");
14200 i_oprcode = PQfnumber(res, "oprcode");
14201 i_oprleft = PQfnumber(res, "oprleft");
14202 i_oprright = PQfnumber(res, "oprright");
14203 i_oprcom = PQfnumber(res, "oprcom");
14204 i_oprnegate = PQfnumber(res, "oprnegate");
14205 i_oprrest = PQfnumber(res, "oprrest");
14206 i_oprjoin = PQfnumber(res, "oprjoin");
14207 i_oprcanmerge = PQfnumber(res, "oprcanmerge");
14208 i_oprcanhash = PQfnumber(res, "oprcanhash");
14209
14210 oprkind = PQgetvalue(res, 0, i_oprkind);
14211 oprcode = PQgetvalue(res, 0, i_oprcode);
14212 oprleft = PQgetvalue(res, 0, i_oprleft);
14213 oprright = PQgetvalue(res, 0, i_oprright);
14214 oprcom = PQgetvalue(res, 0, i_oprcom);
14215 oprnegate = PQgetvalue(res, 0, i_oprnegate);
14216 oprrest = PQgetvalue(res, 0, i_oprrest);
14217 oprjoin = PQgetvalue(res, 0, i_oprjoin);
14220
14221 /* In PG14 upwards postfix operator support does not exist anymore. */
14222 if (strcmp(oprkind, "r") == 0)
14223 pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
14224 oprcode);
14225
14227 if (oprregproc)
14228 {
14229 appendPQExpBuffer(details, " FUNCTION = %s", oprregproc);
14231 }
14232
14233 appendPQExpBuffer(oprid, "%s (",
14234 oprinfo->dobj.name);
14235
14236 /*
14237 * right unary means there's a left arg and left unary means there's a
14238 * right arg. (Although the "r" case is dead code for PG14 and later,
14239 * continue to support it in case we're dumping from an old server.)
14240 */
14241 if (strcmp(oprkind, "r") == 0 ||
14242 strcmp(oprkind, "b") == 0)
14243 {
14244 appendPQExpBuffer(details, ",\n LEFTARG = %s", oprleft);
14245 appendPQExpBufferStr(oprid, oprleft);
14246 }
14247 else
14248 appendPQExpBufferStr(oprid, "NONE");
14249
14250 if (strcmp(oprkind, "l") == 0 ||
14251 strcmp(oprkind, "b") == 0)
14252 {
14253 appendPQExpBuffer(details, ",\n RIGHTARG = %s", oprright);
14254 appendPQExpBuffer(oprid, ", %s)", oprright);
14255 }
14256 else
14257 appendPQExpBufferStr(oprid, ", NONE)");
14258
14260 if (oprref)
14261 {
14262 appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
14263 free(oprref);
14264 }
14265
14267 if (oprref)
14268 {
14269 appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
14270 free(oprref);
14271 }
14272
14273 if (strcmp(oprcanmerge, "t") == 0)
14274 appendPQExpBufferStr(details, ",\n MERGES");
14275
14276 if (strcmp(oprcanhash, "t") == 0)
14277 appendPQExpBufferStr(details, ",\n HASHES");
14278
14280 if (oprregproc)
14281 {
14282 appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
14284 }
14285
14287 if (oprregproc)
14288 {
14289 appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
14291 }
14292
14293 appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
14294 fmtId(oprinfo->dobj.namespace->dobj.name),
14295 oprid->data);
14296
14297 appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
14298 fmtId(oprinfo->dobj.namespace->dobj.name),
14299 oprinfo->dobj.name, details->data);
14300
14301 if (dopt->binary_upgrade)
14303 "OPERATOR", oprid->data,
14304 oprinfo->dobj.namespace->dobj.name);
14305
14306 if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14307 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
14308 ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
14309 .namespace = oprinfo->dobj.namespace->dobj.name,
14310 .owner = oprinfo->rolname,
14311 .description = "OPERATOR",
14312 .section = SECTION_PRE_DATA,
14313 .createStmt = q->data,
14314 .dropStmt = delq->data));
14315
14316 /* Dump Operator Comments */
14317 if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14318 dumpComment(fout, "OPERATOR", oprid->data,
14319 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
14320 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
14321
14322 PQclear(res);
14323
14324 destroyPQExpBuffer(query);
14328 destroyPQExpBuffer(details);
14329}
14330
14331/*
14332 * Convert a function reference obtained from pg_operator
14333 *
14334 * Returns allocated string of what to print, or NULL if function references
14335 * is InvalidOid. Returned string is expected to be free'd by the caller.
14336 *
14337 * The input is a REGPROCEDURE display; we have to strip the argument-types
14338 * part.
14339 */
14340static char *
14341convertRegProcReference(const char *proc)
14342{
14343 char *name;
14344 char *paren;
14345 bool inquote;
14346
14347 /* In all cases "-" means a null reference */
14348 if (strcmp(proc, "-") == 0)
14349 return NULL;
14350
14351 name = pg_strdup(proc);
14352 /* find non-double-quoted left paren */
14353 inquote = false;
14354 for (paren = name; *paren; paren++)
14355 {
14356 if (*paren == '(' && !inquote)
14357 {
14358 *paren = '\0';
14359 break;
14360 }
14361 if (*paren == '"')
14362 inquote = !inquote;
14363 }
14364 return name;
14365}
14366
14367/*
14368 * getFormattedOperatorName - retrieve the operator name for the
14369 * given operator OID (presented in string form).
14370 *
14371 * Returns an allocated string, or NULL if the given OID is invalid.
14372 * Caller is responsible for free'ing result string.
14373 *
14374 * What we produce has the format "OPERATOR(schema.oprname)". This is only
14375 * useful in commands where the operator's argument types can be inferred from
14376 * context. We always schema-qualify the name, though. The predecessor to
14377 * this code tried to skip the schema qualification if possible, but that led
14378 * to wrong results in corner cases, such as if an operator and its negator
14379 * are in different schemas.
14380 */
14381static char *
14383{
14385
14386 /* In all cases "0" means a null reference */
14387 if (strcmp(oproid, "0") == 0)
14388 return NULL;
14389
14391 if (oprInfo == NULL)
14392 {
14393 pg_log_warning("could not find operator with OID %s",
14394 oproid);
14395 return NULL;
14396 }
14397
14398 return psprintf("OPERATOR(%s.%s)",
14399 fmtId(oprInfo->dobj.namespace->dobj.name),
14400 oprInfo->dobj.name);
14401}
14402
14403/*
14404 * Convert a function OID obtained from pg_ts_parser or pg_ts_template
14405 *
14406 * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
14407 * argument lists of these functions are predetermined. Note that the
14408 * caller should ensure we are in the proper schema, because the results
14409 * are search path dependent!
14410 */
14411static char *
14413{
14414 char *result;
14415 char query[128];
14416 PGresult *res;
14417
14418 snprintf(query, sizeof(query),
14419 "SELECT '%u'::pg_catalog.regproc", funcOid);
14420 res = ExecuteSqlQueryForSingleRow(fout, query);
14421
14422 result = pg_strdup(PQgetvalue(res, 0, 0));
14423
14424 PQclear(res);
14425
14426 return result;
14427}
14428
14429/*
14430 * dumpAccessMethod
14431 * write out a single access method definition
14432 */
14433static void
14435{
14436 DumpOptions *dopt = fout->dopt;
14437 PQExpBuffer q;
14439 char *qamname;
14440
14441 /* Do nothing if not dumping schema */
14442 if (!dopt->dumpSchema)
14443 return;
14444
14445 q = createPQExpBuffer();
14447
14448 qamname = pg_strdup(fmtId(aminfo->dobj.name));
14449
14450 appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
14451
14452 switch (aminfo->amtype)
14453 {
14454 case AMTYPE_INDEX:
14455 appendPQExpBufferStr(q, "TYPE INDEX ");
14456 break;
14457 case AMTYPE_TABLE:
14458 appendPQExpBufferStr(q, "TYPE TABLE ");
14459 break;
14460 default:
14461 pg_log_warning("invalid type \"%c\" of access method \"%s\"",
14462 aminfo->amtype, qamname);
14465 free(qamname);
14466 return;
14467 }
14468
14469 appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
14470
14471 appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
14472 qamname);
14473
14474 if (dopt->binary_upgrade)
14476 "ACCESS METHOD", qamname, NULL);
14477
14478 if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14479 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
14480 ARCHIVE_OPTS(.tag = aminfo->dobj.name,
14481 .description = "ACCESS METHOD",
14482 .section = SECTION_PRE_DATA,
14483 .createStmt = q->data,
14484 .dropStmt = delq->data));
14485
14486 /* Dump Access Method Comments */
14487 if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14488 dumpComment(fout, "ACCESS METHOD", qamname,
14489 NULL, "",
14490 aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
14491
14494 free(qamname);
14495}
14496
14497/*
14498 * dumpOpclass
14499 * write out a single operator class definition
14500 */
14501static void
14503{
14504 DumpOptions *dopt = fout->dopt;
14505 PQExpBuffer query;
14506 PQExpBuffer q;
14509 PGresult *res;
14510 int ntups;
14511 int i_opcintype;
14512 int i_opckeytype;
14513 int i_opcdefault;
14514 int i_opcfamily;
14515 int i_opcfamilyname;
14516 int i_opcfamilynsp;
14517 int i_amname;
14518 int i_amopstrategy;
14519 int i_amopopr;
14520 int i_sortfamily;
14521 int i_sortfamilynsp;
14522 int i_amprocnum;
14523 int i_amproc;
14524 int i_amproclefttype;
14526 char *opcintype;
14527 char *opckeytype;
14528 char *opcdefault;
14529 char *opcfamily;
14530 char *opcfamilyname;
14531 char *opcfamilynsp;
14532 char *amname;
14533 char *amopstrategy;
14534 char *amopopr;
14535 char *sortfamily;
14536 char *sortfamilynsp;
14537 char *amprocnum;
14538 char *amproc;
14539 char *amproclefttype;
14540 char *amprocrighttype;
14541 bool needComma;
14542 int i;
14543
14544 /* Do nothing if not dumping schema */
14545 if (!dopt->dumpSchema)
14546 return;
14547
14548 query = createPQExpBuffer();
14549 q = createPQExpBuffer();
14552
14553 /* Get additional fields from the pg_opclass row */
14554 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
14555 "opckeytype::pg_catalog.regtype, "
14556 "opcdefault, opcfamily, "
14557 "opfname AS opcfamilyname, "
14558 "nspname AS opcfamilynsp, "
14559 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
14560 "FROM pg_catalog.pg_opclass c "
14561 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
14562 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14563 "WHERE c.oid = '%u'::pg_catalog.oid",
14564 opcinfo->dobj.catId.oid);
14565
14566 res = ExecuteSqlQueryForSingleRow(fout, query->data);
14567
14568 i_opcintype = PQfnumber(res, "opcintype");
14569 i_opckeytype = PQfnumber(res, "opckeytype");
14570 i_opcdefault = PQfnumber(res, "opcdefault");
14571 i_opcfamily = PQfnumber(res, "opcfamily");
14572 i_opcfamilyname = PQfnumber(res, "opcfamilyname");
14573 i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
14574 i_amname = PQfnumber(res, "amname");
14575
14576 /* opcintype may still be needed after we PQclear res */
14577 opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
14580 /* opcfamily will still be needed after we PQclear res */
14581 opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
14584 /* amname will still be needed after we PQclear res */
14585 amname = pg_strdup(PQgetvalue(res, 0, i_amname));
14586
14587 appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
14589 appendPQExpBuffer(delq, " USING %s;\n",
14590 fmtId(amname));
14591
14592 /* Build the fixed portion of the CREATE command */
14593 appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
14595 if (strcmp(opcdefault, "t") == 0)
14596 appendPQExpBufferStr(q, "DEFAULT ");
14597 appendPQExpBuffer(q, "FOR TYPE %s USING %s",
14598 opcintype,
14599 fmtId(amname));
14600 if (strlen(opcfamilyname) > 0)
14601 {
14602 appendPQExpBufferStr(q, " FAMILY ");
14605 }
14606 appendPQExpBufferStr(q, " AS\n ");
14607
14608 needComma = false;
14609
14610 if (strcmp(opckeytype, "-") != 0)
14611 {
14612 appendPQExpBuffer(q, "STORAGE %s",
14613 opckeytype);
14614 needComma = true;
14615 }
14616
14617 PQclear(res);
14618
14619 /*
14620 * Now fetch and print the OPERATOR entries (pg_amop rows).
14621 *
14622 * Print only those opfamily members that are tied to the opclass by
14623 * pg_depend entries.
14624 */
14625 resetPQExpBuffer(query);
14626 appendPQExpBuffer(query, "SELECT amopstrategy, "
14627 "amopopr::pg_catalog.regoperator, "
14628 "opfname AS sortfamily, "
14629 "nspname AS sortfamilynsp "
14630 "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
14631 "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
14632 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
14633 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14634 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
14635 "AND refobjid = '%u'::pg_catalog.oid "
14636 "AND amopfamily = '%s'::pg_catalog.oid "
14637 "ORDER BY amopstrategy",
14638 opcinfo->dobj.catId.oid,
14639 opcfamily);
14640
14641 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14642
14643 ntups = PQntuples(res);
14644
14645 i_amopstrategy = PQfnumber(res, "amopstrategy");
14646 i_amopopr = PQfnumber(res, "amopopr");
14647 i_sortfamily = PQfnumber(res, "sortfamily");
14648 i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
14649
14650 for (i = 0; i < ntups; i++)
14651 {
14653 amopopr = PQgetvalue(res, i, i_amopopr);
14654 sortfamily = PQgetvalue(res, i, i_sortfamily);
14656
14657 if (needComma)
14658 appendPQExpBufferStr(q, " ,\n ");
14659
14660 appendPQExpBuffer(q, "OPERATOR %s %s",
14662
14663 if (strlen(sortfamily) > 0)
14664 {
14665 appendPQExpBufferStr(q, " FOR ORDER BY ");
14667 appendPQExpBufferStr(q, fmtId(sortfamily));
14668 }
14669
14670 needComma = true;
14671 }
14672
14673 PQclear(res);
14674
14675 /*
14676 * Now fetch and print the FUNCTION entries (pg_amproc rows).
14677 *
14678 * Print only those opfamily members that are tied to the opclass by
14679 * pg_depend entries.
14680 *
14681 * We print the amproclefttype/amprocrighttype even though in most cases
14682 * the backend could deduce the right values, because of the corner case
14683 * of a btree sort support function for a cross-type comparison.
14684 */
14685 resetPQExpBuffer(query);
14686
14687 appendPQExpBuffer(query, "SELECT amprocnum, "
14688 "amproc::pg_catalog.regprocedure, "
14689 "amproclefttype::pg_catalog.regtype, "
14690 "amprocrighttype::pg_catalog.regtype "
14691 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
14692 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
14693 "AND refobjid = '%u'::pg_catalog.oid "
14694 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
14695 "AND objid = ap.oid "
14696 "ORDER BY amprocnum",
14697 opcinfo->dobj.catId.oid);
14698
14699 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14700
14701 ntups = PQntuples(res);
14702
14703 i_amprocnum = PQfnumber(res, "amprocnum");
14704 i_amproc = PQfnumber(res, "amproc");
14705 i_amproclefttype = PQfnumber(res, "amproclefttype");
14706 i_amprocrighttype = PQfnumber(res, "amprocrighttype");
14707
14708 for (i = 0; i < ntups; i++)
14709 {
14711 amproc = PQgetvalue(res, i, i_amproc);
14714
14715 if (needComma)
14716 appendPQExpBufferStr(q, " ,\n ");
14717
14718 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
14719
14722
14723 appendPQExpBuffer(q, " %s", amproc);
14724
14725 needComma = true;
14726 }
14727
14728 PQclear(res);
14729
14730 /*
14731 * If needComma is still false it means we haven't added anything after
14732 * the AS keyword. To avoid printing broken SQL, append a dummy STORAGE
14733 * clause with the same datatype. This isn't sanctioned by the
14734 * documentation, but actually DefineOpClass will treat it as a no-op.
14735 */
14736 if (!needComma)
14737 appendPQExpBuffer(q, "STORAGE %s", opcintype);
14738
14739 appendPQExpBufferStr(q, ";\n");
14740
14742 appendPQExpBuffer(nameusing, " USING %s",
14743 fmtId(amname));
14744
14745 if (dopt->binary_upgrade)
14747 "OPERATOR CLASS", nameusing->data,
14748 opcinfo->dobj.namespace->dobj.name);
14749
14750 if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14751 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
14752 ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
14753 .namespace = opcinfo->dobj.namespace->dobj.name,
14754 .owner = opcinfo->rolname,
14755 .description = "OPERATOR CLASS",
14756 .section = SECTION_PRE_DATA,
14757 .createStmt = q->data,
14758 .dropStmt = delq->data));
14759
14760 /* Dump Operator Class Comments */
14761 if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14762 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
14763 opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
14764 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
14765
14766 free(opcintype);
14767 free(opcfamily);
14768 free(amname);
14769 destroyPQExpBuffer(query);
14773}
14774
14775/*
14776 * dumpOpfamily
14777 * write out a single operator family definition
14778 *
14779 * Note: this also dumps any "loose" operator members that aren't bound to a
14780 * specific opclass within the opfamily.
14781 */
14782static void
14784{
14785 DumpOptions *dopt = fout->dopt;
14786 PQExpBuffer query;
14787 PQExpBuffer q;
14790 PGresult *res;
14793 int ntups;
14794 int i_amname;
14795 int i_amopstrategy;
14796 int i_amopopr;
14797 int i_sortfamily;
14798 int i_sortfamilynsp;
14799 int i_amprocnum;
14800 int i_amproc;
14801 int i_amproclefttype;
14803 char *amname;
14804 char *amopstrategy;
14805 char *amopopr;
14806 char *sortfamily;
14807 char *sortfamilynsp;
14808 char *amprocnum;
14809 char *amproc;
14810 char *amproclefttype;
14811 char *amprocrighttype;
14812 bool needComma;
14813 int i;
14814
14815 /* Do nothing if not dumping schema */
14816 if (!dopt->dumpSchema)
14817 return;
14818
14819 query = createPQExpBuffer();
14820 q = createPQExpBuffer();
14823
14824 /*
14825 * Fetch only those opfamily members that are tied directly to the
14826 * opfamily by pg_depend entries.
14827 */
14828 appendPQExpBuffer(query, "SELECT amopstrategy, "
14829 "amopopr::pg_catalog.regoperator, "
14830 "opfname AS sortfamily, "
14831 "nspname AS sortfamilynsp "
14832 "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
14833 "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
14834 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
14835 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14836 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
14837 "AND refobjid = '%u'::pg_catalog.oid "
14838 "AND amopfamily = '%u'::pg_catalog.oid "
14839 "ORDER BY amopstrategy",
14840 opfinfo->dobj.catId.oid,
14841 opfinfo->dobj.catId.oid);
14842
14844
14845 resetPQExpBuffer(query);
14846
14847 appendPQExpBuffer(query, "SELECT amprocnum, "
14848 "amproc::pg_catalog.regprocedure, "
14849 "amproclefttype::pg_catalog.regtype, "
14850 "amprocrighttype::pg_catalog.regtype "
14851 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
14852 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
14853 "AND refobjid = '%u'::pg_catalog.oid "
14854 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
14855 "AND objid = ap.oid "
14856 "ORDER BY amprocnum",
14857 opfinfo->dobj.catId.oid);
14858
14860
14861 /* Get additional fields from the pg_opfamily row */
14862 resetPQExpBuffer(query);
14863
14864 appendPQExpBuffer(query, "SELECT "
14865 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
14866 "FROM pg_catalog.pg_opfamily "
14867 "WHERE oid = '%u'::pg_catalog.oid",
14868 opfinfo->dobj.catId.oid);
14869
14870 res = ExecuteSqlQueryForSingleRow(fout, query->data);
14871
14872 i_amname = PQfnumber(res, "amname");
14873
14874 /* amname will still be needed after we PQclear res */
14875 amname = pg_strdup(PQgetvalue(res, 0, i_amname));
14876
14877 appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
14879 appendPQExpBuffer(delq, " USING %s;\n",
14880 fmtId(amname));
14881
14882 /* Build the fixed portion of the CREATE command */
14883 appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
14885 appendPQExpBuffer(q, " USING %s;\n",
14886 fmtId(amname));
14887
14888 PQclear(res);
14889
14890 /* Do we need an ALTER to add loose members? */
14891 if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
14892 {
14893 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
14895 appendPQExpBuffer(q, " USING %s ADD\n ",
14896 fmtId(amname));
14897
14898 needComma = false;
14899
14900 /*
14901 * Now fetch and print the OPERATOR entries (pg_amop rows).
14902 */
14903 ntups = PQntuples(res_ops);
14904
14905 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
14906 i_amopopr = PQfnumber(res_ops, "amopopr");
14907 i_sortfamily = PQfnumber(res_ops, "sortfamily");
14908 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
14909
14910 for (i = 0; i < ntups; i++)
14911 {
14914 sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
14916
14917 if (needComma)
14918 appendPQExpBufferStr(q, " ,\n ");
14919
14920 appendPQExpBuffer(q, "OPERATOR %s %s",
14922
14923 if (strlen(sortfamily) > 0)
14924 {
14925 appendPQExpBufferStr(q, " FOR ORDER BY ");
14927 appendPQExpBufferStr(q, fmtId(sortfamily));
14928 }
14929
14930 needComma = true;
14931 }
14932
14933 /*
14934 * Now fetch and print the FUNCTION entries (pg_amproc rows).
14935 */
14936 ntups = PQntuples(res_procs);
14937
14938 i_amprocnum = PQfnumber(res_procs, "amprocnum");
14939 i_amproc = PQfnumber(res_procs, "amproc");
14940 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
14941 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
14942
14943 for (i = 0; i < ntups; i++)
14944 {
14949
14950 if (needComma)
14951 appendPQExpBufferStr(q, " ,\n ");
14952
14953 appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
14955 amproc);
14956
14957 needComma = true;
14958 }
14959
14960 appendPQExpBufferStr(q, ";\n");
14961 }
14962
14964 appendPQExpBuffer(nameusing, " USING %s",
14965 fmtId(amname));
14966
14967 if (dopt->binary_upgrade)
14969 "OPERATOR FAMILY", nameusing->data,
14970 opfinfo->dobj.namespace->dobj.name);
14971
14972 if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14973 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
14974 ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
14975 .namespace = opfinfo->dobj.namespace->dobj.name,
14976 .owner = opfinfo->rolname,
14977 .description = "OPERATOR FAMILY",
14978 .section = SECTION_PRE_DATA,
14979 .createStmt = q->data,
14980 .dropStmt = delq->data));
14981
14982 /* Dump Operator Family Comments */
14983 if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14984 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
14985 opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
14986 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
14987
14988 free(amname);
14991 destroyPQExpBuffer(query);
14995}
14996
14997/*
14998 * dumpCollation
14999 * write out a single collation definition
15000 */
15001static void
15003{
15004 DumpOptions *dopt = fout->dopt;
15005 PQExpBuffer query;
15006 PQExpBuffer q;
15008 char *qcollname;
15009 PGresult *res;
15010 int i_collprovider;
15012 int i_collcollate;
15013 int i_collctype;
15014 int i_colllocale;
15015 int i_collicurules;
15016 const char *collprovider;
15017 const char *collcollate;
15018 const char *collctype;
15019 const char *colllocale;
15020 const char *collicurules;
15021
15022 /* Do nothing if not dumping schema */
15023 if (!dopt->dumpSchema)
15024 return;
15025
15026 query = createPQExpBuffer();
15027 q = createPQExpBuffer();
15029
15030 qcollname = pg_strdup(fmtId(collinfo->dobj.name));
15031
15032 /* Get collation-specific details */
15033 appendPQExpBufferStr(query, "SELECT ");
15034
15035 if (fout->remoteVersion >= 100000)
15037 "collprovider, "
15038 "collversion, ");
15039 else
15041 "'c' AS collprovider, "
15042 "NULL AS collversion, ");
15043
15044 if (fout->remoteVersion >= 120000)
15046 "collisdeterministic, ");
15047 else
15049 "true AS collisdeterministic, ");
15050
15051 if (fout->remoteVersion >= 170000)
15053 "colllocale, ");
15054 else if (fout->remoteVersion >= 150000)
15056 "colliculocale AS colllocale, ");
15057 else
15059 "NULL AS colllocale, ");
15060
15061 if (fout->remoteVersion >= 160000)
15063 "collicurules, ");
15064 else
15066 "NULL AS collicurules, ");
15067
15068 appendPQExpBuffer(query,
15069 "collcollate, "
15070 "collctype "
15071 "FROM pg_catalog.pg_collation c "
15072 "WHERE c.oid = '%u'::pg_catalog.oid",
15073 collinfo->dobj.catId.oid);
15074
15075 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15076
15077 i_collprovider = PQfnumber(res, "collprovider");
15078 i_collisdeterministic = PQfnumber(res, "collisdeterministic");
15079 i_collcollate = PQfnumber(res, "collcollate");
15080 i_collctype = PQfnumber(res, "collctype");
15081 i_colllocale = PQfnumber(res, "colllocale");
15082 i_collicurules = PQfnumber(res, "collicurules");
15083
15085
15086 if (!PQgetisnull(res, 0, i_collcollate))
15088 else
15089 collcollate = NULL;
15090
15091 if (!PQgetisnull(res, 0, i_collctype))
15092 collctype = PQgetvalue(res, 0, i_collctype);
15093 else
15094 collctype = NULL;
15095
15096 /*
15097 * Before version 15, collcollate and collctype were of type NAME and
15098 * non-nullable. Treat empty strings as NULL for consistency.
15099 */
15100 if (fout->remoteVersion < 150000)
15101 {
15102 if (collcollate[0] == '\0')
15103 collcollate = NULL;
15104 if (collctype[0] == '\0')
15105 collctype = NULL;
15106 }
15107
15108 if (!PQgetisnull(res, 0, i_colllocale))
15110 else
15111 colllocale = NULL;
15112
15113 if (!PQgetisnull(res, 0, i_collicurules))
15115 else
15117
15118 appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
15120
15121 appendPQExpBuffer(q, "CREATE COLLATION %s (",
15123
15124 appendPQExpBufferStr(q, "provider = ");
15125 if (collprovider[0] == 'b')
15126 appendPQExpBufferStr(q, "builtin");
15127 else if (collprovider[0] == 'c')
15128 appendPQExpBufferStr(q, "libc");
15129 else if (collprovider[0] == 'i')
15130 appendPQExpBufferStr(q, "icu");
15131 else if (collprovider[0] == 'd')
15132 /* to allow dumping pg_catalog; not accepted on input */
15133 appendPQExpBufferStr(q, "default");
15134 else
15135 pg_fatal("unrecognized collation provider: %s",
15136 collprovider);
15137
15138 if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
15139 appendPQExpBufferStr(q, ", deterministic = false");
15140
15141 if (collprovider[0] == 'd')
15142 {
15144 pg_log_warning("invalid collation \"%s\"", qcollname);
15145
15146 /* no locale -- the default collation cannot be reloaded anyway */
15147 }
15148 else if (collprovider[0] == 'b')
15149 {
15151 pg_log_warning("invalid collation \"%s\"", qcollname);
15152
15153 appendPQExpBufferStr(q, ", locale = ");
15155 fout);
15156 }
15157 else if (collprovider[0] == 'i')
15158 {
15159 if (fout->remoteVersion >= 150000)
15160 {
15161 if (collcollate || collctype || !colllocale)
15162 pg_log_warning("invalid collation \"%s\"", qcollname);
15163
15164 appendPQExpBufferStr(q, ", locale = ");
15166 fout);
15167 }
15168 else
15169 {
15170 if (!collcollate || !collctype || colllocale ||
15172 pg_log_warning("invalid collation \"%s\"", qcollname);
15173
15174 appendPQExpBufferStr(q, ", locale = ");
15176 }
15177
15178 if (collicurules)
15179 {
15180 appendPQExpBufferStr(q, ", rules = ");
15182 }
15183 }
15184 else if (collprovider[0] == 'c')
15185 {
15187 pg_log_warning("invalid collation \"%s\"", qcollname);
15188
15190 {
15191 appendPQExpBufferStr(q, ", locale = ");
15193 }
15194 else
15195 {
15196 appendPQExpBufferStr(q, ", lc_collate = ");
15198 appendPQExpBufferStr(q, ", lc_ctype = ");
15200 }
15201 }
15202 else
15203 pg_fatal("unrecognized collation provider: %s", collprovider);
15204
15205 /*
15206 * For binary upgrade, carry over the collation version. For normal
15207 * dump/restore, omit the version, so that it is computed upon restore.
15208 */
15209 if (dopt->binary_upgrade)
15210 {
15211 int i_collversion;
15212
15213 i_collversion = PQfnumber(res, "collversion");
15214 if (!PQgetisnull(res, 0, i_collversion))
15215 {
15216 appendPQExpBufferStr(q, ", version = ");
15218 PQgetvalue(res, 0, i_collversion),
15219 fout);
15220 }
15221 }
15222
15223 appendPQExpBufferStr(q, ");\n");
15224
15225 if (dopt->binary_upgrade)
15227 "COLLATION", qcollname,
15228 collinfo->dobj.namespace->dobj.name);
15229
15230 if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15231 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
15232 ARCHIVE_OPTS(.tag = collinfo->dobj.name,
15233 .namespace = collinfo->dobj.namespace->dobj.name,
15234 .owner = collinfo->rolname,
15235 .description = "COLLATION",
15236 .section = SECTION_PRE_DATA,
15237 .createStmt = q->data,
15238 .dropStmt = delq->data));
15239
15240 /* Dump Collation Comments */
15241 if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15242 dumpComment(fout, "COLLATION", qcollname,
15243 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
15244 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
15245
15246 PQclear(res);
15247
15248 destroyPQExpBuffer(query);
15251 free(qcollname);
15252}
15253
15254/*
15255 * dumpConversion
15256 * write out a single conversion definition
15257 */
15258static void
15260{
15261 DumpOptions *dopt = fout->dopt;
15262 PQExpBuffer query;
15263 PQExpBuffer q;
15265 char *qconvname;
15266 PGresult *res;
15267 int i_conforencoding;
15268 int i_contoencoding;
15269 int i_conproc;
15270 int i_condefault;
15271 const char *conforencoding;
15272 const char *contoencoding;
15273 const char *conproc;
15274 bool condefault;
15275
15276 /* Do nothing if not dumping schema */
15277 if (!dopt->dumpSchema)
15278 return;
15279
15280 query = createPQExpBuffer();
15281 q = createPQExpBuffer();
15283
15284 qconvname = pg_strdup(fmtId(convinfo->dobj.name));
15285
15286 /* Get conversion-specific details */
15287 appendPQExpBuffer(query, "SELECT "
15288 "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
15289 "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
15290 "conproc, condefault "
15291 "FROM pg_catalog.pg_conversion c "
15292 "WHERE c.oid = '%u'::pg_catalog.oid",
15293 convinfo->dobj.catId.oid);
15294
15295 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15296
15297 i_conforencoding = PQfnumber(res, "conforencoding");
15298 i_contoencoding = PQfnumber(res, "contoencoding");
15299 i_conproc = PQfnumber(res, "conproc");
15300 i_condefault = PQfnumber(res, "condefault");
15301
15304 conproc = PQgetvalue(res, 0, i_conproc);
15305 condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
15306
15307 appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
15309
15310 appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
15311 (condefault) ? "DEFAULT " : "",
15314 appendPQExpBufferStr(q, " TO ");
15316 /* regproc output is already sufficiently quoted */
15317 appendPQExpBuffer(q, " FROM %s;\n", conproc);
15318
15319 if (dopt->binary_upgrade)
15321 "CONVERSION", qconvname,
15322 convinfo->dobj.namespace->dobj.name);
15323
15324 if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15325 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
15326 ARCHIVE_OPTS(.tag = convinfo->dobj.name,
15327 .namespace = convinfo->dobj.namespace->dobj.name,
15328 .owner = convinfo->rolname,
15329 .description = "CONVERSION",
15330 .section = SECTION_PRE_DATA,
15331 .createStmt = q->data,
15332 .dropStmt = delq->data));
15333
15334 /* Dump Conversion Comments */
15335 if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15336 dumpComment(fout, "CONVERSION", qconvname,
15337 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
15338 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
15339
15340 PQclear(res);
15341
15342 destroyPQExpBuffer(query);
15345 free(qconvname);
15346}
15347
15348/*
15349 * format_aggregate_signature: generate aggregate name and argument list
15350 *
15351 * The argument type names are qualified if needed. The aggregate name
15352 * is never qualified.
15353 */
15354static char *
15356{
15358 int j;
15359
15361 if (honor_quotes)
15362 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
15363 else
15364 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
15365
15366 if (agginfo->aggfn.nargs == 0)
15367 appendPQExpBufferStr(&buf, "(*)");
15368 else
15369 {
15371 for (j = 0; j < agginfo->aggfn.nargs; j++)
15372 appendPQExpBuffer(&buf, "%s%s",
15373 (j > 0) ? ", " : "",
15375 agginfo->aggfn.argtypes[j],
15376 zeroIsError));
15378 }
15379 return buf.data;
15380}
15381
15382/*
15383 * dumpAgg
15384 * write out a single aggregate definition
15385 */
15386static void
15388{
15389 DumpOptions *dopt = fout->dopt;
15390 PQExpBuffer query;
15391 PQExpBuffer q;
15393 PQExpBuffer details;
15394 char *aggsig; /* identity signature */
15395 char *aggfullsig = NULL; /* full signature */
15396 char *aggsig_tag;
15397 PGresult *res;
15398 int i_agginitval;
15399 int i_aggminitval;
15400 const char *aggtransfn;
15401 const char *aggfinalfn;
15402 const char *aggcombinefn;
15403 const char *aggserialfn;
15404 const char *aggdeserialfn;
15405 const char *aggmtransfn;
15406 const char *aggminvtransfn;
15407 const char *aggmfinalfn;
15408 bool aggfinalextra;
15409 bool aggmfinalextra;
15410 char aggfinalmodify;
15411 char aggmfinalmodify;
15412 const char *aggsortop;
15413 char *aggsortconvop;
15414 char aggkind;
15415 const char *aggtranstype;
15416 const char *aggtransspace;
15417 const char *aggmtranstype;
15418 const char *aggmtransspace;
15419 const char *agginitval;
15420 const char *aggminitval;
15421 const char *proparallel;
15422 char defaultfinalmodify;
15423
15424 /* Do nothing if not dumping schema */
15425 if (!dopt->dumpSchema)
15426 return;
15427
15428 query = createPQExpBuffer();
15429 q = createPQExpBuffer();
15431 details = createPQExpBuffer();
15432
15433 if (!fout->is_prepared[PREPQUERY_DUMPAGG])
15434 {
15435 /* Set up query for aggregate-specific details */
15437 "PREPARE dumpAgg(pg_catalog.oid) AS\n");
15438
15440 "SELECT "
15441 "aggtransfn,\n"
15442 "aggfinalfn,\n"
15443 "aggtranstype::pg_catalog.regtype,\n"
15444 "agginitval,\n"
15445 "aggsortop,\n"
15446 "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
15447 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
15448
15449 if (fout->remoteVersion >= 90400)
15451 "aggkind,\n"
15452 "aggmtransfn,\n"
15453 "aggminvtransfn,\n"
15454 "aggmfinalfn,\n"
15455 "aggmtranstype::pg_catalog.regtype,\n"
15456 "aggfinalextra,\n"
15457 "aggmfinalextra,\n"
15458 "aggtransspace,\n"
15459 "aggmtransspace,\n"
15460 "aggminitval,\n");
15461 else
15463 "'n' AS aggkind,\n"
15464 "'-' AS aggmtransfn,\n"
15465 "'-' AS aggminvtransfn,\n"
15466 "'-' AS aggmfinalfn,\n"
15467 "0 AS aggmtranstype,\n"
15468 "false AS aggfinalextra,\n"
15469 "false AS aggmfinalextra,\n"
15470 "0 AS aggtransspace,\n"
15471 "0 AS aggmtransspace,\n"
15472 "NULL AS aggminitval,\n");
15473
15474 if (fout->remoteVersion >= 90600)
15476 "aggcombinefn,\n"
15477 "aggserialfn,\n"
15478 "aggdeserialfn,\n"
15479 "proparallel,\n");
15480 else
15482 "'-' AS aggcombinefn,\n"
15483 "'-' AS aggserialfn,\n"
15484 "'-' AS aggdeserialfn,\n"
15485 "'u' AS proparallel,\n");
15486
15487 if (fout->remoteVersion >= 110000)
15489 "aggfinalmodify,\n"
15490 "aggmfinalmodify\n");
15491 else
15493 "'0' AS aggfinalmodify,\n"
15494 "'0' AS aggmfinalmodify\n");
15495
15497 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
15498 "WHERE a.aggfnoid = p.oid "
15499 "AND p.oid = $1");
15500
15501 ExecuteSqlStatement(fout, query->data);
15502
15503 fout->is_prepared[PREPQUERY_DUMPAGG] = true;
15504 }
15505
15506 printfPQExpBuffer(query,
15507 "EXECUTE dumpAgg('%u')",
15508 agginfo->aggfn.dobj.catId.oid);
15509
15510 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15511
15512 i_agginitval = PQfnumber(res, "agginitval");
15513 i_aggminitval = PQfnumber(res, "aggminitval");
15514
15515 aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
15516 aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
15517 aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
15518 aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
15519 aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
15520 aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
15521 aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
15522 aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
15523 aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
15524 aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
15525 aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
15526 aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
15527 aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
15528 aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
15529 aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
15530 aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
15531 aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
15532 aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
15535 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
15536
15537 {
15538 char *funcargs;
15539 char *funciargs;
15540
15541 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
15542 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
15545 }
15546
15548
15549 /* identify default modify flag for aggkind (must match DefineAggregate) */
15551 /* replace omitted flags for old versions */
15552 if (aggfinalmodify == '0')
15554 if (aggmfinalmodify == '0')
15556
15557 /* regproc and regtype output is already sufficiently quoted */
15558 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
15559 aggtransfn, aggtranstype);
15560
15561 if (strcmp(aggtransspace, "0") != 0)
15562 {
15563 appendPQExpBuffer(details, ",\n SSPACE = %s",
15564 aggtransspace);
15565 }
15566
15567 if (!PQgetisnull(res, 0, i_agginitval))
15568 {
15569 appendPQExpBufferStr(details, ",\n INITCOND = ");
15571 }
15572
15573 if (strcmp(aggfinalfn, "-") != 0)
15574 {
15575 appendPQExpBuffer(details, ",\n FINALFUNC = %s",
15576 aggfinalfn);
15577 if (aggfinalextra)
15578 appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
15580 {
15581 switch (aggfinalmodify)
15582 {
15584 appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_ONLY");
15585 break;
15587 appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = SHAREABLE");
15588 break;
15590 appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_WRITE");
15591 break;
15592 default:
15593 pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
15594 agginfo->aggfn.dobj.name);
15595 break;
15596 }
15597 }
15598 }
15599
15600 if (strcmp(aggcombinefn, "-") != 0)
15601 appendPQExpBuffer(details, ",\n COMBINEFUNC = %s", aggcombinefn);
15602
15603 if (strcmp(aggserialfn, "-") != 0)
15604 appendPQExpBuffer(details, ",\n SERIALFUNC = %s", aggserialfn);
15605
15606 if (strcmp(aggdeserialfn, "-") != 0)
15607 appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
15608
15609 if (strcmp(aggmtransfn, "-") != 0)
15610 {
15611 appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
15615 }
15616
15617 if (strcmp(aggmtransspace, "0") != 0)
15618 {
15619 appendPQExpBuffer(details, ",\n MSSPACE = %s",
15621 }
15622
15623 if (!PQgetisnull(res, 0, i_aggminitval))
15624 {
15625 appendPQExpBufferStr(details, ",\n MINITCOND = ");
15627 }
15628
15629 if (strcmp(aggmfinalfn, "-") != 0)
15630 {
15631 appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
15632 aggmfinalfn);
15633 if (aggmfinalextra)
15634 appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
15636 {
15637 switch (aggmfinalmodify)
15638 {
15640 appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_ONLY");
15641 break;
15643 appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = SHAREABLE");
15644 break;
15646 appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_WRITE");
15647 break;
15648 default:
15649 pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
15650 agginfo->aggfn.dobj.name);
15651 break;
15652 }
15653 }
15654 }
15655
15657 if (aggsortconvop)
15658 {
15659 appendPQExpBuffer(details, ",\n SORTOP = %s",
15662 }
15663
15665 appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
15666
15668 {
15669 if (proparallel[0] == PROPARALLEL_SAFE)
15670 appendPQExpBufferStr(details, ",\n PARALLEL = safe");
15671 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
15672 appendPQExpBufferStr(details, ",\n PARALLEL = restricted");
15673 else if (proparallel[0] != PROPARALLEL_UNSAFE)
15674 pg_fatal("unrecognized proparallel value for function \"%s\"",
15675 agginfo->aggfn.dobj.name);
15676 }
15677
15678 appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
15679 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
15680 aggsig);
15681
15682 appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
15683 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
15684 aggfullsig ? aggfullsig : aggsig, details->data);
15685
15686 if (dopt->binary_upgrade)
15688 "AGGREGATE", aggsig,
15689 agginfo->aggfn.dobj.namespace->dobj.name);
15690
15691 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
15692 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
15693 agginfo->aggfn.dobj.dumpId,
15694 ARCHIVE_OPTS(.tag = aggsig_tag,
15695 .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
15696 .owner = agginfo->aggfn.rolname,
15697 .description = "AGGREGATE",
15698 .section = SECTION_PRE_DATA,
15699 .createStmt = q->data,
15700 .dropStmt = delq->data));
15701
15702 /* Dump Aggregate Comments */
15703 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
15704 dumpComment(fout, "AGGREGATE", aggsig,
15705 agginfo->aggfn.dobj.namespace->dobj.name,
15706 agginfo->aggfn.rolname,
15707 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
15708
15709 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
15710 dumpSecLabel(fout, "AGGREGATE", aggsig,
15711 agginfo->aggfn.dobj.namespace->dobj.name,
15712 agginfo->aggfn.rolname,
15713 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
15714
15715 /*
15716 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
15717 * command look like a function's GRANT; in particular this affects the
15718 * syntax for zero-argument aggregates and ordered-set aggregates.
15719 */
15720 free(aggsig);
15721
15722 aggsig = format_function_signature(fout, &agginfo->aggfn, true);
15723
15724 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
15725 dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
15726 "FUNCTION", aggsig, NULL,
15727 agginfo->aggfn.dobj.namespace->dobj.name,
15728 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
15729
15730 free(aggsig);
15733
15734 PQclear(res);
15735
15736 destroyPQExpBuffer(query);
15739 destroyPQExpBuffer(details);
15740}
15741
15742/*
15743 * dumpTSParser
15744 * write out a single text search parser
15745 */
15746static void
15748{
15749 DumpOptions *dopt = fout->dopt;
15750 PQExpBuffer q;
15752 char *qprsname;
15753
15754 /* Do nothing if not dumping schema */
15755 if (!dopt->dumpSchema)
15756 return;
15757
15758 q = createPQExpBuffer();
15760
15761 qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
15762
15763 appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
15765
15766 appendPQExpBuffer(q, " START = %s,\n",
15767 convertTSFunction(fout, prsinfo->prsstart));
15768 appendPQExpBuffer(q, " GETTOKEN = %s,\n",
15769 convertTSFunction(fout, prsinfo->prstoken));
15770 appendPQExpBuffer(q, " END = %s,\n",
15771 convertTSFunction(fout, prsinfo->prsend));
15772 if (prsinfo->prsheadline != InvalidOid)
15773 appendPQExpBuffer(q, " HEADLINE = %s,\n",
15774 convertTSFunction(fout, prsinfo->prsheadline));
15775 appendPQExpBuffer(q, " LEXTYPES = %s );\n",
15776 convertTSFunction(fout, prsinfo->prslextype));
15777
15778 appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
15780
15781 if (dopt->binary_upgrade)
15783 "TEXT SEARCH PARSER", qprsname,
15784 prsinfo->dobj.namespace->dobj.name);
15785
15786 if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15787 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
15788 ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
15789 .namespace = prsinfo->dobj.namespace->dobj.name,
15790 .description = "TEXT SEARCH PARSER",
15791 .section = SECTION_PRE_DATA,
15792 .createStmt = q->data,
15793 .dropStmt = delq->data));
15794
15795 /* Dump Parser Comments */
15796 if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15797 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
15798 prsinfo->dobj.namespace->dobj.name, "",
15799 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
15800
15803 free(qprsname);
15804}
15805
15806/*
15807 * dumpTSDictionary
15808 * write out a single text search dictionary
15809 */
15810static void
15812{
15813 DumpOptions *dopt = fout->dopt;
15814 PQExpBuffer q;
15816 PQExpBuffer query;
15817 char *qdictname;
15818 PGresult *res;
15819 char *nspname;
15820 char *tmplname;
15821
15822 /* Do nothing if not dumping schema */
15823 if (!dopt->dumpSchema)
15824 return;
15825
15826 q = createPQExpBuffer();
15828 query = createPQExpBuffer();
15829
15830 qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
15831
15832 /* Fetch name and namespace of the dictionary's template */
15833 appendPQExpBuffer(query, "SELECT nspname, tmplname "
15834 "FROM pg_ts_template p, pg_namespace n "
15835 "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
15836 dictinfo->dicttemplate);
15837 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15838 nspname = PQgetvalue(res, 0, 0);
15839 tmplname = PQgetvalue(res, 0, 1);
15840
15841 appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
15843
15844 appendPQExpBufferStr(q, " TEMPLATE = ");
15845 appendPQExpBuffer(q, "%s.", fmtId(nspname));
15847
15848 PQclear(res);
15849
15850 /* the dictinitoption can be dumped straight into the command */
15851 if (dictinfo->dictinitoption)
15852 appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
15853
15854 appendPQExpBufferStr(q, " );\n");
15855
15856 appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
15858
15859 if (dopt->binary_upgrade)
15861 "TEXT SEARCH DICTIONARY", qdictname,
15862 dictinfo->dobj.namespace->dobj.name);
15863
15864 if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15865 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
15866 ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
15867 .namespace = dictinfo->dobj.namespace->dobj.name,
15868 .owner = dictinfo->rolname,
15869 .description = "TEXT SEARCH DICTIONARY",
15870 .section = SECTION_PRE_DATA,
15871 .createStmt = q->data,
15872 .dropStmt = delq->data));
15873
15874 /* Dump Dictionary Comments */
15875 if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15876 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
15877 dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
15878 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
15879
15882 destroyPQExpBuffer(query);
15883 free(qdictname);
15884}
15885
15886/*
15887 * dumpTSTemplate
15888 * write out a single text search template
15889 */
15890static void
15892{
15893 DumpOptions *dopt = fout->dopt;
15894 PQExpBuffer q;
15896 char *qtmplname;
15897
15898 /* Do nothing if not dumping schema */
15899 if (!dopt->dumpSchema)
15900 return;
15901
15902 q = createPQExpBuffer();
15904
15905 qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
15906
15907 appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
15909
15910 if (tmplinfo->tmplinit != InvalidOid)
15911 appendPQExpBuffer(q, " INIT = %s,\n",
15912 convertTSFunction(fout, tmplinfo->tmplinit));
15913 appendPQExpBuffer(q, " LEXIZE = %s );\n",
15914 convertTSFunction(fout, tmplinfo->tmpllexize));
15915
15916 appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
15918
15919 if (dopt->binary_upgrade)
15921 "TEXT SEARCH TEMPLATE", qtmplname,
15922 tmplinfo->dobj.namespace->dobj.name);
15923
15924 if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15925 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
15926 ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
15927 .namespace = tmplinfo->dobj.namespace->dobj.name,
15928 .description = "TEXT SEARCH TEMPLATE",
15929 .section = SECTION_PRE_DATA,
15930 .createStmt = q->data,
15931 .dropStmt = delq->data));
15932
15933 /* Dump Template Comments */
15934 if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15935 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
15936 tmplinfo->dobj.namespace->dobj.name, "",
15937 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
15938
15941 free(qtmplname);
15942}
15943
15944/*
15945 * dumpTSConfig
15946 * write out a single text search configuration
15947 */
15948static void
15950{
15951 DumpOptions *dopt = fout->dopt;
15952 PQExpBuffer q;
15954 PQExpBuffer query;
15955 char *qcfgname;
15956 PGresult *res;
15957 char *nspname;
15958 char *prsname;
15959 int ntups,
15960 i;
15961 int i_tokenname;
15962 int i_dictname;
15963
15964 /* Do nothing if not dumping schema */
15965 if (!dopt->dumpSchema)
15966 return;
15967
15968 q = createPQExpBuffer();
15970 query = createPQExpBuffer();
15971
15972 qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
15973
15974 /* Fetch name and namespace of the config's parser */
15975 appendPQExpBuffer(query, "SELECT nspname, prsname "
15976 "FROM pg_ts_parser p, pg_namespace n "
15977 "WHERE p.oid = '%u' AND n.oid = prsnamespace",
15978 cfginfo->cfgparser);
15979 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15980 nspname = PQgetvalue(res, 0, 0);
15981 prsname = PQgetvalue(res, 0, 1);
15982
15983 appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
15985
15986 appendPQExpBuffer(q, " PARSER = %s.", fmtId(nspname));
15987 appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
15988
15989 PQclear(res);
15990
15991 resetPQExpBuffer(query);
15992 appendPQExpBuffer(query,
15993 "SELECT\n"
15994 " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
15995 " WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
15996 " m.mapdict::pg_catalog.regdictionary AS dictname\n"
15997 "FROM pg_catalog.pg_ts_config_map AS m\n"
15998 "WHERE m.mapcfg = '%u'\n"
15999 "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
16000 cfginfo->cfgparser, cfginfo->dobj.catId.oid);
16001
16002 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16003 ntups = PQntuples(res);
16004
16005 i_tokenname = PQfnumber(res, "tokenname");
16006 i_dictname = PQfnumber(res, "dictname");
16007
16008 for (i = 0; i < ntups; i++)
16009 {
16010 char *tokenname = PQgetvalue(res, i, i_tokenname);
16011 char *dictname = PQgetvalue(res, i, i_dictname);
16012
16013 if (i == 0 ||
16014 strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
16015 {
16016 /* starting a new token type, so start a new command */
16017 if (i > 0)
16018 appendPQExpBufferStr(q, ";\n");
16019 appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
16021 /* tokenname needs quoting, dictname does NOT */
16022 appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
16023 fmtId(tokenname), dictname);
16024 }
16025 else
16026 appendPQExpBuffer(q, ", %s", dictname);
16027 }
16028
16029 if (ntups > 0)
16030 appendPQExpBufferStr(q, ";\n");
16031
16032 PQclear(res);
16033
16034 appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
16036
16037 if (dopt->binary_upgrade)
16039 "TEXT SEARCH CONFIGURATION", qcfgname,
16040 cfginfo->dobj.namespace->dobj.name);
16041
16042 if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16043 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
16044 ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
16045 .namespace = cfginfo->dobj.namespace->dobj.name,
16046 .owner = cfginfo->rolname,
16047 .description = "TEXT SEARCH CONFIGURATION",
16048 .section = SECTION_PRE_DATA,
16049 .createStmt = q->data,
16050 .dropStmt = delq->data));
16051
16052 /* Dump Configuration Comments */
16053 if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16054 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
16055 cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
16056 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
16057
16060 destroyPQExpBuffer(query);
16061 free(qcfgname);
16062}
16063
16064/*
16065 * dumpForeignDataWrapper
16066 * write out a single foreign-data wrapper definition
16067 */
16068static void
16070{
16071 DumpOptions *dopt = fout->dopt;
16072 PQExpBuffer q;
16074 char *qfdwname;
16075
16076 /* Do nothing if not dumping schema */
16077 if (!dopt->dumpSchema)
16078 return;
16079
16080 q = createPQExpBuffer();
16082
16083 qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
16084
16085 appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
16086 qfdwname);
16087
16088 if (strcmp(fdwinfo->fdwhandler, "-") != 0)
16089 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
16090
16091 if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
16092 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
16093
16094 if (strlen(fdwinfo->fdwoptions) > 0)
16095 appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
16096
16097 appendPQExpBufferStr(q, ";\n");
16098
16099 appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
16100 qfdwname);
16101
16102 if (dopt->binary_upgrade)
16104 "FOREIGN DATA WRAPPER", qfdwname,
16105 NULL);
16106
16107 if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16108 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
16109 ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
16110 .owner = fdwinfo->rolname,
16111 .description = "FOREIGN DATA WRAPPER",
16112 .section = SECTION_PRE_DATA,
16113 .createStmt = q->data,
16114 .dropStmt = delq->data));
16115
16116 /* Dump Foreign Data Wrapper Comments */
16117 if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16118 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
16119 NULL, fdwinfo->rolname,
16120 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
16121
16122 /* Handle the ACL */
16123 if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
16124 dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
16125 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
16126 NULL, fdwinfo->rolname, &fdwinfo->dacl);
16127
16128 free(qfdwname);
16129
16132}
16133
16134/*
16135 * dumpForeignServer
16136 * write out a foreign server definition
16137 */
16138static void
16140{
16141 DumpOptions *dopt = fout->dopt;
16142 PQExpBuffer q;
16144 PQExpBuffer query;
16145 PGresult *res;
16146 char *qsrvname;
16147 char *fdwname;
16148
16149 /* Do nothing if not dumping schema */
16150 if (!dopt->dumpSchema)
16151 return;
16152
16153 q = createPQExpBuffer();
16155 query = createPQExpBuffer();
16156
16157 qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
16158
16159 /* look up the foreign-data wrapper */
16160 appendPQExpBuffer(query, "SELECT fdwname "
16161 "FROM pg_foreign_data_wrapper w "
16162 "WHERE w.oid = '%u'",
16163 srvinfo->srvfdw);
16164 res = ExecuteSqlQueryForSingleRow(fout, query->data);
16165 fdwname = PQgetvalue(res, 0, 0);
16166
16167 appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
16168 if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
16169 {
16170 appendPQExpBufferStr(q, " TYPE ");
16171 appendStringLiteralAH(q, srvinfo->srvtype, fout);
16172 }
16173 if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
16174 {
16175 appendPQExpBufferStr(q, " VERSION ");
16176 appendStringLiteralAH(q, srvinfo->srvversion, fout);
16177 }
16178
16179 appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
16180 appendPQExpBufferStr(q, fmtId(fdwname));
16181
16182 if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
16183 appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
16184
16185 appendPQExpBufferStr(q, ";\n");
16186
16187 appendPQExpBuffer(delq, "DROP SERVER %s;\n",
16188 qsrvname);
16189
16190 if (dopt->binary_upgrade)
16192 "SERVER", qsrvname, NULL);
16193
16194 if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16195 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
16196 ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
16197 .owner = srvinfo->rolname,
16198 .description = "SERVER",
16199 .section = SECTION_PRE_DATA,
16200 .createStmt = q->data,
16201 .dropStmt = delq->data));
16202
16203 /* Dump Foreign Server Comments */
16204 if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16205 dumpComment(fout, "SERVER", qsrvname,
16206 NULL, srvinfo->rolname,
16207 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
16208
16209 /* Handle the ACL */
16210 if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
16211 dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
16212 "FOREIGN SERVER", qsrvname, NULL, NULL,
16213 NULL, srvinfo->rolname, &srvinfo->dacl);
16214
16215 /* Dump user mappings */
16216 if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
16218 srvinfo->dobj.name, NULL,
16219 srvinfo->rolname,
16220 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
16221
16222 PQclear(res);
16223
16224 free(qsrvname);
16225
16228 destroyPQExpBuffer(query);
16229}
16230
16231/*
16232 * dumpUserMappings
16233 *
16234 * This routine is used to dump any user mappings associated with the
16235 * server handed to this routine. Should be called after ArchiveEntry()
16236 * for the server.
16237 */
16238static void
16240 const char *servername, const char *namespace,
16241 const char *owner,
16242 CatalogId catalogId, DumpId dumpId)
16243{
16244 PQExpBuffer q;
16246 PQExpBuffer query;
16247 PQExpBuffer tag;
16248 PGresult *res;
16249 int ntups;
16250 int i_usename;
16251 int i_umoptions;
16252 int i;
16253
16254 q = createPQExpBuffer();
16255 tag = createPQExpBuffer();
16257 query = createPQExpBuffer();
16258
16259 /*
16260 * We read from the publicly accessible view pg_user_mappings, so as not
16261 * to fail if run by a non-superuser. Note that the view will show
16262 * umoptions as null if the user hasn't got privileges for the associated
16263 * server; this means that pg_dump will dump such a mapping, but with no
16264 * OPTIONS clause. A possible alternative is to skip such mappings
16265 * altogether, but it's not clear that that's an improvement.
16266 */
16267 appendPQExpBuffer(query,
16268 "SELECT usename, "
16269 "array_to_string(ARRAY("
16270 "SELECT quote_ident(option_name) || ' ' || "
16271 "quote_literal(option_value) "
16272 "FROM pg_options_to_table(umoptions) "
16273 "ORDER BY option_name"
16274 "), E',\n ') AS umoptions "
16275 "FROM pg_user_mappings "
16276 "WHERE srvid = '%u' "
16277 "ORDER BY usename",
16278 catalogId.oid);
16279
16280 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16281
16282 ntups = PQntuples(res);
16283 i_usename = PQfnumber(res, "usename");
16284 i_umoptions = PQfnumber(res, "umoptions");
16285
16286 for (i = 0; i < ntups; i++)
16287 {
16288 char *usename;
16289 char *umoptions;
16290
16291 usename = PQgetvalue(res, i, i_usename);
16293
16295 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
16296 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
16297
16298 if (umoptions && strlen(umoptions) > 0)
16299 appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
16300
16301 appendPQExpBufferStr(q, ";\n");
16302
16304 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
16305 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
16306
16307 resetPQExpBuffer(tag);
16308 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
16309 usename, servername);
16310
16312 ARCHIVE_OPTS(.tag = tag->data,
16313 .namespace = namespace,
16314 .owner = owner,
16315 .description = "USER MAPPING",
16316 .section = SECTION_PRE_DATA,
16317 .createStmt = q->data,
16318 .dropStmt = delq->data));
16319 }
16320
16321 PQclear(res);
16322
16323 destroyPQExpBuffer(query);
16325 destroyPQExpBuffer(tag);
16327}
16328
16329/*
16330 * Write out default privileges information
16331 */
16332static void
16334{
16335 DumpOptions *dopt = fout->dopt;
16336 PQExpBuffer q;
16337 PQExpBuffer tag;
16338 const char *type;
16339
16340 /* Do nothing if not dumping schema, or if we're skipping ACLs */
16341 if (!dopt->dumpSchema || dopt->aclsSkip)
16342 return;
16343
16344 q = createPQExpBuffer();
16345 tag = createPQExpBuffer();
16346
16347 switch (daclinfo->defaclobjtype)
16348 {
16349 case DEFACLOBJ_RELATION:
16350 type = "TABLES";
16351 break;
16352 case DEFACLOBJ_SEQUENCE:
16353 type = "SEQUENCES";
16354 break;
16355 case DEFACLOBJ_FUNCTION:
16356 type = "FUNCTIONS";
16357 break;
16358 case DEFACLOBJ_TYPE:
16359 type = "TYPES";
16360 break;
16362 type = "SCHEMAS";
16363 break;
16365 type = "LARGE OBJECTS";
16366 break;
16367 default:
16368 /* shouldn't get here */
16369 pg_fatal("unrecognized object type in default privileges: %d",
16370 (int) daclinfo->defaclobjtype);
16371 type = ""; /* keep compiler quiet */
16372 }
16373
16374 appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
16375
16376 /* build the actual command(s) for this tuple */
16378 daclinfo->dobj.namespace != NULL ?
16379 daclinfo->dobj.namespace->dobj.name : NULL,
16380 daclinfo->dacl.acl,
16381 daclinfo->dacl.acldefault,
16382 daclinfo->defaclrole,
16383 fout->remoteVersion,
16384 q))
16385 pg_fatal("could not parse default ACL list (%s)",
16386 daclinfo->dacl.acl);
16387
16388 if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
16389 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
16390 ARCHIVE_OPTS(.tag = tag->data,
16391 .namespace = daclinfo->dobj.namespace ?
16392 daclinfo->dobj.namespace->dobj.name : NULL,
16393 .owner = daclinfo->defaclrole,
16394 .description = "DEFAULT ACL",
16395 .section = SECTION_POST_DATA,
16396 .createStmt = q->data));
16397
16398 destroyPQExpBuffer(tag);
16400}
16401
16402/*----------
16403 * Write out grant/revoke information
16404 *
16405 * 'objDumpId' is the dump ID of the underlying object.
16406 * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
16407 * or InvalidDumpId if there is no need for a second dependency.
16408 * 'type' must be one of
16409 * TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
16410 * FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
16411 * 'name' is the formatted name of the object. Must be quoted etc. already.
16412 * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
16413 * (Currently we assume that subname is only provided for table columns.)
16414 * 'nspname' is the namespace the object is in (NULL if none).
16415 * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
16416 * to use the default for the object type.
16417 * 'owner' is the owner, NULL if there is no owner (for languages).
16418 * 'dacl' is the DumpableAcl struct for the object.
16419 *
16420 * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
16421 * no ACL entry was created.
16422 *----------
16423 */
16424static DumpId
16426 const char *type, const char *name, const char *subname,
16427 const char *nspname, const char *tag, const char *owner,
16428 const DumpableAcl *dacl)
16429{
16431 DumpOptions *dopt = fout->dopt;
16432 const char *acls = dacl->acl;
16433 const char *acldefault = dacl->acldefault;
16434 char privtype = dacl->privtype;
16435 const char *initprivs = dacl->initprivs;
16436 const char *baseacls;
16437 PQExpBuffer sql;
16438
16439 /* Do nothing if ACL dump is not enabled */
16440 if (dopt->aclsSkip)
16441 return InvalidDumpId;
16442
16443 /* --data-only skips ACLs *except* large object ACLs */
16444 if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
16445 return InvalidDumpId;
16446
16447 sql = createPQExpBuffer();
16448
16449 /*
16450 * In binary upgrade mode, we don't run an extension's script but instead
16451 * dump out the objects independently and then recreate them. To preserve
16452 * any initial privileges which were set on extension objects, we need to
16453 * compute the set of GRANT and REVOKE commands necessary to get from the
16454 * default privileges of an object to its initial privileges as recorded
16455 * in pg_init_privs.
16456 *
16457 * At restore time, we apply these commands after having called
16458 * binary_upgrade_set_record_init_privs(true). That tells the backend to
16459 * copy the results into pg_init_privs. This is how we preserve the
16460 * contents of that catalog across binary upgrades.
16461 */
16462 if (dopt->binary_upgrade && privtype == 'e' &&
16463 initprivs && *initprivs != '\0')
16464 {
16465 appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
16466 if (!buildACLCommands(name, subname, nspname, type,
16467 initprivs, acldefault, owner,
16468 "", fout->remoteVersion, sql))
16469 pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
16470 initprivs, acldefault, name, type);
16471 appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
16472 }
16473
16474 /*
16475 * Now figure the GRANT and REVOKE commands needed to get to the object's
16476 * actual current ACL, starting from the initprivs if given, else from the
16477 * object-type-specific default. Also, while buildACLCommands will assume
16478 * that a NULL/empty acls string means it needn't do anything, what that
16479 * actually represents is the object-type-specific default; so we need to
16480 * substitute the acldefault string to get the right results in that case.
16481 */
16482 if (initprivs && *initprivs != '\0')
16483 {
16484 baseacls = initprivs;
16485 if (acls == NULL || *acls == '\0')
16486 acls = acldefault;
16487 }
16488 else
16490
16491 if (!buildACLCommands(name, subname, nspname, type,
16492 acls, baseacls, owner,
16493 "", fout->remoteVersion, sql))
16494 pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
16495 acls, baseacls, name, type);
16496
16497 if (sql->len > 0)
16498 {
16500 DumpId aclDeps[2];
16501 int nDeps = 0;
16502
16503 if (tag)
16505 else if (subname)
16506 appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
16507 else
16508 appendPQExpBuffer(tagbuf, "%s %s", type, name);
16509
16510 aclDeps[nDeps++] = objDumpId;
16511 if (altDumpId != InvalidDumpId)
16512 aclDeps[nDeps++] = altDumpId;
16513
16515
16517 ARCHIVE_OPTS(.tag = tagbuf->data,
16518 .namespace = nspname,
16519 .owner = owner,
16520 .description = "ACL",
16521 .section = SECTION_NONE,
16522 .createStmt = sql->data,
16523 .deps = aclDeps,
16524 .nDeps = nDeps));
16525
16527 }
16528
16529 destroyPQExpBuffer(sql);
16530
16531 return aclDumpId;
16532}
16533
16534/*
16535 * dumpSecLabel
16536 *
16537 * This routine is used to dump any security labels associated with the
16538 * object handed to this routine. The routine takes the object type
16539 * and object name (ready to print, except for schema decoration), plus
16540 * the namespace and owner of the object (for labeling the ArchiveEntry),
16541 * plus catalog ID and subid which are the lookup key for pg_seclabel,
16542 * plus the dump ID for the object (for setting a dependency).
16543 * If a matching pg_seclabel entry is found, it is dumped.
16544 *
16545 * Note: although this routine takes a dumpId for dependency purposes,
16546 * that purpose is just to mark the dependency in the emitted dump file
16547 * for possible future use by pg_restore. We do NOT use it for determining
16548 * ordering of the label in the dump file, because this routine is called
16549 * after dependency sorting occurs. This routine should be called just after
16550 * calling ArchiveEntry() for the specified object.
16551 */
16552static void
16553dumpSecLabel(Archive *fout, const char *type, const char *name,
16554 const char *namespace, const char *owner,
16555 CatalogId catalogId, int subid, DumpId dumpId)
16556{
16557 DumpOptions *dopt = fout->dopt;
16559 int nlabels;
16560 int i;
16561 PQExpBuffer query;
16562
16563 /* do nothing, if --no-security-labels is supplied */
16564 if (dopt->no_security_labels)
16565 return;
16566
16567 /*
16568 * Security labels are schema not data ... except large object labels are
16569 * data
16570 */
16571 if (strcmp(type, "LARGE OBJECT") != 0)
16572 {
16573 if (!dopt->dumpSchema)
16574 return;
16575 }
16576 else
16577 {
16578 /* We do dump large object security labels in binary-upgrade mode */
16579 if (!dopt->dumpData && !dopt->binary_upgrade)
16580 return;
16581 }
16582
16583 /* Search for security labels associated with catalogId, using table */
16584 nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
16585
16586 query = createPQExpBuffer();
16587
16588 for (i = 0; i < nlabels; i++)
16589 {
16590 /*
16591 * Ignore label entries for which the subid doesn't match.
16592 */
16593 if (labels[i].objsubid != subid)
16594 continue;
16595
16596 appendPQExpBuffer(query,
16597 "SECURITY LABEL FOR %s ON %s ",
16599 if (namespace && *namespace)
16600 appendPQExpBuffer(query, "%s.", fmtId(namespace));
16601 appendPQExpBuffer(query, "%s IS ", name);
16603 appendPQExpBufferStr(query, ";\n");
16604 }
16605
16606 if (query->len > 0)
16607 {
16609
16610 appendPQExpBuffer(tag, "%s %s", type, name);
16612 ARCHIVE_OPTS(.tag = tag->data,
16613 .namespace = namespace,
16614 .owner = owner,
16615 .description = "SECURITY LABEL",
16616 .section = SECTION_NONE,
16617 .createStmt = query->data,
16618 .deps = &dumpId,
16619 .nDeps = 1));
16620 destroyPQExpBuffer(tag);
16621 }
16622
16623 destroyPQExpBuffer(query);
16624}
16625
16626/*
16627 * dumpTableSecLabel
16628 *
16629 * As above, but dump security label for both the specified table (or view)
16630 * and its columns.
16631 */
16632static void
16634{
16635 DumpOptions *dopt = fout->dopt;
16637 int nlabels;
16638 int i;
16639 PQExpBuffer query;
16640 PQExpBuffer target;
16641
16642 /* do nothing, if --no-security-labels is supplied */
16643 if (dopt->no_security_labels)
16644 return;
16645
16646 /* SecLabel are SCHEMA not data */
16647 if (!dopt->dumpSchema)
16648 return;
16649
16650 /* Search for comments associated with relation, using table */
16651 nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
16652 tbinfo->dobj.catId.oid,
16653 &labels);
16654
16655 /* If security labels exist, build SECURITY LABEL statements */
16656 if (nlabels <= 0)
16657 return;
16658
16659 query = createPQExpBuffer();
16660 target = createPQExpBuffer();
16661
16662 for (i = 0; i < nlabels; i++)
16663 {
16664 const char *colname;
16665 const char *provider = labels[i].provider;
16666 const char *label = labels[i].label;
16667 int objsubid = labels[i].objsubid;
16668
16669 resetPQExpBuffer(target);
16670 if (objsubid == 0)
16671 {
16672 appendPQExpBuffer(target, "%s %s", reltypename,
16674 }
16675 else
16676 {
16677 colname = getAttrName(objsubid, tbinfo);
16678 /* first fmtXXX result must be consumed before calling again */
16679 appendPQExpBuffer(target, "COLUMN %s",
16681 appendPQExpBuffer(target, ".%s", fmtId(colname));
16682 }
16683 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
16684 fmtId(provider), target->data);
16686 appendPQExpBufferStr(query, ";\n");
16687 }
16688 if (query->len > 0)
16689 {
16690 resetPQExpBuffer(target);
16691 appendPQExpBuffer(target, "%s %s", reltypename,
16692 fmtId(tbinfo->dobj.name));
16694 ARCHIVE_OPTS(.tag = target->data,
16695 .namespace = tbinfo->dobj.namespace->dobj.name,
16696 .owner = tbinfo->rolname,
16697 .description = "SECURITY LABEL",
16698 .section = SECTION_NONE,
16699 .createStmt = query->data,
16700 .deps = &(tbinfo->dobj.dumpId),
16701 .nDeps = 1));
16702 }
16703 destroyPQExpBuffer(query);
16704 destroyPQExpBuffer(target);
16705}
16706
16707/*
16708 * findSecLabels
16709 *
16710 * Find the security label(s), if any, associated with the given object.
16711 * All the objsubid values associated with the given classoid/objoid are
16712 * found with one search.
16713 */
16714static int
16715findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
16716{
16718 SecLabelItem *low;
16719 SecLabelItem *high;
16720 int nmatch;
16721
16722 if (nseclabels <= 0) /* no labels, so no match is possible */
16723 {
16724 *items = NULL;
16725 return 0;
16726 }
16727
16728 /*
16729 * Do binary search to find some item matching the object.
16730 */
16731 low = &seclabels[0];
16732 high = &seclabels[nseclabels - 1];
16733 while (low <= high)
16734 {
16735 middle = low + (high - low) / 2;
16736
16737 if (classoid < middle->classoid)
16738 high = middle - 1;
16739 else if (classoid > middle->classoid)
16740 low = middle + 1;
16741 else if (objoid < middle->objoid)
16742 high = middle - 1;
16743 else if (objoid > middle->objoid)
16744 low = middle + 1;
16745 else
16746 break; /* found a match */
16747 }
16748
16749 if (low > high) /* no matches */
16750 {
16751 *items = NULL;
16752 return 0;
16753 }
16754
16755 /*
16756 * Now determine how many items match the object. The search loop
16757 * invariant still holds: only items between low and high inclusive could
16758 * match.
16759 */
16760 nmatch = 1;
16761 while (middle > low)
16762 {
16763 if (classoid != middle[-1].classoid ||
16764 objoid != middle[-1].objoid)
16765 break;
16766 middle--;
16767 nmatch++;
16768 }
16769
16770 *items = middle;
16771
16772 middle += nmatch;
16773 while (middle <= high)
16774 {
16775 if (classoid != middle->classoid ||
16776 objoid != middle->objoid)
16777 break;
16778 middle++;
16779 nmatch++;
16780 }
16781
16782 return nmatch;
16783}
16784
16785/*
16786 * collectSecLabels
16787 *
16788 * Construct a table of all security labels available for database objects;
16789 * also set the has-seclabel component flag for each relevant object.
16790 *
16791 * The table is sorted by classoid/objid/objsubid for speed in lookup.
16792 */
16793static void
16795{
16796 PGresult *res;
16797 PQExpBuffer query;
16798 int i_label;
16799 int i_provider;
16800 int i_classoid;
16801 int i_objoid;
16802 int i_objsubid;
16803 int ntups;
16804 int i;
16805 DumpableObject *dobj;
16806
16807 query = createPQExpBuffer();
16808
16810 "SELECT label, provider, classoid, objoid, objsubid "
16811 "FROM pg_catalog.pg_seclabels "
16812 "ORDER BY classoid, objoid, objsubid");
16813
16814 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16815
16816 /* Construct lookup table containing OIDs in numeric form */
16817 i_label = PQfnumber(res, "label");
16818 i_provider = PQfnumber(res, "provider");
16819 i_classoid = PQfnumber(res, "classoid");
16820 i_objoid = PQfnumber(res, "objoid");
16821 i_objsubid = PQfnumber(res, "objsubid");
16822
16823 ntups = PQntuples(res);
16824
16825 seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
16826 nseclabels = 0;
16827 dobj = NULL;
16828
16829 for (i = 0; i < ntups; i++)
16830 {
16831 CatalogId objId;
16832 int subid;
16833
16834 objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
16835 objId.oid = atooid(PQgetvalue(res, i, i_objoid));
16836 subid = atoi(PQgetvalue(res, i, i_objsubid));
16837
16838 /* We needn't remember labels that don't match any dumpable object */
16839 if (dobj == NULL ||
16840 dobj->catId.tableoid != objId.tableoid ||
16841 dobj->catId.oid != objId.oid)
16842 dobj = findObjectByCatalogId(objId);
16843 if (dobj == NULL)
16844 continue;
16845
16846 /*
16847 * Labels on columns of composite types are linked to the type's
16848 * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
16849 * in the type's own DumpableObject.
16850 */
16851 if (subid != 0 && dobj->objType == DO_TABLE &&
16852 ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
16853 {
16855
16856 cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
16857 if (cTypeInfo)
16858 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
16859 }
16860 else
16861 dobj->components |= DUMP_COMPONENT_SECLABEL;
16862
16866 seclabels[nseclabels].objoid = objId.oid;
16867 seclabels[nseclabels].objsubid = subid;
16868 nseclabels++;
16869 }
16870
16871 PQclear(res);
16872 destroyPQExpBuffer(query);
16873}
16874
16875/*
16876 * dumpTable
16877 * write out to fout the declarations (not data) of a user-defined table
16878 */
16879static void
16881{
16882 DumpOptions *dopt = fout->dopt;
16884 char *namecopy;
16885
16886 /* Do nothing if not dumping schema */
16887 if (!dopt->dumpSchema)
16888 return;
16889
16890 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16891 {
16892 if (tbinfo->relkind == RELKIND_SEQUENCE)
16894 else
16896 }
16897
16898 /* Handle the ACL here */
16899 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
16900 if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
16901 {
16902 const char *objtype =
16903 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
16904
16906 dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
16907 objtype, namecopy, NULL,
16908 tbinfo->dobj.namespace->dobj.name,
16909 NULL, tbinfo->rolname, &tbinfo->dacl);
16910 }
16911
16912 /*
16913 * Handle column ACLs, if any. Note: we pull these with a separate query
16914 * rather than trying to fetch them during getTableAttrs, so that we won't
16915 * miss ACLs on system columns. Doing it this way also allows us to dump
16916 * ACLs for catalogs that we didn't mark "interesting" back in getTables.
16917 */
16918 if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
16919 {
16921 PGresult *res;
16922 int i;
16923
16924 if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
16925 {
16926 /* Set up query for column ACLs */
16928 "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
16929
16930 if (fout->remoteVersion >= 90600)
16931 {
16932 /*
16933 * In principle we should call acldefault('c', relowner) to
16934 * get the default ACL for a column. However, we don't
16935 * currently store the numeric OID of the relowner in
16936 * TableInfo. We could convert the owner name using regrole,
16937 * but that creates a risk of failure due to concurrent role
16938 * renames. Given that the default ACL for columns is empty
16939 * and is likely to stay that way, it's not worth extra cycles
16940 * and risk to avoid hard-wiring that knowledge here.
16941 */
16943 "SELECT at.attname, "
16944 "at.attacl, "
16945 "'{}' AS acldefault, "
16946 "pip.privtype, pip.initprivs "
16947 "FROM pg_catalog.pg_attribute at "
16948 "LEFT JOIN pg_catalog.pg_init_privs pip ON "
16949 "(at.attrelid = pip.objoid "
16950 "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
16951 "AND at.attnum = pip.objsubid) "
16952 "WHERE at.attrelid = $1 AND "
16953 "NOT at.attisdropped "
16954 "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
16955 "ORDER BY at.attnum");
16956 }
16957 else
16958 {
16960 "SELECT attname, attacl, '{}' AS acldefault, "
16961 "NULL AS privtype, NULL AS initprivs "
16962 "FROM pg_catalog.pg_attribute "
16963 "WHERE attrelid = $1 AND NOT attisdropped "
16964 "AND attacl IS NOT NULL "
16965 "ORDER BY attnum");
16966 }
16967
16968 ExecuteSqlStatement(fout, query->data);
16969
16970 fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
16971 }
16972
16973 printfPQExpBuffer(query,
16974 "EXECUTE getColumnACLs('%u')",
16975 tbinfo->dobj.catId.oid);
16976
16977 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16978
16979 for (i = 0; i < PQntuples(res); i++)
16980 {
16981 char *attname = PQgetvalue(res, i, 0);
16982 char *attacl = PQgetvalue(res, i, 1);
16983 char *acldefault = PQgetvalue(res, i, 2);
16984 char privtype = *(PQgetvalue(res, i, 3));
16985 char *initprivs = PQgetvalue(res, i, 4);
16987 char *attnamecopy;
16988
16989 coldacl.acl = attacl;
16990 coldacl.acldefault = acldefault;
16991 coldacl.privtype = privtype;
16992 coldacl.initprivs = initprivs;
16994
16995 /*
16996 * Column's GRANT type is always TABLE. Each column ACL depends
16997 * on the table-level ACL, since we can restore column ACLs in
16998 * parallel but the table-level ACL has to be done first.
16999 */
17000 dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
17001 "TABLE", namecopy, attnamecopy,
17002 tbinfo->dobj.namespace->dobj.name,
17003 NULL, tbinfo->rolname, &coldacl);
17005 }
17006 PQclear(res);
17007 destroyPQExpBuffer(query);
17008 }
17009
17010 free(namecopy);
17011}
17012
17013/*
17014 * Create the AS clause for a view or materialized view. The semicolon is
17015 * stripped because a materialized view must add a WITH NO DATA clause.
17016 *
17017 * This returns a new buffer which must be freed by the caller.
17018 */
17019static PQExpBuffer
17021{
17023 PQExpBuffer result = createPQExpBuffer();
17024 PGresult *res;
17025 int len;
17026
17027 /* Fetch the view definition */
17028 appendPQExpBuffer(query,
17029 "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
17030 tbinfo->dobj.catId.oid);
17031
17032 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17033
17034 if (PQntuples(res) != 1)
17035 {
17036 if (PQntuples(res) < 1)
17037 pg_fatal("query to obtain definition of view \"%s\" returned no data",
17038 tbinfo->dobj.name);
17039 else
17040 pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
17041 tbinfo->dobj.name);
17042 }
17043
17044 len = PQgetlength(res, 0, 0);
17045
17046 if (len == 0)
17047 pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
17048 tbinfo->dobj.name);
17049
17050 /* Strip off the trailing semicolon so that other things may follow. */
17051 Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
17052 appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
17053
17054 PQclear(res);
17055 destroyPQExpBuffer(query);
17056
17057 return result;
17058}
17059
17060/*
17061 * Create a dummy AS clause for a view. This is used when the real view
17062 * definition has to be postponed because of circular dependencies.
17063 * We must duplicate the view's external properties -- column names and types
17064 * (including collation) -- so that it works for subsequent references.
17065 *
17066 * This returns a new buffer which must be freed by the caller.
17067 */
17068static PQExpBuffer
17070{
17071 PQExpBuffer result = createPQExpBuffer();
17072 int j;
17073
17074 appendPQExpBufferStr(result, "SELECT");
17075
17076 for (j = 0; j < tbinfo->numatts; j++)
17077 {
17078 if (j > 0)
17079 appendPQExpBufferChar(result, ',');
17080 appendPQExpBufferStr(result, "\n ");
17081
17082 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
17083
17084 /*
17085 * Must add collation if not default for the type, because CREATE OR
17086 * REPLACE VIEW won't change it
17087 */
17088 if (OidIsValid(tbinfo->attcollation[j]))
17089 {
17090 CollInfo *coll;
17091
17092 coll = findCollationByOid(tbinfo->attcollation[j]);
17093 if (coll)
17094 appendPQExpBuffer(result, " COLLATE %s",
17096 }
17097
17098 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
17099 }
17100
17101 return result;
17102}
17103
17104/*
17105 * dumpTableSchema
17106 * write the declaration (not data) of one user-defined table or view
17107 */
17108static void
17110{
17111 DumpOptions *dopt = fout->dopt;
17115 char *qrelname;
17116 char *qualrelname;
17117 int numParents;
17118 TableInfo **parents;
17119 int actual_atts; /* number of attrs in this CREATE statement */
17120 const char *reltypename;
17121 char *storage;
17122 int j,
17123 k;
17124
17125 /* We had better have loaded per-column details about this table */
17126 Assert(tbinfo->interesting);
17127
17128 qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
17130
17131 if (tbinfo->hasoids)
17132 pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
17133 qrelname);
17134
17135 if (dopt->binary_upgrade)
17137
17138 /* Is it a table or a view? */
17139 if (tbinfo->relkind == RELKIND_VIEW)
17140 {
17141 PQExpBuffer result;
17142
17143 /*
17144 * Note: keep this code in sync with the is_view case in dumpRule()
17145 */
17146
17147 reltypename = "VIEW";
17148
17149 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
17150
17151 if (dopt->binary_upgrade)
17153 tbinfo->dobj.catId.oid);
17154
17155 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
17156
17157 if (tbinfo->dummy_view)
17159 else
17160 {
17161 if (nonemptyReloptions(tbinfo->reloptions))
17162 {
17163 appendPQExpBufferStr(q, " WITH (");
17164 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
17165 appendPQExpBufferChar(q, ')');
17166 }
17167 result = createViewAsClause(fout, tbinfo);
17168 }
17169 appendPQExpBuffer(q, " AS\n%s", result->data);
17170 destroyPQExpBuffer(result);
17171
17172 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
17173 appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
17174 appendPQExpBufferStr(q, ";\n");
17175 }
17176 else
17177 {
17178 char *partkeydef = NULL;
17179 char *ftoptions = NULL;
17180 char *srvname = NULL;
17181 const char *foreign = "";
17182
17183 /*
17184 * Set reltypename, and collect any relkind-specific data that we
17185 * didn't fetch during getTables().
17186 */
17187 switch (tbinfo->relkind)
17188 {
17190 {
17192 PGresult *res;
17193
17194 reltypename = "TABLE";
17195
17196 /* retrieve partition key definition */
17197 appendPQExpBuffer(query,
17198 "SELECT pg_get_partkeydef('%u')",
17199 tbinfo->dobj.catId.oid);
17200 res = ExecuteSqlQueryForSingleRow(fout, query->data);
17201 partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
17202 PQclear(res);
17203 destroyPQExpBuffer(query);
17204 break;
17205 }
17207 {
17209 PGresult *res;
17210 int i_srvname;
17211 int i_ftoptions;
17212
17213 reltypename = "FOREIGN TABLE";
17214
17215 /* retrieve name of foreign server and generic options */
17216 appendPQExpBuffer(query,
17217 "SELECT fs.srvname, "
17218 "pg_catalog.array_to_string(ARRAY("
17219 "SELECT pg_catalog.quote_ident(option_name) || "
17220 "' ' || pg_catalog.quote_literal(option_value) "
17221 "FROM pg_catalog.pg_options_to_table(ftoptions) "
17222 "ORDER BY option_name"
17223 "), E',\n ') AS ftoptions "
17224 "FROM pg_catalog.pg_foreign_table ft "
17225 "JOIN pg_catalog.pg_foreign_server fs "
17226 "ON (fs.oid = ft.ftserver) "
17227 "WHERE ft.ftrelid = '%u'",
17228 tbinfo->dobj.catId.oid);
17229 res = ExecuteSqlQueryForSingleRow(fout, query->data);
17230 i_srvname = PQfnumber(res, "srvname");
17231 i_ftoptions = PQfnumber(res, "ftoptions");
17234 PQclear(res);
17235 destroyPQExpBuffer(query);
17236
17237 foreign = "FOREIGN ";
17238 break;
17239 }
17240 case RELKIND_MATVIEW:
17241 reltypename = "MATERIALIZED VIEW";
17242 break;
17243 default:
17244 reltypename = "TABLE";
17245 break;
17246 }
17247
17248 numParents = tbinfo->numParents;
17249 parents = tbinfo->parents;
17250
17251 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
17252
17253 if (dopt->binary_upgrade)
17255 tbinfo->dobj.catId.oid);
17256
17257 /*
17258 * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
17259 * ignore it when dumping if it was set in this case.
17260 */
17261 appendPQExpBuffer(q, "CREATE %s%s %s",
17262 (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
17263 tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
17264 "UNLOGGED " : "",
17266 qualrelname);
17267
17268 /*
17269 * Attach to type, if reloftype; except in case of a binary upgrade,
17270 * we dump the table normally and attach it to the type afterward.
17271 */
17272 if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
17273 appendPQExpBuffer(q, " OF %s",
17274 getFormattedTypeName(fout, tbinfo->reloftype,
17275 zeroIsError));
17276
17277 if (tbinfo->relkind != RELKIND_MATVIEW)
17278 {
17279 /* Dump the attributes */
17280 actual_atts = 0;
17281 for (j = 0; j < tbinfo->numatts; j++)
17282 {
17283 /*
17284 * Normally, dump if it's locally defined in this table, and
17285 * not dropped. But for binary upgrade, we'll dump all the
17286 * columns, and then fix up the dropped and nonlocal cases
17287 * below.
17288 */
17289 if (shouldPrintColumn(dopt, tbinfo, j))
17290 {
17291 bool print_default;
17292 bool print_notnull;
17293
17294 /*
17295 * Default value --- suppress if to be printed separately
17296 * or not at all.
17297 */
17298 print_default = (tbinfo->attrdefs[j] != NULL &&
17299 tbinfo->attrdefs[j]->dobj.dump &&
17300 !tbinfo->attrdefs[j]->separate);
17301
17302 /*
17303 * Not Null constraint --- print it if it is locally
17304 * defined, or if binary upgrade. (In the latter case, we
17305 * reset conislocal below.)
17306 */
17307 print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
17308 (tbinfo->notnull_islocal[j] ||
17309 dopt->binary_upgrade ||
17310 tbinfo->ispartition));
17311
17312 /*
17313 * Skip column if fully defined by reloftype, except in
17314 * binary upgrade
17315 */
17316 if (OidIsValid(tbinfo->reloftype) &&
17318 !dopt->binary_upgrade)
17319 continue;
17320
17321 /* Format properly if not first attr */
17322 if (actual_atts == 0)
17323 appendPQExpBufferStr(q, " (");
17324 else
17325 appendPQExpBufferChar(q, ',');
17326 appendPQExpBufferStr(q, "\n ");
17327 actual_atts++;
17328
17329 /* Attribute name */
17330 appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
17331
17332 if (tbinfo->attisdropped[j])
17333 {
17334 /*
17335 * ALTER TABLE DROP COLUMN clears
17336 * pg_attribute.atttypid, so we will not have gotten a
17337 * valid type name; insert INTEGER as a stopgap. We'll
17338 * clean things up later.
17339 */
17340 appendPQExpBufferStr(q, " INTEGER /* dummy */");
17341 /* and skip to the next column */
17342 continue;
17343 }
17344
17345 /*
17346 * Attribute type; print it except when creating a typed
17347 * table ('OF type_name'), but in binary-upgrade mode,
17348 * print it in that case too.
17349 */
17350 if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
17351 {
17352 appendPQExpBuffer(q, " %s",
17353 tbinfo->atttypnames[j]);
17354 }
17355
17356 if (print_default)
17357 {
17358 if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
17359 appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
17360 tbinfo->attrdefs[j]->adef_expr);
17361 else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
17362 appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
17363 tbinfo->attrdefs[j]->adef_expr);
17364 else
17365 appendPQExpBuffer(q, " DEFAULT %s",
17366 tbinfo->attrdefs[j]->adef_expr);
17367 }
17368
17369 if (print_notnull)
17370 {
17371 if (tbinfo->notnull_constrs[j][0] == '\0')
17372 appendPQExpBufferStr(q, " NOT NULL");
17373 else
17374 appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
17375 fmtId(tbinfo->notnull_constrs[j]));
17376
17377 if (tbinfo->notnull_noinh[j])
17378 appendPQExpBufferStr(q, " NO INHERIT");
17379 }
17380
17381 /* Add collation if not default for the type */
17382 if (OidIsValid(tbinfo->attcollation[j]))
17383 {
17384 CollInfo *coll;
17385
17386 coll = findCollationByOid(tbinfo->attcollation[j]);
17387 if (coll)
17388 appendPQExpBuffer(q, " COLLATE %s",
17390 }
17391 }
17392
17393 /*
17394 * On the other hand, if we choose not to print a column
17395 * (likely because it is created by inheritance), but the
17396 * column has a locally-defined not-null constraint, we need
17397 * to dump the constraint as a standalone object.
17398 *
17399 * This syntax isn't SQL-conforming, but if you wanted
17400 * standard output you wouldn't be creating non-standard
17401 * objects to begin with.
17402 */
17403 if (!shouldPrintColumn(dopt, tbinfo, j) &&
17404 !tbinfo->attisdropped[j] &&
17405 tbinfo->notnull_constrs[j] != NULL &&
17406 tbinfo->notnull_islocal[j])
17407 {
17408 /* Format properly if not first attr */
17409 if (actual_atts == 0)
17410 appendPQExpBufferStr(q, " (");
17411 else
17412 appendPQExpBufferChar(q, ',');
17413 appendPQExpBufferStr(q, "\n ");
17414 actual_atts++;
17415
17416 if (tbinfo->notnull_constrs[j][0] == '\0')
17417 appendPQExpBuffer(q, "NOT NULL %s",
17418 fmtId(tbinfo->attnames[j]));
17419 else
17420 appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
17421 tbinfo->notnull_constrs[j],
17422 fmtId(tbinfo->attnames[j]));
17423 }
17424 }
17425
17426 /*
17427 * Add non-inherited CHECK constraints, if any.
17428 *
17429 * For partitions, we need to include check constraints even if
17430 * they're not defined locally, because the ALTER TABLE ATTACH
17431 * PARTITION that we'll emit later expects the constraint to be
17432 * there. (No need to fix conislocal: ATTACH PARTITION does that)
17433 */
17434 for (j = 0; j < tbinfo->ncheck; j++)
17435 {
17436 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
17437
17438 if (constr->separate ||
17439 (!constr->conislocal && !tbinfo->ispartition))
17440 continue;
17441
17442 if (actual_atts == 0)
17443 appendPQExpBufferStr(q, " (\n ");
17444 else
17445 appendPQExpBufferStr(q, ",\n ");
17446
17447 appendPQExpBuffer(q, "CONSTRAINT %s ",
17448 fmtId(constr->dobj.name));
17449 appendPQExpBufferStr(q, constr->condef);
17450
17451 actual_atts++;
17452 }
17453
17454 if (actual_atts)
17455 appendPQExpBufferStr(q, "\n)");
17456 else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
17457 {
17458 /*
17459 * No attributes? we must have a parenthesized attribute list,
17460 * even though empty, when not using the OF TYPE syntax.
17461 */
17462 appendPQExpBufferStr(q, " (\n)");
17463 }
17464
17465 /*
17466 * Emit the INHERITS clause (not for partitions), except in
17467 * binary-upgrade mode.
17468 */
17469 if (numParents > 0 && !tbinfo->ispartition &&
17470 !dopt->binary_upgrade)
17471 {
17472 appendPQExpBufferStr(q, "\nINHERITS (");
17473 for (k = 0; k < numParents; k++)
17474 {
17475 TableInfo *parentRel = parents[k];
17476
17477 if (k > 0)
17478 appendPQExpBufferStr(q, ", ");
17480 }
17481 appendPQExpBufferChar(q, ')');
17482 }
17483
17484 if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
17485 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
17486
17487 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
17488 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
17489 }
17490
17491 if (nonemptyReloptions(tbinfo->reloptions) ||
17492 nonemptyReloptions(tbinfo->toast_reloptions))
17493 {
17494 bool addcomma = false;
17495
17496 appendPQExpBufferStr(q, "\nWITH (");
17497 if (nonemptyReloptions(tbinfo->reloptions))
17498 {
17499 addcomma = true;
17500 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
17501 }
17502 if (nonemptyReloptions(tbinfo->toast_reloptions))
17503 {
17504 if (addcomma)
17505 appendPQExpBufferStr(q, ", ");
17506 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
17507 fout);
17508 }
17509 appendPQExpBufferChar(q, ')');
17510 }
17511
17512 /* Dump generic options if any */
17513 if (ftoptions && ftoptions[0])
17514 appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
17515
17516 /*
17517 * For materialized views, create the AS clause just like a view. At
17518 * this point, we always mark the view as not populated.
17519 */
17520 if (tbinfo->relkind == RELKIND_MATVIEW)
17521 {
17522 PQExpBuffer result;
17523
17524 result = createViewAsClause(fout, tbinfo);
17525 appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
17526 result->data);
17527 destroyPQExpBuffer(result);
17528 }
17529 else
17530 appendPQExpBufferStr(q, ";\n");
17531
17532 /* Materialized views can depend on extensions */
17533 if (tbinfo->relkind == RELKIND_MATVIEW)
17535 "pg_catalog.pg_class",
17536 "MATERIALIZED VIEW",
17537 qualrelname);
17538
17539 /*
17540 * in binary upgrade mode, update the catalog with any missing values
17541 * that might be present.
17542 */
17543 if (dopt->binary_upgrade)
17544 {
17545 for (j = 0; j < tbinfo->numatts; j++)
17546 {
17547 if (tbinfo->attmissingval[j][0] != '\0')
17548 {
17549 appendPQExpBufferStr(q, "\n-- set missing value.\n");
17551 "SELECT pg_catalog.binary_upgrade_set_missing_value(");
17553 appendPQExpBufferStr(q, "::pg_catalog.regclass,");
17554 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17555 appendPQExpBufferChar(q, ',');
17556 appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
17557 appendPQExpBufferStr(q, ");\n\n");
17558 }
17559 }
17560 }
17561
17562 /*
17563 * To create binary-compatible heap files, we have to ensure the same
17564 * physical column order, including dropped columns, as in the
17565 * original. Therefore, we create dropped columns above and drop them
17566 * here, also updating their attlen/attalign values so that the
17567 * dropped column can be skipped properly. (We do not bother with
17568 * restoring the original attbyval setting.) Also, inheritance
17569 * relationships are set up by doing ALTER TABLE INHERIT rather than
17570 * using an INHERITS clause --- the latter would possibly mess up the
17571 * column order. That also means we have to take care about setting
17572 * attislocal correctly, plus fix up any inherited CHECK constraints.
17573 * Analogously, we set up typed tables using ALTER TABLE / OF here.
17574 *
17575 * We process foreign and partitioned tables here, even though they
17576 * lack heap storage, because they can participate in inheritance
17577 * relationships and we want this stuff to be consistent across the
17578 * inheritance tree. We can exclude indexes, toast tables, sequences
17579 * and matviews, even though they have storage, because we don't
17580 * support altering or dropping columns in them, nor can they be part
17581 * of inheritance trees.
17582 */
17583 if (dopt->binary_upgrade &&
17584 (tbinfo->relkind == RELKIND_RELATION ||
17585 tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
17586 tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
17587 {
17588 bool firstitem;
17589 bool firstitem_extra;
17590
17591 /*
17592 * Drop any dropped columns. Merge the pg_attribute manipulations
17593 * into a single SQL command, so that we don't cause repeated
17594 * relcache flushes on the target table. Otherwise we risk O(N^2)
17595 * relcache bloat while dropping N columns.
17596 */
17597 resetPQExpBuffer(extra);
17598 firstitem = true;
17599 for (j = 0; j < tbinfo->numatts; j++)
17600 {
17601 if (tbinfo->attisdropped[j])
17602 {
17603 if (firstitem)
17604 {
17605 appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
17606 "UPDATE pg_catalog.pg_attribute\n"
17607 "SET attlen = v.dlen, "
17608 "attalign = v.dalign, "
17609 "attbyval = false\n"
17610 "FROM (VALUES ");
17611 firstitem = false;
17612 }
17613 else
17614 appendPQExpBufferStr(q, ",\n ");
17615 appendPQExpBufferChar(q, '(');
17616 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17617 appendPQExpBuffer(q, ", %d, '%c')",
17618 tbinfo->attlen[j],
17619 tbinfo->attalign[j]);
17620 /* The ALTER ... DROP COLUMN commands must come after */
17621 appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
17623 appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
17624 fmtId(tbinfo->attnames[j]));
17625 }
17626 }
17627 if (!firstitem)
17628 {
17629 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
17630 "WHERE attrelid = ");
17632 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
17633 " AND attname = v.dname;\n");
17634 /* Now we can issue the actual DROP COLUMN commands */
17635 appendBinaryPQExpBuffer(q, extra->data, extra->len);
17636 }
17637
17638 /*
17639 * Fix up inherited columns. As above, do the pg_attribute
17640 * manipulations in a single SQL command.
17641 */
17642 firstitem = true;
17643 for (j = 0; j < tbinfo->numatts; j++)
17644 {
17645 if (!tbinfo->attisdropped[j] &&
17646 !tbinfo->attislocal[j])
17647 {
17648 if (firstitem)
17649 {
17650 appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
17651 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
17652 "SET attislocal = false\n"
17653 "WHERE attrelid = ");
17655 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
17656 " AND attname IN (");
17657 firstitem = false;
17658 }
17659 else
17660 appendPQExpBufferStr(q, ", ");
17661 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17662 }
17663 }
17664 if (!firstitem)
17665 appendPQExpBufferStr(q, ");\n");
17666
17667 /*
17668 * Fix up not-null constraints that come from inheritance. As
17669 * above, do the pg_constraint manipulations in a single SQL
17670 * command. (Actually, two in special cases, if we're doing an
17671 * upgrade from < 18).
17672 */
17673 firstitem = true;
17674 firstitem_extra = true;
17675 resetPQExpBuffer(extra);
17676 for (j = 0; j < tbinfo->numatts; j++)
17677 {
17678 /*
17679 * If a not-null constraint comes from inheritance, reset
17680 * conislocal. The inhcount is fixed by ALTER TABLE INHERIT,
17681 * below. Special hack: in versions < 18, columns with no
17682 * local definition need their constraint to be matched by
17683 * column number in conkeys instead of by constraint name,
17684 * because the latter is not available. (We distinguish the
17685 * case because the constraint name is the empty string.)
17686 */
17687 if (tbinfo->notnull_constrs[j] != NULL &&
17688 !tbinfo->notnull_islocal[j])
17689 {
17690 if (tbinfo->notnull_constrs[j][0] != '\0')
17691 {
17692 if (firstitem)
17693 {
17694 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
17695 "SET conislocal = false\n"
17696 "WHERE contype = 'n' AND conrelid = ");
17698 appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
17699 "conname IN (");
17700 firstitem = false;
17701 }
17702 else
17703 appendPQExpBufferStr(q, ", ");
17704 appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
17705 }
17706 else
17707 {
17708 if (firstitem_extra)
17709 {
17710 appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
17711 "SET conislocal = false\n"
17712 "WHERE contype = 'n' AND conrelid = ");
17714 appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
17715 "conkey IN (");
17716 firstitem_extra = false;
17717 }
17718 else
17719 appendPQExpBufferStr(extra, ", ");
17720 appendPQExpBuffer(extra, "'{%d}'", j + 1);
17721 }
17722 }
17723 }
17724 if (!firstitem)
17725 appendPQExpBufferStr(q, ");\n");
17726 if (!firstitem_extra)
17727 appendPQExpBufferStr(extra, ");\n");
17728
17729 if (extra->len > 0)
17730 appendBinaryPQExpBuffer(q, extra->data, extra->len);
17731
17732 /*
17733 * Add inherited CHECK constraints, if any.
17734 *
17735 * For partitions, they were already dumped, and conislocal
17736 * doesn't need fixing.
17737 *
17738 * As above, issue only one direct manipulation of pg_constraint.
17739 * Although it is tempting to merge the ALTER ADD CONSTRAINT
17740 * commands into one as well, refrain for now due to concern about
17741 * possible backend memory bloat if there are many such
17742 * constraints.
17743 */
17744 resetPQExpBuffer(extra);
17745 firstitem = true;
17746 for (k = 0; k < tbinfo->ncheck; k++)
17747 {
17748 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
17749
17750 if (constr->separate || constr->conislocal || tbinfo->ispartition)
17751 continue;
17752
17753 if (firstitem)
17754 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
17755 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
17757 fmtId(constr->dobj.name),
17758 constr->condef);
17759 /* Update pg_constraint after all the ALTER TABLEs */
17760 if (firstitem)
17761 {
17762 appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
17763 "SET conislocal = false\n"
17764 "WHERE contype = 'c' AND conrelid = ");
17766 appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
17767 appendPQExpBufferStr(extra, " AND conname IN (");
17768 firstitem = false;
17769 }
17770 else
17771 appendPQExpBufferStr(extra, ", ");
17772 appendStringLiteralAH(extra, constr->dobj.name, fout);
17773 }
17774 if (!firstitem)
17775 {
17776 appendPQExpBufferStr(extra, ");\n");
17777 appendBinaryPQExpBuffer(q, extra->data, extra->len);
17778 }
17779
17780 if (numParents > 0 && !tbinfo->ispartition)
17781 {
17782 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
17783 for (k = 0; k < numParents; k++)
17784 {
17785 TableInfo *parentRel = parents[k];
17786
17787 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
17790 }
17791 }
17792
17793 if (OidIsValid(tbinfo->reloftype))
17794 {
17795 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
17796 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
17798 getFormattedTypeName(fout, tbinfo->reloftype,
17799 zeroIsError));
17800 }
17801 }
17802
17803 /*
17804 * In binary_upgrade mode, arrange to restore the old relfrozenxid and
17805 * relminmxid of all vacuumable relations. (While vacuum.c processes
17806 * TOAST tables semi-independently, here we see them only as children
17807 * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
17808 * child toast table is handled below.)
17809 */
17810 if (dopt->binary_upgrade &&
17811 (tbinfo->relkind == RELKIND_RELATION ||
17812 tbinfo->relkind == RELKIND_MATVIEW))
17813 {
17814 appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
17815 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
17816 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
17817 "WHERE oid = ",
17818 tbinfo->frozenxid, tbinfo->minmxid);
17820 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
17821
17822 if (tbinfo->toast_oid)
17823 {
17824 /*
17825 * The toast table will have the same OID at restore, so we
17826 * can safely target it by OID.
17827 */
17828 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
17829 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
17830 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
17831 "WHERE oid = '%u';\n",
17832 tbinfo->toast_frozenxid,
17833 tbinfo->toast_minmxid, tbinfo->toast_oid);
17834 }
17835 }
17836
17837 /*
17838 * In binary_upgrade mode, restore matviews' populated status by
17839 * poking pg_class directly. This is pretty ugly, but we can't use
17840 * REFRESH MATERIALIZED VIEW since it's possible that some underlying
17841 * matview is not populated even though this matview is; in any case,
17842 * we want to transfer the matview's heap storage, not run REFRESH.
17843 */
17844 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
17845 tbinfo->relispopulated)
17846 {
17847 appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
17848 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
17849 "SET relispopulated = 't'\n"
17850 "WHERE oid = ");
17852 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
17853 }
17854
17855 /*
17856 * Dump additional per-column properties that we can't handle in the
17857 * main CREATE TABLE command.
17858 */
17859 for (j = 0; j < tbinfo->numatts; j++)
17860 {
17861 /* None of this applies to dropped columns */
17862 if (tbinfo->attisdropped[j])
17863 continue;
17864
17865 /*
17866 * Dump per-column statistics information. We only issue an ALTER
17867 * TABLE statement if the attstattarget entry for this column is
17868 * not the default value.
17869 */
17870 if (tbinfo->attstattarget[j] >= 0)
17871 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
17873 fmtId(tbinfo->attnames[j]),
17874 tbinfo->attstattarget[j]);
17875
17876 /*
17877 * Dump per-column storage information. The statement is only
17878 * dumped if the storage has been changed from the type's default.
17879 */
17880 if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
17881 {
17882 switch (tbinfo->attstorage[j])
17883 {
17884 case TYPSTORAGE_PLAIN:
17885 storage = "PLAIN";
17886 break;
17888 storage = "EXTERNAL";
17889 break;
17891 storage = "EXTENDED";
17892 break;
17893 case TYPSTORAGE_MAIN:
17894 storage = "MAIN";
17895 break;
17896 default:
17897 storage = NULL;
17898 }
17899
17900 /*
17901 * Only dump the statement if it's a storage type we recognize
17902 */
17903 if (storage != NULL)
17904 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
17906 fmtId(tbinfo->attnames[j]),
17907 storage);
17908 }
17909
17910 /*
17911 * Dump per-column compression, if it's been set.
17912 */
17913 if (!dopt->no_toast_compression)
17914 {
17915 const char *cmname;
17916
17917 switch (tbinfo->attcompression[j])
17918 {
17919 case 'p':
17920 cmname = "pglz";
17921 break;
17922 case 'l':
17923 cmname = "lz4";
17924 break;
17925 default:
17926 cmname = NULL;
17927 break;
17928 }
17929
17930 if (cmname != NULL)
17931 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
17933 fmtId(tbinfo->attnames[j]),
17934 cmname);
17935 }
17936
17937 /*
17938 * Dump per-column attributes.
17939 */
17940 if (tbinfo->attoptions[j][0] != '\0')
17941 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
17943 fmtId(tbinfo->attnames[j]),
17944 tbinfo->attoptions[j]);
17945
17946 /*
17947 * Dump per-column fdw options.
17948 */
17949 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
17950 tbinfo->attfdwoptions[j][0] != '\0')
17952 "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
17953 " %s\n"
17954 ");\n",
17956 fmtId(tbinfo->attnames[j]),
17957 tbinfo->attfdwoptions[j]);
17958 } /* end loop over columns */
17959
17961 free(ftoptions);
17962 free(srvname);
17963 }
17964
17965 /*
17966 * dump properties we only have ALTER TABLE syntax for
17967 */
17968 if ((tbinfo->relkind == RELKIND_RELATION ||
17969 tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
17970 tbinfo->relkind == RELKIND_MATVIEW) &&
17971 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
17972 {
17973 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
17974 {
17975 /* nothing to do, will be set when the index is dumped */
17976 }
17977 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
17978 {
17979 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
17980 qualrelname);
17981 }
17982 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
17983 {
17984 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
17985 qualrelname);
17986 }
17987 }
17988
17989 if (tbinfo->forcerowsec)
17990 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
17991 qualrelname);
17992
17993 if (dopt->binary_upgrade)
17996 tbinfo->dobj.namespace->dobj.name);
17997
17998 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17999 {
18000 char *tablespace = NULL;
18001 char *tableam = NULL;
18002
18003 /*
18004 * _selectTablespace() relies on tablespace-enabled objects in the
18005 * default tablespace to have a tablespace of "" (empty string) versus
18006 * non-tablespace-enabled objects to have a tablespace of NULL.
18007 * getTables() sets tbinfo->reltablespace to "" for the default
18008 * tablespace (not NULL).
18009 */
18010 if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
18011 tablespace = tbinfo->reltablespace;
18012
18013 if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
18015 tableam = tbinfo->amname;
18016
18017 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
18018 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
18019 .namespace = tbinfo->dobj.namespace->dobj.name,
18020 .tablespace = tablespace,
18021 .tableam = tableam,
18022 .relkind = tbinfo->relkind,
18023 .owner = tbinfo->rolname,
18024 .description = reltypename,
18025 .section = tbinfo->postponed_def ?
18027 .createStmt = q->data,
18028 .dropStmt = delq->data));
18029 }
18030
18031 /* Dump Table Comments */
18032 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18034
18035 /* Dump Table Security Labels */
18036 if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
18038
18039 /*
18040 * Dump comments for not-null constraints that aren't to be dumped
18041 * separately (those are processed by collectComments/dumpComment).
18042 */
18043 if (!fout->dopt->no_comments && dopt->dumpSchema &&
18044 fout->remoteVersion >= 180000)
18045 {
18047 PQExpBuffer tag = NULL;
18048
18049 for (j = 0; j < tbinfo->numatts; j++)
18050 {
18051 if (tbinfo->notnull_constrs[j] != NULL &&
18052 tbinfo->notnull_comment[j] != NULL)
18053 {
18054 if (comment == NULL)
18055 {
18057 tag = createPQExpBuffer();
18058 }
18059 else
18060 {
18062 resetPQExpBuffer(tag);
18063 }
18064
18065 appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
18066 fmtId(tbinfo->notnull_constrs[j]), qualrelname);
18067 appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
18069
18070 appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
18071 fmtId(tbinfo->notnull_constrs[j]), qrelname);
18072
18074 ARCHIVE_OPTS(.tag = tag->data,
18075 .namespace = tbinfo->dobj.namespace->dobj.name,
18076 .owner = tbinfo->rolname,
18077 .description = "COMMENT",
18078 .section = SECTION_NONE,
18079 .createStmt = comment->data,
18080 .deps = &(tbinfo->dobj.dumpId),
18081 .nDeps = 1));
18082 }
18083 }
18084
18086 destroyPQExpBuffer(tag);
18087 }
18088
18089 /* Dump comments on inlined table constraints */
18090 for (j = 0; j < tbinfo->ncheck; j++)
18091 {
18092 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
18093
18094 if (constr->separate || !constr->conislocal)
18095 continue;
18096
18097 if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
18099 }
18100
18103 destroyPQExpBuffer(extra);
18104 free(qrelname);
18106}
18107
18108/*
18109 * dumpTableAttach
18110 * write to fout the commands to attach a child partition
18111 *
18112 * Child partitions are always made by creating them separately
18113 * and then using ATTACH PARTITION, rather than using
18114 * CREATE TABLE ... PARTITION OF. This is important for preserving
18115 * any possible discrepancy in column layout, to allow assigning the
18116 * correct tablespace if different, and so that it's possible to restore
18117 * a partition without restoring its parent. (You'll get an error from
18118 * the ATTACH PARTITION command, but that can be ignored, or skipped
18119 * using "pg_restore -L" if you prefer.) The last point motivates
18120 * treating ATTACH PARTITION as a completely separate ArchiveEntry
18121 * rather than emitting it within the child partition's ArchiveEntry.
18122 */
18123static void
18125{
18126 DumpOptions *dopt = fout->dopt;
18127 PQExpBuffer q;
18128 PGresult *res;
18129 char *partbound;
18130
18131 /* Do nothing if not dumping schema */
18132 if (!dopt->dumpSchema)
18133 return;
18134
18135 q = createPQExpBuffer();
18136
18137 if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
18138 {
18139 /* Set up query for partbound details */
18141 "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
18142
18144 "SELECT pg_get_expr(c.relpartbound, c.oid) "
18145 "FROM pg_class c "
18146 "WHERE c.oid = $1");
18147
18149
18150 fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
18151 }
18152
18154 "EXECUTE dumpTableAttach('%u')",
18155 attachinfo->partitionTbl->dobj.catId.oid);
18156
18158 partbound = PQgetvalue(res, 0, 0);
18159
18160 /* Perform ALTER TABLE on the parent */
18162 "ALTER TABLE ONLY %s ",
18163 fmtQualifiedDumpable(attachinfo->parentTbl));
18165 "ATTACH PARTITION %s %s;\n",
18166 fmtQualifiedDumpable(attachinfo->partitionTbl),
18167 partbound);
18168
18169 /*
18170 * There is no point in creating a drop query as the drop is done by table
18171 * drop. (If you think to change this, see also _printTocEntry().)
18172 * Although this object doesn't really have ownership as such, set the
18173 * owner field anyway to ensure that the command is run by the correct
18174 * role at restore time.
18175 */
18176 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
18177 ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
18178 .namespace = attachinfo->dobj.namespace->dobj.name,
18179 .owner = attachinfo->partitionTbl->rolname,
18180 .description = "TABLE ATTACH",
18181 .section = SECTION_PRE_DATA,
18182 .createStmt = q->data));
18183
18184 PQclear(res);
18186}
18187
18188/*
18189 * dumpAttrDef --- dump an attribute's default-value declaration
18190 */
18191static void
18193{
18194 DumpOptions *dopt = fout->dopt;
18195 TableInfo *tbinfo = adinfo->adtable;
18196 int adnum = adinfo->adnum;
18197 PQExpBuffer q;
18199 char *qualrelname;
18200 char *tag;
18201 char *foreign;
18202
18203 /* Do nothing if not dumping schema */
18204 if (!dopt->dumpSchema)
18205 return;
18206
18207 /* Skip if not "separate"; it was dumped in the table's definition */
18208 if (!adinfo->separate)
18209 return;
18210
18211 q = createPQExpBuffer();
18213
18215
18216 foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
18217
18219 "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
18220 foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
18221 adinfo->adef_expr);
18222
18223 appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
18225 fmtId(tbinfo->attnames[adnum - 1]));
18226
18227 tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
18228
18229 if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18230 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
18231 ARCHIVE_OPTS(.tag = tag,
18232 .namespace = tbinfo->dobj.namespace->dobj.name,
18233 .owner = tbinfo->rolname,
18234 .description = "DEFAULT",
18235 .section = SECTION_PRE_DATA,
18236 .createStmt = q->data,
18237 .dropStmt = delq->data));
18238
18239 free(tag);
18243}
18244
18245/*
18246 * getAttrName: extract the correct name for an attribute
18247 *
18248 * The array tblInfo->attnames[] only provides names of user attributes;
18249 * if a system attribute number is supplied, we have to fake it.
18250 * We also do a little bit of bounds checking for safety's sake.
18251 */
18252static const char *
18253getAttrName(int attrnum, const TableInfo *tblInfo)
18254{
18255 if (attrnum > 0 && attrnum <= tblInfo->numatts)
18256 return tblInfo->attnames[attrnum - 1];
18257 switch (attrnum)
18258 {
18260 return "ctid";
18262 return "xmin";
18264 return "cmin";
18266 return "xmax";
18268 return "cmax";
18270 return "tableoid";
18271 }
18272 pg_fatal("invalid column number %d for table \"%s\"",
18273 attrnum, tblInfo->dobj.name);
18274 return NULL; /* keep compiler quiet */
18275}
18276
18277/*
18278 * dumpIndex
18279 * write out to fout a user-defined index
18280 */
18281static void
18283{
18284 DumpOptions *dopt = fout->dopt;
18285 TableInfo *tbinfo = indxinfo->indextable;
18286 bool is_constraint = (indxinfo->indexconstraint != 0);
18287 PQExpBuffer q;
18289 char *qindxname;
18290 char *qqindxname;
18291
18292 /* Do nothing if not dumping schema */
18293 if (!dopt->dumpSchema)
18294 return;
18295
18296 q = createPQExpBuffer();
18298
18299 qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
18301
18302 /*
18303 * If there's an associated constraint, don't dump the index per se, but
18304 * do dump any comment for it. (This is safe because dependency ordering
18305 * will have ensured the constraint is emitted first.) Note that the
18306 * emitted comment has to be shown as depending on the constraint, not the
18307 * index, in such cases.
18308 */
18309 if (!is_constraint)
18310 {
18311 char *indstatcols = indxinfo->indstatcols;
18312 char *indstatvals = indxinfo->indstatvals;
18313 char **indstatcolsarray = NULL;
18314 char **indstatvalsarray = NULL;
18315 int nstatcols = 0;
18316 int nstatvals = 0;
18317
18318 if (dopt->binary_upgrade)
18320 indxinfo->dobj.catId.oid);
18321
18322 /* Plain secondary index */
18323 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
18324
18325 /*
18326 * Append ALTER TABLE commands as needed to set properties that we
18327 * only have ALTER TABLE syntax for. Keep this in sync with the
18328 * similar code in dumpConstraint!
18329 */
18330
18331 /* If the index is clustered, we need to record that. */
18332 if (indxinfo->indisclustered)
18333 {
18334 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
18336 /* index name is not qualified in this syntax */
18337 appendPQExpBuffer(q, " ON %s;\n",
18338 qindxname);
18339 }
18340
18341 /*
18342 * If the index has any statistics on some of its columns, generate
18343 * the associated ALTER INDEX queries.
18344 */
18345 if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
18346 {
18347 int j;
18348
18349 if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
18350 pg_fatal("could not parse index statistic columns");
18351 if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
18352 pg_fatal("could not parse index statistic values");
18353 if (nstatcols != nstatvals)
18354 pg_fatal("mismatched number of columns and values for index statistics");
18355
18356 for (j = 0; j < nstatcols; j++)
18357 {
18358 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
18359
18360 /*
18361 * Note that this is a column number, so no quotes should be
18362 * used.
18363 */
18364 appendPQExpBuffer(q, "ALTER COLUMN %s ",
18366 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
18368 }
18369 }
18370
18371 /* Indexes can depend on extensions */
18373 "pg_catalog.pg_class",
18374 "INDEX", qqindxname);
18375
18376 /* If the index defines identity, we need to record that. */
18377 if (indxinfo->indisreplident)
18378 {
18379 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
18381 /* index name is not qualified in this syntax */
18382 appendPQExpBuffer(q, " INDEX %s;\n",
18383 qindxname);
18384 }
18385
18386 /*
18387 * If this index is a member of a partitioned index, the backend will
18388 * not allow us to drop it separately, so don't try. It will go away
18389 * automatically when we drop either the index's table or the
18390 * partitioned index. (If, in a selective restore with --clean, we
18391 * drop neither of those, then this index will not be dropped either.
18392 * But that's fine, and even if you think it's not, the backend won't
18393 * let us do differently.)
18394 */
18395 if (indxinfo->parentidx == 0)
18396 appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
18397
18398 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18399 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
18400 ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
18401 .namespace = tbinfo->dobj.namespace->dobj.name,
18402 .tablespace = indxinfo->tablespace,
18403 .owner = tbinfo->rolname,
18404 .description = "INDEX",
18405 .section = SECTION_POST_DATA,
18406 .createStmt = q->data,
18407 .dropStmt = delq->data));
18408
18411 }
18412
18413 /* Dump Index Comments */
18414 if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18415 dumpComment(fout, "INDEX", qindxname,
18416 tbinfo->dobj.namespace->dobj.name,
18417 tbinfo->rolname,
18418 indxinfo->dobj.catId, 0,
18419 is_constraint ? indxinfo->indexconstraint :
18420 indxinfo->dobj.dumpId);
18421
18424 free(qindxname);
18426}
18427
18428/*
18429 * dumpIndexAttach
18430 * write out to fout a partitioned-index attachment clause
18431 */
18432static void
18434{
18435 /* Do nothing if not dumping schema */
18436 if (!fout->dopt->dumpSchema)
18437 return;
18438
18439 if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
18440 {
18442
18443 appendPQExpBuffer(q, "ALTER INDEX %s ",
18444 fmtQualifiedDumpable(attachinfo->parentIdx));
18445 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
18446 fmtQualifiedDumpable(attachinfo->partitionIdx));
18447
18448 /*
18449 * There is no need for a dropStmt since the drop is done implicitly
18450 * when we drop either the index's table or the partitioned index.
18451 * Moreover, since there's no ALTER INDEX DETACH PARTITION command,
18452 * there's no way to do it anyway. (If you think to change this,
18453 * consider also what to do with --if-exists.)
18454 *
18455 * Although this object doesn't really have ownership as such, set the
18456 * owner field anyway to ensure that the command is run by the correct
18457 * role at restore time.
18458 */
18459 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
18460 ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
18461 .namespace = attachinfo->dobj.namespace->dobj.name,
18462 .owner = attachinfo->parentIdx->indextable->rolname,
18463 .description = "INDEX ATTACH",
18464 .section = SECTION_POST_DATA,
18465 .createStmt = q->data));
18466
18468 }
18469}
18470
18471/*
18472 * dumpStatisticsExt
18473 * write out to fout an extended statistics object
18474 */
18475static void
18477{
18478 DumpOptions *dopt = fout->dopt;
18479 PQExpBuffer q;
18481 PQExpBuffer query;
18482 char *qstatsextname;
18483 PGresult *res;
18484 char *stxdef;
18485
18486 /* Do nothing if not dumping schema */
18487 if (!dopt->dumpSchema)
18488 return;
18489
18490 q = createPQExpBuffer();
18492 query = createPQExpBuffer();
18493
18495
18496 appendPQExpBuffer(query, "SELECT "
18497 "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
18498 statsextinfo->dobj.catId.oid);
18499
18500 res = ExecuteSqlQueryForSingleRow(fout, query->data);
18501
18502 stxdef = PQgetvalue(res, 0, 0);
18503
18504 /* Result of pg_get_statisticsobjdef is complete except for semicolon */
18505 appendPQExpBuffer(q, "%s;\n", stxdef);
18506
18507 /*
18508 * We only issue an ALTER STATISTICS statement if the stxstattarget entry
18509 * for this statistics object is not the default value.
18510 */
18511 if (statsextinfo->stattarget >= 0)
18512 {
18513 appendPQExpBuffer(q, "ALTER STATISTICS %s ",
18515 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
18516 statsextinfo->stattarget);
18517 }
18518
18519 appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
18521
18522 if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18523 ArchiveEntry(fout, statsextinfo->dobj.catId,
18524 statsextinfo->dobj.dumpId,
18525 ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
18526 .namespace = statsextinfo->dobj.namespace->dobj.name,
18527 .owner = statsextinfo->rolname,
18528 .description = "STATISTICS",
18529 .section = SECTION_POST_DATA,
18530 .createStmt = q->data,
18531 .dropStmt = delq->data));
18532
18533 /* Dump Statistics Comments */
18534 if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18535 dumpComment(fout, "STATISTICS", qstatsextname,
18536 statsextinfo->dobj.namespace->dobj.name,
18537 statsextinfo->rolname,
18538 statsextinfo->dobj.catId, 0,
18539 statsextinfo->dobj.dumpId);
18540
18541 PQclear(res);
18544 destroyPQExpBuffer(query);
18546}
18547
18548/*
18549 * dumpStatisticsExtStats
18550 * write out to fout the stats for an extended statistics object
18551 */
18552static void
18554{
18555 DumpOptions *dopt = fout->dopt;
18556 PQExpBuffer query;
18557 PGresult *res;
18558 int nstats;
18559
18560 /* Do nothing if not dumping statistics */
18561 if (!dopt->dumpStatistics)
18562 return;
18563
18564 if (!fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS])
18565 {
18567
18568 /*---------
18569 * Set up query for details about extended statistics objects.
18570 *
18571 * The query depends on the backend version:
18572 * - In v19 and newer versions, query directly the pg_stats_ext*
18573 * catalogs.
18574 * - In v18 and older versions, ndistinct and dependencies have a
18575 * different format that needs translation.
18576 * - In v14 and older versions, inherited does not exist.
18577 * - In v11 and older versions, there is no pg_stats_ext, hence
18578 * the logic joins pg_statistic_ext and pg_namespace.
18579 *---------
18580 */
18581
18583 "PREPARE getExtStatsStats(pg_catalog.name, pg_catalog.name) AS\n"
18584 "SELECT ");
18585
18586 /*
18587 * Versions 15 and newer have inherited stats.
18588 *
18589 * Create this column in all versions because we need to order by it
18590 * later.
18591 */
18592 if (fout->remoteVersion >= 150000)
18593 appendPQExpBufferStr(pq, "e.inherited, ");
18594 else
18595 appendPQExpBufferStr(pq, "false AS inherited, ");
18596
18597 /*--------
18598 * The ndistinct and dependencies formats changed in v19, so
18599 * everything before that needs to be translated.
18600 *
18601 * The ndistinct translation converts this kind of data:
18602 * {"3, 4": 11, "3, 6": 11, "4, 6": 11, "3, 4, 6": 11}
18603 *
18604 * to this:
18605 * [ {"attributes": [3,4], "ndistinct": 11},
18606 * {"attributes": [3,6], "ndistinct": 11},
18607 * {"attributes": [4,6], "ndistinct": 11},
18608 * {"attributes": [3,4,6], "ndistinct": 11} ]
18609 *
18610 * The dependencies translation converts this kind of data:
18611 * {"3 => 4": 1.000000, "3 => 6": 1.000000,
18612 * "4 => 6": 1.000000, "3, 4 => 6": 1.000000,
18613 * "3, 6 => 4": 1.000000}
18614 *
18615 * to this:
18616 * [ {"attributes": [3], "dependency": 4, "degree": 1.000000},
18617 * {"attributes": [3], "dependency": 6, "degree": 1.000000},
18618 * {"attributes": [4], "dependency": 6, "degree": 1.000000},
18619 * {"attributes": [3,4], "dependency": 6, "degree": 1.000000},
18620 * {"attributes": [3,6], "dependency": 4, "degree": 1.000000} ]
18621 *--------
18622 */
18623 if (fout->remoteVersion >= 190000)
18624 appendPQExpBufferStr(pq, "e.n_distinct, e.dependencies ");
18625 else
18627 "( "
18628 "SELECT json_agg( "
18629 " json_build_object( "
18631 " string_to_array(kv.key, ', ')::integer[], "
18633 " kv.value::bigint )) "
18634 "FROM json_each_text(e.n_distinct::text::json) AS kv"
18635 ") AS n_distinct, "
18636 "( "
18637 "SELECT json_agg( "
18638 " json_build_object( "
18640 " string_to_array( "
18641 " split_part(kv.key, ' => ', 1), "
18642 " ', ')::integer[], "
18644 " split_part(kv.key, ' => ', 2)::integer, "
18646 " kv.value::double precision )) "
18647 "FROM json_each_text(e.dependencies::text::json) AS kv "
18648 ") AS dependencies ");
18649
18650 /* pg_stats_ext introduced in v12 */
18651 if (fout->remoteVersion >= 120000)
18653 "FROM pg_catalog.pg_stats_ext AS e "
18654 "WHERE e.statistics_schemaname = $1 "
18655 "AND e.statistics_name = $2 ");
18656 else
18658 "FROM ( "
18659 "SELECT s.stxndistinct AS n_distinct, "
18660 " s.stxdependencies AS dependencies "
18661 "FROM pg_catalog.pg_statistic_ext AS s "
18662 "JOIN pg_catalog.pg_namespace AS n "
18663 "ON n.oid = s.stxnamespace "
18664 "WHERE n.nspname = $1 "
18665 "AND s.stxname = $2 "
18666 ") AS e ");
18667
18668 /* we always have an inherited column, but it may be a constant */
18669 appendPQExpBufferStr(pq, "ORDER BY inherited");
18670
18671 ExecuteSqlStatement(fout, pq->data);
18672
18673 fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS] = true;
18674
18676 }
18677
18678 query = createPQExpBuffer();
18679
18680 appendPQExpBufferStr(query, "EXECUTE getExtStatsStats(");
18681 appendStringLiteralAH(query, statsextinfo->dobj.namespace->dobj.name, fout);
18682 appendPQExpBufferStr(query, "::pg_catalog.name, ");
18683 appendStringLiteralAH(query, statsextinfo->dobj.name, fout);
18684 appendPQExpBufferStr(query, "::pg_catalog.name)");
18685
18686 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18687
18688 destroyPQExpBuffer(query);
18689
18690 nstats = PQntuples(res);
18691
18692 if (nstats > 0)
18693 {
18695
18696 int i_inherited = PQfnumber(res, "inherited");
18697 int i_ndistinct = PQfnumber(res, "n_distinct");
18698 int i_dependencies = PQfnumber(res, "dependencies");
18699
18700 for (int i = 0; i < nstats; i++)
18701 {
18702 TableInfo *tbinfo = statsextinfo->stattable;
18703
18704 if (PQgetisnull(res, i, i_inherited))
18705 pg_fatal("inherited cannot be NULL");
18706
18708 "SELECT * FROM pg_catalog.pg_restore_extended_stats(\n");
18709 appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
18710 fout->remoteVersion);
18711
18712 /* Relation information */
18713 appendPQExpBufferStr(out, "\t'schemaname', ");
18714 appendStringLiteralAH(out, tbinfo->dobj.namespace->dobj.name, fout);
18715 appendPQExpBufferStr(out, ",\n\t'relname', ");
18716 appendStringLiteralAH(out, tbinfo->dobj.name, fout);
18717
18718 /* Extended statistics information */
18719 appendPQExpBufferStr(out, ",\n\t'statistics_schemaname', ");
18720 appendStringLiteralAH(out, statsextinfo->dobj.namespace->dobj.name, fout);
18721 appendPQExpBufferStr(out, ",\n\t'statistics_name', ");
18722 appendStringLiteralAH(out, statsextinfo->dobj.name, fout);
18723 appendNamedArgument(out, fout, "inherited", "boolean",
18724 PQgetvalue(res, i, i_inherited));
18725
18726 if (!PQgetisnull(res, i, i_ndistinct))
18727 appendNamedArgument(out, fout, "n_distinct", "pg_ndistinct",
18728 PQgetvalue(res, i, i_ndistinct));
18729
18730 if (!PQgetisnull(res, i, i_dependencies))
18731 appendNamedArgument(out, fout, "dependencies", "pg_dependencies",
18732 PQgetvalue(res, i, i_dependencies));
18733
18734 appendPQExpBufferStr(out, "\n);\n");
18735 }
18736
18738 ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
18739 .namespace = statsextinfo->dobj.namespace->dobj.name,
18740 .owner = statsextinfo->rolname,
18741 .description = "EXTENDED STATISTICS DATA",
18742 .section = SECTION_POST_DATA,
18743 .createStmt = out->data,
18744 .deps = &statsextinfo->dobj.dumpId,
18745 .nDeps = 1));
18746 destroyPQExpBuffer(out);
18747 }
18748 PQclear(res);
18749}
18750
18751/*
18752 * dumpConstraint
18753 * write out to fout a user-defined constraint
18754 */
18755static void
18757{
18758 DumpOptions *dopt = fout->dopt;
18759 TableInfo *tbinfo = coninfo->contable;
18760 PQExpBuffer q;
18762 char *tag = NULL;
18763 char *foreign;
18764
18765 /* Do nothing if not dumping schema */
18766 if (!dopt->dumpSchema)
18767 return;
18768
18769 q = createPQExpBuffer();
18771
18772 foreign = tbinfo &&
18773 tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
18774
18775 if (coninfo->contype == 'p' ||
18776 coninfo->contype == 'u' ||
18777 coninfo->contype == 'x')
18778 {
18779 /* Index-related constraint */
18781 int k;
18782
18784
18785 if (indxinfo == NULL)
18786 pg_fatal("missing index for constraint \"%s\"",
18787 coninfo->dobj.name);
18788
18789 if (dopt->binary_upgrade)
18791 indxinfo->dobj.catId.oid);
18792
18793 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
18795 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
18796 fmtId(coninfo->dobj.name));
18797
18798 if (coninfo->condef)
18799 {
18800 /* pg_get_constraintdef should have provided everything */
18801 appendPQExpBuffer(q, "%s;\n", coninfo->condef);
18802 }
18803 else
18804 {
18806 coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
18807
18808 /*
18809 * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
18810 * indexes. Being able to create this was fixed, but we need to
18811 * make the index distinct in order to be able to restore the
18812 * dump.
18813 */
18814 if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
18815 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
18816 appendPQExpBufferStr(q, " (");
18817 for (k = 0; k < indxinfo->indnkeyattrs; k++)
18818 {
18819 int indkey = (int) indxinfo->indkeys[k];
18820 const char *attname;
18821
18823 break;
18825
18826 appendPQExpBuffer(q, "%s%s",
18827 (k == 0) ? "" : ", ",
18828 fmtId(attname));
18829 }
18830 if (coninfo->conperiod)
18831 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
18832
18833 if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
18834 appendPQExpBufferStr(q, ") INCLUDE (");
18835
18836 for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
18837 {
18838 int indkey = (int) indxinfo->indkeys[k];
18839 const char *attname;
18840
18842 break;
18844
18845 appendPQExpBuffer(q, "%s%s",
18846 (k == indxinfo->indnkeyattrs) ? "" : ", ",
18847 fmtId(attname));
18848 }
18849
18850 appendPQExpBufferChar(q, ')');
18851
18852 if (nonemptyReloptions(indxinfo->indreloptions))
18853 {
18854 appendPQExpBufferStr(q, " WITH (");
18855 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
18856 appendPQExpBufferChar(q, ')');
18857 }
18858
18859 if (coninfo->condeferrable)
18860 {
18861 appendPQExpBufferStr(q, " DEFERRABLE");
18862 if (coninfo->condeferred)
18863 appendPQExpBufferStr(q, " INITIALLY DEFERRED");
18864 }
18865
18866 appendPQExpBufferStr(q, ";\n");
18867 }
18868
18869 /*
18870 * Append ALTER TABLE commands as needed to set properties that we
18871 * only have ALTER TABLE syntax for. Keep this in sync with the
18872 * similar code in dumpIndex!
18873 */
18874
18875 /* If the index is clustered, we need to record that. */
18876 if (indxinfo->indisclustered)
18877 {
18878 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
18880 /* index name is not qualified in this syntax */
18881 appendPQExpBuffer(q, " ON %s;\n",
18882 fmtId(indxinfo->dobj.name));
18883 }
18884
18885 /* If the index defines identity, we need to record that. */
18886 if (indxinfo->indisreplident)
18887 {
18888 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
18890 /* index name is not qualified in this syntax */
18891 appendPQExpBuffer(q, " INDEX %s;\n",
18892 fmtId(indxinfo->dobj.name));
18893 }
18894
18895 /* Indexes can depend on extensions */
18897 "pg_catalog.pg_class", "INDEX",
18899
18900 appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
18902 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
18903 fmtId(coninfo->dobj.name));
18904
18905 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18906
18907 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18908 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
18909 ARCHIVE_OPTS(.tag = tag,
18910 .namespace = tbinfo->dobj.namespace->dobj.name,
18911 .tablespace = indxinfo->tablespace,
18912 .owner = tbinfo->rolname,
18913 .description = "CONSTRAINT",
18914 .section = SECTION_POST_DATA,
18915 .createStmt = q->data,
18916 .dropStmt = delq->data));
18917 }
18918 else if (coninfo->contype == 'f')
18919 {
18920 char *only;
18921
18922 /*
18923 * Foreign keys on partitioned tables are always declared as
18924 * inheriting to partitions; for all other cases, emit them as
18925 * applying ONLY directly to the named table, because that's how they
18926 * work for regular inherited tables.
18927 */
18928 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
18929
18930 /*
18931 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
18932 * current table data is not processed
18933 */
18934 appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
18936 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
18937 fmtId(coninfo->dobj.name),
18938 coninfo->condef);
18939
18940 appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
18942 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
18943 fmtId(coninfo->dobj.name));
18944
18945 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18946
18947 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18948 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
18949 ARCHIVE_OPTS(.tag = tag,
18950 .namespace = tbinfo->dobj.namespace->dobj.name,
18951 .owner = tbinfo->rolname,
18952 .description = "FK CONSTRAINT",
18953 .section = SECTION_POST_DATA,
18954 .createStmt = q->data,
18955 .dropStmt = delq->data));
18956 }
18957 else if ((coninfo->contype == 'c' || coninfo->contype == 'n') && tbinfo)
18958 {
18959 /* CHECK or invalid not-null constraint on a table */
18960
18961 /* Ignore if not to be dumped separately, or if it was inherited */
18962 if (coninfo->separate && coninfo->conislocal)
18963 {
18964 const char *keyword;
18965
18966 if (coninfo->contype == 'c')
18967 keyword = "CHECK CONSTRAINT";
18968 else
18969 keyword = "CONSTRAINT";
18970
18971 /* not ONLY since we want it to propagate to children */
18972 appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
18974 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
18975 fmtId(coninfo->dobj.name),
18976 coninfo->condef);
18977
18978 appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
18980 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
18981 fmtId(coninfo->dobj.name));
18982
18983 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18984
18985 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18986 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
18987 ARCHIVE_OPTS(.tag = tag,
18988 .namespace = tbinfo->dobj.namespace->dobj.name,
18989 .owner = tbinfo->rolname,
18990 .description = keyword,
18991 .section = SECTION_POST_DATA,
18992 .createStmt = q->data,
18993 .dropStmt = delq->data));
18994 }
18995 }
18996 else if (tbinfo == NULL)
18997 {
18998 /* CHECK, NOT NULL constraint on a domain */
18999 TypeInfo *tyinfo = coninfo->condomain;
19000
19001 Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
19002
19003 /* Ignore if not to be dumped separately */
19004 if (coninfo->separate)
19005 {
19006 const char *keyword;
19007
19008 if (coninfo->contype == 'c')
19009 keyword = "CHECK CONSTRAINT";
19010 else
19011 keyword = "CONSTRAINT";
19012
19013 appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
19015 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
19016 fmtId(coninfo->dobj.name),
19017 coninfo->condef);
19018
19019 appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
19021 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
19022 fmtId(coninfo->dobj.name));
19023
19024 tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
19025
19026 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19027 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
19028 ARCHIVE_OPTS(.tag = tag,
19029 .namespace = tyinfo->dobj.namespace->dobj.name,
19030 .owner = tyinfo->rolname,
19031 .description = keyword,
19032 .section = SECTION_POST_DATA,
19033 .createStmt = q->data,
19034 .dropStmt = delq->data));
19035
19036 if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19037 {
19039 char *qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
19040
19041 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
19042 fmtId(coninfo->dobj.name));
19043
19045 tyinfo->dobj.namespace->dobj.name,
19046 tyinfo->rolname,
19047 coninfo->dobj.catId, 0, coninfo->dobj.dumpId);
19049 free(qtypname);
19050 }
19051 }
19052 }
19053 else
19054 {
19055 pg_fatal("unrecognized constraint type: %c",
19056 coninfo->contype);
19057 }
19058
19059 /* Dump Constraint Comments --- only works for table constraints */
19060 if (tbinfo && coninfo->separate &&
19061 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19063
19064 free(tag);
19067}
19068
19069/*
19070 * dumpTableConstraintComment --- dump a constraint's comment if any
19071 *
19072 * This is split out because we need the function in two different places
19073 * depending on whether the constraint is dumped as part of CREATE TABLE
19074 * or as a separate ALTER command.
19075 */
19076static void
19078{
19079 TableInfo *tbinfo = coninfo->contable;
19081 char *qtabname;
19082
19083 qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19084
19085 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
19086 fmtId(coninfo->dobj.name));
19087
19088 if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19090 tbinfo->dobj.namespace->dobj.name,
19091 tbinfo->rolname,
19092 coninfo->dobj.catId, 0,
19093 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
19094
19096 free(qtabname);
19097}
19098
19099static inline SeqType
19100parse_sequence_type(const char *name)
19101{
19102 for (int i = 0; i < lengthof(SeqTypeNames); i++)
19103 {
19104 if (strcmp(SeqTypeNames[i], name) == 0)
19105 return (SeqType) i;
19106 }
19107
19108 pg_fatal("unrecognized sequence type: %s", name);
19109 return (SeqType) 0; /* keep compiler quiet */
19110}
19111
19112/*
19113 * bsearch() comparator for SequenceItem
19114 */
19115static int
19116SequenceItemCmp(const void *p1, const void *p2)
19117{
19118 SequenceItem v1 = *((const SequenceItem *) p1);
19119 SequenceItem v2 = *((const SequenceItem *) p2);
19120
19121 return pg_cmp_u32(v1.oid, v2.oid);
19122}
19123
19124/*
19125 * collectSequences
19126 *
19127 * Construct a table of sequence information. This table is sorted by OID for
19128 * speed in lookup.
19129 */
19130static void
19132{
19133 PGresult *res;
19134 const char *query;
19135
19136 /*
19137 * Before Postgres 10, sequence metadata is in the sequence itself. With
19138 * some extra effort, we might be able to use the sorted table for those
19139 * versions, but for now it seems unlikely to be worth it.
19140 *
19141 * Since version 18, we can gather the sequence data in this query with
19142 * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
19143 */
19144 if (fout->remoteVersion < 100000)
19145 return;
19146 else if (fout->remoteVersion < 180000 ||
19147 (!fout->dopt->dumpData && !fout->dopt->sequence_data))
19148 query = "SELECT seqrelid, format_type(seqtypid, NULL), "
19149 "seqstart, seqincrement, "
19150 "seqmax, seqmin, "
19151 "seqcache, seqcycle, "
19152 "NULL, 'f' "
19153 "FROM pg_catalog.pg_sequence "
19154 "ORDER BY seqrelid";
19155 else
19156 query = "SELECT seqrelid, format_type(seqtypid, NULL), "
19157 "seqstart, seqincrement, "
19158 "seqmax, seqmin, "
19159 "seqcache, seqcycle, "
19160 "last_value, is_called "
19161 "FROM pg_catalog.pg_sequence, "
19162 "pg_get_sequence_data(seqrelid) "
19163 "ORDER BY seqrelid;";
19164
19165 res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
19166
19167 nsequences = PQntuples(res);
19169
19170 for (int i = 0; i < nsequences; i++)
19171 {
19172 sequences[i].oid = atooid(PQgetvalue(res, i, 0));
19174 sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
19175 sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
19176 sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
19177 sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
19178 sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
19179 sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
19180 sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
19181 sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
19182 sequences[i].null_seqtuple = (PQgetisnull(res, i, 8) || PQgetisnull(res, i, 9));
19183 }
19184
19185 PQclear(res);
19186}
19187
19188/*
19189 * dumpSequence
19190 * write the declaration (not data) of one user-defined sequence
19191 */
19192static void
19194{
19195 DumpOptions *dopt = fout->dopt;
19197 bool is_ascending;
19202 char *qseqname;
19203 TableInfo *owning_tab = NULL;
19204
19205 qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
19206
19207 /*
19208 * For versions >= 10, the sequence information is gathered in a sorted
19209 * table before any calls to dumpSequence(). See collectSequences() for
19210 * more information.
19211 */
19212 if (fout->remoteVersion >= 100000)
19213 {
19214 SequenceItem key = {0};
19215
19217
19218 key.oid = tbinfo->dobj.catId.oid;
19220 sizeof(SequenceItem), SequenceItemCmp);
19221 }
19222 else
19223 {
19224 PGresult *res;
19225
19226 /*
19227 * Before PostgreSQL 10, sequence metadata is in the sequence itself.
19228 *
19229 * Note: it might seem that 'bigint' potentially needs to be
19230 * schema-qualified, but actually that's a keyword.
19231 */
19232 appendPQExpBuffer(query,
19233 "SELECT 'bigint' AS sequence_type, "
19234 "start_value, increment_by, max_value, min_value, "
19235 "cache_value, is_cycled FROM %s",
19237
19238 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19239
19240 if (PQntuples(res) != 1)
19241 pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
19242 "query to get data of sequence \"%s\" returned %d rows (expected 1)",
19243 PQntuples(res)),
19244 tbinfo->dobj.name, PQntuples(res));
19245
19246 seq = pg_malloc0(sizeof(SequenceItem));
19247 seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
19248 seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
19249 seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
19250 seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
19251 seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
19252 seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
19253 seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
19254
19255 PQclear(res);
19256 }
19257
19258 /* Calculate default limits for a sequence of this type */
19259 is_ascending = (seq->incby >= 0);
19260 if (seq->seqtype == SEQTYPE_SMALLINT)
19261 {
19264 }
19265 else if (seq->seqtype == SEQTYPE_INTEGER)
19266 {
19269 }
19270 else if (seq->seqtype == SEQTYPE_BIGINT)
19271 {
19274 }
19275 else
19276 {
19277 pg_fatal("unrecognized sequence type: %d", seq->seqtype);
19278 default_minv = default_maxv = 0; /* keep compiler quiet */
19279 }
19280
19281 /*
19282 * Identity sequences are not to be dropped separately.
19283 */
19284 if (!tbinfo->is_identity_sequence)
19285 {
19286 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
19288 }
19289
19290 resetPQExpBuffer(query);
19291
19292 if (dopt->binary_upgrade)
19293 {
19295 tbinfo->dobj.catId.oid);
19296
19297 /*
19298 * In older PG versions a sequence will have a pg_type entry, but v14
19299 * and up don't use that, so don't attempt to preserve the type OID.
19300 */
19301 }
19302
19303 if (tbinfo->is_identity_sequence)
19304 {
19305 owning_tab = findTableByOid(tbinfo->owning_tab);
19306
19307 appendPQExpBuffer(query,
19308 "ALTER TABLE %s ",
19309 fmtQualifiedDumpable(owning_tab));
19310 appendPQExpBuffer(query,
19311 "ALTER COLUMN %s ADD GENERATED ",
19312 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
19313 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
19314 appendPQExpBufferStr(query, "ALWAYS");
19315 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
19316 appendPQExpBufferStr(query, "BY DEFAULT");
19317 appendPQExpBuffer(query, " AS IDENTITY (\n SEQUENCE NAME %s\n",
19319
19320 /*
19321 * Emit persistence option only if it's different from the owning
19322 * table's. This avoids using this new syntax unnecessarily.
19323 */
19324 if (tbinfo->relpersistence != owning_tab->relpersistence)
19325 appendPQExpBuffer(query, " %s\n",
19326 tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
19327 "UNLOGGED" : "LOGGED");
19328 }
19329 else
19330 {
19331 appendPQExpBuffer(query,
19332 "CREATE %sSEQUENCE %s\n",
19333 tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
19334 "UNLOGGED " : "",
19336
19337 if (seq->seqtype != SEQTYPE_BIGINT)
19338 appendPQExpBuffer(query, " AS %s\n", SeqTypeNames[seq->seqtype]);
19339 }
19340
19341 appendPQExpBuffer(query, " START WITH " INT64_FORMAT "\n", seq->startv);
19342
19343 appendPQExpBuffer(query, " INCREMENT BY " INT64_FORMAT "\n", seq->incby);
19344
19345 if (seq->minv != default_minv)
19346 appendPQExpBuffer(query, " MINVALUE " INT64_FORMAT "\n", seq->minv);
19347 else
19348 appendPQExpBufferStr(query, " NO MINVALUE\n");
19349
19350 if (seq->maxv != default_maxv)
19351 appendPQExpBuffer(query, " MAXVALUE " INT64_FORMAT "\n", seq->maxv);
19352 else
19353 appendPQExpBufferStr(query, " NO MAXVALUE\n");
19354
19355 appendPQExpBuffer(query,
19356 " CACHE " INT64_FORMAT "%s",
19357 seq->cache, (seq->cycled ? "\n CYCLE" : ""));
19358
19359 if (tbinfo->is_identity_sequence)
19360 appendPQExpBufferStr(query, "\n);\n");
19361 else
19362 appendPQExpBufferStr(query, ";\n");
19363
19364 /* binary_upgrade: no need to clear TOAST table oid */
19365
19366 if (dopt->binary_upgrade)
19368 "SEQUENCE", qseqname,
19369 tbinfo->dobj.namespace->dobj.name);
19370
19371 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19372 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
19373 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19374 .namespace = tbinfo->dobj.namespace->dobj.name,
19375 .owner = tbinfo->rolname,
19376 .description = "SEQUENCE",
19377 .section = SECTION_PRE_DATA,
19378 .createStmt = query->data,
19379 .dropStmt = delqry->data));
19380
19381 /*
19382 * If the sequence is owned by a table column, emit the ALTER for it as a
19383 * separate TOC entry immediately following the sequence's own entry. It's
19384 * OK to do this rather than using full sorting logic, because the
19385 * dependency that tells us it's owned will have forced the table to be
19386 * created first. We can't just include the ALTER in the TOC entry
19387 * because it will fail if we haven't reassigned the sequence owner to
19388 * match the table's owner.
19389 *
19390 * We need not schema-qualify the table reference because both sequence
19391 * and table must be in the same schema.
19392 */
19393 if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
19394 {
19395 owning_tab = findTableByOid(tbinfo->owning_tab);
19396
19397 if (owning_tab == NULL)
19398 pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
19399 tbinfo->owning_tab, tbinfo->dobj.catId.oid);
19400
19401 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
19402 {
19403 resetPQExpBuffer(query);
19404 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
19406 appendPQExpBuffer(query, " OWNED BY %s",
19407 fmtQualifiedDumpable(owning_tab));
19408 appendPQExpBuffer(query, ".%s;\n",
19409 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
19410
19411 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19413 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19414 .namespace = tbinfo->dobj.namespace->dobj.name,
19415 .owner = tbinfo->rolname,
19416 .description = "SEQUENCE OWNED BY",
19417 .section = SECTION_PRE_DATA,
19418 .createStmt = query->data,
19419 .deps = &(tbinfo->dobj.dumpId),
19420 .nDeps = 1));
19421 }
19422 }
19423
19424 /* Dump Sequence Comments and Security Labels */
19425 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19426 dumpComment(fout, "SEQUENCE", qseqname,
19427 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19428 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
19429
19430 if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
19431 dumpSecLabel(fout, "SEQUENCE", qseqname,
19432 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19433 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
19434
19435 if (fout->remoteVersion < 100000)
19436 pg_free(seq);
19437 destroyPQExpBuffer(query);
19439 free(qseqname);
19440}
19441
19442/*
19443 * dumpSequenceData
19444 * write the data of one user-defined sequence
19445 */
19446static void
19448{
19449 TableInfo *tbinfo = tdinfo->tdtable;
19450 int64 last;
19451 bool called;
19452 PQExpBuffer query;
19453
19454 /* needn't bother if not dumping sequence data */
19455 if (!fout->dopt->dumpData && !fout->dopt->sequence_data)
19456 return;
19457
19458 query = createPQExpBuffer();
19459
19460 /*
19461 * For versions >= 18, the sequence information is gathered in the sorted
19462 * array before any calls to dumpSequenceData(). See collectSequences()
19463 * for more information.
19464 *
19465 * For older versions, we have to query the sequence relations
19466 * individually.
19467 */
19468 if (fout->remoteVersion < 180000)
19469 {
19470 PGresult *res;
19471
19472 appendPQExpBuffer(query,
19473 "SELECT last_value, is_called FROM %s",
19475
19476 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19477
19478 if (PQntuples(res) != 1)
19479 pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
19480 "query to get data of sequence \"%s\" returned %d rows (expected 1)",
19481 PQntuples(res)),
19482 tbinfo->dobj.name, PQntuples(res));
19483
19484 last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
19485 called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
19486
19487 PQclear(res);
19488 }
19489 else
19490 {
19491 SequenceItem key = {0};
19492 SequenceItem *entry;
19493
19495 Assert(tbinfo->dobj.catId.oid);
19496
19497 key.oid = tbinfo->dobj.catId.oid;
19498 entry = bsearch(&key, sequences, nsequences,
19499 sizeof(SequenceItem), SequenceItemCmp);
19500
19501 if (entry->null_seqtuple)
19502 pg_fatal("failed to get data for sequence \"%s\"; user may lack "
19503 "SELECT privilege on the sequence or the sequence may "
19504 "have been concurrently dropped",
19505 tbinfo->dobj.name);
19506
19507 last = entry->last_value;
19508 called = entry->is_called;
19509 }
19510
19511 resetPQExpBuffer(query);
19512 appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
19514 appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
19515 last, (called ? "true" : "false"));
19516
19517 if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
19519 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19520 .namespace = tbinfo->dobj.namespace->dobj.name,
19521 .owner = tbinfo->rolname,
19522 .description = "SEQUENCE SET",
19523 .section = SECTION_DATA,
19524 .createStmt = query->data,
19525 .deps = &(tbinfo->dobj.dumpId),
19526 .nDeps = 1));
19527
19528 destroyPQExpBuffer(query);
19529}
19530
19531/*
19532 * dumpTrigger
19533 * write the declaration of one user-defined table trigger
19534 */
19535static void
19537{
19538 DumpOptions *dopt = fout->dopt;
19539 TableInfo *tbinfo = tginfo->tgtable;
19540 PQExpBuffer query;
19544 char *qtabname;
19545 char *tag;
19546
19547 /* Do nothing if not dumping schema */
19548 if (!dopt->dumpSchema)
19549 return;
19550
19551 query = createPQExpBuffer();
19555
19556 qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19557
19558 appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
19560
19561 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
19562 appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
19563
19564 /* Triggers can depend on extensions */
19566 "pg_catalog.pg_trigger", "TRIGGER",
19567 trigidentity->data);
19568
19569 if (tginfo->tgispartition)
19570 {
19571 Assert(tbinfo->ispartition);
19572
19573 /*
19574 * Partition triggers only appear here because their 'tgenabled' flag
19575 * differs from its parent's. The trigger is created already, so
19576 * remove the CREATE and replace it with an ALTER. (Clear out the
19577 * DROP query too, so that pg_dump --create does not cause errors.)
19578 */
19579 resetPQExpBuffer(query);
19581 appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
19582 tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
19584 switch (tginfo->tgenabled)
19585 {
19586 case 'f':
19587 case 'D':
19588 appendPQExpBufferStr(query, "DISABLE");
19589 break;
19590 case 't':
19591 case 'O':
19592 appendPQExpBufferStr(query, "ENABLE");
19593 break;
19594 case 'R':
19595 appendPQExpBufferStr(query, "ENABLE REPLICA");
19596 break;
19597 case 'A':
19598 appendPQExpBufferStr(query, "ENABLE ALWAYS");
19599 break;
19600 }
19601 appendPQExpBuffer(query, " TRIGGER %s;\n",
19602 fmtId(tginfo->dobj.name));
19603 }
19604 else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
19605 {
19606 appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
19607 tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
19609 switch (tginfo->tgenabled)
19610 {
19611 case 'D':
19612 case 'f':
19613 appendPQExpBufferStr(query, "DISABLE");
19614 break;
19615 case 'A':
19616 appendPQExpBufferStr(query, "ENABLE ALWAYS");
19617 break;
19618 case 'R':
19619 appendPQExpBufferStr(query, "ENABLE REPLICA");
19620 break;
19621 default:
19622 appendPQExpBufferStr(query, "ENABLE");
19623 break;
19624 }
19625 appendPQExpBuffer(query, " TRIGGER %s;\n",
19626 fmtId(tginfo->dobj.name));
19627 }
19628
19629 appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
19630 fmtId(tginfo->dobj.name));
19631
19632 tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
19633
19634 if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19635 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
19636 ARCHIVE_OPTS(.tag = tag,
19637 .namespace = tbinfo->dobj.namespace->dobj.name,
19638 .owner = tbinfo->rolname,
19639 .description = "TRIGGER",
19640 .section = SECTION_POST_DATA,
19641 .createStmt = query->data,
19642 .dropStmt = delqry->data));
19643
19644 if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19646 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19647 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
19648
19649 free(tag);
19650 destroyPQExpBuffer(query);
19654 free(qtabname);
19655}
19656
19657/*
19658 * dumpEventTrigger
19659 * write the declaration of one user-defined event trigger
19660 */
19661static void
19663{
19664 DumpOptions *dopt = fout->dopt;
19665 PQExpBuffer query;
19667 char *qevtname;
19668
19669 /* Do nothing if not dumping schema */
19670 if (!dopt->dumpSchema)
19671 return;
19672
19673 query = createPQExpBuffer();
19675
19676 qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
19677
19678 appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
19680 appendPQExpBufferStr(query, " ON ");
19681 appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
19682
19683 if (strcmp("", evtinfo->evttags) != 0)
19684 {
19685 appendPQExpBufferStr(query, "\n WHEN TAG IN (");
19686 appendPQExpBufferStr(query, evtinfo->evttags);
19687 appendPQExpBufferChar(query, ')');
19688 }
19689
19690 appendPQExpBufferStr(query, "\n EXECUTE FUNCTION ");
19691 appendPQExpBufferStr(query, evtinfo->evtfname);
19692 appendPQExpBufferStr(query, "();\n");
19693
19694 if (evtinfo->evtenabled != 'O')
19695 {
19696 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
19697 qevtname);
19698 switch (evtinfo->evtenabled)
19699 {
19700 case 'D':
19701 appendPQExpBufferStr(query, "DISABLE");
19702 break;
19703 case 'A':
19704 appendPQExpBufferStr(query, "ENABLE ALWAYS");
19705 break;
19706 case 'R':
19707 appendPQExpBufferStr(query, "ENABLE REPLICA");
19708 break;
19709 default:
19710 appendPQExpBufferStr(query, "ENABLE");
19711 break;
19712 }
19713 appendPQExpBufferStr(query, ";\n");
19714 }
19715
19716 appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
19717 qevtname);
19718
19719 if (dopt->binary_upgrade)
19721 "EVENT TRIGGER", qevtname, NULL);
19722
19723 if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19724 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
19725 ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
19726 .owner = evtinfo->evtowner,
19727 .description = "EVENT TRIGGER",
19728 .section = SECTION_POST_DATA,
19729 .createStmt = query->data,
19730 .dropStmt = delqry->data));
19731
19732 if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19733 dumpComment(fout, "EVENT TRIGGER", qevtname,
19734 NULL, evtinfo->evtowner,
19735 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
19736
19737 if (evtinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
19738 dumpSecLabel(fout, "EVENT TRIGGER", qevtname,
19739 NULL, evtinfo->evtowner,
19740 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
19741
19742 destroyPQExpBuffer(query);
19744 free(qevtname);
19745}
19746
19747/*
19748 * dumpRule
19749 * Dump a rule
19750 */
19751static void
19752dumpRule(Archive *fout, const RuleInfo *rinfo)
19753{
19754 DumpOptions *dopt = fout->dopt;
19755 TableInfo *tbinfo = rinfo->ruletable;
19756 bool is_view;
19757 PQExpBuffer query;
19758 PQExpBuffer cmd;
19761 char *qtabname;
19762 PGresult *res;
19763 char *tag;
19764
19765 /* Do nothing if not dumping schema */
19766 if (!dopt->dumpSchema)
19767 return;
19768
19769 /*
19770 * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
19771 * we do not want to dump it as a separate object.
19772 */
19773 if (!rinfo->separate)
19774 return;
19775
19776 /*
19777 * If it's an ON SELECT rule, we want to print it as a view definition,
19778 * instead of a rule.
19779 */
19780 is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
19781
19782 query = createPQExpBuffer();
19783 cmd = createPQExpBuffer();
19786
19787 qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19788
19789 if (is_view)
19790 {
19791 PQExpBuffer result;
19792
19793 /*
19794 * We need OR REPLACE here because we'll be replacing a dummy view.
19795 * Otherwise this should look largely like the regular view dump code.
19796 */
19797 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
19799 if (nonemptyReloptions(tbinfo->reloptions))
19800 {
19801 appendPQExpBufferStr(cmd, " WITH (");
19802 appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
19803 appendPQExpBufferChar(cmd, ')');
19804 }
19805 result = createViewAsClause(fout, tbinfo);
19806 appendPQExpBuffer(cmd, " AS\n%s", result->data);
19807 destroyPQExpBuffer(result);
19808 if (tbinfo->checkoption != NULL)
19809 appendPQExpBuffer(cmd, "\n WITH %s CHECK OPTION",
19810 tbinfo->checkoption);
19811 appendPQExpBufferStr(cmd, ";\n");
19812 }
19813 else
19814 {
19815 /* In the rule case, just print pg_get_ruledef's result verbatim */
19816 appendPQExpBuffer(query,
19817 "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
19818 rinfo->dobj.catId.oid);
19819
19820 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19821
19822 if (PQntuples(res) != 1)
19823 pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
19824 rinfo->dobj.name, tbinfo->dobj.name);
19825
19826 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
19827
19828 PQclear(res);
19829 }
19830
19831 /*
19832 * Add the command to alter the rules replication firing semantics if it
19833 * differs from the default.
19834 */
19835 if (rinfo->ev_enabled != 'O')
19836 {
19837 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
19838 switch (rinfo->ev_enabled)
19839 {
19840 case 'A':
19841 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
19842 fmtId(rinfo->dobj.name));
19843 break;
19844 case 'R':
19845 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
19846 fmtId(rinfo->dobj.name));
19847 break;
19848 case 'D':
19849 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
19850 fmtId(rinfo->dobj.name));
19851 break;
19852 }
19853 }
19854
19855 if (is_view)
19856 {
19857 /*
19858 * We can't DROP a view's ON SELECT rule. Instead, use CREATE OR
19859 * REPLACE VIEW to replace the rule with something with minimal
19860 * dependencies.
19861 */
19862 PQExpBuffer result;
19863
19864 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
19867 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
19868 destroyPQExpBuffer(result);
19869 }
19870 else
19871 {
19872 appendPQExpBuffer(delcmd, "DROP RULE %s ",
19873 fmtId(rinfo->dobj.name));
19874 appendPQExpBuffer(delcmd, "ON %s;\n",
19876 }
19877
19878 appendPQExpBuffer(ruleprefix, "RULE %s ON",
19879 fmtId(rinfo->dobj.name));
19880
19881 tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
19882
19883 if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19884 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
19885 ARCHIVE_OPTS(.tag = tag,
19886 .namespace = tbinfo->dobj.namespace->dobj.name,
19887 .owner = tbinfo->rolname,
19888 .description = "RULE",
19889 .section = SECTION_POST_DATA,
19890 .createStmt = cmd->data,
19891 .dropStmt = delcmd->data));
19892
19893 /* Dump rule comments */
19894 if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19896 tbinfo->dobj.namespace->dobj.name,
19897 tbinfo->rolname,
19898 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
19899
19900 free(tag);
19901 destroyPQExpBuffer(query);
19902 destroyPQExpBuffer(cmd);
19905 free(qtabname);
19906}
19907
19908/*
19909 * getExtensionMembership --- obtain extension membership data
19910 *
19911 * We need to identify objects that are extension members as soon as they're
19912 * loaded, so that we can correctly determine whether they need to be dumped.
19913 * Generally speaking, extension member objects will get marked as *not* to
19914 * be dumped, as they will be recreated by the single CREATE EXTENSION
19915 * command. However, in binary upgrade mode we still need to dump the members
19916 * individually.
19917 */
19918void
19920 int numExtensions)
19921{
19922 PQExpBuffer query;
19923 PGresult *res;
19924 int ntups,
19925 i;
19926 int i_classid,
19927 i_objid,
19928 i_refobjid;
19929 ExtensionInfo *ext;
19930
19931 /* Nothing to do if no extensions */
19932 if (numExtensions == 0)
19933 return;
19934
19935 query = createPQExpBuffer();
19936
19937 /* refclassid constraint is redundant but may speed the search */
19938 appendPQExpBufferStr(query, "SELECT "
19939 "classid, objid, refobjid "
19940 "FROM pg_depend "
19941 "WHERE refclassid = 'pg_extension'::regclass "
19942 "AND deptype = 'e' "
19943 "ORDER BY 3");
19944
19945 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19946
19947 ntups = PQntuples(res);
19948
19949 i_classid = PQfnumber(res, "classid");
19950 i_objid = PQfnumber(res, "objid");
19951 i_refobjid = PQfnumber(res, "refobjid");
19952
19953 /*
19954 * Since we ordered the SELECT by referenced ID, we can expect that
19955 * multiple entries for the same extension will appear together; this
19956 * saves on searches.
19957 */
19958 ext = NULL;
19959
19960 for (i = 0; i < ntups; i++)
19961 {
19962 CatalogId objId;
19963 Oid extId;
19964
19965 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
19966 objId.oid = atooid(PQgetvalue(res, i, i_objid));
19968
19969 if (ext == NULL ||
19970 ext->dobj.catId.oid != extId)
19972
19973 if (ext == NULL)
19974 {
19975 /* shouldn't happen */
19976 pg_log_warning("could not find referenced extension %u", extId);
19977 continue;
19978 }
19979
19980 recordExtensionMembership(objId, ext);
19981 }
19982
19983 PQclear(res);
19984
19985 destroyPQExpBuffer(query);
19986}
19987
19988/*
19989 * processExtensionTables --- deal with extension configuration tables
19990 *
19991 * There are two parts to this process:
19992 *
19993 * 1. Identify and create dump records for extension configuration tables.
19994 *
19995 * Extensions can mark tables as "configuration", which means that the user
19996 * is able and expected to modify those tables after the extension has been
19997 * loaded. For these tables, we dump out only the data- the structure is
19998 * expected to be handled at CREATE EXTENSION time, including any indexes or
19999 * foreign keys, which brings us to-
20000 *
20001 * 2. Record FK dependencies between configuration tables.
20002 *
20003 * Due to the FKs being created at CREATE EXTENSION time and therefore before
20004 * the data is loaded, we have to work out what the best order for reloading
20005 * the data is, to avoid FK violations when the tables are restored. This is
20006 * not perfect- we can't handle circular dependencies and if any exist they
20007 * will cause an invalid dump to be produced (though at least all of the data
20008 * is included for a user to manually restore). This is currently documented
20009 * but perhaps we can provide a better solution in the future.
20010 */
20011void
20013 int numExtensions)
20014{
20015 DumpOptions *dopt = fout->dopt;
20016 PQExpBuffer query;
20017 PGresult *res;
20018 int ntups,
20019 i;
20020 int i_conrelid,
20022
20023 /* Nothing to do if no extensions */
20024 if (numExtensions == 0)
20025 return;
20026
20027 /*
20028 * Identify extension configuration tables and create TableDataInfo
20029 * objects for them, ensuring their data will be dumped even though the
20030 * tables themselves won't be.
20031 *
20032 * Note that we create TableDataInfo objects even in schema-only mode, ie,
20033 * user data in a configuration table is treated like schema data. This
20034 * seems appropriate since system data in a config table would get
20035 * reloaded by CREATE EXTENSION. If the extension is not listed in the
20036 * list of extensions to be included, none of its data is dumped.
20037 */
20038 for (i = 0; i < numExtensions; i++)
20039 {
20041 char *extconfig = curext->extconfig;
20042 char *extcondition = curext->extcondition;
20043 char **extconfigarray = NULL;
20044 char **extconditionarray = NULL;
20045 int nconfigitems = 0;
20046 int nconditionitems = 0;
20047
20048 /*
20049 * Check if this extension is listed as to include in the dump. If
20050 * not, any table data associated with it is discarded.
20051 */
20054 curext->dobj.catId.oid))
20055 continue;
20056
20057 /*
20058 * Check if this extension is listed as to exclude in the dump. If
20059 * yes, any table data associated with it is discarded.
20060 */
20063 curext->dobj.catId.oid))
20064 continue;
20065
20066 if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
20067 {
20068 int j;
20069
20070 if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
20071 pg_fatal("could not parse %s array", "extconfig");
20072 if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
20073 pg_fatal("could not parse %s array", "extcondition");
20075 pg_fatal("mismatched number of configurations and conditions for extension");
20076
20077 for (j = 0; j < nconfigitems; j++)
20078 {
20081 bool dumpobj =
20082 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
20083
20085 if (configtbl == NULL)
20086 continue;
20087
20088 /*
20089 * Tables of not-to-be-dumped extensions shouldn't be dumped
20090 * unless the table or its schema is explicitly included
20091 */
20092 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
20093 {
20094 /* check table explicitly requested */
20095 if (table_include_oids.head != NULL &&
20097 configtbloid))
20098 dumpobj = true;
20099
20100 /* check table's schema explicitly requested */
20101 if (configtbl->dobj.namespace->dobj.dump &
20103 dumpobj = true;
20104 }
20105
20106 /* check table excluded by an exclusion switch */
20107 if (table_exclude_oids.head != NULL &&
20109 configtbloid))
20110 dumpobj = false;
20111
20112 /* check schema excluded by an exclusion switch */
20114 configtbl->dobj.namespace->dobj.catId.oid))
20115 dumpobj = false;
20116
20117 if (dumpobj)
20118 {
20120 if (configtbl->dataObj != NULL)
20121 {
20122 if (strlen(extconditionarray[j]) > 0)
20123 configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
20124 }
20125 }
20126 }
20127 }
20128 if (extconfigarray)
20132 }
20133
20134 /*
20135 * Now that all the TableDataInfo objects have been created for all the
20136 * extensions, check their FK dependencies and register them to try and
20137 * dump the data out in an order that they can be restored in.
20138 *
20139 * Note that this is not a problem for user tables as their FKs are
20140 * recreated after the data has been loaded.
20141 */
20142
20143 query = createPQExpBuffer();
20144
20145 printfPQExpBuffer(query,
20146 "SELECT conrelid, confrelid "
20147 "FROM pg_constraint "
20148 "JOIN pg_depend ON (objid = confrelid) "
20149 "WHERE contype = 'f' "
20150 "AND refclassid = 'pg_extension'::regclass "
20151 "AND classid = 'pg_class'::regclass;");
20152
20153 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
20154 ntups = PQntuples(res);
20155
20156 i_conrelid = PQfnumber(res, "conrelid");
20157 i_confrelid = PQfnumber(res, "confrelid");
20158
20159 /* Now get the dependencies and register them */
20160 for (i = 0; i < ntups; i++)
20161 {
20162 Oid conrelid,
20163 confrelid;
20165 *contable;
20166
20167 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
20168 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
20169 contable = findTableByOid(conrelid);
20170 reftable = findTableByOid(confrelid);
20171
20172 if (reftable == NULL ||
20173 reftable->dataObj == NULL ||
20174 contable == NULL ||
20175 contable->dataObj == NULL)
20176 continue;
20177
20178 /*
20179 * Make referencing TABLE_DATA object depend on the referenced table's
20180 * TABLE_DATA object.
20181 */
20182 addObjectDependency(&contable->dataObj->dobj,
20183 reftable->dataObj->dobj.dumpId);
20184 }
20185 PQclear(res);
20186 destroyPQExpBuffer(query);
20187}
20188
20189/*
20190 * getDependencies --- obtain available dependency data
20191 */
20192static void
20194{
20195 PQExpBuffer query;
20196 PGresult *res;
20197 int ntups,
20198 i;
20199 int i_classid,
20200 i_objid,
20202 i_refobjid,
20203 i_deptype;
20204 DumpableObject *dobj,
20205 *refdobj;
20206
20207 pg_log_info("reading dependency data");
20208
20209 query = createPQExpBuffer();
20210
20211 /*
20212 * Messy query to collect the dependency data we need. Note that we
20213 * ignore the sub-object column, so that dependencies of or on a column
20214 * look the same as dependencies of or on a whole table.
20215 *
20216 * PIN dependencies aren't interesting, and EXTENSION dependencies were
20217 * already processed by getExtensionMembership.
20218 */
20219 appendPQExpBufferStr(query, "SELECT "
20220 "classid, objid, refclassid, refobjid, deptype "
20221 "FROM pg_depend "
20222 "WHERE deptype != 'p' AND deptype != 'e'\n");
20223
20224 /*
20225 * Since we don't treat pg_amop entries as separate DumpableObjects, we
20226 * have to translate their dependencies into dependencies of their parent
20227 * opfamily. Ignore internal dependencies though, as those will point to
20228 * their parent opclass, which we needn't consider here (and if we did,
20229 * it'd just result in circular dependencies). Also, "loose" opfamily
20230 * entries will have dependencies on their parent opfamily, which we
20231 * should drop since they'd likewise become useless self-dependencies.
20232 * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
20233 */
20234 appendPQExpBufferStr(query, "UNION ALL\n"
20235 "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
20236 "FROM pg_depend d, pg_amop o "
20237 "WHERE deptype NOT IN ('p', 'e', 'i') AND "
20238 "classid = 'pg_amop'::regclass AND objid = o.oid "
20239 "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
20240
20241 /* Likewise for pg_amproc entries */
20242 appendPQExpBufferStr(query, "UNION ALL\n"
20243 "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
20244 "FROM pg_depend d, pg_amproc p "
20245 "WHERE deptype NOT IN ('p', 'e', 'i') AND "
20246 "classid = 'pg_amproc'::regclass AND objid = p.oid "
20247 "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
20248
20249 /* Sort the output for efficiency below */
20250 appendPQExpBufferStr(query, "ORDER BY 1,2");
20251
20252 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
20253
20254 ntups = PQntuples(res);
20255
20256 i_classid = PQfnumber(res, "classid");
20257 i_objid = PQfnumber(res, "objid");
20258 i_refclassid = PQfnumber(res, "refclassid");
20259 i_refobjid = PQfnumber(res, "refobjid");
20260 i_deptype = PQfnumber(res, "deptype");
20261
20262 /*
20263 * Since we ordered the SELECT by referencing ID, we can expect that
20264 * multiple entries for the same object will appear together; this saves
20265 * on searches.
20266 */
20267 dobj = NULL;
20268
20269 for (i = 0; i < ntups; i++)
20270 {
20271 CatalogId objId;
20273 char deptype;
20274
20275 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
20276 objId.oid = atooid(PQgetvalue(res, i, i_objid));
20277 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
20278 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
20279 deptype = *(PQgetvalue(res, i, i_deptype));
20280
20281 if (dobj == NULL ||
20282 dobj->catId.tableoid != objId.tableoid ||
20283 dobj->catId.oid != objId.oid)
20284 dobj = findObjectByCatalogId(objId);
20285
20286 /*
20287 * Failure to find objects mentioned in pg_depend is not unexpected,
20288 * since for example we don't collect info about TOAST tables.
20289 */
20290 if (dobj == NULL)
20291 {
20292#ifdef NOT_USED
20293 pg_log_warning("no referencing object %u %u",
20294 objId.tableoid, objId.oid);
20295#endif
20296 continue;
20297 }
20298
20300
20301 if (refdobj == NULL)
20302 {
20303#ifdef NOT_USED
20304 pg_log_warning("no referenced object %u %u",
20305 refobjId.tableoid, refobjId.oid);
20306#endif
20307 continue;
20308 }
20309
20310 /*
20311 * For 'x' dependencies, mark the object for later; we still add the
20312 * normal dependency, for possible ordering purposes. Currently
20313 * pg_dump_sort.c knows to put extensions ahead of all object types
20314 * that could possibly depend on them, but this is safer.
20315 */
20316 if (deptype == 'x')
20317 dobj->depends_on_ext = true;
20318
20319 /*
20320 * Ordinarily, table rowtypes have implicit dependencies on their
20321 * tables. However, for a composite type the implicit dependency goes
20322 * the other way in pg_depend; which is the right thing for DROP but
20323 * it doesn't produce the dependency ordering we need. So in that one
20324 * case, we reverse the direction of the dependency.
20325 */
20326 if (deptype == 'i' &&
20327 dobj->objType == DO_TABLE &&
20328 refdobj->objType == DO_TYPE)
20330 else
20331 /* normal case */
20332 addObjectDependency(dobj, refdobj->dumpId);
20333 }
20334
20335 PQclear(res);
20336
20337 destroyPQExpBuffer(query);
20338}
20339
20340
20341/*
20342 * createBoundaryObjects - create dummy DumpableObjects to represent
20343 * dump section boundaries.
20344 */
20345static DumpableObject *
20347{
20349
20350 dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
20351
20353 dobjs[0].catId = nilCatalogId;
20354 AssignDumpId(dobjs + 0);
20355 dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
20356
20357 dobjs[1].objType = DO_POST_DATA_BOUNDARY;
20358 dobjs[1].catId = nilCatalogId;
20359 AssignDumpId(dobjs + 1);
20360 dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
20361
20362 return dobjs;
20363}
20364
20365/*
20366 * addBoundaryDependencies - add dependencies as needed to enforce the dump
20367 * section boundaries.
20368 */
20369static void
20372{
20375 int i;
20376
20377 for (i = 0; i < numObjs; i++)
20378 {
20379 DumpableObject *dobj = dobjs[i];
20380
20381 /*
20382 * The classification of object types here must match the SECTION_xxx
20383 * values assigned during subsequent ArchiveEntry calls!
20384 */
20385 switch (dobj->objType)
20386 {
20387 case DO_NAMESPACE:
20388 case DO_EXTENSION:
20389 case DO_TYPE:
20390 case DO_SHELL_TYPE:
20391 case DO_FUNC:
20392 case DO_AGG:
20393 case DO_OPERATOR:
20394 case DO_ACCESS_METHOD:
20395 case DO_OPCLASS:
20396 case DO_OPFAMILY:
20397 case DO_COLLATION:
20398 case DO_CONVERSION:
20399 case DO_TABLE:
20400 case DO_TABLE_ATTACH:
20401 case DO_ATTRDEF:
20402 case DO_PROCLANG:
20403 case DO_CAST:
20404 case DO_DUMMY_TYPE:
20405 case DO_TSPARSER:
20406 case DO_TSDICT:
20407 case DO_TSTEMPLATE:
20408 case DO_TSCONFIG:
20409 case DO_FDW:
20410 case DO_FOREIGN_SERVER:
20411 case DO_TRANSFORM:
20412 /* Pre-data objects: must come before the pre-data boundary */
20414 break;
20415 case DO_TABLE_DATA:
20416 case DO_SEQUENCE_SET:
20417 case DO_LARGE_OBJECT:
20419 /* Data objects: must come between the boundaries */
20420 addObjectDependency(dobj, preDataBound->dumpId);
20422 break;
20423 case DO_INDEX:
20424 case DO_INDEX_ATTACH:
20425 case DO_STATSEXT:
20426 case DO_REFRESH_MATVIEW:
20427 case DO_TRIGGER:
20428 case DO_EVENT_TRIGGER:
20429 case DO_DEFAULT_ACL:
20430 case DO_POLICY:
20431 case DO_PUBLICATION:
20432 case DO_PUBLICATION_REL:
20434 case DO_SUBSCRIPTION:
20436 /* Post-data objects: must come after the post-data boundary */
20437 addObjectDependency(dobj, postDataBound->dumpId);
20438 break;
20439 case DO_RULE:
20440 /* Rules are post-data, but only if dumped separately */
20441 if (((RuleInfo *) dobj)->separate)
20442 addObjectDependency(dobj, postDataBound->dumpId);
20443 break;
20444 case DO_CONSTRAINT:
20445 case DO_FK_CONSTRAINT:
20446 /* Constraints are post-data, but only if dumped separately */
20447 if (((ConstraintInfo *) dobj)->separate)
20448 addObjectDependency(dobj, postDataBound->dumpId);
20449 break;
20451 /* nothing to do */
20452 break;
20454 /* must come after the pre-data boundary */
20455 addObjectDependency(dobj, preDataBound->dumpId);
20456 break;
20457 case DO_REL_STATS:
20458 /* stats section varies by parent object type, DATA or POST */
20459 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
20460 {
20461 addObjectDependency(dobj, preDataBound->dumpId);
20462 addObjectDependency(postDataBound, dobj->dumpId);
20463 }
20464 else
20465 addObjectDependency(dobj, postDataBound->dumpId);
20466 break;
20467 }
20468 }
20469}
20470
20471
20472/*
20473 * BuildArchiveDependencies - create dependency data for archive TOC entries
20474 *
20475 * The raw dependency data obtained by getDependencies() is not terribly
20476 * useful in an archive dump, because in many cases there are dependency
20477 * chains linking through objects that don't appear explicitly in the dump.
20478 * For example, a view will depend on its _RETURN rule while the _RETURN rule
20479 * will depend on other objects --- but the rule will not appear as a separate
20480 * object in the dump. We need to adjust the view's dependencies to include
20481 * whatever the rule depends on that is included in the dump.
20482 *
20483 * Just to make things more complicated, there are also "special" dependencies
20484 * such as the dependency of a TABLE DATA item on its TABLE, which we must
20485 * not rearrange because pg_restore knows that TABLE DATA only depends on
20486 * its table. In these cases we must leave the dependencies strictly as-is
20487 * even if they refer to not-to-be-dumped objects.
20488 *
20489 * To handle this, the convention is that "special" dependencies are created
20490 * during ArchiveEntry calls, and an archive TOC item that has any such
20491 * entries will not be touched here. Otherwise, we recursively search the
20492 * DumpableObject data structures to build the correct dependencies for each
20493 * archive TOC item.
20494 */
20495static void
20497{
20499 TocEntry *te;
20500
20501 /* Scan all TOC entries in the archive */
20502 for (te = AH->toc->next; te != AH->toc; te = te->next)
20503 {
20504 DumpableObject *dobj;
20505 DumpId *dependencies;
20506 int nDeps;
20507 int allocDeps;
20508
20509 /* No need to process entries that will not be dumped */
20510 if (te->reqs == 0)
20511 continue;
20512 /* Ignore entries that already have "special" dependencies */
20513 if (te->nDeps > 0)
20514 continue;
20515 /* Otherwise, look up the item's original DumpableObject, if any */
20516 dobj = findObjectByDumpId(te->dumpId);
20517 if (dobj == NULL)
20518 continue;
20519 /* No work if it has no dependencies */
20520 if (dobj->nDeps <= 0)
20521 continue;
20522 /* Set up work array */
20523 allocDeps = 64;
20524 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
20525 nDeps = 0;
20526 /* Recursively find all dumpable dependencies */
20527 findDumpableDependencies(AH, dobj,
20528 &dependencies, &nDeps, &allocDeps);
20529 /* And save 'em ... */
20530 if (nDeps > 0)
20531 {
20532 dependencies = (DumpId *) pg_realloc(dependencies,
20533 nDeps * sizeof(DumpId));
20534 te->dependencies = dependencies;
20535 te->nDeps = nDeps;
20536 }
20537 else
20538 free(dependencies);
20539 }
20540}
20541
20542/* Recursive search subroutine for BuildArchiveDependencies */
20543static void
20545 DumpId **dependencies, int *nDeps, int *allocDeps)
20546{
20547 int i;
20548
20549 /*
20550 * Ignore section boundary objects: if we search through them, we'll
20551 * report lots of bogus dependencies.
20552 */
20553 if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
20555 return;
20556
20557 for (i = 0; i < dobj->nDeps; i++)
20558 {
20559 DumpId depid = dobj->dependencies[i];
20560
20561 if (TocIDRequired(AH, depid) != 0)
20562 {
20563 /* Object will be dumped, so just reference it as a dependency */
20564 if (*nDeps >= *allocDeps)
20565 {
20566 *allocDeps *= 2;
20567 *dependencies = (DumpId *) pg_realloc(*dependencies,
20568 *allocDeps * sizeof(DumpId));
20569 }
20570 (*dependencies)[*nDeps] = depid;
20571 (*nDeps)++;
20572 }
20573 else
20574 {
20575 /*
20576 * Object will not be dumped, so recursively consider its deps. We
20577 * rely on the assumption that sortDumpableObjects already broke
20578 * any dependency loops, else we might recurse infinitely.
20579 */
20581
20582 if (otherdobj)
20584 dependencies, nDeps, allocDeps);
20585 }
20586 }
20587}
20588
20589
20590/*
20591 * getFormattedTypeName - retrieve a nicely-formatted type name for the
20592 * given type OID.
20593 *
20594 * This does not guarantee to schema-qualify the output, so it should not
20595 * be used to create the target object name for CREATE or ALTER commands.
20596 *
20597 * Note that the result is cached and must not be freed by the caller.
20598 */
20599static const char *
20601{
20603 char *result;
20604 PQExpBuffer query;
20605 PGresult *res;
20606
20607 if (oid == 0)
20608 {
20609 if ((opts & zeroAsStar) != 0)
20610 return "*";
20611 else if ((opts & zeroAsNone) != 0)
20612 return "NONE";
20613 }
20614
20615 /* see if we have the result cached in the type's TypeInfo record */
20616 typeInfo = findTypeByOid(oid);
20617 if (typeInfo && typeInfo->ftypname)
20618 return typeInfo->ftypname;
20619
20620 query = createPQExpBuffer();
20621 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
20622 oid);
20623
20624 res = ExecuteSqlQueryForSingleRow(fout, query->data);
20625
20626 /* result of format_type is already quoted */
20627 result = pg_strdup(PQgetvalue(res, 0, 0));
20628
20629 PQclear(res);
20630 destroyPQExpBuffer(query);
20631
20632 /*
20633 * Cache the result for re-use in later requests, if possible. If we
20634 * don't have a TypeInfo for the type, the string will be leaked once the
20635 * caller is done with it ... but that case really should not happen, so
20636 * leaking if it does seems acceptable.
20637 */
20638 if (typeInfo)
20639 typeInfo->ftypname = result;
20640
20641 return result;
20642}
20643
20644/*
20645 * Return a column list clause for the given relation.
20646 *
20647 * Special case: if there are no undropped columns in the relation, return
20648 * "", not an invalid "()" column list.
20649 */
20650static const char *
20652{
20653 int numatts = ti->numatts;
20654 char **attnames = ti->attnames;
20655 bool *attisdropped = ti->attisdropped;
20656 char *attgenerated = ti->attgenerated;
20657 bool needComma;
20658 int i;
20659
20660 appendPQExpBufferChar(buffer, '(');
20661 needComma = false;
20662 for (i = 0; i < numatts; i++)
20663 {
20664 if (attisdropped[i])
20665 continue;
20666 if (attgenerated[i])
20667 continue;
20668 if (needComma)
20669 appendPQExpBufferStr(buffer, ", ");
20670 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
20671 needComma = true;
20672 }
20673
20674 if (!needComma)
20675 return ""; /* no undropped columns */
20676
20677 appendPQExpBufferChar(buffer, ')');
20678 return buffer->data;
20679}
20680
20681/*
20682 * Check if a reloptions array is nonempty.
20683 */
20684static bool
20685nonemptyReloptions(const char *reloptions)
20686{
20687 /* Don't want to print it if it's just "{}" */
20688 return (reloptions != NULL && strlen(reloptions) > 2);
20689}
20690
20691/*
20692 * Format a reloptions array and append it to the given buffer.
20693 *
20694 * "prefix" is prepended to the option names; typically it's "" or "toast.".
20695 */
20696static void
20697appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
20698 const char *prefix, Archive *fout)
20699{
20700 bool res;
20701
20702 res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
20703 fout->std_strings);
20704 if (!res)
20705 pg_log_warning("could not parse %s array", "reloptions");
20706}
20707
20708/*
20709 * read_dump_filters - retrieve object identifier patterns from file
20710 *
20711 * Parse the specified filter file for include and exclude patterns, and add
20712 * them to the relevant lists. If the filename is "-" then filters will be
20713 * read from STDIN rather than a file.
20714 */
20715static void
20716read_dump_filters(const char *filename, DumpOptions *dopt)
20717{
20719 char *objname;
20721 FilterObjectType objtype;
20722
20724
20725 while (filter_read_item(&fstate, &objname, &comtype, &objtype))
20726 {
20728 {
20729 switch (objtype)
20730 {
20732 break;
20739 pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
20740 "include",
20741 filter_object_type_name(objtype));
20742 exit_nicely(1);
20743 break; /* unreachable */
20744
20747 break;
20750 break;
20753 dopt->include_everything = false;
20754 break;
20757 dopt->include_everything = false;
20758 break;
20761 objname);
20762 dopt->include_everything = false;
20763 break;
20764 }
20765 }
20767 {
20768 switch (objtype)
20769 {
20771 break;
20777 pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
20778 "exclude",
20779 filter_object_type_name(objtype));
20780 exit_nicely(1);
20781 break;
20782
20785 break;
20788 objname);
20789 break;
20792 objname);
20793 break;
20796 break;
20799 break;
20802 objname);
20803 break;
20804 }
20805 }
20806 else
20807 {
20809 Assert(objtype == FILTER_OBJECT_TYPE_NONE);
20810 }
20811
20812 if (objname)
20813 free(objname);
20814 }
20815
20817}
Acl * acldefault(ObjectType objtype, Oid ownerId)
Definition acl.c:803
#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:719
void recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
Definition common.c:1063
FuncInfo * findFuncByOid(Oid oid)
Definition common.c:918
TableInfo * findTableByOid(Oid oid)
Definition common.c:863
ExtensionInfo * findExtensionByOid(Oid oid)
Definition common.c:1008
CollInfo * findCollationByOid(Oid oid)
Definition common.c:972
SubscriptionInfo * findSubscriptionByOid(Oid oid)
Definition common.c:1044
OprInfo * findOprByOid(Oid oid)
Definition common.c:936
NamespaceInfo * findNamespaceByOid(Oid oid)
Definition common.c:990
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition common.c:818
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition common.c:765
void parseOidArray(const char *str, Oid *array, int arraysize)
Definition common.c:1111
ExtensionInfo * findOwningExtension(CatalogId catalogId)
Definition common.c:1087
TableInfo * getSchemaData(Archive *fout, int *numTablesPtr)
Definition common.c:98
TypeInfo * findTypeByOid(Oid oid)
Definition common.c:899
DumpId createDumpId(void)
Definition common.c:745
DumpableObject * findObjectByCatalogId(CatalogId catalogId)
Definition common.c:778
void AssignDumpId(DumpableObject *dobj)
Definition common.c:657
void getDumpableObjects(DumpableObject ***objs, int *numObjs)
Definition common.c:797
PublicationInfo * findPublicationByOid(Oid oid)
Definition common.c:1026
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:2480
uint32 BlockNumber
Definition block.h:31
static void cleanup(void)
Definition bootstrap.c:717
static const gbtree_vinfo tinfo
Definition btree_bit.c:109
#define PG_INT32_MAX
Definition c.h:603
#define ngettext(s, p, n)
Definition c.h:1170
#define INT64_FORMAT
Definition c.h:564
#define Assert(condition)
Definition c.h:873
#define PG_TEXTDOMAIN(domain)
Definition c.h:1203
int64_t int64
Definition c.h:543
#define PG_INT16_MIN
Definition c.h:599
#define CppAsString2(x)
Definition c.h:428
int32_t int32
Definition c.h:542
#define PG_INT64_MAX
Definition c.h:606
#define PG_INT64_MIN
Definition c.h:605
uint32_t uint32
Definition c.h:546
#define lengthof(array)
Definition c.h:803
#define PG_INT32_MIN
Definition c.h:602
#define PG_INT16_MAX
Definition c.h:600
#define OidIsValid(objectId)
Definition c.h:788
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:49
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:973
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:997
void buildShSecLabelQuery(const char *catalog_name, Oid objectId, PQExpBuffer sql)
Definition dumputils.c:678
void makeAlterConfigCommand(PGconn *conn, const char *configitem, const char *type, const char *name, const char *type2, const char *name2, PQExpBuffer buf)
Definition dumputils.c:865
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:730
void quoteAclUserName(PQExpBuffer output, const char *input)
Definition dumputils.c:585
void emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer, const char *objtype, const char *objname)
Definition dumputils.c:696
#define _(x)
Definition elog.c:91
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:4049
Oid PQftype(const PGresult *res, int field_num)
Definition fe-exec.c:3736
int PQfnumber(const PGresult *res, const char *field_name)
Definition fe-exec.c:3606
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:47
char * pg_strdup(const char *in)
Definition fe_memutils.c:85
void * pg_malloc0(size_t size)
Definition fe_memutils.c:53
void pg_free(void *ptr)
void * pg_realloc(void *ptr, size_t size)
Definition fe_memutils.c:65
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 @172 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:125
@ PGRES_COPY_OUT
Definition libpq-fe.h:131
@ PGRES_TUPLES_OK
Definition libpq-fe.h:128
#define INV_READ
Definition libpq-fs.h:22
void pg_logging_increase_verbosity(void)
Definition logging.c:185
void pg_logging_init(const char *argv0)
Definition logging.c:83
void pg_logging_set_level(enum pg_log_level new_level)
Definition logging.c:176
#define pg_log_error(...)
Definition logging.h:106
#define pg_log_error_hint(...)
Definition logging.h:112
#define pg_log_info(...)
Definition logging.h:124
@ PG_LOG_WARNING
Definition logging.h:38
#define pg_log_error_detail(...)
Definition logging.h:109
const char * progname
Definition main.c:44
char * pstrdup(const char *in)
Definition mcxt.c:1781
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)
Oid oprid(Operator op)
Definition parse_oper.c:239
static AmcheckOptions opts
Definition pg_amcheck.c:112
NameData attname
char attalign
int16 attlen
NameData rolname
Definition pg_authid.h:34
@ 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)
void * arg
#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:44
NameData datname
Definition pg_database.h:35
bool datistemplate
Definition pg_database.h:47
int32 datconnlimit
Definition pg_database.h:59
static void expand_schema_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names)
Definition pg_dump.c:1677
static const CatalogId nilCatalogId
Definition pg_dump.c:191
static void dumpEncoding(Archive *AH)
Definition pg_dump.c:3849
void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:8308
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:16426
static SimpleStringList schema_include_patterns
Definition pg_dump.c:167
static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
Definition pg_dump.c:18193
ExtensionInfo * getExtensions(Archive *fout, int *numExtensions)
Definition pg_dump.c:6137
static void selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
Definition pg_dump.c:2229
static void collectBinaryUpgradeClassOids(Archive *fout)
Definition pg_dump.c:5837
static PQExpBuffer createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
Definition pg_dump.c:17070
static void dumpUserMappings(Archive *fout, const char *servername, const char *namespace, const char *owner, CatalogId catalogId, DumpId dumpId)
Definition pg_dump.c:16240
static void dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
Definition pg_dump.c:4977
static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs, DumpableObject *boundaryObjs)
Definition pg_dump.c:20371
void getPublicationNamespaces(Archive *fout)
Definition pg_dump.c:4770
static void dumpSearchPath(Archive *AH)
Definition pg_dump.c:3898
static int ncomments
Definition pg_dump.c:203
static void selectDumpableTable(TableInfo *tbinfo, Archive *fout)
Definition pg_dump.c:2098
static DumpableObject * createBoundaryObjects(void)
Definition pg_dump.c:20347
static char * convertTSFunction(Archive *fout, Oid funcOid)
Definition pg_dump.c:14413
static void dumpDatabase(Archive *fout)
Definition pg_dump.c:3296
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:5650
static Oid get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
Definition pg_dump.c:5695
static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
Definition pg_dump.c:11875
static bool forcePartitionRootLoad(const TableInfo *tbinfo)
Definition pg_dump.c:2856
static void dumpCast(Archive *fout, const CastInfo *cast)
Definition pg_dump.c:13889
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:18283
void getPartitioningInfo(Archive *fout)
Definition pg_dump.c:7797
static int nbinaryUpgradeClassOids
Definition pg_dump.c:211
static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12468
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:11119
static SimpleOidList extension_include_oids
Definition pg_dump.c:186
static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
Definition pg_dump.c:15812
static void dumpAgg(Archive *fout, const AggInfo *agginfo)
Definition pg_dump.c:15388
static int extra_float_digits
Definition pg_dump.c:195
static int SequenceItemCmp(const void *p1, const void *p2)
Definition pg_dump.c:19117
static void dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
Definition pg_dump.c:11392
static void dumpTableComment(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
Definition pg_dump.c:11418
static SimpleStringList extension_include_patterns
Definition pg_dump.c:185
static void selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
Definition pg_dump.c:2012
InhInfo * getInherits(Archive *fout, int *numInherits)
Definition pg_dump.c:7741
void getForeignDataWrappers(Archive *fout)
Definition pg_dump.c:10428
static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
Definition pg_dump.c:19537
static void binary_upgrade_set_type_oids_by_rel(Archive *fout, PQExpBuffer upgrade_buffer, const TableInfo *tbinfo)
Definition pg_dump.c:5806
static void dumpTable(Archive *fout, const TableInfo *tbinfo)
Definition pg_dump.c:16881
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:17021
static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
Definition pg_dump.c:18477
void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:4261
static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12246
void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition pg_dump.c:19920
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:10997
static char * getFormattedOperatorName(const char *oproid)
Definition pg_dump.c:14383
static char * format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
Definition pg_dump.c:13438
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:3874
static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
Definition pg_dump.c:18757
static void dumpType(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12075
static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
Definition pg_dump.c:18125
void getTypes(Archive *fout)
Definition pg_dump.c:6212
static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
Definition pg_dump.c:14435
static void dumpOpr(Archive *fout, const OprInfo *oprinfo)
Definition pg_dump.c:14123
static void selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
Definition pg_dump.c:2354
static void selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
Definition pg_dump.c:2336
static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
Definition pg_dump.c:19448
static void dumpFunc(Archive *fout, const FuncInfo *finfo)
Definition pg_dump.c:13467
static void selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
Definition pg_dump.c:2182
static void BuildArchiveDependencies(Archive *fout)
Definition pg_dump.c:20497
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:7122
static const char *const SeqTypeNames[]
Definition pg_dump.c:119
void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:7676
static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
Definition pg_dump.c:3053
static int nsequences
Definition pg_dump.c:215
static const char * getAttrName(int attrnum, const TableInfo *tblInfo)
Definition pg_dump.c:18254
static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
Definition pg_dump.c:16140
static RoleNameItem * rolenames
Definition pg_dump.c:198
static void collectRoleNames(Archive *fout)
Definition pg_dump.c:10733
static PGresult * fetchAttributeStats(Archive *fout)
Definition pg_dump.c:11031
static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions, const char *prefix, Archive *fout)
Definition pg_dump.c:20698
void getOpclasses(Archive *fout)
Definition pg_dump.c:6658
void getForeignServers(Archive *fout)
Definition pg_dump.c:10512
void getFuncs(Archive *fout)
Definition pg_dump.c:6927
static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
Definition pg_dump.c:2884
static void prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
Definition pg_dump.c:1937
static bool dosync
Definition pg_dump.c:152
static int dumpTableData_copy(Archive *fout, const void *dcontext)
Definition pg_dump.c:2394
#define MAX_BLOBS_PER_ARCHIVE_ENTRY
Definition pg_dump.c:237
static const char * getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
Definition pg_dump.c:20601
static void getDependencies(Archive *fout)
Definition pg_dump.c:20194
static void buildMatViewRefreshDependencies(Archive *fout)
Definition pg_dump.c:3140
void getTSDictionaries(Archive *fout)
Definition pg_dump.c:10244
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:5726
#define DUMP_DEFAULT_ROWS_PER_INSERT
Definition pg_dump.c:230
void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:4850
static SeqType parse_sequence_type(const char *name)
Definition pg_dump.c:19101
static const char * getRoleName(const char *roleoid_str)
Definition pg_dump.c:10697
static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
Definition pg_dump.c:13237
static SequenceItem * sequences
Definition pg_dump.c:214
static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
Definition pg_dump.c:2999
static int findComments(Oid classoid, Oid objoid, CommentItem **items)
Definition pg_dump.c:11516
static SimpleStringList foreign_servers_include_patterns
Definition pg_dump.c:182
static void selectDumpableCast(CastInfo *cast, Archive *fout)
Definition pg_dump.c:2204
void getCasts(Archive *fout)
Definition pg_dump.c:9057
static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
Definition pg_dump.c:4667
static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
Definition pg_dump.c:4433
void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:7857
static void setupDumpWorker(Archive *AH)
Definition pg_dump.c:1610
static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
Definition pg_dump.c:8467
void getTSConfigurations(Archive *fout)
Definition pg_dump.c:10369
static int nrolenames
Definition pg_dump.c:199
static int findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
Definition pg_dump.c:16716
static SimpleStringList table_include_patterns_and_children
Definition pg_dump.c:173
static char * convertRegProcReference(const char *proc)
Definition pg_dump.c:14342
static void getAdditionalACLs(Archive *fout)
Definition pg_dump.c:10768
static void getTableDataFKConstraints(void)
Definition pg_dump.c:3255
static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
Definition pg_dump.c:3034
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:6584
void getConversions(Archive *fout)
Definition pg_dump.c:6522
void getRules(Archive *fout)
Definition pg_dump.c:8602
static void dumpDomain(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12717
void getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition pg_dump.c:9251
static void collectComments(Archive *fout)
Definition pg_dump.c:11593
static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
Definition pg_dump.c:8490
static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
Definition pg_dump.c:14784
static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
Definition pg_dump.c:16334
static void selectDumpableObject(DumpableObject *dobj, Archive *fout)
Definition pg_dump.c:2372
static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
Definition pg_dump.c:15892
static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
Definition pg_dump.c:18434
static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
Definition pg_dump.c:5427
void getCollations(Archive *fout)
Definition pg_dump.c:6456
static char * format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
Definition pg_dump.c:13415
static int strict_names
Definition pg_dump.c:157
static void dumpTransform(Archive *fout, const TransformInfo *transform)
Definition pg_dump.c:13994
void getAggregates(Archive *fout)
Definition pg_dump.c:6786
static void dumpLO(Archive *fout, const LoInfo *loinfo)
Definition pg_dump.c:4125
void getNamespaces(Archive *fout)
Definition pg_dump.c:6005
static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
Definition pg_dump.c:5020
void getPublications(Archive *fout)
Definition pg_dump.c:4551
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:5961
static void dumpDumpableObject(Archive *fout, DumpableObject *dobj)
Definition pg_dump.c:11678
static void getLOs(Archive *fout)
Definition pg_dump.c:3960
static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf, const char *dbname, Oid dboid)
Definition pg_dump.c:3805
void getTSParsers(Archive *fout)
Definition pg_dump.c:10170
static DumpId lo_metadata_dumpId
Definition pg_dump.c:221
static void setup_connection(Archive *AH, const char *dumpencoding, const char *dumpsnapshot, char *use_role)
Definition pg_dump.c:1429
static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
Definition pg_dump.c:19078
static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12404
static void selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
Definition pg_dump.c:2262
static const char * fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
Definition pg_dump.c:20652
static void expand_table_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names, bool with_child_tables)
Definition pg_dump.c:1841
static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj, DumpId **dependencies, int *nDeps, int *allocDeps)
Definition pg_dump.c:20545
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:10028
static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
Definition pg_dump.c:17110
static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
Definition pg_dump.c:15748
static void expand_foreign_server_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids)
Definition pg_dump.c:1789
TableInfo * getTables(Archive *fout, int *numTables)
Definition pg_dump.c:7199
static void dumpRule(Archive *fout, const RuleInfo *rinfo)
Definition pg_dump.c:19753
static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12942
static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
Definition pg_dump.c:12106
static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
Definition pg_dump.c:11952
#define fmtQualifiedDumpable(obj)
Definition pg_dump.c:242
static bool nonemptyReloptions(const char *reloptions)
Definition pg_dump.c:20686
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:18554
void getExtendedStatistics(Archive *fout)
Definition pg_dump.c:8226
static NamespaceInfo * findNamespace(Oid nsoid)
Definition pg_dump.c:6119
static char * get_synchronized_snapshot(Archive *fout)
Definition pg_dump.c:1625
static int dumpLOs(Archive *fout, const void *arg)
Definition pg_dump.c:4215
static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
Definition pg_dump.c:5496
static void appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname, const char *argtype, const char *argval)
Definition pg_dump.c:11013
void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition pg_dump.c:20013
static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
Definition pg_dump.c:19663
static int BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
Definition pg_dump.c:5821
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:10897
void getDefaultACLs(Archive *fout)
Definition pg_dump.c:10600
static SimpleStringList tabledata_exclude_patterns
Definition pg_dump.c:178
static void dumpConversion(Archive *fout, const ConvInfo *convinfo)
Definition pg_dump.c:15260
static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
Definition pg_dump.c:16070
static void dumpProcLang(Archive *fout, const ProcLangInfo *plang)
Definition pg_dump.c:13283
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:16554
void getSubscriptions(Archive *fout)
Definition pg_dump.c:5121
static void collectSecLabels(Archive *fout)
Definition pg_dump.c:16795
static void selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
Definition pg_dump.c:2297
static void collectSequences(Archive *fout)
Definition pg_dump.c:19132
static Oid g_last_builtin_oid
Definition pg_dump.c:154
#define MAX_ATTR_STATS_RELS
Definition pg_dump.c:224
void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:8699
void getTransforms(Archive *fout)
Definition pg_dump.c:9167
void getEventTriggers(Archive *fout)
Definition pg_dump.c:8895
static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode)
Definition pg_dump.c:1639
static void read_dump_filters(const char *filename, DumpOptions *dopt)
Definition pg_dump.c:20717
static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
Definition pg_dump.c:15950
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:9146
static bool checkExtensionMembership(DumpableObject *dobj, Archive *fout)
Definition pg_dump.c:1962
static CommentItem * comments
Definition pg_dump.c:202
static int dumpTableData_insert(Archive *fout, const void *dcontext)
Definition pg_dump.c:2562
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:5871
void getTSTemplates(Archive *fout)
Definition pg_dump.c:10310
static void set_restrict_relation_kind(Archive *AH, const char *value)
Definition pg_dump.c:5100
static char * format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
Definition pg_dump.c:15356
void getProcLangs(Archive *fout)
Definition pg_dump.c:8973
static void dumpSequence(Archive *fout, const TableInfo *tbinfo)
Definition pg_dump.c:19194
bool shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
Definition pg_dump.c:10155
static TableInfo * getRootTableInfo(const TableInfo *tbinfo)
Definition pg_dump.c:2831
void getSubscriptionRelations(Archive *fout)
Definition pg_dump.c:5341
void getOperators(Archive *fout)
Definition pg_dump.c:6380
static SimpleOidList foreign_servers_include_oids
Definition pg_dump.c:183
static void dumpCollation(Archive *fout, const CollInfo *collinfo)
Definition pg_dump.c:15003
static void dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
Definition pg_dump.c:16634
static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo, PGresult *res)
Definition pg_dump.c:13148
static void expand_extension_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names)
Definition pg_dump.c:1736
void getOpfamilies(Archive *fout)
Definition pg_dump.c:6721
static void selectDumpableType(TypeInfo *tyinfo, Archive *fout)
Definition pg_dump.c:2137
static SimpleOidList schema_include_oids
Definition pg_dump.c:168
static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
Definition pg_dump.c:14503
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:51
PGDLLIMPORT char * optarg
Definition getopt.c:53
NameData subname
static char buf[DEFAULT_XLOG_SEG_SIZE]
char typalign
Definition pg_type.h:176
#define pg_encoding_to_char
Definition pg_wchar.h:630
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 snprintf
Definition port.h:260
const char * get_progname(const char *argv0)
Definition path.c:652
#define printf(...)
Definition port.h:266
off_t pgoff_t
Definition port.h:421
#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:339
void simple_string_list_append(SimpleStringList *list, const char *val)
Definition simple_list.c:63
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 isStandby
Definition pg_backup.h:235
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:727
bool subpasswordrequired
Definition pg_dump.h:717
const char * rolname
Definition pg_dump.h:711
char * subsynccommit
Definition pg_dump.h:724
char * subpublications
Definition pg_dump.h:725
char * subslotname
Definition pg_dump.h:723
char subtwophasestate
Definition pg_dump.h:715
bool subretaindeadtuples
Definition pg_dump.h:720
char * subconninfo
Definition pg_dump.h:722
DumpableObject dobj
Definition pg_dump.h:710
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:519
TableInfo * contable
Definition pg_dump.h:518
DumpableObject dobj
Definition pg_dump.h:517
DumpId conindex
Definition pg_dump.h:523
bool condeferrable
Definition pg_dump.h:524
char * condef
Definition pg_dump.h:521
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:462
char ** indAttNames
Definition pg_dump.h:461
int32 relpages
Definition pg_dump.h:451
int32 relallfrozen
Definition pg_dump.h:454
char * reltuples
Definition pg_dump.h:452
teSection section
Definition pg_dump.h:463
int32 relallvisible
Definition pg_dump.h:453
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:476
bool separate
Definition pg_dump.h:481
char ev_enabled
Definition pg_dump.h:480
bool is_instead
Definition pg_dump.h:479
TableInfo * ruletable
Definition pg_dump.h:477
char ev_type
Definition pg_dump.h:478
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
DumpId * dependencies
DumpableObject dobj
Definition pg_dump.h:554
DumpableObject dobj
Definition pg_dump.h:205
char data[NAMEDATALEN]
Definition c.h:761
#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:127
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
bool SplitGUCList(char *rawstring, char separator, List **namelist)
Definition varlena.c:2978
const char * description
const char * type
const char * name
ArchiveMode
Definition xlog.h:65

◆ MAX_ATTR_STATS_RELS

#define MAX_ATTR_STATS_RELS   64

Definition at line 224 of file pg_dump.c.

◆ MAX_BLOBS_PER_ARCHIVE_ENTRY

#define MAX_BLOBS_PER_ARCHIVE_ENTRY   1000

Definition at line 237 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 20371 of file pg_dump.c.

20373{
20376 int i;
20377
20378 for (i = 0; i < numObjs; i++)
20379 {
20380 DumpableObject *dobj = dobjs[i];
20381
20382 /*
20383 * The classification of object types here must match the SECTION_xxx
20384 * values assigned during subsequent ArchiveEntry calls!
20385 */
20386 switch (dobj->objType)
20387 {
20388 case DO_NAMESPACE:
20389 case DO_EXTENSION:
20390 case DO_TYPE:
20391 case DO_SHELL_TYPE:
20392 case DO_FUNC:
20393 case DO_AGG:
20394 case DO_OPERATOR:
20395 case DO_ACCESS_METHOD:
20396 case DO_OPCLASS:
20397 case DO_OPFAMILY:
20398 case DO_COLLATION:
20399 case DO_CONVERSION:
20400 case DO_TABLE:
20401 case DO_TABLE_ATTACH:
20402 case DO_ATTRDEF:
20403 case DO_PROCLANG:
20404 case DO_CAST:
20405 case DO_DUMMY_TYPE:
20406 case DO_TSPARSER:
20407 case DO_TSDICT:
20408 case DO_TSTEMPLATE:
20409 case DO_TSCONFIG:
20410 case DO_FDW:
20411 case DO_FOREIGN_SERVER:
20412 case DO_TRANSFORM:
20413 /* Pre-data objects: must come before the pre-data boundary */
20415 break;
20416 case DO_TABLE_DATA:
20417 case DO_SEQUENCE_SET:
20418 case DO_LARGE_OBJECT:
20420 /* Data objects: must come between the boundaries */
20421 addObjectDependency(dobj, preDataBound->dumpId);
20423 break;
20424 case DO_INDEX:
20425 case DO_INDEX_ATTACH:
20426 case DO_STATSEXT:
20427 case DO_REFRESH_MATVIEW:
20428 case DO_TRIGGER:
20429 case DO_EVENT_TRIGGER:
20430 case DO_DEFAULT_ACL:
20431 case DO_POLICY:
20432 case DO_PUBLICATION:
20433 case DO_PUBLICATION_REL:
20435 case DO_SUBSCRIPTION:
20437 /* Post-data objects: must come after the post-data boundary */
20438 addObjectDependency(dobj, postDataBound->dumpId);
20439 break;
20440 case DO_RULE:
20441 /* Rules are post-data, but only if dumped separately */
20442 if (((RuleInfo *) dobj)->separate)
20443 addObjectDependency(dobj, postDataBound->dumpId);
20444 break;
20445 case DO_CONSTRAINT:
20446 case DO_FK_CONSTRAINT:
20447 /* Constraints are post-data, but only if dumped separately */
20448 if (((ConstraintInfo *) dobj)->separate)
20449 addObjectDependency(dobj, postDataBound->dumpId);
20450 break;
20452 /* nothing to do */
20453 break;
20455 /* must come after the pre-data boundary */
20456 addObjectDependency(dobj, preDataBound->dumpId);
20457 break;
20458 case DO_REL_STATS:
20459 /* stats section varies by parent object type, DATA or POST */
20460 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
20461 {
20462 addObjectDependency(dobj, preDataBound->dumpId);
20463 addObjectDependency(postDataBound, dobj->dumpId);
20464 }
20465 else
20466 addObjectDependency(dobj, postDataBound->dumpId);
20467 break;
20468 }
20469 }
20470}

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 8467 of file pg_dump.c.

8468{
8469 SimplePtrListCell *cell;
8470
8472
8473 for (cell = refidx->partattaches.head; cell; cell = cell->next)
8474 {
8476
8477 addObjectDependency(dobj, attach->dobj.dumpId);
8478
8479 if (attach->partitionIdx->partattaches.head != NULL)
8480 addConstrChildIdxDeps(dobj, attach->partitionIdx);
8481 }
8482}

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 5650 of file pg_dump.c.

5656{
5657 if (dobj->depends_on_ext)
5658 {
5659 char *nm;
5660 PGresult *res;
5661 PQExpBuffer query;
5662 int ntups;
5663 int i_extname;
5664 int i;
5665
5666 /* dodge fmtId() non-reentrancy */
5667 nm = pg_strdup(objname);
5668
5669 query = createPQExpBuffer();
5670 appendPQExpBuffer(query,
5671 "SELECT e.extname "
5672 "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
5673 "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
5674 "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
5675 "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
5676 catalog,
5677 dobj->catId.oid);
5678 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5679 ntups = PQntuples(res);
5680 i_extname = PQfnumber(res, "extname");
5681 for (i = 0; i < ntups; i++)
5682 {
5683 appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
5684 keyword, nm,
5685 fmtId(PQgetvalue(res, i, i_extname)));
5686 }
5687
5688 PQclear(res);
5689 destroyPQExpBuffer(query);
5690 pg_free(nm);
5691 }
5692}

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 11013 of file pg_dump.c.

11015{
11016 appendPQExpBufferStr(out, ",\n\t");
11017
11018 appendStringLiteralAH(out, argname, fout);
11019 appendPQExpBufferStr(out, ", ");
11020
11022 appendPQExpBuffer(out, "::%s", argtype);
11023}

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 20698 of file pg_dump.c.

20700{
20701 bool res;
20702
20703 res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
20704 fout->std_strings);
20705 if (!res)
20706 pg_log_warning("could not parse %s array", "reloptions");
20707}

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 5961 of file pg_dump.c.

5966{
5968 int i;
5969
5970 if (!dobj->ext_member)
5971 return;
5972
5973 /*
5974 * Find the parent extension. We could avoid this search if we wanted to
5975 * add a link field to DumpableObject, but the space costs of that would
5976 * be considerable. We assume that member objects could only have a
5977 * direct dependency on their own extension, not any others.
5978 */
5979 for (i = 0; i < dobj->nDeps; i++)
5980 {
5982 if (extobj && extobj->objType == DO_EXTENSION)
5983 break;
5984 extobj = NULL;
5985 }
5986 if (extobj == NULL)
5987 pg_fatal("could not find parent extension for %s %s",
5988 objtype, objname);
5989
5991 "\n-- For binary upgrade, handle extension membership the hard way\n");
5992 appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
5993 fmtId(extobj->name),
5994 objtype);
5995 if (objnamespace && *objnamespace)
5997 appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
5998}

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 5871 of file pg_dump.c.

5873{
5876
5878
5879 /*
5880 * Preserve the OID and relfilenumber of the table, table's index, table's
5881 * toast table and toast table's index if any.
5882 *
5883 * One complexity is that the current table definition might not require
5884 * the creation of a TOAST table, but the old database might have a TOAST
5885 * table that was created earlier, before some wide columns were dropped.
5886 * By setting the TOAST oid we force creation of the TOAST heap and index
5887 * by the new backend, so we can copy the files during binary upgrade
5888 * without worrying about this case.
5889 */
5890 key.oid = pg_class_oid;
5894
5896 "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
5897
5898 if (entry->relkind != RELKIND_INDEX &&
5900 {
5902 "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
5903 pg_class_oid);
5904
5905 /*
5906 * Not every relation has storage. Also, in a pre-v12 database,
5907 * partitioned tables have a relfilenumber, which should not be
5908 * preserved when upgrading.
5909 */
5910 if (RelFileNumberIsValid(entry->relfilenumber) &&
5913 "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
5914 entry->relfilenumber);
5915
5916 /*
5917 * In a pre-v12 database, partitioned tables might be marked as having
5918 * toast tables, but we should ignore them if so.
5919 */
5920 if (OidIsValid(entry->toast_oid) &&
5922 {
5924 "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
5925 entry->toast_oid);
5927 "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
5928 entry->toast_relfilenumber);
5929
5930 /* every toast table has an index */
5932 "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5933 entry->toast_index_oid);
5935 "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5937 }
5938 }
5939 else
5940 {
5941 /* Preserve the OID and relfilenumber of the index */
5943 "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5944 pg_class_oid);
5946 "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5947 entry->relfilenumber);
5948 }
5949
5951}

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 5806 of file pg_dump.c.

5809{
5810 Oid pg_type_oid = tbinfo->reltype;
5811
5814 pg_type_oid, false, false);
5815}

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 5726 of file pg_dump.c.

5731{
5733 PGresult *res;
5737 TypeInfo *tinfo;
5738
5739 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
5741 "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5742 pg_type_oid);
5743
5745 if (tinfo)
5746 pg_type_array_oid = tinfo->typarray;
5747 else
5749
5752
5754 {
5756 "\n-- For binary upgrade, must preserve pg_type array oid\n");
5758 "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5760 }
5761
5762 /*
5763 * Pre-set the multirange type oid and its own array type oid.
5764 */
5766 {
5767 if (fout->remoteVersion >= 140000)
5768 {
5770 "SELECT t.oid, t.typarray "
5771 "FROM pg_catalog.pg_type t "
5772 "JOIN pg_catalog.pg_range r "
5773 "ON t.oid = r.rngmultitypid "
5774 "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
5775 pg_type_oid);
5776
5778
5779 pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
5780 pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
5781
5782 PQclear(res);
5783 }
5784 else
5785 {
5788 }
5789
5791 "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
5793 "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5796 "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
5798 "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5800 }
5801
5803}

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 5821 of file pg_dump.c.

5822{
5825
5826 return pg_cmp_u32(v1.oid, v2.oid);
5827}

References fb(), and pg_cmp_u32().

Referenced by binary_upgrade_set_pg_class_oids().

◆ BuildArchiveDependencies()

static void BuildArchiveDependencies ( Archive fout)
static

Definition at line 20497 of file pg_dump.c.

20498{
20500 TocEntry *te;
20501
20502 /* Scan all TOC entries in the archive */
20503 for (te = AH->toc->next; te != AH->toc; te = te->next)
20504 {
20505 DumpableObject *dobj;
20506 DumpId *dependencies;
20507 int nDeps;
20508 int allocDeps;
20509
20510 /* No need to process entries that will not be dumped */
20511 if (te->reqs == 0)
20512 continue;
20513 /* Ignore entries that already have "special" dependencies */
20514 if (te->nDeps > 0)
20515 continue;
20516 /* Otherwise, look up the item's original DumpableObject, if any */
20517 dobj = findObjectByDumpId(te->dumpId);
20518 if (dobj == NULL)
20519 continue;
20520 /* No work if it has no dependencies */
20521 if (dobj->nDeps <= 0)
20522 continue;
20523 /* Set up work array */
20524 allocDeps = 64;
20525 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
20526 nDeps = 0;
20527 /* Recursively find all dumpable dependencies */
20528 findDumpableDependencies(AH, dobj,
20529 &dependencies, &nDeps, &allocDeps);
20530 /* And save 'em ... */
20531 if (nDeps > 0)
20532 {
20533 dependencies = (DumpId *) pg_realloc(dependencies,
20534 nDeps * sizeof(DumpId));
20535 te->dependencies = dependencies;
20536 te->nDeps = nDeps;
20537 }
20538 else
20539 free(dependencies);
20540 }
20541}

References _tocEntry::dependencies, _tocEntry::dumpId, fb(), findDumpableDependencies(), findObjectByDumpId(), free, _tocEntry::nDeps, _dumpableObject::nDeps, _tocEntry::next, pg_malloc(), pg_realloc(), _tocEntry::reqs, and _archiveHandle::toc.

Referenced by main().

◆ buildMatViewRefreshDependencies()

static void buildMatViewRefreshDependencies ( Archive fout)
static

Definition at line 3140 of file pg_dump.c.

3141{
3142 PQExpBuffer query;
3143 PGresult *res;
3144 int ntups,
3145 i;
3146 int i_classid,
3147 i_objid,
3148 i_refobjid;
3149
3150 /* No Mat Views before 9.3. */
3151 if (fout->remoteVersion < 90300)
3152 return;
3153
3154 query = createPQExpBuffer();
3155
3156 appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
3157 "( "
3158 "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
3159 "FROM pg_depend d1 "
3160 "JOIN pg_class c1 ON c1.oid = d1.objid "
3161 "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
3162 " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
3163 "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
3164 "AND d2.objid = r1.oid "
3165 "AND d2.refobjid <> d1.objid "
3166 "JOIN pg_class c2 ON c2.oid = d2.refobjid "
3167 "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
3169 "WHERE d1.classid = 'pg_class'::regclass "
3170 "UNION "
3171 "SELECT w.objid, d3.refobjid, c3.relkind "
3172 "FROM w "
3173 "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
3174 "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
3175 "AND d3.objid = r3.oid "
3176 "AND d3.refobjid <> w.refobjid "
3177 "JOIN pg_class c3 ON c3.oid = d3.refobjid "
3178 "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
3180 ") "
3181 "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
3182 "FROM w "
3183 "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
3184
3185 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3186
3187 ntups = PQntuples(res);
3188
3189 i_classid = PQfnumber(res, "classid");
3190 i_objid = PQfnumber(res, "objid");
3191 i_refobjid = PQfnumber(res, "refobjid");
3192
3193 for (i = 0; i < ntups; i++)
3194 {
3195 CatalogId objId;
3197 DumpableObject *dobj;
3201
3202 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
3203 objId.oid = atooid(PQgetvalue(res, i, i_objid));
3204 refobjId.tableoid = objId.tableoid;
3205 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
3206
3207 dobj = findObjectByCatalogId(objId);
3208 if (dobj == NULL)
3209 continue;
3210
3211 Assert(dobj->objType == DO_TABLE);
3212 tbinfo = (TableInfo *) dobj;
3213 Assert(tbinfo->relkind == RELKIND_MATVIEW);
3214 dobj = (DumpableObject *) tbinfo->dataObj;
3215 if (dobj == NULL)
3216 continue;
3218
3220 if (refdobj == NULL)
3221 continue;
3222
3223 Assert(refdobj->objType == DO_TABLE);
3225 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
3226 refdobj = (DumpableObject *) reftbinfo->dataObj;
3227 if (refdobj == NULL)
3228 continue;
3229 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
3230
3231 addObjectDependency(dobj, refdobj->dumpId);
3232
3233 if (!reftbinfo->relispopulated)
3234 tbinfo->relispopulated = false;
3235 }
3236
3237 PQclear(res);
3238
3239 destroyPQExpBuffer(query);
3240}

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 1962 of file pg_dump.c.

1963{
1965
1966 if (ext == NULL)
1967 return false;
1968
1969 dobj->ext_member = true;
1970
1971 /* Record dependency so that getDependencies needn't deal with that */
1972 addObjectDependency(dobj, ext->dobj.dumpId);
1973
1974 /*
1975 * In 9.6 and above, mark the member object to have any non-initial ACLs
1976 * dumped. (Any initial ACLs will be removed later, using data from
1977 * pg_init_privs, so that we'll dump only the delta from the extension's
1978 * initial setup.)
1979 *
1980 * Prior to 9.6, we do not include any extension member components.
1981 *
1982 * In binary upgrades, we still dump all components of the members
1983 * individually, since the idea is to exactly reproduce the database
1984 * contents rather than replace the extension contents with something
1985 * different.
1986 *
1987 * Note: it might be interesting someday to implement storage and delta
1988 * dumping of extension members' RLS policies and/or security labels.
1989 * However there is a pitfall for RLS policies: trying to dump them
1990 * requires getting a lock on their tables, and the calling user might not
1991 * have privileges for that. We need no lock to examine a table's ACLs,
1992 * so the current feature doesn't have a problem of that sort.
1993 */
1994 if (fout->dopt->binary_upgrade)
1995 dobj->dump = ext->dobj.dump;
1996 else
1997 {
1998 if (fout->remoteVersion < 90600)
1999 dobj->dump = DUMP_COMPONENT_NONE;
2000 else
2001 dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
2002 }
2003
2004 return true;
2005}

References addObjectDependency(), _dumpableObject::catId, _extensionInfo::dobj, _dumpableObject::dump, DUMP_COMPONENT_ACL, DUMP_COMPONENT_NONE, _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 5837 of file pg_dump.c.

5838{
5839 PGresult *res;
5840 const char *query;
5841
5842 query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
5843 "ct.relfilenode, i.indexrelid, cti.relfilenode "
5844 "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
5845 "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
5846 "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
5847 "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
5848 "ORDER BY c.oid;";
5849
5850 res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
5851
5855
5856 for (int i = 0; i < nbinaryUpgradeClassOids; i++)
5857 {
5865 }
5866
5867 PQclear(res);
5868}

References atooid, binaryUpgradeClassOids, ExecuteSqlQuery(), fb(), i, nbinaryUpgradeClassOids, BinaryUpgradeClassOidItem::oid, pg_malloc(), 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 11593 of file pg_dump.c.

11594{
11595 PGresult *res;
11596 PQExpBuffer query;
11597 int i_description;
11598 int i_classoid;
11599 int i_objoid;
11600 int i_objsubid;
11601 int ntups;
11602 int i;
11603 DumpableObject *dobj;
11604
11605 query = createPQExpBuffer();
11606
11607 appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
11608 "FROM pg_catalog.pg_description "
11609 "ORDER BY classoid, objoid, objsubid");
11610
11611 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11612
11613 /* Construct lookup table containing OIDs in numeric form */
11614
11615 i_description = PQfnumber(res, "description");
11616 i_classoid = PQfnumber(res, "classoid");
11617 i_objoid = PQfnumber(res, "objoid");
11618 i_objsubid = PQfnumber(res, "objsubid");
11619
11620 ntups = PQntuples(res);
11621
11622 comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
11623 ncomments = 0;
11624 dobj = NULL;
11625
11626 for (i = 0; i < ntups; i++)
11627 {
11628 CatalogId objId;
11629 int subid;
11630
11631 objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
11632 objId.oid = atooid(PQgetvalue(res, i, i_objoid));
11633 subid = atoi(PQgetvalue(res, i, i_objsubid));
11634
11635 /* We needn't remember comments that don't match any dumpable object */
11636 if (dobj == NULL ||
11637 dobj->catId.tableoid != objId.tableoid ||
11638 dobj->catId.oid != objId.oid)
11639 dobj = findObjectByCatalogId(objId);
11640 if (dobj == NULL)
11641 continue;
11642
11643 /*
11644 * Comments on columns of composite types are linked to the type's
11645 * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
11646 * in the type's own DumpableObject.
11647 */
11648 if (subid != 0 && dobj->objType == DO_TABLE &&
11649 ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
11650 {
11652
11653 cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
11654 if (cTypeInfo)
11655 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
11656 }
11657 else
11658 dobj->components |= DUMP_COMPONENT_COMMENT;
11659
11662 comments[ncomments].objoid = objId.oid;
11663 comments[ncomments].objsubid = subid;
11664 ncomments++;
11665 }
11666
11667 PQclear(res);
11668 destroyPQExpBuffer(query);
11669}

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(), 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 10733 of file pg_dump.c.

10734{
10735 PGresult *res;
10736 const char *query;
10737 int i;
10738
10739 query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
10740
10741 res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
10742
10743 nrolenames = PQntuples(res);
10744
10746
10747 for (i = 0; i < nrolenames; i++)
10748 {
10749 rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
10751 }
10752
10753 PQclear(res);
10754}

References atooid, ExecuteSqlQuery(), fb(), i, nrolenames, pg_malloc(), 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 16795 of file pg_dump.c.

16796{
16797 PGresult *res;
16798 PQExpBuffer query;
16799 int i_label;
16800 int i_provider;
16801 int i_classoid;
16802 int i_objoid;
16803 int i_objsubid;
16804 int ntups;
16805 int i;
16806 DumpableObject *dobj;
16807
16808 query = createPQExpBuffer();
16809
16811 "SELECT label, provider, classoid, objoid, objsubid "
16812 "FROM pg_catalog.pg_seclabels "
16813 "ORDER BY classoid, objoid, objsubid");
16814
16815 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16816
16817 /* Construct lookup table containing OIDs in numeric form */
16818 i_label = PQfnumber(res, "label");
16819 i_provider = PQfnumber(res, "provider");
16820 i_classoid = PQfnumber(res, "classoid");
16821 i_objoid = PQfnumber(res, "objoid");
16822 i_objsubid = PQfnumber(res, "objsubid");
16823
16824 ntups = PQntuples(res);
16825
16826 seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
16827 nseclabels = 0;
16828 dobj = NULL;
16829
16830 for (i = 0; i < ntups; i++)
16831 {
16832 CatalogId objId;
16833 int subid;
16834
16835 objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
16836 objId.oid = atooid(PQgetvalue(res, i, i_objoid));
16837 subid = atoi(PQgetvalue(res, i, i_objsubid));
16838
16839 /* We needn't remember labels that don't match any dumpable object */
16840 if (dobj == NULL ||
16841 dobj->catId.tableoid != objId.tableoid ||
16842 dobj->catId.oid != objId.oid)
16843 dobj = findObjectByCatalogId(objId);
16844 if (dobj == NULL)
16845 continue;
16846
16847 /*
16848 * Labels on columns of composite types are linked to the type's
16849 * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
16850 * in the type's own DumpableObject.
16851 */
16852 if (subid != 0 && dobj->objType == DO_TABLE &&
16853 ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
16854 {
16856
16857 cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
16858 if (cTypeInfo)
16859 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
16860 }
16861 else
16862 dobj->components |= DUMP_COMPONENT_SECLABEL;
16863
16867 seclabels[nseclabels].objoid = objId.oid;
16868 seclabels[nseclabels].objsubid = subid;
16869 nseclabels++;
16870 }
16871
16872 PQclear(res);
16873 destroyPQExpBuffer(query);
16874}

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(), 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 19132 of file pg_dump.c.

19133{
19134 PGresult *res;
19135 const char *query;
19136
19137 /*
19138 * Before Postgres 10, sequence metadata is in the sequence itself. With
19139 * some extra effort, we might be able to use the sorted table for those
19140 * versions, but for now it seems unlikely to be worth it.
19141 *
19142 * Since version 18, we can gather the sequence data in this query with
19143 * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
19144 */
19145 if (fout->remoteVersion < 100000)
19146 return;
19147 else if (fout->remoteVersion < 180000 ||
19148 (!fout->dopt->dumpData && !fout->dopt->sequence_data))
19149 query = "SELECT seqrelid, format_type(seqtypid, NULL), "
19150 "seqstart, seqincrement, "
19151 "seqmax, seqmin, "
19152 "seqcache, seqcycle, "
19153 "NULL, 'f' "
19154 "FROM pg_catalog.pg_sequence "
19155 "ORDER BY seqrelid";
19156 else
19157 query = "SELECT seqrelid, format_type(seqtypid, NULL), "
19158 "seqstart, seqincrement, "
19159 "seqmax, seqmin, "
19160 "seqcache, seqcycle, "
19161 "last_value, is_called "
19162 "FROM pg_catalog.pg_sequence, "
19163 "pg_get_sequence_data(seqrelid) "
19164 "ORDER BY seqrelid;";
19165
19166 res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
19167
19168 nsequences = PQntuples(res);
19170
19171 for (int i = 0; i < nsequences; i++)
19172 {
19173 sequences[i].oid = atooid(PQgetvalue(res, i, 0));
19175 sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
19176 sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
19177 sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
19178 sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
19179 sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
19180 sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
19181 sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
19182 sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
19183 sequences[i].null_seqtuple = (PQgetisnull(res, i, 8) || PQgetisnull(res, i, 9));
19184 }
19185
19186 PQclear(res);
19187}

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(), 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 14342 of file pg_dump.c.

14343{
14344 char *name;
14345 char *paren;
14346 bool inquote;
14347
14348 /* In all cases "-" means a null reference */
14349 if (strcmp(proc, "-") == 0)
14350 return NULL;
14351
14352 name = pg_strdup(proc);
14353 /* find non-double-quoted left paren */
14354 inquote = false;
14355 for (paren = name; *paren; paren++)
14356 {
14357 if (*paren == '(' && !inquote)
14358 {
14359 *paren = '\0';
14360 break;
14361 }
14362 if (*paren == '"')
14363 inquote = !inquote;
14364 }
14365 return name;
14366}

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

Referenced by dumpOpr().

◆ convertTSFunction()

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

Definition at line 14413 of file pg_dump.c.

14414{
14415 char *result;
14416 char query[128];
14417 PGresult *res;
14418
14419 snprintf(query, sizeof(query),
14420 "SELECT '%u'::pg_catalog.regproc", funcOid);
14421 res = ExecuteSqlQueryForSingleRow(fout, query);
14422
14423 result = pg_strdup(PQgetvalue(res, 0, 0));
14424
14425 PQclear(res);
14426
14427 return result;
14428}

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

Referenced by dumpTSParser(), and dumpTSTemplate().

◆ createBoundaryObjects()

static DumpableObject * createBoundaryObjects ( void  )
static

Definition at line 20347 of file pg_dump.c.

20348{
20350
20351 dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
20352
20354 dobjs[0].catId = nilCatalogId;
20355 AssignDumpId(dobjs + 0);
20356 dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
20357
20358 dobjs[1].objType = DO_POST_DATA_BOUNDARY;
20359 dobjs[1].catId = nilCatalogId;
20360 AssignDumpId(dobjs + 1);
20361 dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
20362
20363 return dobjs;
20364}

References AssignDumpId(), DO_POST_DATA_BOUNDARY, DO_PRE_DATA_BOUNDARY, fb(), nilCatalogId, _dumpableObject::objType, pg_malloc(), and pg_strdup().

Referenced by main().

◆ createDummyViewAsClause()

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

Definition at line 17070 of file pg_dump.c.

17071{
17072 PQExpBuffer result = createPQExpBuffer();
17073 int j;
17074
17075 appendPQExpBufferStr(result, "SELECT");
17076
17077 for (j = 0; j < tbinfo->numatts; j++)
17078 {
17079 if (j > 0)
17080 appendPQExpBufferChar(result, ',');
17081 appendPQExpBufferStr(result, "\n ");
17082
17083 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
17084
17085 /*
17086 * Must add collation if not default for the type, because CREATE OR
17087 * REPLACE VIEW won't change it
17088 */
17089 if (OidIsValid(tbinfo->attcollation[j]))
17090 {
17091 CollInfo *coll;
17092
17093 coll = findCollationByOid(tbinfo->attcollation[j]);
17094 if (coll)
17095 appendPQExpBuffer(result, " COLLATE %s",
17097 }
17098
17099 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
17100 }
17101
17102 return result;
17103}

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

Referenced by dumpRule(), and dumpTableSchema().

◆ createViewAsClause()

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

Definition at line 17021 of file pg_dump.c.

17022{
17024 PQExpBuffer result = createPQExpBuffer();
17025 PGresult *res;
17026 int len;
17027
17028 /* Fetch the view definition */
17029 appendPQExpBuffer(query,
17030 "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
17031 tbinfo->dobj.catId.oid);
17032
17033 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17034
17035 if (PQntuples(res) != 1)
17036 {
17037 if (PQntuples(res) < 1)
17038 pg_fatal("query to obtain definition of view \"%s\" returned no data",
17039 tbinfo->dobj.name);
17040 else
17041 pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
17042 tbinfo->dobj.name);
17043 }
17044
17045 len = PQgetlength(res, 0, 0);
17046
17047 if (len == 0)
17048 pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
17049 tbinfo->dobj.name);
17050
17051 /* Strip off the trailing semicolon so that other things may follow. */
17052 Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
17053 appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
17054
17055 PQclear(res);
17056 destroyPQExpBuffer(query);
17057
17058 return result;
17059}

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

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 10028 of file pg_dump.c.

10036{
10037 DumpOptions *dopt = fout->dopt;
10038
10039 /*
10040 * If this not-null constraint is not valid, list its OID in
10041 * invalidnotnulloids and do nothing further. It'll be processed
10042 * elsewhere later.
10043 *
10044 * Because invalid not-null constraints are rare, we don't want to malloc
10045 * invalidnotnulloids until we're sure we're going it need it, which
10046 * happens here.
10047 */
10048 if (!PQgetisnull(res, r, i_notnull_invalidoid))
10049 {
10050 char *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
10051
10052 if (*invalidnotnulloids == NULL)
10053 {
10057 }
10058 else
10060
10061 /*
10062 * Track when a parent constraint is invalid for the cases where a
10063 * child constraint has been validated independenly.
10064 */
10065 tbinfo->notnull_invalid[j] = true;
10066
10067 /* nothing else to do */
10068 tbinfo->notnull_constrs[j] = NULL;
10069 return;
10070 }
10071
10072 /*
10073 * notnull_noinh is straight from the query result. notnull_islocal also,
10074 * though flagInhAttrs may change that one later.
10075 */
10076 tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
10077 tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
10078 tbinfo->notnull_invalid[j] = false;
10079
10080 /*
10081 * Determine a constraint name to use. If the column is not marked not-
10082 * null, we set NULL which cues ... to do nothing. An empty string says
10083 * to print an unnamed NOT NULL, and anything else is a constraint name to
10084 * use.
10085 */
10086 if (fout->remoteVersion < 180000)
10087 {
10088 /*
10089 * < 18 doesn't have not-null names, so an unnamed constraint is
10090 * sufficient.
10091 */
10092 if (PQgetisnull(res, r, i_notnull_name))
10093 tbinfo->notnull_constrs[j] = NULL;
10094 else
10095 tbinfo->notnull_constrs[j] = "";
10096 }
10097 else
10098 {
10099 if (PQgetisnull(res, r, i_notnull_name))
10100 tbinfo->notnull_constrs[j] = NULL;
10101 else
10102 {
10103 /*
10104 * In binary upgrade of inheritance child tables, must have a
10105 * constraint name that we can UPDATE later; same if there's a
10106 * comment on the constraint.
10107 */
10108 if ((dopt->binary_upgrade &&
10109 !tbinfo->ispartition &&
10110 !tbinfo->notnull_islocal) ||
10112 {
10113 tbinfo->notnull_constrs[j] =
10115 }
10116 else
10117 {
10118 char *default_name;
10119
10120 /* XXX should match ChooseConstraintName better */
10121 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
10122 tbinfo->attnames[j]);
10123 if (strcmp(default_name,
10124 PQgetvalue(res, r, i_notnull_name)) == 0)
10125 tbinfo->notnull_constrs[j] = "";
10126 else
10127 {
10128 tbinfo->notnull_constrs[j] =
10130 }
10132 }
10133 }
10134 }
10135}

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

Referenced by getTableAttrs().

◆ dumpAccessMethod()

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

Definition at line 14435 of file pg_dump.c.

14436{
14437 DumpOptions *dopt = fout->dopt;
14438 PQExpBuffer q;
14440 char *qamname;
14441
14442 /* Do nothing if not dumping schema */
14443 if (!dopt->dumpSchema)
14444 return;
14445
14446 q = createPQExpBuffer();
14448
14449 qamname = pg_strdup(fmtId(aminfo->dobj.name));
14450
14451 appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
14452
14453 switch (aminfo->amtype)
14454 {
14455 case AMTYPE_INDEX:
14456 appendPQExpBufferStr(q, "TYPE INDEX ");
14457 break;
14458 case AMTYPE_TABLE:
14459 appendPQExpBufferStr(q, "TYPE TABLE ");
14460 break;
14461 default:
14462 pg_log_warning("invalid type \"%c\" of access method \"%s\"",
14463 aminfo->amtype, qamname);
14466 free(qamname);
14467 return;
14468 }
14469
14470 appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
14471
14472 appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
14473 qamname);
14474
14475 if (dopt->binary_upgrade)
14477 "ACCESS METHOD", qamname, NULL);
14478
14479 if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14480 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
14481 ARCHIVE_OPTS(.tag = aminfo->dobj.name,
14482 .description = "ACCESS METHOD",
14483 .section = SECTION_PRE_DATA,
14484 .createStmt = q->data,
14485 .dropStmt = delq->data));
14486
14487 /* Dump Access Method Comments */
14488 if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14489 dumpComment(fout, "ACCESS METHOD", qamname,
14490 NULL, "",
14491 aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
14492
14495 free(qamname);
14496}

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(), 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 16426 of file pg_dump.c.

16430{
16432 DumpOptions *dopt = fout->dopt;
16433 const char *acls = dacl->acl;
16434 const char *acldefault = dacl->acldefault;
16435 char privtype = dacl->privtype;
16436 const char *initprivs = dacl->initprivs;
16437 const char *baseacls;
16438 PQExpBuffer sql;
16439
16440 /* Do nothing if ACL dump is not enabled */
16441 if (dopt->aclsSkip)
16442 return InvalidDumpId;
16443
16444 /* --data-only skips ACLs *except* large object ACLs */
16445 if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
16446 return InvalidDumpId;
16447
16448 sql = createPQExpBuffer();
16449
16450 /*
16451 * In binary upgrade mode, we don't run an extension's script but instead
16452 * dump out the objects independently and then recreate them. To preserve
16453 * any initial privileges which were set on extension objects, we need to
16454 * compute the set of GRANT and REVOKE commands necessary to get from the
16455 * default privileges of an object to its initial privileges as recorded
16456 * in pg_init_privs.
16457 *
16458 * At restore time, we apply these commands after having called
16459 * binary_upgrade_set_record_init_privs(true). That tells the backend to
16460 * copy the results into pg_init_privs. This is how we preserve the
16461 * contents of that catalog across binary upgrades.
16462 */
16463 if (dopt->binary_upgrade && privtype == 'e' &&
16464 initprivs && *initprivs != '\0')
16465 {
16466 appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
16467 if (!buildACLCommands(name, subname, nspname, type,
16468 initprivs, acldefault, owner,
16469 "", fout->remoteVersion, sql))
16470 pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
16471 initprivs, acldefault, name, type);
16472 appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
16473 }
16474
16475 /*
16476 * Now figure the GRANT and REVOKE commands needed to get to the object's
16477 * actual current ACL, starting from the initprivs if given, else from the
16478 * object-type-specific default. Also, while buildACLCommands will assume
16479 * that a NULL/empty acls string means it needn't do anything, what that
16480 * actually represents is the object-type-specific default; so we need to
16481 * substitute the acldefault string to get the right results in that case.
16482 */
16483 if (initprivs && *initprivs != '\0')
16484 {
16485 baseacls = initprivs;
16486 if (acls == NULL || *acls == '\0')
16487 acls = acldefault;
16488 }
16489 else
16491
16492 if (!buildACLCommands(name, subname, nspname, type,
16493 acls, baseacls, owner,
16494 "", fout->remoteVersion, sql))
16495 pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
16496 acls, baseacls, name, type);
16497
16498 if (sql->len > 0)
16499 {
16501 DumpId aclDeps[2];
16502 int nDeps = 0;
16503
16504 if (tag)
16506 else if (subname)
16507 appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
16508 else
16509 appendPQExpBuffer(tagbuf, "%s %s", type, name);
16510
16511 aclDeps[nDeps++] = objDumpId;
16512 if (altDumpId != InvalidDumpId)
16513 aclDeps[nDeps++] = altDumpId;
16514
16516
16518 ARCHIVE_OPTS(.tag = tagbuf->data,
16519 .namespace = nspname,
16520 .owner = owner,
16521 .description = "ACL",
16522 .section = SECTION_NONE,
16523 .createStmt = sql->data,
16524 .deps = aclDeps,
16525 .nDeps = nDeps));
16526
16528 }
16529
16530 destroyPQExpBuffer(sql);
16531
16532 return aclDumpId;
16533}

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 15388 of file pg_dump.c.

15389{
15390 DumpOptions *dopt = fout->dopt;
15391 PQExpBuffer query;
15392 PQExpBuffer q;
15394 PQExpBuffer details;
15395 char *aggsig; /* identity signature */
15396 char *aggfullsig = NULL; /* full signature */
15397 char *aggsig_tag;
15398 PGresult *res;
15399 int i_agginitval;
15400 int i_aggminitval;
15401 const char *aggtransfn;
15402 const char *aggfinalfn;
15403 const char *aggcombinefn;
15404 const char *aggserialfn;
15405 const char *aggdeserialfn;
15406 const char *aggmtransfn;
15407 const char *aggminvtransfn;
15408 const char *aggmfinalfn;
15409 bool aggfinalextra;
15410 bool aggmfinalextra;
15411 char aggfinalmodify;
15412 char aggmfinalmodify;
15413 const char *aggsortop;
15414 char *aggsortconvop;
15415 char aggkind;
15416 const char *aggtranstype;
15417 const char *aggtransspace;
15418 const char *aggmtranstype;
15419 const char *aggmtransspace;
15420 const char *agginitval;
15421 const char *aggminitval;
15422 const char *proparallel;
15423 char defaultfinalmodify;
15424
15425 /* Do nothing if not dumping schema */
15426 if (!dopt->dumpSchema)
15427 return;
15428
15429 query = createPQExpBuffer();
15430 q = createPQExpBuffer();
15432 details = createPQExpBuffer();
15433
15434 if (!fout->is_prepared[PREPQUERY_DUMPAGG])
15435 {
15436 /* Set up query for aggregate-specific details */
15438 "PREPARE dumpAgg(pg_catalog.oid) AS\n");
15439
15441 "SELECT "
15442 "aggtransfn,\n"
15443 "aggfinalfn,\n"
15444 "aggtranstype::pg_catalog.regtype,\n"
15445 "agginitval,\n"
15446 "aggsortop,\n"
15447 "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
15448 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
15449
15450 if (fout->remoteVersion >= 90400)
15452 "aggkind,\n"
15453 "aggmtransfn,\n"
15454 "aggminvtransfn,\n"
15455 "aggmfinalfn,\n"
15456 "aggmtranstype::pg_catalog.regtype,\n"
15457 "aggfinalextra,\n"
15458 "aggmfinalextra,\n"
15459 "aggtransspace,\n"
15460 "aggmtransspace,\n"
15461 "aggminitval,\n");
15462 else
15464 "'n' AS aggkind,\n"
15465 "'-' AS aggmtransfn,\n"
15466 "'-' AS aggminvtransfn,\n"
15467 "'-' AS aggmfinalfn,\n"
15468 "0 AS aggmtranstype,\n"
15469 "false AS aggfinalextra,\n"
15470 "false AS aggmfinalextra,\n"
15471 "0 AS aggtransspace,\n"
15472 "0 AS aggmtransspace,\n"
15473 "NULL AS aggminitval,\n");
15474
15475 if (fout->remoteVersion >= 90600)
15477 "aggcombinefn,\n"
15478 "aggserialfn,\n"
15479 "aggdeserialfn,\n"
15480 "proparallel,\n");
15481 else
15483 "'-' AS aggcombinefn,\n"
15484 "'-' AS aggserialfn,\n"
15485 "'-' AS aggdeserialfn,\n"
15486 "'u' AS proparallel,\n");
15487
15488 if (fout->remoteVersion >= 110000)
15490 "aggfinalmodify,\n"
15491 "aggmfinalmodify\n");
15492 else
15494 "'0' AS aggfinalmodify,\n"
15495 "'0' AS aggmfinalmodify\n");
15496
15498 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
15499 "WHERE a.aggfnoid = p.oid "
15500 "AND p.oid = $1");
15501
15502 ExecuteSqlStatement(fout, query->data);
15503
15504 fout->is_prepared[PREPQUERY_DUMPAGG] = true;
15505 }
15506
15507 printfPQExpBuffer(query,
15508 "EXECUTE dumpAgg('%u')",
15509 agginfo->aggfn.dobj.catId.oid);
15510
15511 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15512
15513 i_agginitval = PQfnumber(res, "agginitval");
15514 i_aggminitval = PQfnumber(res, "aggminitval");
15515
15516 aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
15517 aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
15518 aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
15519 aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
15520 aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
15521 aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
15522 aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
15523 aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
15524 aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
15525 aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
15526 aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
15527 aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
15528 aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
15529 aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
15530 aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
15531 aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
15532 aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
15533 aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
15536 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
15537
15538 {
15539 char *funcargs;
15540 char *funciargs;
15541
15542 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
15543 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
15546 }
15547
15549
15550 /* identify default modify flag for aggkind (must match DefineAggregate) */
15552 /* replace omitted flags for old versions */
15553 if (aggfinalmodify == '0')
15555 if (aggmfinalmodify == '0')
15557
15558 /* regproc and regtype output is already sufficiently quoted */
15559 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
15560 aggtransfn, aggtranstype);
15561
15562 if (strcmp(aggtransspace, "0") != 0)
15563 {
15564 appendPQExpBuffer(details, ",\n SSPACE = %s",
15565 aggtransspace);
15566 }
15567
15568 if (!PQgetisnull(res, 0, i_agginitval))
15569 {
15570 appendPQExpBufferStr(details, ",\n INITCOND = ");
15572 }
15573
15574 if (strcmp(aggfinalfn, "-") != 0)
15575 {
15576 appendPQExpBuffer(details, ",\n FINALFUNC = %s",
15577 aggfinalfn);
15578 if (aggfinalextra)
15579 appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
15581 {
15582 switch (aggfinalmodify)
15583 {
15585 appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_ONLY");
15586 break;
15588 appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = SHAREABLE");
15589 break;
15591 appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_WRITE");
15592 break;
15593 default:
15594 pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
15595 agginfo->aggfn.dobj.name);
15596 break;
15597 }
15598 }
15599 }
15600
15601 if (strcmp(aggcombinefn, "-") != 0)
15602 appendPQExpBuffer(details, ",\n COMBINEFUNC = %s", aggcombinefn);
15603
15604 if (strcmp(aggserialfn, "-") != 0)
15605 appendPQExpBuffer(details, ",\n SERIALFUNC = %s", aggserialfn);
15606
15607 if (strcmp(aggdeserialfn, "-") != 0)
15608 appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
15609
15610 if (strcmp(aggmtransfn, "-") != 0)
15611 {
15612 appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
15616 }
15617
15618 if (strcmp(aggmtransspace, "0") != 0)
15619 {
15620 appendPQExpBuffer(details, ",\n MSSPACE = %s",
15622 }
15623
15624 if (!PQgetisnull(res, 0, i_aggminitval))
15625 {
15626 appendPQExpBufferStr(details, ",\n MINITCOND = ");
15628 }
15629
15630 if (strcmp(aggmfinalfn, "-") != 0)
15631 {
15632 appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
15633 aggmfinalfn);
15634 if (aggmfinalextra)
15635 appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
15637 {
15638 switch (aggmfinalmodify)
15639 {
15641 appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_ONLY");
15642 break;
15644 appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = SHAREABLE");
15645 break;
15647 appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_WRITE");
15648 break;
15649 default:
15650 pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
15651 agginfo->aggfn.dobj.name);
15652 break;
15653 }
15654 }
15655 }
15656
15658 if (aggsortconvop)
15659 {
15660 appendPQExpBuffer(details, ",\n SORTOP = %s",
15663 }
15664
15666 appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
15667
15669 {
15670 if (proparallel[0] == PROPARALLEL_SAFE)
15671 appendPQExpBufferStr(details, ",\n PARALLEL = safe");
15672 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
15673 appendPQExpBufferStr(details, ",\n PARALLEL = restricted");
15674 else if (proparallel[0] != PROPARALLEL_UNSAFE)
15675 pg_fatal("unrecognized proparallel value for function \"%s\"",
15676 agginfo->aggfn.dobj.name);
15677 }
15678
15679 appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
15680 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
15681 aggsig);
15682
15683 appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
15684 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
15685 aggfullsig ? aggfullsig : aggsig, details->data);
15686
15687 if (dopt->binary_upgrade)
15689 "AGGREGATE", aggsig,
15690 agginfo->aggfn.dobj.namespace->dobj.name);
15691
15692 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
15693 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
15694 agginfo->aggfn.dobj.dumpId,
15695 ARCHIVE_OPTS(.tag = aggsig_tag,
15696 .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
15697 .owner = agginfo->aggfn.rolname,
15698 .description = "AGGREGATE",
15699 .section = SECTION_PRE_DATA,
15700 .createStmt = q->data,
15701 .dropStmt = delq->data));
15702
15703 /* Dump Aggregate Comments */
15704 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
15705 dumpComment(fout, "AGGREGATE", aggsig,
15706 agginfo->aggfn.dobj.namespace->dobj.name,
15707 agginfo->aggfn.rolname,
15708 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
15709
15710 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
15711 dumpSecLabel(fout, "AGGREGATE", aggsig,
15712 agginfo->aggfn.dobj.namespace->dobj.name,
15713 agginfo->aggfn.rolname,
15714 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
15715
15716 /*
15717 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
15718 * command look like a function's GRANT; in particular this affects the
15719 * syntax for zero-argument aggregates and ordered-set aggregates.
15720 */
15721 free(aggsig);
15722
15723 aggsig = format_function_signature(fout, &agginfo->aggfn, true);
15724
15725 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
15726 dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
15727 "FUNCTION", aggsig, NULL,
15728 agginfo->aggfn.dobj.namespace->dobj.name,
15729 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
15730
15731 free(aggsig);
15734
15735 PQclear(res);
15736
15737 destroyPQExpBuffer(query);
15740 destroyPQExpBuffer(details);
15741}

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 18193 of file pg_dump.c.

18194{
18195 DumpOptions *dopt = fout->dopt;
18196 TableInfo *tbinfo = adinfo->adtable;
18197 int adnum = adinfo->adnum;
18198 PQExpBuffer q;
18200 char *qualrelname;
18201 char *tag;
18202 char *foreign;
18203
18204 /* Do nothing if not dumping schema */
18205 if (!dopt->dumpSchema)
18206 return;
18207
18208 /* Skip if not "separate"; it was dumped in the table's definition */
18209 if (!adinfo->separate)
18210 return;
18211
18212 q = createPQExpBuffer();
18214
18216
18217 foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
18218
18220 "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
18221 foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
18222 adinfo->adef_expr);
18223
18224 appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
18226 fmtId(tbinfo->attnames[adnum - 1]));
18227
18228 tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
18229
18230 if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18231 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
18232 ARCHIVE_OPTS(.tag = tag,
18233 .namespace = tbinfo->dobj.namespace->dobj.name,
18234 .owner = tbinfo->rolname,
18235 .description = "DEFAULT",
18236 .section = SECTION_PRE_DATA,
18237 .createStmt = q->data,
18238 .dropStmt = delq->data));
18239
18240 free(tag);
18244}

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

Referenced by dumpDumpableObject().

◆ dumpBaseType()

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

Definition at line 12468 of file pg_dump.c.

12469{
12470 DumpOptions *dopt = fout->dopt;
12474 PGresult *res;
12475 char *qtypname;
12476 char *qualtypname;
12477 char *typlen;
12478 char *typinput;
12479 char *typoutput;
12480 char *typreceive;
12481 char *typsend;
12482 char *typmodin;
12483 char *typmodout;
12484 char *typanalyze;
12485 char *typsubscript;
12492 char *typcategory;
12493 char *typispreferred;
12494 char *typdelim;
12495 char *typbyval;
12496 char *typalign;
12497 char *typstorage;
12498 char *typcollatable;
12499 char *typdefault;
12500 bool typdefault_is_literal = false;
12501
12502 if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
12503 {
12504 /* Set up query for type-specific details */
12506 "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
12507 "SELECT typlen, "
12508 "typinput, typoutput, typreceive, typsend, "
12509 "typreceive::pg_catalog.oid AS typreceiveoid, "
12510 "typsend::pg_catalog.oid AS typsendoid, "
12511 "typanalyze, "
12512 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
12513 "typdelim, typbyval, typalign, typstorage, "
12514 "typmodin, typmodout, "
12515 "typmodin::pg_catalog.oid AS typmodinoid, "
12516 "typmodout::pg_catalog.oid AS typmodoutoid, "
12517 "typcategory, typispreferred, "
12518 "(typcollation <> 0) AS typcollatable, "
12519 "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
12520
12521 if (fout->remoteVersion >= 140000)
12523 "typsubscript, "
12524 "typsubscript::pg_catalog.oid AS typsubscriptoid ");
12525 else
12527 "'-' AS typsubscript, 0 AS typsubscriptoid ");
12528
12529 appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
12530 "WHERE oid = $1");
12531
12532 ExecuteSqlStatement(fout, query->data);
12533
12534 fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
12535 }
12536
12537 printfPQExpBuffer(query,
12538 "EXECUTE dumpBaseType('%u')",
12539 tyinfo->dobj.catId.oid);
12540
12541 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12542
12543 typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
12544 typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
12545 typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
12546 typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
12547 typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
12548 typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
12549 typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
12550 typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
12551 typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
12552 typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
12553 typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
12554 typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
12555 typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
12556 typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
12557 typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
12558 typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
12559 typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
12560 typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
12561 typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
12562 typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
12563 typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
12564 typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
12565 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
12566 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
12567 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
12568 {
12569 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
12570 typdefault_is_literal = true; /* it needs quotes */
12571 }
12572 else
12573 typdefault = NULL;
12574
12575 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12577
12578 /*
12579 * The reason we include CASCADE is that the circular dependency between
12580 * the type and its I/O functions makes it impossible to drop the type any
12581 * other way.
12582 */
12583 appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
12584
12585 /*
12586 * We might already have a shell type, but setting pg_type_oid is
12587 * harmless, and in any case we'd better set the array type OID.
12588 */
12589 if (dopt->binary_upgrade)
12591 tyinfo->dobj.catId.oid,
12592 false, false);
12593
12595 "CREATE TYPE %s (\n"
12596 " INTERNALLENGTH = %s",
12598 (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
12599
12600 /* regproc result is sufficiently quoted already */
12601 appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
12602 appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
12604 appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
12606 appendPQExpBuffer(q, ",\n SEND = %s", typsend);
12608 appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
12610 appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
12612 appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
12613
12614 if (strcmp(typcollatable, "t") == 0)
12615 appendPQExpBufferStr(q, ",\n COLLATABLE = true");
12616
12617 if (typdefault != NULL)
12618 {
12619 appendPQExpBufferStr(q, ",\n DEFAULT = ");
12622 else
12624 }
12625
12627 appendPQExpBuffer(q, ",\n SUBSCRIPT = %s", typsubscript);
12628
12629 if (OidIsValid(tyinfo->typelem))
12630 appendPQExpBuffer(q, ",\n ELEMENT = %s",
12632 zeroIsError));
12633
12634 if (strcmp(typcategory, "U") != 0)
12635 {
12636 appendPQExpBufferStr(q, ",\n CATEGORY = ");
12638 }
12639
12640 if (strcmp(typispreferred, "t") == 0)
12641 appendPQExpBufferStr(q, ",\n PREFERRED = true");
12642
12643 if (typdelim && strcmp(typdelim, ",") != 0)
12644 {
12645 appendPQExpBufferStr(q, ",\n DELIMITER = ");
12646 appendStringLiteralAH(q, typdelim, fout);
12647 }
12648
12649 if (*typalign == TYPALIGN_CHAR)
12650 appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
12651 else if (*typalign == TYPALIGN_SHORT)
12652 appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
12653 else if (*typalign == TYPALIGN_INT)
12654 appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
12655 else if (*typalign == TYPALIGN_DOUBLE)
12656 appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
12657
12658 if (*typstorage == TYPSTORAGE_PLAIN)
12659 appendPQExpBufferStr(q, ",\n STORAGE = plain");
12660 else if (*typstorage == TYPSTORAGE_EXTERNAL)
12661 appendPQExpBufferStr(q, ",\n STORAGE = external");
12662 else if (*typstorage == TYPSTORAGE_EXTENDED)
12663 appendPQExpBufferStr(q, ",\n STORAGE = extended");
12664 else if (*typstorage == TYPSTORAGE_MAIN)
12665 appendPQExpBufferStr(q, ",\n STORAGE = main");
12666
12667 if (strcmp(typbyval, "t") == 0)
12668 appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
12669
12670 appendPQExpBufferStr(q, "\n);\n");
12671
12672 if (dopt->binary_upgrade)
12674 "TYPE", qtypname,
12675 tyinfo->dobj.namespace->dobj.name);
12676
12677 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12678 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12679 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12680 .namespace = tyinfo->dobj.namespace->dobj.name,
12681 .owner = tyinfo->rolname,
12682 .description = "TYPE",
12683 .section = SECTION_PRE_DATA,
12684 .createStmt = q->data,
12685 .dropStmt = delq->data));
12686
12687 /* Dump Type Comments and Security Labels */
12688 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12689 dumpComment(fout, "TYPE", qtypname,
12690 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12691 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12692
12693 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12694 dumpSecLabel(fout, "TYPE", qtypname,
12695 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12696 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12697
12698 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12699 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12700 qtypname, NULL,
12701 tyinfo->dobj.namespace->dobj.name,
12702 NULL, tyinfo->rolname, &tyinfo->dacl);
12703
12704 PQclear(res);
12707 destroyPQExpBuffer(query);
12708 free(qtypname);
12710}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), atooid, _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), binary_upgrade_set_type_oids_by_type_oid(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_ACL, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpACL(), dumpComment(), dumpSecLabel(), ExecuteSqlQueryForSingleRow(), ExecuteSqlStatement(), fb(), fmtId(), fmtQualifiedDumpable, free, getFormattedTypeName(), InvalidDumpId, OidIsValid, pg_strdup(), PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PREPQUERY_DUMPBASETYPE, printfPQExpBuffer(), SECTION_PRE_DATA, typalign, and zeroIsError.

Referenced by dumpType().

◆ dumpCast()

static void dumpCast ( Archive fout,
const CastInfo cast 
)
static

Definition at line 13889 of file pg_dump.c.

13890{
13891 DumpOptions *dopt = fout->dopt;
13897 const char *sourceType;
13898 const char *targetType;
13899
13900 /* Do nothing if not dumping schema */
13901 if (!dopt->dumpSchema)
13902 return;
13903
13904 /* Cannot dump if we don't have the cast function's info */
13905 if (OidIsValid(cast->castfunc))
13906 {
13907 funcInfo = findFuncByOid(cast->castfunc);
13908 if (funcInfo == NULL)
13909 pg_fatal("could not find function definition for function with OID %u",
13910 cast->castfunc);
13911 }
13912
13917
13920 appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
13922
13923 appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
13925
13926 switch (cast->castmethod)
13927 {
13929 appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
13930 break;
13932 appendPQExpBufferStr(defqry, "WITH INOUT");
13933 break;
13935 if (funcInfo)
13936 {
13938
13939 /*
13940 * Always qualify the function name (format_function_signature
13941 * won't qualify it).
13942 */
13943 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
13944 fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
13945 free(fsig);
13946 }
13947 else
13948 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
13949 break;
13950 default:
13951 pg_log_warning("bogus value in pg_cast.castmethod field");
13952 }
13953
13954 if (cast->castcontext == 'a')
13955 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
13956 else if (cast->castcontext == 'i')
13957 appendPQExpBufferStr(defqry, " AS IMPLICIT");
13959
13960 appendPQExpBuffer(labelq, "CAST (%s AS %s)",
13962
13963 appendPQExpBuffer(castargs, "(%s AS %s)",
13965
13966 if (dopt->binary_upgrade)
13968 "CAST", castargs->data, NULL);
13969
13970 if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
13971 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
13972 ARCHIVE_OPTS(.tag = labelq->data,
13973 .description = "CAST",
13974 .section = SECTION_PRE_DATA,
13975 .createStmt = defqry->data,
13976 .dropStmt = delqry->data));
13977
13978 /* Dump Cast Comments */
13979 if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
13980 dumpComment(fout, "CAST", castargs->data,
13981 NULL, "",
13982 cast->dobj.catId, 0, cast->dobj.dumpId);
13983
13988}

References appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), createPQExpBuffer(), destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, fb(), findFuncByOid(), fmtId(), format_function_signature(), free, getFormattedTypeName(), OidIsValid, pg_fatal, pg_log_warning, SECTION_PRE_DATA, and zeroAsNone.

Referenced by dumpDumpableObject().

◆ dumpCollation()

static void dumpCollation ( Archive fout,
const CollInfo collinfo 
)
static

Definition at line 15003 of file pg_dump.c.

15004{
15005 DumpOptions *dopt = fout->dopt;
15006 PQExpBuffer query;
15007 PQExpBuffer q;
15009 char *qcollname;
15010 PGresult *res;
15011 int i_collprovider;
15013 int i_collcollate;
15014 int i_collctype;
15015 int i_colllocale;
15016 int i_collicurules;
15017 const char *collprovider;
15018 const char *collcollate;
15019 const char *collctype;
15020 const char *colllocale;
15021 const char *collicurules;
15022
15023 /* Do nothing if not dumping schema */
15024 if (!dopt->dumpSchema)
15025 return;
15026
15027 query = createPQExpBuffer();
15028 q = createPQExpBuffer();
15030
15031 qcollname = pg_strdup(fmtId(collinfo->dobj.name));
15032
15033 /* Get collation-specific details */
15034 appendPQExpBufferStr(query, "SELECT ");
15035
15036 if (fout->remoteVersion >= 100000)
15038 "collprovider, "
15039 "collversion, ");
15040 else
15042 "'c' AS collprovider, "
15043 "NULL AS collversion, ");
15044
15045 if (fout->remoteVersion >= 120000)
15047 "collisdeterministic, ");
15048 else
15050 "true AS collisdeterministic, ");
15051
15052 if (fout->remoteVersion >= 170000)
15054 "colllocale, ");
15055 else if (fout->remoteVersion >= 150000)
15057 "colliculocale AS colllocale, ");
15058 else
15060 "NULL AS colllocale, ");
15061
15062 if (fout->remoteVersion >= 160000)
15064 "collicurules, ");
15065 else
15067 "NULL AS collicurules, ");
15068
15069 appendPQExpBuffer(query,
15070 "collcollate, "
15071 "collctype "
15072 "FROM pg_catalog.pg_collation c "
15073 "WHERE c.oid = '%u'::pg_catalog.oid",
15074 collinfo->dobj.catId.oid);
15075
15076 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15077
15078 i_collprovider = PQfnumber(res, "collprovider");
15079 i_collisdeterministic = PQfnumber(res, "collisdeterministic");
15080 i_collcollate = PQfnumber(res, "collcollate");
15081 i_collctype = PQfnumber(res, "collctype");
15082 i_colllocale = PQfnumber(res, "colllocale");
15083 i_collicurules = PQfnumber(res, "collicurules");
15084
15086
15087 if (!PQgetisnull(res, 0, i_collcollate))
15089 else
15090 collcollate = NULL;
15091
15092 if (!PQgetisnull(res, 0, i_collctype))
15093 collctype = PQgetvalue(res, 0, i_collctype);
15094 else
15095 collctype = NULL;
15096
15097 /*
15098 * Before version 15, collcollate and collctype were of type NAME and
15099 * non-nullable. Treat empty strings as NULL for consistency.
15100 */
15101 if (fout->remoteVersion < 150000)
15102 {
15103 if (collcollate[0] == '\0')
15104 collcollate = NULL;
15105 if (collctype[0] == '\0')
15106 collctype = NULL;
15107 }
15108
15109 if (!PQgetisnull(res, 0, i_colllocale))
15111 else
15112 colllocale = NULL;
15113
15114 if (!PQgetisnull(res, 0, i_collicurules))
15116 else
15118
15119 appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
15121
15122 appendPQExpBuffer(q, "CREATE COLLATION %s (",
15124
15125 appendPQExpBufferStr(q, "provider = ");
15126 if (collprovider[0] == 'b')
15127 appendPQExpBufferStr(q, "builtin");
15128 else if (collprovider[0] == 'c')
15129 appendPQExpBufferStr(q, "libc");
15130 else if (collprovider[0] == 'i')
15131 appendPQExpBufferStr(q, "icu");
15132 else if (collprovider[0] == 'd')
15133 /* to allow dumping pg_catalog; not accepted on input */
15134 appendPQExpBufferStr(q, "default");
15135 else
15136 pg_fatal("unrecognized collation provider: %s",
15137 collprovider);
15138
15139 if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
15140 appendPQExpBufferStr(q, ", deterministic = false");
15141
15142 if (collprovider[0] == 'd')
15143 {
15145 pg_log_warning("invalid collation \"%s\"", qcollname);
15146
15147 /* no locale -- the default collation cannot be reloaded anyway */
15148 }
15149 else if (collprovider[0] == 'b')
15150 {
15152 pg_log_warning("invalid collation \"%s\"", qcollname);
15153
15154 appendPQExpBufferStr(q, ", locale = ");
15156 fout);
15157 }
15158 else if (collprovider[0] == 'i')
15159 {
15160 if (fout->remoteVersion >= 150000)
15161 {
15162 if (collcollate || collctype || !colllocale)
15163 pg_log_warning("invalid collation \"%s\"", qcollname);
15164
15165 appendPQExpBufferStr(q, ", locale = ");
15167 fout);
15168 }
15169 else
15170 {
15171 if (!collcollate || !collctype || colllocale ||
15173 pg_log_warning("invalid collation \"%s\"", qcollname);
15174
15175 appendPQExpBufferStr(q, ", locale = ");
15177 }
15178
15179 if (collicurules)
15180 {
15181 appendPQExpBufferStr(q, ", rules = ");
15183 }
15184 }
15185 else if (collprovider[0] == 'c')
15186 {
15188 pg_log_warning("invalid collation \"%s\"", qcollname);
15189
15191 {
15192 appendPQExpBufferStr(q, ", locale = ");
15194 }
15195 else
15196 {
15197 appendPQExpBufferStr(q, ", lc_collate = ");
15199 appendPQExpBufferStr(q, ", lc_ctype = ");
15201 }
15202 }
15203 else
15204 pg_fatal("unrecognized collation provider: %s", collprovider);
15205
15206 /*
15207 * For binary upgrade, carry over the collation version. For normal
15208 * dump/restore, omit the version, so that it is computed upon restore.
15209 */
15210 if (dopt->binary_upgrade)
15211 {
15212 int i_collversion;
15213
15214 i_collversion = PQfnumber(res, "collversion");
15215 if (!PQgetisnull(res, 0, i_collversion))
15216 {
15217 appendPQExpBufferStr(q, ", version = ");
15219 PQgetvalue(res, 0, i_collversion),
15220 fout);
15221 }
15222 }
15223
15224 appendPQExpBufferStr(q, ");\n");
15225
15226 if (dopt->binary_upgrade)
15228 "COLLATION", qcollname,
15229 collinfo->dobj.namespace->dobj.name);
15230
15231 if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15232 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
15233 ARCHIVE_OPTS(.tag = collinfo->dobj.name,
15234 .namespace = collinfo->dobj.namespace->dobj.name,
15235 .owner = collinfo->rolname,
15236 .description = "COLLATION",
15237 .section = SECTION_PRE_DATA,
15238 .createStmt = q->data,
15239 .dropStmt = delq->data));
15240
15241 /* Dump Collation Comments */
15242 if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15243 dumpComment(fout, "COLLATION", qcollname,
15244 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
15245 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
15246
15247 PQclear(res);
15248
15249 destroyPQExpBuffer(query);
15252 free(qcollname);
15253}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, ExecuteSqlQueryForSingleRow(), fb(), fmtId(), fmtQualifiedDumpable, free, pg_fatal, pg_log_warning, pg_strdup(), PQclear, PQfnumber(), PQgetisnull, PQgetvalue, and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpComment()

◆ dumpCommentExtended()

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

Definition at line 10897 of file pg_dump.c.

10902{
10903 DumpOptions *dopt = fout->dopt;
10905 int ncomments;
10906
10907 /* do nothing, if --no-comments is supplied */
10908 if (dopt->no_comments)
10909 return;
10910
10911 /* Comments are schema not data ... except LO comments are data */
10912 if (strcmp(type, "LARGE OBJECT") != 0)
10913 {
10914 if (!dopt->dumpSchema)
10915 return;
10916 }
10917 else
10918 {
10919 /* We do dump LO comments in binary-upgrade mode */
10920 if (!dopt->dumpData && !dopt->binary_upgrade)
10921 return;
10922 }
10923
10924 /* Search for comments associated with catalogId, using table */
10925 ncomments = findComments(catalogId.tableoid, catalogId.oid,
10926 &comments);
10927
10928 /* Is there one matching the subid? */
10929 while (ncomments > 0)
10930 {
10931 if (comments->objsubid == subid)
10932 break;
10933 comments++;
10934 ncomments--;
10935 }
10936
10937 if (initdb_comment != NULL)
10938 {
10939 static CommentItem empty_comment = {.descr = ""};
10940
10941 /*
10942 * initdb creates this object with a comment. Skip dumping the
10943 * initdb-provided comment, which would complicate matters for
10944 * non-superuser use of pg_dump. When the DBA has removed initdb's
10945 * comment, replicate that.
10946 */
10947 if (ncomments == 0)
10948 {
10950 ncomments = 1;
10951 }
10952 else if (strcmp(comments->descr, initdb_comment) == 0)
10953 ncomments = 0;
10954 }
10955
10956 /* If a comment exists, build COMMENT ON statement */
10957 if (ncomments > 0)
10958 {
10961
10962 appendPQExpBuffer(query, "COMMENT ON %s ", type);
10963 if (namespace && *namespace)
10964 appendPQExpBuffer(query, "%s.", fmtId(namespace));
10965 appendPQExpBuffer(query, "%s IS ", name);
10967 appendPQExpBufferStr(query, ";\n");
10968
10969 appendPQExpBuffer(tag, "%s %s", type, name);
10970
10971 /*
10972 * We mark comments as SECTION_NONE because they really belong in the
10973 * same section as their parent, whether that is pre-data or
10974 * post-data.
10975 */
10977 ARCHIVE_OPTS(.tag = tag->data,
10978 .namespace = namespace,
10979 .owner = owner,
10980 .description = "COMMENT",
10981 .section = SECTION_NONE,
10982 .createStmt = query->data,
10983 .deps = &dumpId,
10984 .nDeps = 1));
10985
10986 destroyPQExpBuffer(query);
10987 destroyPQExpBuffer(tag);
10988 }
10989}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, comments, createDumpId(), createPQExpBuffer(), PQExpBufferData::data, CommentItem::descr, destroyPQExpBuffer(), _dumpOptions::dumpData, _dumpOptions::dumpSchema, fb(), findComments(), fmtId(), name, ncomments, nilCatalogId, _dumpOptions::no_comments, CommentItem::objsubid, CatalogId::oid, SECTION_NONE, CatalogId::tableoid, and type.

Referenced by dumpComment(), and dumpNamespace().

◆ dumpCompositeType()

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

Definition at line 12942 of file pg_dump.c.

12943{
12944 DumpOptions *dopt = fout->dopt;
12946 PQExpBuffer dropped = createPQExpBuffer();
12949 PGresult *res;
12950 char *qtypname;
12951 char *qualtypname;
12952 int ntups;
12953 int i_attname;
12954 int i_atttypdefn;
12955 int i_attlen;
12956 int i_attalign;
12957 int i_attisdropped;
12958 int i_attcollation;
12959 int i;
12960 int actual_atts;
12961
12962 if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
12963 {
12964 /*
12965 * Set up query for type-specific details.
12966 *
12967 * Since we only want to dump COLLATE clauses for attributes whose
12968 * collation is different from their type's default, we use a CASE
12969 * here to suppress uninteresting attcollations cheaply. atttypid
12970 * will be 0 for dropped columns; collation does not matter for those.
12971 */
12973 "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
12974 "SELECT a.attname, a.attnum, "
12975 "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
12976 "a.attlen, a.attalign, a.attisdropped, "
12977 "CASE WHEN a.attcollation <> at.typcollation "
12978 "THEN a.attcollation ELSE 0 END AS attcollation "
12979 "FROM pg_catalog.pg_type ct "
12980 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
12981 "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
12982 "WHERE ct.oid = $1 "
12983 "ORDER BY a.attnum");
12984
12985 ExecuteSqlStatement(fout, query->data);
12986
12987 fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
12988 }
12989
12990 printfPQExpBuffer(query,
12991 "EXECUTE dumpCompositeType('%u')",
12992 tyinfo->dobj.catId.oid);
12993
12994 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12995
12996 ntups = PQntuples(res);
12997
12998 i_attname = PQfnumber(res, "attname");
12999 i_atttypdefn = PQfnumber(res, "atttypdefn");
13000 i_attlen = PQfnumber(res, "attlen");
13001 i_attalign = PQfnumber(res, "attalign");
13002 i_attisdropped = PQfnumber(res, "attisdropped");
13003 i_attcollation = PQfnumber(res, "attcollation");
13004
13005 if (dopt->binary_upgrade)
13006 {
13008 tyinfo->dobj.catId.oid,
13009 false, false);
13011 }
13012
13013 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
13015
13016 appendPQExpBuffer(q, "CREATE TYPE %s AS (",
13017 qualtypname);
13018
13019 actual_atts = 0;
13020 for (i = 0; i < ntups; i++)
13021 {
13022 char *attname;
13023 char *atttypdefn;
13024 char *attlen;
13025 char *attalign;
13026 bool attisdropped;
13027 Oid attcollation;
13028
13029 attname = PQgetvalue(res, i, i_attname);
13031 attlen = PQgetvalue(res, i, i_attlen);
13033 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
13034 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
13035
13036 if (attisdropped && !dopt->binary_upgrade)
13037 continue;
13038
13039 /* Format properly if not first attr */
13040 if (actual_atts++ > 0)
13041 appendPQExpBufferChar(q, ',');
13042 appendPQExpBufferStr(q, "\n\t");
13043
13044 if (!attisdropped)
13045 {
13047
13048 /* Add collation if not default for the column type */
13049 if (OidIsValid(attcollation))
13050 {
13051 CollInfo *coll;
13052
13053 coll = findCollationByOid(attcollation);
13054 if (coll)
13055 appendPQExpBuffer(q, " COLLATE %s",
13057 }
13058 }
13059 else
13060 {
13061 /*
13062 * This is a dropped attribute and we're in binary_upgrade mode.
13063 * Insert a placeholder for it in the CREATE TYPE command, and set
13064 * length and alignment with direct UPDATE to the catalogs
13065 * afterwards. See similar code in dumpTableSchema().
13066 */
13067 appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
13068
13069 /* stash separately for insertion after the CREATE TYPE */
13070 appendPQExpBufferStr(dropped,
13071 "\n-- For binary upgrade, recreate dropped column.\n");
13072 appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
13073 "SET attlen = %s, "
13074 "attalign = '%s', attbyval = false\n"
13075 "WHERE attname = ", attlen, attalign);
13077 appendPQExpBufferStr(dropped, "\n AND attrelid = ");
13079 appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
13080
13081 appendPQExpBuffer(dropped, "ALTER TYPE %s ",
13082 qualtypname);
13083 appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
13084 fmtId(attname));
13085 }
13086 }
13087 appendPQExpBufferStr(q, "\n);\n");
13088 appendPQExpBufferStr(q, dropped->data);
13089
13090 appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
13091
13092 if (dopt->binary_upgrade)
13094 "TYPE", qtypname,
13095 tyinfo->dobj.namespace->dobj.name);
13096
13097 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13098 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
13099 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
13100 .namespace = tyinfo->dobj.namespace->dobj.name,
13101 .owner = tyinfo->rolname,
13102 .description = "TYPE",
13103 .section = SECTION_PRE_DATA,
13104 .createStmt = q->data,
13105 .dropStmt = delq->data));
13106
13107
13108 /* Dump Type Comments and Security Labels */
13109 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13110 dumpComment(fout, "TYPE", qtypname,
13111 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
13112 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
13113
13114 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
13115 dumpSecLabel(fout, "TYPE", qtypname,
13116 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
13117 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
13118
13119 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
13120 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
13121 qtypname, NULL,
13122 tyinfo->dobj.namespace->dobj.name,
13123 NULL, tyinfo->rolname, &tyinfo->dacl);
13124
13125 /* Dump any per-column comments */
13126 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13128
13129 PQclear(res);
13131 destroyPQExpBuffer(dropped);
13133 destroyPQExpBuffer(query);
13134 free(qtypname);
13136}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), atooid, attalign, attlen, attname, _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), binary_upgrade_set_pg_class_oids(), binary_upgrade_set_type_oids_by_type_oid(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_ACL, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpACL(), dumpComment(), dumpCompositeTypeColComments(), dumpSecLabel(), ExecuteSqlQuery(), ExecuteSqlStatement(), fb(), findCollationByOid(), fmtId(), fmtQualifiedDumpable, free, i, InvalidDumpId, OidIsValid, pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, PREPQUERY_DUMPCOMPOSITETYPE, printfPQExpBuffer(), and SECTION_PRE_DATA.

Referenced by dumpType().

◆ dumpCompositeTypeColComments()

static void dumpCompositeTypeColComments ( Archive fout,
const TypeInfo tyinfo,
PGresult res 
)
static

Definition at line 13148 of file pg_dump.c.

13150{
13152 int ncomments;
13153 PQExpBuffer query;
13154 PQExpBuffer target;
13155 int i;
13156 int ntups;
13157 int i_attname;
13158 int i_attnum;
13159 int i_attisdropped;
13160
13161 /* do nothing, if --no-comments is supplied */
13162 if (fout->dopt->no_comments)
13163 return;
13164
13165 /* Search for comments associated with type's pg_class OID */
13167 &comments);
13168
13169 /* If no comments exist, we're done */
13170 if (ncomments <= 0)
13171 return;
13172
13173 /* Build COMMENT ON statements */
13174 query = createPQExpBuffer();
13175 target = createPQExpBuffer();
13176
13177 ntups = PQntuples(res);
13178 i_attnum = PQfnumber(res, "attnum");
13179 i_attname = PQfnumber(res, "attname");
13180 i_attisdropped = PQfnumber(res, "attisdropped");
13181 while (ncomments > 0)
13182 {
13183 const char *attname;
13184
13185 attname = NULL;
13186 for (i = 0; i < ntups; i++)
13187 {
13188 if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
13189 PQgetvalue(res, i, i_attisdropped)[0] != 't')
13190 {
13191 attname = PQgetvalue(res, i, i_attname);
13192 break;
13193 }
13194 }
13195 if (attname) /* just in case we don't find it */
13196 {
13197 const char *descr = comments->descr;
13198
13199 resetPQExpBuffer(target);
13200 appendPQExpBuffer(target, "COLUMN %s.",
13201 fmtId(tyinfo->dobj.name));
13203
13204 resetPQExpBuffer(query);
13205 appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
13207 appendPQExpBuffer(query, "%s IS ", fmtId(attname));
13208 appendStringLiteralAH(query, descr, fout);
13209 appendPQExpBufferStr(query, ";\n");
13210
13212 ARCHIVE_OPTS(.tag = target->data,
13213 .namespace = tyinfo->dobj.namespace->dobj.name,
13214 .owner = tyinfo->rolname,
13215 .description = "COMMENT",
13216 .section = SECTION_NONE,
13217 .createStmt = query->data,
13218 .deps = &(tyinfo->dobj.dumpId),
13219 .nDeps = 1));
13220 }
13221
13222 comments++;
13223 ncomments--;
13224 }
13225
13226 destroyPQExpBuffer(query);
13227 destroyPQExpBuffer(target);
13228}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), attname, comments, createDumpId(), createPQExpBuffer(), PQExpBufferData::data, CommentItem::descr, destroyPQExpBuffer(), fb(), findComments(), fmtId(), fmtQualifiedDumpable, i, ncomments, nilCatalogId, CommentItem::objsubid, PQfnumber(), PQgetvalue, PQntuples, resetPQExpBuffer(), and SECTION_NONE.

Referenced by dumpCompositeType().

◆ dumpConstraint()

static void dumpConstraint ( Archive fout,
const ConstraintInfo coninfo 
)
static

Definition at line 18757 of file pg_dump.c.

18758{
18759 DumpOptions *dopt = fout->dopt;
18760 TableInfo *tbinfo = coninfo->contable;
18761 PQExpBuffer q;
18763 char *tag = NULL;
18764 char *foreign;
18765
18766 /* Do nothing if not dumping schema */
18767 if (!dopt->dumpSchema)
18768 return;
18769
18770 q = createPQExpBuffer();
18772
18773 foreign = tbinfo &&
18774 tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
18775
18776 if (coninfo->contype == 'p' ||
18777 coninfo->contype == 'u' ||
18778 coninfo->contype == 'x')
18779 {
18780 /* Index-related constraint */
18782 int k;
18783
18785
18786 if (indxinfo == NULL)
18787 pg_fatal("missing index for constraint \"%s\"",
18788 coninfo->dobj.name);
18789
18790 if (dopt->binary_upgrade)
18792 indxinfo->dobj.catId.oid);
18793
18794 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
18796 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
18797 fmtId(coninfo->dobj.name));
18798
18799 if (coninfo->condef)
18800 {
18801 /* pg_get_constraintdef should have provided everything */
18802 appendPQExpBuffer(q, "%s;\n", coninfo->condef);
18803 }
18804 else
18805 {
18807 coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
18808
18809 /*
18810 * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
18811 * indexes. Being able to create this was fixed, but we need to
18812 * make the index distinct in order to be able to restore the
18813 * dump.
18814 */
18815 if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
18816 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
18817 appendPQExpBufferStr(q, " (");
18818 for (k = 0; k < indxinfo->indnkeyattrs; k++)
18819 {
18820 int indkey = (int) indxinfo->indkeys[k];
18821 const char *attname;
18822
18824 break;
18826
18827 appendPQExpBuffer(q, "%s%s",
18828 (k == 0) ? "" : ", ",
18829 fmtId(attname));
18830 }
18831 if (coninfo->conperiod)
18832 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
18833
18834 if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
18835 appendPQExpBufferStr(q, ") INCLUDE (");
18836
18837 for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
18838 {
18839 int indkey = (int) indxinfo->indkeys[k];
18840 const char *attname;
18841
18843 break;
18845
18846 appendPQExpBuffer(q, "%s%s",
18847 (k == indxinfo->indnkeyattrs) ? "" : ", ",
18848 fmtId(attname));
18849 }
18850
18851 appendPQExpBufferChar(q, ')');
18852
18853 if (nonemptyReloptions(indxinfo->indreloptions))
18854 {
18855 appendPQExpBufferStr(q, " WITH (");
18856 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
18857 appendPQExpBufferChar(q, ')');
18858 }
18859
18860 if (coninfo->condeferrable)
18861 {
18862 appendPQExpBufferStr(q, " DEFERRABLE");
18863 if (coninfo->condeferred)
18864 appendPQExpBufferStr(q, " INITIALLY DEFERRED");
18865 }
18866
18867 appendPQExpBufferStr(q, ";\n");
18868 }
18869
18870 /*
18871 * Append ALTER TABLE commands as needed to set properties that we
18872 * only have ALTER TABLE syntax for. Keep this in sync with the
18873 * similar code in dumpIndex!
18874 */
18875
18876 /* If the index is clustered, we need to record that. */
18877 if (indxinfo->indisclustered)
18878 {
18879 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
18881 /* index name is not qualified in this syntax */
18882 appendPQExpBuffer(q, " ON %s;\n",
18883 fmtId(indxinfo->dobj.name));
18884 }
18885
18886 /* If the index defines identity, we need to record that. */
18887 if (indxinfo->indisreplident)
18888 {
18889 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
18891 /* index name is not qualified in this syntax */
18892 appendPQExpBuffer(q, " INDEX %s;\n",
18893 fmtId(indxinfo->dobj.name));
18894 }
18895
18896 /* Indexes can depend on extensions */
18898 "pg_catalog.pg_class", "INDEX",
18900
18901 appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
18903 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
18904 fmtId(coninfo->dobj.name));
18905
18906 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18907
18908 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18909 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
18910 ARCHIVE_OPTS(.tag = tag,
18911 .namespace = tbinfo->dobj.namespace->dobj.name,
18912 .tablespace = indxinfo->tablespace,
18913 .owner = tbinfo->rolname,
18914 .description = "CONSTRAINT",
18915 .section = SECTION_POST_DATA,
18916 .createStmt = q->data,
18917 .dropStmt = delq->data));
18918 }
18919 else if (coninfo->contype == 'f')
18920 {
18921 char *only;
18922
18923 /*
18924 * Foreign keys on partitioned tables are always declared as
18925 * inheriting to partitions; for all other cases, emit them as
18926 * applying ONLY directly to the named table, because that's how they
18927 * work for regular inherited tables.
18928 */
18929 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
18930
18931 /*
18932 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
18933 * current table data is not processed
18934 */
18935 appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
18937 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
18938 fmtId(coninfo->dobj.name),
18939 coninfo->condef);
18940
18941 appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
18943 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
18944 fmtId(coninfo->dobj.name));
18945
18946 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18947
18948 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18949 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
18950 ARCHIVE_OPTS(.tag = tag,
18951 .namespace = tbinfo->dobj.namespace->dobj.name,
18952 .owner = tbinfo->rolname,
18953 .description = "FK CONSTRAINT",
18954 .section = SECTION_POST_DATA,
18955 .createStmt = q->data,
18956 .dropStmt = delq->data));
18957 }
18958 else if ((coninfo->contype == 'c' || coninfo->contype == 'n') && tbinfo)
18959 {
18960 /* CHECK or invalid not-null constraint on a table */
18961
18962 /* Ignore if not to be dumped separately, or if it was inherited */
18963 if (coninfo->separate && coninfo->conislocal)
18964 {
18965 const char *keyword;
18966
18967 if (coninfo->contype == 'c')
18968 keyword = "CHECK CONSTRAINT";
18969 else
18970 keyword = "CONSTRAINT";
18971
18972 /* not ONLY since we want it to propagate to children */
18973 appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
18975 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
18976 fmtId(coninfo->dobj.name),
18977 coninfo->condef);
18978
18979 appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
18981 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
18982 fmtId(coninfo->dobj.name));
18983
18984 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18985
18986 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18987 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
18988 ARCHIVE_OPTS(.tag = tag,
18989 .namespace = tbinfo->dobj.namespace->dobj.name,
18990 .owner = tbinfo->rolname,
18991 .description = keyword,
18992 .section = SECTION_POST_DATA,
18993 .createStmt = q->data,
18994 .dropStmt = delq->data));
18995 }
18996 }
18997 else if (tbinfo == NULL)
18998 {
18999 /* CHECK, NOT NULL constraint on a domain */
19000 TypeInfo *tyinfo = coninfo->condomain;
19001
19002 Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
19003
19004 /* Ignore if not to be dumped separately */
19005 if (coninfo->separate)
19006 {
19007 const char *keyword;
19008
19009 if (coninfo->contype == 'c')
19010 keyword = "CHECK CONSTRAINT";
19011 else
19012 keyword = "CONSTRAINT";
19013
19014 appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
19016 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
19017 fmtId(coninfo->dobj.name),
19018 coninfo->condef);
19019
19020 appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
19022 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
19023 fmtId(coninfo->dobj.name));
19024
19025 tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
19026
19027 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19028 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
19029 ARCHIVE_OPTS(.tag = tag,
19030 .namespace = tyinfo->dobj.namespace->dobj.name,
19031 .owner = tyinfo->rolname,
19032 .description = keyword,
19033 .section = SECTION_POST_DATA,
19034 .createStmt = q->data,
19035 .dropStmt = delq->data));
19036
19037 if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19038 {
19040 char *qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
19041
19042 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
19043 fmtId(coninfo->dobj.name));
19044
19046 tyinfo->dobj.namespace->dobj.name,
19047 tyinfo->rolname,
19048 coninfo->dobj.catId, 0, coninfo->dobj.dumpId);
19050 free(qtypname);
19051 }
19052 }
19053 }
19054 else
19055 {
19056 pg_fatal("unrecognized constraint type: %c",
19057 coninfo->contype);
19058 }
19059
19060 /* Dump Constraint Comments --- only works for table constraints */
19061 if (tbinfo && coninfo->separate &&
19062 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19064
19065 free(tag);
19068}

References append_depends_on_extension(), appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), appendReloptionsArrayAH(), ARCHIVE_OPTS, ArchiveEntry(), Assert, attname, _dumpOptions::binary_upgrade, binary_upgrade_set_pg_class_oids(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, dumpTableConstraintComment(), fb(), findObjectByDumpId(), fmtId(), fmtQualifiedDumpable, free, getAttrName(), InvalidAttrNumber, nonemptyReloptions(), pg_fatal, pg_strdup(), psprintf(), and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ dumpConversion()

static void dumpConversion ( Archive fout,
const ConvInfo convinfo 
)
static

Definition at line 15260 of file pg_dump.c.

15261{
15262 DumpOptions *dopt = fout->dopt;
15263 PQExpBuffer query;
15264 PQExpBuffer q;
15266 char *qconvname;
15267 PGresult *res;
15268 int i_conforencoding;
15269 int i_contoencoding;
15270 int i_conproc;
15271 int i_condefault;
15272 const char *conforencoding;
15273 const char *contoencoding;
15274 const char *conproc;
15275 bool condefault;
15276
15277 /* Do nothing if not dumping schema */
15278 if (!dopt->dumpSchema)
15279 return;
15280
15281 query = createPQExpBuffer();
15282 q = createPQExpBuffer();
15284
15285 qconvname = pg_strdup(fmtId(convinfo->dobj.name));
15286
15287 /* Get conversion-specific details */
15288 appendPQExpBuffer(query, "SELECT "
15289 "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
15290 "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
15291 "conproc, condefault "
15292 "FROM pg_catalog.pg_conversion c "
15293 "WHERE c.oid = '%u'::pg_catalog.oid",
15294 convinfo->dobj.catId.oid);
15295
15296 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15297
15298 i_conforencoding = PQfnumber(res, "conforencoding");
15299 i_contoencoding = PQfnumber(res, "contoencoding");
15300 i_conproc = PQfnumber(res, "conproc");
15301 i_condefault = PQfnumber(res, "condefault");
15302
15305 conproc = PQgetvalue(res, 0, i_conproc);
15306 condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
15307
15308 appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
15310
15311 appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
15312 (condefault) ? "DEFAULT " : "",
15315 appendPQExpBufferStr(q, " TO ");
15317 /* regproc output is already sufficiently quoted */
15318 appendPQExpBuffer(q, " FROM %s;\n", conproc);
15319
15320 if (dopt->binary_upgrade)
15322 "CONVERSION", qconvname,
15323 convinfo->dobj.namespace->dobj.name);
15324
15325 if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15326 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
15327 ARCHIVE_OPTS(.tag = convinfo->dobj.name,
15328 .namespace = convinfo->dobj.namespace->dobj.name,
15329 .owner = convinfo->rolname,
15330 .description = "CONVERSION",
15331 .section = SECTION_PRE_DATA,
15332 .createStmt = q->data,
15333 .dropStmt = delq->data));
15334
15335 /* Dump Conversion Comments */
15336 if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15337 dumpComment(fout, "CONVERSION", qconvname,
15338 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
15339 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
15340
15341 PQclear(res);
15342
15343 destroyPQExpBuffer(query);
15346 free(qconvname);
15347}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, ExecuteSqlQueryForSingleRow(), fb(), fmtId(), fmtQualifiedDumpable, free, pg_strdup(), PQclear, PQfnumber(), PQgetvalue, and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpDatabase()

static void dumpDatabase ( Archive fout)
static

Definition at line 3296 of file pg_dump.c.

3297{
3298 DumpOptions *dopt = fout->dopt;
3304 PGresult *res;
3305 int i_tableoid,
3306 i_oid,
3307 i_datname,
3308 i_datdba,
3309 i_encoding,
3311 i_collate,
3312 i_ctype,
3316 i_minmxid,
3317 i_datacl,
3326 const char *datname,
3327 *dba,
3328 *encoding,
3330 *collate,
3331 *ctype,
3332 *locale,
3333 *icurules,
3335 *datconnlimit,
3336 *tablespace;
3337 uint32 frozenxid,
3338 minmxid;
3339 char *qdatname;
3340
3341 pg_log_info("saving database definition");
3342
3343 /*
3344 * Fetch the database-level properties for this database.
3345 */
3346 appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
3347 "datdba, "
3348 "pg_encoding_to_char(encoding) AS encoding, "
3349 "datcollate, datctype, datfrozenxid, "
3350 "datacl, acldefault('d', datdba) AS acldefault, "
3351 "datistemplate, datconnlimit, ");
3352 if (fout->remoteVersion >= 90300)
3353 appendPQExpBufferStr(dbQry, "datminmxid, ");
3354 else
3355 appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
3356 if (fout->remoteVersion >= 170000)
3357 appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
3358 else if (fout->remoteVersion >= 150000)
3359 appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
3360 else
3361 appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
3362 if (fout->remoteVersion >= 160000)
3363 appendPQExpBufferStr(dbQry, "daticurules, ");
3364 else
3365 appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
3367 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
3368 "shobj_description(oid, 'pg_database') AS description "
3369 "FROM pg_database "
3370 "WHERE datname = current_database()");
3371
3373
3374 i_tableoid = PQfnumber(res, "tableoid");
3375 i_oid = PQfnumber(res, "oid");
3376 i_datname = PQfnumber(res, "datname");
3377 i_datdba = PQfnumber(res, "datdba");
3378 i_encoding = PQfnumber(res, "encoding");
3379 i_datlocprovider = PQfnumber(res, "datlocprovider");
3380 i_collate = PQfnumber(res, "datcollate");
3381 i_ctype = PQfnumber(res, "datctype");
3382 i_datlocale = PQfnumber(res, "datlocale");
3383 i_daticurules = PQfnumber(res, "daticurules");
3384 i_frozenxid = PQfnumber(res, "datfrozenxid");
3385 i_minmxid = PQfnumber(res, "datminmxid");
3386 i_datacl = PQfnumber(res, "datacl");
3387 i_acldefault = PQfnumber(res, "acldefault");
3388 i_datistemplate = PQfnumber(res, "datistemplate");
3389 i_datconnlimit = PQfnumber(res, "datconnlimit");
3390 i_datcollversion = PQfnumber(res, "datcollversion");
3391 i_tablespace = PQfnumber(res, "tablespace");
3392
3393 dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
3394 dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
3395 datname = PQgetvalue(res, 0, i_datname);
3396 dba = getRoleName(PQgetvalue(res, 0, i_datdba));
3397 encoding = PQgetvalue(res, 0, i_encoding);
3399 collate = PQgetvalue(res, 0, i_collate);
3400 ctype = PQgetvalue(res, 0, i_ctype);
3401 if (!PQgetisnull(res, 0, i_datlocale))
3402 locale = PQgetvalue(res, 0, i_datlocale);
3403 else
3404 locale = NULL;
3405 if (!PQgetisnull(res, 0, i_daticurules))
3407 else
3408 icurules = NULL;
3409 frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
3410 minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
3411 dbdacl.acl = PQgetvalue(res, 0, i_datacl);
3412 dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
3416
3418
3419 /*
3420 * Prepare the CREATE DATABASE command. We must specify OID (if we want
3421 * to preserve that), as well as the encoding, locale, and tablespace
3422 * since those can't be altered later. Other DB properties are left to
3423 * the DATABASE PROPERTIES entry, so that they can be applied after
3424 * reconnecting to the target DB.
3425 *
3426 * For binary upgrade, we use the FILE_COPY strategy because testing has
3427 * shown it to be faster. When the server is in binary upgrade mode, it
3428 * will also skip the checkpoints this strategy ordinarily performs.
3429 */
3430 if (dopt->binary_upgrade)
3431 {
3433 "CREATE DATABASE %s WITH TEMPLATE = template0 "
3434 "OID = %u STRATEGY = FILE_COPY",
3435 qdatname, dbCatId.oid);
3436 }
3437 else
3438 {
3439 appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
3440 qdatname);
3441 }
3442 if (strlen(encoding) > 0)
3443 {
3444 appendPQExpBufferStr(creaQry, " ENCODING = ");
3446 }
3447
3448 appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
3449 if (datlocprovider[0] == 'b')
3450 appendPQExpBufferStr(creaQry, "builtin");
3451 else if (datlocprovider[0] == 'c')
3453 else if (datlocprovider[0] == 'i')
3455 else
3456 pg_fatal("unrecognized locale provider: %s",
3458
3459 if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
3460 {
3461 appendPQExpBufferStr(creaQry, " LOCALE = ");
3463 }
3464 else
3465 {
3466 if (strlen(collate) > 0)
3467 {
3468 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
3470 }
3471 if (strlen(ctype) > 0)
3472 {
3473 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
3475 }
3476 }
3477 if (locale)
3478 {
3479 if (datlocprovider[0] == 'b')
3480 appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
3481 else
3482 appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
3483
3485 }
3486
3487 if (icurules)
3488 {
3489 appendPQExpBufferStr(creaQry, " ICU_RULES = ");
3491 }
3492
3493 /*
3494 * For binary upgrade, carry over the collation version. For normal
3495 * dump/restore, omit the version, so that it is computed upon restore.
3496 */
3497 if (dopt->binary_upgrade)
3498 {
3499 if (!PQgetisnull(res, 0, i_datcollversion))
3500 {
3501 appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
3504 fout);
3505 }
3506 }
3507
3508 /*
3509 * Note: looking at dopt->outputNoTablespaces here is completely the wrong
3510 * thing; the decision whether to specify a tablespace should be left till
3511 * pg_restore, so that pg_restore --no-tablespaces applies. Ideally we'd
3512 * label the DATABASE entry with the tablespace and let the normal
3513 * tablespace selection logic work ... but CREATE DATABASE doesn't pay
3514 * attention to default_tablespace, so that won't work.
3515 */
3516 if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
3517 !dopt->outputNoTablespaces)
3518 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
3519 fmtId(tablespace));
3521
3522 appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
3523 qdatname);
3524
3526
3528 dbCatId, /* catalog ID */
3529 dbDumpId, /* dump ID */
3530 ARCHIVE_OPTS(.tag = datname,
3531 .owner = dba,
3532 .description = "DATABASE",
3533 .section = SECTION_PRE_DATA,
3534 .createStmt = creaQry->data,
3535 .dropStmt = delQry->data));
3536
3537 /* Compute correct tag for archive entry */
3538 appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
3539
3540 /* Dump DB comment if any */
3541 {
3542 /*
3543 * 8.2 and up keep comments on shared objects in a shared table, so we
3544 * cannot use the dumpComment() code used for other database objects.
3545 * Be careful that the ArchiveEntry parameters match that function.
3546 */
3547 char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
3548
3549 if (comment && *comment && !dopt->no_comments)
3550 {
3552
3553 /*
3554 * Generates warning when loaded into a differently-named
3555 * database.
3556 */
3557 appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
3560
3562 ARCHIVE_OPTS(.tag = labelq->data,
3563 .owner = dba,
3564 .description = "COMMENT",
3565 .section = SECTION_NONE,
3566 .createStmt = dbQry->data,
3567 .deps = &dbDumpId,
3568 .nDeps = 1));
3569 }
3570 }
3571
3572 /* Dump DB security label, if enabled */
3573 if (!dopt->no_security_labels)
3574 {
3575 PGresult *shres;
3577
3579
3580 buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
3584 if (seclabelQry->len > 0)
3586 ARCHIVE_OPTS(.tag = labelq->data,
3587 .owner = dba,
3588 .description = "SECURITY LABEL",
3589 .section = SECTION_NONE,
3590 .createStmt = seclabelQry->data,
3591 .deps = &dbDumpId,
3592 .nDeps = 1));
3594 PQclear(shres);
3595 }
3596
3597 /*
3598 * Dump ACL if any. Note that we do not support initial privileges
3599 * (pg_init_privs) on databases.
3600 */
3601 dbdacl.privtype = 0;
3602 dbdacl.initprivs = NULL;
3603
3604 dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
3605 qdatname, NULL, NULL,
3606 NULL, dba, &dbdacl);
3607
3608 /*
3609 * Now construct a DATABASE PROPERTIES archive entry to restore any
3610 * non-default database-level properties. (The reason this must be
3611 * separate is that we cannot put any additional commands into the TOC
3612 * entry that has CREATE DATABASE. pg_restore would execute such a group
3613 * in an implicit transaction block, and the backend won't allow CREATE
3614 * DATABASE in that context.)
3615 */
3618
3619 if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
3620 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
3622
3623 if (strcmp(datistemplate, "t") == 0)
3624 {
3625 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
3626 qdatname);
3627
3628 /*
3629 * The backend won't accept DROP DATABASE on a template database. We
3630 * can deal with that by removing the template marking before the DROP
3631 * gets issued. We'd prefer to use ALTER DATABASE IF EXISTS here, but
3632 * since no such command is currently supported, fake it with a direct
3633 * UPDATE on pg_database.
3634 */
3635 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
3636 "SET datistemplate = false WHERE datname = ");
3639 }
3640
3641 /*
3642 * We do not restore pg_database.dathasloginevt because it is set
3643 * automatically on login event trigger creation.
3644 */
3645
3646 /* Add database-specific SET options */
3648
3649 /*
3650 * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
3651 * entry, too, for lack of a better place.
3652 */
3653 if (dopt->binary_upgrade)
3654 {
3655 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
3656 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
3657 "SET datfrozenxid = '%u', datminmxid = '%u'\n"
3658 "WHERE datname = ",
3659 frozenxid, minmxid);
3662 }
3663
3664 if (creaQry->len > 0)
3666 ARCHIVE_OPTS(.tag = datname,
3667 .owner = dba,
3668 .description = "DATABASE PROPERTIES",
3669 .section = SECTION_PRE_DATA,
3670 .createStmt = creaQry->data,
3671 .dropStmt = delQry->data,
3672 .deps = &dbDumpId));
3673
3674 /*
3675 * pg_largeobject comes from the old system intact, so set its
3676 * relfrozenxids, relminmxids and relfilenode.
3677 *
3678 * pg_largeobject_metadata also comes from the old system intact for
3679 * upgrades from v16 and newer, so set its relfrozenxids, relminmxids, and
3680 * relfilenode, too. pg_upgrade can't copy/link the files from older
3681 * versions because aclitem (needed by pg_largeobject_metadata.lomacl)
3682 * changed its storage format in v16.
3683 */
3684 if (dopt->binary_upgrade)
3685 {
3692 int ii_relfrozenxid,
3694 ii_oid,
3696
3697 if (fout->remoteVersion >= 90300)
3698 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
3699 "FROM pg_catalog.pg_class\n"
3700 "WHERE oid IN (%u, %u, %u, %u);\n",
3703 else
3704 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
3705 "FROM pg_catalog.pg_class\n"
3706 "WHERE oid IN (%u, %u);\n",
3708
3710
3711 ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
3712 ii_relminmxid = PQfnumber(lo_res, "relminmxid");
3713 ii_relfilenode = PQfnumber(lo_res, "relfilenode");
3714 ii_oid = PQfnumber(lo_res, "oid");
3715
3716 appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3717 appendPQExpBufferStr(lomHorizonQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
3718 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
3719 appendPQExpBufferStr(lomOutQry, "\n-- For binary upgrade, preserve pg_largeobject_metadata and index relfilenodes\n");
3720 for (int i = 0; i < PQntuples(lo_res); ++i)
3721 {
3722 Oid oid;
3723 RelFileNumber relfilenumber;
3726
3727 oid = atooid(PQgetvalue(lo_res, i, ii_oid));
3728 relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
3729
3730 if (oid == LargeObjectRelationId ||
3732 {
3734 outQry = loOutQry;
3735 }
3736 else
3737 {
3739 outQry = lomOutQry;
3740 }
3741
3742 appendPQExpBuffer(horizonQry, "UPDATE pg_catalog.pg_class\n"
3743 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3744 "WHERE oid = %u;\n",
3748
3749 if (oid == LargeObjectRelationId ||
3752 "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
3753 relfilenumber);
3754 else if (oid == LargeObjectLOidPNIndexId ||
3757 "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
3758 relfilenumber);
3759 }
3760
3762 "TRUNCATE pg_catalog.pg_largeobject;\n");
3764 "TRUNCATE pg_catalog.pg_largeobject_metadata;\n");
3765
3768
3770 ARCHIVE_OPTS(.tag = "pg_largeobject",
3771 .description = "pg_largeobject",
3772 .section = SECTION_PRE_DATA,
3773 .createStmt = loOutQry->data));
3774
3775 if (fout->remoteVersion >= 160000)
3777 ARCHIVE_OPTS(.tag = "pg_largeobject_metadata",
3778 .description = "pg_largeobject_metadata",
3779 .section = SECTION_PRE_DATA,
3780 .createStmt = lomOutQry->data));
3781
3782 PQclear(lo_res);
3783
3789 }
3790
3791 PQclear(res);
3792
3793 free(qdatname);
3798}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), atooid, _dumpOptions::binary_upgrade, buildShSecLabelQuery(), comment, conn, createDumpId(), createPQExpBuffer(), nameData::data, datconnlimit, datistemplate, datlocprovider, datname, description, destroyPQExpBuffer(), dumpACL(), dumpDatabaseConfig(), emitShSecLabels(), encoding, ExecuteSqlQuery(), ExecuteSqlQueryForSingleRow(), fb(), fmtId(), free, GetConnection(), getRoleName(), i, InvalidDumpId, nilCatalogId, _dumpOptions::no_comments, _dumpOptions::no_security_labels, _dumpOptions::outputNoTablespaces, pg_fatal, pg_log_info, pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, resetPQExpBuffer(), SECTION_NONE, SECTION_PRE_DATA, and tablespace.

Referenced by main().

◆ dumpDatabaseConfig()

static void dumpDatabaseConfig ( Archive AH,
PQExpBuffer  outbuf,
const char dbname,
Oid  dboid 
)
static

Definition at line 3805 of file pg_dump.c.

3807{
3808 PGconn *conn = GetConnection(AH);
3810 PGresult *res;
3811
3812 /* First collect database-specific options */
3813 printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
3814 "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3815 dboid);
3816
3817 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3818
3819 for (int i = 0; i < PQntuples(res); i++)
3821 "DATABASE", dbname, NULL, NULL,
3822 outbuf);
3823
3824 PQclear(res);
3825
3826 /* Now look for role-and-database-specific options */
3827 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3828 "FROM pg_db_role_setting s, pg_roles r "
3829 "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3830 dboid);
3831
3832 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3833
3834 for (int i = 0; i < PQntuples(res); i++)
3836 "ROLE", PQgetvalue(res, i, 0),
3837 "DATABASE", dbname,
3838 outbuf);
3839
3840 PQclear(res);
3841
3843}

References buf, conn, createPQExpBuffer(), dbname, destroyPQExpBuffer(), ExecuteSqlQuery(), fb(), GetConnection(), i, makeAlterConfigCommand(), PGRES_TUPLES_OK, PQclear, PQgetvalue, PQntuples, and printfPQExpBuffer().

Referenced by dumpDatabase().

◆ dumpDefaultACL()

static void dumpDefaultACL ( Archive fout,
const DefaultACLInfo daclinfo 
)
static

Definition at line 16334 of file pg_dump.c.

16335{
16336 DumpOptions *dopt = fout->dopt;
16337 PQExpBuffer q;
16338 PQExpBuffer tag;
16339 const char *type;
16340
16341 /* Do nothing if not dumping schema, or if we're skipping ACLs */
16342 if (!dopt->dumpSchema || dopt->aclsSkip)
16343 return;
16344
16345 q = createPQExpBuffer();
16346 tag = createPQExpBuffer();
16347
16348 switch (daclinfo->defaclobjtype)
16349 {
16350 case DEFACLOBJ_RELATION:
16351 type = "TABLES";
16352 break;
16353 case DEFACLOBJ_SEQUENCE:
16354 type = "SEQUENCES";
16355 break;
16356 case DEFACLOBJ_FUNCTION:
16357 type = "FUNCTIONS";
16358 break;
16359 case DEFACLOBJ_TYPE:
16360 type = "TYPES";
16361 break;
16363 type = "SCHEMAS";
16364 break;
16366 type = "LARGE OBJECTS";
16367 break;
16368 default:
16369 /* shouldn't get here */
16370 pg_fatal("unrecognized object type in default privileges: %d",
16371 (int) daclinfo->defaclobjtype);
16372 type = ""; /* keep compiler quiet */
16373 }
16374
16375 appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
16376
16377 /* build the actual command(s) for this tuple */
16379 daclinfo->dobj.namespace != NULL ?
16380 daclinfo->dobj.namespace->dobj.name : NULL,
16381 daclinfo->dacl.acl,
16382 daclinfo->dacl.acldefault,
16383 daclinfo->defaclrole,
16384 fout->remoteVersion,
16385 q))
16386 pg_fatal("could not parse default ACL list (%s)",
16387 daclinfo->dacl.acl);
16388
16389 if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
16390 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
16391 ARCHIVE_OPTS(.tag = tag->data,
16392 .namespace = daclinfo->dobj.namespace ?
16393 daclinfo->dobj.namespace->dobj.name : NULL,
16394 .owner = daclinfo->defaclrole,
16395 .description = "DEFAULT ACL",
16396 .section = SECTION_POST_DATA,
16397 .createStmt = q->data));
16398
16399 destroyPQExpBuffer(tag);
16401}

References _dumpOptions::aclsSkip, appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), buildDefaultACLCommands(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_ACL, _dumpOptions::dumpSchema, fb(), pg_fatal, SECTION_POST_DATA, and type.

Referenced by dumpDumpableObject().

◆ dumpDomain()

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

Definition at line 12717 of file pg_dump.c.

12718{
12719 DumpOptions *dopt = fout->dopt;
12723 PGresult *res;
12724 int i;
12725 char *qtypname;
12726 char *qualtypname;
12727 char *typnotnull;
12728 char *typdefn;
12729 char *typdefault;
12730 Oid typcollation;
12731 bool typdefault_is_literal = false;
12732
12733 if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
12734 {
12735 /* Set up query for domain-specific details */
12737 "PREPARE dumpDomain(pg_catalog.oid) AS\n");
12738
12739 appendPQExpBufferStr(query, "SELECT t.typnotnull, "
12740 "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
12741 "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
12742 "t.typdefault, "
12743 "CASE WHEN t.typcollation <> u.typcollation "
12744 "THEN t.typcollation ELSE 0 END AS typcollation "
12745 "FROM pg_catalog.pg_type t "
12746 "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
12747 "WHERE t.oid = $1");
12748
12749 ExecuteSqlStatement(fout, query->data);
12750
12751 fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
12752 }
12753
12754 printfPQExpBuffer(query,
12755 "EXECUTE dumpDomain('%u')",
12756 tyinfo->dobj.catId.oid);
12757
12758 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12759
12760 typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
12761 typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
12762 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
12763 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
12764 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
12765 {
12766 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
12767 typdefault_is_literal = true; /* it needs quotes */
12768 }
12769 else
12770 typdefault = NULL;
12771 typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
12772
12773 if (dopt->binary_upgrade)
12775 tyinfo->dobj.catId.oid,
12776 true, /* force array type */
12777 false); /* force multirange type */
12778
12779 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12781
12783 "CREATE DOMAIN %s AS %s",
12785 typdefn);
12786
12787 /* Print collation only if different from base type's collation */
12788 if (OidIsValid(typcollation))
12789 {
12790 CollInfo *coll;
12791
12792 coll = findCollationByOid(typcollation);
12793 if (coll)
12794 appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
12795 }
12796
12797 /*
12798 * Print a not-null constraint if there's one. In servers older than 17
12799 * these don't have names, so just print it unadorned; in newer ones they
12800 * do, but most of the time it's going to be the standard generated one,
12801 * so omit the name in that case also.
12802 */
12803 if (typnotnull[0] == 't')
12804 {
12805 if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
12806 appendPQExpBufferStr(q, " NOT NULL");
12807 else
12808 {
12809 ConstraintInfo *notnull = tyinfo->notnull;
12810
12811 if (!notnull->separate)
12812 {
12813 char *default_name;
12814
12815 /* XXX should match ChooseConstraintName better */
12816 default_name = psprintf("%s_not_null", tyinfo->dobj.name);
12817
12818 if (strcmp(default_name, notnull->dobj.name) == 0)
12819 appendPQExpBufferStr(q, " NOT NULL");
12820 else
12821 appendPQExpBuffer(q, " CONSTRAINT %s %s",
12822 fmtId(notnull->dobj.name), notnull->condef);
12824 }
12825 }
12826 }
12827
12828 if (typdefault != NULL)
12829 {
12830 appendPQExpBufferStr(q, " DEFAULT ");
12833 else
12835 }
12836
12837 PQclear(res);
12838
12839 /*
12840 * Add any CHECK constraints for the domain
12841 */
12842 for (i = 0; i < tyinfo->nDomChecks; i++)
12843 {
12844 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
12845
12846 if (!domcheck->separate && domcheck->contype == 'c')
12847 appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
12848 fmtId(domcheck->dobj.name), domcheck->condef);
12849 }
12850
12851 appendPQExpBufferStr(q, ";\n");
12852
12853 appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
12854
12855 if (dopt->binary_upgrade)
12857 "DOMAIN", qtypname,
12858 tyinfo->dobj.namespace->dobj.name);
12859
12860 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12861 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12862 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12863 .namespace = tyinfo->dobj.namespace->dobj.name,
12864 .owner = tyinfo->rolname,
12865 .description = "DOMAIN",
12866 .section = SECTION_PRE_DATA,
12867 .createStmt = q->data,
12868 .dropStmt = delq->data));
12869
12870 /* Dump Domain Comments and Security Labels */
12871 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12872 dumpComment(fout, "DOMAIN", qtypname,
12873 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12874 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12875
12876 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12877 dumpSecLabel(fout, "DOMAIN", qtypname,
12878 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12879 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12880
12881 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12882 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12883 qtypname, NULL,
12884 tyinfo->dobj.namespace->dobj.name,
12885 NULL, tyinfo->rolname, &tyinfo->dacl);
12886
12887 /* Dump any per-constraint comments */
12888 for (i = 0; i < tyinfo->nDomChecks; i++)
12889 {
12890 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
12892
12893 /* but only if the constraint itself was dumped here */
12894 if (domcheck->separate)
12895 continue;
12896
12898 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
12899 fmtId(domcheck->dobj.name));
12900
12901 if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
12903 tyinfo->dobj.namespace->dobj.name,
12904 tyinfo->rolname,
12905 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
12906
12908 }
12909
12910 /*
12911 * And a comment on the not-null constraint, if there's one -- but only if
12912 * the constraint itself was dumped here
12913 */
12914 if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
12915 {
12917
12918 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
12919 fmtId(tyinfo->notnull->dobj.name));
12920
12921 if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
12923 tyinfo->dobj.namespace->dobj.name,
12924 tyinfo->rolname,
12925 tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
12927 }
12928
12931 destroyPQExpBuffer(query);
12932 free(qtypname);
12934}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), atooid, _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), binary_upgrade_set_type_oids_by_type_oid(), _constraintInfo::condef, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), _constraintInfo::dobj, DUMP_COMPONENT_ACL, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpACL(), dumpComment(), dumpSecLabel(), ExecuteSqlQueryForSingleRow(), ExecuteSqlStatement(), fb(), findCollationByOid(), fmtId(), fmtQualifiedDumpable, free, i, InvalidDumpId, _dumpableObject::name, OidIsValid, pg_strdup(), PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PREPQUERY_DUMPDOMAIN, printfPQExpBuffer(), psprintf(), SECTION_PRE_DATA, and _constraintInfo::separate.

Referenced by dumpType().

◆ dumpDumpableObject()

static void dumpDumpableObject ( Archive fout,
DumpableObject dobj 
)
static

Definition at line 11678 of file pg_dump.c.

11679{
11680 /*
11681 * Clear any dump-request bits for components that don't exist for this
11682 * object. (This makes it safe to initially use DUMP_COMPONENT_ALL as the
11683 * request for every kind of object.)
11684 */
11685 dobj->dump &= dobj->components;
11686
11687 /* Now, short-circuit if there's nothing to be done here. */
11688 if (dobj->dump == 0)
11689 return;
11690
11691 switch (dobj->objType)
11692 {
11693 case DO_NAMESPACE:
11694 dumpNamespace(fout, (const NamespaceInfo *) dobj);
11695 break;
11696 case DO_EXTENSION:
11697 dumpExtension(fout, (const ExtensionInfo *) dobj);
11698 break;
11699 case DO_TYPE:
11700 dumpType(fout, (const TypeInfo *) dobj);
11701 break;
11702 case DO_SHELL_TYPE:
11703 dumpShellType(fout, (const ShellTypeInfo *) dobj);
11704 break;
11705 case DO_FUNC:
11706 dumpFunc(fout, (const FuncInfo *) dobj);
11707 break;
11708 case DO_AGG:
11709 dumpAgg(fout, (const AggInfo *) dobj);
11710 break;
11711 case DO_OPERATOR:
11712 dumpOpr(fout, (const OprInfo *) dobj);
11713 break;
11714 case DO_ACCESS_METHOD:
11715 dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
11716 break;
11717 case DO_OPCLASS:
11718 dumpOpclass(fout, (const OpclassInfo *) dobj);
11719 break;
11720 case DO_OPFAMILY:
11721 dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
11722 break;
11723 case DO_COLLATION:
11724 dumpCollation(fout, (const CollInfo *) dobj);
11725 break;
11726 case DO_CONVERSION:
11727 dumpConversion(fout, (const ConvInfo *) dobj);
11728 break;
11729 case DO_TABLE:
11730 dumpTable(fout, (const TableInfo *) dobj);
11731 break;
11732 case DO_TABLE_ATTACH:
11733 dumpTableAttach(fout, (const TableAttachInfo *) dobj);
11734 break;
11735 case DO_ATTRDEF:
11736 dumpAttrDef(fout, (const AttrDefInfo *) dobj);
11737 break;
11738 case DO_INDEX:
11739 dumpIndex(fout, (const IndxInfo *) dobj);
11740 break;
11741 case DO_INDEX_ATTACH:
11742 dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
11743 break;
11744 case DO_STATSEXT:
11745 dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
11746 dumpStatisticsExtStats(fout, (const StatsExtInfo *) dobj);
11747 break;
11748 case DO_REFRESH_MATVIEW:
11749 refreshMatViewData(fout, (const TableDataInfo *) dobj);
11750 break;
11751 case DO_RULE:
11752 dumpRule(fout, (const RuleInfo *) dobj);
11753 break;
11754 case DO_TRIGGER:
11755 dumpTrigger(fout, (const TriggerInfo *) dobj);
11756 break;
11757 case DO_EVENT_TRIGGER:
11758 dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
11759 break;
11760 case DO_CONSTRAINT:
11761 dumpConstraint(fout, (const ConstraintInfo *) dobj);
11762 break;
11763 case DO_FK_CONSTRAINT:
11764 dumpConstraint(fout, (const ConstraintInfo *) dobj);
11765 break;
11766 case DO_PROCLANG:
11767 dumpProcLang(fout, (const ProcLangInfo *) dobj);
11768 break;
11769 case DO_CAST:
11770 dumpCast(fout, (const CastInfo *) dobj);
11771 break;
11772 case DO_TRANSFORM:
11773 dumpTransform(fout, (const TransformInfo *) dobj);
11774 break;
11775 case DO_SEQUENCE_SET:
11776 dumpSequenceData(fout, (const TableDataInfo *) dobj);
11777 break;
11778 case DO_TABLE_DATA:
11779 dumpTableData(fout, (const TableDataInfo *) dobj);
11780 break;
11781 case DO_DUMMY_TYPE:
11782 /* table rowtypes and array types are never dumped separately */
11783 break;
11784 case DO_TSPARSER:
11785 dumpTSParser(fout, (const TSParserInfo *) dobj);
11786 break;
11787 case DO_TSDICT:
11788 dumpTSDictionary(fout, (const TSDictInfo *) dobj);
11789 break;
11790 case DO_TSTEMPLATE:
11791 dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
11792 break;
11793 case DO_TSCONFIG:
11794 dumpTSConfig(fout, (const TSConfigInfo *) dobj);
11795 break;
11796 case DO_FDW:
11797 dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
11798 break;
11799 case DO_FOREIGN_SERVER:
11800 dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
11801 break;
11802 case DO_DEFAULT_ACL:
11803 dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
11804 break;
11805 case DO_LARGE_OBJECT:
11806 dumpLO(fout, (const LoInfo *) dobj);
11807 break;
11809 if (dobj->dump & DUMP_COMPONENT_DATA)
11810 {
11811 LoInfo *loinfo;
11812 TocEntry *te;
11813
11815 if (loinfo == NULL)
11816 pg_fatal("missing metadata for large objects \"%s\"",
11817 dobj->name);
11818
11819 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
11820 ARCHIVE_OPTS(.tag = dobj->name,
11821 .owner = loinfo->rolname,
11822 .description = "BLOBS",
11823 .section = SECTION_DATA,
11824 .deps = dobj->dependencies,
11825 .nDeps = dobj->nDeps,
11826 .dumpFn = dumpLOs,
11827 .dumpArg = loinfo));
11828
11829 /*
11830 * Set the TocEntry's dataLength in case we are doing a
11831 * parallel dump and want to order dump jobs by table size.
11832 * (We need some size estimate for every TocEntry with a
11833 * DataDumper function.) We don't currently have any cheap
11834 * way to estimate the size of LOs, but fortunately it doesn't
11835 * matter too much as long as we get large batches of LOs
11836 * processed reasonably early. Assume 8K per blob.
11837 */
11838 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
11839 }
11840 break;
11841 case DO_POLICY:
11842 dumpPolicy(fout, (const PolicyInfo *) dobj);
11843 break;
11844 case DO_PUBLICATION:
11845 dumpPublication(fout, (const PublicationInfo *) dobj);
11846 break;
11847 case DO_PUBLICATION_REL:
11849 break;
11852 (const PublicationSchemaInfo *) dobj);
11853 break;
11854 case DO_SUBSCRIPTION:
11855 dumpSubscription(fout, (const SubscriptionInfo *) dobj);
11856 break;
11858 dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
11859 break;
11860 case DO_REL_STATS:
11861 dumpRelationStats(fout, (const RelStatsInfo *) dobj);
11862 break;
11865 /* never dumped, nothing to do */
11866 break;
11867 }
11868}

References ARCHIVE_OPTS, ArchiveEntry(), _dumpableObject::components, _tocEntry::dataLength, 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::dump, DUMP_COMPONENT_DATA, dumpAccessMethod(), dumpAgg(), dumpAttrDef(), dumpCast(), dumpCollation(), dumpConstraint(), dumpConversion(), dumpDefaultACL(), dumpEventTrigger(), dumpExtension(), dumpForeignDataWrapper(), dumpForeignServer(), dumpFunc(), dumpIndex(), dumpIndexAttach(), dumpLO(), dumpLOs(), dumpNamespace(), dumpOpclass(), dumpOpfamily(), dumpOpr(), dumpPolicy(), dumpProcLang(), dumpPublication(), dumpPublicationNamespace(), dumpPublicationTable(), dumpRelationStats(), dumpRule(), dumpSequenceData(), dumpShellType(), dumpStatisticsExt(), dumpStatisticsExtStats(), dumpSubscription(), dumpSubscriptionTable(), dumpTable(), dumpTableAttach(), dumpTableData(), dumpTransform(), dumpTrigger(), dumpTSConfig(), dumpTSDictionary(), dumpTSParser(), dumpTSTemplate(), dumpType(), fb(), findObjectByDumpId(), _dumpableObject::objType, pg_fatal, refreshMatViewData(), _namespaceInfo::rolname, and SECTION_DATA.

Referenced by main().

◆ dumpEncoding()

static void dumpEncoding ( Archive AH)
static

Definition at line 3849 of file pg_dump.c.

3850{
3851 const char *encname = pg_encoding_to_char(AH->encoding);
3853
3854 pg_log_info("saving encoding = %s", encname);
3855
3856 appendPQExpBufferStr(qry, "SET client_encoding = ");
3858 appendPQExpBufferStr(qry, ";\n");
3859
3861 ARCHIVE_OPTS(.tag = "ENCODING",
3862 .description = "ENCODING",
3863 .section = SECTION_PRE_DATA,
3864 .createStmt = qry->data));
3865
3866 destroyPQExpBuffer(qry);
3867}

References appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), createDumpId(), createPQExpBuffer(), PQExpBufferData::data, description, destroyPQExpBuffer(), Archive::encoding, fb(), nilCatalogId, pg_encoding_to_char, pg_log_info, and SECTION_PRE_DATA.

Referenced by main().

◆ dumpEnumType()

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

Definition at line 12106 of file pg_dump.c.

12107{
12108 DumpOptions *dopt = fout->dopt;
12112 PGresult *res;
12113 int num,
12114 i;
12115 Oid enum_oid;
12116 char *qtypname;
12117 char *qualtypname;
12118 char *label;
12119 int i_enumlabel;
12120 int i_oid;
12121
12122 if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
12123 {
12124 /* Set up query for enum-specific details */
12126 "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
12127 "SELECT oid, enumlabel "
12128 "FROM pg_catalog.pg_enum "
12129 "WHERE enumtypid = $1 "
12130 "ORDER BY enumsortorder");
12131
12132 ExecuteSqlStatement(fout, query->data);
12133
12134 fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
12135 }
12136
12137 printfPQExpBuffer(query,
12138 "EXECUTE dumpEnumType('%u')",
12139 tyinfo->dobj.catId.oid);
12140
12141 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12142
12143 num = PQntuples(res);
12144
12145 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12147
12148 /*
12149 * CASCADE shouldn't be required here as for normal types since the I/O
12150 * functions are generic and do not get dropped.
12151 */
12152 appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12153
12154 if (dopt->binary_upgrade)
12156 tyinfo->dobj.catId.oid,
12157 false, false);
12158
12159 appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
12160 qualtypname);
12161
12162 if (!dopt->binary_upgrade)
12163 {
12164 i_enumlabel = PQfnumber(res, "enumlabel");
12165
12166 /* Labels with server-assigned oids */
12167 for (i = 0; i < num; i++)
12168 {
12169 label = PQgetvalue(res, i, i_enumlabel);
12170 if (i > 0)
12171 appendPQExpBufferChar(q, ',');
12172 appendPQExpBufferStr(q, "\n ");
12174 }
12175 }
12176
12177 appendPQExpBufferStr(q, "\n);\n");
12178
12179 if (dopt->binary_upgrade)
12180 {
12181 i_oid = PQfnumber(res, "oid");
12182 i_enumlabel = PQfnumber(res, "enumlabel");
12183
12184 /* Labels with dump-assigned (preserved) oids */
12185 for (i = 0; i < num; i++)
12186 {
12187 enum_oid = atooid(PQgetvalue(res, i, i_oid));
12188 label = PQgetvalue(res, i, i_enumlabel);
12189
12190 if (i == 0)
12191 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
12193 "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
12194 enum_oid);
12195 appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
12197 appendPQExpBufferStr(q, ";\n\n");
12198 }
12199 }
12200
12201 if (dopt->binary_upgrade)
12203 "TYPE", qtypname,
12204 tyinfo->dobj.namespace->dobj.name);
12205
12206 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12207 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12208 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12209 .namespace = tyinfo->dobj.namespace->dobj.name,
12210 .owner = tyinfo->rolname,
12211 .description = "TYPE",
12212 .section = SECTION_PRE_DATA,
12213 .createStmt = q->data,
12214 .dropStmt = delq->data));
12215
12216 /* Dump Type Comments and Security Labels */
12217 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12218 dumpComment(fout, "TYPE", qtypname,
12219 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12220 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12221
12222 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12223 dumpSecLabel(fout, "TYPE", qtypname,
12224 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12225 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12226
12227 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12228 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12229 qtypname, NULL,
12230 tyinfo->dobj.namespace->dobj.name,
12231 NULL, tyinfo->rolname, &tyinfo->dacl);
12232
12233 PQclear(res);
12236 destroyPQExpBuffer(query);
12237 free(qtypname);
12239}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), atooid, _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), binary_upgrade_set_type_oids_by_type_oid(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_ACL, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpACL(), dumpComment(), dumpSecLabel(), ExecuteSqlQuery(), ExecuteSqlStatement(), fb(), fmtId(), fmtQualifiedDumpable, free, i, InvalidDumpId, label, pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, PREPQUERY_DUMPENUMTYPE, printfPQExpBuffer(), and SECTION_PRE_DATA.

Referenced by dumpType().

◆ dumpEventTrigger()

static void dumpEventTrigger ( Archive fout,
const EventTriggerInfo evtinfo 
)
static

Definition at line 19663 of file pg_dump.c.

19664{
19665 DumpOptions *dopt = fout->dopt;
19666 PQExpBuffer query;
19668 char *qevtname;
19669
19670 /* Do nothing if not dumping schema */
19671 if (!dopt->dumpSchema)
19672 return;
19673
19674 query = createPQExpBuffer();
19676
19677 qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
19678
19679 appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
19681 appendPQExpBufferStr(query, " ON ");
19682 appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
19683
19684 if (strcmp("", evtinfo->evttags) != 0)
19685 {
19686 appendPQExpBufferStr(query, "\n WHEN TAG IN (");
19687 appendPQExpBufferStr(query, evtinfo->evttags);
19688 appendPQExpBufferChar(query, ')');
19689 }
19690
19691 appendPQExpBufferStr(query, "\n EXECUTE FUNCTION ");
19692 appendPQExpBufferStr(query, evtinfo->evtfname);
19693 appendPQExpBufferStr(query, "();\n");
19694
19695 if (evtinfo->evtenabled != 'O')
19696 {
19697 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
19698 qevtname);
19699 switch (evtinfo->evtenabled)
19700 {
19701 case 'D':
19702 appendPQExpBufferStr(query, "DISABLE");
19703 break;
19704 case 'A':
19705 appendPQExpBufferStr(query, "ENABLE ALWAYS");
19706 break;
19707 case 'R':
19708 appendPQExpBufferStr(query, "ENABLE REPLICA");
19709 break;
19710 default:
19711 appendPQExpBufferStr(query, "ENABLE");
19712 break;
19713 }
19714 appendPQExpBufferStr(query, ";\n");
19715 }
19716
19717 appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
19718 qevtname);
19719
19720 if (dopt->binary_upgrade)
19722 "EVENT TRIGGER", qevtname, NULL);
19723
19724 if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19725 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
19726 ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
19727 .owner = evtinfo->evtowner,
19728 .description = "EVENT TRIGGER",
19729 .section = SECTION_POST_DATA,
19730 .createStmt = query->data,
19731 .dropStmt = delqry->data));
19732
19733 if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19734 dumpComment(fout, "EVENT TRIGGER", qevtname,
19735 NULL, evtinfo->evtowner,
19736 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
19737
19738 if (evtinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
19739 dumpSecLabel(fout, "EVENT TRIGGER", qevtname,
19740 NULL, evtinfo->evtowner,
19741 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
19742
19743 destroyPQExpBuffer(query);
19745 free(qevtname);
19746}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpComment(), _dumpOptions::dumpSchema, dumpSecLabel(), fb(), fmtId(), free, pg_strdup(), and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ dumpExtension()

static void dumpExtension ( Archive fout,
const ExtensionInfo extinfo 
)
static

Definition at line 11952 of file pg_dump.c.

11953{
11954 DumpOptions *dopt = fout->dopt;
11955 PQExpBuffer q;
11957 char *qextname;
11958
11959 /* Do nothing if not dumping schema */
11960 if (!dopt->dumpSchema)
11961 return;
11962
11963 q = createPQExpBuffer();
11965
11966 qextname = pg_strdup(fmtId(extinfo->dobj.name));
11967
11968 appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
11969
11970 if (!dopt->binary_upgrade)
11971 {
11972 /*
11973 * In a regular dump, we simply create the extension, intentionally
11974 * not specifying a version, so that the destination installation's
11975 * default version is used.
11976 *
11977 * Use of IF NOT EXISTS here is unlike our behavior for other object
11978 * types; but there are various scenarios in which it's convenient to
11979 * manually create the desired extension before restoring, so we
11980 * prefer to allow it to exist already.
11981 */
11982 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
11983 qextname, fmtId(extinfo->namespace));
11984 }
11985 else
11986 {
11987 /*
11988 * In binary-upgrade mode, it's critical to reproduce the state of the
11989 * database exactly, so our procedure is to create an empty extension,
11990 * restore all the contained objects normally, and add them to the
11991 * extension one by one. This function performs just the first of
11992 * those steps. binary_upgrade_extension_member() takes care of
11993 * adding member objects as they're created.
11994 */
11995 int i;
11996 int n;
11997
11998 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
11999
12000 /*
12001 * We unconditionally create the extension, so we must drop it if it
12002 * exists. This could happen if the user deleted 'plpgsql' and then
12003 * readded it, causing its oid to be greater than g_last_builtin_oid.
12004 */
12005 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
12006
12008 "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
12009 appendStringLiteralAH(q, extinfo->dobj.name, fout);
12010 appendPQExpBufferStr(q, ", ");
12011 appendStringLiteralAH(q, extinfo->namespace, fout);
12012 appendPQExpBufferStr(q, ", ");
12013 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
12014 appendStringLiteralAH(q, extinfo->extversion, fout);
12015 appendPQExpBufferStr(q, ", ");
12016
12017 /*
12018 * Note that we're pushing extconfig (an OID array) back into
12019 * pg_extension exactly as-is. This is OK because pg_class OIDs are
12020 * preserved in binary upgrade.
12021 */
12022 if (strlen(extinfo->extconfig) > 2)
12023 appendStringLiteralAH(q, extinfo->extconfig, fout);
12024 else
12025 appendPQExpBufferStr(q, "NULL");
12026 appendPQExpBufferStr(q, ", ");
12027 if (strlen(extinfo->extcondition) > 2)
12028 appendStringLiteralAH(q, extinfo->extcondition, fout);
12029 else
12030 appendPQExpBufferStr(q, "NULL");
12031 appendPQExpBufferStr(q, ", ");
12032 appendPQExpBufferStr(q, "ARRAY[");
12033 n = 0;
12034 for (i = 0; i < extinfo->dobj.nDeps; i++)
12035 {
12037
12038 extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
12039 if (extobj && extobj->objType == DO_EXTENSION)
12040 {
12041 if (n++ > 0)
12042 appendPQExpBufferChar(q, ',');
12044 }
12045 }
12046 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
12047 appendPQExpBufferStr(q, ");\n");
12048 }
12049
12050 if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12051 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
12052 ARCHIVE_OPTS(.tag = extinfo->dobj.name,
12053 .description = "EXTENSION",
12054 .section = SECTION_PRE_DATA,
12055 .createStmt = q->data,
12056 .dropStmt = delq->data));
12057
12058 /* Dump Extension Comments */
12059 if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12060 dumpComment(fout, "EXTENSION", qextname,
12061 NULL, "",
12062 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
12063
12064 free(qextname);
12065
12068}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_EXTENSION, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, fb(), findObjectByDumpId(), fmtId(), free, i, pg_strdup(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpForeignDataWrapper()

static void dumpForeignDataWrapper ( Archive fout,
const FdwInfo fdwinfo 
)
static

Definition at line 16070 of file pg_dump.c.

16071{
16072 DumpOptions *dopt = fout->dopt;
16073 PQExpBuffer q;
16075 char *qfdwname;
16076
16077 /* Do nothing if not dumping schema */
16078 if (!dopt->dumpSchema)
16079 return;
16080
16081 q = createPQExpBuffer();
16083
16084 qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
16085
16086 appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
16087 qfdwname);
16088
16089 if (strcmp(fdwinfo->fdwhandler, "-") != 0)
16090 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
16091
16092 if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
16093 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
16094
16095 if (strlen(fdwinfo->fdwoptions) > 0)
16096 appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
16097
16098 appendPQExpBufferStr(q, ";\n");
16099
16100 appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
16101 qfdwname);
16102
16103 if (dopt->binary_upgrade)
16105 "FOREIGN DATA WRAPPER", qfdwname,
16106 NULL);
16107
16108 if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16109 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
16110 ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
16111 .owner = fdwinfo->rolname,
16112 .description = "FOREIGN DATA WRAPPER",
16113 .section = SECTION_PRE_DATA,
16114 .createStmt = q->data,
16115 .dropStmt = delq->data));
16116
16117 /* Dump Foreign Data Wrapper Comments */
16118 if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16119 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
16120 NULL, fdwinfo->rolname,
16121 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
16122
16123 /* Handle the ACL */
16124 if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
16125 dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
16126 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
16127 NULL, fdwinfo->rolname, &fdwinfo->dacl);
16128
16129 free(qfdwname);
16130
16133}

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

Referenced by dumpDumpableObject().

◆ dumpForeignServer()

static void dumpForeignServer ( Archive fout,
const ForeignServerInfo srvinfo 
)
static

Definition at line 16140 of file pg_dump.c.

16141{
16142 DumpOptions *dopt = fout->dopt;
16143 PQExpBuffer q;
16145 PQExpBuffer query;
16146 PGresult *res;
16147 char *qsrvname;
16148 char *fdwname;
16149
16150 /* Do nothing if not dumping schema */
16151 if (!dopt->dumpSchema)
16152 return;
16153
16154 q = createPQExpBuffer();
16156 query = createPQExpBuffer();
16157
16158 qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
16159
16160 /* look up the foreign-data wrapper */
16161 appendPQExpBuffer(query, "SELECT fdwname "
16162 "FROM pg_foreign_data_wrapper w "
16163 "WHERE w.oid = '%u'",
16164 srvinfo->srvfdw);
16165 res = ExecuteSqlQueryForSingleRow(fout, query->data);
16166 fdwname = PQgetvalue(res, 0, 0);
16167
16168 appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
16169 if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
16170 {
16171 appendPQExpBufferStr(q, " TYPE ");
16172 appendStringLiteralAH(q, srvinfo->srvtype, fout);
16173 }
16174 if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
16175 {
16176 appendPQExpBufferStr(q, " VERSION ");
16177 appendStringLiteralAH(q, srvinfo->srvversion, fout);
16178 }
16179
16180 appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
16181 appendPQExpBufferStr(q, fmtId(fdwname));
16182
16183 if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
16184 appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
16185
16186 appendPQExpBufferStr(q, ";\n");
16187
16188 appendPQExpBuffer(delq, "DROP SERVER %s;\n",
16189 qsrvname);
16190
16191 if (dopt->binary_upgrade)
16193 "SERVER", qsrvname, NULL);
16194
16195 if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16196 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
16197 ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
16198 .owner = srvinfo->rolname,
16199 .description = "SERVER",
16200 .section = SECTION_PRE_DATA,
16201 .createStmt = q->data,
16202 .dropStmt = delq->data));
16203
16204 /* Dump Foreign Server Comments */
16205 if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16206 dumpComment(fout, "SERVER", qsrvname,
16207 NULL, srvinfo->rolname,
16208 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
16209
16210 /* Handle the ACL */
16211 if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
16212 dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
16213 "FOREIGN SERVER", qsrvname, NULL, NULL,
16214 NULL, srvinfo->rolname, &srvinfo->dacl);
16215
16216 /* Dump user mappings */
16217 if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
16219 srvinfo->dobj.name, NULL,
16220 srvinfo->rolname,
16221 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
16222
16223 PQclear(res);
16224
16225 free(qsrvname);
16226
16229 destroyPQExpBuffer(query);
16230}

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_USERMAP, dumpACL(), dumpComment(), _dumpOptions::dumpSchema, dumpUserMappings(), ExecuteSqlQueryForSingleRow(), fb(), fmtId(), free, InvalidDumpId, pg_strdup(), PQclear, PQgetvalue, and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpFunc()

static void dumpFunc ( Archive fout,
const FuncInfo finfo 
)
static

Definition at line 13467 of file pg_dump.c.

13468{
13469 DumpOptions *dopt = fout->dopt;
13470 PQExpBuffer query;
13471 PQExpBuffer q;
13474 PGresult *res;
13475 char *funcsig; /* identity signature */
13476 char *funcfullsig = NULL; /* full signature */
13477 char *funcsig_tag;
13478 char *qual_funcsig;
13479 char *proretset;
13480 char *prosrc;
13481 char *probin;
13482 char *prosqlbody;
13483 char *funcargs;
13484 char *funciargs;
13485 char *funcresult;
13486 char *protrftypes;
13487 char *prokind;
13488 char *provolatile;
13489 char *proisstrict;
13490 char *prosecdef;
13491 char *proleakproof;
13492 char *proconfig;
13493 char *procost;
13494 char *prorows;
13495 char *prosupport;
13496 char *proparallel;
13497 char *lanname;
13498 char **configitems = NULL;
13499 int nconfigitems = 0;
13500 const char *keyword;
13501
13502 /* Do nothing if not dumping schema */
13503 if (!dopt->dumpSchema)
13504 return;
13505
13506 query = createPQExpBuffer();
13507 q = createPQExpBuffer();
13510
13511 if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
13512 {
13513 /* Set up query for function-specific details */
13515 "PREPARE dumpFunc(pg_catalog.oid) AS\n");
13516
13518 "SELECT\n"
13519 "proretset,\n"
13520 "prosrc,\n"
13521 "probin,\n"
13522 "provolatile,\n"
13523 "proisstrict,\n"
13524 "prosecdef,\n"
13525 "lanname,\n"
13526 "proconfig,\n"
13527 "procost,\n"
13528 "prorows,\n"
13529 "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
13530 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
13531 "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
13532 "proleakproof,\n");
13533
13534 if (fout->remoteVersion >= 90500)
13536 "array_to_string(protrftypes, ' ') AS protrftypes,\n");
13537 else
13539 "NULL AS protrftypes,\n");
13540
13541 if (fout->remoteVersion >= 90600)
13543 "proparallel,\n");
13544 else
13546 "'u' AS proparallel,\n");
13547
13548 if (fout->remoteVersion >= 110000)
13550 "prokind,\n");
13551 else
13553 "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
13554
13555 if (fout->remoteVersion >= 120000)
13557 "prosupport,\n");
13558 else
13560 "'-' AS prosupport,\n");
13561
13562 if (fout->remoteVersion >= 140000)
13564 "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
13565 else
13567 "NULL AS prosqlbody\n");
13568
13570 "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
13571 "WHERE p.oid = $1 "
13572 "AND l.oid = p.prolang");
13573
13574 ExecuteSqlStatement(fout, query->data);
13575
13576 fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
13577 }
13578
13579 printfPQExpBuffer(query,
13580 "EXECUTE dumpFunc('%u')",
13581 finfo->dobj.catId.oid);
13582
13583 res = ExecuteSqlQueryForSingleRow(fout, query->data);
13584
13585 proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
13586 if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
13587 {
13588 prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
13589 probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
13590 prosqlbody = NULL;
13591 }
13592 else
13593 {
13594 prosrc = NULL;
13595 probin = NULL;
13596 prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
13597 }
13598 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13599 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13600 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
13601 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
13602 prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
13603 provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
13604 proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
13605 prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
13606 proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
13607 proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
13608 procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
13609 prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
13610 prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
13611 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13612 lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
13613
13614 /*
13615 * See backend/commands/functioncmds.c for details of how the 'AS' clause
13616 * is used.
13617 */
13618 if (prosqlbody)
13619 {
13621 }
13622 else if (probin[0] != '\0')
13623 {
13626 if (prosrc[0] != '\0')
13627 {
13629
13630 /*
13631 * where we have bin, use dollar quoting if allowed and src
13632 * contains quote or backslash; else use regular quoting.
13633 */
13634 if (dopt->disable_dollar_quoting ||
13635 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
13637 else
13639 }
13640 }
13641 else
13642 {
13644 /* with no bin, dollar quote src unconditionally if allowed */
13645 if (dopt->disable_dollar_quoting)
13647 else
13649 }
13650
13651 if (*proconfig)
13652 {
13654 pg_fatal("could not parse %s array", "proconfig");
13655 }
13656 else
13657 {
13658 configitems = NULL;
13659 nconfigitems = 0;
13660 }
13661
13664
13666
13667 qual_funcsig = psprintf("%s.%s",
13668 fmtId(finfo->dobj.namespace->dobj.name),
13669 funcsig);
13670
13671 if (prokind[0] == PROKIND_PROCEDURE)
13672 keyword = "PROCEDURE";
13673 else
13674 keyword = "FUNCTION"; /* works for window functions too */
13675
13676 appendPQExpBuffer(delqry, "DROP %s %s;\n",
13677 keyword, qual_funcsig);
13678
13679 appendPQExpBuffer(q, "CREATE %s %s.%s",
13680 keyword,
13681 fmtId(finfo->dobj.namespace->dobj.name),
13683 funcsig);
13684
13685 if (prokind[0] == PROKIND_PROCEDURE)
13686 /* no result type to output */ ;
13687 else if (funcresult)
13688 appendPQExpBuffer(q, " RETURNS %s", funcresult);
13689 else
13690 appendPQExpBuffer(q, " RETURNS %s%s",
13691 (proretset[0] == 't') ? "SETOF " : "",
13692 getFormattedTypeName(fout, finfo->prorettype,
13693 zeroIsError));
13694
13695 appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
13696
13697 if (*protrftypes)
13698 {
13699 Oid *typeids = pg_malloc(FUNC_MAX_ARGS * sizeof(Oid));
13700 int i;
13701
13702 appendPQExpBufferStr(q, " TRANSFORM ");
13704 for (i = 0; typeids[i]; i++)
13705 {
13706 if (i != 0)
13707 appendPQExpBufferStr(q, ", ");
13708 appendPQExpBuffer(q, "FOR TYPE %s",
13710 }
13711
13712 free(typeids);
13713 }
13714
13715 if (prokind[0] == PROKIND_WINDOW)
13716 appendPQExpBufferStr(q, " WINDOW");
13717
13719 {
13721 appendPQExpBufferStr(q, " IMMUTABLE");
13722 else if (provolatile[0] == PROVOLATILE_STABLE)
13723 appendPQExpBufferStr(q, " STABLE");
13724 else if (provolatile[0] != PROVOLATILE_VOLATILE)
13725 pg_fatal("unrecognized provolatile value for function \"%s\"",
13726 finfo->dobj.name);
13727 }
13728
13729 if (proisstrict[0] == 't')
13730 appendPQExpBufferStr(q, " STRICT");
13731
13732 if (prosecdef[0] == 't')
13733 appendPQExpBufferStr(q, " SECURITY DEFINER");
13734
13735 if (proleakproof[0] == 't')
13736 appendPQExpBufferStr(q, " LEAKPROOF");
13737
13738 /*
13739 * COST and ROWS are emitted only if present and not default, so as not to
13740 * break backwards-compatibility of the dump without need. Keep this code
13741 * in sync with the defaults in functioncmds.c.
13742 */
13743 if (strcmp(procost, "0") != 0)
13744 {
13745 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
13746 {
13747 /* default cost is 1 */
13748 if (strcmp(procost, "1") != 0)
13749 appendPQExpBuffer(q, " COST %s", procost);
13750 }
13751 else
13752 {
13753 /* default cost is 100 */
13754 if (strcmp(procost, "100") != 0)
13755 appendPQExpBuffer(q, " COST %s", procost);
13756 }
13757 }
13758 if (proretset[0] == 't' &&
13759 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
13760 appendPQExpBuffer(q, " ROWS %s", prorows);
13761
13762 if (strcmp(prosupport, "-") != 0)
13763 {
13764 /* We rely on regprocout to provide quoting and qualification */
13765 appendPQExpBuffer(q, " SUPPORT %s", prosupport);
13766 }
13767
13769 {
13770 if (proparallel[0] == PROPARALLEL_SAFE)
13771 appendPQExpBufferStr(q, " PARALLEL SAFE");
13772 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
13773 appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
13774 else if (proparallel[0] != PROPARALLEL_UNSAFE)
13775 pg_fatal("unrecognized proparallel value for function \"%s\"",
13776 finfo->dobj.name);
13777 }
13778
13779 for (int i = 0; i < nconfigitems; i++)
13780 {
13781 /* we feel free to scribble on configitems[] here */
13782 char *configitem = configitems[i];
13783 char *pos;
13784
13785 pos = strchr(configitem, '=');
13786 if (pos == NULL)
13787 continue;
13788 *pos++ = '\0';
13789 appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
13790
13791 /*
13792 * Variables that are marked GUC_LIST_QUOTE were already fully quoted
13793 * by flatten_set_variable_args() before they were put into the
13794 * proconfig array. However, because the quoting rules used there
13795 * aren't exactly like SQL's, we have to break the list value apart
13796 * and then quote the elements as string literals. (The elements may
13797 * be double-quoted as-is, but we can't just feed them to the SQL
13798 * parser; it would do the wrong thing with elements that are
13799 * zero-length or longer than NAMEDATALEN.) Also, we need a special
13800 * case for empty lists.
13801 *
13802 * Variables that are not so marked should just be emitted as simple
13803 * string literals. If the variable is not known to
13804 * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
13805 * to use GUC_LIST_QUOTE for extension variables.
13806 */
13808 {
13809 char **namelist;
13810 char **nameptr;
13811
13812 /* Parse string into list of identifiers */
13813 /* this shouldn't fail really */
13814 if (SplitGUCList(pos, ',', &namelist))
13815 {
13816 /* Special case: represent an empty list as NULL */
13817 if (*namelist == NULL)
13818 appendPQExpBufferStr(q, "NULL");
13819 for (nameptr = namelist; *nameptr; nameptr++)
13820 {
13821 if (nameptr != namelist)
13822 appendPQExpBufferStr(q, ", ");
13824 }
13825 }
13827 }
13828 else
13829 appendStringLiteralAH(q, pos, fout);
13830 }
13831
13832 appendPQExpBuffer(q, "\n %s;\n", asPart->data);
13833
13835 "pg_catalog.pg_proc", keyword,
13836 qual_funcsig);
13837
13838 if (dopt->binary_upgrade)
13840 keyword, funcsig,
13841 finfo->dobj.namespace->dobj.name);
13842
13843 if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13844 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
13846 .namespace = finfo->dobj.namespace->dobj.name,
13847 .owner = finfo->rolname,
13848 .description = keyword,
13849 .section = finfo->postponed_def ?
13851 .createStmt = q->data,
13852 .dropStmt = delqry->data));
13853
13854 /* Dump Function Comments and Security Labels */
13855 if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13856 dumpComment(fout, keyword, funcsig,
13857 finfo->dobj.namespace->dobj.name, finfo->rolname,
13858 finfo->dobj.catId, 0, finfo->dobj.dumpId);
13859
13860 if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
13861 dumpSecLabel(fout, keyword, funcsig,
13862 finfo->dobj.namespace->dobj.name, finfo->rolname,
13863 finfo->dobj.catId, 0, finfo->dobj.dumpId);
13864
13865 if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
13866 dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
13867 funcsig, NULL,
13868 finfo->dobj.namespace->dobj.name,
13869 NULL, finfo->rolname, &finfo->dacl);
13870
13871 PQclear(res);
13872
13873 destroyPQExpBuffer(query);
13877 free(funcsig);
13882}

References append_depends_on_extension(), appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, appendStringLiteralDQ(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), _dumpableObject::catId, createPQExpBuffer(), _funcInfo::dacl, PQExpBufferData::data, destroyPQExpBuffer(), _dumpOptions::disable_dollar_quoting, _funcInfo::dobj, _dumpableObject::dump, DUMP_COMPONENT_ACL, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpACL(), dumpComment(), _dumpableObject::dumpId, _dumpOptions::dumpSchema, dumpSecLabel(), ExecuteSqlQueryForSingleRow(), ExecuteSqlStatement(), fb(), fmtId(), format_function_arguments(), format_function_signature(), free, FUNC_MAX_ARGS, getFormattedTypeName(), i, InvalidDumpId, _dumpableObject::name, CatalogId::oid, parseOidArray(), parsePGArray(), pg_fatal, pg_free(), pg_malloc(), _funcInfo::postponed_def, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PREPQUERY_DUMPFUNC, printfPQExpBuffer(), _funcInfo::prorettype, psprintf(), _funcInfo::rolname, SECTION_POST_DATA, SECTION_PRE_DATA, SplitGUCList(), variable_is_guc_list_quote(), zeroAsNone, and zeroIsError.

Referenced by dumpDumpableObject().

◆ dumpIndex()

static void dumpIndex ( Archive fout,
const IndxInfo indxinfo 
)
static

Definition at line 18283 of file pg_dump.c.

18284{
18285 DumpOptions *dopt = fout->dopt;
18286 TableInfo *tbinfo = indxinfo->indextable;
18287 bool is_constraint = (indxinfo->indexconstraint != 0);
18288 PQExpBuffer q;
18290 char *qindxname;
18291 char *qqindxname;
18292
18293 /* Do nothing if not dumping schema */
18294 if (!dopt->dumpSchema)
18295 return;
18296
18297 q = createPQExpBuffer();
18299
18300 qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
18302
18303 /*
18304 * If there's an associated constraint, don't dump the index per se, but
18305 * do dump any comment for it. (This is safe because dependency ordering
18306 * will have ensured the constraint is emitted first.) Note that the
18307 * emitted comment has to be shown as depending on the constraint, not the
18308 * index, in such cases.
18309 */
18310 if (!is_constraint)
18311 {
18312 char *indstatcols = indxinfo->indstatcols;
18313 char *indstatvals = indxinfo->indstatvals;
18314 char **indstatcolsarray = NULL;
18315 char **indstatvalsarray = NULL;
18316 int nstatcols = 0;
18317 int nstatvals = 0;
18318
18319 if (dopt->binary_upgrade)
18321 indxinfo->dobj.catId.oid);
18322
18323 /* Plain secondary index */
18324 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
18325
18326 /*
18327 * Append ALTER TABLE commands as needed to set properties that we
18328 * only have ALTER TABLE syntax for. Keep this in sync with the
18329 * similar code in dumpConstraint!
18330 */
18331
18332 /* If the index is clustered, we need to record that. */
18333 if (indxinfo->indisclustered)
18334 {
18335 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
18337 /* index name is not qualified in this syntax */
18338 appendPQExpBuffer(q, " ON %s;\n",
18339 qindxname);
18340 }
18341
18342 /*
18343 * If the index has any statistics on some of its columns, generate
18344 * the associated ALTER INDEX queries.
18345 */
18346 if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
18347 {
18348 int j;
18349
18350 if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
18351 pg_fatal("could not parse index statistic columns");
18352 if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
18353 pg_fatal("could not parse index statistic values");
18354 if (nstatcols != nstatvals)
18355 pg_fatal("mismatched number of columns and values for index statistics");
18356
18357 for (j = 0; j < nstatcols; j++)
18358 {
18359 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
18360
18361 /*
18362 * Note that this is a column number, so no quotes should be
18363 * used.
18364 */
18365 appendPQExpBuffer(q, "ALTER COLUMN %s ",
18367 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
18369 }
18370 }
18371
18372 /* Indexes can depend on extensions */
18374 "pg_catalog.pg_class",
18375 "INDEX", qqindxname);
18376
18377 /* If the index defines identity, we need to record that. */
18378 if (indxinfo->indisreplident)
18379 {
18380 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
18382 /* index name is not qualified in this syntax */
18383 appendPQExpBuffer(q, " INDEX %s;\n",
18384 qindxname);
18385 }
18386
18387 /*
18388 * If this index is a member of a partitioned index, the backend will
18389 * not allow us to drop it separately, so don't try. It will go away
18390 * automatically when we drop either the index's table or the
18391 * partitioned index. (If, in a selective restore with --clean, we
18392 * drop neither of those, then this index will not be dropped either.
18393 * But that's fine, and even if you think it's not, the backend won't
18394 * let us do differently.)
18395 */
18396 if (indxinfo->parentidx == 0)
18397 appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
18398
18399 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18400 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
18401 ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
18402 .namespace = tbinfo->dobj.namespace->dobj.name,
18403 .tablespace = indxinfo->tablespace,
18404 .owner = tbinfo->rolname,
18405 .description = "INDEX",
18406 .section = SECTION_POST_DATA,
18407 .createStmt = q->data,
18408 .dropStmt = delq->data));
18409
18412 }
18413
18414 /* Dump Index Comments */
18415 if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18416 dumpComment(fout, "INDEX", qindxname,
18417 tbinfo->dobj.namespace->dobj.name,
18418 tbinfo->rolname,
18419 indxinfo->dobj.catId, 0,
18420 is_constraint ? indxinfo->indexconstraint :
18421 indxinfo->dobj.dumpId);
18422
18425 free(qindxname);
18427}

References append_depends_on_extension(), appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_set_pg_class_oids(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, fb(), fmtId(), fmtQualifiedDumpable, free, j, parsePGArray(), pg_fatal, pg_strdup(), and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ dumpIndexAttach()

static void dumpIndexAttach ( Archive fout,
const IndexAttachInfo attachinfo 
)
static

Definition at line 18434 of file pg_dump.c.

18435{
18436 /* Do nothing if not dumping schema */
18437 if (!fout->dopt->dumpSchema)
18438 return;
18439
18440 if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
18441 {
18443
18444 appendPQExpBuffer(q, "ALTER INDEX %s ",
18445 fmtQualifiedDumpable(attachinfo->parentIdx));
18446 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
18447 fmtQualifiedDumpable(attachinfo->partitionIdx));
18448
18449 /*
18450 * There is no need for a dropStmt since the drop is done implicitly
18451 * when we drop either the index's table or the partitioned index.
18452 * Moreover, since there's no ALTER INDEX DETACH PARTITION command,
18453 * there's no way to do it anyway. (If you think to change this,
18454 * consider also what to do with --if-exists.)
18455 *
18456 * Although this object doesn't really have ownership as such, set the
18457 * owner field anyway to ensure that the command is run by the correct
18458 * role at restore time.
18459 */
18460 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
18461 ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
18462 .namespace = attachinfo->dobj.namespace->dobj.name,
18463 .owner = attachinfo->parentIdx->indextable->rolname,
18464 .description = "INDEX ATTACH",
18465 .section = SECTION_POST_DATA,
18466 .createStmt = q->data));
18467
18469 }
18470}

References appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_DEFINITION, fb(), fmtQualifiedDumpable, and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ dumpLO()

static void dumpLO ( Archive fout,
const LoInfo loinfo 
)
static

Definition at line 4125 of file pg_dump.c.

4126{
4128
4129 /*
4130 * The "definition" is just a newline-separated list of OIDs. We need to
4131 * put something into the dropStmt too, but it can just be a comment.
4132 */
4133 for (int i = 0; i < loinfo->numlos; i++)
4134 appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
4135
4136 if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4137 ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
4138 ARCHIVE_OPTS(.tag = loinfo->dobj.name,
4139 .owner = loinfo->rolname,
4140 .description = "BLOB METADATA",
4141 .section = SECTION_DATA,
4142 .createStmt = cquery->data,
4143 .dropStmt = "-- dummy"));
4144
4145 /*
4146 * Dump per-blob comments and seclabels if any. We assume these are rare
4147 * enough that it's okay to generate retail TOC entries for them.
4148 */
4149 if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
4151 {
4152 for (int i = 0; i < loinfo->numlos; i++)
4153 {
4154 CatalogId catId;
4155 char namebuf[32];
4156
4157 /* Build identifying info for this blob */
4158 catId.tableoid = loinfo->dobj.catId.tableoid;
4159 catId.oid = loinfo->looids[i];
4160 snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
4161
4162 if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4163 dumpComment(fout, "LARGE OBJECT", namebuf,
4164 NULL, loinfo->rolname,
4165 catId, 0, loinfo->dobj.dumpId);
4166
4167 if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4168 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
4169 NULL, loinfo->rolname,
4170 catId, 0, loinfo->dobj.dumpId);
4171 }
4172 }
4173
4174 /*
4175 * Dump the ACLs if any (remember that all blobs in the group will have
4176 * the same ACL). If there's just one blob, dump a simple ACL entry; if
4177 * there's more, make a "LARGE OBJECTS" entry that really contains only
4178 * the ACL for the first blob. _printTocEntry() will be cued by the tag
4179 * string to emit a mutated version for each blob.
4180 */
4181 if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
4182 {
4183 char namebuf[32];
4184
4185 /* Build identifying info for the first blob */
4186 snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
4187
4188 if (loinfo->numlos > 1)
4189 {
4190 char tagbuf[64];
4191
4192 snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
4193 loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
4194
4195 dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
4196 "LARGE OBJECT", namebuf, NULL, NULL,
4197 tagbuf, loinfo->rolname, &loinfo->dacl);
4198 }
4199 else
4200 {
4201 dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
4202 "LARGE OBJECT", namebuf, NULL, NULL,
4203 NULL, loinfo->rolname, &loinfo->dacl);
4204 }
4205 }
4206
4208}

References appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), createPQExpBuffer(), destroyPQExpBuffer(), DUMP_COMPONENT_ACL, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpACL(), dumpComment(), dumpSecLabel(), fb(), i, InvalidDumpId, CatalogId::oid, SECTION_DATA, snprintf, and CatalogId::tableoid.

Referenced by dumpDumpableObject().

◆ dumpLOs()

static int dumpLOs ( Archive fout,
const void arg 
)
static

Definition at line 4215 of file pg_dump.c.

4216{
4217 const LoInfo *loinfo = (const LoInfo *) arg;
4219 char buf[LOBBUFSIZE];
4220
4221 pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
4222
4223 for (int i = 0; i < loinfo->numlos; i++)
4224 {
4225 Oid loOid = loinfo->looids[i];
4226 int loFd;
4227 int cnt;
4228
4229 /* Open the LO */
4230 loFd = lo_open(conn, loOid, INV_READ);
4231 if (loFd == -1)
4232 pg_fatal("could not open large object %u: %s",
4234
4235 StartLO(fout, loOid);
4236
4237 /* Now read it in chunks, sending data to archive */
4238 do
4239 {
4240 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
4241 if (cnt < 0)
4242 pg_fatal("error reading large object %u: %s",
4244
4245 WriteData(fout, buf, cnt);
4246 } while (cnt > 0);
4247
4248 lo_close(conn, loFd);
4249
4250 EndLO(fout, loOid);
4251 }
4252
4253 return 1;
4254}

References arg, buf, conn, EndLO(), fb(), GetConnection(), i, INV_READ, lo_close(), lo_open(), lo_read(), LOBBUFSIZE, pg_fatal, pg_log_info, PQerrorMessage(), StartLO(), and WriteData().

Referenced by dumpDumpableObject().

◆ dumpNamespace()

static void dumpNamespace ( Archive fout,
const NamespaceInfo nspinfo 
)
static

Definition at line 11875 of file pg_dump.c.

11876{
11877 DumpOptions *dopt = fout->dopt;
11878 PQExpBuffer q;
11880 char *qnspname;
11881
11882 /* Do nothing if not dumping schema */
11883 if (!dopt->dumpSchema)
11884 return;
11885
11886 q = createPQExpBuffer();
11888
11889 qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
11890
11891 if (nspinfo->create)
11892 {
11893 appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
11894 appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
11895 }
11896 else
11897 {
11898 /* see selectDumpableNamespace() */
11900 "-- *not* dropping schema, since initdb creates it\n");
11902 "-- *not* creating schema, since initdb creates it\n");
11903 }
11904
11905 if (dopt->binary_upgrade)
11907 "SCHEMA", qnspname, NULL);
11908
11909 if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11910 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
11911 ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
11912 .owner = nspinfo->rolname,
11913 .description = "SCHEMA",
11914 .section = SECTION_PRE_DATA,
11915 .createStmt = q->data,
11916 .dropStmt = delq->data));
11917
11918 /* Dump Schema Comments and Security Labels */
11919 if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11920 {
11921 const char *initdb_comment = NULL;
11922
11923 if (!nspinfo->create && strcmp(qnspname, "public") == 0)
11924 initdb_comment = "standard public schema";
11926 NULL, nspinfo->rolname,
11927 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
11929 }
11930
11931 if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11932 dumpSecLabel(fout, "SCHEMA", qnspname,
11933 NULL, nspinfo->rolname,
11934 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
11935
11936 if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
11937 dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
11938 qnspname, NULL, NULL,
11939 NULL, nspinfo->rolname, &nspinfo->dacl);
11940
11941 free(qnspname);
11942
11945}

References appendPQExpBuffer(), appendPQExpBufferStr(), 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(), dumpCommentExtended(), _dumpOptions::dumpSchema, dumpSecLabel(), fb(), fmtId(), free, InvalidDumpId, pg_strdup(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpOpclass()

static void dumpOpclass ( Archive fout,
const OpclassInfo opcinfo 
)
static

Definition at line 14503 of file pg_dump.c.

14504{
14505 DumpOptions *dopt = fout->dopt;
14506 PQExpBuffer query;
14507 PQExpBuffer q;
14510 PGresult *res;
14511 int ntups;
14512 int i_opcintype;
14513 int i_opckeytype;
14514 int i_opcdefault;
14515 int i_opcfamily;
14516 int i_opcfamilyname;
14517 int i_opcfamilynsp;
14518 int i_amname;
14519 int i_amopstrategy;
14520 int i_amopopr;
14521 int i_sortfamily;
14522 int i_sortfamilynsp;
14523 int i_amprocnum;
14524 int i_amproc;
14525 int i_amproclefttype;
14527 char *opcintype;
14528 char *opckeytype;
14529 char *opcdefault;
14530 char *opcfamily;
14531 char *opcfamilyname;
14532 char *opcfamilynsp;
14533 char *amname;
14534 char *amopstrategy;
14535 char *amopopr;
14536 char *sortfamily;
14537 char *sortfamilynsp;
14538 char *amprocnum;
14539 char *amproc;
14540 char *amproclefttype;
14541 char *amprocrighttype;
14542 bool needComma;
14543 int i;
14544
14545 /* Do nothing if not dumping schema */
14546 if (!dopt->dumpSchema)
14547 return;
14548
14549 query = createPQExpBuffer();
14550 q = createPQExpBuffer();
14553
14554 /* Get additional fields from the pg_opclass row */
14555 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
14556 "opckeytype::pg_catalog.regtype, "
14557 "opcdefault, opcfamily, "
14558 "opfname AS opcfamilyname, "
14559 "nspname AS opcfamilynsp, "
14560 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
14561 "FROM pg_catalog.pg_opclass c "
14562 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
14563 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14564 "WHERE c.oid = '%u'::pg_catalog.oid",
14565 opcinfo->dobj.catId.oid);
14566
14567 res = ExecuteSqlQueryForSingleRow(fout, query->data);
14568
14569 i_opcintype = PQfnumber(res, "opcintype");
14570 i_opckeytype = PQfnumber(res, "opckeytype");
14571 i_opcdefault = PQfnumber(res, "opcdefault");
14572 i_opcfamily = PQfnumber(res, "opcfamily");
14573 i_opcfamilyname = PQfnumber(res, "opcfamilyname");
14574 i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
14575 i_amname = PQfnumber(res, "amname");
14576
14577 /* opcintype may still be needed after we PQclear res */
14578 opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
14581 /* opcfamily will still be needed after we PQclear res */
14582 opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
14585 /* amname will still be needed after we PQclear res */
14586 amname = pg_strdup(PQgetvalue(res, 0, i_amname));
14587
14588 appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
14590 appendPQExpBuffer(delq, " USING %s;\n",
14591 fmtId(amname));
14592
14593 /* Build the fixed portion of the CREATE command */
14594 appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
14596 if (strcmp(opcdefault, "t") == 0)
14597 appendPQExpBufferStr(q, "DEFAULT ");
14598 appendPQExpBuffer(q, "FOR TYPE %s USING %s",
14599 opcintype,
14600 fmtId(amname));
14601 if (strlen(opcfamilyname) > 0)
14602 {
14603 appendPQExpBufferStr(q, " FAMILY ");
14606 }
14607 appendPQExpBufferStr(q, " AS\n ");
14608
14609 needComma = false;
14610
14611 if (strcmp(opckeytype, "-") != 0)
14612 {
14613 appendPQExpBuffer(q, "STORAGE %s",
14614 opckeytype);
14615 needComma = true;
14616 }
14617
14618 PQclear(res);
14619
14620 /*
14621 * Now fetch and print the OPERATOR entries (pg_amop rows).
14622 *
14623 * Print only those opfamily members that are tied to the opclass by
14624 * pg_depend entries.
14625 */
14626 resetPQExpBuffer(query);
14627 appendPQExpBuffer(query, "SELECT amopstrategy, "
14628 "amopopr::pg_catalog.regoperator, "
14629 "opfname AS sortfamily, "
14630 "nspname AS sortfamilynsp "
14631 "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
14632 "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
14633 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
14634 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14635 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
14636 "AND refobjid = '%u'::pg_catalog.oid "
14637 "AND amopfamily = '%s'::pg_catalog.oid "
14638 "ORDER BY amopstrategy",
14639 opcinfo->dobj.catId.oid,
14640 opcfamily);
14641
14642 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14643
14644 ntups = PQntuples(res);
14645
14646 i_amopstrategy = PQfnumber(res, "amopstrategy");
14647 i_amopopr = PQfnumber(res, "amopopr");
14648 i_sortfamily = PQfnumber(res, "sortfamily");
14649 i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
14650
14651 for (i = 0; i < ntups; i++)
14652 {
14654 amopopr = PQgetvalue(res, i, i_amopopr);
14655 sortfamily = PQgetvalue(res, i, i_sortfamily);
14657
14658 if (needComma)
14659 appendPQExpBufferStr(q, " ,\n ");
14660
14661 appendPQExpBuffer(q, "OPERATOR %s %s",
14663
14664 if (strlen(sortfamily) > 0)
14665 {
14666 appendPQExpBufferStr(q, " FOR ORDER BY ");
14668 appendPQExpBufferStr(q, fmtId(sortfamily));
14669 }
14670
14671 needComma = true;
14672 }
14673
14674 PQclear(res);
14675
14676 /*
14677 * Now fetch and print the FUNCTION entries (pg_amproc rows).
14678 *
14679 * Print only those opfamily members that are tied to the opclass by
14680 * pg_depend entries.
14681 *
14682 * We print the amproclefttype/amprocrighttype even though in most cases
14683 * the backend could deduce the right values, because of the corner case
14684 * of a btree sort support function for a cross-type comparison.
14685 */
14686 resetPQExpBuffer(query);
14687
14688 appendPQExpBuffer(query, "SELECT amprocnum, "
14689 "amproc::pg_catalog.regprocedure, "
14690 "amproclefttype::pg_catalog.regtype, "
14691 "amprocrighttype::pg_catalog.regtype "
14692 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
14693 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
14694 "AND refobjid = '%u'::pg_catalog.oid "
14695 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
14696 "AND objid = ap.oid "
14697 "ORDER BY amprocnum",
14698 opcinfo->dobj.catId.oid);
14699
14700 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14701
14702 ntups = PQntuples(res);
14703
14704 i_amprocnum = PQfnumber(res, "amprocnum");
14705 i_amproc = PQfnumber(res, "amproc");
14706 i_amproclefttype = PQfnumber(res, "amproclefttype");
14707 i_amprocrighttype = PQfnumber(res, "amprocrighttype");
14708
14709 for (i = 0; i < ntups; i++)
14710 {
14712 amproc = PQgetvalue(res, i, i_amproc);
14715
14716 if (needComma)
14717 appendPQExpBufferStr(q, " ,\n ");
14718
14719 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
14720
14723
14724 appendPQExpBuffer(q, " %s", amproc);
14725
14726 needComma = true;
14727 }
14728
14729 PQclear(res);
14730
14731 /*
14732 * If needComma is still false it means we haven't added anything after
14733 * the AS keyword. To avoid printing broken SQL, append a dummy STORAGE
14734 * clause with the same datatype. This isn't sanctioned by the
14735 * documentation, but actually DefineOpClass will treat it as a no-op.
14736 */
14737 if (!needComma)
14738 appendPQExpBuffer(q, "STORAGE %s", opcintype);
14739
14740 appendPQExpBufferStr(q, ";\n");
14741
14743 appendPQExpBuffer(nameusing, " USING %s",
14744 fmtId(amname));
14745
14746 if (dopt->binary_upgrade)
14748 "OPERATOR CLASS", nameusing->data,
14749 opcinfo->dobj.namespace->dobj.name);
14750
14751 if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14752 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
14753 ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
14754 .namespace = opcinfo->dobj.namespace->dobj.name,
14755 .owner = opcinfo->rolname,
14756 .description = "OPERATOR CLASS",
14757 .section = SECTION_PRE_DATA,
14758 .createStmt = q->data,
14759 .dropStmt = delq->data));
14760
14761 /* Dump Operator Class Comments */
14762 if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14763 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
14764 opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
14765 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
14766
14767 free(opcintype);
14768 free(opcfamily);
14769 free(amname);
14770 destroyPQExpBuffer(query);
14774}

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, ExecuteSqlQuery(), ExecuteSqlQueryForSingleRow(), fb(), fmtId(), fmtQualifiedDumpable, free, i, pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, resetPQExpBuffer(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpOpfamily()

static void dumpOpfamily ( Archive fout,
const OpfamilyInfo opfinfo 
)
static

Definition at line 14784 of file pg_dump.c.

14785{
14786 DumpOptions *dopt = fout->dopt;
14787 PQExpBuffer query;
14788 PQExpBuffer q;
14791 PGresult *res;
14794 int ntups;
14795 int i_amname;
14796 int i_amopstrategy;
14797 int i_amopopr;
14798 int i_sortfamily;
14799 int i_sortfamilynsp;
14800 int i_amprocnum;
14801 int i_amproc;
14802 int i_amproclefttype;
14804 char *amname;
14805 char *amopstrategy;
14806 char *amopopr;
14807 char *sortfamily;
14808 char *sortfamilynsp;
14809 char *amprocnum;
14810 char *amproc;
14811 char *amproclefttype;
14812 char *amprocrighttype;
14813 bool needComma;
14814 int i;
14815
14816 /* Do nothing if not dumping schema */
14817 if (!dopt->dumpSchema)
14818 return;
14819
14820 query = createPQExpBuffer();
14821 q = createPQExpBuffer();
14824
14825 /*
14826 * Fetch only those opfamily members that are tied directly to the
14827 * opfamily by pg_depend entries.
14828 */
14829 appendPQExpBuffer(query, "SELECT amopstrategy, "
14830 "amopopr::pg_catalog.regoperator, "
14831 "opfname AS sortfamily, "
14832 "nspname AS sortfamilynsp "
14833 "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
14834 "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
14835 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
14836 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14837 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
14838 "AND refobjid = '%u'::pg_catalog.oid "
14839 "AND amopfamily = '%u'::pg_catalog.oid "
14840 "ORDER BY amopstrategy",
14841 opfinfo->dobj.catId.oid,
14842 opfinfo->dobj.catId.oid);
14843
14845
14846 resetPQExpBuffer(query);
14847
14848 appendPQExpBuffer(query, "SELECT amprocnum, "
14849 "amproc::pg_catalog.regprocedure, "
14850 "amproclefttype::pg_catalog.regtype, "
14851 "amprocrighttype::pg_catalog.regtype "
14852 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
14853 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
14854 "AND refobjid = '%u'::pg_catalog.oid "
14855 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
14856 "AND objid = ap.oid "
14857 "ORDER BY amprocnum",
14858 opfinfo->dobj.catId.oid);
14859
14861
14862 /* Get additional fields from the pg_opfamily row */
14863 resetPQExpBuffer(query);
14864
14865 appendPQExpBuffer(query, "SELECT "
14866 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
14867 "FROM pg_catalog.pg_opfamily "
14868 "WHERE oid = '%u'::pg_catalog.oid",
14869 opfinfo->dobj.catId.oid);
14870
14871 res = ExecuteSqlQueryForSingleRow(fout, query->data);
14872
14873 i_amname = PQfnumber(res, "amname");
14874
14875 /* amname will still be needed after we PQclear res */
14876 amname = pg_strdup(PQgetvalue(res, 0, i_amname));
14877
14878 appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
14880 appendPQExpBuffer(delq, " USING %s;\n",
14881 fmtId(amname));
14882
14883 /* Build the fixed portion of the CREATE command */
14884 appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
14886 appendPQExpBuffer(q, " USING %s;\n",
14887 fmtId(amname));
14888
14889 PQclear(res);
14890
14891 /* Do we need an ALTER to add loose members? */
14892 if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
14893 {
14894 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
14896 appendPQExpBuffer(q, " USING %s ADD\n ",
14897 fmtId(amname));
14898
14899 needComma = false;
14900
14901 /*
14902 * Now fetch and print the OPERATOR entries (pg_amop rows).
14903 */
14904 ntups = PQntuples(res_ops);
14905
14906 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
14907 i_amopopr = PQfnumber(res_ops, "amopopr");
14908 i_sortfamily = PQfnumber(res_ops, "sortfamily");
14909 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
14910
14911 for (i = 0; i < ntups; i++)
14912 {
14915 sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
14917
14918 if (needComma)
14919 appendPQExpBufferStr(q, " ,\n ");
14920
14921 appendPQExpBuffer(q, "OPERATOR %s %s",
14923
14924 if (strlen(sortfamily) > 0)
14925 {
14926 appendPQExpBufferStr(q, " FOR ORDER BY ");
14928 appendPQExpBufferStr(q, fmtId(sortfamily));
14929 }
14930
14931 needComma = true;
14932 }
14933
14934 /*
14935 * Now fetch and print the FUNCTION entries (pg_amproc rows).
14936 */
14937 ntups = PQntuples(res_procs);
14938
14939 i_amprocnum = PQfnumber(res_procs, "amprocnum");
14940 i_amproc = PQfnumber(res_procs, "amproc");
14941 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
14942 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
14943
14944 for (i = 0; i < ntups; i++)
14945 {
14950
14951 if (needComma)
14952 appendPQExpBufferStr(q, " ,\n ");
14953
14954 appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
14956 amproc);
14957
14958 needComma = true;
14959 }
14960
14961 appendPQExpBufferStr(q, ";\n");
14962 }
14963
14965 appendPQExpBuffer(nameusing, " USING %s",
14966 fmtId(amname));
14967
14968 if (dopt->binary_upgrade)
14970 "OPERATOR FAMILY", nameusing->data,
14971 opfinfo->dobj.namespace->dobj.name);
14972
14973 if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14974 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
14975 ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
14976 .namespace = opfinfo->dobj.namespace->dobj.name,
14977 .owner = opfinfo->rolname,
14978 .description = "OPERATOR FAMILY",
14979 .section = SECTION_PRE_DATA,
14980 .createStmt = q->data,
14981 .dropStmt = delq->data));
14982
14983 /* Dump Operator Family Comments */
14984 if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14985 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
14986 opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
14987 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
14988
14989 free(amname);
14992 destroyPQExpBuffer(query);
14996}

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, ExecuteSqlQuery(), ExecuteSqlQueryForSingleRow(), fb(), fmtId(), fmtQualifiedDumpable, free, i, pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, resetPQExpBuffer(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpOpr()

static void dumpOpr ( Archive fout,
const OprInfo oprinfo 
)
static

Definition at line 14123 of file pg_dump.c.

14124{
14125 DumpOptions *dopt = fout->dopt;
14126 PQExpBuffer query;
14127 PQExpBuffer q;
14130 PQExpBuffer details;
14131 PGresult *res;
14132 int i_oprkind;
14133 int i_oprcode;
14134 int i_oprleft;
14135 int i_oprright;
14136 int i_oprcom;
14137 int i_oprnegate;
14138 int i_oprrest;
14139 int i_oprjoin;
14140 int i_oprcanmerge;
14141 int i_oprcanhash;
14142 char *oprkind;
14143 char *oprcode;
14144 char *oprleft;
14145 char *oprright;
14146 char *oprcom;
14147 char *oprnegate;
14148 char *oprrest;
14149 char *oprjoin;
14150 char *oprcanmerge;
14151 char *oprcanhash;
14152 char *oprregproc;
14153 char *oprref;
14154
14155 /* Do nothing if not dumping schema */
14156 if (!dopt->dumpSchema)
14157 return;
14158
14159 /*
14160 * some operators are invalid because they were the result of user
14161 * defining operators before commutators exist
14162 */
14163 if (!OidIsValid(oprinfo->oprcode))
14164 return;
14165
14166 query = createPQExpBuffer();
14167 q = createPQExpBuffer();
14170 details = createPQExpBuffer();
14171
14172 if (!fout->is_prepared[PREPQUERY_DUMPOPR])
14173 {
14174 /* Set up query for operator-specific details */
14176 "PREPARE dumpOpr(pg_catalog.oid) AS\n"
14177 "SELECT oprkind, "
14178 "oprcode::pg_catalog.regprocedure, "
14179 "oprleft::pg_catalog.regtype, "
14180 "oprright::pg_catalog.regtype, "
14181 "oprcom, "
14182 "oprnegate, "
14183 "oprrest::pg_catalog.regprocedure, "
14184 "oprjoin::pg_catalog.regprocedure, "
14185 "oprcanmerge, oprcanhash "
14186 "FROM pg_catalog.pg_operator "
14187 "WHERE oid = $1");
14188
14189 ExecuteSqlStatement(fout, query->data);
14190
14191 fout->is_prepared[PREPQUERY_DUMPOPR] = true;
14192 }
14193
14194 printfPQExpBuffer(query,
14195 "EXECUTE dumpOpr('%u')",
14196 oprinfo->dobj.catId.oid);
14197
14198 res = ExecuteSqlQueryForSingleRow(fout, query->data);
14199
14200 i_oprkind = PQfnumber(res, "oprkind");
14201 i_oprcode = PQfnumber(res, "oprcode");
14202 i_oprleft = PQfnumber(res, "oprleft");
14203 i_oprright = PQfnumber(res, "oprright");
14204 i_oprcom = PQfnumber(res, "oprcom");
14205 i_oprnegate = PQfnumber(res, "oprnegate");
14206 i_oprrest = PQfnumber(res, "oprrest");
14207 i_oprjoin = PQfnumber(res, "oprjoin");
14208 i_oprcanmerge = PQfnumber(res, "oprcanmerge");
14209 i_oprcanhash = PQfnumber(res, "oprcanhash");
14210
14211 oprkind = PQgetvalue(res, 0, i_oprkind);
14212 oprcode = PQgetvalue(res, 0, i_oprcode);
14213 oprleft = PQgetvalue(res, 0, i_oprleft);
14214 oprright = PQgetvalue(res, 0, i_oprright);
14215 oprcom = PQgetvalue(res, 0, i_oprcom);
14216 oprnegate = PQgetvalue(res, 0, i_oprnegate);
14217 oprrest = PQgetvalue(res, 0, i_oprrest);
14218 oprjoin = PQgetvalue(res, 0, i_oprjoin);
14221
14222 /* In PG14 upwards postfix operator support does not exist anymore. */
14223 if (strcmp(oprkind, "r") == 0)
14224 pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
14225 oprcode);
14226
14228 if (oprregproc)
14229 {
14230 appendPQExpBuffer(details, " FUNCTION = %s", oprregproc);
14232 }
14233
14234 appendPQExpBuffer(oprid, "%s (",
14235 oprinfo->dobj.name);
14236
14237 /*
14238 * right unary means there's a left arg and left unary means there's a
14239 * right arg. (Although the "r" case is dead code for PG14 and later,
14240 * continue to support it in case we're dumping from an old server.)
14241 */
14242 if (strcmp(oprkind, "r") == 0 ||
14243 strcmp(oprkind, "b") == 0)
14244 {
14245 appendPQExpBuffer(details, ",\n LEFTARG = %s", oprleft);
14246 appendPQExpBufferStr(oprid, oprleft);
14247 }
14248 else
14249 appendPQExpBufferStr(oprid, "NONE");
14250
14251 if (strcmp(oprkind, "l") == 0 ||
14252 strcmp(oprkind, "b") == 0)
14253 {
14254 appendPQExpBuffer(details, ",\n RIGHTARG = %s", oprright);
14255 appendPQExpBuffer(oprid, ", %s)", oprright);
14256 }
14257 else
14258 appendPQExpBufferStr(oprid, ", NONE)");
14259
14261 if (oprref)
14262 {
14263 appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
14264 free(oprref);
14265 }
14266
14268 if (oprref)
14269 {
14270 appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
14271 free(oprref);
14272 }
14273
14274 if (strcmp(oprcanmerge, "t") == 0)
14275 appendPQExpBufferStr(details, ",\n MERGES");
14276
14277 if (strcmp(oprcanhash, "t") == 0)
14278 appendPQExpBufferStr(details, ",\n HASHES");
14279
14281 if (oprregproc)
14282 {
14283 appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
14285 }
14286
14288 if (oprregproc)
14289 {
14290 appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
14292 }
14293
14294 appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
14295 fmtId(oprinfo->dobj.namespace->dobj.name),
14296 oprid->data);
14297
14298 appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
14299 fmtId(oprinfo->dobj.namespace->dobj.name),
14300 oprinfo->dobj.name, details->data);
14301
14302 if (dopt->binary_upgrade)
14304 "OPERATOR", oprid->data,
14305 oprinfo->dobj.namespace->dobj.name);
14306
14307 if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14308 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
14309 ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
14310 .namespace = oprinfo->dobj.namespace->dobj.name,
14311 .owner = oprinfo->rolname,
14312 .description = "OPERATOR",
14313 .section = SECTION_PRE_DATA,
14314 .createStmt = q->data,
14315 .dropStmt = delq->data));
14316
14317 /* Dump Operator Comments */
14318 if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14319 dumpComment(fout, "OPERATOR", oprid->data,
14320 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
14321 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
14322
14323 PQclear(res);
14324
14325 destroyPQExpBuffer(query);
14329 destroyPQExpBuffer(details);
14330}

References appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), convertRegProcReference(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, ExecuteSqlQueryForSingleRow(), ExecuteSqlStatement(), fb(), fmtId(), free, getFormattedOperatorName(), OidIsValid, oprid(), pg_log_warning, PQclear, PQfnumber(), PQgetvalue, PREPQUERY_DUMPOPR, printfPQExpBuffer(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpPolicy()

static void dumpPolicy ( Archive fout,
const PolicyInfo polinfo 
)
static

Definition at line 4433 of file pg_dump.c.

4434{
4435 DumpOptions *dopt = fout->dopt;
4436 TableInfo *tbinfo = polinfo->poltable;
4437 PQExpBuffer query;
4440 char *qtabname;
4441 const char *cmd;
4442 char *tag;
4443
4444 /* Do nothing if not dumping schema */
4445 if (!dopt->dumpSchema)
4446 return;
4447
4448 /*
4449 * If polname is NULL, then this record is just indicating that ROW LEVEL
4450 * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
4451 * ROW LEVEL SECURITY.
4452 */
4453 if (polinfo->polname == NULL)
4454 {
4455 query = createPQExpBuffer();
4456
4457 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
4459
4460 /*
4461 * We must emit the ROW SECURITY object's dependency on its table
4462 * explicitly, because it will not match anything in pg_depend (unlike
4463 * the case for other PolicyInfo objects).
4464 */
4465 if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4466 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
4467 ARCHIVE_OPTS(.tag = polinfo->dobj.name,
4468 .namespace = polinfo->dobj.namespace->dobj.name,
4469 .owner = tbinfo->rolname,
4470 .description = "ROW SECURITY",
4471 .section = SECTION_POST_DATA,
4472 .createStmt = query->data,
4473 .deps = &(tbinfo->dobj.dumpId),
4474 .nDeps = 1));
4475
4476 destroyPQExpBuffer(query);
4477 return;
4478 }
4479
4480 if (polinfo->polcmd == '*')
4481 cmd = "";
4482 else if (polinfo->polcmd == 'r')
4483 cmd = " FOR SELECT";
4484 else if (polinfo->polcmd == 'a')
4485 cmd = " FOR INSERT";
4486 else if (polinfo->polcmd == 'w')
4487 cmd = " FOR UPDATE";
4488 else if (polinfo->polcmd == 'd')
4489 cmd = " FOR DELETE";
4490 else
4491 pg_fatal("unexpected policy command type: %c",
4492 polinfo->polcmd);
4493
4494 query = createPQExpBuffer();
4497
4498 qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
4499
4500 appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
4501
4502 appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
4503 !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
4504
4505 if (polinfo->polroles != NULL)
4506 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
4507
4508 if (polinfo->polqual != NULL)
4509 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
4510
4511 if (polinfo->polwithcheck != NULL)
4512 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
4513
4514 appendPQExpBufferStr(query, ";\n");
4515
4516 appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
4518
4519 appendPQExpBuffer(polprefix, "POLICY %s ON",
4520 fmtId(polinfo->polname));
4521
4522 tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
4523
4524 if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4525 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
4526 ARCHIVE_OPTS(.tag = tag,
4527 .namespace = polinfo->dobj.namespace->dobj.name,
4528 .owner = tbinfo->rolname,
4529 .description = "POLICY",
4530 .section = SECTION_POST_DATA,
4531 .createStmt = query->data,
4532 .dropStmt = delqry->data));
4533
4534 if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4536 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
4537 polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
4538
4539 free(tag);
4540 destroyPQExpBuffer(query);
4543 free(qtabname);
4544}

References appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, fb(), fmtId(), fmtQualifiedDumpable, free, pg_fatal, pg_strdup(), psprintf(), and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ dumpProcLang()

static void dumpProcLang ( Archive fout,
const ProcLangInfo plang 
)
static

Definition at line 13283 of file pg_dump.c.

13284{
13285 DumpOptions *dopt = fout->dopt;
13288 bool useParams;
13289 char *qlanname;
13293
13294 /* Do nothing if not dumping schema */
13295 if (!dopt->dumpSchema)
13296 return;
13297
13298 /*
13299 * Try to find the support function(s). It is not an error if we don't
13300 * find them --- if the functions are in the pg_catalog schema, as is
13301 * standard in 8.1 and up, then we won't have loaded them. (In this case
13302 * we will emit a parameterless CREATE LANGUAGE command, which will
13303 * require PL template knowledge in the backend to reload.)
13304 */
13305
13306 funcInfo = findFuncByOid(plang->lanplcallfoid);
13307 if (funcInfo != NULL && !funcInfo->dobj.dump)
13308 funcInfo = NULL; /* treat not-dumped same as not-found */
13309
13310 if (OidIsValid(plang->laninline))
13311 {
13312 inlineInfo = findFuncByOid(plang->laninline);
13313 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
13314 inlineInfo = NULL;
13315 }
13316
13317 if (OidIsValid(plang->lanvalidator))
13318 {
13319 validatorInfo = findFuncByOid(plang->lanvalidator);
13320 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
13322 }
13323
13324 /*
13325 * If the functions are dumpable then emit a complete CREATE LANGUAGE with
13326 * parameters. Otherwise, we'll write a parameterless command, which will
13327 * be interpreted as CREATE EXTENSION.
13328 */
13329 useParams = (funcInfo != NULL &&
13330 (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
13331 (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
13332
13335
13336 qlanname = pg_strdup(fmtId(plang->dobj.name));
13337
13338 appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
13339 qlanname);
13340
13341 if (useParams)
13342 {
13343 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
13344 plang->lanpltrusted ? "TRUSTED " : "",
13345 qlanname);
13346 appendPQExpBuffer(defqry, " HANDLER %s",
13348 if (OidIsValid(plang->laninline))
13349 appendPQExpBuffer(defqry, " INLINE %s",
13351 if (OidIsValid(plang->lanvalidator))
13352 appendPQExpBuffer(defqry, " VALIDATOR %s",
13354 }
13355 else
13356 {
13357 /*
13358 * If not dumping parameters, then use CREATE OR REPLACE so that the
13359 * command will not fail if the language is preinstalled in the target
13360 * database.
13361 *
13362 * Modern servers will interpret this as CREATE EXTENSION IF NOT
13363 * EXISTS; perhaps we should emit that instead? But it might just add
13364 * confusion.
13365 */
13366 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
13367 qlanname);
13368 }
13370
13371 if (dopt->binary_upgrade)
13373 "LANGUAGE", qlanname, NULL);
13374
13375 if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
13376 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
13377 ARCHIVE_OPTS(.tag = plang->dobj.name,
13378 .owner = plang->lanowner,
13379 .description = "PROCEDURAL LANGUAGE",
13380 .section = SECTION_PRE_DATA,
13381 .createStmt = defqry->data,
13382 .dropStmt = delqry->data,
13383 ));
13384
13385 /* Dump Proc Lang Comments and Security Labels */
13386 if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
13387 dumpComment(fout, "LANGUAGE", qlanname,
13388 NULL, plang->lanowner,
13389 plang->dobj.catId, 0, plang->dobj.dumpId);
13390
13391 if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
13392 dumpSecLabel(fout, "LANGUAGE", qlanname,
13393 NULL, plang->lanowner,
13394 plang->dobj.catId, 0, plang->dobj.dumpId);
13395
13396 if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
13397 dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
13398 qlanname, NULL, NULL,
13399 NULL, plang->lanowner, &plang->dacl);
13400
13401 free(qlanname);
13402
13405}

References appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), createPQExpBuffer(), destroyPQExpBuffer(), DUMP_COMPONENT_ACL, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpACL(), dumpComment(), _dumpOptions::dumpSchema, dumpSecLabel(), fb(), findFuncByOid(), fmtId(), fmtQualifiedDumpable, free, InvalidDumpId, OidIsValid, pg_strdup(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpPublication()

static void dumpPublication ( Archive fout,
const PublicationInfo pubinfo 
)
static

Definition at line 4667 of file pg_dump.c.

4668{
4669 DumpOptions *dopt = fout->dopt;
4671 PQExpBuffer query;
4672 char *qpubname;
4673 bool first = true;
4674
4675 /* Do nothing if not dumping schema */
4676 if (!dopt->dumpSchema)
4677 return;
4678
4680 query = createPQExpBuffer();
4681
4682 qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
4683
4684 appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
4685 qpubname);
4686
4687 appendPQExpBuffer(query, "CREATE PUBLICATION %s",
4688 qpubname);
4689
4690 if (pubinfo->puballtables && pubinfo->puballsequences)
4691 appendPQExpBufferStr(query, " FOR ALL TABLES, ALL SEQUENCES");
4692 else if (pubinfo->puballtables)
4693 appendPQExpBufferStr(query, " FOR ALL TABLES");
4694 else if (pubinfo->puballsequences)
4695 appendPQExpBufferStr(query, " FOR ALL SEQUENCES");
4696
4697 appendPQExpBufferStr(query, " WITH (publish = '");
4698 if (pubinfo->pubinsert)
4699 {
4700 appendPQExpBufferStr(query, "insert");
4701 first = false;
4702 }
4703
4704 if (pubinfo->pubupdate)
4705 {
4706 if (!first)
4707 appendPQExpBufferStr(query, ", ");
4708
4709 appendPQExpBufferStr(query, "update");
4710 first = false;
4711 }
4712
4713 if (pubinfo->pubdelete)
4714 {
4715 if (!first)
4716 appendPQExpBufferStr(query, ", ");
4717
4718 appendPQExpBufferStr(query, "delete");
4719 first = false;
4720 }
4721
4722 if (pubinfo->pubtruncate)
4723 {
4724 if (!first)
4725 appendPQExpBufferStr(query, ", ");
4726
4727 appendPQExpBufferStr(query, "truncate");
4728 first = false;
4729 }
4730
4731 appendPQExpBufferChar(query, '\'');
4732
4733 if (pubinfo->pubviaroot)
4734 appendPQExpBufferStr(query, ", publish_via_partition_root = true");
4735
4736 if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
4737 appendPQExpBufferStr(query, ", publish_generated_columns = stored");
4738
4739 appendPQExpBufferStr(query, ");\n");
4740
4741 if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4742 ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
4743 ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
4744 .owner = pubinfo->rolname,
4745 .description = "PUBLICATION",
4746 .section = SECTION_POST_DATA,
4747 .createStmt = query->data,
4748 .dropStmt = delq->data));
4749
4750 if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4751 dumpComment(fout, "PUBLICATION", qpubname,
4752 NULL, pubinfo->rolname,
4753 pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4754
4755 if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4756 dumpSecLabel(fout, "PUBLICATION", qpubname,
4757 NULL, pubinfo->rolname,
4758 pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4759
4761 destroyPQExpBuffer(query);
4762 free(qpubname);
4763}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpComment(), _dumpOptions::dumpSchema, dumpSecLabel(), fb(), fmtId(), free, pg_strdup(), and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ dumpPublicationNamespace()

static void dumpPublicationNamespace ( Archive fout,
const PublicationSchemaInfo pubsinfo 
)
static

Definition at line 4977 of file pg_dump.c.

4978{
4979 DumpOptions *dopt = fout->dopt;
4980 NamespaceInfo *schemainfo = pubsinfo->pubschema;
4981 PublicationInfo *pubinfo = pubsinfo->publication;
4982 PQExpBuffer query;
4983 char *tag;
4984
4985 /* Do nothing if not dumping schema */
4986 if (!dopt->dumpSchema)
4987 return;
4988
4989 tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
4990
4991 query = createPQExpBuffer();
4992
4993 appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
4994 appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
4995
4996 /*
4997 * There is no point in creating drop query as the drop is done by schema
4998 * drop.
4999 */
5000 if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5001 ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
5002 ARCHIVE_OPTS(.tag = tag,
5003 .namespace = schemainfo->dobj.name,
5004 .owner = pubinfo->rolname,
5005 .description = "PUBLICATION TABLES IN SCHEMA",
5006 .section = SECTION_POST_DATA,
5007 .createStmt = query->data));
5008
5009 /* These objects can't currently have comments or seclabels */
5010
5011 free(tag);
5012 destroyPQExpBuffer(query);
5013}

References appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_DEFINITION, _dumpOptions::dumpSchema, fb(), fmtId(), free, psprintf(), and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ dumpPublicationTable()

static void dumpPublicationTable ( Archive fout,
const PublicationRelInfo pubrinfo 
)
static

Definition at line 5020 of file pg_dump.c.

5021{
5022 DumpOptions *dopt = fout->dopt;
5023 PublicationInfo *pubinfo = pubrinfo->publication;
5024 TableInfo *tbinfo = pubrinfo->pubtable;
5025 PQExpBuffer query;
5026 char *tag;
5027
5028 /* Do nothing if not dumping schema */
5029 if (!dopt->dumpSchema)
5030 return;
5031
5032 tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
5033
5034 query = createPQExpBuffer();
5035
5036 appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
5037 fmtId(pubinfo->dobj.name));
5038 appendPQExpBuffer(query, " %s",
5040
5041 if (pubrinfo->pubrattrs)
5042 appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
5043
5044 if (pubrinfo->pubrelqual)
5045 {
5046 /*
5047 * It's necessary to add parentheses around the expression because
5048 * pg_get_expr won't supply the parentheses for things like WHERE
5049 * TRUE.
5050 */
5051 appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
5052 }
5053 appendPQExpBufferStr(query, ";\n");
5054
5055 /*
5056 * There is no point in creating a drop query as the drop is done by table
5057 * drop. (If you think to change this, see also _printTocEntry().)
5058 * Although this object doesn't really have ownership as such, set the
5059 * owner field anyway to ensure that the command is run by the correct
5060 * role at restore time.
5061 */
5062 if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5063 ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
5064 ARCHIVE_OPTS(.tag = tag,
5065 .namespace = tbinfo->dobj.namespace->dobj.name,
5066 .owner = pubinfo->rolname,
5067 .description = "PUBLICATION TABLE",
5068 .section = SECTION_POST_DATA,
5069 .createStmt = query->data));
5070
5071 /* These objects can't currently have comments or seclabels */
5072
5073 free(tag);
5074 destroyPQExpBuffer(query);
5075}

References appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_DEFINITION, _dumpOptions::dumpSchema, fb(), fmtId(), fmtQualifiedDumpable, free, psprintf(), and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ dumpRangeType()

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

Definition at line 12246 of file pg_dump.c.

12247{
12248 DumpOptions *dopt = fout->dopt;
12252 PGresult *res;
12254 char *qtypname;
12255 char *qualtypname;
12256 char *procname;
12257
12258 if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
12259 {
12260 /* Set up query for range-specific details */
12262 "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
12263
12265 "SELECT ");
12266
12267 if (fout->remoteVersion >= 140000)
12269 "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
12270 else
12272 "NULL AS rngmultitype, ");
12273
12275 "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
12276 "opc.opcname AS opcname, "
12277 "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
12278 " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
12279 "opc.opcdefault, "
12280 "CASE WHEN rngcollation = st.typcollation THEN 0 "
12281 " ELSE rngcollation END AS collation, "
12282 "rngcanonical, rngsubdiff "
12283 "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
12284 " pg_catalog.pg_opclass opc "
12285 "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
12286 "rngtypid = $1");
12287
12288 ExecuteSqlStatement(fout, query->data);
12289
12290 fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
12291 }
12292
12293 printfPQExpBuffer(query,
12294 "EXECUTE dumpRangeType('%u')",
12295 tyinfo->dobj.catId.oid);
12296
12297 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12298
12299 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12301
12302 /*
12303 * CASCADE shouldn't be required here as for normal types since the I/O
12304 * functions are generic and do not get dropped.
12305 */
12306 appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12307
12308 if (dopt->binary_upgrade)
12310 tyinfo->dobj.catId.oid,
12311 false, true);
12312
12313 appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
12314 qualtypname);
12315
12316 appendPQExpBuffer(q, "\n subtype = %s",
12317 PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
12318
12319 if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
12320 appendPQExpBuffer(q, ",\n multirange_type_name = %s",
12321 PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
12322
12323 /* print subtype_opclass only if not default for subtype */
12324 if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
12325 {
12326 char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
12327 char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
12328
12329 appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
12330 fmtId(nspname));
12332 }
12333
12334 collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
12336 {
12338
12339 if (coll)
12340 appendPQExpBuffer(q, ",\n collation = %s",
12342 }
12343
12344 procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
12345 if (strcmp(procname, "-") != 0)
12346 appendPQExpBuffer(q, ",\n canonical = %s", procname);
12347
12348 procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
12349 if (strcmp(procname, "-") != 0)
12350 appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
12351
12352 appendPQExpBufferStr(q, "\n);\n");
12353
12354 if (dopt->binary_upgrade)
12356 "TYPE", qtypname,
12357 tyinfo->dobj.namespace->dobj.name);
12358
12359 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12360 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12361 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12362 .namespace = tyinfo->dobj.namespace->dobj.name,
12363 .owner = tyinfo->rolname,
12364 .description = "TYPE",
12365 .section = SECTION_PRE_DATA,
12366 .createStmt = q->data,
12367 .dropStmt = delq->data));
12368
12369 /* Dump Type Comments and Security Labels */
12370 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12371 dumpComment(fout, "TYPE", qtypname,
12372 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12373 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12374
12375 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12376 dumpSecLabel(fout, "TYPE", qtypname,
12377 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12378 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12379
12380 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12381 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12382 qtypname, NULL,
12383 tyinfo->dobj.namespace->dobj.name,
12384 NULL, tyinfo->rolname, &tyinfo->dacl);
12385
12386 PQclear(res);
12389 destroyPQExpBuffer(query);
12390 free(qtypname);
12392}

References appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), atooid, _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), binary_upgrade_set_type_oids_by_type_oid(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_ACL, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpACL(), dumpComment(), dumpSecLabel(), ExecuteSqlQueryForSingleRow(), ExecuteSqlStatement(), fb(), findCollationByOid(), fmtId(), fmtQualifiedDumpable, free, InvalidDumpId, OidIsValid, pg_strdup(), PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PREPQUERY_DUMPRANGETYPE, printfPQExpBuffer(), and SECTION_PRE_DATA.

Referenced by dumpType().

◆ dumpRelationStats()

static void dumpRelationStats ( Archive fout,
const RelStatsInfo rsinfo 
)
static

Definition at line 11392 of file pg_dump.c.

11393{
11394 const DumpableObject *dobj = &rsinfo->dobj;
11395
11396 /* nothing to do if we are not dumping statistics */
11397 if (!fout->dopt->dumpStatistics)
11398 return;
11399
11401 ARCHIVE_OPTS(.tag = dobj->name,
11402 .namespace = dobj->namespace->dobj.name,
11403 .description = "STATISTICS DATA",
11404 .section = rsinfo->section,
11405 .defnFn = dumpRelationStats_dumper,
11406 .defnArg = rsinfo,
11407 .deps = dobj->dependencies,
11408 .nDeps = dobj->nDeps));
11409}

References ARCHIVE_OPTS, ArchiveEntry(), createDumpId(), _dumpableObject::dependencies, dumpRelationStats_dumper(), fb(), _dumpableObject::name, _dumpableObject::nDeps, and nilCatalogId.

Referenced by dumpDumpableObject().

◆ dumpRelationStats_dumper()

static char * dumpRelationStats_dumper ( Archive fout,
const void userArg,
const TocEntry te 
)
static

Definition at line 11119 of file pg_dump.c.

11120{
11121 const RelStatsInfo *rsinfo = userArg;
11122 static PGresult *res;
11123 static int rownum;
11124 PQExpBuffer query;
11126 PQExpBuffer out = &out_data;
11127 int i_schemaname;
11128 int i_tablename;
11129 int i_attname;
11130 int i_inherited;
11131 int i_null_frac;
11132 int i_avg_width;
11133 int i_n_distinct;
11137 int i_correlation;
11144 static TocEntry *expected_te;
11145
11146 /*
11147 * fetchAttributeStats() assumes that the statistics are dumped in the
11148 * order they are listed in the TOC. We verify that here for safety.
11149 */
11150 if (!expected_te)
11151 expected_te = ((ArchiveHandle *) fout)->toc;
11152
11154 while ((expected_te->reqs & REQ_STATS) == 0 ||
11155 strcmp(expected_te->desc, "STATISTICS DATA") != 0)
11157
11158 if (te != expected_te)
11159 pg_fatal("statistics dumped out of order (current: %d %s %s, expected: %d %s %s)",
11160 te->dumpId, te->desc, te->tag,
11161 expected_te->dumpId, expected_te->desc, expected_te->tag);
11162
11163 query = createPQExpBuffer();
11164 if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
11165 {
11167 "PREPARE getAttributeStats(pg_catalog.name[], pg_catalog.name[]) AS\n"
11168 "SELECT s.schemaname, s.tablename, s.attname, s.inherited, "
11169 "s.null_frac, s.avg_width, s.n_distinct, "
11170 "s.most_common_vals, s.most_common_freqs, "
11171 "s.histogram_bounds, s.correlation, "
11172 "s.most_common_elems, s.most_common_elem_freqs, "
11173 "s.elem_count_histogram, ");
11174
11175 if (fout->remoteVersion >= 170000)
11177 "s.range_length_histogram, "
11178 "s.range_empty_frac, "
11179 "s.range_bounds_histogram ");
11180 else
11182 "NULL AS range_length_histogram,"
11183 "NULL AS range_empty_frac,"
11184 "NULL AS range_bounds_histogram ");
11185
11186 /*
11187 * The results must be in the order of the relations supplied in the
11188 * parameters to ensure we remain in sync as we walk through the TOC.
11189 * The redundant filter clause on s.tablename = ANY(...) seems
11190 * sufficient to convince the planner to use
11191 * pg_class_relname_nsp_index, which avoids a full scan of pg_stats.
11192 * This may not work for all versions.
11193 *
11194 * Our query for retrieving statistics for multiple relations uses
11195 * WITH ORDINALITY and multi-argument UNNEST(), both of which were
11196 * introduced in v9.4. For older versions, we resort to gathering
11197 * statistics for a single relation at a time.
11198 */
11199 if (fout->remoteVersion >= 90400)
11201 "FROM pg_catalog.pg_stats s "
11202 "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) "
11203 "ON s.schemaname = u.schemaname "
11204 "AND s.tablename = u.tablename "
11205 "WHERE s.tablename = ANY($2) "
11206 "ORDER BY u.ord, s.attname, s.inherited");
11207 else
11209 "FROM pg_catalog.pg_stats s "
11210 "WHERE s.schemaname = $1[1] "
11211 "AND s.tablename = $2[1] "
11212 "ORDER BY s.attname, s.inherited");
11213
11214 ExecuteSqlStatement(fout, query->data);
11215
11216 fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
11217 resetPQExpBuffer(query);
11218 }
11219
11220 initPQExpBuffer(out);
11221
11222 /* restore relation stats */
11223 appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
11224 appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
11225 fout->remoteVersion);
11226 appendPQExpBufferStr(out, "\t'schemaname', ");
11227 appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
11228 appendPQExpBufferStr(out, ",\n");
11229 appendPQExpBufferStr(out, "\t'relname', ");
11230 appendStringLiteralAH(out, rsinfo->dobj.name, fout);
11231 appendPQExpBufferStr(out, ",\n");
11232 appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
11233
11234 /*
11235 * Before v14, a reltuples value of 0 was ambiguous: it could either mean
11236 * the relation is empty, or it could mean that it hadn't yet been
11237 * vacuumed or analyzed. (Newer versions use -1 for the latter case.)
11238 * This ambiguity allegedly can cause the planner to choose inefficient
11239 * plans after restoring to v18 or newer. To deal with this, let's just
11240 * set reltuples to -1 in that case.
11241 */
11242 if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
11243 appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
11244 else
11245 appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
11246
11247 appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
11248 rsinfo->relallvisible);
11249
11250 if (fout->remoteVersion >= 180000)
11251 appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
11252
11253 appendPQExpBufferStr(out, "\n);\n");
11254
11255 /* Fetch the next batch of attribute statistics if needed. */
11256 if (rownum >= PQntuples(res))
11257 {
11258 PQclear(res);
11260 rownum = 0;
11261 }
11262
11263 i_schemaname = PQfnumber(res, "schemaname");
11264 i_tablename = PQfnumber(res, "tablename");
11265 i_attname = PQfnumber(res, "attname");
11266 i_inherited = PQfnumber(res, "inherited");
11267 i_null_frac = PQfnumber(res, "null_frac");
11268 i_avg_width = PQfnumber(res, "avg_width");
11269 i_n_distinct = PQfnumber(res, "n_distinct");
11270 i_most_common_vals = PQfnumber(res, "most_common_vals");
11271 i_most_common_freqs = PQfnumber(res, "most_common_freqs");
11272 i_histogram_bounds = PQfnumber(res, "histogram_bounds");
11273 i_correlation = PQfnumber(res, "correlation");
11274 i_most_common_elems = PQfnumber(res, "most_common_elems");
11275 i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
11276 i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
11277 i_range_length_histogram = PQfnumber(res, "range_length_histogram");
11278 i_range_empty_frac = PQfnumber(res, "range_empty_frac");
11279 i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
11280
11281 /* restore attribute stats */
11282 for (; rownum < PQntuples(res); rownum++)
11283 {
11284 const char *attname;
11285
11286 /* Stop if the next stat row in our cache isn't for this relation. */
11287 if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
11288 strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
11289 break;
11290
11291 appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
11292 appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
11293 fout->remoteVersion);
11294 appendPQExpBufferStr(out, "\t'schemaname', ");
11295 appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
11296 appendPQExpBufferStr(out, ",\n\t'relname', ");
11297 appendStringLiteralAH(out, rsinfo->dobj.name, fout);
11298
11299 if (PQgetisnull(res, rownum, i_attname))
11300 pg_fatal("unexpected null attname");
11301 attname = PQgetvalue(res, rownum, i_attname);
11302
11303 /*
11304 * Indexes look up attname in indAttNames to derive attnum, all others
11305 * use attname directly. We must specify attnum for indexes, since
11306 * their attnames are not necessarily stable across dump/reload.
11307 */
11308 if (rsinfo->nindAttNames == 0)
11309 {
11310 appendPQExpBufferStr(out, ",\n\t'attname', ");
11312 }
11313 else
11314 {
11315 bool found = false;
11316
11317 for (int i = 0; i < rsinfo->nindAttNames; i++)
11318 {
11319 if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
11320 {
11321 appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
11322 i + 1);
11323 found = true;
11324 break;
11325 }
11326 }
11327
11328 if (!found)
11329 pg_fatal("could not find index attname \"%s\"", attname);
11330 }
11331
11332 if (!PQgetisnull(res, rownum, i_inherited))
11333 appendNamedArgument(out, fout, "inherited", "boolean",
11334 PQgetvalue(res, rownum, i_inherited));
11335 if (!PQgetisnull(res, rownum, i_null_frac))
11336 appendNamedArgument(out, fout, "null_frac", "real",
11337 PQgetvalue(res, rownum, i_null_frac));
11338 if (!PQgetisnull(res, rownum, i_avg_width))
11339 appendNamedArgument(out, fout, "avg_width", "integer",
11340 PQgetvalue(res, rownum, i_avg_width));
11341 if (!PQgetisnull(res, rownum, i_n_distinct))
11342 appendNamedArgument(out, fout, "n_distinct", "real",
11343 PQgetvalue(res, rownum, i_n_distinct));
11344 if (!PQgetisnull(res, rownum, i_most_common_vals))
11345 appendNamedArgument(out, fout, "most_common_vals", "text",
11346 PQgetvalue(res, rownum, i_most_common_vals));
11347 if (!PQgetisnull(res, rownum, i_most_common_freqs))
11348 appendNamedArgument(out, fout, "most_common_freqs", "real[]",
11349 PQgetvalue(res, rownum, i_most_common_freqs));
11350 if (!PQgetisnull(res, rownum, i_histogram_bounds))
11351 appendNamedArgument(out, fout, "histogram_bounds", "text",
11352 PQgetvalue(res, rownum, i_histogram_bounds));
11353 if (!PQgetisnull(res, rownum, i_correlation))
11354 appendNamedArgument(out, fout, "correlation", "real",
11355 PQgetvalue(res, rownum, i_correlation));
11356 if (!PQgetisnull(res, rownum, i_most_common_elems))
11357 appendNamedArgument(out, fout, "most_common_elems", "text",
11358 PQgetvalue(res, rownum, i_most_common_elems));
11359 if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
11360 appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
11361 PQgetvalue(res, rownum, i_most_common_elem_freqs));
11362 if (!PQgetisnull(res, rownum, i_elem_count_histogram))
11363 appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
11364 PQgetvalue(res, rownum, i_elem_count_histogram));
11365 if (fout->remoteVersion >= 170000)
11366 {
11367 if (!PQgetisnull(res, rownum, i_range_length_histogram))
11368 appendNamedArgument(out, fout, "range_length_histogram", "text",
11369 PQgetvalue(res, rownum, i_range_length_histogram));
11370 if (!PQgetisnull(res, rownum, i_range_empty_frac))
11371 appendNamedArgument(out, fout, "range_empty_frac", "real",
11372 PQgetvalue(res, rownum, i_range_empty_frac));
11373 if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
11374 appendNamedArgument(out, fout, "range_bounds_histogram", "text",
11375 PQgetvalue(res, rownum, i_range_bounds_histogram));
11376 }
11377 appendPQExpBufferStr(out, "\n);\n");
11378 }
11379
11380 destroyPQExpBuffer(query);
11381 return out->data;
11382}

References appendNamedArgument(), appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, attname, createPQExpBuffer(), PQExpBufferData::data, _tocEntry::desc, destroyPQExpBuffer(), _tocEntry::dumpId, ExecuteSqlStatement(), fb(), fetchAttributeStats(), i, initPQExpBuffer(), _tocEntry::next, pg_fatal, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, PREPQUERY_GETATTRIBUTESTATS, REQ_STATS, resetPQExpBuffer(), and _tocEntry::tag.

Referenced by dumpRelationStats().

◆ dumpRule()

static void dumpRule ( Archive fout,
const RuleInfo rinfo 
)
static

Definition at line 19753 of file pg_dump.c.

19754{
19755 DumpOptions *dopt = fout->dopt;
19756 TableInfo *tbinfo = rinfo->ruletable;
19757 bool is_view;
19758 PQExpBuffer query;
19759 PQExpBuffer cmd;
19762 char *qtabname;
19763 PGresult *res;
19764 char *tag;
19765
19766 /* Do nothing if not dumping schema */
19767 if (!dopt->dumpSchema)
19768 return;
19769
19770 /*
19771 * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
19772 * we do not want to dump it as a separate object.
19773 */
19774 if (!rinfo->separate)
19775 return;
19776
19777 /*
19778 * If it's an ON SELECT rule, we want to print it as a view definition,
19779 * instead of a rule.
19780 */
19781 is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
19782
19783 query = createPQExpBuffer();
19784 cmd = createPQExpBuffer();
19787
19788 qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19789
19790 if (is_view)
19791 {
19792 PQExpBuffer result;
19793
19794 /*
19795 * We need OR REPLACE here because we'll be replacing a dummy view.
19796 * Otherwise this should look largely like the regular view dump code.
19797 */
19798 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
19800 if (nonemptyReloptions(tbinfo->reloptions))
19801 {
19802 appendPQExpBufferStr(cmd, " WITH (");
19803 appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
19804 appendPQExpBufferChar(cmd, ')');
19805 }
19806 result = createViewAsClause(fout, tbinfo);
19807 appendPQExpBuffer(cmd, " AS\n%s", result->data);
19808 destroyPQExpBuffer(result);
19809 if (tbinfo->checkoption != NULL)
19810 appendPQExpBuffer(cmd, "\n WITH %s CHECK OPTION",
19811 tbinfo->checkoption);
19812 appendPQExpBufferStr(cmd, ";\n");
19813 }
19814 else
19815 {
19816 /* In the rule case, just print pg_get_ruledef's result verbatim */
19817 appendPQExpBuffer(query,
19818 "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
19819 rinfo->dobj.catId.oid);
19820
19821 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19822
19823 if (PQntuples(res) != 1)
19824 pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
19825 rinfo->dobj.name, tbinfo->dobj.name);
19826
19827 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
19828
19829 PQclear(res);
19830 }
19831
19832 /*
19833 * Add the command to alter the rules replication firing semantics if it
19834 * differs from the default.
19835 */
19836 if (rinfo->ev_enabled != 'O')
19837 {
19838 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
19839 switch (rinfo->ev_enabled)
19840 {
19841 case 'A':
19842 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
19843 fmtId(rinfo->dobj.name));
19844 break;
19845 case 'R':
19846 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
19847 fmtId(rinfo->dobj.name));
19848 break;
19849 case 'D':
19850 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
19851 fmtId(rinfo->dobj.name));
19852 break;
19853 }
19854 }
19855
19856 if (is_view)
19857 {
19858 /*
19859 * We can't DROP a view's ON SELECT rule. Instead, use CREATE OR
19860 * REPLACE VIEW to replace the rule with something with minimal
19861 * dependencies.
19862 */
19863 PQExpBuffer result;
19864
19865 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
19868 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
19869 destroyPQExpBuffer(result);
19870 }
19871 else
19872 {
19873 appendPQExpBuffer(delcmd, "DROP RULE %s ",
19874 fmtId(rinfo->dobj.name));
19875 appendPQExpBuffer(delcmd, "ON %s;\n",
19877 }
19878
19879 appendPQExpBuffer(ruleprefix, "RULE %s ON",
19880 fmtId(rinfo->dobj.name));
19881
19882 tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
19883
19884 if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19885 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
19886 ARCHIVE_OPTS(.tag = tag,
19887 .namespace = tbinfo->dobj.namespace->dobj.name,
19888 .owner = tbinfo->rolname,
19889 .description = "RULE",
19890 .section = SECTION_POST_DATA,
19891 .createStmt = cmd->data,
19892 .dropStmt = delcmd->data));
19893
19894 /* Dump rule comments */
19895 if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19897 tbinfo->dobj.namespace->dobj.name,
19898 tbinfo->rolname,
19899 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
19900
19901 free(tag);
19902 destroyPQExpBuffer(query);
19903 destroyPQExpBuffer(cmd);
19906 free(qtabname);
19907}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), appendReloptionsArrayAH(), ARCHIVE_OPTS, ArchiveEntry(), _dumpableObject::catId, createDummyViewAsClause(), createPQExpBuffer(), createViewAsClause(), PQExpBufferData::data, destroyPQExpBuffer(), _ruleInfo::dobj, _dumpableObject::dump, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpableObject::dumpId, _dumpOptions::dumpSchema, _ruleInfo::ev_enabled, _ruleInfo::ev_type, ExecuteSqlQuery(), fb(), fmtId(), fmtQualifiedDumpable, free, _ruleInfo::is_instead, _dumpableObject::name, nonemptyReloptions(), CatalogId::oid, pg_fatal, pg_strdup(), PGRES_TUPLES_OK, PQclear, PQgetvalue, PQntuples, printfPQExpBuffer(), psprintf(), _ruleInfo::ruletable, SECTION_POST_DATA, and _ruleInfo::separate.

Referenced by dumpDumpableObject().

◆ dumpSearchPath()

static void dumpSearchPath ( Archive AH)
static

Definition at line 3898 of file pg_dump.c.

3899{
3902 PGresult *res;
3903 char **schemanames = NULL;
3904 int nschemanames = 0;
3905 int i;
3906
3907 /*
3908 * We use the result of current_schemas(), not the search_path GUC,
3909 * because that might contain wildcards such as "$user", which won't
3910 * necessarily have the same value during restore. Also, this way avoids
3911 * listing schemas that may appear in search_path but not actually exist,
3912 * which seems like a prudent exclusion.
3913 */
3915 "SELECT pg_catalog.current_schemas(false)");
3916
3917 if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3918 pg_fatal("could not parse result of current_schemas()");
3919
3920 /*
3921 * We use set_config(), not a simple "SET search_path" command, because
3922 * the latter has less-clean behavior if the search path is empty. While
3923 * that's likely to get fixed at some point, it seems like a good idea to
3924 * be as backwards-compatible as possible in what we put into archives.
3925 */
3926 for (i = 0; i < nschemanames; i++)
3927 {
3928 if (i > 0)
3929 appendPQExpBufferStr(path, ", ");
3931 }
3932
3933 appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3934 appendStringLiteralAH(qry, path->data, AH);
3935 appendPQExpBufferStr(qry, ", false);\n");
3936
3937 pg_log_info("saving \"search_path = %s\"", path->data);
3938
3940 ARCHIVE_OPTS(.tag = "SEARCHPATH",
3941 .description = "SEARCHPATH",
3942 .section = SECTION_PRE_DATA,
3943 .createStmt = qry->data));
3944
3945 /* Also save it in AH->searchpath, in case we're doing plain text dump */
3946 AH->searchpath = pg_strdup(qry->data);
3947
3949 PQclear(res);
3950 destroyPQExpBuffer(qry);
3951 destroyPQExpBuffer(path);
3952}

References appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), createDumpId(), createPQExpBuffer(), PQExpBufferData::data, description, destroyPQExpBuffer(), ExecuteSqlQueryForSingleRow(), fb(), fmtId(), free, i, nilCatalogId, parsePGArray(), pg_fatal, pg_log_info, pg_strdup(), PQclear, PQgetvalue, Archive::searchpath, and SECTION_PRE_DATA.

Referenced by main().

◆ dumpSecLabel()

static void dumpSecLabel ( Archive fout,
const char type,
const char name,
const char namespace,
const char owner,
CatalogId  catalogId,
int  subid,
DumpId  dumpId 
)
static

Definition at line 16554 of file pg_dump.c.

16557{
16558 DumpOptions *dopt = fout->dopt;
16560 int nlabels;
16561 int i;
16562 PQExpBuffer query;
16563
16564 /* do nothing, if --no-security-labels is supplied */
16565 if (dopt->no_security_labels)
16566 return;
16567
16568 /*
16569 * Security labels are schema not data ... except large object labels are
16570 * data
16571 */
16572 if (strcmp(type, "LARGE OBJECT") != 0)
16573 {
16574 if (!dopt->dumpSchema)
16575 return;
16576 }
16577 else
16578 {
16579 /* We do dump large object security labels in binary-upgrade mode */
16580 if (!dopt->dumpData && !dopt->binary_upgrade)
16581 return;
16582 }
16583
16584 /* Search for security labels associated with catalogId, using table */
16585 nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
16586
16587 query = createPQExpBuffer();
16588
16589 for (i = 0; i < nlabels; i++)
16590 {
16591 /*
16592 * Ignore label entries for which the subid doesn't match.
16593 */
16594 if (labels[i].objsubid != subid)
16595 continue;
16596
16597 appendPQExpBuffer(query,
16598 "SECURITY LABEL FOR %s ON %s ",
16600 if (namespace && *namespace)
16601 appendPQExpBuffer(query, "%s.", fmtId(namespace));
16602 appendPQExpBuffer(query, "%s IS ", name);
16604 appendPQExpBufferStr(query, ";\n");
16605 }
16606
16607 if (query->len > 0)
16608 {
16610
16611 appendPQExpBuffer(tag, "%s %s", type, name);
16613 ARCHIVE_OPTS(.tag = tag->data,
16614 .namespace = namespace,
16615 .owner = owner,
16616 .description = "SECURITY LABEL",
16617 .section = SECTION_NONE,
16618 .createStmt = query->data,
16619 .deps = &dumpId,
16620 .nDeps = 1));
16621 destroyPQExpBuffer(tag);
16622 }
16623
16624 destroyPQExpBuffer(query);
16625}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, createDumpId(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), _dumpOptions::dumpData, _dumpOptions::dumpSchema, fb(), findSecLabels(), fmtId(), i, label, PQExpBufferData::len, name, nilCatalogId, _dumpOptions::no_security_labels, CatalogId::oid, SECTION_NONE, CatalogId::tableoid, and type.

Referenced by dumpAgg(), dumpBaseType(), dumpCompositeType(), dumpDomain(), dumpEnumType(), dumpEventTrigger(), dumpFunc(), dumpLO(), dumpNamespace(), dumpProcLang(), dumpPublication(), dumpRangeType(), dumpSequence(), dumpSubscription(), and dumpUndefinedType().

◆ dumpSequence()

static void dumpSequence ( Archive fout,
const TableInfo tbinfo 
)
static

Definition at line 19194 of file pg_dump.c.

19195{
19196 DumpOptions *dopt = fout->dopt;
19198 bool is_ascending;
19203 char *qseqname;
19204 TableInfo *owning_tab = NULL;
19205
19206 qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
19207
19208 /*
19209 * For versions >= 10, the sequence information is gathered in a sorted
19210 * table before any calls to dumpSequence(). See collectSequences() for
19211 * more information.
19212 */
19213 if (fout->remoteVersion >= 100000)
19214 {
19215 SequenceItem key = {0};
19216
19218
19219 key.oid = tbinfo->dobj.catId.oid;
19221 sizeof(SequenceItem), SequenceItemCmp);
19222 }
19223 else
19224 {
19225 PGresult *res;
19226
19227 /*
19228 * Before PostgreSQL 10, sequence metadata is in the sequence itself.
19229 *
19230 * Note: it might seem that 'bigint' potentially needs to be
19231 * schema-qualified, but actually that's a keyword.
19232 */
19233 appendPQExpBuffer(query,
19234 "SELECT 'bigint' AS sequence_type, "
19235 "start_value, increment_by, max_value, min_value, "
19236 "cache_value, is_cycled FROM %s",
19238
19239 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19240
19241 if (PQntuples(res) != 1)
19242 pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
19243 "query to get data of sequence \"%s\" returned %d rows (expected 1)",
19244 PQntuples(res)),
19245 tbinfo->dobj.name, PQntuples(res));
19246
19247 seq = pg_malloc0(sizeof(SequenceItem));
19248 seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
19249 seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
19250 seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
19251 seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
19252 seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
19253 seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
19254 seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
19255
19256 PQclear(res);
19257 }
19258
19259 /* Calculate default limits for a sequence of this type */
19260 is_ascending = (seq->incby >= 0);
19261 if (seq->seqtype == SEQTYPE_SMALLINT)
19262 {
19265 }
19266 else if (seq->seqtype == SEQTYPE_INTEGER)
19267 {
19270 }
19271 else if (seq->seqtype == SEQTYPE_BIGINT)
19272 {
19275 }
19276 else
19277 {
19278 pg_fatal("unrecognized sequence type: %d", seq->seqtype);
19279 default_minv = default_maxv = 0; /* keep compiler quiet */
19280 }
19281
19282 /*
19283 * Identity sequences are not to be dropped separately.
19284 */
19285 if (!tbinfo->is_identity_sequence)
19286 {
19287 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
19289 }
19290
19291 resetPQExpBuffer(query);
19292
19293 if (dopt->binary_upgrade)
19294 {
19296 tbinfo->dobj.catId.oid);
19297
19298 /*
19299 * In older PG versions a sequence will have a pg_type entry, but v14
19300 * and up don't use that, so don't attempt to preserve the type OID.
19301 */
19302 }
19303
19304 if (tbinfo->is_identity_sequence)
19305 {
19306 owning_tab = findTableByOid(tbinfo->owning_tab);
19307
19308 appendPQExpBuffer(query,
19309 "ALTER TABLE %s ",
19310 fmtQualifiedDumpable(owning_tab));
19311 appendPQExpBuffer(query,
19312 "ALTER COLUMN %s ADD GENERATED ",
19313 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
19314 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
19315 appendPQExpBufferStr(query, "ALWAYS");
19316 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
19317 appendPQExpBufferStr(query, "BY DEFAULT");
19318 appendPQExpBuffer(query, " AS IDENTITY (\n SEQUENCE NAME %s\n",
19320
19321 /*
19322 * Emit persistence option only if it's different from the owning
19323 * table's. This avoids using this new syntax unnecessarily.
19324 */
19325 if (tbinfo->relpersistence != owning_tab->relpersistence)
19326 appendPQExpBuffer(query, " %s\n",
19327 tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
19328 "UNLOGGED" : "LOGGED");
19329 }
19330 else
19331 {
19332 appendPQExpBuffer(query,
19333 "CREATE %sSEQUENCE %s\n",
19334 tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
19335 "UNLOGGED " : "",
19337
19338 if (seq->seqtype != SEQTYPE_BIGINT)
19339 appendPQExpBuffer(query, " AS %s\n", SeqTypeNames[seq->seqtype]);
19340 }
19341
19342 appendPQExpBuffer(query, " START WITH " INT64_FORMAT "\n", seq->startv);
19343
19344 appendPQExpBuffer(query, " INCREMENT BY " INT64_FORMAT "\n", seq->incby);
19345
19346 if (seq->minv != default_minv)
19347 appendPQExpBuffer(query, " MINVALUE " INT64_FORMAT "\n", seq->minv);
19348 else
19349 appendPQExpBufferStr(query, " NO MINVALUE\n");
19350
19351 if (seq->maxv != default_maxv)
19352 appendPQExpBuffer(query, " MAXVALUE " INT64_FORMAT "\n", seq->maxv);
19353 else
19354 appendPQExpBufferStr(query, " NO MAXVALUE\n");
19355
19356 appendPQExpBuffer(query,
19357 " CACHE " INT64_FORMAT "%s",
19358 seq->cache, (seq->cycled ? "\n CYCLE" : ""));
19359
19360 if (tbinfo->is_identity_sequence)
19361 appendPQExpBufferStr(query, "\n);\n");
19362 else
19363 appendPQExpBufferStr(query, ";\n");
19364
19365 /* binary_upgrade: no need to clear TOAST table oid */
19366
19367 if (dopt->binary_upgrade)
19369 "SEQUENCE", qseqname,
19370 tbinfo->dobj.namespace->dobj.name);
19371
19372 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19373 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
19374 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19375 .namespace = tbinfo->dobj.namespace->dobj.name,
19376 .owner = tbinfo->rolname,
19377 .description = "SEQUENCE",
19378 .section = SECTION_PRE_DATA,
19379 .createStmt = query->data,
19380 .dropStmt = delqry->data));
19381
19382 /*
19383 * If the sequence is owned by a table column, emit the ALTER for it as a
19384 * separate TOC entry immediately following the sequence's own entry. It's
19385 * OK to do this rather than using full sorting logic, because the
19386 * dependency that tells us it's owned will have forced the table to be
19387 * created first. We can't just include the ALTER in the TOC entry
19388 * because it will fail if we haven't reassigned the sequence owner to
19389 * match the table's owner.
19390 *
19391 * We need not schema-qualify the table reference because both sequence
19392 * and table must be in the same schema.
19393 */
19394 if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
19395 {
19396 owning_tab = findTableByOid(tbinfo->owning_tab);
19397
19398 if (owning_tab == NULL)
19399 pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
19400 tbinfo->owning_tab, tbinfo->dobj.catId.oid);
19401
19402 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
19403 {
19404 resetPQExpBuffer(query);
19405 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
19407 appendPQExpBuffer(query, " OWNED BY %s",
19408 fmtQualifiedDumpable(owning_tab));
19409 appendPQExpBuffer(query, ".%s;\n",
19410 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
19411
19412 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19414 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19415 .namespace = tbinfo->dobj.namespace->dobj.name,
19416 .owner = tbinfo->rolname,
19417 .description = "SEQUENCE OWNED BY",
19418 .section = SECTION_PRE_DATA,
19419 .createStmt = query->data,
19420 .deps = &(tbinfo->dobj.dumpId),
19421 .nDeps = 1));
19422 }
19423 }
19424
19425 /* Dump Sequence Comments and Security Labels */
19426 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19427 dumpComment(fout, "SEQUENCE", qseqname,
19428 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19429 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
19430
19431 if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
19432 dumpSecLabel(fout, "SEQUENCE", qseqname,
19433 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19434 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
19435
19436 if (fout->remoteVersion < 100000)
19437 pg_free(seq);
19438 destroyPQExpBuffer(query);
19440 free(qseqname);
19441}

References appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), Assert, _tableInfo::attidentity, _tableInfo::attnames, _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), binary_upgrade_set_pg_class_oids(), createDumpId(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), _tableInfo::dobj, _dumpableObject::dump, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpComment(), dumpSecLabel(), ExecuteSqlQuery(), fb(), findTableByOid(), fmtId(), fmtQualifiedDumpable, free, INT64_FORMAT, ngettext, nilCatalogId, nsequences, OidIsValid, parse_sequence_type(), pg_fatal, pg_free(), PG_INT16_MAX, PG_INT16_MIN, PG_INT32_MAX, PG_INT32_MIN, PG_INT64_MAX, PG_INT64_MIN, pg_malloc0(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQgetvalue, PQntuples, _tableInfo::relpersistence, resetPQExpBuffer(), SECTION_PRE_DATA, SEQTYPE_BIGINT, SEQTYPE_INTEGER, SEQTYPE_SMALLINT, SeqTypeNames, SequenceItemCmp(), and sequences.

Referenced by dumpTable().

◆ dumpSequenceData()

static void dumpSequenceData ( Archive fout,
const TableDataInfo tdinfo 
)
static

Definition at line 19448 of file pg_dump.c.

19449{
19450 TableInfo *tbinfo = tdinfo->tdtable;
19451 int64 last;
19452 bool called;
19453 PQExpBuffer query;
19454
19455 /* needn't bother if not dumping sequence data */
19456 if (!fout->dopt->dumpData && !fout->dopt->sequence_data)
19457 return;
19458
19459 query = createPQExpBuffer();
19460
19461 /*
19462 * For versions >= 18, the sequence information is gathered in the sorted
19463 * array before any calls to dumpSequenceData(). See collectSequences()
19464 * for more information.
19465 *
19466 * For older versions, we have to query the sequence relations
19467 * individually.
19468 */
19469 if (fout->remoteVersion < 180000)
19470 {
19471 PGresult *res;
19472
19473 appendPQExpBuffer(query,
19474 "SELECT last_value, is_called FROM %s",
19476
19477 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19478
19479 if (PQntuples(res) != 1)
19480 pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
19481 "query to get data of sequence \"%s\" returned %d rows (expected 1)",
19482 PQntuples(res)),
19483 tbinfo->dobj.name, PQntuples(res));
19484
19485 last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
19486 called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
19487
19488 PQclear(res);
19489 }
19490 else
19491 {
19492 SequenceItem key = {0};
19493 SequenceItem *entry;
19494
19496 Assert(tbinfo->dobj.catId.oid);
19497
19498 key.oid = tbinfo->dobj.catId.oid;
19499 entry = bsearch(&key, sequences, nsequences,
19500 sizeof(SequenceItem), SequenceItemCmp);
19501
19502 if (entry->null_seqtuple)
19503 pg_fatal("failed to get data for sequence \"%s\"; user may lack "
19504 "SELECT privilege on the sequence or the sequence may "
19505 "have been concurrently dropped",
19506 tbinfo->dobj.name);
19507
19508 last = entry->last_value;
19509 called = entry->is_called;
19510 }
19511
19512 resetPQExpBuffer(query);
19513 appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
19515 appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
19516 last, (called ? "true" : "false"));
19517
19518 if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
19520 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19521 .namespace = tbinfo->dobj.namespace->dobj.name,
19522 .owner = tbinfo->rolname,
19523 .description = "SEQUENCE SET",
19524 .section = SECTION_DATA,
19525 .createStmt = query->data,
19526 .deps = &(tbinfo->dobj.dumpId),
19527 .nDeps = 1));
19528
19529 destroyPQExpBuffer(query);
19530}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), Assert, createDumpId(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_DATA, ExecuteSqlQuery(), fb(), fmtQualifiedDumpable, INT64_FORMAT, SequenceItem::is_called, SequenceItem::last_value, ngettext, nilCatalogId, nsequences, SequenceItem::null_seqtuple, pg_fatal, PGRES_TUPLES_OK, PQclear, PQgetvalue, PQntuples, resetPQExpBuffer(), SECTION_DATA, SequenceItemCmp(), and sequences.

Referenced by dumpDumpableObject().

◆ dumpShellType()

static void dumpShellType ( Archive fout,
const ShellTypeInfo stinfo 
)
static

Definition at line 13237 of file pg_dump.c.

13238{
13239 DumpOptions *dopt = fout->dopt;
13240 PQExpBuffer q;
13241
13242 /* Do nothing if not dumping schema */
13243 if (!dopt->dumpSchema)
13244 return;
13245
13246 q = createPQExpBuffer();
13247
13248 /*
13249 * Note the lack of a DROP command for the shell type; any required DROP
13250 * is driven off the base type entry, instead. This interacts with
13251 * _printTocEntry()'s use of the presence of a DROP command to decide
13252 * whether an entry needs an ALTER OWNER command. We don't want to alter
13253 * the shell type's owner immediately on creation; that should happen only
13254 * after it's filled in, otherwise the backend complains.
13255 */
13256
13257 if (dopt->binary_upgrade)
13259 stinfo->baseType->dobj.catId.oid,
13260 false, false);
13261
13262 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
13264
13265 if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13266 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
13267 ARCHIVE_OPTS(.tag = stinfo->dobj.name,
13268 .namespace = stinfo->dobj.namespace->dobj.name,
13269 .owner = stinfo->baseType->rolname,
13270 .description = "SHELL TYPE",
13271 .section = SECTION_PRE_DATA,
13272 .createStmt = q->data));
13273
13275}

References appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_set_type_oids_by_type_oid(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_DEFINITION, _dumpOptions::dumpSchema, fb(), fmtQualifiedDumpable, and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpStatisticsExt()

static void dumpStatisticsExt ( Archive fout,
const StatsExtInfo statsextinfo 
)
static

Definition at line 18477 of file pg_dump.c.

18478{
18479 DumpOptions *dopt = fout->dopt;
18480 PQExpBuffer q;
18482 PQExpBuffer query;
18483 char *qstatsextname;
18484 PGresult *res;
18485 char *stxdef;
18486
18487 /* Do nothing if not dumping schema */
18488 if (!dopt->dumpSchema)
18489 return;
18490
18491 q = createPQExpBuffer();
18493 query = createPQExpBuffer();
18494
18496
18497 appendPQExpBuffer(query, "SELECT "
18498 "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
18499 statsextinfo->dobj.catId.oid);
18500
18501 res = ExecuteSqlQueryForSingleRow(fout, query->data);
18502
18503 stxdef = PQgetvalue(res, 0, 0);
18504
18505 /* Result of pg_get_statisticsobjdef is complete except for semicolon */
18506 appendPQExpBuffer(q, "%s;\n", stxdef);
18507
18508 /*
18509 * We only issue an ALTER STATISTICS statement if the stxstattarget entry
18510 * for this statistics object is not the default value.
18511 */
18512 if (statsextinfo->stattarget >= 0)
18513 {
18514 appendPQExpBuffer(q, "ALTER STATISTICS %s ",
18516 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
18517 statsextinfo->stattarget);
18518 }
18519
18520 appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
18522
18523 if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18524 ArchiveEntry(fout, statsextinfo->dobj.catId,
18525 statsextinfo->dobj.dumpId,
18526 ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
18527 .namespace = statsextinfo->dobj.namespace->dobj.name,
18528 .owner = statsextinfo->rolname,
18529 .description = "STATISTICS",
18530 .section = SECTION_POST_DATA,
18531 .createStmt = q->data,
18532 .dropStmt = delq->data));
18533
18534 /* Dump Statistics Comments */
18535 if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18536 dumpComment(fout, "STATISTICS", qstatsextname,
18537 statsextinfo->dobj.namespace->dobj.name,
18538 statsextinfo->rolname,
18539 statsextinfo->dobj.catId, 0,
18540 statsextinfo->dobj.dumpId);
18541
18542 PQclear(res);
18545 destroyPQExpBuffer(query);
18547}

References appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, ExecuteSqlQueryForSingleRow(), fb(), fmtId(), fmtQualifiedDumpable, free, pg_strdup(), PQclear, PQgetvalue, and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ dumpStatisticsExtStats()

static void dumpStatisticsExtStats ( Archive fout,
const StatsExtInfo statsextinfo 
)
static

Definition at line 18554 of file pg_dump.c.

18555{
18556 DumpOptions *dopt = fout->dopt;
18557 PQExpBuffer query;
18558 PGresult *res;
18559 int nstats;
18560
18561 /* Do nothing if not dumping statistics */
18562 if (!dopt->dumpStatistics)
18563 return;
18564
18565 if (!fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS])
18566 {
18568
18569 /*---------
18570 * Set up query for details about extended statistics objects.
18571 *
18572 * The query depends on the backend version:
18573 * - In v19 and newer versions, query directly the pg_stats_ext*
18574 * catalogs.
18575 * - In v18 and older versions, ndistinct and dependencies have a
18576 * different format that needs translation.
18577 * - In v14 and older versions, inherited does not exist.
18578 * - In v11 and older versions, there is no pg_stats_ext, hence
18579 * the logic joins pg_statistic_ext and pg_namespace.
18580 *---------
18581 */
18582
18584 "PREPARE getExtStatsStats(pg_catalog.name, pg_catalog.name) AS\n"
18585 "SELECT ");
18586
18587 /*
18588 * Versions 15 and newer have inherited stats.
18589 *
18590 * Create this column in all versions because we need to order by it
18591 * later.
18592 */
18593 if (fout->remoteVersion >= 150000)
18594 appendPQExpBufferStr(pq, "e.inherited, ");
18595 else
18596 appendPQExpBufferStr(pq, "false AS inherited, ");
18597
18598 /*--------
18599 * The ndistinct and dependencies formats changed in v19, so
18600 * everything before that needs to be translated.
18601 *
18602 * The ndistinct translation converts this kind of data:
18603 * {"3, 4": 11, "3, 6": 11, "4, 6": 11, "3, 4, 6": 11}
18604 *
18605 * to this:
18606 * [ {"attributes": [3,4], "ndistinct": 11},
18607 * {"attributes": [3,6], "ndistinct": 11},
18608 * {"attributes": [4,6], "ndistinct": 11},
18609 * {"attributes": [3,4,6], "ndistinct": 11} ]
18610 *
18611 * The dependencies translation converts this kind of data:
18612 * {"3 => 4": 1.000000, "3 => 6": 1.000000,
18613 * "4 => 6": 1.000000, "3, 4 => 6": 1.000000,
18614 * "3, 6 => 4": 1.000000}
18615 *
18616 * to this:
18617 * [ {"attributes": [3], "dependency": 4, "degree": 1.000000},
18618 * {"attributes": [3], "dependency": 6, "degree": 1.000000},
18619 * {"attributes": [4], "dependency": 6, "degree": 1.000000},
18620 * {"attributes": [3,4], "dependency": 6, "degree": 1.000000},
18621 * {"attributes": [3,6], "dependency": 4, "degree": 1.000000} ]
18622 *--------
18623 */
18624 if (fout->remoteVersion >= 190000)
18625 appendPQExpBufferStr(pq, "e.n_distinct, e.dependencies ");
18626 else
18628 "( "
18629 "SELECT json_agg( "
18630 " json_build_object( "
18632 " string_to_array(kv.key, ', ')::integer[], "
18634 " kv.value::bigint )) "
18635 "FROM json_each_text(e.n_distinct::text::json) AS kv"
18636 ") AS n_distinct, "
18637 "( "
18638 "SELECT json_agg( "
18639 " json_build_object( "
18641 " string_to_array( "
18642 " split_part(kv.key, ' => ', 1), "
18643 " ', ')::integer[], "
18645 " split_part(kv.key, ' => ', 2)::integer, "
18647 " kv.value::double precision )) "
18648 "FROM json_each_text(e.dependencies::text::json) AS kv "
18649 ") AS dependencies ");
18650
18651 /* pg_stats_ext introduced in v12 */
18652 if (fout->remoteVersion >= 120000)
18654 "FROM pg_catalog.pg_stats_ext AS e "
18655 "WHERE e.statistics_schemaname = $1 "
18656 "AND e.statistics_name = $2 ");
18657 else
18659 "FROM ( "
18660 "SELECT s.stxndistinct AS n_distinct, "
18661 " s.stxdependencies AS dependencies "
18662 "FROM pg_catalog.pg_statistic_ext AS s "
18663 "JOIN pg_catalog.pg_namespace AS n "
18664 "ON n.oid = s.stxnamespace "
18665 "WHERE n.nspname = $1 "
18666 "AND s.stxname = $2 "
18667 ") AS e ");
18668
18669 /* we always have an inherited column, but it may be a constant */
18670 appendPQExpBufferStr(pq, "ORDER BY inherited");
18671
18672 ExecuteSqlStatement(fout, pq->data);
18673
18674 fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS] = true;
18675
18677 }
18678
18679 query = createPQExpBuffer();
18680
18681 appendPQExpBufferStr(query, "EXECUTE getExtStatsStats(");
18682 appendStringLiteralAH(query, statsextinfo->dobj.namespace->dobj.name, fout);
18683 appendPQExpBufferStr(query, "::pg_catalog.name, ");
18684 appendStringLiteralAH(query, statsextinfo->dobj.name, fout);
18685 appendPQExpBufferStr(query, "::pg_catalog.name)");
18686
18687 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18688
18689 destroyPQExpBuffer(query);
18690
18691 nstats = PQntuples(res);
18692
18693 if (nstats > 0)
18694 {
18696
18697 int i_inherited = PQfnumber(res, "inherited");
18698 int i_ndistinct = PQfnumber(res, "n_distinct");
18699 int i_dependencies = PQfnumber(res, "dependencies");
18700
18701 for (int i = 0; i < nstats; i++)
18702 {
18703 TableInfo *tbinfo = statsextinfo->stattable;
18704
18705 if (PQgetisnull(res, i, i_inherited))
18706 pg_fatal("inherited cannot be NULL");
18707
18709 "SELECT * FROM pg_catalog.pg_restore_extended_stats(\n");
18710 appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
18711 fout->remoteVersion);
18712
18713 /* Relation information */
18714 appendPQExpBufferStr(out, "\t'schemaname', ");
18715 appendStringLiteralAH(out, tbinfo->dobj.namespace->dobj.name, fout);
18716 appendPQExpBufferStr(out, ",\n\t'relname', ");
18717 appendStringLiteralAH(out, tbinfo->dobj.name, fout);
18718
18719 /* Extended statistics information */
18720 appendPQExpBufferStr(out, ",\n\t'statistics_schemaname', ");
18721 appendStringLiteralAH(out, statsextinfo->dobj.namespace->dobj.name, fout);
18722 appendPQExpBufferStr(out, ",\n\t'statistics_name', ");
18723 appendStringLiteralAH(out, statsextinfo->dobj.name, fout);
18724 appendNamedArgument(out, fout, "inherited", "boolean",
18725 PQgetvalue(res, i, i_inherited));
18726
18727 if (!PQgetisnull(res, i, i_ndistinct))
18728 appendNamedArgument(out, fout, "n_distinct", "pg_ndistinct",
18729 PQgetvalue(res, i, i_ndistinct));
18730
18731 if (!PQgetisnull(res, i, i_dependencies))
18732 appendNamedArgument(out, fout, "dependencies", "pg_dependencies",
18733 PQgetvalue(res, i, i_dependencies));
18734
18735 appendPQExpBufferStr(out, "\n);\n");
18736 }
18737
18739 ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
18740 .namespace = statsextinfo->dobj.namespace->dobj.name,
18741 .owner = statsextinfo->rolname,
18742 .description = "EXTENDED STATISTICS DATA",
18743 .section = SECTION_POST_DATA,
18744 .createStmt = out->data,
18745 .deps = &statsextinfo->dobj.dumpId,
18746 .nDeps = 1));
18747 destroyPQExpBuffer(out);
18748 }
18749 PQclear(res);
18750}

References appendNamedArgument(), appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), createDumpId(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), _dumpOptions::dumpStatistics, ExecuteSqlQuery(), ExecuteSqlStatement(), fb(), i, nilCatalogId, PG_DEPENDENCIES_KEY_ATTRIBUTES, PG_DEPENDENCIES_KEY_DEGREE, PG_DEPENDENCIES_KEY_DEPENDENCY, pg_fatal, PG_NDISTINCT_KEY_ATTRIBUTES, PG_NDISTINCT_KEY_NDISTINCT, PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, PREPQUERY_DUMPEXTSTATSOBJSTATS, and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ dumpStdStrings()

static void dumpStdStrings ( Archive AH)
static

Definition at line 3874 of file pg_dump.c.

3875{
3876 const char *stdstrings = AH->std_strings ? "on" : "off";
3878
3879 pg_log_info("saving \"standard_conforming_strings = %s\"",
3880 stdstrings);
3881
3882 appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3883 stdstrings);
3884
3886 ARCHIVE_OPTS(.tag = "STDSTRINGS",
3887 .description = "STDSTRINGS",
3888 .section = SECTION_PRE_DATA,
3889 .createStmt = qry->data));
3890
3891 destroyPQExpBuffer(qry);
3892}

References appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), createDumpId(), createPQExpBuffer(), PQExpBufferData::data, description, destroyPQExpBuffer(), fb(), nilCatalogId, pg_log_info, SECTION_PRE_DATA, and Archive::std_strings.

Referenced by main().

◆ dumpSubscription()

static void dumpSubscription ( Archive fout,
const SubscriptionInfo subinfo 
)
static

Definition at line 5496 of file pg_dump.c.

5497{
5498 DumpOptions *dopt = fout->dopt;
5500 PQExpBuffer query;
5501 PQExpBuffer publications;
5502 char *qsubname;
5503 char **pubnames = NULL;
5504 int npubnames = 0;
5505 int i;
5506
5507 /* Do nothing if not dumping schema */
5508 if (!dopt->dumpSchema)
5509 return;
5510
5512 query = createPQExpBuffer();
5513
5514 qsubname = pg_strdup(fmtId(subinfo->dobj.name));
5515
5516 appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
5517 qsubname);
5518
5519 appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
5520 qsubname);
5521 appendStringLiteralAH(query, subinfo->subconninfo, fout);
5522
5523 /* Build list of quoted publications and append them to query. */
5525 pg_fatal("could not parse %s array", "subpublications");
5526
5527 publications = createPQExpBuffer();
5528 for (i = 0; i < npubnames; i++)
5529 {
5530 if (i > 0)
5531 appendPQExpBufferStr(publications, ", ");
5532
5533 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
5534 }
5535
5536 appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
5537 if (subinfo->subslotname)
5538 appendStringLiteralAH(query, subinfo->subslotname, fout);
5539 else
5540 appendPQExpBufferStr(query, "NONE");
5541
5542 if (subinfo->subbinary)
5543 appendPQExpBufferStr(query, ", binary = true");
5544
5545 if (subinfo->substream == LOGICALREP_STREAM_ON)
5546 appendPQExpBufferStr(query, ", streaming = on");
5547 else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
5548 appendPQExpBufferStr(query, ", streaming = parallel");
5549 else
5550 appendPQExpBufferStr(query, ", streaming = off");
5551
5553 appendPQExpBufferStr(query, ", two_phase = on");
5554
5555 if (subinfo->subdisableonerr)
5556 appendPQExpBufferStr(query, ", disable_on_error = true");
5557
5558 if (!subinfo->subpasswordrequired)
5559 appendPQExpBufferStr(query, ", password_required = false");
5560
5561 if (subinfo->subrunasowner)
5562 appendPQExpBufferStr(query, ", run_as_owner = true");
5563
5564 if (subinfo->subfailover)
5565 appendPQExpBufferStr(query, ", failover = true");
5566
5567 if (subinfo->subretaindeadtuples)
5568 appendPQExpBufferStr(query, ", retain_dead_tuples = true");
5569
5570 if (subinfo->submaxretention)
5571 appendPQExpBuffer(query, ", max_retention_duration = %d", subinfo->submaxretention);
5572
5573 if (strcmp(subinfo->subsynccommit, "off") != 0)
5574 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
5575
5576 if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
5577 appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
5578
5579 appendPQExpBufferStr(query, ");\n");
5580
5581 /*
5582 * In binary-upgrade mode, we allow the replication to continue after the
5583 * upgrade.
5584 */
5585 if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5586 {
5587 if (subinfo->suboriginremotelsn)
5588 {
5589 /*
5590 * Preserve the remote_lsn for the subscriber's replication
5591 * origin. This value is required to start the replication from
5592 * the position before the upgrade. This value will be stale if
5593 * the publisher gets upgraded before the subscriber node.
5594 * However, this shouldn't be a problem as the upgrade of the
5595 * publisher ensures that all the transactions were replicated
5596 * before upgrading it.
5597 */
5599 "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
5601 "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
5602 appendStringLiteralAH(query, subinfo->dobj.name, fout);
5603 appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
5604 }
5605
5606 if (subinfo->subenabled)
5607 {
5608 /*
5609 * Enable the subscription to allow the replication to continue
5610 * after the upgrade.
5611 */
5613 "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
5614 appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
5615 }
5616 }
5617
5618 if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5619 ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
5620 ARCHIVE_OPTS(.tag = subinfo->dobj.name,
5621 .owner = subinfo->rolname,
5622 .description = "SUBSCRIPTION",
5623 .section = SECTION_POST_DATA,
5624 .createStmt = query->data,
5625 .dropStmt = delq->data));
5626
5627 if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
5628 dumpComment(fout, "SUBSCRIPTION", qsubname,
5629 NULL, subinfo->rolname,
5630 subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5631
5632 if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
5633 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
5634 NULL, subinfo->rolname,
5635 subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5636
5637 destroyPQExpBuffer(publications);
5638 free(pubnames);
5639
5641 destroyPQExpBuffer(query);
5642 free(qsubname);
5643}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, _dumpableObject::catId, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), _SubscriptionInfo::dobj, _dumpableObject::dump, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpComment(), _dumpableObject::dumpId, _dumpOptions::dumpSchema, dumpSecLabel(), fb(), fmtId(), free, i, _dumpableObject::name, parsePGArray(), pg_fatal, pg_strcasecmp(), pg_strdup(), _SubscriptionInfo::rolname, SECTION_POST_DATA, _SubscriptionInfo::subbinary, _SubscriptionInfo::subconninfo, _SubscriptionInfo::subdisableonerr, _SubscriptionInfo::subenabled, _SubscriptionInfo::subfailover, _SubscriptionInfo::submaxretention, _SubscriptionInfo::suborigin, _SubscriptionInfo::suboriginremotelsn, _SubscriptionInfo::subpasswordrequired, _SubscriptionInfo::subpublications, _SubscriptionInfo::subretaindeadtuples, _SubscriptionInfo::subrunasowner, _SubscriptionInfo::subslotname, _SubscriptionInfo::substream, _SubscriptionInfo::subsynccommit, and _SubscriptionInfo::subtwophasestate.

Referenced by dumpDumpableObject().

◆ dumpSubscriptionTable()

static void dumpSubscriptionTable ( Archive fout,
const SubRelInfo subrinfo 
)
static

Definition at line 5427 of file pg_dump.c.

5428{
5429 DumpOptions *dopt = fout->dopt;
5430 SubscriptionInfo *subinfo = subrinfo->subinfo;
5431 PQExpBuffer query;
5432 char *tag;
5433
5434 /* Do nothing if not dumping schema */
5435 if (!dopt->dumpSchema)
5436 return;
5437
5438 Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
5439
5440 tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->tblinfo->dobj.name);
5441
5442 query = createPQExpBuffer();
5443
5444 if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5445 {
5446 /*
5447 * binary_upgrade_add_sub_rel_state will add the subscription relation
5448 * to pg_subscription_rel table. This will be used only in
5449 * binary-upgrade mode.
5450 */
5452 "\n-- For binary upgrade, must preserve the subscriber table.\n");
5454 "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
5455 appendStringLiteralAH(query, subinfo->dobj.name, fout);
5456 appendPQExpBuffer(query,
5457 ", %u, '%c'",
5458 subrinfo->tblinfo->dobj.catId.oid,
5459 subrinfo->srsubstate);
5460
5461 if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
5462 appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
5463 else
5464 appendPQExpBufferStr(query, ", NULL");
5465
5466 appendPQExpBufferStr(query, ");\n");
5467 }
5468
5469 /*
5470 * There is no point in creating a drop query as the drop is done by table
5471 * drop. (If you think to change this, see also _printTocEntry().)
5472 * Although this object doesn't really have ownership as such, set the
5473 * owner field anyway to ensure that the command is run by the correct
5474 * role at restore time.
5475 */
5476 if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5477 ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
5478 ARCHIVE_OPTS(.tag = tag,
5479 .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
5480 .owner = subinfo->rolname,
5481 .description = "SUBSCRIPTION TABLE",
5482 .section = SECTION_POST_DATA,
5483 .createStmt = query->data));
5484
5485 /* These objects can't currently have comments or seclabels */
5486
5487 free(tag);
5488 destroyPQExpBuffer(query);
5489}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), Assert, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), _SubscriptionInfo::dobj, _dumpableObject::dump, DUMP_COMPONENT_DEFINITION, _dumpOptions::dumpSchema, fb(), free, _dumpableObject::name, psprintf(), _SubscriptionInfo::rolname, and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ dumpTable()

static void dumpTable ( Archive fout,
const TableInfo tbinfo 
)
static

Definition at line 16881 of file pg_dump.c.

16882{
16883 DumpOptions *dopt = fout->dopt;
16885 char *namecopy;
16886
16887 /* Do nothing if not dumping schema */
16888 if (!dopt->dumpSchema)
16889 return;
16890
16891 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16892 {
16893 if (tbinfo->relkind == RELKIND_SEQUENCE)
16895 else
16897 }
16898
16899 /* Handle the ACL here */
16900 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
16901 if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
16902 {
16903 const char *objtype =
16904 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
16905
16907 dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
16908 objtype, namecopy, NULL,
16909 tbinfo->dobj.namespace->dobj.name,
16910 NULL, tbinfo->rolname, &tbinfo->dacl);
16911 }
16912
16913 /*
16914 * Handle column ACLs, if any. Note: we pull these with a separate query
16915 * rather than trying to fetch them during getTableAttrs, so that we won't
16916 * miss ACLs on system columns. Doing it this way also allows us to dump
16917 * ACLs for catalogs that we didn't mark "interesting" back in getTables.
16918 */
16919 if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
16920 {
16922 PGresult *res;
16923 int i;
16924
16925 if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
16926 {
16927 /* Set up query for column ACLs */
16929 "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
16930
16931 if (fout->remoteVersion >= 90600)
16932 {
16933 /*
16934 * In principle we should call acldefault('c', relowner) to
16935 * get the default ACL for a column. However, we don't
16936 * currently store the numeric OID of the relowner in
16937 * TableInfo. We could convert the owner name using regrole,
16938 * but that creates a risk of failure due to concurrent role
16939 * renames. Given that the default ACL for columns is empty
16940 * and is likely to stay that way, it's not worth extra cycles
16941 * and risk to avoid hard-wiring that knowledge here.
16942 */
16944 "SELECT at.attname, "
16945 "at.attacl, "
16946 "'{}' AS acldefault, "
16947 "pip.privtype, pip.initprivs "
16948 "FROM pg_catalog.pg_attribute at "
16949 "LEFT JOIN pg_catalog.pg_init_privs pip ON "
16950 "(at.attrelid = pip.objoid "
16951 "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
16952 "AND at.attnum = pip.objsubid) "
16953 "WHERE at.attrelid = $1 AND "
16954 "NOT at.attisdropped "
16955 "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
16956 "ORDER BY at.attnum");
16957 }
16958 else
16959 {
16961 "SELECT attname, attacl, '{}' AS acldefault, "
16962 "NULL AS privtype, NULL AS initprivs "
16963 "FROM pg_catalog.pg_attribute "
16964 "WHERE attrelid = $1 AND NOT attisdropped "
16965 "AND attacl IS NOT NULL "
16966 "ORDER BY attnum");
16967 }
16968
16969 ExecuteSqlStatement(fout, query->data);
16970
16971 fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
16972 }
16973
16974 printfPQExpBuffer(query,
16975 "EXECUTE getColumnACLs('%u')",
16976 tbinfo->dobj.catId.oid);
16977
16978 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16979
16980 for (i = 0; i < PQntuples(res); i++)
16981 {
16982 char *attname = PQgetvalue(res, i, 0);
16983 char *attacl = PQgetvalue(res, i, 1);
16984 char *acldefault = PQgetvalue(res, i, 2);
16985 char privtype = *(PQgetvalue(res, i, 3));
16986 char *initprivs = PQgetvalue(res, i, 4);
16988 char *attnamecopy;
16989
16990 coldacl.acl = attacl;
16991 coldacl.acldefault = acldefault;
16992 coldacl.privtype = privtype;
16993 coldacl.initprivs = initprivs;
16995
16996 /*
16997 * Column's GRANT type is always TABLE. Each column ACL depends
16998 * on the table-level ACL, since we can restore column ACLs in
16999 * parallel but the table-level ACL has to be done first.
17000 */
17001 dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
17002 "TABLE", namecopy, attnamecopy,
17003 tbinfo->dobj.namespace->dobj.name,
17004 NULL, tbinfo->rolname, &coldacl);
17006 }
17007 PQclear(res);
17008 destroyPQExpBuffer(query);
17009 }
17010
17011 free(namecopy);
17012}

References _dumpableAcl::acl, acldefault(), appendPQExpBufferStr(), attname, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_ACL, DUMP_COMPONENT_DEFINITION, dumpACL(), _dumpOptions::dumpSchema, dumpSequence(), dumpTableSchema(), ExecuteSqlQuery(), ExecuteSqlStatement(), fb(), fmtId(), free, i, InvalidDumpId, pg_strdup(), PGRES_TUPLES_OK, PQclear, PQgetvalue, PQntuples, PREPQUERY_GETCOLUMNACLS, and printfPQExpBuffer().

Referenced by dumpDumpableObject().

◆ dumpTableAttach()

static void dumpTableAttach ( Archive fout,
const TableAttachInfo attachinfo 
)
static

Definition at line 18125 of file pg_dump.c.

18126{
18127 DumpOptions *dopt = fout->dopt;
18128 PQExpBuffer q;
18129 PGresult *res;
18130 char *partbound;
18131
18132 /* Do nothing if not dumping schema */
18133 if (!dopt->dumpSchema)
18134 return;
18135
18136 q = createPQExpBuffer();
18137
18138 if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
18139 {
18140 /* Set up query for partbound details */
18142 "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
18143
18145 "SELECT pg_get_expr(c.relpartbound, c.oid) "
18146 "FROM pg_class c "
18147 "WHERE c.oid = $1");
18148
18150
18151 fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
18152 }
18153
18155 "EXECUTE dumpTableAttach('%u')",
18156 attachinfo->partitionTbl->dobj.catId.oid);
18157
18159 partbound = PQgetvalue(res, 0, 0);
18160
18161 /* Perform ALTER TABLE on the parent */
18163 "ALTER TABLE ONLY %s ",
18164 fmtQualifiedDumpable(attachinfo->parentTbl));
18166 "ATTACH PARTITION %s %s;\n",
18167 fmtQualifiedDumpable(attachinfo->partitionTbl),
18168 partbound);
18169
18170 /*
18171 * There is no point in creating a drop query as the drop is done by table
18172 * drop. (If you think to change this, see also _printTocEntry().)
18173 * Although this object doesn't really have ownership as such, set the
18174 * owner field anyway to ensure that the command is run by the correct
18175 * role at restore time.
18176 */
18177 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
18178 ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
18179 .namespace = attachinfo->dobj.namespace->dobj.name,
18180 .owner = attachinfo->partitionTbl->rolname,
18181 .description = "TABLE ATTACH",
18182 .section = SECTION_PRE_DATA,
18183 .createStmt = q->data));
18184
18185 PQclear(res);
18187}

References appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), _dumpOptions::dumpSchema, ExecuteSqlQueryForSingleRow(), ExecuteSqlStatement(), fb(), fmtQualifiedDumpable, PQclear, PQgetvalue, PREPQUERY_DUMPTABLEATTACH, printfPQExpBuffer(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpTableComment()

static void dumpTableComment ( Archive fout,
const TableInfo tbinfo,
const char reltypename 
)
static

Definition at line 11418 of file pg_dump.c.

11420{
11421 DumpOptions *dopt = fout->dopt;
11423 int ncomments;
11424 PQExpBuffer query;
11425 PQExpBuffer tag;
11426
11427 /* do nothing, if --no-comments is supplied */
11428 if (dopt->no_comments)
11429 return;
11430
11431 /* Comments are SCHEMA not data */
11432 if (!dopt->dumpSchema)
11433 return;
11434
11435 /* Search for comments associated with relation, using table */
11436 ncomments = findComments(tbinfo->dobj.catId.tableoid,
11437 tbinfo->dobj.catId.oid,
11438 &comments);
11439
11440 /* If comments exist, build COMMENT ON statements */
11441 if (ncomments <= 0)
11442 return;
11443
11444 query = createPQExpBuffer();
11445 tag = createPQExpBuffer();
11446
11447 while (ncomments > 0)
11448 {
11449 const char *descr = comments->descr;
11450 int objsubid = comments->objsubid;
11451
11452 if (objsubid == 0)
11453 {
11454 resetPQExpBuffer(tag);
11455 appendPQExpBuffer(tag, "%s %s", reltypename,
11456 fmtId(tbinfo->dobj.name));
11457
11458 resetPQExpBuffer(query);
11459 appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
11461 appendStringLiteralAH(query, descr, fout);
11462 appendPQExpBufferStr(query, ";\n");
11463
11465 ARCHIVE_OPTS(.tag = tag->data,
11466 .namespace = tbinfo->dobj.namespace->dobj.name,
11467 .owner = tbinfo->rolname,
11468 .description = "COMMENT",
11469 .section = SECTION_NONE,
11470 .createStmt = query->data,
11471 .deps = &(tbinfo->dobj.dumpId),
11472 .nDeps = 1));
11473 }
11474 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
11475 {
11476 resetPQExpBuffer(tag);
11477 appendPQExpBuffer(tag, "COLUMN %s.",
11478 fmtId(tbinfo->dobj.name));
11479 appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
11480
11481 resetPQExpBuffer(query);
11482 appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11484 appendPQExpBuffer(query, "%s IS ",
11485 fmtId(tbinfo->attnames[objsubid - 1]));
11486 appendStringLiteralAH(query, descr, fout);
11487 appendPQExpBufferStr(query, ";\n");
11488
11490 ARCHIVE_OPTS(.tag = tag->data,
11491 .namespace = tbinfo->dobj.namespace->dobj.name,
11492 .owner = tbinfo->rolname,
11493 .description = "COMMENT",
11494 .section = SECTION_NONE,
11495 .createStmt = query->data,
11496 .deps = &(tbinfo->dobj.dumpId),
11497 .nDeps = 1));
11498 }
11499
11500 comments++;
11501 ncomments--;
11502 }
11503
11504 destroyPQExpBuffer(query);
11505 destroyPQExpBuffer(tag);
11506}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), comments, createDumpId(), createPQExpBuffer(), PQExpBufferData::data, CommentItem::descr, destroyPQExpBuffer(), _dumpOptions::dumpSchema, fb(), findComments(), fmtId(), fmtQualifiedDumpable, ncomments, nilCatalogId, _dumpOptions::no_comments, CommentItem::objsubid, resetPQExpBuffer(), and SECTION_NONE.

Referenced by dumpTableSchema().

◆ dumpTableConstraintComment()

static void dumpTableConstraintComment ( Archive fout,
const ConstraintInfo coninfo 
)
static

Definition at line 19078 of file pg_dump.c.

19079{
19080 TableInfo *tbinfo = coninfo->contable;
19082 char *qtabname;
19083
19084 qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19085
19086 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
19087 fmtId(coninfo->dobj.name));
19088
19089 if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19091 tbinfo->dobj.namespace->dobj.name,
19092 tbinfo->rolname,
19093 coninfo->dobj.catId, 0,
19094 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
19095
19097 free(qtabname);
19098}

References appendPQExpBuffer(), createPQExpBuffer(), destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, dumpComment(), fb(), fmtId(), free, and pg_strdup().

Referenced by dumpConstraint(), and dumpTableSchema().

◆ dumpTableData()

static void dumpTableData ( Archive fout,
const TableDataInfo tdinfo 
)
static

Definition at line 2884 of file pg_dump.c.

2885{
2886 DumpOptions *dopt = fout->dopt;
2887 const TableInfo *tbinfo = tdinfo->tdtable;
2890 DataDumperPtr dumpFn;
2891 char *tdDefn = NULL;
2892 char *copyStmt;
2893 const char *copyFrom;
2894
2895 /* We had better have loaded per-column details about this table */
2896 Assert(tbinfo->interesting);
2897
2898 /*
2899 * When load-via-partition-root is set or forced, get the root table name
2900 * for the partition table, so that we can reload data through the root
2901 * table. Then construct a comment to be inserted into the TOC entry's
2902 * defn field, so that such cases can be identified reliably.
2903 */
2904 if (tbinfo->ispartition &&
2905 (dopt->load_via_partition_root ||
2907 {
2908 const TableInfo *parentTbinfo;
2909 char *sanitized;
2910
2914 printfPQExpBuffer(copyBuf, "-- load via partition root %s",
2915 sanitized);
2916 free(sanitized);
2917 tdDefn = pg_strdup(copyBuf->data);
2918 }
2919 else
2921
2922 if (dopt->dump_inserts == 0)
2923 {
2924 /* Dump/restore using COPY */
2925 dumpFn = dumpTableData_copy;
2926 /* must use 2 steps here 'cause fmtId is nonreentrant */
2927 printfPQExpBuffer(copyBuf, "COPY %s ",
2928 copyFrom);
2929 appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2931 copyStmt = copyBuf->data;
2932 }
2933 else
2934 {
2935 /* Restore using INSERT */
2936 dumpFn = dumpTableData_insert;
2937 copyStmt = NULL;
2938 }
2939
2940 /*
2941 * Note: although the TableDataInfo is a full DumpableObject, we treat its
2942 * dependency on its table as "special" and pass it to ArchiveEntry now.
2943 * See comments for BuildArchiveDependencies.
2944 */
2945 if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2946 {
2947 TocEntry *te;
2948
2949 te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2950 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2951 .namespace = tbinfo->dobj.namespace->dobj.name,
2952 .owner = tbinfo->rolname,
2953 .description = "TABLE DATA",
2954 .section = SECTION_DATA,
2955 .createStmt = tdDefn,
2956 .copyStmt = copyStmt,
2957 .deps = &(tbinfo->dobj.dumpId),
2958 .nDeps = 1,
2959 .dumpFn = dumpFn,
2960 .dumpArg = tdinfo));
2961
2962 /*
2963 * Set the TocEntry's dataLength in case we are doing a parallel dump
2964 * and want to order dump jobs by table size. We choose to measure
2965 * dataLength in table pages (including TOAST pages) during dump, so
2966 * no scaling is needed.
2967 *
2968 * However, relpages is declared as "integer" in pg_class, and hence
2969 * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2970 * Cast so that we get the right interpretation of table sizes
2971 * exceeding INT_MAX pages.
2972 */
2973 te->dataLength = (BlockNumber) tbinfo->relpages;
2974 te->dataLength += (BlockNumber) tbinfo->toastpages;
2975
2976 /*
2977 * If pgoff_t is only 32 bits wide, the above refinement is useless,
2978 * and instead we'd better worry about integer overflow. Clamp to
2979 * INT_MAX if the correct result exceeds that.
2980 */
2981 if (sizeof(te->dataLength) == 4 &&
2982 (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
2983 te->dataLength < 0))
2984 te->dataLength = INT_MAX;
2985 }
2986
2989}

References appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), Assert, createPQExpBuffer(), _tocEntry::dataLength, destroyPQExpBuffer(), DUMP_COMPONENT_DATA, _dumpOptions::dump_inserts, dumpTableData_copy(), dumpTableData_insert(), fb(), fmtCopyColumnList(), fmtQualifiedDumpable, forcePartitionRootLoad(), free, getRootTableInfo(), _dumpOptions::load_via_partition_root, pg_strdup(), printfPQExpBuffer(), sanitize_line(), and SECTION_DATA.

Referenced by dumpDumpableObject().

◆ dumpTableData_copy()

static int dumpTableData_copy ( Archive fout,
const void dcontext 
)
static

Definition at line 2394 of file pg_dump.c.

2395{
2396 const TableDataInfo *tdinfo = dcontext;
2397 const TableInfo *tbinfo = tdinfo->tdtable;
2398 const char *classname = tbinfo->dobj.name;
2400
2401 /*
2402 * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
2403 * which uses it already.
2404 */
2407 PGresult *res;
2408 int ret;
2409 char *copybuf;
2410 const char *column_list;
2411
2412 pg_log_info("dumping contents of table \"%s.%s\"",
2413 tbinfo->dobj.namespace->dobj.name, classname);
2414
2415 /*
2416 * Specify the column list explicitly so that we have no possibility of
2417 * retrieving data in the wrong column order. (The default column
2418 * ordering of COPY will not be what we want in certain corner cases
2419 * involving ADD COLUMN and inheritance.)
2420 */
2422
2423 /*
2424 * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
2425 * a filter condition was specified. For other cases a simple COPY
2426 * suffices.
2427 */
2428 if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2429 {
2430 /* Temporary allows to access to foreign tables to dump data */
2431 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2433
2434 appendPQExpBufferStr(q, "COPY (SELECT ");
2435 /* klugery to get rid of parens in column list */
2436 if (strlen(column_list) > 2)
2437 {
2439 q->data[q->len - 1] = ' ';
2440 }
2441 else
2442 appendPQExpBufferStr(q, "* ");
2443
2444 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
2446 tdinfo->filtercond ? tdinfo->filtercond : "");
2447 }
2448 else
2449 {
2450 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
2452 column_list);
2453 }
2455 PQclear(res);
2457
2458 for (;;)
2459 {
2460 ret = PQgetCopyData(conn, &copybuf, 0);
2461
2462 if (ret < 0)
2463 break; /* done or error */
2464
2465 if (copybuf)
2466 {
2467 WriteData(fout, copybuf, ret);
2469 }
2470
2471 /* ----------
2472 * THROTTLE:
2473 *
2474 * There was considerable discussion in late July, 2000 regarding
2475 * slowing down pg_dump when backing up large tables. Users with both
2476 * slow & fast (multi-processor) machines experienced performance
2477 * degradation when doing a backup.
2478 *
2479 * Initial attempts based on sleeping for a number of ms for each ms
2480 * of work were deemed too complex, then a simple 'sleep in each loop'
2481 * implementation was suggested. The latter failed because the loop
2482 * was too tight. Finally, the following was implemented:
2483 *
2484 * If throttle is non-zero, then
2485 * See how long since the last sleep.
2486 * Work out how long to sleep (based on ratio).
2487 * If sleep is more than 100ms, then
2488 * sleep
2489 * reset timer
2490 * EndIf
2491 * EndIf
2492 *
2493 * where the throttle value was the number of ms to sleep per ms of
2494 * work. The calculation was done in each loop.
2495 *
2496 * Most of the hard work is done in the backend, and this solution
2497 * still did not work particularly well: on slow machines, the ratio
2498 * was 50:1, and on medium paced machines, 1:1, and on fast
2499 * multi-processor machines, it had little or no effect, for reasons
2500 * that were unclear.
2501 *
2502 * Further discussion ensued, and the proposal was dropped.
2503 *
2504 * For those people who want this feature, it can be implemented using
2505 * gettimeofday in each loop, calculating the time since last sleep,
2506 * multiplying that by the sleep ratio, then if the result is more
2507 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
2508 * function to sleep for a subsecond period ie.
2509 *
2510 * select(0, NULL, NULL, NULL, &tvi);
2511 *
2512 * This will return after the interval specified in the structure tvi.
2513 * Finally, call gettimeofday again to save the 'last sleep time'.
2514 * ----------
2515 */
2516 }
2517 archprintf(fout, "\\.\n\n\n");
2518
2519 if (ret == -2)
2520 {
2521 /* copy data transfer failed */
2522 pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
2523 pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2524 pg_log_error_detail("Command was: %s", q->data);
2525 exit_nicely(1);
2526 }
2527
2528 /* Check command status and return to normal libpq state */
2529 res = PQgetResult(conn);
2530 if (PQresultStatus(res) != PGRES_COMMAND_OK)
2531 {
2532 pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
2533 pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2534 pg_log_error_detail("Command was: %s", q->data);
2535 exit_nicely(1);
2536 }
2537 PQclear(res);
2538
2539 /* Do this to ensure we've pumped libpq back to idle state */
2540 if (PQgetResult(conn) != NULL)
2541 pg_log_warning("unexpected extra results during COPY of table \"%s\"",
2542 classname);
2543
2545
2546 /* Revert back the setting */
2547 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2548 set_restrict_relation_kind(fout, "view, foreign-table");
2549
2550 return 1;
2551}

References appendPQExpBuffer(), appendPQExpBufferStr(), archprintf(), conn, copybuf, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), _tableInfo::dobj, ExecuteSqlQuery(), exit_nicely(), fb(), fmtCopyColumnList(), fmtQualifiedDumpable, GetConnection(), PQExpBufferData::len, _dumpableObject::name, pg_log_error, pg_log_error_detail, pg_log_info, pg_log_warning, PGRES_COMMAND_OK, PGRES_COPY_OUT, PQclear, PQerrorMessage(), PQfreemem(), PQgetCopyData(), PQgetResult, PQresultStatus, set_restrict_relation_kind(), and WriteData().

Referenced by dumpTableData().

◆ dumpTableData_insert()

static int dumpTableData_insert ( Archive fout,
const void dcontext 
)
static

Definition at line 2562 of file pg_dump.c.

2563{
2564 const TableDataInfo *tdinfo = dcontext;
2565 const TableInfo *tbinfo = tdinfo->tdtable;
2566 DumpOptions *dopt = fout->dopt;
2569 char *attgenerated;
2570 PGresult *res;
2571 int nfields,
2572 i;
2573 int rows_per_statement = dopt->dump_inserts;
2574 int rows_this_statement = 0;
2575
2576 /* Temporary allows to access to foreign tables to dump data */
2577 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2579
2580 /*
2581 * If we're going to emit INSERTs with column names, the most efficient
2582 * way to deal with generated columns is to exclude them entirely. For
2583 * INSERTs without column names, we have to emit DEFAULT rather than the
2584 * actual column value --- but we can save a few cycles by fetching nulls
2585 * rather than the uninteresting-to-us value.
2586 */
2587 attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
2588 appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
2589 nfields = 0;
2590 for (i = 0; i < tbinfo->numatts; i++)
2591 {
2592 if (tbinfo->attisdropped[i])
2593 continue;
2594 if (tbinfo->attgenerated[i] && dopt->column_inserts)
2595 continue;
2596 if (nfields > 0)
2597 appendPQExpBufferStr(q, ", ");
2598 if (tbinfo->attgenerated[i])
2599 appendPQExpBufferStr(q, "NULL");
2600 else
2601 appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
2602 attgenerated[nfields] = tbinfo->attgenerated[i];
2603 nfields++;
2604 }
2605 /* Servers before 9.4 will complain about zero-column SELECT */
2606 if (nfields == 0)
2607 appendPQExpBufferStr(q, "NULL");
2608 appendPQExpBuffer(q, " FROM ONLY %s",
2610 if (tdinfo->filtercond)
2611 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
2612
2614
2615 while (1)
2616 {
2617 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
2619
2620 /* cross-check field count, allowing for dummy NULL if any */
2621 if (nfields != PQnfields(res) &&
2622 !(nfields == 0 && PQnfields(res) == 1))
2623 pg_fatal("wrong number of fields retrieved from table \"%s\"",
2624 tbinfo->dobj.name);
2625
2626 /*
2627 * First time through, we build as much of the INSERT statement as
2628 * possible in "insertStmt", which we can then just print for each
2629 * statement. If the table happens to have zero dumpable columns then
2630 * this will be a complete statement, otherwise it will end in
2631 * "VALUES" and be ready to have the row's column values printed.
2632 */
2633 if (insertStmt == NULL)
2634 {
2635 const TableInfo *targettab;
2636
2638
2639 /*
2640 * When load-via-partition-root is set or forced, get the root
2641 * table name for the partition table, so that we can reload data
2642 * through the root table.
2643 */
2644 if (tbinfo->ispartition &&
2645 (dopt->load_via_partition_root ||
2648 else
2649 targettab = tbinfo;
2650
2651 appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
2653
2654 /* corner case for zero-column table */
2655 if (nfields == 0)
2656 {
2657 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
2658 }
2659 else
2660 {
2661 /* append the list of column names if required */
2662 if (dopt->column_inserts)
2663 {
2665 for (int field = 0; field < nfields; field++)
2666 {
2667 if (field > 0)
2670 fmtId(PQfname(res, field)));
2671 }
2673 }
2674
2675 if (tbinfo->needs_override)
2676 appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
2677
2679 }
2680 }
2681
2682 for (int tuple = 0; tuple < PQntuples(res); tuple++)
2683 {
2684 /* Write the INSERT if not in the middle of a multi-row INSERT. */
2685 if (rows_this_statement == 0)
2686 archputs(insertStmt->data, fout);
2687
2688 /*
2689 * If it is zero-column table then we've already written the
2690 * complete statement, which will mean we've disobeyed
2691 * --rows-per-insert when it's set greater than 1. We do support
2692 * a way to make this multi-row with: SELECT UNION ALL SELECT
2693 * UNION ALL ... but that's non-standard so we should avoid it
2694 * given that using INSERTs is mostly only ever needed for
2695 * cross-database exports.
2696 */
2697 if (nfields == 0)
2698 continue;
2699
2700 /* Emit a row heading */
2701 if (rows_per_statement == 1)
2702 archputs(" (", fout);
2703 else if (rows_this_statement > 0)
2704 archputs(",\n\t(", fout);
2705 else
2706 archputs("\n\t(", fout);
2707
2708 for (int field = 0; field < nfields; field++)
2709 {
2710 if (field > 0)
2711 archputs(", ", fout);
2712 if (attgenerated[field])
2713 {
2714 archputs("DEFAULT", fout);
2715 continue;
2716 }
2717 if (PQgetisnull(res, tuple, field))
2718 {
2719 archputs("NULL", fout);
2720 continue;
2721 }
2722
2723 /* XXX This code is partially duplicated in ruleutils.c */
2724 switch (PQftype(res, field))
2725 {
2726 case INT2OID:
2727 case INT4OID:
2728 case INT8OID:
2729 case OIDOID:
2730 case FLOAT4OID:
2731 case FLOAT8OID:
2732 case NUMERICOID:
2733 {
2734 /*
2735 * These types are printed without quotes unless
2736 * they contain values that aren't accepted by the
2737 * scanner unquoted (e.g., 'NaN'). Note that
2738 * strtod() and friends might accept NaN, so we
2739 * can't use that to test.
2740 *
2741 * In reality we only need to defend against
2742 * infinity and NaN, so we need not get too crazy
2743 * about pattern matching here.
2744 */
2745 const char *s = PQgetvalue(res, tuple, field);
2746
2747 if (strspn(s, "0123456789 +-eE.") == strlen(s))
2748 archputs(s, fout);
2749 else
2750 archprintf(fout, "'%s'", s);
2751 }
2752 break;
2753
2754 case BITOID:
2755 case VARBITOID:
2756 archprintf(fout, "B'%s'",
2757 PQgetvalue(res, tuple, field));
2758 break;
2759
2760 case BOOLOID:
2761 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2762 archputs("true", fout);
2763 else
2764 archputs("false", fout);
2765 break;
2766
2767 default:
2768 /* All other types are printed as string literals. */
2771 PQgetvalue(res, tuple, field),
2772 fout);
2773 archputs(q->data, fout);
2774 break;
2775 }
2776 }
2777
2778 /* Terminate the row ... */
2779 archputs(")", fout);
2780
2781 /* ... and the statement, if the target no. of rows is reached */
2783 {
2784 if (dopt->do_nothing)
2785 archputs(" ON CONFLICT DO NOTHING;\n", fout);
2786 else
2787 archputs(";\n", fout);
2788 /* Reset the row counter */
2790 }
2791 }
2792
2793 if (PQntuples(res) <= 0)
2794 {
2795 PQclear(res);
2796 break;
2797 }
2798 PQclear(res);
2799 }
2800
2801 /* Terminate any statements that didn't make the row count. */
2802 if (rows_this_statement > 0)
2803 {
2804 if (dopt->do_nothing)
2805 archputs(" ON CONFLICT DO NOTHING;\n", fout);
2806 else
2807 archputs(";\n", fout);
2808 }
2809
2810 archputs("\n\n", fout);
2811
2812 ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2813
2815 if (insertStmt != NULL)
2817 free(attgenerated);
2818
2819 /* Revert back the setting */
2820 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2821 set_restrict_relation_kind(fout, "view, foreign-table");
2822
2823 return 1;
2824}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), appendStringLiteralAH, archprintf(), archputs(), _dumpOptions::column_inserts, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), _dumpOptions::do_nothing, _dumpOptions::dump_inserts, ExecuteSqlQuery(), ExecuteSqlStatement(), fb(), fmtId(), fmtQualifiedDumpable, forcePartitionRootLoad(), free, getRootTableInfo(), i, _dumpOptions::load_via_partition_root, pg_fatal, pg_malloc(), PGRES_TUPLES_OK, PQclear, PQfname, PQftype(), PQgetisnull, PQgetvalue, PQnfields, PQntuples, resetPQExpBuffer(), and set_restrict_relation_kind().

Referenced by dumpTableData().

◆ dumpTableSchema()

static void dumpTableSchema ( Archive fout,
const TableInfo tbinfo 
)
static

Definition at line 17110 of file pg_dump.c.

17111{
17112 DumpOptions *dopt = fout->dopt;
17116 char *qrelname;
17117 char *qualrelname;
17118 int numParents;
17119 TableInfo **parents;
17120 int actual_atts; /* number of attrs in this CREATE statement */
17121 const char *reltypename;
17122 char *storage;
17123 int j,
17124 k;
17125
17126 /* We had better have loaded per-column details about this table */
17127 Assert(tbinfo->interesting);
17128
17129 qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
17131
17132 if (tbinfo->hasoids)
17133 pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
17134 qrelname);
17135
17136 if (dopt->binary_upgrade)
17138
17139 /* Is it a table or a view? */
17140 if (tbinfo->relkind == RELKIND_VIEW)
17141 {
17142 PQExpBuffer result;
17143
17144 /*
17145 * Note: keep this code in sync with the is_view case in dumpRule()
17146 */
17147
17148 reltypename = "VIEW";
17149
17150 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
17151
17152 if (dopt->binary_upgrade)
17154 tbinfo->dobj.catId.oid);
17155
17156 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
17157
17158 if (tbinfo->dummy_view)
17160 else
17161 {
17162 if (nonemptyReloptions(tbinfo->reloptions))
17163 {
17164 appendPQExpBufferStr(q, " WITH (");
17165 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
17166 appendPQExpBufferChar(q, ')');
17167 }
17168 result = createViewAsClause(fout, tbinfo);
17169 }
17170 appendPQExpBuffer(q, " AS\n%s", result->data);
17171 destroyPQExpBuffer(result);
17172
17173 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
17174 appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
17175 appendPQExpBufferStr(q, ";\n");
17176 }
17177 else
17178 {
17179 char *partkeydef = NULL;
17180 char *ftoptions = NULL;
17181 char *srvname = NULL;
17182 const char *foreign = "";
17183
17184 /*
17185 * Set reltypename, and collect any relkind-specific data that we
17186 * didn't fetch during getTables().
17187 */
17188 switch (tbinfo->relkind)
17189 {
17191 {
17193 PGresult *res;
17194
17195 reltypename = "TABLE";
17196
17197 /* retrieve partition key definition */
17198 appendPQExpBuffer(query,
17199 "SELECT pg_get_partkeydef('%u')",
17200 tbinfo->dobj.catId.oid);
17201 res = ExecuteSqlQueryForSingleRow(fout, query->data);
17202 partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
17203 PQclear(res);
17204 destroyPQExpBuffer(query);
17205 break;
17206 }
17208 {
17210 PGresult *res;
17211 int i_srvname;
17212 int i_ftoptions;
17213
17214 reltypename = "FOREIGN TABLE";
17215
17216 /* retrieve name of foreign server and generic options */
17217 appendPQExpBuffer(query,
17218 "SELECT fs.srvname, "
17219 "pg_catalog.array_to_string(ARRAY("
17220 "SELECT pg_catalog.quote_ident(option_name) || "
17221 "' ' || pg_catalog.quote_literal(option_value) "
17222 "FROM pg_catalog.pg_options_to_table(ftoptions) "
17223 "ORDER BY option_name"
17224 "), E',\n ') AS ftoptions "
17225 "FROM pg_catalog.pg_foreign_table ft "
17226 "JOIN pg_catalog.pg_foreign_server fs "
17227 "ON (fs.oid = ft.ftserver) "
17228 "WHERE ft.ftrelid = '%u'",
17229 tbinfo->dobj.catId.oid);
17230 res = ExecuteSqlQueryForSingleRow(fout, query->data);
17231 i_srvname = PQfnumber(res, "srvname");
17232 i_ftoptions = PQfnumber(res, "ftoptions");
17235 PQclear(res);
17236 destroyPQExpBuffer(query);
17237
17238 foreign = "FOREIGN ";
17239 break;
17240 }
17241 case RELKIND_MATVIEW:
17242 reltypename = "MATERIALIZED VIEW";
17243 break;
17244 default:
17245 reltypename = "TABLE";
17246 break;
17247 }
17248
17249 numParents = tbinfo->numParents;
17250 parents = tbinfo->parents;
17251
17252 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
17253
17254 if (dopt->binary_upgrade)
17256 tbinfo->dobj.catId.oid);
17257
17258 /*
17259 * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
17260 * ignore it when dumping if it was set in this case.
17261 */
17262 appendPQExpBuffer(q, "CREATE %s%s %s",
17263 (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
17264 tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
17265 "UNLOGGED " : "",
17267 qualrelname);
17268
17269 /*
17270 * Attach to type, if reloftype; except in case of a binary upgrade,
17271 * we dump the table normally and attach it to the type afterward.
17272 */
17273 if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
17274 appendPQExpBuffer(q, " OF %s",
17275 getFormattedTypeName(fout, tbinfo->reloftype,
17276 zeroIsError));
17277
17278 if (tbinfo->relkind != RELKIND_MATVIEW)
17279 {
17280 /* Dump the attributes */
17281 actual_atts = 0;
17282 for (j = 0; j < tbinfo->numatts; j++)
17283 {
17284 /*
17285 * Normally, dump if it's locally defined in this table, and
17286 * not dropped. But for binary upgrade, we'll dump all the
17287 * columns, and then fix up the dropped and nonlocal cases
17288 * below.
17289 */
17290 if (shouldPrintColumn(dopt, tbinfo, j))
17291 {
17292 bool print_default;
17293 bool print_notnull;
17294
17295 /*
17296 * Default value --- suppress if to be printed separately
17297 * or not at all.
17298 */
17299 print_default = (tbinfo->attrdefs[j] != NULL &&
17300 tbinfo->attrdefs[j]->dobj.dump &&
17301 !tbinfo->attrdefs[j]->separate);
17302
17303 /*
17304 * Not Null constraint --- print it if it is locally
17305 * defined, or if binary upgrade. (In the latter case, we
17306 * reset conislocal below.)
17307 */
17308 print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
17309 (tbinfo->notnull_islocal[j] ||
17310 dopt->binary_upgrade ||
17311 tbinfo->ispartition));
17312
17313 /*
17314 * Skip column if fully defined by reloftype, except in
17315 * binary upgrade
17316 */
17317 if (OidIsValid(tbinfo->reloftype) &&
17319 !dopt->binary_upgrade)
17320 continue;
17321
17322 /* Format properly if not first attr */
17323 if (actual_atts == 0)
17324 appendPQExpBufferStr(q, " (");
17325 else
17326 appendPQExpBufferChar(q, ',');
17327 appendPQExpBufferStr(q, "\n ");
17328 actual_atts++;
17329
17330 /* Attribute name */
17331 appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
17332
17333 if (tbinfo->attisdropped[j])
17334 {
17335 /*
17336 * ALTER TABLE DROP COLUMN clears
17337 * pg_attribute.atttypid, so we will not have gotten a
17338 * valid type name; insert INTEGER as a stopgap. We'll
17339 * clean things up later.
17340 */
17341 appendPQExpBufferStr(q, " INTEGER /* dummy */");
17342 /* and skip to the next column */
17343 continue;
17344 }
17345
17346 /*
17347 * Attribute type; print it except when creating a typed
17348 * table ('OF type_name'), but in binary-upgrade mode,
17349 * print it in that case too.
17350 */
17351 if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
17352 {
17353 appendPQExpBuffer(q, " %s",
17354 tbinfo->atttypnames[j]);
17355 }
17356
17357 if (print_default)
17358 {
17359 if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
17360 appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
17361 tbinfo->attrdefs[j]->adef_expr);
17362 else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
17363 appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
17364 tbinfo->attrdefs[j]->adef_expr);
17365 else
17366 appendPQExpBuffer(q, " DEFAULT %s",
17367 tbinfo->attrdefs[j]->adef_expr);
17368 }
17369
17370 if (print_notnull)
17371 {
17372 if (tbinfo->notnull_constrs[j][0] == '\0')
17373 appendPQExpBufferStr(q, " NOT NULL");
17374 else
17375 appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
17376 fmtId(tbinfo->notnull_constrs[j]));
17377
17378 if (tbinfo->notnull_noinh[j])
17379 appendPQExpBufferStr(q, " NO INHERIT");
17380 }
17381
17382 /* Add collation if not default for the type */
17383 if (OidIsValid(tbinfo->attcollation[j]))
17384 {
17385 CollInfo *coll;
17386
17387 coll = findCollationByOid(tbinfo->attcollation[j]);
17388 if (coll)
17389 appendPQExpBuffer(q, " COLLATE %s",
17391 }
17392 }
17393
17394 /*
17395 * On the other hand, if we choose not to print a column
17396 * (likely because it is created by inheritance), but the
17397 * column has a locally-defined not-null constraint, we need
17398 * to dump the constraint as a standalone object.
17399 *
17400 * This syntax isn't SQL-conforming, but if you wanted
17401 * standard output you wouldn't be creating non-standard
17402 * objects to begin with.
17403 */
17404 if (!shouldPrintColumn(dopt, tbinfo, j) &&
17405 !tbinfo->attisdropped[j] &&
17406 tbinfo->notnull_constrs[j] != NULL &&
17407 tbinfo->notnull_islocal[j])
17408 {
17409 /* Format properly if not first attr */
17410 if (actual_atts == 0)
17411 appendPQExpBufferStr(q, " (");
17412 else
17413 appendPQExpBufferChar(q, ',');
17414 appendPQExpBufferStr(q, "\n ");
17415 actual_atts++;
17416
17417 if (tbinfo->notnull_constrs[j][0] == '\0')
17418 appendPQExpBuffer(q, "NOT NULL %s",
17419 fmtId(tbinfo->attnames[j]));
17420 else
17421 appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
17422 tbinfo->notnull_constrs[j],
17423 fmtId(tbinfo->attnames[j]));
17424 }
17425 }
17426
17427 /*
17428 * Add non-inherited CHECK constraints, if any.
17429 *
17430 * For partitions, we need to include check constraints even if
17431 * they're not defined locally, because the ALTER TABLE ATTACH
17432 * PARTITION that we'll emit later expects the constraint to be
17433 * there. (No need to fix conislocal: ATTACH PARTITION does that)
17434 */
17435 for (j = 0; j < tbinfo->ncheck; j++)
17436 {
17437 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
17438
17439 if (constr->separate ||
17440 (!constr->conislocal && !tbinfo->ispartition))
17441 continue;
17442
17443 if (actual_atts == 0)
17444 appendPQExpBufferStr(q, " (\n ");
17445 else
17446 appendPQExpBufferStr(q, ",\n ");
17447
17448 appendPQExpBuffer(q, "CONSTRAINT %s ",
17449 fmtId(constr->dobj.name));
17450 appendPQExpBufferStr(q, constr->condef);
17451
17452 actual_atts++;
17453 }
17454
17455 if (actual_atts)
17456 appendPQExpBufferStr(q, "\n)");
17457 else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
17458 {
17459 /*
17460 * No attributes? we must have a parenthesized attribute list,
17461 * even though empty, when not using the OF TYPE syntax.
17462 */
17463 appendPQExpBufferStr(q, " (\n)");
17464 }
17465
17466 /*
17467 * Emit the INHERITS clause (not for partitions), except in
17468 * binary-upgrade mode.
17469 */
17470 if (numParents > 0 && !tbinfo->ispartition &&
17471 !dopt->binary_upgrade)
17472 {
17473 appendPQExpBufferStr(q, "\nINHERITS (");
17474 for (k = 0; k < numParents; k++)
17475 {
17476 TableInfo *parentRel = parents[k];
17477
17478 if (k > 0)
17479 appendPQExpBufferStr(q, ", ");
17481 }
17482 appendPQExpBufferChar(q, ')');
17483 }
17484
17485 if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
17486 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
17487
17488 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
17489 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
17490 }
17491
17492 if (nonemptyReloptions(tbinfo->reloptions) ||
17493 nonemptyReloptions(tbinfo->toast_reloptions))
17494 {
17495 bool addcomma = false;
17496
17497 appendPQExpBufferStr(q, "\nWITH (");
17498 if (nonemptyReloptions(tbinfo->reloptions))
17499 {
17500 addcomma = true;
17501 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
17502 }
17503 if (nonemptyReloptions(tbinfo->toast_reloptions))
17504 {
17505 if (addcomma)
17506 appendPQExpBufferStr(q, ", ");
17507 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
17508 fout);
17509 }
17510 appendPQExpBufferChar(q, ')');
17511 }
17512
17513 /* Dump generic options if any */
17514 if (ftoptions && ftoptions[0])
17515 appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
17516
17517 /*
17518 * For materialized views, create the AS clause just like a view. At
17519 * this point, we always mark the view as not populated.
17520 */
17521 if (tbinfo->relkind == RELKIND_MATVIEW)
17522 {
17523 PQExpBuffer result;
17524
17525 result = createViewAsClause(fout, tbinfo);
17526 appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
17527 result->data);
17528 destroyPQExpBuffer(result);
17529 }
17530 else
17531 appendPQExpBufferStr(q, ";\n");
17532
17533 /* Materialized views can depend on extensions */
17534 if (tbinfo->relkind == RELKIND_MATVIEW)
17536 "pg_catalog.pg_class",
17537 "MATERIALIZED VIEW",
17538 qualrelname);
17539
17540 /*
17541 * in binary upgrade mode, update the catalog with any missing values
17542 * that might be present.
17543 */
17544 if (dopt->binary_upgrade)
17545 {
17546 for (j = 0; j < tbinfo->numatts; j++)
17547 {
17548 if (tbinfo->attmissingval[j][0] != '\0')
17549 {
17550 appendPQExpBufferStr(q, "\n-- set missing value.\n");
17552 "SELECT pg_catalog.binary_upgrade_set_missing_value(");
17554 appendPQExpBufferStr(q, "::pg_catalog.regclass,");
17555 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17556 appendPQExpBufferChar(q, ',');
17557 appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
17558 appendPQExpBufferStr(q, ");\n\n");
17559 }
17560 }
17561 }
17562
17563 /*
17564 * To create binary-compatible heap files, we have to ensure the same
17565 * physical column order, including dropped columns, as in the
17566 * original. Therefore, we create dropped columns above and drop them
17567 * here, also updating their attlen/attalign values so that the
17568 * dropped column can be skipped properly. (We do not bother with
17569 * restoring the original attbyval setting.) Also, inheritance
17570 * relationships are set up by doing ALTER TABLE INHERIT rather than
17571 * using an INHERITS clause --- the latter would possibly mess up the
17572 * column order. That also means we have to take care about setting
17573 * attislocal correctly, plus fix up any inherited CHECK constraints.
17574 * Analogously, we set up typed tables using ALTER TABLE / OF here.
17575 *
17576 * We process foreign and partitioned tables here, even though they
17577 * lack heap storage, because they can participate in inheritance
17578 * relationships and we want this stuff to be consistent across the
17579 * inheritance tree. We can exclude indexes, toast tables, sequences
17580 * and matviews, even though they have storage, because we don't
17581 * support altering or dropping columns in them, nor can they be part
17582 * of inheritance trees.
17583 */
17584 if (dopt->binary_upgrade &&
17585 (tbinfo->relkind == RELKIND_RELATION ||
17586 tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
17587 tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
17588 {
17589 bool firstitem;
17590 bool firstitem_extra;
17591
17592 /*
17593 * Drop any dropped columns. Merge the pg_attribute manipulations
17594 * into a single SQL command, so that we don't cause repeated
17595 * relcache flushes on the target table. Otherwise we risk O(N^2)
17596 * relcache bloat while dropping N columns.
17597 */
17598 resetPQExpBuffer(extra);
17599 firstitem = true;
17600 for (j = 0; j < tbinfo->numatts; j++)
17601 {
17602 if (tbinfo->attisdropped[j])
17603 {
17604 if (firstitem)
17605 {
17606 appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
17607 "UPDATE pg_catalog.pg_attribute\n"
17608 "SET attlen = v.dlen, "
17609 "attalign = v.dalign, "
17610 "attbyval = false\n"
17611 "FROM (VALUES ");
17612 firstitem = false;
17613 }
17614 else
17615 appendPQExpBufferStr(q, ",\n ");
17616 appendPQExpBufferChar(q, '(');
17617 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17618 appendPQExpBuffer(q, ", %d, '%c')",
17619 tbinfo->attlen[j],
17620 tbinfo->attalign[j]);
17621 /* The ALTER ... DROP COLUMN commands must come after */
17622 appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
17624 appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
17625 fmtId(tbinfo->attnames[j]));
17626 }
17627 }
17628 if (!firstitem)
17629 {
17630 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
17631 "WHERE attrelid = ");
17633 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
17634 " AND attname = v.dname;\n");
17635 /* Now we can issue the actual DROP COLUMN commands */
17636 appendBinaryPQExpBuffer(q, extra->data, extra->len);
17637 }
17638
17639 /*
17640 * Fix up inherited columns. As above, do the pg_attribute
17641 * manipulations in a single SQL command.
17642 */
17643 firstitem = true;
17644 for (j = 0; j < tbinfo->numatts; j++)
17645 {
17646 if (!tbinfo->attisdropped[j] &&
17647 !tbinfo->attislocal[j])
17648 {
17649 if (firstitem)
17650 {
17651 appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
17652 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
17653 "SET attislocal = false\n"
17654 "WHERE attrelid = ");
17656 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
17657 " AND attname IN (");
17658 firstitem = false;
17659 }
17660 else
17661 appendPQExpBufferStr(q, ", ");
17662 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17663 }
17664 }
17665 if (!firstitem)
17666 appendPQExpBufferStr(q, ");\n");
17667
17668 /*
17669 * Fix up not-null constraints that come from inheritance. As
17670 * above, do the pg_constraint manipulations in a single SQL
17671 * command. (Actually, two in special cases, if we're doing an
17672 * upgrade from < 18).
17673 */
17674 firstitem = true;
17675 firstitem_extra = true;
17676 resetPQExpBuffer(extra);
17677 for (j = 0; j < tbinfo->numatts; j++)
17678 {
17679 /*
17680 * If a not-null constraint comes from inheritance, reset
17681 * conislocal. The inhcount is fixed by ALTER TABLE INHERIT,
17682 * below. Special hack: in versions < 18, columns with no
17683 * local definition need their constraint to be matched by
17684 * column number in conkeys instead of by constraint name,
17685 * because the latter is not available. (We distinguish the
17686 * case because the constraint name is the empty string.)
17687 */
17688 if (tbinfo->notnull_constrs[j] != NULL &&
17689 !tbinfo->notnull_islocal[j])
17690 {
17691 if (tbinfo->notnull_constrs[j][0] != '\0')
17692 {
17693 if (firstitem)
17694 {
17695 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
17696 "SET conislocal = false\n"
17697 "WHERE contype = 'n' AND conrelid = ");
17699 appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
17700 "conname IN (");
17701 firstitem = false;
17702 }
17703 else
17704 appendPQExpBufferStr(q, ", ");
17705 appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
17706 }
17707 else
17708 {
17709 if (firstitem_extra)
17710 {
17711 appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
17712 "SET conislocal = false\n"
17713 "WHERE contype = 'n' AND conrelid = ");
17715 appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
17716 "conkey IN (");
17717 firstitem_extra = false;
17718 }
17719 else
17720 appendPQExpBufferStr(extra, ", ");
17721 appendPQExpBuffer(extra, "'{%d}'", j + 1);
17722 }
17723 }
17724 }
17725 if (!firstitem)
17726 appendPQExpBufferStr(q, ");\n");
17727 if (!firstitem_extra)
17728 appendPQExpBufferStr(extra, ");\n");
17729
17730 if (extra->len > 0)
17731 appendBinaryPQExpBuffer(q, extra->data, extra->len);
17732
17733 /*
17734 * Add inherited CHECK constraints, if any.
17735 *
17736 * For partitions, they were already dumped, and conislocal
17737 * doesn't need fixing.
17738 *
17739 * As above, issue only one direct manipulation of pg_constraint.
17740 * Although it is tempting to merge the ALTER ADD CONSTRAINT
17741 * commands into one as well, refrain for now due to concern about
17742 * possible backend memory bloat if there are many such
17743 * constraints.
17744 */
17745 resetPQExpBuffer(extra);
17746 firstitem = true;
17747 for (k = 0; k < tbinfo->ncheck; k++)
17748 {
17749 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
17750
17751 if (constr->separate || constr->conislocal || tbinfo->ispartition)
17752 continue;
17753
17754 if (firstitem)
17755 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
17756 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
17758 fmtId(constr->dobj.name),
17759 constr->condef);
17760 /* Update pg_constraint after all the ALTER TABLEs */
17761 if (firstitem)
17762 {
17763 appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
17764 "SET conislocal = false\n"
17765 "WHERE contype = 'c' AND conrelid = ");
17767 appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
17768 appendPQExpBufferStr(extra, " AND conname IN (");
17769 firstitem = false;
17770 }
17771 else
17772 appendPQExpBufferStr(extra, ", ");
17773 appendStringLiteralAH(extra, constr->dobj.name, fout);
17774 }
17775 if (!firstitem)
17776 {
17777 appendPQExpBufferStr(extra, ");\n");
17778 appendBinaryPQExpBuffer(q, extra->data, extra->len);
17779 }
17780
17781 if (numParents > 0 && !tbinfo->ispartition)
17782 {
17783 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
17784 for (k = 0; k < numParents; k++)
17785 {
17786 TableInfo *parentRel = parents[k];
17787
17788 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
17791 }
17792 }
17793
17794 if (OidIsValid(tbinfo->reloftype))
17795 {
17796 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
17797 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
17799 getFormattedTypeName(fout, tbinfo->reloftype,
17800 zeroIsError));
17801 }
17802 }
17803
17804 /*
17805 * In binary_upgrade mode, arrange to restore the old relfrozenxid and
17806 * relminmxid of all vacuumable relations. (While vacuum.c processes
17807 * TOAST tables semi-independently, here we see them only as children
17808 * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
17809 * child toast table is handled below.)
17810 */
17811 if (dopt->binary_upgrade &&
17812 (tbinfo->relkind == RELKIND_RELATION ||
17813 tbinfo->relkind == RELKIND_MATVIEW))
17814 {
17815 appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
17816 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
17817 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
17818 "WHERE oid = ",
17819 tbinfo->frozenxid, tbinfo->minmxid);
17821 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
17822
17823 if (tbinfo->toast_oid)
17824 {
17825 /*
17826 * The toast table will have the same OID at restore, so we
17827 * can safely target it by OID.
17828 */
17829 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
17830 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
17831 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
17832 "WHERE oid = '%u';\n",
17833 tbinfo->toast_frozenxid,
17834 tbinfo->toast_minmxid, tbinfo->toast_oid);
17835 }
17836 }
17837
17838 /*
17839 * In binary_upgrade mode, restore matviews' populated status by
17840 * poking pg_class directly. This is pretty ugly, but we can't use
17841 * REFRESH MATERIALIZED VIEW since it's possible that some underlying
17842 * matview is not populated even though this matview is; in any case,
17843 * we want to transfer the matview's heap storage, not run REFRESH.
17844 */
17845 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
17846 tbinfo->relispopulated)
17847 {
17848 appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
17849 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
17850 "SET relispopulated = 't'\n"
17851 "WHERE oid = ");
17853 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
17854 }
17855
17856 /*
17857 * Dump additional per-column properties that we can't handle in the
17858 * main CREATE TABLE command.
17859 */
17860 for (j = 0; j < tbinfo->numatts; j++)
17861 {
17862 /* None of this applies to dropped columns */
17863 if (tbinfo->attisdropped[j])
17864 continue;
17865
17866 /*
17867 * Dump per-column statistics information. We only issue an ALTER
17868 * TABLE statement if the attstattarget entry for this column is
17869 * not the default value.
17870 */
17871 if (tbinfo->attstattarget[j] >= 0)
17872 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
17874 fmtId(tbinfo->attnames[j]),
17875 tbinfo->attstattarget[j]);
17876
17877 /*
17878 * Dump per-column storage information. The statement is only
17879 * dumped if the storage has been changed from the type's default.
17880 */
17881 if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
17882 {
17883 switch (tbinfo->attstorage[j])
17884 {
17885 case TYPSTORAGE_PLAIN:
17886 storage = "PLAIN";
17887 break;
17889 storage = "EXTERNAL";
17890 break;
17892 storage = "EXTENDED";
17893 break;
17894 case TYPSTORAGE_MAIN:
17895 storage = "MAIN";
17896 break;
17897 default:
17898 storage = NULL;
17899 }
17900
17901 /*
17902 * Only dump the statement if it's a storage type we recognize
17903 */
17904 if (storage != NULL)
17905 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
17907 fmtId(tbinfo->attnames[j]),
17908 storage);
17909 }
17910
17911 /*
17912 * Dump per-column compression, if it's been set.
17913 */
17914 if (!dopt->no_toast_compression)
17915 {
17916 const char *cmname;
17917
17918 switch (tbinfo->attcompression[j])
17919 {
17920 case 'p':
17921 cmname = "pglz";
17922 break;
17923 case 'l':
17924 cmname = "lz4";
17925 break;
17926 default:
17927 cmname = NULL;
17928 break;
17929 }
17930
17931 if (cmname != NULL)
17932 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
17934 fmtId(tbinfo->attnames[j]),
17935 cmname);
17936 }
17937
17938 /*
17939 * Dump per-column attributes.
17940 */
17941 if (tbinfo->attoptions[j][0] != '\0')
17942 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
17944 fmtId(tbinfo->attnames[j]),
17945 tbinfo->attoptions[j]);
17946
17947 /*
17948 * Dump per-column fdw options.
17949 */
17950 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
17951 tbinfo->attfdwoptions[j][0] != '\0')
17953 "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
17954 " %s\n"
17955 ");\n",
17957 fmtId(tbinfo->attnames[j]),
17958 tbinfo->attfdwoptions[j]);
17959 } /* end loop over columns */
17960
17962 free(ftoptions);
17963 free(srvname);
17964 }
17965
17966 /*
17967 * dump properties we only have ALTER TABLE syntax for
17968 */
17969 if ((tbinfo->relkind == RELKIND_RELATION ||
17970 tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
17971 tbinfo->relkind == RELKIND_MATVIEW) &&
17972 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
17973 {
17974 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
17975 {
17976 /* nothing to do, will be set when the index is dumped */
17977 }
17978 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
17979 {
17980 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
17981 qualrelname);
17982 }
17983 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
17984 {
17985 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
17986 qualrelname);
17987 }
17988 }
17989
17990 if (tbinfo->forcerowsec)
17991 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
17992 qualrelname);
17993
17994 if (dopt->binary_upgrade)
17997 tbinfo->dobj.namespace->dobj.name);
17998
17999 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18000 {
18001 char *tablespace = NULL;
18002 char *tableam = NULL;
18003
18004 /*
18005 * _selectTablespace() relies on tablespace-enabled objects in the
18006 * default tablespace to have a tablespace of "" (empty string) versus
18007 * non-tablespace-enabled objects to have a tablespace of NULL.
18008 * getTables() sets tbinfo->reltablespace to "" for the default
18009 * tablespace (not NULL).
18010 */
18011 if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
18012 tablespace = tbinfo->reltablespace;
18013
18014 if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
18016 tableam = tbinfo->amname;
18017
18018 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
18019 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
18020 .namespace = tbinfo->dobj.namespace->dobj.name,
18021 .tablespace = tablespace,
18022 .tableam = tableam,
18023 .relkind = tbinfo->relkind,
18024 .owner = tbinfo->rolname,
18025 .description = reltypename,
18026 .section = tbinfo->postponed_def ?
18028 .createStmt = q->data,
18029 .dropStmt = delq->data));
18030 }
18031
18032 /* Dump Table Comments */
18033 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18035
18036 /* Dump Table Security Labels */
18037 if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
18039
18040 /*
18041 * Dump comments for not-null constraints that aren't to be dumped
18042 * separately (those are processed by collectComments/dumpComment).
18043 */
18044 if (!fout->dopt->no_comments && dopt->dumpSchema &&
18045 fout->remoteVersion >= 180000)
18046 {
18048 PQExpBuffer tag = NULL;
18049
18050 for (j = 0; j < tbinfo->numatts; j++)
18051 {
18052 if (tbinfo->notnull_constrs[j] != NULL &&
18053 tbinfo->notnull_comment[j] != NULL)
18054 {
18055 if (comment == NULL)
18056 {
18058 tag = createPQExpBuffer();
18059 }
18060 else
18061 {
18063 resetPQExpBuffer(tag);
18064 }
18065
18066 appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
18067 fmtId(tbinfo->notnull_constrs[j]), qualrelname);
18068 appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
18070
18071 appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
18072 fmtId(tbinfo->notnull_constrs[j]), qrelname);
18073
18075 ARCHIVE_OPTS(.tag = tag->data,
18076 .namespace = tbinfo->dobj.namespace->dobj.name,
18077 .owner = tbinfo->rolname,
18078 .description = "COMMENT",
18079 .section = SECTION_NONE,
18080 .createStmt = comment->data,
18081 .deps = &(tbinfo->dobj.dumpId),
18082 .nDeps = 1));
18083 }
18084 }
18085
18087 destroyPQExpBuffer(tag);
18088 }
18089
18090 /* Dump comments on inlined table constraints */
18091 for (j = 0; j < tbinfo->ncheck; j++)
18092 {
18093 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
18094
18095 if (constr->separate || !constr->conislocal)
18096 continue;
18097
18098 if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
18100 }
18101
18104 destroyPQExpBuffer(extra);
18105 free(qrelname);
18107}

References append_depends_on_extension(), appendBinaryPQExpBuffer(), appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), appendReloptionsArrayAH(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), Assert, _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), binary_upgrade_set_pg_class_oids(), binary_upgrade_set_type_oids_by_rel(), comment, _constraintInfo::condef, _constraintInfo::conislocal, createDummyViewAsClause(), createDumpId(), createPQExpBuffer(), createViewAsClause(), PQExpBufferData::data, destroyPQExpBuffer(), _constraintInfo::dobj, _dumpableObject::dump, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, _dumpOptions::dumpSchema, dumpTableComment(), dumpTableConstraintComment(), dumpTableSecLabel(), ExecuteSqlQueryForSingleRow(), fb(), findCollationByOid(), fmtId(), fmtQualifiedDumpable, free, getFormattedTypeName(), j, PQExpBufferData::len, _dumpableObject::name, nilCatalogId, _dumpOptions::no_toast_compression, nonemptyReloptions(), OidIsValid, _tableInfo::parents, pg_log_warning, pg_strdup(), PQclear, PQfnumber(), PQgetvalue, resetPQExpBuffer(), SECTION_NONE, SECTION_POST_DATA, SECTION_PRE_DATA, _constraintInfo::separate, shouldPrintColumn(), storage, tablespace, and zeroIsError.

Referenced by dumpTable().

◆ dumpTableSecLabel()

static void dumpTableSecLabel ( Archive fout,
const TableInfo tbinfo,
const char reltypename 
)
static

Definition at line 16634 of file pg_dump.c.

16635{
16636 DumpOptions *dopt = fout->dopt;
16638 int nlabels;
16639 int i;
16640 PQExpBuffer query;
16641 PQExpBuffer target;
16642
16643 /* do nothing, if --no-security-labels is supplied */
16644 if (dopt->no_security_labels)
16645 return;
16646
16647 /* SecLabel are SCHEMA not data */
16648 if (!dopt->dumpSchema)
16649 return;
16650
16651 /* Search for comments associated with relation, using table */
16652 nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
16653 tbinfo->dobj.catId.oid,
16654 &labels);
16655
16656 /* If security labels exist, build SECURITY LABEL statements */
16657 if (nlabels <= 0)
16658 return;
16659
16660 query = createPQExpBuffer();
16661 target = createPQExpBuffer();
16662
16663 for (i = 0; i < nlabels; i++)
16664 {
16665 const char *colname;
16666 const char *provider = labels[i].provider;
16667 const char *label = labels[i].label;
16668 int objsubid = labels[i].objsubid;
16669
16670 resetPQExpBuffer(target);
16671 if (objsubid == 0)
16672 {
16673 appendPQExpBuffer(target, "%s %s", reltypename,
16675 }
16676 else
16677 {
16678 colname = getAttrName(objsubid, tbinfo);
16679 /* first fmtXXX result must be consumed before calling again */
16680 appendPQExpBuffer(target, "COLUMN %s",
16682 appendPQExpBuffer(target, ".%s", fmtId(colname));
16683 }
16684 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
16685 fmtId(provider), target->data);
16687 appendPQExpBufferStr(query, ";\n");
16688 }
16689 if (query->len > 0)
16690 {
16691 resetPQExpBuffer(target);
16692 appendPQExpBuffer(target, "%s %s", reltypename,
16693 fmtId(tbinfo->dobj.name));
16695 ARCHIVE_OPTS(.tag = target->data,
16696 .namespace = tbinfo->dobj.namespace->dobj.name,
16697 .owner = tbinfo->rolname,
16698 .description = "SECURITY LABEL",
16699 .section = SECTION_NONE,
16700 .createStmt = query->data,
16701 .deps = &(tbinfo->dobj.dumpId),
16702 .nDeps = 1));
16703 }
16704 destroyPQExpBuffer(query);
16705 destroyPQExpBuffer(target);
16706}

References appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralAH, ARCHIVE_OPTS, ArchiveEntry(), createDumpId(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), _dumpOptions::dumpSchema, fb(), findSecLabels(), fmtId(), fmtQualifiedDumpable, getAttrName(), i, label, PQExpBufferData::len, nilCatalogId, _dumpOptions::no_security_labels, resetPQExpBuffer(), and SECTION_NONE.

Referenced by dumpTableSchema().

◆ dumpTransform()

static void dumpTransform ( Archive fout,
const TransformInfo transform 
)
static

Definition at line 13994 of file pg_dump.c.

13995{
13996 DumpOptions *dopt = fout->dopt;
14003 char *lanname;
14004 const char *transformType;
14005
14006 /* Do nothing if not dumping schema */
14007 if (!dopt->dumpSchema)
14008 return;
14009
14010 /* Cannot dump if we don't have the transform functions' info */
14011 if (OidIsValid(transform->trffromsql))
14012 {
14014 if (fromsqlFuncInfo == NULL)
14015 pg_fatal("could not find function definition for function with OID %u",
14016 transform->trffromsql);
14017 }
14018 if (OidIsValid(transform->trftosql))
14019 {
14020 tosqlFuncInfo = findFuncByOid(transform->trftosql);
14021 if (tosqlFuncInfo == NULL)
14022 pg_fatal("could not find function definition for function with OID %u",
14023 transform->trftosql);
14024 }
14025
14030
14031 lanname = get_language_name(fout, transform->trflang);
14033
14034 appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
14036
14037 appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
14039
14040 if (!transform->trffromsql && !transform->trftosql)
14041 pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
14042
14043 if (transform->trffromsql)
14044 {
14045 if (fromsqlFuncInfo)
14046 {
14048
14049 /*
14050 * Always qualify the function name (format_function_signature
14051 * won't qualify it).
14052 */
14053 appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
14054 fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
14055 free(fsig);
14056 }
14057 else
14058 pg_log_warning("bogus value in pg_transform.trffromsql field");
14059 }
14060
14061 if (transform->trftosql)
14062 {
14063 if (transform->trffromsql)
14065
14066 if (tosqlFuncInfo)
14067 {
14069
14070 /*
14071 * Always qualify the function name (format_function_signature
14072 * won't qualify it).
14073 */
14074 appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
14075 fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
14076 free(fsig);
14077 }
14078 else
14079 pg_log_warning("bogus value in pg_transform.trftosql field");
14080 }
14081
14083
14084 appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
14086
14087 appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
14089
14090 if (dopt->binary_upgrade)
14092 "TRANSFORM", transformargs->data, NULL);
14093
14094 if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
14095 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
14096 ARCHIVE_OPTS(.tag = labelq->data,
14097 .description = "TRANSFORM",
14098 .section = SECTION_PRE_DATA,
14099 .createStmt = defqry->data,
14100 .dropStmt = delqry->data,
14101 .deps = transform->dobj.dependencies,
14102 .nDeps = transform->dobj.nDeps));
14103
14104 /* Dump Transform Comments */
14105 if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
14106 dumpComment(fout, "TRANSFORM", transformargs->data,
14107 NULL, "",
14108 transform->dobj.catId, 0, transform->dobj.dumpId);
14109
14110 free(lanname);
14115}

References appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), _dumpableObject::catId, createPQExpBuffer(), _dumpableObject::dependencies, destroyPQExpBuffer(), _transformInfo::dobj, _dumpableObject::dump, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpableObject::dumpId, _dumpOptions::dumpSchema, fb(), findFuncByOid(), fmtId(), format_function_signature(), free, get_language_name(), getFormattedTypeName(), _dumpableObject::nDeps, OidIsValid, pg_fatal, pg_log_warning, SECTION_PRE_DATA, _transformInfo::trffromsql, _transformInfo::trflang, _transformInfo::trftosql, _transformInfo::trftype, and zeroAsNone.

Referenced by dumpDumpableObject().

◆ dumpTrigger()

static void dumpTrigger ( Archive fout,
const TriggerInfo tginfo 
)
static

Definition at line 19537 of file pg_dump.c.

19538{
19539 DumpOptions *dopt = fout->dopt;
19540 TableInfo *tbinfo = tginfo->tgtable;
19541 PQExpBuffer query;
19545 char *qtabname;
19546 char *tag;
19547
19548 /* Do nothing if not dumping schema */
19549 if (!dopt->dumpSchema)
19550 return;
19551
19552 query = createPQExpBuffer();
19556
19557 qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19558
19559 appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
19561
19562 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
19563 appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
19564
19565 /* Triggers can depend on extensions */
19567 "pg_catalog.pg_trigger", "TRIGGER",
19568 trigidentity->data);
19569
19570 if (tginfo->tgispartition)
19571 {
19572 Assert(tbinfo->ispartition);
19573
19574 /*
19575 * Partition triggers only appear here because their 'tgenabled' flag
19576 * differs from its parent's. The trigger is created already, so
19577 * remove the CREATE and replace it with an ALTER. (Clear out the
19578 * DROP query too, so that pg_dump --create does not cause errors.)
19579 */
19580 resetPQExpBuffer(query);
19582 appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
19583 tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
19585 switch (tginfo->tgenabled)
19586 {
19587 case 'f':
19588 case 'D':
19589 appendPQExpBufferStr(query, "DISABLE");
19590 break;
19591 case 't':
19592 case 'O':
19593 appendPQExpBufferStr(query, "ENABLE");
19594 break;
19595 case 'R':
19596 appendPQExpBufferStr(query, "ENABLE REPLICA");
19597 break;
19598 case 'A':
19599 appendPQExpBufferStr(query, "ENABLE ALWAYS");
19600 break;
19601 }
19602 appendPQExpBuffer(query, " TRIGGER %s;\n",
19603 fmtId(tginfo->dobj.name));
19604 }
19605 else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
19606 {
19607 appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
19608 tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
19610 switch (tginfo->tgenabled)
19611 {
19612 case 'D':
19613 case 'f':
19614 appendPQExpBufferStr(query, "DISABLE");
19615 break;
19616 case 'A':
19617 appendPQExpBufferStr(query, "ENABLE ALWAYS");
19618 break;
19619 case 'R':
19620 appendPQExpBufferStr(query, "ENABLE REPLICA");
19621 break;
19622 default:
19623 appendPQExpBufferStr(query, "ENABLE");
19624 break;
19625 }
19626 appendPQExpBuffer(query, " TRIGGER %s;\n",
19627 fmtId(tginfo->dobj.name));
19628 }
19629
19630 appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
19631 fmtId(tginfo->dobj.name));
19632
19633 tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
19634
19635 if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19636 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
19637 ARCHIVE_OPTS(.tag = tag,
19638 .namespace = tbinfo->dobj.namespace->dobj.name,
19639 .owner = tbinfo->rolname,
19640 .description = "TRIGGER",
19641 .section = SECTION_POST_DATA,
19642 .createStmt = query->data,
19643 .dropStmt = delqry->data));
19644
19645 if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
19647 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19648 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
19649
19650 free(tag);
19651 destroyPQExpBuffer(query);
19655 free(qtabname);
19656}

References append_depends_on_extension(), appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), Assert, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, fb(), fmtId(), fmtQualifiedDumpable, free, pg_strdup(), psprintf(), resetPQExpBuffer(), and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ dumpTSConfig()

static void dumpTSConfig ( Archive fout,
const TSConfigInfo cfginfo 
)
static

Definition at line 15950 of file pg_dump.c.

15951{
15952 DumpOptions *dopt = fout->dopt;
15953 PQExpBuffer q;
15955 PQExpBuffer query;
15956 char *qcfgname;
15957 PGresult *res;
15958 char *nspname;
15959 char *prsname;
15960 int ntups,
15961 i;
15962 int i_tokenname;
15963 int i_dictname;
15964
15965 /* Do nothing if not dumping schema */
15966 if (!dopt->dumpSchema)
15967 return;
15968
15969 q = createPQExpBuffer();
15971 query = createPQExpBuffer();
15972
15973 qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
15974
15975 /* Fetch name and namespace of the config's parser */
15976 appendPQExpBuffer(query, "SELECT nspname, prsname "
15977 "FROM pg_ts_parser p, pg_namespace n "
15978 "WHERE p.oid = '%u' AND n.oid = prsnamespace",
15979 cfginfo->cfgparser);
15980 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15981 nspname = PQgetvalue(res, 0, 0);
15982 prsname = PQgetvalue(res, 0, 1);
15983
15984 appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
15986
15987 appendPQExpBuffer(q, " PARSER = %s.", fmtId(nspname));
15988 appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
15989
15990 PQclear(res);
15991
15992 resetPQExpBuffer(query);
15993 appendPQExpBuffer(query,
15994 "SELECT\n"
15995 " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
15996 " WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
15997 " m.mapdict::pg_catalog.regdictionary AS dictname\n"
15998 "FROM pg_catalog.pg_ts_config_map AS m\n"
15999 "WHERE m.mapcfg = '%u'\n"
16000 "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
16001 cfginfo->cfgparser, cfginfo->dobj.catId.oid);
16002
16003 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16004 ntups = PQntuples(res);
16005
16006 i_tokenname = PQfnumber(res, "tokenname");
16007 i_dictname = PQfnumber(res, "dictname");
16008
16009 for (i = 0; i < ntups; i++)
16010 {
16011 char *tokenname = PQgetvalue(res, i, i_tokenname);
16012 char *dictname = PQgetvalue(res, i, i_dictname);
16013
16014 if (i == 0 ||
16015 strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
16016 {
16017 /* starting a new token type, so start a new command */
16018 if (i > 0)
16019 appendPQExpBufferStr(q, ";\n");
16020 appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
16022 /* tokenname needs quoting, dictname does NOT */
16023 appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
16024 fmtId(tokenname), dictname);
16025 }
16026 else
16027 appendPQExpBuffer(q, ", %s", dictname);
16028 }
16029
16030 if (ntups > 0)
16031 appendPQExpBufferStr(q, ";\n");
16032
16033 PQclear(res);
16034
16035 appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
16037
16038 if (dopt->binary_upgrade)
16040 "TEXT SEARCH CONFIGURATION", qcfgname,
16041 cfginfo->dobj.namespace->dobj.name);
16042
16043 if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16044 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
16045 ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
16046 .namespace = cfginfo->dobj.namespace->dobj.name,
16047 .owner = cfginfo->rolname,
16048 .description = "TEXT SEARCH CONFIGURATION",
16049 .section = SECTION_PRE_DATA,
16050 .createStmt = q->data,
16051 .dropStmt = delq->data));
16052
16053 /* Dump Configuration Comments */
16054 if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16055 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
16056 cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
16057 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
16058
16061 destroyPQExpBuffer(query);
16062 free(qcfgname);
16063}

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, ExecuteSqlQuery(), ExecuteSqlQueryForSingleRow(), fb(), fmtId(), fmtQualifiedDumpable, free, i, pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, resetPQExpBuffer(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpTSDictionary()

static void dumpTSDictionary ( Archive fout,
const TSDictInfo dictinfo 
)
static

Definition at line 15812 of file pg_dump.c.

15813{
15814 DumpOptions *dopt = fout->dopt;
15815 PQExpBuffer q;
15817 PQExpBuffer query;
15818 char *qdictname;
15819 PGresult *res;
15820 char *nspname;
15821 char *tmplname;
15822
15823 /* Do nothing if not dumping schema */
15824 if (!dopt->dumpSchema)
15825 return;
15826
15827 q = createPQExpBuffer();
15829 query = createPQExpBuffer();
15830
15831 qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
15832
15833 /* Fetch name and namespace of the dictionary's template */
15834 appendPQExpBuffer(query, "SELECT nspname, tmplname "
15835 "FROM pg_ts_template p, pg_namespace n "
15836 "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
15837 dictinfo->dicttemplate);
15838 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15839 nspname = PQgetvalue(res, 0, 0);
15840 tmplname = PQgetvalue(res, 0, 1);
15841
15842 appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
15844
15845 appendPQExpBufferStr(q, " TEMPLATE = ");
15846 appendPQExpBuffer(q, "%s.", fmtId(nspname));
15848
15849 PQclear(res);
15850
15851 /* the dictinitoption can be dumped straight into the command */
15852 if (dictinfo->dictinitoption)
15853 appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
15854
15855 appendPQExpBufferStr(q, " );\n");
15856
15857 appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
15859
15860 if (dopt->binary_upgrade)
15862 "TEXT SEARCH DICTIONARY", qdictname,
15863 dictinfo->dobj.namespace->dobj.name);
15864
15865 if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15866 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
15867 ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
15868 .namespace = dictinfo->dobj.namespace->dobj.name,
15869 .owner = dictinfo->rolname,
15870 .description = "TEXT SEARCH DICTIONARY",
15871 .section = SECTION_PRE_DATA,
15872 .createStmt = q->data,
15873 .dropStmt = delq->data));
15874
15875 /* Dump Dictionary Comments */
15876 if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15877 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
15878 dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
15879 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
15880
15883 destroyPQExpBuffer(query);
15884 free(qdictname);
15885}

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, ExecuteSqlQueryForSingleRow(), fb(), fmtId(), fmtQualifiedDumpable, free, pg_strdup(), PQclear, PQgetvalue, and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpTSParser()

static void dumpTSParser ( Archive fout,
const TSParserInfo prsinfo 
)
static

Definition at line 15748 of file pg_dump.c.

15749{
15750 DumpOptions *dopt = fout->dopt;
15751 PQExpBuffer q;
15753 char *qprsname;
15754
15755 /* Do nothing if not dumping schema */
15756 if (!dopt->dumpSchema)
15757 return;
15758
15759 q = createPQExpBuffer();
15761
15762 qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
15763
15764 appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
15766
15767 appendPQExpBuffer(q, " START = %s,\n",
15768 convertTSFunction(fout, prsinfo->prsstart));
15769 appendPQExpBuffer(q, " GETTOKEN = %s,\n",
15770 convertTSFunction(fout, prsinfo->prstoken));
15771 appendPQExpBuffer(q, " END = %s,\n",
15772 convertTSFunction(fout, prsinfo->prsend));
15773 if (prsinfo->prsheadline != InvalidOid)
15774 appendPQExpBuffer(q, " HEADLINE = %s,\n",
15775 convertTSFunction(fout, prsinfo->prsheadline));
15776 appendPQExpBuffer(q, " LEXTYPES = %s );\n",
15777 convertTSFunction(fout, prsinfo->prslextype));
15778
15779 appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
15781
15782 if (dopt->binary_upgrade)
15784 "TEXT SEARCH PARSER", qprsname,
15785 prsinfo->dobj.namespace->dobj.name);
15786
15787 if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15788 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
15789 ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
15790 .namespace = prsinfo->dobj.namespace->dobj.name,
15791 .description = "TEXT SEARCH PARSER",
15792 .section = SECTION_PRE_DATA,
15793 .createStmt = q->data,
15794 .dropStmt = delq->data));
15795
15796 /* Dump Parser Comments */
15797 if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15798 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
15799 prsinfo->dobj.namespace->dobj.name, "",
15800 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
15801
15804 free(qprsname);
15805}

References appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), convertTSFunction(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, fb(), fmtId(), fmtQualifiedDumpable, free, InvalidOid, pg_strdup(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpTSTemplate()

static void dumpTSTemplate ( Archive fout,
const TSTemplateInfo tmplinfo 
)
static

Definition at line 15892 of file pg_dump.c.

15893{
15894 DumpOptions *dopt = fout->dopt;
15895 PQExpBuffer q;
15897 char *qtmplname;
15898
15899 /* Do nothing if not dumping schema */
15900 if (!dopt->dumpSchema)
15901 return;
15902
15903 q = createPQExpBuffer();
15905
15906 qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
15907
15908 appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
15910
15911 if (tmplinfo->tmplinit != InvalidOid)
15912 appendPQExpBuffer(q, " INIT = %s,\n",
15913 convertTSFunction(fout, tmplinfo->tmplinit));
15914 appendPQExpBuffer(q, " LEXIZE = %s );\n",
15915 convertTSFunction(fout, tmplinfo->tmpllexize));
15916
15917 appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
15919
15920 if (dopt->binary_upgrade)
15922 "TEXT SEARCH TEMPLATE", qtmplname,
15923 tmplinfo->dobj.namespace->dobj.name);
15924
15925 if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15926 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
15927 ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
15928 .namespace = tmplinfo->dobj.namespace->dobj.name,
15929 .description = "TEXT SEARCH TEMPLATE",
15930 .section = SECTION_PRE_DATA,
15931 .createStmt = q->data,
15932 .dropStmt = delq->data));
15933
15934 /* Dump Template Comments */
15935 if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15936 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
15937 tmplinfo->dobj.namespace->dobj.name, "",
15938 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
15939
15942 free(qtmplname);
15943}

References appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), convertTSFunction(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, dumpComment(), _dumpOptions::dumpSchema, fb(), fmtId(), fmtQualifiedDumpable, free, InvalidOid, pg_strdup(), and SECTION_PRE_DATA.

Referenced by dumpDumpableObject().

◆ dumpType()

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

Definition at line 12075 of file pg_dump.c.

12076{
12077 DumpOptions *dopt = fout->dopt;
12078
12079 /* Do nothing if not dumping schema */
12080 if (!dopt->dumpSchema)
12081 return;
12082
12083 /* Dump out in proper style */
12084 if (tyinfo->typtype == TYPTYPE_BASE)
12086 else if (tyinfo->typtype == TYPTYPE_DOMAIN)
12088 else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
12090 else if (tyinfo->typtype == TYPTYPE_ENUM)
12092 else if (tyinfo->typtype == TYPTYPE_RANGE)
12094 else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
12096 else
12097 pg_log_warning("typtype of data type \"%s\" appears to be invalid",
12098 tyinfo->dobj.name);
12099}

References dumpBaseType(), dumpCompositeType(), dumpDomain(), dumpEnumType(), dumpRangeType(), _dumpOptions::dumpSchema, dumpUndefinedType(), fb(), and pg_log_warning.

Referenced by crashDumpHandler(), and dumpDumpableObject().

◆ dumpUndefinedType()

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

Definition at line 12404 of file pg_dump.c.

12405{
12406 DumpOptions *dopt = fout->dopt;
12409 char *qtypname;
12410 char *qualtypname;
12411
12412 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
12414
12415 appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12416
12417 if (dopt->binary_upgrade)
12419 tyinfo->dobj.catId.oid,
12420 false, false);
12421
12422 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
12423 qualtypname);
12424
12425 if (dopt->binary_upgrade)
12427 "TYPE", qtypname,
12428 tyinfo->dobj.namespace->dobj.name);
12429
12430 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12431 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
12432 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12433 .namespace = tyinfo->dobj.namespace->dobj.name,
12434 .owner = tyinfo->rolname,
12435 .description = "TYPE",
12436 .section = SECTION_PRE_DATA,
12437 .createStmt = q->data,
12438 .dropStmt = delq->data));
12439
12440 /* Dump Type Comments and Security Labels */
12441 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12442 dumpComment(fout, "TYPE", qtypname,
12443 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12444 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12445
12446 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12447 dumpSecLabel(fout, "TYPE", qtypname,
12448 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12449 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12450
12451 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
12452 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12453 qtypname, NULL,
12454 tyinfo->dobj.namespace->dobj.name,
12455 NULL, tyinfo->rolname, &tyinfo->dacl);
12456
12459 free(qtypname);
12461}

References appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), _dumpOptions::binary_upgrade, binary_upgrade_extension_member(), binary_upgrade_set_type_oids_by_type_oid(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_ACL, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_SECLABEL, dumpACL(), dumpComment(), dumpSecLabel(), fb(), fmtId(), fmtQualifiedDumpable, free, InvalidDumpId, pg_strdup(), and SECTION_PRE_DATA.

Referenced by dumpType().

◆ dumpUserMappings()

static void dumpUserMappings ( Archive fout,
const char servername,
const char namespace,
const char owner,
CatalogId  catalogId,
DumpId  dumpId 
)
static

Definition at line 16240 of file pg_dump.c.

16244{
16245 PQExpBuffer q;
16247 PQExpBuffer query;
16248 PQExpBuffer tag;
16249 PGresult *res;
16250 int ntups;
16251 int i_usename;
16252 int i_umoptions;
16253 int i;
16254
16255 q = createPQExpBuffer();
16256 tag = createPQExpBuffer();
16258 query = createPQExpBuffer();
16259
16260 /*
16261 * We read from the publicly accessible view pg_user_mappings, so as not
16262 * to fail if run by a non-superuser. Note that the view will show
16263 * umoptions as null if the user hasn't got privileges for the associated
16264 * server; this means that pg_dump will dump such a mapping, but with no
16265 * OPTIONS clause. A possible alternative is to skip such mappings
16266 * altogether, but it's not clear that that's an improvement.
16267 */
16268 appendPQExpBuffer(query,
16269 "SELECT usename, "
16270 "array_to_string(ARRAY("
16271 "SELECT quote_ident(option_name) || ' ' || "
16272 "quote_literal(option_value) "
16273 "FROM pg_options_to_table(umoptions) "
16274 "ORDER BY option_name"
16275 "), E',\n ') AS umoptions "
16276 "FROM pg_user_mappings "
16277 "WHERE srvid = '%u' "
16278 "ORDER BY usename",
16279 catalogId.oid);
16280
16281 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16282
16283 ntups = PQntuples(res);
16284 i_usename = PQfnumber(res, "usename");
16285 i_umoptions = PQfnumber(res, "umoptions");
16286
16287 for (i = 0; i < ntups; i++)
16288 {
16289 char *usename;
16290 char *umoptions;
16291
16292 usename = PQgetvalue(res, i, i_usename);
16294
16296 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
16297 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
16298
16299 if (umoptions && strlen(umoptions) > 0)
16300 appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
16301
16302 appendPQExpBufferStr(q, ";\n");
16303
16305 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
16306 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
16307
16308 resetPQExpBuffer(tag);
16309 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
16310 usename, servername);
16311
16313 ARCHIVE_OPTS(.tag = tag->data,
16314 .namespace = namespace,
16315 .owner = owner,
16316 .description = "USER MAPPING",
16317 .section = SECTION_PRE_DATA,
16318 .createStmt = q->data,
16319 .dropStmt = delq->data));
16320 }
16321
16322 PQclear(res);
16323
16324 destroyPQExpBuffer(query);
16326 destroyPQExpBuffer(tag);
16328}

References appendPQExpBuffer(), appendPQExpBufferStr(), ARCHIVE_OPTS, ArchiveEntry(), createDumpId(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), ExecuteSqlQuery(), fb(), fmtId(), i, nilCatalogId, CatalogId::oid, PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, resetPQExpBuffer(), and SECTION_PRE_DATA.

Referenced by dumpForeignServer().

◆ expand_extension_name_patterns()

static void expand_extension_name_patterns ( Archive fout,
SimpleStringList patterns,
SimpleOidList oids,
bool  strict_names 
)
static

Definition at line 1736 of file pg_dump.c.

1740{
1741 PQExpBuffer query;
1742 PGresult *res;
1744 int i;
1745
1746 if (patterns->head == NULL)
1747 return; /* nothing to do */
1748
1749 query = createPQExpBuffer();
1750
1751 /*
1752 * The loop below runs multiple SELECTs might sometimes result in
1753 * duplicate entries in the OID list, but we don't care.
1754 */
1755 for (cell = patterns->head; cell; cell = cell->next)
1756 {
1757 int dotcnt;
1758
1760 "SELECT oid FROM pg_catalog.pg_extension e\n");
1761 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1762 false, NULL, "e.extname", NULL, NULL, NULL,
1763 &dotcnt);
1764 if (dotcnt > 0)
1765 pg_fatal("improper qualified name (too many dotted names): %s",
1766 cell->val);
1767
1768 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1769 if (strict_names && PQntuples(res) == 0)
1770 pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
1771
1772 for (i = 0; i < PQntuples(res); i++)
1773 {
1774 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1775 }
1776
1777 PQclear(res);
1778 resetPQExpBuffer(query);
1779 }
1780
1781 destroyPQExpBuffer(query);
1782}

References appendPQExpBufferStr(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), ExecuteSqlQuery(), fb(), GetConnection(), i, SimpleStringListCell::next, pg_fatal, PGRES_TUPLES_OK, PQclear, PQgetvalue, PQntuples, processSQLNamePattern(), resetPQExpBuffer(), simple_oid_list_append(), strict_names, and SimpleStringListCell::val.

Referenced by main().

◆ expand_foreign_server_name_patterns()

static void expand_foreign_server_name_patterns ( Archive fout,
SimpleStringList patterns,
SimpleOidList oids 
)
static

Definition at line 1789 of file pg_dump.c.

1792{
1793 PQExpBuffer query;
1794 PGresult *res;
1796 int i;
1797
1798 if (patterns->head == NULL)
1799 return; /* nothing to do */
1800
1801 query = createPQExpBuffer();
1802
1803 /*
1804 * The loop below runs multiple SELECTs might sometimes result in
1805 * duplicate entries in the OID list, but we don't care.
1806 */
1807
1808 for (cell = patterns->head; cell; cell = cell->next)
1809 {
1810 int dotcnt;
1811
1813 "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
1814 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1815 false, NULL, "s.srvname", NULL, NULL, NULL,
1816 &dotcnt);
1817 if (dotcnt > 0)
1818 pg_fatal("improper qualified name (too many dotted names): %s",
1819 cell->val);
1820
1821 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1822 if (PQntuples(res) == 0)
1823 pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
1824
1825 for (i = 0; i < PQntuples(res); i++)
1826 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1827
1828 PQclear(res);
1829 resetPQExpBuffer(query);
1830 }
1831
1832 destroyPQExpBuffer(query);
1833}

References appendPQExpBufferStr(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), ExecuteSqlQuery(), fb(), GetConnection(), i, SimpleStringListCell::next, pg_fatal, PGRES_TUPLES_OK, PQclear, PQgetvalue, PQntuples, processSQLNamePattern(), resetPQExpBuffer(), simple_oid_list_append(), and SimpleStringListCell::val.

Referenced by main().

◆ expand_schema_name_patterns()

static void expand_schema_name_patterns ( Archive fout,
SimpleStringList patterns,
SimpleOidList oids,
bool  strict_names 
)
static

Definition at line 1677 of file pg_dump.c.

1681{
1682 PQExpBuffer query;
1683 PGresult *res;
1685 int i;
1686
1687 if (patterns->head == NULL)
1688 return; /* nothing to do */
1689
1690 query = createPQExpBuffer();
1691
1692 /*
1693 * The loop below runs multiple SELECTs might sometimes result in
1694 * duplicate entries in the OID list, but we don't care.
1695 */
1696
1697 for (cell = patterns->head; cell; cell = cell->next)
1698 {
1700 int dotcnt;
1701
1703 "SELECT oid FROM pg_catalog.pg_namespace n\n");
1705 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1706 false, NULL, "n.nspname", NULL, NULL, &dbbuf,
1707 &dotcnt);
1708 if (dotcnt > 1)
1709 pg_fatal("improper qualified name (too many dotted names): %s",
1710 cell->val);
1711 else if (dotcnt == 1)
1714
1715 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1716 if (strict_names && PQntuples(res) == 0)
1717 pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
1718
1719 for (i = 0; i < PQntuples(res); i++)
1720 {
1721 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1722 }
1723
1724 PQclear(res);
1725 resetPQExpBuffer(query);
1726 }
1727
1728 destroyPQExpBuffer(query);
1729}

References appendPQExpBufferStr(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), ExecuteSqlQuery(), fb(), GetConnection(), i, initPQExpBuffer(), SimpleStringListCell::next, pg_fatal, PGRES_TUPLES_OK, PQclear, PQgetvalue, PQntuples, processSQLNamePattern(), prohibit_crossdb_refs(), resetPQExpBuffer(), simple_oid_list_append(), strict_names, termPQExpBuffer(), and SimpleStringListCell::val.

Referenced by main().

◆ expand_table_name_patterns()

static void expand_table_name_patterns ( Archive fout,
SimpleStringList patterns,
SimpleOidList oids,
bool  strict_names,
bool  with_child_tables 
)
static

Definition at line 1841 of file pg_dump.c.

1844{
1845 PQExpBuffer query;
1846 PGresult *res;
1848 int i;
1849
1850 if (patterns->head == NULL)
1851 return; /* nothing to do */
1852
1853 query = createPQExpBuffer();
1854
1855 /*
1856 * this might sometimes result in duplicate entries in the OID list, but
1857 * we don't care.
1858 */
1859
1860 for (cell = patterns->head; cell; cell = cell->next)
1861 {
1863 int dotcnt;
1864
1865 /*
1866 * Query must remain ABSOLUTELY devoid of unqualified names. This
1867 * would be unnecessary given a pg_table_is_visible() variant taking a
1868 * search_path argument.
1869 *
1870 * For with_child_tables, we start with the basic query's results and
1871 * recursively search the inheritance tree to add child tables.
1872 */
1874 {
1875 appendPQExpBufferStr(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
1876 }
1877
1878 appendPQExpBuffer(query,
1879 "SELECT c.oid"
1880 "\nFROM pg_catalog.pg_class c"
1881 "\n LEFT JOIN pg_catalog.pg_namespace n"
1882 "\n ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1883 "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1884 "\n (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1889 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1890 false, "n.nspname", "c.relname", NULL,
1891 "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
1892 &dotcnt);
1893 if (dotcnt > 2)
1894 pg_fatal("improper relation name (too many dotted names): %s",
1895 cell->val);
1896 else if (dotcnt == 2)
1899
1901 {
1902 appendPQExpBufferStr(query, "UNION"
1903 "\nSELECT i.inhrelid"
1904 "\nFROM partition_tree p"
1905 "\n JOIN pg_catalog.pg_inherits i"
1906 "\n ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
1907 "\n)"
1908 "\nSELECT relid FROM partition_tree");
1909 }
1910
1911 ExecuteSqlStatement(fout, "RESET search_path");
1912 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1915 if (strict_names && PQntuples(res) == 0)
1916 pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
1917
1918 for (i = 0; i < PQntuples(res); i++)
1919 {
1920 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1921 }
1922
1923 PQclear(res);
1924 resetPQExpBuffer(query);
1925 }
1926
1927 destroyPQExpBuffer(query);
1928}

References ALWAYS_SECURE_SEARCH_PATH_SQL, appendPQExpBuffer(), appendPQExpBufferStr(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), ExecuteSqlQuery(), ExecuteSqlQueryForSingleRow(), ExecuteSqlStatement(), fb(), GetConnection(), i, initPQExpBuffer(), SimpleStringListCell::next, pg_fatal, PGRES_TUPLES_OK, PQclear, PQgetvalue, PQntuples, processSQLNamePattern(), prohibit_crossdb_refs(), resetPQExpBuffer(), simple_oid_list_append(), strict_names, termPQExpBuffer(), and SimpleStringListCell::val.

Referenced by main().

◆ fetchAttributeStats()

static PGresult * fetchAttributeStats ( Archive fout)
static

Definition at line 11031 of file pg_dump.c.

11032{
11036 int count = 0;
11037 PGresult *res = NULL;
11038 static TocEntry *te;
11039 static bool restarted;
11041
11042 /*
11043 * Our query for retrieving statistics for multiple relations uses WITH
11044 * ORDINALITY and multi-argument UNNEST(), both of which were introduced
11045 * in v9.4. For older versions, we resort to gathering statistics for a
11046 * single relation at a time.
11047 */
11048 if (fout->remoteVersion < 90400)
11049 max_rels = 1;
11050
11051 /* If we're just starting, set our TOC pointer. */
11052 if (!te)
11053 te = AH->toc->next;
11054
11055 /*
11056 * We can't easily avoid a second TOC scan for the tar format because it
11057 * writes restore.sql separately, which means we must execute the queries
11058 * twice. This feels risky, but there is no known reason it should
11059 * generate different output than the first pass. Even if it does, the
11060 * worst-case scenario is that restore.sql might have different statistics
11061 * data than the archive.
11062 */
11063 if (!restarted && te == AH->toc && AH->format == archTar)
11064 {
11065 te = AH->toc->next;
11066 restarted = true;
11067 }
11068
11071
11072 /*
11073 * Scan the TOC for the next set of relevant stats entries. We assume
11074 * that statistics are dumped in the order they are listed in the TOC.
11075 * This is perhaps not the sturdiest assumption, so we verify it matches
11076 * reality in dumpRelationStats_dumper().
11077 */
11078 for (; te != AH->toc && count < max_rels; te = te->next)
11079 {
11080 if ((te->reqs & REQ_STATS) != 0 &&
11081 strcmp(te->desc, "STATISTICS DATA") == 0)
11082 {
11083 appendPGArray(nspnames, te->namespace);
11085 count++;
11086 }
11087 }
11088
11091
11092 /* Execute the query for the next batch of relations. */
11093 if (count > 0)
11094 {
11096
11097 appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
11098 appendStringLiteralAH(query, nspnames->data, fout);
11099 appendPQExpBufferStr(query, "::pg_catalog.name[],");
11100 appendStringLiteralAH(query, relnames->data, fout);
11101 appendPQExpBufferStr(query, "::pg_catalog.name[])");
11102 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11103 destroyPQExpBuffer(query);
11104 }
11105
11108 return res;
11109}

References appendPGArray(), appendPQExpBufferChar(), appendPQExpBufferStr(), appendStringLiteralAH, archTar, createPQExpBuffer(), PQExpBufferData::data, _tocEntry::desc, destroyPQExpBuffer(), ExecuteSqlQuery(), fb(), _archiveHandle::format, MAX_ATTR_STATS_RELS, _tocEntry::next, PGRES_TUPLES_OK, REQ_STATS, _tocEntry::reqs, _tocEntry::tag, and _archiveHandle::toc.

Referenced by dumpRelationStats_dumper().

◆ findComments()

static int findComments ( Oid  classoid,
Oid  objoid,
CommentItem **  items 
)
static

Definition at line 11516 of file pg_dump.c.

11517{
11519 CommentItem *low;
11520 CommentItem *high;
11521 int nmatch;
11522
11523 /*
11524 * Do binary search to find some item matching the object.
11525 */
11526 low = &comments[0];
11527 high = &comments[ncomments - 1];
11528 while (low <= high)
11529 {
11530 middle = low + (high - low) / 2;
11531
11532 if (classoid < middle->classoid)
11533 high = middle - 1;
11534 else if (classoid > middle->classoid)
11535 low = middle + 1;
11536 else if (objoid < middle->objoid)
11537 high = middle - 1;
11538 else if (objoid > middle->objoid)
11539 low = middle + 1;
11540 else
11541 break; /* found a match */
11542 }
11543
11544 if (low > high) /* no matches */
11545 {
11546 *items = NULL;
11547 return 0;
11548 }
11549
11550 /*
11551 * Now determine how many items match the object. The search loop
11552 * invariant still holds: only items between low and high inclusive could
11553 * match.
11554 */
11555 nmatch = 1;
11556 while (middle > low)
11557 {
11558 if (classoid != middle[-1].classoid ||
11559 objoid != middle[-1].objoid)
11560 break;
11561 middle--;
11562 nmatch++;
11563 }
11564
11565 *items = middle;
11566
11567 middle += nmatch;
11568 while (middle <= high)
11569 {
11570 if (classoid != middle->classoid ||
11571 objoid != middle->objoid)
11572 break;
11573 middle++;
11574 nmatch++;
11575 }
11576
11577 return nmatch;
11578}

References comments, fb(), items, and ncomments.

Referenced by dumpCommentExtended(), dumpCompositeTypeColComments(), and dumpTableComment().

◆ findDumpableDependencies()

static void findDumpableDependencies ( ArchiveHandle AH,
const DumpableObject dobj,
DumpId **  dependencies,
int nDeps,
int allocDeps 
)
static

Definition at line 20545 of file pg_dump.c.

20547{
20548 int i;
20549
20550 /*
20551 * Ignore section boundary objects: if we search through them, we'll
20552 * report lots of bogus dependencies.
20553 */
20554 if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
20556 return;
20557
20558 for (i = 0; i < dobj->nDeps; i++)
20559 {
20560 DumpId depid = dobj->dependencies[i];
20561
20562 if (TocIDRequired(AH, depid) != 0)
20563 {
20564 /* Object will be dumped, so just reference it as a dependency */
20565 if (*nDeps >= *allocDeps)
20566 {
20567 *allocDeps *= 2;
20568 *dependencies = (DumpId *) pg_realloc(*dependencies,
20569 *allocDeps * sizeof(DumpId));
20570 }
20571 (*dependencies)[*nDeps] = depid;
20572 (*nDeps)++;
20573 }
20574 else
20575 {
20576 /*
20577 * Object will not be dumped, so recursively consider its deps. We
20578 * rely on the assumption that sortDumpableObjects already broke
20579 * any dependency loops, else we might recurse infinitely.
20580 */
20582
20583 if (otherdobj)
20585 dependencies, nDeps, allocDeps);
20586 }
20587 }
20588}

References _dumpableObject::dependencies, DO_POST_DATA_BOUNDARY, DO_PRE_DATA_BOUNDARY, fb(), findDumpableDependencies(), findObjectByDumpId(), i, _dumpableObject::nDeps, _dumpableObject::objType, pg_realloc(), and TocIDRequired().

Referenced by BuildArchiveDependencies(), and findDumpableDependencies().

◆ findNamespace()

static NamespaceInfo * findNamespace ( Oid  nsoid)
static

◆ findSecLabels()

static int findSecLabels ( Oid  classoid,
Oid  objoid,
SecLabelItem **  items 
)
static

Definition at line 16716 of file pg_dump.c.

16717{
16719 SecLabelItem *low;
16720 SecLabelItem *high;
16721 int nmatch;
16722
16723 if (nseclabels <= 0) /* no labels, so no match is possible */
16724 {
16725 *items = NULL;
16726 return 0;
16727 }
16728
16729 /*
16730 * Do binary search to find some item matching the object.
16731 */
16732 low = &seclabels[0];
16733 high = &seclabels[nseclabels - 1];
16734 while (low <= high)
16735 {
16736 middle = low + (high - low) / 2;
16737
16738 if (classoid < middle->classoid)
16739 high = middle - 1;
16740 else if (classoid > middle->classoid)
16741 low = middle + 1;
16742 else if (objoid < middle->objoid)
16743 high = middle - 1;
16744 else if (objoid > middle->objoid)
16745 low = middle + 1;
16746 else
16747 break; /* found a match */
16748 }
16749
16750 if (low > high) /* no matches */
16751 {
16752 *items = NULL;
16753 return 0;
16754 }
16755
16756 /*
16757 * Now determine how many items match the object. The search loop
16758 * invariant still holds: only items between low and high inclusive could
16759 * match.
16760 */
16761 nmatch = 1;
16762 while (middle > low)
16763 {
16764 if (classoid != middle[-1].classoid ||
16765 objoid != middle[-1].objoid)
16766 break;
16767 middle--;
16768 nmatch++;
16769 }
16770
16771 *items = middle;
16772
16773 middle += nmatch;
16774 while (middle <= high)
16775 {
16776 if (classoid != middle->classoid ||
16777 objoid != middle->objoid)
16778 break;
16779 middle++;
16780 nmatch++;
16781 }
16782
16783 return nmatch;
16784}

References fb(), items, nseclabels, and seclabels.

Referenced by dumpSecLabel(), and dumpTableSecLabel().

◆ fmtCopyColumnList()

static const char * fmtCopyColumnList ( const TableInfo ti,
PQExpBuffer  buffer 
)
static

Definition at line 20652 of file pg_dump.c.

20653{
20654 int numatts = ti->numatts;
20655 char **attnames = ti->attnames;
20656 bool *attisdropped = ti->attisdropped;
20657 char *attgenerated = ti->attgenerated;
20658 bool needComma;
20659 int i;
20660
20661 appendPQExpBufferChar(buffer, '(');
20662 needComma = false;
20663 for (i = 0; i < numatts; i++)
20664 {
20665 if (attisdropped[i])
20666 continue;
20667 if (attgenerated[i])
20668 continue;
20669 if (needComma)
20670 appendPQExpBufferStr(buffer, ", ");
20671 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
20672 needComma = true;
20673 }
20674
20675 if (!needComma)
20676 return ""; /* no undropped columns */
20677
20678 appendPQExpBufferChar(buffer, ')');
20679 return buffer->data;
20680}

References appendPQExpBufferChar(), appendPQExpBufferStr(), PQExpBufferData::data, fb(), fmtId(), and i.

Referenced by dumpTableData(), and dumpTableData_copy().

◆ forcePartitionRootLoad()

static bool forcePartitionRootLoad ( const TableInfo tbinfo)
static

Definition at line 2856 of file pg_dump.c.

2857{
2859
2860 Assert(tbinfo->ispartition);
2861 Assert(tbinfo->numParents == 1);
2862
2863 parentTbinfo = tbinfo->parents[0];
2864 if (parentTbinfo->unsafe_partitions)
2865 return true;
2866 while (parentTbinfo->ispartition)
2867 {
2868 Assert(parentTbinfo->numParents == 1);
2869 parentTbinfo = parentTbinfo->parents[0];
2870 if (parentTbinfo->unsafe_partitions)
2871 return true;
2872 }
2873
2874 return false;
2875}

References Assert, and fb().

Referenced by dumpTableData(), and dumpTableData_insert().

◆ format_aggregate_signature()

static char * format_aggregate_signature ( const AggInfo agginfo,
Archive fout,
bool  honor_quotes 
)
static

Definition at line 15356 of file pg_dump.c.

15357{
15359 int j;
15360
15362 if (honor_quotes)
15363 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
15364 else
15365 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
15366
15367 if (agginfo->aggfn.nargs == 0)
15368 appendPQExpBufferStr(&buf, "(*)");
15369 else
15370 {
15372 for (j = 0; j < agginfo->aggfn.nargs; j++)
15373 appendPQExpBuffer(&buf, "%s%s",
15374 (j > 0) ? ", " : "",
15376 agginfo->aggfn.argtypes[j],
15377 zeroIsError));
15379 }
15380 return buf.data;
15381}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), buf, fb(), fmtId(), getFormattedTypeName(), initPQExpBuffer(), j, and zeroIsError.

Referenced by dumpAgg().

◆ format_function_arguments()

static char * format_function_arguments ( const FuncInfo finfo,
const char funcargs,
bool  is_agg 
)
static

Definition at line 13415 of file pg_dump.c.

13416{
13418
13421 if (is_agg && finfo->nargs == 0)
13422 appendPQExpBufferStr(&fn, "(*)");
13423 else
13424 appendPQExpBuffer(&fn, "(%s)", funcargs);
13425 return fn.data;
13426}

References appendPQExpBuffer(), appendPQExpBufferStr(), _funcInfo::dobj, fb(), fmtId(), fn(), initPQExpBuffer(), _dumpableObject::name, and _funcInfo::nargs.

Referenced by dumpAgg(), and dumpFunc().

◆ format_function_signature()

static char * format_function_signature ( Archive fout,
const FuncInfo finfo,
bool  honor_quotes 
)
static

Definition at line 13438 of file pg_dump.c.

13439{
13441 int j;
13442
13444 if (honor_quotes)
13445 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
13446 else
13447 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
13448 for (j = 0; j < finfo->nargs; j++)
13449 {
13450 if (j > 0)
13451 appendPQExpBufferStr(&fn, ", ");
13452
13455 zeroIsError));
13456 }
13458 return fn.data;
13459}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), _funcInfo::argtypes, _funcInfo::dobj, fb(), fmtId(), fn(), getFormattedTypeName(), initPQExpBuffer(), j, _dumpableObject::name, _funcInfo::nargs, and zeroIsError.

Referenced by dumpAgg(), dumpCast(), dumpFunc(), and dumpTransform().

◆ get_language_name()

static char * get_language_name ( Archive fout,
Oid  langid 
)
static

Definition at line 9146 of file pg_dump.c.

9147{
9148 PQExpBuffer query;
9149 PGresult *res;
9150 char *lanname;
9151
9152 query = createPQExpBuffer();
9153 appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
9154 res = ExecuteSqlQueryForSingleRow(fout, query->data);
9155 lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
9156 destroyPQExpBuffer(query);
9157 PQclear(res);
9158
9159 return lanname;
9160}

References appendPQExpBuffer(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), ExecuteSqlQueryForSingleRow(), fb(), fmtId(), pg_strdup(), PQclear, and PQgetvalue.

Referenced by dumpTransform(), and getTransforms().

◆ get_next_possible_free_pg_type_oid()

static Oid get_next_possible_free_pg_type_oid ( Archive fout,
PQExpBuffer  upgrade_query 
)
static

Definition at line 5695 of file pg_dump.c.

5696{
5697 /*
5698 * If the old version didn't assign an array type, but the new version
5699 * does, we must select an unused type OID to assign. This currently only
5700 * happens for domains, when upgrading pre-v11 to v11 and up.
5701 *
5702 * Note: local state here is kind of ugly, but we must have some, since we
5703 * mustn't choose the same unused OID more than once.
5704 */
5706 PGresult *res;
5707 bool is_dup;
5708
5709 do
5710 {
5713 "SELECT EXISTS(SELECT 1 "
5714 "FROM pg_catalog.pg_type "
5715 "WHERE oid = '%u'::pg_catalog.oid);",
5718 is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
5719 PQclear(res);
5720 } while (is_dup);
5721
5723}

References ExecuteSqlQueryForSingleRow(), fb(), FirstNormalObjectId, PQclear, PQgetvalue, and printfPQExpBuffer().

Referenced by binary_upgrade_set_type_oids_by_type_oid().

◆ get_synchronized_snapshot()

static char * get_synchronized_snapshot ( Archive fout)
static

Definition at line 1625 of file pg_dump.c.

1626{
1627 char *query = "SELECT pg_catalog.pg_export_snapshot()";
1628 char *result;
1629 PGresult *res;
1630
1631 res = ExecuteSqlQueryForSingleRow(fout, query);
1632 result = pg_strdup(PQgetvalue(res, 0, 0));
1633 PQclear(res);
1634
1635 return result;
1636}

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

Referenced by setup_connection().

◆ getAccessMethods()

void getAccessMethods ( Archive fout)

Definition at line 6584 of file pg_dump.c.

6585{
6586 PGresult *res;
6587 int ntups;
6588 int i;
6589 PQExpBuffer query;
6591 int i_tableoid;
6592 int i_oid;
6593 int i_amname;
6594 int i_amhandler;
6595 int i_amtype;
6596
6597 query = createPQExpBuffer();
6598
6599 /*
6600 * Select all access methods from pg_am table. v9.6 introduced CREATE
6601 * ACCESS METHOD, so earlier versions usually have only built-in access
6602 * methods. v9.6 also changed the access method API, replacing dozens of
6603 * pg_am columns with amhandler. Even if a user created an access method
6604 * by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am
6605 * columns to a v9.6+ CREATE ACCESS METHOD. Hence, before v9.6, read
6606 * pg_am just to facilitate findAccessMethodByOid() providing the
6607 * OID-to-name mapping.
6608 */
6609 appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
6610 if (fout->remoteVersion >= 90600)
6612 "amtype, "
6613 "amhandler::pg_catalog.regproc AS amhandler ");
6614 else
6616 "'i'::pg_catalog.\"char\" AS amtype, "
6617 "'-'::pg_catalog.regproc AS amhandler ");
6618 appendPQExpBufferStr(query, "FROM pg_am");
6619
6620 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6621
6622 ntups = PQntuples(res);
6623
6624 aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
6625
6626 i_tableoid = PQfnumber(res, "tableoid");
6627 i_oid = PQfnumber(res, "oid");
6628 i_amname = PQfnumber(res, "amname");
6629 i_amhandler = PQfnumber(res, "amhandler");
6630 i_amtype = PQfnumber(res, "amtype");
6631
6632 for (i = 0; i < ntups; i++)
6633 {
6634 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
6635 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6636 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6637 AssignDumpId(&aminfo[i].dobj);
6638 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
6639 aminfo[i].dobj.namespace = NULL;
6640 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
6641 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
6642
6643 /* Decide whether we want to dump it */
6645 }
6646
6647 PQclear(res);
6648
6649 destroyPQExpBuffer(query);
6650}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_ACCESS_METHOD, ExecuteSqlQuery(), fb(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableAccessMethod().

Referenced by getSchemaData().

◆ getAdditionalACLs()

static void getAdditionalACLs ( Archive fout)
static

Definition at line 10768 of file pg_dump.c.

10769{
10771 PGresult *res;
10772 int ntups,
10773 i;
10774
10775 /* Check for per-column ACLs */
10777 "SELECT DISTINCT attrelid FROM pg_attribute "
10778 "WHERE attacl IS NOT NULL");
10779
10780 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10781
10782 ntups = PQntuples(res);
10783 for (i = 0; i < ntups; i++)
10784 {
10785 Oid relid = atooid(PQgetvalue(res, i, 0));
10786 TableInfo *tblinfo;
10787
10788 tblinfo = findTableByOid(relid);
10789 /* OK to ignore tables we haven't got a DumpableObject for */
10790 if (tblinfo)
10791 {
10793 tblinfo->hascolumnACLs = true;
10794 }
10795 }
10796 PQclear(res);
10797
10798 /* Fetch initial-privileges data */
10799 if (fout->remoteVersion >= 90600)
10800 {
10801 printfPQExpBuffer(query,
10802 "SELECT objoid, classoid, objsubid, privtype, initprivs "
10803 "FROM pg_init_privs");
10804
10805 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10806
10807 ntups = PQntuples(res);
10808 for (i = 0; i < ntups; i++)
10809 {
10810 Oid objoid = atooid(PQgetvalue(res, i, 0));
10811 Oid classoid = atooid(PQgetvalue(res, i, 1));
10812 int objsubid = atoi(PQgetvalue(res, i, 2));
10813 char privtype = *(PQgetvalue(res, i, 3));
10814 char *initprivs = PQgetvalue(res, i, 4);
10815 CatalogId objId;
10816 DumpableObject *dobj;
10817
10818 objId.tableoid = classoid;
10819 objId.oid = objoid;
10820 dobj = findObjectByCatalogId(objId);
10821 /* OK to ignore entries we haven't got a DumpableObject for */
10822 if (dobj)
10823 {
10824 /* Cope with sub-object initprivs */
10825 if (objsubid != 0)
10826 {
10827 if (dobj->objType == DO_TABLE)
10828 {
10829 /* For a column initprivs, set the table's ACL flags */
10831 ((TableInfo *) dobj)->hascolumnACLs = true;
10832 }
10833 else
10834 pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10835 classoid, objoid, objsubid);
10836 continue;
10837 }
10838
10839 /*
10840 * We ignore any pg_init_privs.initprivs entry for the public
10841 * schema, as explained in getNamespaces().
10842 */
10843 if (dobj->objType == DO_NAMESPACE &&
10844 strcmp(dobj->name, "public") == 0)
10845 continue;
10846
10847 /* Else it had better be of a type we think has ACLs */
10848 if (dobj->objType == DO_NAMESPACE ||
10849 dobj->objType == DO_TYPE ||
10850 dobj->objType == DO_FUNC ||
10851 dobj->objType == DO_AGG ||
10852 dobj->objType == DO_TABLE ||
10853 dobj->objType == DO_PROCLANG ||
10854 dobj->objType == DO_FDW ||
10855 dobj->objType == DO_FOREIGN_SERVER)
10856 {
10858
10859 daobj->dacl.privtype = privtype;
10860 daobj->dacl.initprivs = pstrdup(initprivs);
10861 }
10862 else
10863 pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10864 classoid, objoid, objsubid);
10865 }
10866 }
10867 PQclear(res);
10868 }
10869
10870 destroyPQExpBuffer(query);
10871}

References appendPQExpBufferStr(), atooid, _dumpableObject::components, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_AGG, DO_FDW, DO_FOREIGN_SERVER, DO_FUNC, DO_NAMESPACE, DO_PROCLANG, DO_TABLE, DO_TYPE, _tableInfo::dobj, DUMP_COMPONENT_ACL, ExecuteSqlQuery(), fb(), findObjectByCatalogId(), findTableByOid(), _tableInfo::hascolumnACLs, i, _dumpableObject::name, _dumpableObject::objType, CatalogId::oid, pg_log_warning, PGRES_TUPLES_OK, PQclear, PQgetvalue, PQntuples, printfPQExpBuffer(), pstrdup(), and CatalogId::tableoid.

Referenced by main().

◆ getAggregates()

void getAggregates ( Archive fout)

Definition at line 6786 of file pg_dump.c.

6787{
6788 DumpOptions *dopt = fout->dopt;
6789 PGresult *res;
6790 int ntups;
6791 int i;
6794 int i_tableoid;
6795 int i_oid;
6796 int i_aggname;
6797 int i_aggnamespace;
6798 int i_pronargs;
6799 int i_proargtypes;
6800 int i_proowner;
6801 int i_aggacl;
6802 int i_acldefault;
6803
6804 /*
6805 * Find all interesting aggregates. See comment in getFuncs() for the
6806 * rationale behind the filtering logic.
6807 */
6808 if (fout->remoteVersion >= 90600)
6809 {
6810 const char *agg_check;
6811
6812 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
6813 : "p.proisagg");
6814
6815 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
6816 "p.proname AS aggname, "
6817 "p.pronamespace AS aggnamespace, "
6818 "p.pronargs, p.proargtypes, "
6819 "p.proowner, "
6820 "p.proacl AS aggacl, "
6821 "acldefault('f', p.proowner) AS acldefault "
6822 "FROM pg_proc p "
6823 "LEFT JOIN pg_init_privs pip ON "
6824 "(p.oid = pip.objoid "
6825 "AND pip.classoid = 'pg_proc'::regclass "
6826 "AND pip.objsubid = 0) "
6827 "WHERE %s AND ("
6828 "p.pronamespace != "
6829 "(SELECT oid FROM pg_namespace "
6830 "WHERE nspname = 'pg_catalog') OR "
6831 "p.proacl IS DISTINCT FROM pip.initprivs",
6832 agg_check);
6833 if (dopt->binary_upgrade)
6835 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6836 "classid = 'pg_proc'::regclass AND "
6837 "objid = p.oid AND "
6838 "refclassid = 'pg_extension'::regclass AND "
6839 "deptype = 'e')");
6840 appendPQExpBufferChar(query, ')');
6841 }
6842 else
6843 {
6844 appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
6845 "pronamespace AS aggnamespace, "
6846 "pronargs, proargtypes, "
6847 "proowner, "
6848 "proacl AS aggacl, "
6849 "acldefault('f', proowner) AS acldefault "
6850 "FROM pg_proc p "
6851 "WHERE proisagg AND ("
6852 "pronamespace != "
6853 "(SELECT oid FROM pg_namespace "
6854 "WHERE nspname = 'pg_catalog')");
6855 if (dopt->binary_upgrade)
6857 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6858 "classid = 'pg_proc'::regclass AND "
6859 "objid = p.oid AND "
6860 "refclassid = 'pg_extension'::regclass AND "
6861 "deptype = 'e')");
6862 appendPQExpBufferChar(query, ')');
6863 }
6864
6865 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6866
6867 ntups = PQntuples(res);
6868
6869 agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
6870
6871 i_tableoid = PQfnumber(res, "tableoid");
6872 i_oid = PQfnumber(res, "oid");
6873 i_aggname = PQfnumber(res, "aggname");
6874 i_aggnamespace = PQfnumber(res, "aggnamespace");
6875 i_pronargs = PQfnumber(res, "pronargs");
6876 i_proargtypes = PQfnumber(res, "proargtypes");
6877 i_proowner = PQfnumber(res, "proowner");
6878 i_aggacl = PQfnumber(res, "aggacl");
6879 i_acldefault = PQfnumber(res, "acldefault");
6880
6881 for (i = 0; i < ntups; i++)
6882 {
6883 agginfo[i].aggfn.dobj.objType = DO_AGG;
6884 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6885 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6886 AssignDumpId(&agginfo[i].aggfn.dobj);
6887 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
6888 agginfo[i].aggfn.dobj.namespace =
6890 agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
6891 agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6892 agginfo[i].aggfn.dacl.privtype = 0;
6893 agginfo[i].aggfn.dacl.initprivs = NULL;
6894 agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
6895 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
6896 agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
6897 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
6898 if (agginfo[i].aggfn.nargs == 0)
6899 agginfo[i].aggfn.argtypes = NULL;
6900 else
6901 {
6902 agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
6904 agginfo[i].aggfn.argtypes,
6905 agginfo[i].aggfn.nargs);
6906 }
6907 agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
6908
6909 /* Decide whether we want to dump it */
6910 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
6911
6912 /* Mark whether aggregate has an ACL */
6913 if (!PQgetisnull(res, i, i_aggacl))
6914 agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
6915 }
6916
6917 PQclear(res);
6918
6919 destroyPQExpBuffer(query);
6920}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), AssignDumpId(), atooid, _dumpOptions::binary_upgrade, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_AGG, DUMP_COMPONENT_ACL, ExecuteSqlQuery(), fb(), findNamespace(), getRoleName(), i, InvalidOid, parseOidArray(), pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getAttrName()

static const char * getAttrName ( int  attrnum,
const TableInfo tblInfo 
)
static

Definition at line 18254 of file pg_dump.c.

18255{
18256 if (attrnum > 0 && attrnum <= tblInfo->numatts)
18257 return tblInfo->attnames[attrnum - 1];
18258 switch (attrnum)
18259 {
18261 return "ctid";
18263 return "xmin";
18265 return "cmin";
18267 return "xmax";
18269 return "cmax";
18271 return "tableoid";
18272 }
18273 pg_fatal("invalid column number %d for table \"%s\"",
18274 attrnum, tblInfo->dobj.name);
18275 return NULL; /* keep compiler quiet */
18276}

References fb(), MaxCommandIdAttributeNumber, MaxTransactionIdAttributeNumber, MinCommandIdAttributeNumber, MinTransactionIdAttributeNumber, pg_fatal, SelfItemPointerAttributeNumber, and TableOidAttributeNumber.

Referenced by dumpConstraint(), and dumpTableSecLabel().

◆ getCasts()

void getCasts ( Archive fout)

Definition at line 9057 of file pg_dump.c.

9058{
9059 PGresult *res;
9060 int ntups;
9061 int i;
9064 int i_tableoid;
9065 int i_oid;
9066 int i_castsource;
9067 int i_casttarget;
9068 int i_castfunc;
9069 int i_castcontext;
9070 int i_castmethod;
9071
9072 if (fout->remoteVersion >= 140000)
9073 {
9074 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9075 "castsource, casttarget, castfunc, castcontext, "
9076 "castmethod "
9077 "FROM pg_cast c "
9078 "WHERE NOT EXISTS ( "
9079 "SELECT 1 FROM pg_range r "
9080 "WHERE c.castsource = r.rngtypid "
9081 "AND c.casttarget = r.rngmultitypid "
9082 ") "
9083 "ORDER BY 3,4");
9084 }
9085 else
9086 {
9087 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9088 "castsource, casttarget, castfunc, castcontext, "
9089 "castmethod "
9090 "FROM pg_cast ORDER BY 3,4");
9091 }
9092
9093 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9094
9095 ntups = PQntuples(res);
9096
9097 castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
9098
9099 i_tableoid = PQfnumber(res, "tableoid");
9100 i_oid = PQfnumber(res, "oid");
9101 i_castsource = PQfnumber(res, "castsource");
9102 i_casttarget = PQfnumber(res, "casttarget");
9103 i_castfunc = PQfnumber(res, "castfunc");
9104 i_castcontext = PQfnumber(res, "castcontext");
9105 i_castmethod = PQfnumber(res, "castmethod");
9106
9107 for (i = 0; i < ntups; i++)
9108 {
9112
9114 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9115 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9116 AssignDumpId(&castinfo[i].dobj);
9117 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
9118 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
9119 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
9120 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
9121 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
9122
9123 /*
9124 * Try to name cast as concatenation of typnames. This is only used
9125 * for purposes of sorting. If we fail to find either type, the name
9126 * will be an empty string.
9127 */
9129 sTypeInfo = findTypeByOid(castinfo[i].castsource);
9130 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
9131 if (sTypeInfo && tTypeInfo)
9132 appendPQExpBuffer(&namebuf, "%s %s",
9133 sTypeInfo->dobj.name, tTypeInfo->dobj.name);
9134 castinfo[i].dobj.name = namebuf.data;
9135
9136 /* Decide whether we want to dump it */
9138 }
9139
9140 PQclear(res);
9141
9142 destroyPQExpBuffer(query);
9143}

References appendPQExpBuffer(), appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_CAST, _typeInfo::dobj, ExecuteSqlQuery(), fb(), findTypeByOid(), i, initPQExpBuffer(), _dumpableObject::objType, pg_malloc(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableCast().

Referenced by getSchemaData().

◆ getCollations()

void getCollations ( Archive fout)

Definition at line 6456 of file pg_dump.c.

6457{
6458 PGresult *res;
6459 int ntups;
6460 int i;
6461 PQExpBuffer query;
6463 int i_tableoid;
6464 int i_oid;
6465 int i_collname;
6466 int i_collnamespace;
6467 int i_collowner;
6468 int i_collencoding;
6469
6470 query = createPQExpBuffer();
6471
6472 /*
6473 * find all collations, including builtin collations; we filter out
6474 * system-defined collations at dump-out time.
6475 */
6476
6477 appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
6478 "collnamespace, "
6479 "collowner, "
6480 "collencoding "
6481 "FROM pg_collation");
6482
6483 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6484
6485 ntups = PQntuples(res);
6486
6487 collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
6488
6489 i_tableoid = PQfnumber(res, "tableoid");
6490 i_oid = PQfnumber(res, "oid");
6491 i_collname = PQfnumber(res, "collname");
6492 i_collnamespace = PQfnumber(res, "collnamespace");
6493 i_collowner = PQfnumber(res, "collowner");
6494 i_collencoding = PQfnumber(res, "collencoding");
6495
6496 for (i = 0; i < ntups; i++)
6497 {
6498 collinfo[i].dobj.objType = DO_COLLATION;
6499 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6500 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6501 AssignDumpId(&collinfo[i].dobj);
6502 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
6503 collinfo[i].dobj.namespace =
6505 collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
6506 collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
6507
6508 /* Decide whether we want to dump it */
6510 }
6511
6512 PQclear(res);
6513
6514 destroyPQExpBuffer(query);
6515}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_COLLATION, ExecuteSqlQuery(), fb(), findNamespace(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getConstraints()

void getConstraints ( Archive fout,
TableInfo  tblinfo[],
int  numTables 
)

Definition at line 8308 of file pg_dump.c.

8309{
8312 PGresult *res;
8313 int ntups;
8314 int curtblindx;
8317 int i_contableoid,
8318 i_conoid,
8319 i_conrelid,
8320 i_conname,
8322 i_conindid,
8323 i_condef;
8324
8325 /*
8326 * We want to perform just one query against pg_constraint. However, we
8327 * mustn't try to select every row of the catalog and then sort it out on
8328 * the client side, because some of the server-side functions we need
8329 * would be unsafe to apply to tables we don't have lock on. Hence, we
8330 * build an array of the OIDs of tables we care about (and now have lock
8331 * on!), and use a WHERE clause to constrain which rows are selected.
8332 */
8334 for (int i = 0; i < numTables; i++)
8335 {
8336 TableInfo *tinfo = &tblinfo[i];
8337
8338 if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
8339 continue;
8340
8341 /* OK, we need info for this table */
8342 if (tbloids->len > 1) /* do we have more than the '{'? */
8344 appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
8345 }
8347
8349 "SELECT c.tableoid, c.oid, "
8350 "conrelid, conname, confrelid, ");
8351 if (fout->remoteVersion >= 110000)
8352 appendPQExpBufferStr(query, "conindid, ");
8353 else
8354 appendPQExpBufferStr(query, "0 AS conindid, ");
8355 appendPQExpBuffer(query,
8356 "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
8357 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8358 "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
8359 "WHERE contype = 'f' ",
8360 tbloids->data);
8361 if (fout->remoteVersion >= 110000)
8363 "AND conparentid = 0 ");
8365 "ORDER BY conrelid, conname");
8366
8367 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8368
8369 ntups = PQntuples(res);
8370
8371 i_contableoid = PQfnumber(res, "tableoid");
8372 i_conoid = PQfnumber(res, "oid");
8373 i_conrelid = PQfnumber(res, "conrelid");
8374 i_conname = PQfnumber(res, "conname");
8375 i_confrelid = PQfnumber(res, "confrelid");
8376 i_conindid = PQfnumber(res, "conindid");
8377 i_condef = PQfnumber(res, "condef");
8378
8379 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
8380
8381 curtblindx = -1;
8382 for (int j = 0; j < ntups; j++)
8383 {
8384 Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
8386
8387 /*
8388 * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8389 * order.
8390 */
8391 if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
8392 {
8393 while (++curtblindx < numTables)
8394 {
8395 tbinfo = &tblinfo[curtblindx];
8396 if (tbinfo->dobj.catId.oid == conrelid)
8397 break;
8398 }
8399 if (curtblindx >= numTables)
8400 pg_fatal("unrecognized table OID %u", conrelid);
8401 }
8402
8403 constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
8404 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
8405 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
8406 AssignDumpId(&constrinfo[j].dobj);
8407 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
8408 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
8409 constrinfo[j].contable = tbinfo;
8410 constrinfo[j].condomain = NULL;
8411 constrinfo[j].contype = 'f';
8412 constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
8413 constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
8414 constrinfo[j].conindex = 0;
8415 constrinfo[j].condeferrable = false;
8416 constrinfo[j].condeferred = false;
8417 constrinfo[j].conislocal = true;
8418 constrinfo[j].separate = true;
8419
8420 /*
8421 * Restoring an FK that points to a partitioned table requires that
8422 * all partition indexes have been attached beforehand. Ensure that
8423 * happens by making the constraint depend on each index partition
8424 * attach object.
8425 */
8426 reftable = findTableByOid(constrinfo[j].confrelid);
8427 if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
8428 {
8429 Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));
8430
8431 if (indexOid != InvalidOid)
8432 {
8433 for (int k = 0; k < reftable->numIndexes; k++)
8434 {
8436
8437 /* not our index? */
8438 if (reftable->indexes[k].dobj.catId.oid != indexOid)
8439 continue;
8440
8441 refidx = &reftable->indexes[k];
8443 break;
8444 }
8445 }
8446 }
8447 }
8448
8449 PQclear(res);
8450
8451 destroyPQExpBuffer(query);
8453}

References addConstrChildIdxDeps(), appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_FK_CONSTRAINT, DUMP_COMPONENT_DEFINITION, ExecuteSqlQuery(), fb(), findTableByOid(), i, InvalidOid, j, pg_fatal, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and tinfo.

Referenced by getSchemaData().

◆ getConversions()

void getConversions ( Archive fout)

Definition at line 6522 of file pg_dump.c.

6523{
6524 PGresult *res;
6525 int ntups;
6526 int i;
6527 PQExpBuffer query;
6529 int i_tableoid;
6530 int i_oid;
6531 int i_conname;
6532 int i_connamespace;
6533 int i_conowner;
6534
6535 query = createPQExpBuffer();
6536
6537 /*
6538 * find all conversions, including builtin conversions; we filter out
6539 * system-defined conversions at dump-out time.
6540 */
6541
6542 appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
6543 "connamespace, "
6544 "conowner "
6545 "FROM pg_conversion");
6546
6547 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6548
6549 ntups = PQntuples(res);
6550
6551 convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
6552
6553 i_tableoid = PQfnumber(res, "tableoid");
6554 i_oid = PQfnumber(res, "oid");
6555 i_conname = PQfnumber(res, "conname");
6556 i_connamespace = PQfnumber(res, "connamespace");
6557 i_conowner = PQfnumber(res, "conowner");
6558
6559 for (i = 0; i < ntups; i++)
6560 {
6561 convinfo[i].dobj.objType = DO_CONVERSION;
6562 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6563 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6564 AssignDumpId(&convinfo[i].dobj);
6565 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
6566 convinfo[i].dobj.namespace =
6568 convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
6569
6570 /* Decide whether we want to dump it */
6572 }
6573
6574 PQclear(res);
6575
6576 destroyPQExpBuffer(query);
6577}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_CONVERSION, ExecuteSqlQuery(), fb(), findNamespace(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getDefaultACLs()

void getDefaultACLs ( Archive fout)

Definition at line 10600 of file pg_dump.c.

10601{
10602 DumpOptions *dopt = fout->dopt;
10604 PQExpBuffer query;
10605 PGresult *res;
10606 int i_oid;
10607 int i_tableoid;
10608 int i_defaclrole;
10610 int i_defaclobjtype;
10611 int i_defaclacl;
10612 int i_acldefault;
10613 int i,
10614 ntups;
10615
10616 query = createPQExpBuffer();
10617
10618 /*
10619 * Global entries (with defaclnamespace=0) replace the hard-wired default
10620 * ACL for their object type. We should dump them as deltas from the
10621 * default ACL, since that will be used as a starting point for
10622 * interpreting the ALTER DEFAULT PRIVILEGES commands. On the other hand,
10623 * non-global entries can only add privileges not revoke them. We must
10624 * dump those as-is (i.e., as deltas from an empty ACL).
10625 *
10626 * We can use defaclobjtype as the object type for acldefault(), except
10627 * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
10628 * 's'.
10629 */
10631 "SELECT oid, tableoid, "
10632 "defaclrole, "
10633 "defaclnamespace, "
10634 "defaclobjtype, "
10635 "defaclacl, "
10636 "CASE WHEN defaclnamespace = 0 THEN "
10637 "acldefault(CASE WHEN defaclobjtype = 'S' "
10638 "THEN 's'::\"char\" ELSE defaclobjtype END, "
10639 "defaclrole) ELSE '{}' END AS acldefault "
10640 "FROM pg_default_acl");
10641
10642 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10643
10644 ntups = PQntuples(res);
10645
10646 daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
10647
10648 i_oid = PQfnumber(res, "oid");
10649 i_tableoid = PQfnumber(res, "tableoid");
10650 i_defaclrole = PQfnumber(res, "defaclrole");
10651 i_defaclnamespace = PQfnumber(res, "defaclnamespace");
10652 i_defaclobjtype = PQfnumber(res, "defaclobjtype");
10653 i_defaclacl = PQfnumber(res, "defaclacl");
10654 i_acldefault = PQfnumber(res, "acldefault");
10655
10656 for (i = 0; i < ntups; i++)
10657 {
10659
10660 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
10661 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10662 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10663 AssignDumpId(&daclinfo[i].dobj);
10664 /* cheesy ... is it worth coming up with a better object name? */
10665 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
10666
10667 if (nspid != InvalidOid)
10668 daclinfo[i].dobj.namespace = findNamespace(nspid);
10669 else
10670 daclinfo[i].dobj.namespace = NULL;
10671
10672 daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
10673 daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10674 daclinfo[i].dacl.privtype = 0;
10675 daclinfo[i].dacl.initprivs = NULL;
10676 daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
10677 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
10678
10679 /* Default ACLs are ACLs, of course */
10680 daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10681
10682 /* Decide whether we want to dump it */
10684 }
10685
10686 PQclear(res);
10687
10688 destroyPQExpBuffer(query);
10689}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_DEFAULT_ACL, DUMP_COMPONENT_ACL, ExecuteSqlQuery(), fb(), findNamespace(), getRoleName(), i, InvalidOid, nspid, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableDefaultACL().

Referenced by getSchemaData().

◆ getDependencies()

static void getDependencies ( Archive fout)
static

Definition at line 20194 of file pg_dump.c.

20195{
20196 PQExpBuffer query;
20197 PGresult *res;
20198 int ntups,
20199 i;
20200 int i_classid,
20201 i_objid,
20203 i_refobjid,
20204 i_deptype;
20205 DumpableObject *dobj,
20206 *refdobj;
20207
20208 pg_log_info("reading dependency data");
20209
20210 query = createPQExpBuffer();
20211
20212 /*
20213 * Messy query to collect the dependency data we need. Note that we
20214 * ignore the sub-object column, so that dependencies of or on a column
20215 * look the same as dependencies of or on a whole table.
20216 *
20217 * PIN dependencies aren't interesting, and EXTENSION dependencies were
20218 * already processed by getExtensionMembership.
20219 */
20220 appendPQExpBufferStr(query, "SELECT "
20221 "classid, objid, refclassid, refobjid, deptype "
20222 "FROM pg_depend "
20223 "WHERE deptype != 'p' AND deptype != 'e'\n");
20224
20225 /*
20226 * Since we don't treat pg_amop entries as separate DumpableObjects, we
20227 * have to translate their dependencies into dependencies of their parent
20228 * opfamily. Ignore internal dependencies though, as those will point to
20229 * their parent opclass, which we needn't consider here (and if we did,
20230 * it'd just result in circular dependencies). Also, "loose" opfamily
20231 * entries will have dependencies on their parent opfamily, which we
20232 * should drop since they'd likewise become useless self-dependencies.
20233 * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
20234 */
20235 appendPQExpBufferStr(query, "UNION ALL\n"
20236 "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
20237 "FROM pg_depend d, pg_amop o "
20238 "WHERE deptype NOT IN ('p', 'e', 'i') AND "
20239 "classid = 'pg_amop'::regclass AND objid = o.oid "
20240 "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
20241
20242 /* Likewise for pg_amproc entries */
20243 appendPQExpBufferStr(query, "UNION ALL\n"
20244 "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
20245 "FROM pg_depend d, pg_amproc p "
20246 "WHERE deptype NOT IN ('p', 'e', 'i') AND "
20247 "classid = 'pg_amproc'::regclass AND objid = p.oid "
20248 "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
20249
20250 /* Sort the output for efficiency below */
20251 appendPQExpBufferStr(query, "ORDER BY 1,2");
20252
20253 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
20254
20255 ntups = PQntuples(res);
20256
20257 i_classid = PQfnumber(res, "classid");
20258 i_objid = PQfnumber(res, "objid");
20259 i_refclassid = PQfnumber(res, "refclassid");
20260 i_refobjid = PQfnumber(res, "refobjid");
20261 i_deptype = PQfnumber(res, "deptype");
20262
20263 /*
20264 * Since we ordered the SELECT by referencing ID, we can expect that
20265 * multiple entries for the same object will appear together; this saves
20266 * on searches.
20267 */
20268 dobj = NULL;
20269
20270 for (i = 0; i < ntups; i++)
20271 {
20272 CatalogId objId;
20274 char deptype;
20275
20276 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
20277 objId.oid = atooid(PQgetvalue(res, i, i_objid));
20278 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
20279 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
20280 deptype = *(PQgetvalue(res, i, i_deptype));
20281
20282 if (dobj == NULL ||
20283 dobj->catId.tableoid != objId.tableoid ||
20284 dobj->catId.oid != objId.oid)
20285 dobj = findObjectByCatalogId(objId);
20286
20287 /*
20288 * Failure to find objects mentioned in pg_depend is not unexpected,
20289 * since for example we don't collect info about TOAST tables.
20290 */
20291 if (dobj == NULL)
20292 {
20293#ifdef NOT_USED
20294 pg_log_warning("no referencing object %u %u",
20295 objId.tableoid, objId.oid);
20296#endif
20297 continue;
20298 }
20299
20301
20302 if (refdobj == NULL)
20303 {
20304#ifdef NOT_USED
20305 pg_log_warning("no referenced object %u %u",
20306 refobjId.tableoid, refobjId.oid);
20307#endif
20308 continue;
20309 }
20310
20311 /*
20312 * For 'x' dependencies, mark the object for later; we still add the
20313 * normal dependency, for possible ordering purposes. Currently
20314 * pg_dump_sort.c knows to put extensions ahead of all object types
20315 * that could possibly depend on them, but this is safer.
20316 */
20317 if (deptype == 'x')
20318 dobj->depends_on_ext = true;
20319
20320 /*
20321 * Ordinarily, table rowtypes have implicit dependencies on their
20322 * tables. However, for a composite type the implicit dependency goes
20323 * the other way in pg_depend; which is the right thing for DROP but
20324 * it doesn't produce the dependency ordering we need. So in that one
20325 * case, we reverse the direction of the dependency.
20326 */
20327 if (deptype == 'i' &&
20328 dobj->objType == DO_TABLE &&
20329 refdobj->objType == DO_TYPE)
20331 else
20332 /* normal case */
20333 addObjectDependency(dobj, refdobj->dumpId);
20334 }
20335
20336 PQclear(res);
20337
20338 destroyPQExpBuffer(query);
20339}

References addObjectDependency(), appendPQExpBufferStr(), atooid, _dumpableObject::catId, createPQExpBuffer(), PQExpBufferData::data, _dumpableObject::depends_on_ext, destroyPQExpBuffer(), DO_TABLE, DO_TYPE, _dumpableObject::dumpId, ExecuteSqlQuery(), fb(), findObjectByCatalogId(), i, _dumpableObject::objType, CatalogId::oid, pg_log_info, pg_log_warning, PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and CatalogId::tableoid.

Referenced by main().

◆ getDomainConstraints()

static void getDomainConstraints ( Archive fout,
TypeInfo tyinfo 
)
static

Definition at line 8490 of file pg_dump.c.

8491{
8494 PGresult *res;
8495 int i_tableoid,
8496 i_oid,
8497 i_conname,
8498 i_consrc,
8500 i_contype;
8501 int ntups;
8502
8503 if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
8504 {
8505 /*
8506 * Set up query for constraint-specific details. For servers 17 and
8507 * up, domains have constraints of type 'n' as well as 'c', otherwise
8508 * just the latter.
8509 */
8510 appendPQExpBuffer(query,
8511 "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
8512 "SELECT tableoid, oid, conname, "
8513 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8514 "convalidated, contype "
8515 "FROM pg_catalog.pg_constraint "
8516 "WHERE contypid = $1 AND contype IN (%s) "
8517 "ORDER BY conname",
8518 fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
8519
8520 ExecuteSqlStatement(fout, query->data);
8521
8522 fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
8523 }
8524
8525 printfPQExpBuffer(query,
8526 "EXECUTE getDomainConstraints('%u')",
8527 tyinfo->dobj.catId.oid);
8528
8529 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8530
8531 ntups = PQntuples(res);
8532
8533 i_tableoid = PQfnumber(res, "tableoid");
8534 i_oid = PQfnumber(res, "oid");
8535 i_conname = PQfnumber(res, "conname");
8536 i_consrc = PQfnumber(res, "consrc");
8537 i_convalidated = PQfnumber(res, "convalidated");
8538 i_contype = PQfnumber(res, "contype");
8539
8540 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
8541 tyinfo->domChecks = constrinfo;
8542
8543 /* 'i' tracks result rows; 'j' counts CHECK constraints */
8544 for (int i = 0, j = 0; i < ntups; i++)
8545 {
8546 bool validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
8547 char contype = (PQgetvalue(res, i, i_contype))[0];
8548 ConstraintInfo *constraint;
8549
8550 if (contype == CONSTRAINT_CHECK)
8551 {
8552 constraint = &constrinfo[j++];
8553 tyinfo->nDomChecks++;
8554 }
8555 else
8556 {
8557 Assert(contype == CONSTRAINT_NOTNULL);
8558 Assert(tyinfo->notnull == NULL);
8559 /* use last item in array for the not-null constraint */
8560 tyinfo->notnull = &(constrinfo[ntups - 1]);
8561 constraint = tyinfo->notnull;
8562 }
8563
8564 constraint->dobj.objType = DO_CONSTRAINT;
8565 constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8566 constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8567 AssignDumpId(&(constraint->dobj));
8568 constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
8569 constraint->dobj.namespace = tyinfo->dobj.namespace;
8570 constraint->contable = NULL;
8571 constraint->condomain = tyinfo;
8572 constraint->contype = contype;
8573 constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
8574 constraint->confrelid = InvalidOid;
8575 constraint->conindex = 0;
8576 constraint->condeferrable = false;
8577 constraint->condeferred = false;
8578 constraint->conislocal = true;
8579
8580 constraint->separate = !validated;
8581
8582 /*
8583 * Make the domain depend on the constraint, ensuring it won't be
8584 * output till any constraint dependencies are OK. If the constraint
8585 * has not been validated, it's going to be dumped after the domain
8586 * anyway, so this doesn't matter.
8587 */
8588 if (validated)
8589 addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
8590 }
8591
8592 PQclear(res);
8593
8594 destroyPQExpBuffer(query);
8595}

References addObjectDependency(), appendPQExpBuffer(), Assert, AssignDumpId(), atooid, _dumpableObject::catId, _constraintInfo::condef, _constraintInfo::condeferrable, _constraintInfo::condeferred, _constraintInfo::condomain, _constraintInfo::confrelid, _constraintInfo::conindex, _constraintInfo::conislocal, _constraintInfo::contable, _constraintInfo::contype, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_CONSTRAINT, _constraintInfo::dobj, _dumpableObject::dumpId, ExecuteSqlQuery(), ExecuteSqlStatement(), fb(), i, InvalidOid, j, _dumpableObject::name, _dumpableObject::objType, CatalogId::oid, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, PREPQUERY_GETDOMAINCONSTRAINTS, printfPQExpBuffer(), _constraintInfo::separate, and CatalogId::tableoid.

Referenced by getTypes().

◆ getEventTriggers()

void getEventTriggers ( Archive fout)

Definition at line 8895 of file pg_dump.c.

8896{
8897 int i;
8898 PQExpBuffer query;
8899 PGresult *res;
8901 int i_tableoid,
8902 i_oid,
8903 i_evtname,
8904 i_evtevent,
8905 i_evtowner,
8906 i_evttags,
8907 i_evtfname,
8909 int ntups;
8910
8911 /* Before 9.3, there are no event triggers */
8912 if (fout->remoteVersion < 90300)
8913 return;
8914
8915 query = createPQExpBuffer();
8916
8918 "SELECT e.tableoid, e.oid, evtname, evtenabled, "
8919 "evtevent, evtowner, "
8920 "array_to_string(array("
8921 "select quote_literal(x) "
8922 " from unnest(evttags) as t(x)), ', ') as evttags, "
8923 "e.evtfoid::regproc as evtfname "
8924 "FROM pg_event_trigger e "
8925 "ORDER BY e.oid");
8926
8927 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8928
8929 ntups = PQntuples(res);
8930
8931 evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
8932
8933 i_tableoid = PQfnumber(res, "tableoid");
8934 i_oid = PQfnumber(res, "oid");
8935 i_evtname = PQfnumber(res, "evtname");
8936 i_evtevent = PQfnumber(res, "evtevent");
8937 i_evtowner = PQfnumber(res, "evtowner");
8938 i_evttags = PQfnumber(res, "evttags");
8939 i_evtfname = PQfnumber(res, "evtfname");
8940 i_evtenabled = PQfnumber(res, "evtenabled");
8941
8942 for (i = 0; i < ntups; i++)
8943 {
8944 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
8945 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8946 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8947 AssignDumpId(&evtinfo[i].dobj);
8948 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
8949 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
8950 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
8951 evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
8952 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
8953 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
8954 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
8955
8956 /* Decide whether we want to dump it */
8958 }
8959
8960 PQclear(res);
8961
8962 destroyPQExpBuffer(query);
8963}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_EVENT_TRIGGER, ExecuteSqlQuery(), fb(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getExtendedStatistics()

void getExtendedStatistics ( Archive fout)

Definition at line 8226 of file pg_dump.c.

8227{
8228 PQExpBuffer query;
8229 PGresult *res;
8231 int ntups;
8232 int i_tableoid;
8233 int i_oid;
8234 int i_stxname;
8235 int i_stxnamespace;
8236 int i_stxowner;
8237 int i_stxrelid;
8238 int i_stattarget;
8239 int i;
8240
8241 /* Extended statistics were new in v10 */
8242 if (fout->remoteVersion < 100000)
8243 return;
8244
8245 query = createPQExpBuffer();
8246
8247 if (fout->remoteVersion < 130000)
8248 appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
8249 "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
8250 "FROM pg_catalog.pg_statistic_ext");
8251 else
8252 appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
8253 "stxnamespace, stxowner, stxrelid, stxstattarget "
8254 "FROM pg_catalog.pg_statistic_ext");
8255
8256 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8257
8258 ntups = PQntuples(res);
8259
8260 i_tableoid = PQfnumber(res, "tableoid");
8261 i_oid = PQfnumber(res, "oid");
8262 i_stxname = PQfnumber(res, "stxname");
8263 i_stxnamespace = PQfnumber(res, "stxnamespace");
8264 i_stxowner = PQfnumber(res, "stxowner");
8265 i_stxrelid = PQfnumber(res, "stxrelid");
8266 i_stattarget = PQfnumber(res, "stxstattarget");
8267
8268 statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
8269
8270 for (i = 0; i < ntups; i++)
8271 {
8272 statsextinfo[i].dobj.objType = DO_STATSEXT;
8273 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8274 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8275 AssignDumpId(&statsextinfo[i].dobj);
8276 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
8277 statsextinfo[i].dobj.namespace =
8279 statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
8280 statsextinfo[i].stattable =
8282 if (PQgetisnull(res, i, i_stattarget))
8283 statsextinfo[i].stattarget = -1;
8284 else
8285 statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
8286
8287 /* Decide whether we want to dump it */
8289
8290 if (fout->dopt->dumpStatistics)
8291 statsextinfo[i].dobj.components |= DUMP_COMPONENT_STATISTICS;
8292 }
8293
8294 PQclear(res);
8295 destroyPQExpBuffer(query);
8296}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_STATSEXT, DUMP_COMPONENT_STATISTICS, ExecuteSqlQuery(), fb(), findNamespace(), findTableByOid(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, and selectDumpableStatisticsObject().

Referenced by getSchemaData().

◆ getExtensionMembership()

void getExtensionMembership ( Archive fout,
ExtensionInfo  extinfo[],
int  numExtensions 
)

Definition at line 19920 of file pg_dump.c.

19922{
19923 PQExpBuffer query;
19924 PGresult *res;
19925 int ntups,
19926 i;
19927 int i_classid,
19928 i_objid,
19929 i_refobjid;
19930 ExtensionInfo *ext;
19931
19932 /* Nothing to do if no extensions */
19933 if (numExtensions == 0)
19934 return;
19935
19936 query = createPQExpBuffer();
19937
19938 /* refclassid constraint is redundant but may speed the search */
19939 appendPQExpBufferStr(query, "SELECT "
19940 "classid, objid, refobjid "
19941 "FROM pg_depend "
19942 "WHERE refclassid = 'pg_extension'::regclass "
19943 "AND deptype = 'e' "
19944 "ORDER BY 3");
19945
19946 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19947
19948 ntups = PQntuples(res);
19949
19950 i_classid = PQfnumber(res, "classid");
19951 i_objid = PQfnumber(res, "objid");
19952 i_refobjid = PQfnumber(res, "refobjid");
19953
19954 /*
19955 * Since we ordered the SELECT by referenced ID, we can expect that
19956 * multiple entries for the same extension will appear together; this
19957 * saves on searches.
19958 */
19959 ext = NULL;
19960
19961 for (i = 0; i < ntups; i++)
19962 {
19963 CatalogId objId;
19964 Oid extId;
19965
19966 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
19967 objId.oid = atooid(PQgetvalue(res, i, i_objid));
19969
19970 if (ext == NULL ||
19971 ext->dobj.catId.oid != extId)
19973
19974 if (ext == NULL)
19975 {
19976 /* shouldn't happen */
19977 pg_log_warning("could not find referenced extension %u", extId);
19978 continue;
19979 }
19980
19981 recordExtensionMembership(objId, ext);
19982 }
19983
19984 PQclear(res);
19985
19986 destroyPQExpBuffer(query);
19987}

References appendPQExpBufferStr(), atooid, _dumpableObject::catId, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), _extensionInfo::dobj, ExecuteSqlQuery(), fb(), findExtensionByOid(), i, CatalogId::oid, pg_log_warning, PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, recordExtensionMembership(), and CatalogId::tableoid.

Referenced by getSchemaData().

◆ getExtensions()

ExtensionInfo * getExtensions ( Archive fout,
int numExtensions 
)

Definition at line 6137 of file pg_dump.c.

6138{
6139 DumpOptions *dopt = fout->dopt;
6140 PGresult *res;
6141 int ntups;
6142 int i;
6143 PQExpBuffer query;
6145 int i_tableoid;
6146 int i_oid;
6147 int i_extname;
6148 int i_nspname;
6149 int i_extrelocatable;
6150 int i_extversion;
6151 int i_extconfig;
6152 int i_extcondition;
6153
6154 query = createPQExpBuffer();
6155
6156 appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
6157 "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
6158 "FROM pg_extension x "
6159 "JOIN pg_namespace n ON n.oid = x.extnamespace");
6160
6161 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6162
6163 ntups = PQntuples(res);
6164 if (ntups == 0)
6165 goto cleanup;
6166
6167 extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
6168
6169 i_tableoid = PQfnumber(res, "tableoid");
6170 i_oid = PQfnumber(res, "oid");
6171 i_extname = PQfnumber(res, "extname");
6172 i_nspname = PQfnumber(res, "nspname");
6173 i_extrelocatable = PQfnumber(res, "extrelocatable");
6174 i_extversion = PQfnumber(res, "extversion");
6175 i_extconfig = PQfnumber(res, "extconfig");
6176 i_extcondition = PQfnumber(res, "extcondition");
6177
6178 for (i = 0; i < ntups; i++)
6179 {
6180 extinfo[i].dobj.objType = DO_EXTENSION;
6181 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6182 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6183 AssignDumpId(&extinfo[i].dobj);
6184 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
6185 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
6186 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
6187 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
6188 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
6189 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
6190
6191 /* Decide whether we want to dump it */
6193 }
6194
6195cleanup:
6196 PQclear(res);
6197 destroyPQExpBuffer(query);
6198
6199 *numExtensions = ntups;
6200
6201 return extinfo;
6202}

References appendPQExpBufferStr(), AssignDumpId(), atooid, cleanup(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_EXTENSION, ExecuteSqlQuery(), fb(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableExtension().

Referenced by getSchemaData().

◆ getForeignDataWrappers()

void getForeignDataWrappers ( Archive fout)

Definition at line 10428 of file pg_dump.c.

10429{
10430 PGresult *res;
10431 int ntups;
10432 int i;
10433 PQExpBuffer query;
10435 int i_tableoid;
10436 int i_oid;
10437 int i_fdwname;
10438 int i_fdwowner;
10439 int i_fdwhandler;
10440 int i_fdwvalidator;
10441 int i_fdwacl;
10442 int i_acldefault;
10443 int i_fdwoptions;
10444
10445 query = createPQExpBuffer();
10446
10447 appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
10448 "fdwowner, "
10449 "fdwhandler::pg_catalog.regproc, "
10450 "fdwvalidator::pg_catalog.regproc, "
10451 "fdwacl, "
10452 "acldefault('F', fdwowner) AS acldefault, "
10453 "array_to_string(ARRAY("
10454 "SELECT quote_ident(option_name) || ' ' || "
10455 "quote_literal(option_value) "
10456 "FROM pg_options_to_table(fdwoptions) "
10457 "ORDER BY option_name"
10458 "), E',\n ') AS fdwoptions "
10459 "FROM pg_foreign_data_wrapper");
10460
10461 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10462
10463 ntups = PQntuples(res);
10464
10465 fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
10466
10467 i_tableoid = PQfnumber(res, "tableoid");
10468 i_oid = PQfnumber(res, "oid");
10469 i_fdwname = PQfnumber(res, "fdwname");
10470 i_fdwowner = PQfnumber(res, "fdwowner");
10471 i_fdwhandler = PQfnumber(res, "fdwhandler");
10472 i_fdwvalidator = PQfnumber(res, "fdwvalidator");
10473 i_fdwacl = PQfnumber(res, "fdwacl");
10474 i_acldefault = PQfnumber(res, "acldefault");
10475 i_fdwoptions = PQfnumber(res, "fdwoptions");
10476
10477 for (i = 0; i < ntups; i++)
10478 {
10479 fdwinfo[i].dobj.objType = DO_FDW;
10480 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10481 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10482 AssignDumpId(&fdwinfo[i].dobj);
10483 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
10484 fdwinfo[i].dobj.namespace = NULL;
10485 fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
10486 fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10487 fdwinfo[i].dacl.privtype = 0;
10488 fdwinfo[i].dacl.initprivs = NULL;
10489 fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
10490 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
10491 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
10492 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
10493
10494 /* Decide whether we want to dump it */
10496
10497 /* Mark whether FDW has an ACL */
10498 if (!PQgetisnull(res, i, i_fdwacl))
10499 fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10500 }
10501
10502 PQclear(res);
10503
10504 destroyPQExpBuffer(query);
10505}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_FDW, DUMP_COMPONENT_ACL, ExecuteSqlQuery(), fb(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getForeignServers()

void getForeignServers ( Archive fout)

Definition at line 10512 of file pg_dump.c.

10513{
10514 PGresult *res;
10515 int ntups;
10516 int i;
10517 PQExpBuffer query;
10519 int i_tableoid;
10520 int i_oid;
10521 int i_srvname;
10522 int i_srvowner;
10523 int i_srvfdw;
10524 int i_srvtype;
10525 int i_srvversion;
10526 int i_srvacl;
10527 int i_acldefault;
10528 int i_srvoptions;
10529
10530 query = createPQExpBuffer();
10531
10532 appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
10533 "srvowner, "
10534 "srvfdw, srvtype, srvversion, srvacl, "
10535 "acldefault('S', srvowner) AS acldefault, "
10536 "array_to_string(ARRAY("
10537 "SELECT quote_ident(option_name) || ' ' || "
10538 "quote_literal(option_value) "
10539 "FROM pg_options_to_table(srvoptions) "
10540 "ORDER BY option_name"
10541 "), E',\n ') AS srvoptions "
10542 "FROM pg_foreign_server");
10543
10544 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10545
10546 ntups = PQntuples(res);
10547
10549
10550 i_tableoid = PQfnumber(res, "tableoid");
10551 i_oid = PQfnumber(res, "oid");
10552 i_srvname = PQfnumber(res, "srvname");
10553 i_srvowner = PQfnumber(res, "srvowner");
10554 i_srvfdw = PQfnumber(res, "srvfdw");
10555 i_srvtype = PQfnumber(res, "srvtype");
10556 i_srvversion = PQfnumber(res, "srvversion");
10557 i_srvacl = PQfnumber(res, "srvacl");
10558 i_acldefault = PQfnumber(res, "acldefault");
10559 i_srvoptions = PQfnumber(res, "srvoptions");
10560
10561 for (i = 0; i < ntups; i++)
10562 {
10563 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
10564 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10565 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10566 AssignDumpId(&srvinfo[i].dobj);
10567 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
10568 srvinfo[i].dobj.namespace = NULL;
10569 srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
10570 srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10571 srvinfo[i].dacl.privtype = 0;
10572 srvinfo[i].dacl.initprivs = NULL;
10573 srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
10574 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
10575 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
10576 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
10577 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
10578
10579 /* Decide whether we want to dump it */
10581
10582 /* Servers have user mappings */
10583 srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
10584
10585 /* Mark whether server has an ACL */
10586 if (!PQgetisnull(res, i, i_srvacl))
10587 srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10588 }
10589
10590 PQclear(res);
10591
10592 destroyPQExpBuffer(query);
10593}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_FOREIGN_SERVER, DUMP_COMPONENT_ACL, DUMP_COMPONENT_USERMAP, ExecuteSqlQuery(), fb(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getFormattedOperatorName()

static char * getFormattedOperatorName ( const char oproid)
static

Definition at line 14383 of file pg_dump.c.

14384{
14386
14387 /* In all cases "0" means a null reference */
14388 if (strcmp(oproid, "0") == 0)
14389 return NULL;
14390
14392 if (oprInfo == NULL)
14393 {
14394 pg_log_warning("could not find operator with OID %s",
14395 oproid);
14396 return NULL;
14397 }
14398
14399 return psprintf("OPERATOR(%s.%s)",
14400 fmtId(oprInfo->dobj.namespace->dobj.name),
14401 oprInfo->dobj.name);
14402}

References atooid, fb(), findOprByOid(), fmtId(), pg_log_warning, and psprintf().

Referenced by dumpAgg(), and dumpOpr().

◆ getFormattedTypeName()

static const char * getFormattedTypeName ( Archive fout,
Oid  oid,
OidOptions  opts 
)
static

Definition at line 20601 of file pg_dump.c.

20602{
20604 char *result;
20605 PQExpBuffer query;
20606 PGresult *res;
20607
20608 if (oid == 0)
20609 {
20610 if ((opts & zeroAsStar) != 0)
20611 return "*";
20612 else if ((opts & zeroAsNone) != 0)
20613 return "NONE";
20614 }
20615
20616 /* see if we have the result cached in the type's TypeInfo record */
20617 typeInfo = findTypeByOid(oid);
20618 if (typeInfo && typeInfo->ftypname)
20619 return typeInfo->ftypname;
20620
20621 query = createPQExpBuffer();
20622 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
20623 oid);
20624
20625 res = ExecuteSqlQueryForSingleRow(fout, query->data);
20626
20627 /* result of format_type is already quoted */
20628 result = pg_strdup(PQgetvalue(res, 0, 0));
20629
20630 PQclear(res);
20631 destroyPQExpBuffer(query);
20632
20633 /*
20634 * Cache the result for re-use in later requests, if possible. If we
20635 * don't have a TypeInfo for the type, the string will be leaked once the
20636 * caller is done with it ... but that case really should not happen, so
20637 * leaking if it does seems acceptable.
20638 */
20639 if (typeInfo)
20640 typeInfo->ftypname = result;
20641
20642 return result;
20643}

References appendPQExpBuffer(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), ExecuteSqlQueryForSingleRow(), fb(), findTypeByOid(), opts, pg_strdup(), PQclear, PQgetvalue, zeroAsNone, and zeroAsStar.

Referenced by dumpBaseType(), dumpCast(), dumpFunc(), dumpTableSchema(), dumpTransform(), format_aggregate_signature(), and format_function_signature().

◆ getFuncs()

void getFuncs ( Archive fout)

Definition at line 6927 of file pg_dump.c.

6928{
6929 DumpOptions *dopt = fout->dopt;
6930 PGresult *res;
6931 int ntups;
6932 int i;
6934 FuncInfo *finfo;
6935 int i_tableoid;
6936 int i_oid;
6937 int i_proname;
6938 int i_pronamespace;
6939 int i_proowner;
6940 int i_prolang;
6941 int i_pronargs;
6942 int i_proargtypes;
6943 int i_prorettype;
6944 int i_proacl;
6945 int i_acldefault;
6946
6947 /*
6948 * Find all interesting functions. This is a bit complicated:
6949 *
6950 * 1. Always exclude aggregates; those are handled elsewhere.
6951 *
6952 * 2. Always exclude functions that are internally dependent on something
6953 * else, since presumably those will be created as a result of creating
6954 * the something else. This currently acts only to suppress constructor
6955 * functions for range types. Note this is OK only because the
6956 * constructors don't have any dependencies the range type doesn't have;
6957 * otherwise we might not get creation ordering correct.
6958 *
6959 * 3. Otherwise, we normally exclude functions in pg_catalog. However, if
6960 * they're members of extensions and we are in binary-upgrade mode then
6961 * include them, since we want to dump extension members individually in
6962 * that mode. Also, if they are used by casts or transforms then we need
6963 * to gather the information about them, though they won't be dumped if
6964 * they are built-in. Also, in 9.6 and up, include functions in
6965 * pg_catalog if they have an ACL different from what's shown in
6966 * pg_init_privs (so we have to join to pg_init_privs; annoying).
6967 */
6968 if (fout->remoteVersion >= 90600)
6969 {
6970 const char *not_agg_check;
6971
6972 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
6973 : "NOT p.proisagg");
6974
6975 appendPQExpBuffer(query,
6976 "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
6977 "p.pronargs, p.proargtypes, p.prorettype, "
6978 "p.proacl, "
6979 "acldefault('f', p.proowner) AS acldefault, "
6980 "p.pronamespace, "
6981 "p.proowner "
6982 "FROM pg_proc p "
6983 "LEFT JOIN pg_init_privs pip ON "
6984 "(p.oid = pip.objoid "
6985 "AND pip.classoid = 'pg_proc'::regclass "
6986 "AND pip.objsubid = 0) "
6987 "WHERE %s"
6988 "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6989 "WHERE classid = 'pg_proc'::regclass AND "
6990 "objid = p.oid AND deptype = 'i')"
6991 "\n AND ("
6992 "\n pronamespace != "
6993 "(SELECT oid FROM pg_namespace "
6994 "WHERE nspname = 'pg_catalog')"
6995 "\n OR EXISTS (SELECT 1 FROM pg_cast"
6996 "\n WHERE pg_cast.oid > %u "
6997 "\n AND p.oid = pg_cast.castfunc)"
6998 "\n OR EXISTS (SELECT 1 FROM pg_transform"
6999 "\n WHERE pg_transform.oid > %u AND "
7000 "\n (p.oid = pg_transform.trffromsql"
7001 "\n OR p.oid = pg_transform.trftosql))",
7005 if (dopt->binary_upgrade)
7007 "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
7008 "classid = 'pg_proc'::regclass AND "
7009 "objid = p.oid AND "
7010 "refclassid = 'pg_extension'::regclass AND "
7011 "deptype = 'e')");
7013 "\n OR p.proacl IS DISTINCT FROM pip.initprivs");
7014 appendPQExpBufferChar(query, ')');
7015 }
7016 else
7017 {
7018 appendPQExpBuffer(query,
7019 "SELECT tableoid, oid, proname, prolang, "
7020 "pronargs, proargtypes, prorettype, proacl, "
7021 "acldefault('f', proowner) AS acldefault, "
7022 "pronamespace, "
7023 "proowner "
7024 "FROM pg_proc p "
7025 "WHERE NOT proisagg"
7026 "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
7027 "WHERE classid = 'pg_proc'::regclass AND "
7028 "objid = p.oid AND deptype = 'i')"
7029 "\n AND ("
7030 "\n pronamespace != "
7031 "(SELECT oid FROM pg_namespace "
7032 "WHERE nspname = 'pg_catalog')"
7033 "\n OR EXISTS (SELECT 1 FROM pg_cast"
7034 "\n WHERE pg_cast.oid > '%u'::oid"
7035 "\n AND p.oid = pg_cast.castfunc)",
7037
7038 if (fout->remoteVersion >= 90500)
7039 appendPQExpBuffer(query,
7040 "\n OR EXISTS (SELECT 1 FROM pg_transform"
7041 "\n WHERE pg_transform.oid > '%u'::oid"
7042 "\n AND (p.oid = pg_transform.trffromsql"
7043 "\n OR p.oid = pg_transform.trftosql))",
7045
7046 if (dopt->binary_upgrade)
7048 "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
7049 "classid = 'pg_proc'::regclass AND "
7050 "objid = p.oid AND "
7051 "refclassid = 'pg_extension'::regclass AND "
7052 "deptype = 'e')");
7053 appendPQExpBufferChar(query, ')');
7054 }
7055
7056 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7057
7058 ntups = PQntuples(res);
7059
7060 finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
7061
7062 i_tableoid = PQfnumber(res, "tableoid");
7063 i_oid = PQfnumber(res, "oid");
7064 i_proname = PQfnumber(res, "proname");
7065 i_pronamespace = PQfnumber(res, "pronamespace");
7066 i_proowner = PQfnumber(res, "proowner");
7067 i_prolang = PQfnumber(res, "prolang");
7068 i_pronargs = PQfnumber(res, "pronargs");
7069 i_proargtypes = PQfnumber(res, "proargtypes");
7070 i_prorettype = PQfnumber(res, "prorettype");
7071 i_proacl = PQfnumber(res, "proacl");
7072 i_acldefault = PQfnumber(res, "acldefault");
7073
7074 for (i = 0; i < ntups; i++)
7075 {
7076 finfo[i].dobj.objType = DO_FUNC;
7077 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7078 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7079 AssignDumpId(&finfo[i].dobj);
7080 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
7081 finfo[i].dobj.namespace =
7083 finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
7085 finfo[i].dacl.privtype = 0;
7086 finfo[i].dacl.initprivs = NULL;
7087 finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
7088 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
7089 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
7090 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
7091 if (finfo[i].nargs == 0)
7092 finfo[i].argtypes = NULL;
7093 else
7094 {
7095 finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
7097 finfo[i].argtypes, finfo[i].nargs);
7098 }
7099 finfo[i].postponed_def = false; /* might get set during sort */
7100
7101 /* Decide whether we want to dump it */
7102 selectDumpableObject(&(finfo[i].dobj), fout);
7103
7104 /* Mark whether function has an ACL */
7105 if (!PQgetisnull(res, i, i_proacl))
7107 }
7108
7109 PQclear(res);
7110
7111 destroyPQExpBuffer(query);
7112}

References _dumpableAcl::acl, _dumpableAcl::acldefault, appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), _funcInfo::argtypes, AssignDumpId(), atooid, _dumpOptions::binary_upgrade, _dumpableObject::catId, _dumpableObject::components, createPQExpBuffer(), _funcInfo::dacl, PQExpBufferData::data, destroyPQExpBuffer(), DO_FUNC, _funcInfo::dobj, DUMP_COMPONENT_ACL, ExecuteSqlQuery(), fb(), findNamespace(), g_last_builtin_oid, getRoleName(), i, _dumpableAcl::initprivs, _funcInfo::lang, _dumpableObject::name, _funcInfo::nargs, _dumpableObject::objType, CatalogId::oid, parseOidArray(), pg_malloc(), pg_malloc0(), pg_strdup(), PGRES_TUPLES_OK, _funcInfo::postponed_def, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, _dumpableAcl::privtype, _funcInfo::prorettype, _funcInfo::rolname, selectDumpableObject(), and CatalogId::tableoid.

Referenced by getSchemaData().

◆ getIndexes()

void getIndexes ( Archive fout,
TableInfo  tblinfo[],
int  numTables 
)

Definition at line 7857 of file pg_dump.c.

7858{
7861 PGresult *res;
7862 int ntups;
7863 int curtblindx;
7865 int i_tableoid,
7866 i_oid,
7867 i_indrelid,
7869 i_relpages,
7874 i_indexdef,
7876 i_indnatts,
7877 i_indkey,
7881 i_contype,
7882 i_conname,
7887 i_conoid,
7888 i_condef,
7894
7895 /*
7896 * We want to perform just one query against pg_index. However, we
7897 * mustn't try to select every row of the catalog and then sort it out on
7898 * the client side, because some of the server-side functions we need
7899 * would be unsafe to apply to tables we don't have lock on. Hence, we
7900 * build an array of the OIDs of tables we care about (and now have lock
7901 * on!), and use a WHERE clause to constrain which rows are selected.
7902 */
7904 for (int i = 0; i < numTables; i++)
7905 {
7906 TableInfo *tbinfo = &tblinfo[i];
7907
7908 if (!tbinfo->hasindex)
7909 continue;
7910
7911 /*
7912 * We can ignore indexes of uninteresting tables.
7913 */
7914 if (!tbinfo->interesting)
7915 continue;
7916
7917 /* OK, we need info for this table */
7918 if (tbloids->len > 1) /* do we have more than the '{'? */
7920 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
7921 }
7923
7925 "SELECT t.tableoid, t.oid, i.indrelid, "
7926 "t.relname AS indexname, "
7927 "t.relpages, t.reltuples, t.relallvisible, ");
7928
7929 if (fout->remoteVersion >= 180000)
7930 appendPQExpBufferStr(query, "t.relallfrozen, ");
7931 else
7932 appendPQExpBufferStr(query, "0 AS relallfrozen, ");
7933
7935 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7936 "i.indkey, i.indisclustered, "
7937 "c.contype, c.conname, "
7938 "c.condeferrable, c.condeferred, "
7939 "c.tableoid AS contableoid, "
7940 "c.oid AS conoid, "
7941 "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
7942 "CASE WHEN i.indexprs IS NOT NULL THEN "
7943 "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
7944 " FROM pg_catalog.pg_attribute "
7945 " WHERE attrelid = i.indexrelid) "
7946 "ELSE NULL END AS indattnames, "
7947 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7948 "t.reloptions AS indreloptions, ");
7949
7950
7951 if (fout->remoteVersion >= 90400)
7953 "i.indisreplident, ");
7954 else
7956 "false AS indisreplident, ");
7957
7958 if (fout->remoteVersion >= 110000)
7960 "inh.inhparent AS parentidx, "
7961 "i.indnkeyatts AS indnkeyatts, "
7962 "i.indnatts AS indnatts, "
7963 "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
7964 " FROM pg_catalog.pg_attribute "
7965 " WHERE attrelid = i.indexrelid AND "
7966 " attstattarget >= 0) AS indstatcols, "
7967 "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
7968 " FROM pg_catalog.pg_attribute "
7969 " WHERE attrelid = i.indexrelid AND "
7970 " attstattarget >= 0) AS indstatvals, ");
7971 else
7973 "0 AS parentidx, "
7974 "i.indnatts AS indnkeyatts, "
7975 "i.indnatts AS indnatts, "
7976 "'' AS indstatcols, "
7977 "'' AS indstatvals, ");
7978
7979 if (fout->remoteVersion >= 150000)
7981 "i.indnullsnotdistinct, ");
7982 else
7984 "false AS indnullsnotdistinct, ");
7985
7986 if (fout->remoteVersion >= 180000)
7988 "c.conperiod ");
7989 else
7991 "NULL AS conperiod ");
7992
7993 /*
7994 * The point of the messy-looking outer join is to find a constraint that
7995 * is related by an internal dependency link to the index. If we find one,
7996 * create a CONSTRAINT entry linked to the INDEX entry. We assume an
7997 * index won't have more than one internal dependency.
7998 *
7999 * Note: the check on conrelid is redundant, but useful because that
8000 * column is indexed while conindid is not.
8001 */
8002 if (fout->remoteVersion >= 110000)
8003 {
8004 appendPQExpBuffer(query,
8005 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8006 "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
8007 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
8008 "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
8009 "LEFT JOIN pg_catalog.pg_constraint c "
8010 "ON (i.indrelid = c.conrelid AND "
8011 "i.indexrelid = c.conindid AND "
8012 "c.contype IN ('p','u','x')) "
8013 "LEFT JOIN pg_catalog.pg_inherits inh "
8014 "ON (inh.inhrelid = indexrelid) "
8015 "WHERE (i.indisvalid OR t2.relkind = 'p') "
8016 "AND i.indisready "
8017 "ORDER BY i.indrelid, indexname",
8018 tbloids->data);
8019 }
8020 else
8021 {
8022 /*
8023 * the test on indisready is necessary in 9.2, and harmless in
8024 * earlier/later versions
8025 */
8026 appendPQExpBuffer(query,
8027 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8028 "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
8029 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
8030 "LEFT JOIN pg_catalog.pg_constraint c "
8031 "ON (i.indrelid = c.conrelid AND "
8032 "i.indexrelid = c.conindid AND "
8033 "c.contype IN ('p','u','x')) "
8034 "WHERE i.indisvalid AND i.indisready "
8035 "ORDER BY i.indrelid, indexname",
8036 tbloids->data);
8037 }
8038
8039 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8040
8041 ntups = PQntuples(res);
8042
8043 i_tableoid = PQfnumber(res, "tableoid");
8044 i_oid = PQfnumber(res, "oid");
8045 i_indrelid = PQfnumber(res, "indrelid");
8046 i_indexname = PQfnumber(res, "indexname");
8047 i_relpages = PQfnumber(res, "relpages");
8048 i_reltuples = PQfnumber(res, "reltuples");
8049 i_relallvisible = PQfnumber(res, "relallvisible");
8050 i_relallfrozen = PQfnumber(res, "relallfrozen");
8051 i_parentidx = PQfnumber(res, "parentidx");
8052 i_indexdef = PQfnumber(res, "indexdef");
8053 i_indnkeyatts = PQfnumber(res, "indnkeyatts");
8054 i_indnatts = PQfnumber(res, "indnatts");
8055 i_indkey = PQfnumber(res, "indkey");
8056 i_indisclustered = PQfnumber(res, "indisclustered");
8057 i_indisreplident = PQfnumber(res, "indisreplident");
8058 i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
8059 i_contype = PQfnumber(res, "contype");
8060 i_conname = PQfnumber(res, "conname");
8061 i_condeferrable = PQfnumber(res, "condeferrable");
8062 i_condeferred = PQfnumber(res, "condeferred");
8063 i_conperiod = PQfnumber(res, "conperiod");
8064 i_contableoid = PQfnumber(res, "contableoid");
8065 i_conoid = PQfnumber(res, "conoid");
8066 i_condef = PQfnumber(res, "condef");
8067 i_indattnames = PQfnumber(res, "indattnames");
8068 i_tablespace = PQfnumber(res, "tablespace");
8069 i_indreloptions = PQfnumber(res, "indreloptions");
8070 i_indstatcols = PQfnumber(res, "indstatcols");
8071 i_indstatvals = PQfnumber(res, "indstatvals");
8072
8073 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
8074
8075 /*
8076 * Outer loop iterates once per table, not once per row. Incrementing of
8077 * j is handled by the inner loop.
8078 */
8079 curtblindx = -1;
8080 for (int j = 0; j < ntups;)
8081 {
8084 char **indAttNames = NULL;
8085 int nindAttNames = 0;
8086 int numinds;
8087
8088 /* Count rows for this table */
8089 for (numinds = 1; numinds < ntups - j; numinds++)
8090 if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
8091 break;
8092
8093 /*
8094 * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8095 * order.
8096 */
8097 while (++curtblindx < numTables)
8098 {
8099 tbinfo = &tblinfo[curtblindx];
8100 if (tbinfo->dobj.catId.oid == indrelid)
8101 break;
8102 }
8103 if (curtblindx >= numTables)
8104 pg_fatal("unrecognized table OID %u", indrelid);
8105 /* cross-check that we only got requested tables */
8106 if (!tbinfo->hasindex ||
8107 !tbinfo->interesting)
8108 pg_fatal("unexpected index data for table \"%s\"",
8109 tbinfo->dobj.name);
8110
8111 /* Save data for this table */
8112 tbinfo->indexes = indxinfo + j;
8113 tbinfo->numIndexes = numinds;
8114
8115 for (int c = 0; c < numinds; c++, j++)
8116 {
8117 char contype;
8118 char indexkind;
8120 int32 relpages = atoi(PQgetvalue(res, j, i_relpages));
8121 int32 relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
8122 int32 relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
8123
8124 indxinfo[j].dobj.objType = DO_INDEX;
8125 indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8126 indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8127 AssignDumpId(&indxinfo[j].dobj);
8128 indxinfo[j].dobj.dump = tbinfo->dobj.dump;
8129 indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
8130 indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
8131 indxinfo[j].indextable = tbinfo;
8132 indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
8133 indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
8134 indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
8135 indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
8136 indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
8137 indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
8138 indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
8139 indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
8141 indxinfo[j].indkeys, indxinfo[j].indnattrs);
8142 indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
8143 indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
8144 indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
8145 indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
8146 indxinfo[j].partattaches = (SimplePtrList)
8147 {
8148 NULL, NULL
8149 };
8150
8151 if (indxinfo[j].parentidx == 0)
8153 else
8155
8156 if (!PQgetisnull(res, j, i_indattnames))
8157 {
8159 &indAttNames, &nindAttNames))
8160 pg_fatal("could not parse %s array", "indattnames");
8161 }
8162
8163 relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
8164 PQgetvalue(res, j, i_reltuples),
8165 relallvisible, relallfrozen, indexkind,
8166 indAttNames, nindAttNames);
8167
8168 contype = *(PQgetvalue(res, j, i_contype));
8169 if (contype == 'p' || contype == 'u' || contype == 'x')
8170 {
8171 /*
8172 * If we found a constraint matching the index, create an
8173 * entry for it.
8174 */
8176
8179 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
8180 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
8181 AssignDumpId(&constrinfo->dobj);
8182 constrinfo->dobj.dump = tbinfo->dobj.dump;
8183 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
8184 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
8185 constrinfo->contable = tbinfo;
8186 constrinfo->condomain = NULL;
8187 constrinfo->contype = contype;
8188 if (contype == 'x')
8189 constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
8190 else
8191 constrinfo->condef = NULL;
8192 constrinfo->confrelid = InvalidOid;
8193 constrinfo->conindex = indxinfo[j].dobj.dumpId;
8194 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
8195 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
8196 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
8197 constrinfo->conislocal = true;
8198 constrinfo->separate = true;
8199
8200 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
8201 if (relstats != NULL)
8202 addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
8203 }
8204 else
8205 {
8206 /* Plain secondary index */
8207 indxinfo[j].indexconstraint = 0;
8208 }
8209 }
8210 }
8211
8212 PQclear(res);
8213
8214 destroyPQExpBuffer(query);
8216}

References addObjectDependency(), appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_CONSTRAINT, DO_INDEX, _constraintInfo::dobj, ExecuteSqlQuery(), fb(), getRelationStatistics(), i, InvalidOid, j, _dumpableObject::objType, parseOidArray(), parsePGArray(), pg_fatal, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, and PQntuples.

Referenced by getSchemaData().

◆ getInherits()

InhInfo * getInherits ( Archive fout,
int numInherits 
)

Definition at line 7741 of file pg_dump.c.

7742{
7743 PGresult *res;
7744 int ntups;
7745 int i;
7748
7749 int i_inhrelid;
7750 int i_inhparent;
7751
7752 /* find all the inheritance information */
7753 appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
7754
7755 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7756
7757 ntups = PQntuples(res);
7758
7759 *numInherits = ntups;
7760
7761 inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
7762
7763 i_inhrelid = PQfnumber(res, "inhrelid");
7764 i_inhparent = PQfnumber(res, "inhparent");
7765
7766 for (i = 0; i < ntups; i++)
7767 {
7768 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
7769 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
7770 }
7771
7772 PQclear(res);
7773
7774 destroyPQExpBuffer(query);
7775
7776 return inhinfo;
7777}

References appendPQExpBufferStr(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), ExecuteSqlQuery(), fb(), i, pg_malloc(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, and PQntuples.

Referenced by getSchemaData().

◆ getLOs()

static void getLOs ( Archive fout)
static

Definition at line 3960 of file pg_dump.c.

3961{
3962 DumpOptions *dopt = fout->dopt;
3964 PGresult *res;
3965 int ntups;
3966 int i;
3967 int n;
3968 int i_oid;
3969 int i_lomowner;
3970 int i_lomacl;
3971 int i_acldefault;
3972
3973 pg_log_info("reading large objects");
3974
3975 /*
3976 * Fetch LO OIDs and owner/ACL data. Order the data so that all the blobs
3977 * with the same owner/ACL appear together.
3978 */
3980 "SELECT oid, lomowner, lomacl, "
3981 "acldefault('L', lomowner) AS acldefault "
3982 "FROM pg_largeobject_metadata "
3983 "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
3984
3986
3987 i_oid = PQfnumber(res, "oid");
3988 i_lomowner = PQfnumber(res, "lomowner");
3989 i_lomacl = PQfnumber(res, "lomacl");
3990 i_acldefault = PQfnumber(res, "acldefault");
3991
3992 ntups = PQntuples(res);
3993
3994 /*
3995 * Group the blobs into suitably-sized groups that have the same owner and
3996 * ACL setting, and build a metadata and a data DumpableObject for each
3997 * group. (If we supported initprivs for blobs, we'd have to insist that
3998 * groups also share initprivs settings, since the DumpableObject only has
3999 * room for one.) i is the index of the first tuple in the current group,
4000 * and n is the number of tuples we include in the group.
4001 */
4002 for (i = 0; i < ntups; i += n)
4003 {
4004 Oid thisoid = atooid(PQgetvalue(res, i, i_oid));
4005 char *thisowner = PQgetvalue(res, i, i_lomowner);
4006 char *thisacl = PQgetvalue(res, i, i_lomacl);
4007 LoInfo *loinfo;
4009 char namebuf[64];
4010
4011 /* Scan to find first tuple not to be included in group */
4012 n = 1;
4013 while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
4014 {
4015 if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
4016 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
4017 break;
4018 n++;
4019 }
4020
4021 /* Build the metadata DumpableObject */
4022 loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
4023
4025 loinfo->dobj.catId.tableoid = LargeObjectRelationId;
4026 loinfo->dobj.catId.oid = thisoid;
4027 AssignDumpId(&loinfo->dobj);
4028
4029 if (n > 1)
4030 snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
4031 atooid(PQgetvalue(res, i + n - 1, i_oid)));
4032 else
4033 snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
4034 loinfo->dobj.name = pg_strdup(namebuf);
4035 loinfo->dacl.acl = pg_strdup(thisacl);
4036 loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
4037 loinfo->dacl.privtype = 0;
4038 loinfo->dacl.initprivs = NULL;
4039 loinfo->rolname = getRoleName(thisowner);
4040 loinfo->numlos = n;
4041 loinfo->looids[0] = thisoid;
4042 /* Collect OIDs of the remaining blobs in this group */
4043 for (int k = 1; k < n; k++)
4044 {
4046
4047 loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
4048
4049 /* Make sure we can look up loinfo by any of the blobs' OIDs */
4050 extraID.tableoid = LargeObjectRelationId;
4051 extraID.oid = loinfo->looids[k];
4053 }
4054
4055 /* LOs have data */
4056 loinfo->dobj.components |= DUMP_COMPONENT_DATA;
4057
4058 /* Mark whether LO group has a non-empty ACL */
4059 if (!PQgetisnull(res, i, i_lomacl))
4060 loinfo->dobj.components |= DUMP_COMPONENT_ACL;
4061
4062 /*
4063 * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
4064 * as it will be copied by pg_upgrade, which simply copies the
4065 * pg_largeobject table. We *do* however dump out anything but the
4066 * data, as pg_upgrade copies just pg_largeobject, but not
4067 * pg_largeobject_metadata, after the dump is restored. In versions
4068 * before v12, this is done via proper large object commands. In
4069 * newer versions, we dump the content of pg_largeobject_metadata and
4070 * any associated pg_shdepend rows, which is faster to restore. (On
4071 * <v12, pg_largeobject_metadata was created WITH OIDS, so the OID
4072 * column is hidden and won't be dumped.)
4073 */
4074 if (dopt->binary_upgrade)
4075 {
4076 if (fout->remoteVersion >= 120000)
4077 {
4078 /*
4079 * We should've saved pg_largeobject_metadata's dump ID before
4080 * this point.
4081 */
4083
4085
4086 /*
4087 * Mark the large object as dependent on
4088 * pg_largeobject_metadata so that any large object
4089 * comments/seclables are dumped after it.
4090 */
4091 loinfo->dobj.dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
4092 loinfo->dobj.dependencies[0] = lo_metadata_dumpId;
4093 loinfo->dobj.nDeps = loinfo->dobj.allocDeps = 1;
4094 }
4095 else
4096 loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
4097 }
4098
4099 /*
4100 * Create a "BLOBS" data item for the group, too. This is just a
4101 * placeholder for sorting; it carries no data now.
4102 */
4104 lodata->objType = DO_LARGE_OBJECT_DATA;
4105 lodata->catId = nilCatalogId;
4107 lodata->name = pg_strdup(namebuf);
4108 lodata->components |= DUMP_COMPONENT_DATA;
4109 /* Set up explicit dependency from data to metadata */
4110 lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
4111 lodata->dependencies[0] = loinfo->dobj.dumpId;
4112 lodata->nDeps = lodata->allocDeps = 1;
4113 }
4114
4115 PQclear(res);
4117}

References appendPQExpBufferStr(), Assert, AssignDumpId(), atooid, _dumpOptions::binary_upgrade, createPQExpBuffer(), destroyPQExpBuffer(), DO_LARGE_OBJECT, DO_LARGE_OBJECT_DATA, DUMP_COMPONENT_ACL, DUMP_COMPONENT_DATA, DUMP_COMPONENT_DEFINITION, ExecuteSqlQuery(), fb(), getRoleName(), i, lo_metadata_dumpId, MAX_BLOBS_PER_ARCHIVE_ENTRY, nilCatalogId, _dumpableObject::objType, pg_log_info, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, recordAdditionalCatalogID(), and snprintf.

Referenced by main().

◆ getNamespaces()

void getNamespaces ( Archive fout)

Definition at line 6005 of file pg_dump.c.

6006{
6007 PGresult *res;
6008 int ntups;
6009 int i;
6010 PQExpBuffer query;
6012 int i_tableoid;
6013 int i_oid;
6014 int i_nspname;
6015 int i_nspowner;
6016 int i_nspacl;
6017 int i_acldefault;
6018
6019 query = createPQExpBuffer();
6020
6021 /*
6022 * we fetch all namespaces including system ones, so that every object we
6023 * read in can be linked to a containing namespace.
6024 */
6025 appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
6026 "n.nspowner, "
6027 "n.nspacl, "
6028 "acldefault('n', n.nspowner) AS acldefault "
6029 "FROM pg_namespace n");
6030
6031 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6032
6033 ntups = PQntuples(res);
6034
6035 nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
6036
6037 i_tableoid = PQfnumber(res, "tableoid");
6038 i_oid = PQfnumber(res, "oid");
6039 i_nspname = PQfnumber(res, "nspname");
6040 i_nspowner = PQfnumber(res, "nspowner");
6041 i_nspacl = PQfnumber(res, "nspacl");
6042 i_acldefault = PQfnumber(res, "acldefault");
6043
6044 for (i = 0; i < ntups; i++)
6045 {
6046 const char *nspowner;
6047
6048 nsinfo[i].dobj.objType = DO_NAMESPACE;
6049 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6050 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6051 AssignDumpId(&nsinfo[i].dobj);
6052 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
6053 nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
6054 nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6055 nsinfo[i].dacl.privtype = 0;
6056 nsinfo[i].dacl.initprivs = NULL;
6057 nspowner = PQgetvalue(res, i, i_nspowner);
6058 nsinfo[i].nspowner = atooid(nspowner);
6059 nsinfo[i].rolname = getRoleName(nspowner);
6060
6061 /* Decide whether to dump this namespace */
6063
6064 /* Mark whether namespace has an ACL */
6065 if (!PQgetisnull(res, i, i_nspacl))
6066 nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6067
6068 /*
6069 * We ignore any pg_init_privs.initprivs entry for the public schema
6070 * and assume a predetermined default, for several reasons. First,
6071 * dropping and recreating the schema removes its pg_init_privs entry,
6072 * but an empty destination database starts with this ACL nonetheless.
6073 * Second, we support dump/reload of public schema ownership changes.
6074 * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
6075 * initprivs continues to reflect the initial owner. Hence,
6076 * synthesize the value that nspacl will have after the restore's
6077 * ALTER SCHEMA OWNER. Third, this makes the destination database
6078 * match the source's ACL, even if the latter was an initdb-default
6079 * ACL, which changed in v15. An upgrade pulls in changes to most
6080 * system object ACLs that the DBA had not customized. We've made the
6081 * public schema depart from that, because changing its ACL so easily
6082 * breaks applications.
6083 */
6084 if (strcmp(nsinfo[i].dobj.name, "public") == 0)
6085 {
6088
6089 /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
6100
6101 nsinfo[i].dacl.privtype = 'i';
6102 nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
6103 nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6104
6107 }
6108 }
6109
6110 PQclear(res);
6111 destroyPQExpBuffer(query);
6112}

References appendPGArray(), appendPQExpBufferChar(), appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_NAMESPACE, DUMP_COMPONENT_ACL, ExecuteSqlQuery(), fb(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, pstrdup(), quoteAclUserName(), resetPQExpBuffer(), rolname, and selectDumpableNamespace().

Referenced by getSchemaData().

◆ getOpclasses()

void getOpclasses ( Archive fout)

Definition at line 6658 of file pg_dump.c.

6659{
6660 PGresult *res;
6661 int ntups;
6662 int i;
6665 int i_tableoid;
6666 int i_oid;
6667 int i_opcmethod;
6668 int i_opcname;
6669 int i_opcnamespace;
6670 int i_opcowner;
6671
6672 /*
6673 * find all opclasses, including builtin opclasses; we filter out
6674 * system-defined opclasses at dump-out time.
6675 */
6676
6677 appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
6678 "opcnamespace, "
6679 "opcowner "
6680 "FROM pg_opclass");
6681
6682 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6683
6684 ntups = PQntuples(res);
6685
6686 opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
6687
6688 i_tableoid = PQfnumber(res, "tableoid");
6689 i_oid = PQfnumber(res, "oid");
6690 i_opcmethod = PQfnumber(res, "opcmethod");
6691 i_opcname = PQfnumber(res, "opcname");
6692 i_opcnamespace = PQfnumber(res, "opcnamespace");
6693 i_opcowner = PQfnumber(res, "opcowner");
6694
6695 for (i = 0; i < ntups; i++)
6696 {
6697 opcinfo[i].dobj.objType = DO_OPCLASS;
6698 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6699 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6700 AssignDumpId(&opcinfo[i].dobj);
6701 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
6702 opcinfo[i].dobj.namespace =
6704 opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
6705 opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
6706
6707 /* Decide whether we want to dump it */
6709 }
6710
6711 PQclear(res);
6712
6713 destroyPQExpBuffer(query);
6714}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_OPCLASS, ExecuteSqlQuery(), fb(), findNamespace(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getOperators()

void getOperators ( Archive fout)

Definition at line 6380 of file pg_dump.c.

6381{
6382 PGresult *res;
6383 int ntups;
6384 int i;
6387 int i_tableoid;
6388 int i_oid;
6389 int i_oprname;
6390 int i_oprnamespace;
6391 int i_oprowner;
6392 int i_oprkind;
6393 int i_oprleft;
6394 int i_oprright;
6395 int i_oprcode;
6396
6397 /*
6398 * find all operators, including builtin operators; we filter out
6399 * system-defined operators at dump-out time.
6400 */
6401
6402 appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
6403 "oprnamespace, "
6404 "oprowner, "
6405 "oprkind, "
6406 "oprleft, "
6407 "oprright, "
6408 "oprcode::oid AS oprcode "
6409 "FROM pg_operator");
6410
6411 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6412
6413 ntups = PQntuples(res);
6414
6415 oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
6416
6417 i_tableoid = PQfnumber(res, "tableoid");
6418 i_oid = PQfnumber(res, "oid");
6419 i_oprname = PQfnumber(res, "oprname");
6420 i_oprnamespace = PQfnumber(res, "oprnamespace");
6421 i_oprowner = PQfnumber(res, "oprowner");
6422 i_oprkind = PQfnumber(res, "oprkind");
6423 i_oprleft = PQfnumber(res, "oprleft");
6424 i_oprright = PQfnumber(res, "oprright");
6425 i_oprcode = PQfnumber(res, "oprcode");
6426
6427 for (i = 0; i < ntups; i++)
6428 {
6429 oprinfo[i].dobj.objType = DO_OPERATOR;
6430 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6431 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6432 AssignDumpId(&oprinfo[i].dobj);
6433 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
6434 oprinfo[i].dobj.namespace =
6436 oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
6437 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
6438 oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
6439 oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
6440 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
6441
6442 /* Decide whether we want to dump it */
6444 }
6445
6446 PQclear(res);
6447
6448 destroyPQExpBuffer(query);
6449}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_OPERATOR, ExecuteSqlQuery(), fb(), findNamespace(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getOpfamilies()

void getOpfamilies ( Archive fout)

Definition at line 6721 of file pg_dump.c.

6722{
6723 PGresult *res;
6724 int ntups;
6725 int i;
6726 PQExpBuffer query;
6728 int i_tableoid;
6729 int i_oid;
6730 int i_opfmethod;
6731 int i_opfname;
6732 int i_opfnamespace;
6733 int i_opfowner;
6734
6735 query = createPQExpBuffer();
6736
6737 /*
6738 * find all opfamilies, including builtin opfamilies; we filter out
6739 * system-defined opfamilies at dump-out time.
6740 */
6741
6742 appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
6743 "opfnamespace, "
6744 "opfowner "
6745 "FROM pg_opfamily");
6746
6747 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6748
6749 ntups = PQntuples(res);
6750
6751 opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
6752
6753 i_tableoid = PQfnumber(res, "tableoid");
6754 i_oid = PQfnumber(res, "oid");
6755 i_opfname = PQfnumber(res, "opfname");
6756 i_opfmethod = PQfnumber(res, "opfmethod");
6757 i_opfnamespace = PQfnumber(res, "opfnamespace");
6758 i_opfowner = PQfnumber(res, "opfowner");
6759
6760 for (i = 0; i < ntups; i++)
6761 {
6762 opfinfo[i].dobj.objType = DO_OPFAMILY;
6763 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6764 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6765 AssignDumpId(&opfinfo[i].dobj);
6766 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
6767 opfinfo[i].dobj.namespace =
6769 opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
6770 opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
6771
6772 /* Decide whether we want to dump it */
6774 }
6775
6776 PQclear(res);
6777
6778 destroyPQExpBuffer(query);
6779}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_OPFAMILY, ExecuteSqlQuery(), fb(), findNamespace(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getOwnedSeqs()

void getOwnedSeqs ( Archive fout,
TableInfo  tblinfo[],
int  numTables 
)

Definition at line 7676 of file pg_dump.c.

7677{
7678 int i;
7679
7680 /*
7681 * Force sequences that are "owned" by table columns to be dumped whenever
7682 * their owning table is being dumped.
7683 */
7684 for (i = 0; i < numTables; i++)
7685 {
7686 TableInfo *seqinfo = &tblinfo[i];
7687 TableInfo *owning_tab;
7688
7689 if (!OidIsValid(seqinfo->owning_tab))
7690 continue; /* not an owned sequence */
7691
7692 owning_tab = findTableByOid(seqinfo->owning_tab);
7693 if (owning_tab == NULL)
7694 pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
7695 seqinfo->owning_tab, seqinfo->dobj.catId.oid);
7696
7697 /*
7698 * For an identity sequence, dump exactly the same components for the
7699 * sequence as for the owning table. This is important because we
7700 * treat the identity sequence as an integral part of the table. For
7701 * example, there is not any DDL command that allows creation of such
7702 * a sequence independently of the table.
7703 *
7704 * For other owned sequences such as serial sequences, we need to dump
7705 * the components that are being dumped for the table and any
7706 * components that the sequence is explicitly marked with.
7707 *
7708 * We can't simply use the set of components which are being dumped
7709 * for the table as the table might be in an extension (and only the
7710 * non-extension components, eg: ACLs if changed, security labels, and
7711 * policies, are being dumped) while the sequence is not (and
7712 * therefore the definition and other components should also be
7713 * dumped).
7714 *
7715 * If the sequence is part of the extension then it should be properly
7716 * marked by checkExtensionMembership() and this will be a no-op as
7717 * the table will be equivalently marked.
7718 */
7719 if (seqinfo->is_identity_sequence)
7720 seqinfo->dobj.dump = owning_tab->dobj.dump;
7721 else
7722 seqinfo->dobj.dump |= owning_tab->dobj.dump;
7723
7724 /* Make sure that necessary data is available if we're dumping it */
7725 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
7726 {
7727 seqinfo->interesting = true;
7728 owning_tab->interesting = true;
7729 }
7730 }
7731}

References _tableInfo::dobj, _dumpableObject::dump, DUMP_COMPONENT_NONE, fb(), findTableByOid(), i, _tableInfo::interesting, OidIsValid, and pg_fatal.

Referenced by getSchemaData().

◆ getPartitioningInfo()

void getPartitioningInfo ( Archive fout)

Definition at line 7797 of file pg_dump.c.

7798{
7799 PQExpBuffer query;
7800 PGresult *res;
7801 int ntups;
7802
7803 /* hash partitioning didn't exist before v11 */
7804 if (fout->remoteVersion < 110000)
7805 return;
7806 /* needn't bother if not dumping data */
7807 if (!fout->dopt->dumpData)
7808 return;
7809
7810 query = createPQExpBuffer();
7811
7812 /*
7813 * Unsafe partitioning schemes are exactly those for which hash enum_ops
7814 * appears among the partition opclasses. We needn't check partstrat.
7815 *
7816 * Note that this query may well retrieve info about tables we aren't
7817 * going to dump and hence have no lock on. That's okay since we need not
7818 * invoke any unsafe server-side functions.
7819 */
7821 "SELECT partrelid FROM pg_partitioned_table WHERE\n"
7822 "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
7823 "ON c.opcmethod = a.oid\n"
7824 "WHERE opcname = 'enum_ops' "
7825 "AND opcnamespace = 'pg_catalog'::regnamespace "
7826 "AND amname = 'hash') = ANY(partclass)");
7827
7828 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7829
7830 ntups = PQntuples(res);
7831
7832 for (int i = 0; i < ntups; i++)
7833 {
7834 Oid tabrelid = atooid(PQgetvalue(res, i, 0));
7836
7838 if (tbinfo == NULL)
7839 pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
7840 tabrelid);
7841 tbinfo->unsafe_partitions = true;
7842 }
7843
7844 PQclear(res);
7845
7846 destroyPQExpBuffer(query);
7847}

References appendPQExpBufferStr(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), ExecuteSqlQuery(), fb(), findTableByOid(), i, pg_fatal, PGRES_TUPLES_OK, PQclear, PQgetvalue, and PQntuples.

Referenced by getSchemaData().

◆ getPolicies()

void getPolicies ( Archive fout,
TableInfo  tblinfo[],
int  numTables 
)

Definition at line 4261 of file pg_dump.c.

4262{
4263 DumpOptions *dopt = fout->dopt;
4264 PQExpBuffer query;
4266 PGresult *res;
4268 int i_oid;
4269 int i_tableoid;
4270 int i_polrelid;
4271 int i_polname;
4272 int i_polcmd;
4273 int i_polpermissive;
4274 int i_polroles;
4275 int i_polqual;
4276 int i_polwithcheck;
4277 int i,
4278 j,
4279 ntups;
4280
4281 /* No policies before 9.5 */
4282 if (fout->remoteVersion < 90500)
4283 return;
4284
4285 /* Skip if --no-policies was specified */
4286 if (dopt->no_policies)
4287 return;
4288
4289 query = createPQExpBuffer();
4291
4292 /*
4293 * Identify tables of interest, and check which ones have RLS enabled.
4294 */
4296 for (i = 0; i < numTables; i++)
4297 {
4298 TableInfo *tbinfo = &tblinfo[i];
4299
4300 /* Ignore row security on tables not to be dumped */
4301 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
4302 continue;
4303
4304 /* It can't have RLS or policies if it's not a table */
4305 if (tbinfo->relkind != RELKIND_RELATION &&
4307 continue;
4308
4309 /* Add it to the list of table OIDs to be probed below */
4310 if (tbloids->len > 1) /* do we have more than the '{'? */
4312 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
4313
4314 /* Is RLS enabled? (That's separate from whether it has policies) */
4315 if (tbinfo->rowsec)
4316 {
4317 tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
4318
4319 /*
4320 * We represent RLS being enabled on a table by creating a
4321 * PolicyInfo object with null polname.
4322 *
4323 * Note: use tableoid 0 so that this object won't be mistaken for
4324 * something that pg_depend entries apply to.
4325 */
4326 polinfo = pg_malloc(sizeof(PolicyInfo));
4327 polinfo->dobj.objType = DO_POLICY;
4328 polinfo->dobj.catId.tableoid = 0;
4329 polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
4330 AssignDumpId(&polinfo->dobj);
4331 polinfo->dobj.namespace = tbinfo->dobj.namespace;
4332 polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
4333 polinfo->poltable = tbinfo;
4334 polinfo->polname = NULL;
4335 polinfo->polcmd = '\0';
4336 polinfo->polpermissive = 0;
4337 polinfo->polroles = NULL;
4338 polinfo->polqual = NULL;
4339 polinfo->polwithcheck = NULL;
4340 }
4341 }
4343
4344 /*
4345 * Now, read all RLS policies belonging to the tables of interest, and
4346 * create PolicyInfo objects for them. (Note that we must filter the
4347 * results server-side not locally, because we dare not apply pg_get_expr
4348 * to tables we don't have lock on.)
4349 */
4350 pg_log_info("reading row-level security policies");
4351
4352 printfPQExpBuffer(query,
4353 "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
4354 if (fout->remoteVersion >= 100000)
4355 appendPQExpBufferStr(query, "pol.polpermissive, ");
4356 else
4357 appendPQExpBufferStr(query, "'t' as polpermissive, ");
4358 appendPQExpBuffer(query,
4359 "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
4360 " 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, "
4361 "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
4362 "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
4363 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
4364 "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
4365 tbloids->data);
4366
4367 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4368
4369 ntups = PQntuples(res);
4370 if (ntups > 0)
4371 {
4372 i_oid = PQfnumber(res, "oid");
4373 i_tableoid = PQfnumber(res, "tableoid");
4374 i_polrelid = PQfnumber(res, "polrelid");
4375 i_polname = PQfnumber(res, "polname");
4376 i_polcmd = PQfnumber(res, "polcmd");
4377 i_polpermissive = PQfnumber(res, "polpermissive");
4378 i_polroles = PQfnumber(res, "polroles");
4379 i_polqual = PQfnumber(res, "polqual");
4380 i_polwithcheck = PQfnumber(res, "polwithcheck");
4381
4382 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
4383
4384 for (j = 0; j < ntups; j++)
4385 {
4388
4389 tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
4390
4391 polinfo[j].dobj.objType = DO_POLICY;
4392 polinfo[j].dobj.catId.tableoid =
4393 atooid(PQgetvalue(res, j, i_tableoid));
4394 polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4395 AssignDumpId(&polinfo[j].dobj);
4396 polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4397 polinfo[j].poltable = tbinfo;
4398 polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
4399 polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
4400
4401 polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
4402 polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
4403
4404 if (PQgetisnull(res, j, i_polroles))
4405 polinfo[j].polroles = NULL;
4406 else
4407 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
4408
4409 if (PQgetisnull(res, j, i_polqual))
4410 polinfo[j].polqual = NULL;
4411 else
4412 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
4413
4414 if (PQgetisnull(res, j, i_polwithcheck))
4415 polinfo[j].polwithcheck = NULL;
4416 else
4417 polinfo[j].polwithcheck
4419 }
4420 }
4421
4422 PQclear(res);
4423
4424 destroyPQExpBuffer(query);
4426}

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_POLICY, DUMP_COMPONENT_POLICY, ExecuteSqlQuery(), fb(), findTableByOid(), i, j, _dumpOptions::no_policies, pg_log_info, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, and printfPQExpBuffer().

Referenced by getSchemaData().

◆ getProcLangs()

void getProcLangs ( Archive fout)

Definition at line 8973 of file pg_dump.c.

8974{
8975 PGresult *res;
8976 int ntups;
8977 int i;
8980 int i_tableoid;
8981 int i_oid;
8982 int i_lanname;
8983 int i_lanpltrusted;
8984 int i_lanplcallfoid;
8985 int i_laninline;
8986 int i_lanvalidator;
8987 int i_lanacl;
8988 int i_acldefault;
8989 int i_lanowner;
8990
8991 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8992 "lanname, lanpltrusted, lanplcallfoid, "
8993 "laninline, lanvalidator, "
8994 "lanacl, "
8995 "acldefault('l', lanowner) AS acldefault, "
8996 "lanowner "
8997 "FROM pg_language "
8998 "WHERE lanispl "
8999 "ORDER BY oid");
9000
9001 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9002
9003 ntups = PQntuples(res);
9004
9005 planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
9006
9007 i_tableoid = PQfnumber(res, "tableoid");
9008 i_oid = PQfnumber(res, "oid");
9009 i_lanname = PQfnumber(res, "lanname");
9010 i_lanpltrusted = PQfnumber(res, "lanpltrusted");
9011 i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
9012 i_laninline = PQfnumber(res, "laninline");
9013 i_lanvalidator = PQfnumber(res, "lanvalidator");
9014 i_lanacl = PQfnumber(res, "lanacl");
9015 i_acldefault = PQfnumber(res, "acldefault");
9016 i_lanowner = PQfnumber(res, "lanowner");
9017
9018 for (i = 0; i < ntups; i++)
9019 {
9020 planginfo[i].dobj.objType = DO_PROCLANG;
9021 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9022 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9023 AssignDumpId(&planginfo[i].dobj);
9024
9025 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
9026 planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
9027 planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9028 planginfo[i].dacl.privtype = 0;
9029 planginfo[i].dacl.initprivs = NULL;
9030 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
9031 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
9032 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
9033 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
9034 planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
9035
9036 /* Decide whether we want to dump it */
9038
9039 /* Mark whether language has an ACL */
9040 if (!PQgetisnull(res, i, i_lanacl))
9041 planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9042 }
9043
9044 PQclear(res);
9045
9046 destroyPQExpBuffer(query);
9047}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_PROCLANG, DUMP_COMPONENT_ACL, ExecuteSqlQuery(), fb(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, and selectDumpableProcLang().

Referenced by getSchemaData().

◆ getPublicationNamespaces()

void getPublicationNamespaces ( Archive fout)

Definition at line 4770 of file pg_dump.c.

4771{
4772 PQExpBuffer query;
4773 PGresult *res;
4775 DumpOptions *dopt = fout->dopt;
4776 int i_tableoid;
4777 int i_oid;
4778 int i_pnpubid;
4779 int i_pnnspid;
4780 int i,
4781 j,
4782 ntups;
4783
4784 if (dopt->no_publications || fout->remoteVersion < 150000)
4785 return;
4786
4787 query = createPQExpBuffer();
4788
4789 /* Collect all publication membership info. */
4791 "SELECT tableoid, oid, pnpubid, pnnspid "
4792 "FROM pg_catalog.pg_publication_namespace");
4793 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4794
4795 ntups = PQntuples(res);
4796
4797 i_tableoid = PQfnumber(res, "tableoid");
4798 i_oid = PQfnumber(res, "oid");
4799 i_pnpubid = PQfnumber(res, "pnpubid");
4800 i_pnnspid = PQfnumber(res, "pnnspid");
4801
4802 /* this allocation may be more than we need */
4803 pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
4804 j = 0;
4805
4806 for (i = 0; i < ntups; i++)
4807 {
4812
4813 /*
4814 * Ignore any entries for which we aren't interested in either the
4815 * publication or the rel.
4816 */
4818 if (pubinfo == NULL)
4819 continue;
4821 if (nspinfo == NULL)
4822 continue;
4823
4824 /* OK, make a DumpableObject for this relationship */
4826 pubsinfo[j].dobj.catId.tableoid =
4827 atooid(PQgetvalue(res, i, i_tableoid));
4828 pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4829 AssignDumpId(&pubsinfo[j].dobj);
4830 pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
4831 pubsinfo[j].dobj.name = nspinfo->dobj.name;
4832 pubsinfo[j].publication = pubinfo;
4833 pubsinfo[j].pubschema = nspinfo;
4834
4835 /* Decide whether we want to dump it */
4837
4838 j++;
4839 }
4840
4841 PQclear(res);
4842 destroyPQExpBuffer(query);
4843}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_PUBLICATION_TABLE_IN_SCHEMA, ExecuteSqlQuery(), fb(), findNamespaceByOid(), findPublicationByOid(), i, j, _dumpOptions::no_publications, pg_malloc(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpablePublicationObject().

Referenced by getSchemaData().

◆ getPublications()

void getPublications ( Archive fout)

Definition at line 4551 of file pg_dump.c.

4552{
4553 DumpOptions *dopt = fout->dopt;
4554 PQExpBuffer query;
4555 PGresult *res;
4557 int i_tableoid;
4558 int i_oid;
4559 int i_pubname;
4560 int i_pubowner;
4561 int i_puballtables;
4563 int i_pubinsert;
4564 int i_pubupdate;
4565 int i_pubdelete;
4566 int i_pubtruncate;
4567 int i_pubviaroot;
4568 int i_pubgencols;
4569 int i,
4570 ntups;
4571
4572 if (dopt->no_publications || fout->remoteVersion < 100000)
4573 return;
4574
4575 query = createPQExpBuffer();
4576
4577 /* Get the publications. */
4578 appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
4579 "p.pubowner, p.puballtables, p.pubinsert, "
4580 "p.pubupdate, p.pubdelete, ");
4581
4582 if (fout->remoteVersion >= 110000)
4583 appendPQExpBufferStr(query, "p.pubtruncate, ");
4584 else
4585 appendPQExpBufferStr(query, "false AS pubtruncate, ");
4586
4587 if (fout->remoteVersion >= 130000)
4588 appendPQExpBufferStr(query, "p.pubviaroot, ");
4589 else
4590 appendPQExpBufferStr(query, "false AS pubviaroot, ");
4591
4592 if (fout->remoteVersion >= 180000)
4593 appendPQExpBufferStr(query, "p.pubgencols, ");
4594 else
4595 appendPQExpBuffer(query, "'%c' AS pubgencols, ", PUBLISH_GENCOLS_NONE);
4596
4597 if (fout->remoteVersion >= 190000)
4598 appendPQExpBufferStr(query, "p.puballsequences ");
4599 else
4600 appendPQExpBufferStr(query, "false AS puballsequences ");
4601
4602 appendPQExpBufferStr(query, "FROM pg_publication p");
4603
4604 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4605
4606 ntups = PQntuples(res);
4607
4608 if (ntups == 0)
4609 goto cleanup;
4610
4611 i_tableoid = PQfnumber(res, "tableoid");
4612 i_oid = PQfnumber(res, "oid");
4613 i_pubname = PQfnumber(res, "pubname");
4614 i_pubowner = PQfnumber(res, "pubowner");
4615 i_puballtables = PQfnumber(res, "puballtables");
4616 i_puballsequences = PQfnumber(res, "puballsequences");
4617 i_pubinsert = PQfnumber(res, "pubinsert");
4618 i_pubupdate = PQfnumber(res, "pubupdate");
4619 i_pubdelete = PQfnumber(res, "pubdelete");
4620 i_pubtruncate = PQfnumber(res, "pubtruncate");
4621 i_pubviaroot = PQfnumber(res, "pubviaroot");
4622 i_pubgencols = PQfnumber(res, "pubgencols");
4623
4624 pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
4625
4626 for (i = 0; i < ntups; i++)
4627 {
4628 pubinfo[i].dobj.objType = DO_PUBLICATION;
4629 pubinfo[i].dobj.catId.tableoid =
4630 atooid(PQgetvalue(res, i, i_tableoid));
4631 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4632 AssignDumpId(&pubinfo[i].dobj);
4633 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
4634 pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
4635 pubinfo[i].puballtables =
4636 (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
4637 pubinfo[i].puballsequences =
4638 (strcmp(PQgetvalue(res, i, i_puballsequences), "t") == 0);
4639 pubinfo[i].pubinsert =
4640 (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
4641 pubinfo[i].pubupdate =
4642 (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
4643 pubinfo[i].pubdelete =
4644 (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
4645 pubinfo[i].pubtruncate =
4646 (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
4647 pubinfo[i].pubviaroot =
4648 (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
4649 pubinfo[i].pubgencols_type =
4650 *(PQgetvalue(res, i, i_pubgencols));
4651
4652 /* Decide whether we want to dump it */
4654 }
4655
4656cleanup:
4657 PQclear(res);
4658
4659 destroyPQExpBuffer(query);
4660}

References appendPQExpBuffer(), appendPQExpBufferStr(), AssignDumpId(), atooid, cleanup(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_PUBLICATION, ExecuteSqlQuery(), fb(), getRoleName(), i, _dumpOptions::no_publications, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getPublicationTables()

void getPublicationTables ( Archive fout,
TableInfo  tblinfo[],
int  numTables 
)

Definition at line 4850 of file pg_dump.c.

4851{
4852 PQExpBuffer query;
4853 PGresult *res;
4855 DumpOptions *dopt = fout->dopt;
4856 int i_tableoid;
4857 int i_oid;
4858 int i_prpubid;
4859 int i_prrelid;
4860 int i_prrelqual;
4861 int i_prattrs;
4862 int i,
4863 j,
4864 ntups;
4865
4866 if (dopt->no_publications || fout->remoteVersion < 100000)
4867 return;
4868
4869 query = createPQExpBuffer();
4870
4871 /* Collect all publication membership info. */
4872 if (fout->remoteVersion >= 150000)
4874 "SELECT tableoid, oid, prpubid, prrelid, "
4875 "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
4876 "(CASE\n"
4877 " WHEN pr.prattrs IS NOT NULL THEN\n"
4878 " (SELECT array_agg(attname)\n"
4879 " FROM\n"
4880 " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
4881 " pg_catalog.pg_attribute\n"
4882 " WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
4883 " ELSE NULL END) prattrs "
4884 "FROM pg_catalog.pg_publication_rel pr");
4885 else
4887 "SELECT tableoid, oid, prpubid, prrelid, "
4888 "NULL AS prrelqual, NULL AS prattrs "
4889 "FROM pg_catalog.pg_publication_rel");
4890 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4891
4892 ntups = PQntuples(res);
4893
4894 i_tableoid = PQfnumber(res, "tableoid");
4895 i_oid = PQfnumber(res, "oid");
4896 i_prpubid = PQfnumber(res, "prpubid");
4897 i_prrelid = PQfnumber(res, "prrelid");
4898 i_prrelqual = PQfnumber(res, "prrelqual");
4899 i_prattrs = PQfnumber(res, "prattrs");
4900
4901 /* this allocation may be more than we need */
4902 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
4903 j = 0;
4904
4905 for (i = 0; i < ntups; i++)
4906 {
4911
4912 /*
4913 * Ignore any entries for which we aren't interested in either the
4914 * publication or the rel.
4915 */
4917 if (pubinfo == NULL)
4918 continue;
4920 if (tbinfo == NULL)
4921 continue;
4922
4923 /* OK, make a DumpableObject for this relationship */
4924 pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
4925 pubrinfo[j].dobj.catId.tableoid =
4926 atooid(PQgetvalue(res, i, i_tableoid));
4927 pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4928 AssignDumpId(&pubrinfo[j].dobj);
4929 pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4930 pubrinfo[j].dobj.name = tbinfo->dobj.name;
4931 pubrinfo[j].publication = pubinfo;
4932 pubrinfo[j].pubtable = tbinfo;
4933 if (PQgetisnull(res, i, i_prrelqual))
4934 pubrinfo[j].pubrelqual = NULL;
4935 else
4936 pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
4937
4938 if (!PQgetisnull(res, i, i_prattrs))
4939 {
4940 char **attnames;
4941 int nattnames;
4943
4944 if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
4945 &attnames, &nattnames))
4946 pg_fatal("could not parse %s array", "prattrs");
4948 for (int k = 0; k < nattnames; k++)
4949 {
4950 if (k > 0)
4952
4953 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
4954 }
4955 pubrinfo[j].pubrattrs = attribs->data;
4956 free(attribs); /* but not attribs->data */
4957 free(attnames);
4958 }
4959 else
4960 pubrinfo[j].pubrattrs = NULL;
4961
4962 /* Decide whether we want to dump it */
4964
4965 j++;
4966 }
4967
4968 PQclear(res);
4969 destroyPQExpBuffer(query);
4970}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_PUBLICATION_REL, ExecuteSqlQuery(), fb(), findPublicationByOid(), findTableByOid(), fmtId(), free, i, j, _dumpOptions::no_publications, parsePGArray(), pg_fatal, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, and selectDumpablePublicationObject().

Referenced by getSchemaData().

◆ getRelationStatistics()

static RelStatsInfo * getRelationStatistics ( Archive fout,
DumpableObject rel,
int32  relpages,
char reltuples,
int32  relallvisible,
int32  relallfrozen,
char  relkind,
char **  indAttNames,
int  nindAttNames 
)
static

Definition at line 7122 of file pg_dump.c.

7126{
7127 if (!fout->dopt->dumpStatistics)
7128 return NULL;
7129
7130 if ((relkind == RELKIND_RELATION) ||
7131 (relkind == RELKIND_PARTITIONED_TABLE) ||
7132 (relkind == RELKIND_INDEX) ||
7133 (relkind == RELKIND_PARTITIONED_INDEX) ||
7134 (relkind == RELKIND_MATVIEW ||
7135 relkind == RELKIND_FOREIGN_TABLE))
7136 {
7137 RelStatsInfo *info = pg_malloc0(sizeof(RelStatsInfo));
7138 DumpableObject *dobj = &info->dobj;
7139
7140 dobj->objType = DO_REL_STATS;
7141 dobj->catId.tableoid = 0;
7142 dobj->catId.oid = 0;
7143 AssignDumpId(dobj);
7144 dobj->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
7145 dobj->dependencies[0] = rel->dumpId;
7146 dobj->nDeps = 1;
7147 dobj->allocDeps = 1;
7149 dobj->name = pg_strdup(rel->name);
7150 dobj->namespace = rel->namespace;
7151 info->relpages = relpages;
7152 info->reltuples = pstrdup(reltuples);
7153 info->relallvisible = relallvisible;
7154 info->relallfrozen = relallfrozen;
7155 info->relkind = relkind;
7156 info->indAttNames = indAttNames;
7157 info->nindAttNames = nindAttNames;
7158
7159 /*
7160 * Ordinarily, stats go in SECTION_DATA for tables and
7161 * SECTION_POST_DATA for indexes.
7162 *
7163 * However, the section may be updated later for materialized view
7164 * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
7165 * the stats, so the stats must be restored after the data. Also, the
7166 * materialized view definition may be postponed to SECTION_POST_DATA
7167 * (see repairMatViewBoundaryMultiLoop()).
7168 */
7169 switch (info->relkind)
7170 {
7171 case RELKIND_RELATION:
7173 case RELKIND_MATVIEW:
7175 info->section = SECTION_DATA;
7176 break;
7177 case RELKIND_INDEX:
7179 info->section = SECTION_POST_DATA;
7180 break;
7181 default:
7182 pg_fatal("cannot dump statistics for relation kind \"%c\"",
7183 info->relkind);
7184 }
7185
7186 return info;
7187 }
7188 return NULL;
7189}

References _dumpableObject::allocDeps, AssignDumpId(), _dumpableObject::catId, _dumpableObject::components, _dumpableObject::dependencies, DO_REL_STATS, _relStatsInfo::dobj, DUMP_COMPONENT_STATISTICS, _dumpableObject::dumpId, fb(), _relStatsInfo::indAttNames, _dumpableObject::name, _dumpableObject::nDeps, _relStatsInfo::nindAttNames, _dumpableObject::objType, CatalogId::oid, pg_fatal, pg_malloc(), pg_malloc0(), pg_strdup(), pstrdup(), _relStatsInfo::relallfrozen, _relStatsInfo::relallvisible, _relStatsInfo::relkind, _relStatsInfo::relpages, _relStatsInfo::reltuples, _relStatsInfo::section, SECTION_DATA, SECTION_POST_DATA, and CatalogId::tableoid.

Referenced by getIndexes(), and getTables().

◆ getRoleName()

static const char * getRoleName ( const char roleoid_str)
static

Definition at line 10697 of file pg_dump.c.

10698{
10699 Oid roleoid = atooid(roleoid_str);
10700
10701 /*
10702 * Do binary search to find the appropriate item.
10703 */
10704 if (nrolenames > 0)
10705 {
10706 RoleNameItem *low = &rolenames[0];
10707 RoleNameItem *high = &rolenames[nrolenames - 1];
10708
10709 while (low <= high)
10710 {
10711 RoleNameItem *middle = low + (high - low) / 2;
10712
10713 if (roleoid < middle->roleoid)
10714 high = middle - 1;
10715 else if (roleoid > middle->roleoid)
10716 low = middle + 1;
10717 else
10718 return middle->rolename; /* found a match */
10719 }
10720 }
10721
10722 pg_fatal("role with OID %u does not exist", roleoid);
10723 return NULL; /* keep compiler quiet */
10724}

References atooid, fb(), nrolenames, pg_fatal, RoleNameItem::rolename, and rolenames.

Referenced by dumpDatabase(), getAggregates(), getCollations(), getConversions(), getDefaultACLs(), getEventTriggers(), getExtendedStatistics(), getForeignDataWrappers(), getForeignServers(), getFuncs(), getLOs(), getNamespaces(), getOpclasses(), getOperators(), getOpfamilies(), getProcLangs(), getPublications(), getSubscriptions(), getTables(), getTSConfigurations(), getTSDictionaries(), and getTypes().

◆ getRootTableInfo()

static TableInfo * getRootTableInfo ( const TableInfo tbinfo)
static

Definition at line 2831 of file pg_dump.c.

2832{
2834
2835 Assert(tbinfo->ispartition);
2836 Assert(tbinfo->numParents == 1);
2837
2838 parentTbinfo = tbinfo->parents[0];
2839 while (parentTbinfo->ispartition)
2840 {
2841 Assert(parentTbinfo->numParents == 1);
2842 parentTbinfo = parentTbinfo->parents[0];
2843 }
2844
2845 return parentTbinfo;
2846}

References Assert, and fb().

Referenced by dumpTableData(), and dumpTableData_insert().

◆ getRules()

void getRules ( Archive fout)

Definition at line 8602 of file pg_dump.c.

8603{
8604 PGresult *res;
8605 int ntups;
8606 int i;
8609 int i_tableoid;
8610 int i_oid;
8611 int i_rulename;
8612 int i_ruletable;
8613 int i_ev_type;
8614 int i_is_instead;
8615 int i_ev_enabled;
8616
8617 appendPQExpBufferStr(query, "SELECT "
8618 "tableoid, oid, rulename, "
8619 "ev_class AS ruletable, ev_type, is_instead, "
8620 "ev_enabled "
8621 "FROM pg_rewrite "
8622 "ORDER BY oid");
8623
8624 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8625
8626 ntups = PQntuples(res);
8627
8628 ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
8629
8630 i_tableoid = PQfnumber(res, "tableoid");
8631 i_oid = PQfnumber(res, "oid");
8632 i_rulename = PQfnumber(res, "rulename");
8633 i_ruletable = PQfnumber(res, "ruletable");
8634 i_ev_type = PQfnumber(res, "ev_type");
8635 i_is_instead = PQfnumber(res, "is_instead");
8636 i_ev_enabled = PQfnumber(res, "ev_enabled");
8637
8638 for (i = 0; i < ntups; i++)
8639 {
8641
8642 ruleinfo[i].dobj.objType = DO_RULE;
8643 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8644 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8645 AssignDumpId(&ruleinfo[i].dobj);
8646 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
8648 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
8649 if (ruleinfo[i].ruletable == NULL)
8650 pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
8651 ruletableoid, ruleinfo[i].dobj.catId.oid);
8652 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
8653 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
8654 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
8655 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
8656 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
8657 if (ruleinfo[i].ruletable)
8658 {
8659 /*
8660 * If the table is a view or materialized view, force its ON
8661 * SELECT rule to be sorted before the view itself --- this
8662 * ensures that any dependencies for the rule affect the table's
8663 * positioning. Other rules are forced to appear after their
8664 * table.
8665 */
8666 if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
8667 ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
8668 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
8669 {
8670 addObjectDependency(&ruleinfo[i].ruletable->dobj,
8671 ruleinfo[i].dobj.dumpId);
8672 /* We'll merge the rule into CREATE VIEW, if possible */
8673 ruleinfo[i].separate = false;
8674 }
8675 else
8676 {
8678 ruleinfo[i].ruletable->dobj.dumpId);
8679 ruleinfo[i].separate = true;
8680 }
8681 }
8682 else
8683 ruleinfo[i].separate = true;
8684 }
8685
8686 PQclear(res);
8687
8688 destroyPQExpBuffer(query);
8689}

References addObjectDependency(), appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_RULE, ExecuteSqlQuery(), fb(), findTableByOid(), i, pg_fatal, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, and PQntuples.

Referenced by getSchemaData().

◆ getSubscriptionRelations()

void getSubscriptionRelations ( Archive fout)

Definition at line 5341 of file pg_dump.c.

5342{
5343 DumpOptions *dopt = fout->dopt;
5344 SubscriptionInfo *subinfo = NULL;
5346 PGresult *res;
5347 int i_srsubid;
5348 int i_srrelid;
5349 int i_srsubstate;
5350 int i_srsublsn;
5351 int ntups;
5353
5354 if (dopt->no_subscriptions || !dopt->binary_upgrade ||
5355 fout->remoteVersion < 170000)
5356 return;
5357
5358 res = ExecuteSqlQuery(fout,
5359 "SELECT srsubid, srrelid, srsubstate, srsublsn "
5360 "FROM pg_catalog.pg_subscription_rel "
5361 "ORDER BY srsubid",
5363 ntups = PQntuples(res);
5364 if (ntups == 0)
5365 goto cleanup;
5366
5367 /* Get pg_subscription_rel attributes */
5368 i_srsubid = PQfnumber(res, "srsubid");
5369 i_srrelid = PQfnumber(res, "srrelid");
5370 i_srsubstate = PQfnumber(res, "srsubstate");
5371 i_srsublsn = PQfnumber(res, "srsublsn");
5372
5373 subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
5374 for (int i = 0; i < ntups; i++)
5375 {
5377 Oid relid = atooid(PQgetvalue(res, i, i_srrelid));
5378 TableInfo *tblinfo;
5379
5380 /*
5381 * If we switched to a new subscription, check if the subscription
5382 * exists.
5383 */
5385 {
5387 if (subinfo == NULL)
5388 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
5389
5391 }
5392
5393 tblinfo = findTableByOid(relid);
5394 if (tblinfo == NULL)
5395 pg_fatal("failed sanity check, relation with OID %u not found",
5396 relid);
5397
5398 /* OK, make a DumpableObject for this relationship */
5399 subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
5400 subrinfo[i].dobj.catId.tableoid = relid;
5401 subrinfo[i].dobj.catId.oid = cur_srsubid;
5402 AssignDumpId(&subrinfo[i].dobj);
5403 subrinfo[i].dobj.namespace = tblinfo->dobj.namespace;
5404 subrinfo[i].dobj.name = tblinfo->dobj.name;
5405 subrinfo[i].subinfo = subinfo;
5406 subrinfo[i].tblinfo = tblinfo;
5407 subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
5408 if (PQgetisnull(res, i, i_srsublsn))
5409 subrinfo[i].srsublsn = NULL;
5410 else
5411 subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
5412
5413 /* Decide whether we want to dump it */
5415 }
5416
5417cleanup:
5418 PQclear(res);
5419}

References AssignDumpId(), atooid, _dumpOptions::binary_upgrade, cleanup(), DO_SUBSCRIPTION_REL, _tableInfo::dobj, ExecuteSqlQuery(), fb(), findSubscriptionByOid(), findTableByOid(), i, InvalidOid, _dumpableObject::name, _dumpOptions::no_subscriptions, pg_fatal, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getSubscriptions()

void getSubscriptions ( Archive fout)

Definition at line 5121 of file pg_dump.c.

5122{
5123 DumpOptions *dopt = fout->dopt;
5124 PQExpBuffer query;
5125 PGresult *res;
5126 SubscriptionInfo *subinfo;
5127 int i_tableoid;
5128 int i_oid;
5129 int i_subname;
5130 int i_subowner;
5131 int i_subbinary;
5132 int i_substream;
5136 int i_subrunasowner;
5137 int i_subconninfo;
5138 int i_subslotname;
5139 int i_subsynccommit;
5141 int i_suborigin;
5143 int i_subenabled;
5144 int i_subfailover;
5147 int i,
5148 ntups;
5149
5150 if (dopt->no_subscriptions || fout->remoteVersion < 100000)
5151 return;
5152
5153 if (!is_superuser(fout))
5154 {
5155 int n;
5156
5157 res = ExecuteSqlQuery(fout,
5158 "SELECT count(*) FROM pg_subscription "
5159 "WHERE subdbid = (SELECT oid FROM pg_database"
5160 " WHERE datname = current_database())",
5162 n = atoi(PQgetvalue(res, 0, 0));
5163 if (n > 0)
5164 pg_log_warning("subscriptions not dumped because current user is not a superuser");
5165 PQclear(res);
5166 return;
5167 }
5168
5169 query = createPQExpBuffer();
5170
5171 /* Get the subscriptions in current database. */
5173 "SELECT s.tableoid, s.oid, s.subname,\n"
5174 " s.subowner,\n"
5175 " s.subconninfo, s.subslotname, s.subsynccommit,\n"
5176 " s.subpublications,\n");
5177
5178 if (fout->remoteVersion >= 140000)
5179 appendPQExpBufferStr(query, " s.subbinary,\n");
5180 else
5181 appendPQExpBufferStr(query, " false AS subbinary,\n");
5182
5183 if (fout->remoteVersion >= 140000)
5184 appendPQExpBufferStr(query, " s.substream,\n");
5185 else
5186 appendPQExpBufferStr(query, " 'f' AS substream,\n");
5187
5188 if (fout->remoteVersion >= 150000)
5190 " s.subtwophasestate,\n"
5191 " s.subdisableonerr,\n");
5192 else
5193 appendPQExpBuffer(query,
5194 " '%c' AS subtwophasestate,\n"
5195 " false AS subdisableonerr,\n",
5197
5198 if (fout->remoteVersion >= 160000)
5200 " s.subpasswordrequired,\n"
5201 " s.subrunasowner,\n"
5202 " s.suborigin,\n");
5203 else
5204 appendPQExpBuffer(query,
5205 " 't' AS subpasswordrequired,\n"
5206 " 't' AS subrunasowner,\n"
5207 " '%s' AS suborigin,\n",
5209
5210 if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5211 appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
5212 " s.subenabled,\n");
5213 else
5214 appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
5215 " false AS subenabled,\n");
5216
5217 if (fout->remoteVersion >= 170000)
5219 " s.subfailover,\n");
5220 else
5222 " false AS subfailover,\n");
5223
5224 if (fout->remoteVersion >= 190000)
5226 " s.subretaindeadtuples,\n");
5227 else
5229 " false AS subretaindeadtuples,\n");
5230
5231 if (fout->remoteVersion >= 190000)
5233 " s.submaxretention\n");
5234 else
5235 appendPQExpBuffer(query,
5236 " 0 AS submaxretention\n");
5237
5239 "FROM pg_subscription s\n");
5240
5241 if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5243 "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
5244 " ON o.external_id = 'pg_' || s.oid::text \n");
5245
5247 "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
5248 " WHERE datname = current_database())");
5249
5250 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5251
5252 ntups = PQntuples(res);
5253
5254 /*
5255 * Get subscription fields. We don't include subskiplsn in the dump as
5256 * after restoring the dump this value may no longer be relevant.
5257 */
5258 i_tableoid = PQfnumber(res, "tableoid");
5259 i_oid = PQfnumber(res, "oid");
5260 i_subname = PQfnumber(res, "subname");
5261 i_subowner = PQfnumber(res, "subowner");
5262 i_subenabled = PQfnumber(res, "subenabled");
5263 i_subbinary = PQfnumber(res, "subbinary");
5264 i_substream = PQfnumber(res, "substream");
5265 i_subtwophasestate = PQfnumber(res, "subtwophasestate");
5266 i_subdisableonerr = PQfnumber(res, "subdisableonerr");
5267 i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
5268 i_subrunasowner = PQfnumber(res, "subrunasowner");
5269 i_subfailover = PQfnumber(res, "subfailover");
5270 i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
5271 i_submaxretention = PQfnumber(res, "submaxretention");
5272 i_subconninfo = PQfnumber(res, "subconninfo");
5273 i_subslotname = PQfnumber(res, "subslotname");
5274 i_subsynccommit = PQfnumber(res, "subsynccommit");
5275 i_subpublications = PQfnumber(res, "subpublications");
5276 i_suborigin = PQfnumber(res, "suborigin");
5277 i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
5278
5279 subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
5280
5281 for (i = 0; i < ntups; i++)
5282 {
5283 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
5284 subinfo[i].dobj.catId.tableoid =
5285 atooid(PQgetvalue(res, i, i_tableoid));
5286 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5287 AssignDumpId(&subinfo[i].dobj);
5288 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
5289 subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
5290
5291 subinfo[i].subenabled =
5292 (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
5293 subinfo[i].subbinary =
5294 (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
5295 subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
5296 subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
5297 subinfo[i].subdisableonerr =
5298 (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
5299 subinfo[i].subpasswordrequired =
5300 (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
5301 subinfo[i].subrunasowner =
5302 (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
5303 subinfo[i].subfailover =
5304 (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
5305 subinfo[i].subretaindeadtuples =
5306 (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
5307 subinfo[i].submaxretention =
5309 subinfo[i].subconninfo =
5311 if (PQgetisnull(res, i, i_subslotname))
5312 subinfo[i].subslotname = NULL;
5313 else
5314 subinfo[i].subslotname =
5316 subinfo[i].subsynccommit =
5318 subinfo[i].subpublications =
5320 subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
5322 subinfo[i].suboriginremotelsn = NULL;
5323 else
5324 subinfo[i].suboriginremotelsn =
5326
5327 /* Decide whether we want to dump it */
5328 selectDumpableObject(&(subinfo[i].dobj), fout);
5329 }
5330 PQclear(res);
5331
5332 destroyPQExpBuffer(query);
5333}

References appendPQExpBuffer(), appendPQExpBufferStr(), AssignDumpId(), atooid, _dumpOptions::binary_upgrade, _dumpableObject::catId, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_SUBSCRIPTION, _SubscriptionInfo::dobj, ExecuteSqlQuery(), fb(), getRoleName(), i, is_superuser(), _dumpableObject::name, _dumpOptions::no_subscriptions, _dumpableObject::objType, CatalogId::oid, pg_log_warning, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, _SubscriptionInfo::rolname, selectDumpableObject(), _SubscriptionInfo::subbinary, _SubscriptionInfo::subconninfo, _SubscriptionInfo::subdisableonerr, _SubscriptionInfo::subenabled, _SubscriptionInfo::subfailover, _SubscriptionInfo::submaxretention, _SubscriptionInfo::suborigin, _SubscriptionInfo::suboriginremotelsn, _SubscriptionInfo::subpasswordrequired, _SubscriptionInfo::subpublications, _SubscriptionInfo::subretaindeadtuples, _SubscriptionInfo::subrunasowner, _SubscriptionInfo::subslotname, _SubscriptionInfo::substream, _SubscriptionInfo::subsynccommit, _SubscriptionInfo::subtwophasestate, and CatalogId::tableoid.

Referenced by getSchemaData().

◆ getTableAttrs()

void getTableAttrs ( Archive fout,
TableInfo tblinfo,
int  numTables 
)

Definition at line 9251 of file pg_dump.c.

9252{
9253 DumpOptions *dopt = fout->dopt;
9258 PGresult *res;
9259 int ntups;
9260 int curtblindx;
9261 int i_attrelid;
9262 int i_attnum;
9263 int i_attname;
9264 int i_atttypname;
9265 int i_attstattarget;
9266 int i_attstorage;
9267 int i_typstorage;
9268 int i_attidentity;
9269 int i_attgenerated;
9270 int i_attisdropped;
9271 int i_attlen;
9272 int i_attalign;
9273 int i_attislocal;
9274 int i_notnull_name;
9279 int i_attoptions;
9280 int i_attcollation;
9281 int i_attcompression;
9282 int i_attfdwoptions;
9283 int i_attmissingval;
9284 int i_atthasdef;
9285
9286 /*
9287 * We want to perform just one query against pg_attribute, and then just
9288 * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
9289 * (for CHECK constraints and for NOT NULL constraints). However, we
9290 * mustn't try to select every row of those catalogs and then sort it out
9291 * on the client side, because some of the server-side functions we need
9292 * would be unsafe to apply to tables we don't have lock on. Hence, we
9293 * build an array of the OIDs of tables we care about (and now have lock
9294 * on!), and use a WHERE clause to constrain which rows are selected.
9295 */
9298 for (int i = 0; i < numTables; i++)
9299 {
9300 TableInfo *tbinfo = &tblinfo[i];
9301
9302 /* Don't bother to collect info for sequences */
9303 if (tbinfo->relkind == RELKIND_SEQUENCE)
9304 continue;
9305
9306 /*
9307 * Don't bother with uninteresting tables, either. For binary
9308 * upgrades, this is bypassed for pg_largeobject_metadata and
9309 * pg_shdepend so that the columns names are collected for the
9310 * corresponding COPY commands. Restoring the data for those catalogs
9311 * is faster than restoring the equivalent set of large object
9312 * commands. We can only do this for upgrades from v12 and newer; in
9313 * older versions, pg_largeobject_metadata was created WITH OIDS, so
9314 * the OID column is hidden and won't be dumped.
9315 */
9316 if (!tbinfo->interesting &&
9317 !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
9318 (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
9319 tbinfo->dobj.catId.oid == SharedDependRelationId)))
9320 continue;
9321
9322 /* OK, we need info for this table */
9323 if (tbloids->len > 1) /* do we have more than the '{'? */
9325 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
9326
9327 if (tbinfo->ncheck > 0)
9328 {
9329 /* Also make a list of the ones with check constraints */
9330 if (checkoids->len > 1) /* do we have more than the '{'? */
9332 appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
9333 }
9334 }
9337
9338 /*
9339 * Find all the user attributes and their types.
9340 *
9341 * Since we only want to dump COLLATE clauses for attributes whose
9342 * collation is different from their type's default, we use a CASE here to
9343 * suppress uninteresting attcollations cheaply.
9344 */
9346 "SELECT\n"
9347 "a.attrelid,\n"
9348 "a.attnum,\n"
9349 "a.attname,\n"
9350 "a.attstattarget,\n"
9351 "a.attstorage,\n"
9352 "t.typstorage,\n"
9353 "a.atthasdef,\n"
9354 "a.attisdropped,\n"
9355 "a.attlen,\n"
9356 "a.attalign,\n"
9357 "a.attislocal,\n"
9358 "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
9359 "array_to_string(a.attoptions, ', ') AS attoptions,\n"
9360 "CASE WHEN a.attcollation <> t.typcollation "
9361 "THEN a.attcollation ELSE 0 END AS attcollation,\n"
9362 "pg_catalog.array_to_string(ARRAY("
9363 "SELECT pg_catalog.quote_ident(option_name) || "
9364 "' ' || pg_catalog.quote_literal(option_value) "
9365 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
9366 "ORDER BY option_name"
9367 "), E',\n ') AS attfdwoptions,\n");
9368
9369 /*
9370 * Find out any NOT NULL markings for each column. In 18 and up we read
9371 * pg_constraint to obtain the constraint name, and for valid constraints
9372 * also pg_description to obtain its comment. notnull_noinherit is set
9373 * according to the NO INHERIT property. For versions prior to 18, we
9374 * store an empty string as the name when a constraint is marked as
9375 * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
9376 * without a name); also, such cases are never NO INHERIT.
9377 *
9378 * For invalid constraints, we need to store their OIDs for processing
9379 * elsewhere, so we bring the pg_constraint.oid value when the constraint
9380 * is invalid, and NULL otherwise. Their comments are handled not here
9381 * but by collectComments, because they're their own dumpable object.
9382 *
9383 * We track in notnull_islocal whether the constraint was defined directly
9384 * in this table or via an ancestor, for binary upgrade. flagInhAttrs
9385 * might modify this later.
9386 */
9387 if (fout->remoteVersion >= 180000)
9389 "co.conname AS notnull_name,\n"
9390 "CASE WHEN co.convalidated THEN pt.description"
9391 " ELSE NULL END AS notnull_comment,\n"
9392 "CASE WHEN NOT co.convalidated THEN co.oid "
9393 "ELSE NULL END AS notnull_invalidoid,\n"
9394 "co.connoinherit AS notnull_noinherit,\n"
9395 "co.conislocal AS notnull_islocal,\n");
9396 else
9398 "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
9399 "NULL AS notnull_comment,\n"
9400 "NULL AS notnull_invalidoid,\n"
9401 "false AS notnull_noinherit,\n"
9402 "CASE WHEN a.attislocal THEN true\n"
9403 " WHEN a.attnotnull AND NOT a.attislocal THEN true\n"
9404 " ELSE false\n"
9405 "END AS notnull_islocal,\n");
9406
9407 if (fout->remoteVersion >= 140000)
9409 "a.attcompression AS attcompression,\n");
9410 else
9412 "'' AS attcompression,\n");
9413
9414 if (fout->remoteVersion >= 100000)
9416 "a.attidentity,\n");
9417 else
9419 "'' AS attidentity,\n");
9420
9421 if (fout->remoteVersion >= 110000)
9423 "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
9424 "THEN a.attmissingval ELSE null END AS attmissingval,\n");
9425 else
9427 "NULL AS attmissingval,\n");
9428
9429 if (fout->remoteVersion >= 120000)
9431 "a.attgenerated\n");
9432 else
9434 "'' AS attgenerated\n");
9435
9436 /* need left join to pg_type to not fail on dropped columns ... */
9438 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9439 "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
9440 "LEFT JOIN pg_catalog.pg_type t "
9441 "ON (a.atttypid = t.oid)\n",
9442 tbloids->data);
9443
9444 /*
9445 * In versions 18 and up, we need pg_constraint for explicit NOT NULL
9446 * entries and pg_description to get their comments.
9447 */
9448 if (fout->remoteVersion >= 180000)
9450 " LEFT JOIN pg_catalog.pg_constraint co ON "
9451 "(a.attrelid = co.conrelid\n"
9452 " AND co.contype = 'n' AND "
9453 "co.conkey = array[a.attnum])\n"
9454 " LEFT JOIN pg_catalog.pg_description pt ON "
9455 "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
9456
9458 "WHERE a.attnum > 0::pg_catalog.int2\n"
9459 "ORDER BY a.attrelid, a.attnum");
9460
9462
9463 ntups = PQntuples(res);
9464
9465 i_attrelid = PQfnumber(res, "attrelid");
9466 i_attnum = PQfnumber(res, "attnum");
9467 i_attname = PQfnumber(res, "attname");
9468 i_atttypname = PQfnumber(res, "atttypname");
9469 i_attstattarget = PQfnumber(res, "attstattarget");
9470 i_attstorage = PQfnumber(res, "attstorage");
9471 i_typstorage = PQfnumber(res, "typstorage");
9472 i_attidentity = PQfnumber(res, "attidentity");
9473 i_attgenerated = PQfnumber(res, "attgenerated");
9474 i_attisdropped = PQfnumber(res, "attisdropped");
9475 i_attlen = PQfnumber(res, "attlen");
9476 i_attalign = PQfnumber(res, "attalign");
9477 i_attislocal = PQfnumber(res, "attislocal");
9478 i_notnull_name = PQfnumber(res, "notnull_name");
9479 i_notnull_comment = PQfnumber(res, "notnull_comment");
9480 i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
9481 i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
9482 i_notnull_islocal = PQfnumber(res, "notnull_islocal");
9483 i_attoptions = PQfnumber(res, "attoptions");
9484 i_attcollation = PQfnumber(res, "attcollation");
9485 i_attcompression = PQfnumber(res, "attcompression");
9486 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
9487 i_attmissingval = PQfnumber(res, "attmissingval");
9488 i_atthasdef = PQfnumber(res, "atthasdef");
9489
9490 /* Within the next loop, we'll accumulate OIDs of tables with defaults */
9493
9494 /*
9495 * Outer loop iterates once per table, not once per row. Incrementing of
9496 * r is handled by the inner loop.
9497 */
9498 curtblindx = -1;
9499 for (int r = 0; r < ntups;)
9500 {
9501 Oid attrelid = atooid(PQgetvalue(res, r, i_attrelid));
9503 int numatts;
9504 bool hasdefaults;
9505
9506 /* Count rows for this table */
9507 for (numatts = 1; numatts < ntups - r; numatts++)
9508 if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
9509 break;
9510
9511 /*
9512 * Locate the associated TableInfo; we rely on tblinfo[] being in OID
9513 * order.
9514 */
9515 while (++curtblindx < numTables)
9516 {
9517 tbinfo = &tblinfo[curtblindx];
9518 if (tbinfo->dobj.catId.oid == attrelid)
9519 break;
9520 }
9521 if (curtblindx >= numTables)
9522 pg_fatal("unrecognized table OID %u", attrelid);
9523 /* cross-check that we only got requested tables */
9524 if (tbinfo->relkind == RELKIND_SEQUENCE ||
9525 (!tbinfo->interesting &&
9526 !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
9527 (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
9528 tbinfo->dobj.catId.oid == SharedDependRelationId))))
9529 pg_fatal("unexpected column data for table \"%s\"",
9530 tbinfo->dobj.name);
9531
9532 /* Save data for this table */
9533 tbinfo->numatts = numatts;
9534 tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
9535 tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
9536 tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
9537 tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
9538 tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
9539 tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
9540 tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
9541 tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
9542 tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
9543 tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
9544 tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
9545 tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
9546 tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
9547 tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
9548 tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
9549 tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
9550 tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
9551 tbinfo->notnull_comment = (char **) pg_malloc(numatts * sizeof(char *));
9552 tbinfo->notnull_invalid = (bool *) pg_malloc(numatts * sizeof(bool));
9553 tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
9554 tbinfo->notnull_islocal = (bool *) pg_malloc(numatts * sizeof(bool));
9555 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
9556 hasdefaults = false;
9557
9558 for (int j = 0; j < numatts; j++, r++)
9559 {
9560 if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
9561 pg_fatal("invalid column numbering in table \"%s\"",
9562 tbinfo->dobj.name);
9563 tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
9564 tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
9565 if (PQgetisnull(res, r, i_attstattarget))
9566 tbinfo->attstattarget[j] = -1;
9567 else
9568 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
9569 tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
9570 tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
9571 tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
9572 tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
9573 tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
9574 tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
9575 tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
9576 tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
9577 tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
9578
9579 /* Handle not-null constraint name and flags */
9581 tbinfo, j,
9588
9589 tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
9591 tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
9592 tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
9593 tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
9594 tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
9595 tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
9596 tbinfo->attrdefs[j] = NULL; /* fix below */
9597 if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
9598 hasdefaults = true;
9599 }
9600
9601 if (hasdefaults)
9602 {
9603 /* Collect OIDs of interesting tables that have defaults */
9604 if (tbloids->len > 1) /* do we have more than the '{'? */
9606 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
9607 }
9608 }
9609
9610 /* If invalidnotnulloids has any data, finalize it */
9611 if (invalidnotnulloids != NULL)
9613
9614 PQclear(res);
9615
9616 /*
9617 * Now get info about column defaults. This is skipped for a data-only
9618 * dump, as it is only needed for table schemas.
9619 */
9620 if (dopt->dumpSchema && tbloids->len > 1)
9621 {
9622 AttrDefInfo *attrdefs;
9623 int numDefaults;
9625
9626 pg_log_info("finding table default expressions");
9627
9629
9630 printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
9631 "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
9632 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9633 "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
9634 "ORDER BY a.adrelid, a.adnum",
9635 tbloids->data);
9636
9638
9639 numDefaults = PQntuples(res);
9640 attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
9641
9642 curtblindx = -1;
9643 for (int j = 0; j < numDefaults; j++)
9644 {
9645 Oid adtableoid = atooid(PQgetvalue(res, j, 0));
9646 Oid adoid = atooid(PQgetvalue(res, j, 1));
9647 Oid adrelid = atooid(PQgetvalue(res, j, 2));
9648 int adnum = atoi(PQgetvalue(res, j, 3));
9649 char *adsrc = PQgetvalue(res, j, 4);
9650
9651 /*
9652 * Locate the associated TableInfo; we rely on tblinfo[] being in
9653 * OID order.
9654 */
9655 if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
9656 {
9657 while (++curtblindx < numTables)
9658 {
9659 tbinfo = &tblinfo[curtblindx];
9660 if (tbinfo->dobj.catId.oid == adrelid)
9661 break;
9662 }
9663 if (curtblindx >= numTables)
9664 pg_fatal("unrecognized table OID %u", adrelid);
9665 }
9666
9667 if (adnum <= 0 || adnum > tbinfo->numatts)
9668 pg_fatal("invalid adnum value %d for table \"%s\"",
9669 adnum, tbinfo->dobj.name);
9670
9671 /*
9672 * dropped columns shouldn't have defaults, but just in case,
9673 * ignore 'em
9674 */
9675 if (tbinfo->attisdropped[adnum - 1])
9676 continue;
9677
9678 attrdefs[j].dobj.objType = DO_ATTRDEF;
9679 attrdefs[j].dobj.catId.tableoid = adtableoid;
9680 attrdefs[j].dobj.catId.oid = adoid;
9681 AssignDumpId(&attrdefs[j].dobj);
9682 attrdefs[j].adtable = tbinfo;
9683 attrdefs[j].adnum = adnum;
9684 attrdefs[j].adef_expr = pg_strdup(adsrc);
9685
9686 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
9687 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
9688
9689 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
9690
9691 /*
9692 * Figure out whether the default/generation expression should be
9693 * dumped as part of the main CREATE TABLE (or similar) command or
9694 * as a separate ALTER TABLE (or similar) command. The preference
9695 * is to put it into the CREATE command, but in some cases that's
9696 * not possible.
9697 */
9698 if (tbinfo->attgenerated[adnum - 1])
9699 {
9700 /*
9701 * Column generation expressions cannot be dumped separately,
9702 * because there is no syntax for it. By setting separate to
9703 * false here we prevent the "default" from being processed as
9704 * its own dumpable object. Later, flagInhAttrs() will mark
9705 * it as not to be dumped at all, if possible (that is, if it
9706 * can be inherited from a parent).
9707 */
9708 attrdefs[j].separate = false;
9709 }
9710 else if (tbinfo->relkind == RELKIND_VIEW)
9711 {
9712 /*
9713 * Defaults on a VIEW must always be dumped as separate ALTER
9714 * TABLE commands.
9715 */
9716 attrdefs[j].separate = true;
9717 }
9718 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
9719 {
9720 /* column will be suppressed, print default separately */
9721 attrdefs[j].separate = true;
9722 }
9723 else
9724 {
9725 attrdefs[j].separate = false;
9726 }
9727
9728 if (!attrdefs[j].separate)
9729 {
9730 /*
9731 * Mark the default as needing to appear before the table, so
9732 * that any dependencies it has must be emitted before the
9733 * CREATE TABLE. If this is not possible, we'll change to
9734 * "separate" mode while sorting dependencies.
9735 */
9737 attrdefs[j].dobj.dumpId);
9738 }
9739
9740 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
9741 }
9742
9743 PQclear(res);
9744 }
9745
9746 /*
9747 * Get info about NOT NULL NOT VALID constraints. This is skipped for a
9748 * data-only dump, as it is only needed for table schemas.
9749 */
9750 if (dopt->dumpSchema && invalidnotnulloids)
9751 {
9753 int numConstrs;
9754 int i_tableoid;
9755 int i_oid;
9756 int i_conrelid;
9757 int i_conname;
9758 int i_consrc;
9759 int i_conislocal;
9760
9761 pg_log_info("finding invalid not-null constraints");
9762
9765 "SELECT c.tableoid, c.oid, conrelid, conname, "
9766 "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9767 "conislocal, convalidated "
9768 "FROM unnest('%s'::pg_catalog.oid[]) AS src(conoid)\n"
9769 "JOIN pg_catalog.pg_constraint c ON (src.conoid = c.oid)\n"
9770 "ORDER BY c.conrelid, c.conname",
9771 invalidnotnulloids->data);
9772
9774
9775 numConstrs = PQntuples(res);
9777
9778 i_tableoid = PQfnumber(res, "tableoid");
9779 i_oid = PQfnumber(res, "oid");
9780 i_conrelid = PQfnumber(res, "conrelid");
9781 i_conname = PQfnumber(res, "conname");
9782 i_consrc = PQfnumber(res, "consrc");
9783 i_conislocal = PQfnumber(res, "conislocal");
9784
9785 /* As above, this loop iterates once per table, not once per row */
9786 curtblindx = -1;
9787 for (int j = 0; j < numConstrs;)
9788 {
9789 Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9791 int numcons;
9792
9793 /* Count rows for this table */
9794 for (numcons = 1; numcons < numConstrs - j; numcons++)
9795 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9796 break;
9797
9798 /*
9799 * Locate the associated TableInfo; we rely on tblinfo[] being in
9800 * OID order.
9801 */
9802 while (++curtblindx < numTables)
9803 {
9804 tbinfo = &tblinfo[curtblindx];
9805 if (tbinfo->dobj.catId.oid == conrelid)
9806 break;
9807 }
9808 if (curtblindx >= numTables)
9809 pg_fatal("unrecognized table OID %u", conrelid);
9810
9811 for (int c = 0; c < numcons; c++, j++)
9812 {
9813 constrs[j].dobj.objType = DO_CONSTRAINT;
9814 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9815 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
9816 AssignDumpId(&constrs[j].dobj);
9817 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
9818 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
9819 constrs[j].contable = tbinfo;
9820 constrs[j].condomain = NULL;
9821 constrs[j].contype = 'n';
9822 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
9823 constrs[j].confrelid = InvalidOid;
9824 constrs[j].conindex = 0;
9825 constrs[j].condeferrable = false;
9826 constrs[j].condeferred = false;
9827 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9828
9829 /*
9830 * All invalid not-null constraints must be dumped separately,
9831 * because CREATE TABLE would not create them as invalid, and
9832 * also because they must be created after potentially
9833 * violating data has been loaded.
9834 */
9835 constrs[j].separate = true;
9836
9837 constrs[j].dobj.dump = tbinfo->dobj.dump;
9838 }
9839 }
9840 PQclear(res);
9841 }
9842
9843 /*
9844 * Get info about table CHECK constraints. This is skipped for a
9845 * data-only dump, as it is only needed for table schemas.
9846 */
9847 if (dopt->dumpSchema && checkoids->len > 2)
9848 {
9850 int numConstrs;
9851 int i_tableoid;
9852 int i_oid;
9853 int i_conrelid;
9854 int i_conname;
9855 int i_consrc;
9856 int i_conislocal;
9857 int i_convalidated;
9858
9859 pg_log_info("finding table check constraints");
9860
9863 "SELECT c.tableoid, c.oid, conrelid, conname, "
9864 "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9865 "conislocal, convalidated "
9866 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9867 "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
9868 "WHERE contype = 'c' "
9869 "ORDER BY c.conrelid, c.conname",
9870 checkoids->data);
9871
9873
9874 numConstrs = PQntuples(res);
9876
9877 i_tableoid = PQfnumber(res, "tableoid");
9878 i_oid = PQfnumber(res, "oid");
9879 i_conrelid = PQfnumber(res, "conrelid");
9880 i_conname = PQfnumber(res, "conname");
9881 i_consrc = PQfnumber(res, "consrc");
9882 i_conislocal = PQfnumber(res, "conislocal");
9883 i_convalidated = PQfnumber(res, "convalidated");
9884
9885 /* As above, this loop iterates once per table, not once per row */
9886 curtblindx = -1;
9887 for (int j = 0; j < numConstrs;)
9888 {
9889 Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9891 int numcons;
9892
9893 /* Count rows for this table */
9894 for (numcons = 1; numcons < numConstrs - j; numcons++)
9895 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9896 break;
9897
9898 /*
9899 * Locate the associated TableInfo; we rely on tblinfo[] being in
9900 * OID order.
9901 */
9902 while (++curtblindx < numTables)
9903 {
9904 tbinfo = &tblinfo[curtblindx];
9905 if (tbinfo->dobj.catId.oid == conrelid)
9906 break;
9907 }
9908 if (curtblindx >= numTables)
9909 pg_fatal("unrecognized table OID %u", conrelid);
9910
9911 if (numcons != tbinfo->ncheck)
9912 {
9913 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
9914 "expected %d check constraints on table \"%s\" but found %d",
9915 tbinfo->ncheck),
9916 tbinfo->ncheck, tbinfo->dobj.name, numcons);
9917 pg_log_error_hint("The system catalogs might be corrupted.");
9918 exit_nicely(1);
9919 }
9920
9921 tbinfo->checkexprs = constrs + j;
9922
9923 for (int c = 0; c < numcons; c++, j++)
9924 {
9925 bool validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
9926
9927 constrs[j].dobj.objType = DO_CONSTRAINT;
9928 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9929 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
9930 AssignDumpId(&constrs[j].dobj);
9931 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
9932 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
9933 constrs[j].contable = tbinfo;
9934 constrs[j].condomain = NULL;
9935 constrs[j].contype = 'c';
9936 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
9937 constrs[j].confrelid = InvalidOid;
9938 constrs[j].conindex = 0;
9939 constrs[j].condeferrable = false;
9940 constrs[j].condeferred = false;
9941 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9942
9943 /*
9944 * An unvalidated constraint needs to be dumped separately, so
9945 * that potentially-violating existing data is loaded before
9946 * the constraint.
9947 */
9948 constrs[j].separate = !validated;
9949
9950 constrs[j].dobj.dump = tbinfo->dobj.dump;
9951
9952 /*
9953 * Mark the constraint as needing to appear before the table
9954 * --- this is so that any other dependencies of the
9955 * constraint will be emitted before we try to create the
9956 * table. If the constraint is to be dumped separately, it
9957 * will be dumped after data is loaded anyway, so don't do it.
9958 * (There's an automatic dependency in the opposite direction
9959 * anyway, so don't need to add one manually here.)
9960 */
9961 if (!constrs[j].separate)
9963 constrs[j].dobj.dumpId);
9964
9965 /*
9966 * We will detect later whether the constraint must be split
9967 * out from the table definition.
9968 */
9969 }
9970 }
9971
9972 PQclear(res);
9973 }
9974
9978}

References addObjectDependency(), _attrDefInfo::adef_expr, _attrDefInfo::adnum, _attrDefInfo::adtable, appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), AssignDumpId(), atooid, _dumpableObject::catId, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), determineNotNullFlags(), DO_ATTRDEF, DO_CONSTRAINT, _attrDefInfo::dobj, _dumpableObject::dump, _dumpableObject::dumpId, _dumpOptions::dumpSchema, ExecuteSqlQuery(), exit_nicely(), fb(), i, InvalidOid, j, _dumpableObject::name, ngettext, _dumpableObject::objType, CatalogId::oid, pg_fatal, pg_log_error, pg_log_error_hint, pg_log_info, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, printfPQExpBuffer(), resetPQExpBuffer(), _attrDefInfo::separate, shouldPrintColumn(), and CatalogId::tableoid.

Referenced by getSchemaData().

◆ getTableData()

static void getTableData ( DumpOptions dopt,
TableInfo tblinfo,
int  numTables,
char  relkind 
)
static

Definition at line 3034 of file pg_dump.c.

3035{
3036 int i;
3037
3038 for (i = 0; i < numTables; i++)
3039 {
3040 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
3041 (!relkind || tblinfo[i].relkind == relkind))
3042 makeTableDataInfo(dopt, &(tblinfo[i]));
3043 }
3044}

References DUMP_COMPONENT_DATA, fb(), i, makeTableDataInfo(), and _tableInfo::relkind.

Referenced by main().

◆ getTableDataFKConstraints()

static void getTableDataFKConstraints ( void  )
static

Definition at line 3255 of file pg_dump.c.

3256{
3258 int numObjs;
3259 int i;
3260
3261 /* Search through all the dumpable objects for FK constraints */
3263 for (i = 0; i < numObjs; i++)
3264 {
3265 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
3266 {
3269
3270 /* Not interesting unless both tables are to be dumped */
3271 if (cinfo->contable == NULL ||
3272 cinfo->contable->dataObj == NULL)
3273 continue;
3274 ftable = findTableByOid(cinfo->confrelid);
3275 if (ftable == NULL ||
3276 ftable->dataObj == NULL)
3277 continue;
3278
3279 /*
3280 * Okay, make referencing table's TABLE_DATA object depend on the
3281 * referenced table's TABLE_DATA object.
3282 */
3283 addObjectDependency(&cinfo->contable->dataObj->dobj,
3284 ftable->dataObj->dobj.dumpId);
3285 }
3286 }
3287 free(dobjs);
3288}

References addObjectDependency(), DO_FK_CONSTRAINT, fb(), findTableByOid(), free, getDumpableObjects(), and i.

Referenced by main().

◆ getTables()

TableInfo * getTables ( Archive fout,
int numTables 
)

Definition at line 7199 of file pg_dump.c.

7200{
7201 DumpOptions *dopt = fout->dopt;
7202 PGresult *res;
7203 int ntups;
7204 int i;
7206 TableInfo *tblinfo;
7207 int i_reltableoid;
7208 int i_reloid;
7209 int i_relname;
7210 int i_relnamespace;
7211 int i_relkind;
7212 int i_reltype;
7213 int i_relowner;
7214 int i_relchecks;
7215 int i_relhasindex;
7216 int i_relhasrules;
7217 int i_relpages;
7218 int i_reltuples;
7219 int i_relallvisible;
7220 int i_relallfrozen;
7221 int i_toastpages;
7222 int i_owning_tab;
7223 int i_owning_col;
7224 int i_reltablespace;
7225 int i_relhasoids;
7226 int i_relhastriggers;
7227 int i_relpersistence;
7228 int i_relispopulated;
7229 int i_relreplident;
7230 int i_relrowsec;
7231 int i_relforcerowsec;
7232 int i_relfrozenxid;
7233 int i_toastfrozenxid;
7234 int i_toastoid;
7235 int i_relminmxid;
7236 int i_toastminmxid;
7237 int i_reloptions;
7238 int i_checkoption;
7240 int i_reloftype;
7241 int i_foreignserver;
7242 int i_amname;
7244 int i_relacl;
7245 int i_acldefault;
7246 int i_ispartition;
7247
7248 /*
7249 * Find all the tables and table-like objects.
7250 *
7251 * We must fetch all tables in this phase because otherwise we cannot
7252 * correctly identify inherited columns, owned sequences, etc.
7253 *
7254 * We include system catalogs, so that we can work if a user table is
7255 * defined to inherit from a system catalog (pretty weird, but...)
7256 *
7257 * Note: in this phase we should collect only a minimal amount of
7258 * information about each table, basically just enough to decide if it is
7259 * interesting. In particular, since we do not yet have lock on any user
7260 * table, we MUST NOT invoke any server-side data collection functions
7261 * (for instance, pg_get_partkeydef()). Those are likely to fail or give
7262 * wrong answers if any concurrent DDL is happening.
7263 */
7264
7266 "SELECT c.tableoid, c.oid, c.relname, "
7267 "c.relnamespace, c.relkind, c.reltype, "
7268 "c.relowner, "
7269 "c.relchecks, "
7270 "c.relhasindex, c.relhasrules, c.relpages, "
7271 "c.reltuples, c.relallvisible, ");
7272
7273 if (fout->remoteVersion >= 180000)
7274 appendPQExpBufferStr(query, "c.relallfrozen, ");
7275 else
7276 appendPQExpBufferStr(query, "0 AS relallfrozen, ");
7277
7279 "c.relhastriggers, c.relpersistence, "
7280 "c.reloftype, "
7281 "c.relacl, "
7282 "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
7283 " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
7284 "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
7285 "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
7286 "ELSE 0 END AS foreignserver, "
7287 "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
7288 "tc.oid AS toid, "
7289 "tc.relpages AS toastpages, "
7290 "tc.reloptions AS toast_reloptions, "
7291 "d.refobjid AS owning_tab, "
7292 "d.refobjsubid AS owning_col, "
7293 "tsp.spcname AS reltablespace, ");
7294
7295 if (fout->remoteVersion >= 120000)
7297 "false AS relhasoids, ");
7298 else
7300 "c.relhasoids, ");
7301
7302 if (fout->remoteVersion >= 90300)
7304 "c.relispopulated, ");
7305 else
7307 "'t' as relispopulated, ");
7308
7309 if (fout->remoteVersion >= 90400)
7311 "c.relreplident, ");
7312 else
7314 "'d' AS relreplident, ");
7315
7316 if (fout->remoteVersion >= 90500)
7318 "c.relrowsecurity, c.relforcerowsecurity, ");
7319 else
7321 "false AS relrowsecurity, "
7322 "false AS relforcerowsecurity, ");
7323
7324 if (fout->remoteVersion >= 90300)
7326 "c.relminmxid, tc.relminmxid AS tminmxid, ");
7327 else
7329 "0 AS relminmxid, 0 AS tminmxid, ");
7330
7331 if (fout->remoteVersion >= 90300)
7333 "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
7334 "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
7335 "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
7336 else
7338 "c.reloptions, NULL AS checkoption, ");
7339
7340 if (fout->remoteVersion >= 90600)
7342 "am.amname, ");
7343 else
7345 "NULL AS amname, ");
7346
7347 if (fout->remoteVersion >= 90600)
7349 "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
7350 else
7352 "false AS is_identity_sequence, ");
7353
7354 if (fout->remoteVersion >= 100000)
7356 "c.relispartition AS ispartition ");
7357 else
7359 "false AS ispartition ");
7360
7361 /*
7362 * Left join to pg_depend to pick up dependency info linking sequences to
7363 * their owning column, if any (note this dependency is AUTO except for
7364 * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
7365 * collect the spcname.
7366 */
7368 "\nFROM pg_class c\n"
7369 "LEFT JOIN pg_depend d ON "
7370 "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
7371 "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
7372 "d.objsubid = 0 AND "
7373 "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
7374 "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
7375
7376 /*
7377 * In 9.6 and up, left join to pg_am to pick up the amname.
7378 */
7379 if (fout->remoteVersion >= 90600)
7381 "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
7382
7383 /*
7384 * We purposefully ignore toast OIDs for partitioned tables; the reason is
7385 * that versions 10 and 11 have them, but later versions do not, so
7386 * emitting them causes the upgrade to fail.
7387 */
7389 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
7390 " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
7391 " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
7392
7393 /*
7394 * Restrict to interesting relkinds (in particular, not indexes). Not all
7395 * relkinds are possible in older servers, but it's not worth the trouble
7396 * to emit a version-dependent list.
7397 *
7398 * Composite-type table entries won't be dumped as such, but we have to
7399 * make a DumpableObject for them so that we can track dependencies of the
7400 * composite type (pg_depend entries for columns of the composite type
7401 * link to the pg_class entry not the pg_type entry).
7402 */
7404 "WHERE c.relkind IN ("
7412 "ORDER BY c.oid");
7413
7414 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7415
7416 ntups = PQntuples(res);
7417
7418 *numTables = ntups;
7419
7420 /*
7421 * Extract data from result and lock dumpable tables. We do the locking
7422 * before anything else, to minimize the window wherein a table could
7423 * disappear under us.
7424 *
7425 * Note that we have to save info about all tables here, even when dumping
7426 * only one, because we don't yet know which tables might be inheritance
7427 * ancestors of the target table.
7428 */
7429 tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
7430
7431 i_reltableoid = PQfnumber(res, "tableoid");
7432 i_reloid = PQfnumber(res, "oid");
7433 i_relname = PQfnumber(res, "relname");
7434 i_relnamespace = PQfnumber(res, "relnamespace");
7435 i_relkind = PQfnumber(res, "relkind");
7436 i_reltype = PQfnumber(res, "reltype");
7437 i_relowner = PQfnumber(res, "relowner");
7438 i_relchecks = PQfnumber(res, "relchecks");
7439 i_relhasindex = PQfnumber(res, "relhasindex");
7440 i_relhasrules = PQfnumber(res, "relhasrules");
7441 i_relpages = PQfnumber(res, "relpages");
7442 i_reltuples = PQfnumber(res, "reltuples");
7443 i_relallvisible = PQfnumber(res, "relallvisible");
7444 i_relallfrozen = PQfnumber(res, "relallfrozen");
7445 i_toastpages = PQfnumber(res, "toastpages");
7446 i_owning_tab = PQfnumber(res, "owning_tab");
7447 i_owning_col = PQfnumber(res, "owning_col");
7448 i_reltablespace = PQfnumber(res, "reltablespace");
7449 i_relhasoids = PQfnumber(res, "relhasoids");
7450 i_relhastriggers = PQfnumber(res, "relhastriggers");
7451 i_relpersistence = PQfnumber(res, "relpersistence");
7452 i_relispopulated = PQfnumber(res, "relispopulated");
7453 i_relreplident = PQfnumber(res, "relreplident");
7454 i_relrowsec = PQfnumber(res, "relrowsecurity");
7455 i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
7456 i_relfrozenxid = PQfnumber(res, "relfrozenxid");
7457 i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
7458 i_toastoid = PQfnumber(res, "toid");
7459 i_relminmxid = PQfnumber(res, "relminmxid");
7460 i_toastminmxid = PQfnumber(res, "tminmxid");
7461 i_reloptions = PQfnumber(res, "reloptions");
7462 i_checkoption = PQfnumber(res, "checkoption");
7463 i_toastreloptions = PQfnumber(res, "toast_reloptions");
7464 i_reloftype = PQfnumber(res, "reloftype");
7465 i_foreignserver = PQfnumber(res, "foreignserver");
7466 i_amname = PQfnumber(res, "amname");
7467 i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
7468 i_relacl = PQfnumber(res, "relacl");
7469 i_acldefault = PQfnumber(res, "acldefault");
7470 i_ispartition = PQfnumber(res, "ispartition");
7471
7472 if (dopt->lockWaitTimeout)
7473 {
7474 /*
7475 * Arrange to fail instead of waiting forever for a table lock.
7476 *
7477 * NB: this coding assumes that the only queries issued within the
7478 * following loop are LOCK TABLEs; else the timeout may be undesirably
7479 * applied to other things too.
7480 */
7481 resetPQExpBuffer(query);
7482 appendPQExpBufferStr(query, "SET statement_timeout = ");
7484 ExecuteSqlStatement(fout, query->data);
7485 }
7486
7487 resetPQExpBuffer(query);
7488
7489 for (i = 0; i < ntups; i++)
7490 {
7491 int32 relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
7492 int32 relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
7493
7494 tblinfo[i].dobj.objType = DO_TABLE;
7495 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
7496 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
7497 AssignDumpId(&tblinfo[i].dobj);
7498 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
7499 tblinfo[i].dobj.namespace =
7501 tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
7502 tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
7503 tblinfo[i].dacl.privtype = 0;
7504 tblinfo[i].dacl.initprivs = NULL;
7505 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
7506 tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
7507 tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
7508 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
7509 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
7510 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
7511 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
7512 if (PQgetisnull(res, i, i_toastpages))
7513 tblinfo[i].toastpages = 0;
7514 else
7515 tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
7516 if (PQgetisnull(res, i, i_owning_tab))
7517 {
7518 tblinfo[i].owning_tab = InvalidOid;
7519 tblinfo[i].owning_col = 0;
7520 }
7521 else
7522 {
7523 tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
7524 tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
7525 }
7527 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
7528 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
7529 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
7530 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
7531 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
7532 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
7533 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
7534 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
7536 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
7537 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
7538 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
7539 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
7540 if (PQgetisnull(res, i, i_checkoption))
7541 tblinfo[i].checkoption = NULL;
7542 else
7543 tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
7545 tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
7547 if (PQgetisnull(res, i, i_amname))
7548 tblinfo[i].amname = NULL;
7549 else
7550 tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
7551 tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
7552 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
7553
7554 /* other fields were zeroed above */
7555
7556 /*
7557 * Decide whether we want to dump this table.
7558 */
7559 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
7560 tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
7561 else
7562 selectDumpableTable(&tblinfo[i], fout);
7563
7564 /*
7565 * Now, consider the table "interesting" if we need to dump its
7566 * definition, data or its statistics. Later on, we'll skip a lot of
7567 * data collection for uninteresting tables.
7568 *
7569 * Note: the "interesting" flag will also be set by flagInhTables for
7570 * parents of interesting tables, so that we collect necessary
7571 * inheritance info even when the parents are not themselves being
7572 * dumped. This is the main reason why we need an "interesting" flag
7573 * that's separate from the components-to-dump bitmask.
7574 */
7575 tblinfo[i].interesting = (tblinfo[i].dobj.dump &
7579
7580 tblinfo[i].dummy_view = false; /* might get set during sort */
7581 tblinfo[i].postponed_def = false; /* might get set during sort */
7582
7583 /* Tables have data */
7585
7586 /* Mark whether table has an ACL */
7587 if (!PQgetisnull(res, i, i_relacl))
7588 tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
7589 tblinfo[i].hascolumnACLs = false; /* may get set later */
7590
7591 /* Add statistics */
7592 if (tblinfo[i].interesting)
7593 {
7594 RelStatsInfo *stats;
7595
7596 stats = getRelationStatistics(fout, &tblinfo[i].dobj,
7597 tblinfo[i].relpages,
7598 PQgetvalue(res, i, i_reltuples),
7599 relallvisible, relallfrozen,
7600 tblinfo[i].relkind, NULL, 0);
7601 if (tblinfo[i].relkind == RELKIND_MATVIEW)
7602 tblinfo[i].stats = stats;
7603 }
7604
7605 /*
7606 * Read-lock target tables to make sure they aren't DROPPED or altered
7607 * in schema before we get around to dumping them.
7608 *
7609 * Note that we don't explicitly lock parents of the target tables; we
7610 * assume our lock on the child is enough to prevent schema
7611 * alterations to parent tables.
7612 *
7613 * NOTE: it'd be kinda nice to lock other relations too, not only
7614 * plain or partitioned tables, but the backend doesn't presently
7615 * allow that.
7616 *
7617 * We only need to lock the table for certain components; see
7618 * pg_dump.h
7619 */
7620 if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
7621 (tblinfo[i].relkind == RELKIND_RELATION ||
7622 tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
7623 {
7624 /*
7625 * Tables are locked in batches. When dumping from a remote
7626 * server this can save a significant amount of time by reducing
7627 * the number of round trips.
7628 */
7629 if (query->len == 0)
7630 appendPQExpBuffer(query, "LOCK TABLE %s",
7631 fmtQualifiedDumpable(&tblinfo[i]));
7632 else
7633 {
7634 appendPQExpBuffer(query, ", %s",
7635 fmtQualifiedDumpable(&tblinfo[i]));
7636
7637 /* Arbitrarily end a batch when query length reaches 100K. */
7638 if (query->len >= 100000)
7639 {
7640 /* Lock another batch of tables. */
7641 appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7642 ExecuteSqlStatement(fout, query->data);
7643 resetPQExpBuffer(query);
7644 }
7645 }
7646 }
7647 }
7648
7649 if (query->len != 0)
7650 {
7651 /* Lock the tables in the last batch. */
7652 appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7653 ExecuteSqlStatement(fout, query->data);
7654 }
7655
7656 if (dopt->lockWaitTimeout)
7657 {
7658 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
7659 }
7660
7661 PQclear(res);
7662
7663 destroyPQExpBuffer(query);
7664
7665 return tblinfo;
7666}

References _dumpableAcl::acl, _dumpableAcl::acldefault, _tableInfo::amname, appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralConn(), AssignDumpId(), atooid, _dumpableObject::catId, _tableInfo::checkoption, _dumpableObject::components, CppAsString2, createPQExpBuffer(), _tableInfo::dacl, PQExpBufferData::data, destroyPQExpBuffer(), DO_TABLE, _tableInfo::dobj, _tableInfo::dummy_view, _dumpableObject::dump, DUMP_COMPONENT_ACL, DUMP_COMPONENT_DATA, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_NONE, DUMP_COMPONENT_STATISTICS, DUMP_COMPONENTS_REQUIRING_LOCK, ExecuteSqlQuery(), ExecuteSqlStatement(), fb(), findNamespace(), fmtQualifiedDumpable, _tableInfo::forcerowsec, _tableInfo::foreign_server, _tableInfo::frozenxid, GetConnection(), getRelationStatistics(), getRoleName(), _tableInfo::hascolumnACLs, _tableInfo::hasindex, _tableInfo::hasoids, _tableInfo::hasrules, _tableInfo::hastriggers, i, _dumpableAcl::initprivs, _tableInfo::interesting, InvalidOid, _tableInfo::is_identity_sequence, _tableInfo::ispartition, PQExpBufferData::len, _dumpOptions::lockWaitTimeout, _tableInfo::minmxid, _dumpableObject::name, _tableInfo::ncheck, _dumpableObject::objType, CatalogId::oid, _tableInfo::owning_col, _tableInfo::owning_tab, pg_malloc0(), pg_strdup(), PGRES_TUPLES_OK, _tableInfo::postponed_def, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, _dumpableAcl::privtype, _tableInfo::relispopulated, _tableInfo::relkind, _tableInfo::reloftype, _tableInfo::reloptions, _tableInfo::relpages, _tableInfo::relpersistence, _tableInfo::relreplident, _tableInfo::reltablespace, _tableInfo::reltype, resetPQExpBuffer(), _tableInfo::rolname, _tableInfo::rowsec, selectDumpableTable(), _tableInfo::stats, CatalogId::tableoid, _tableInfo::toast_frozenxid, _tableInfo::toast_minmxid, _tableInfo::toast_oid, _tableInfo::toast_reloptions, and _tableInfo::toastpages.

Referenced by getSchemaData().

◆ getTransforms()

void getTransforms ( Archive fout)

Definition at line 9167 of file pg_dump.c.

9168{
9169 PGresult *res;
9170 int ntups;
9171 int i;
9172 PQExpBuffer query;
9174 int i_tableoid;
9175 int i_oid;
9176 int i_trftype;
9177 int i_trflang;
9178 int i_trffromsql;
9179 int i_trftosql;
9180
9181 /* Transforms didn't exist pre-9.5 */
9182 if (fout->remoteVersion < 90500)
9183 return;
9184
9185 query = createPQExpBuffer();
9186
9187 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9188 "trftype, trflang, trffromsql::oid, trftosql::oid "
9189 "FROM pg_transform "
9190 "ORDER BY 3,4");
9191
9192 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9193
9194 ntups = PQntuples(res);
9195
9196 transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
9197
9198 i_tableoid = PQfnumber(res, "tableoid");
9199 i_oid = PQfnumber(res, "oid");
9200 i_trftype = PQfnumber(res, "trftype");
9201 i_trflang = PQfnumber(res, "trflang");
9202 i_trffromsql = PQfnumber(res, "trffromsql");
9203 i_trftosql = PQfnumber(res, "trftosql");
9204
9205 for (i = 0; i < ntups; i++)
9206 {
9209 char *lanname;
9210
9212 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9213 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9215 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
9216 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
9217 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
9218 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
9219
9220 /*
9221 * Try to name transform as concatenation of type and language name.
9222 * This is only used for purposes of sorting. If we fail to find
9223 * either, the name will be an empty string.
9224 */
9228 if (typeInfo && lanname)
9229 appendPQExpBuffer(&namebuf, "%s %s",
9230 typeInfo->dobj.name, lanname);
9231 transforminfo[i].dobj.name = namebuf.data;
9232 free(lanname);
9233
9234 /* Decide whether we want to dump it */
9236 }
9237
9238 PQclear(res);
9239
9240 destroyPQExpBuffer(query);
9241}

References appendPQExpBuffer(), appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_TRANSFORM, _typeInfo::dobj, ExecuteSqlQuery(), fb(), findTypeByOid(), free, get_language_name(), i, initPQExpBuffer(), _dumpableObject::objType, pg_malloc(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getTriggers()

void getTriggers ( Archive fout,
TableInfo  tblinfo[],
int  numTables 
)

Definition at line 8699 of file pg_dump.c.

8700{
8703 PGresult *res;
8704 int ntups;
8705 int curtblindx;
8707 int i_tableoid,
8708 i_oid,
8709 i_tgrelid,
8710 i_tgname,
8713 i_tgdef;
8714
8715 /*
8716 * We want to perform just one query against pg_trigger. However, we
8717 * mustn't try to select every row of the catalog and then sort it out on
8718 * the client side, because some of the server-side functions we need
8719 * would be unsafe to apply to tables we don't have lock on. Hence, we
8720 * build an array of the OIDs of tables we care about (and now have lock
8721 * on!), and use a WHERE clause to constrain which rows are selected.
8722 */
8724 for (int i = 0; i < numTables; i++)
8725 {
8726 TableInfo *tbinfo = &tblinfo[i];
8727
8728 if (!tbinfo->hastriggers ||
8729 !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
8730 continue;
8731
8732 /* OK, we need info for this table */
8733 if (tbloids->len > 1) /* do we have more than the '{'? */
8735 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8736 }
8738
8739 if (fout->remoteVersion >= 150000)
8740 {
8741 /*
8742 * NB: think not to use pretty=true in pg_get_triggerdef. It could
8743 * result in non-forward-compatible dumps of WHEN clauses due to
8744 * under-parenthesization.
8745 *
8746 * NB: We need to see partition triggers in case the tgenabled flag
8747 * has been changed from the parent.
8748 */
8749 appendPQExpBuffer(query,
8750 "SELECT t.tgrelid, t.tgname, "
8751 "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8752 "t.tgenabled, t.tableoid, t.oid, "
8753 "t.tgparentid <> 0 AS tgispartition\n"
8754 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8755 "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8756 "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8757 "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
8758 "OR t.tgenabled != u.tgenabled) "
8759 "ORDER BY t.tgrelid, t.tgname",
8760 tbloids->data);
8761 }
8762 else if (fout->remoteVersion >= 130000)
8763 {
8764 /*
8765 * NB: think not to use pretty=true in pg_get_triggerdef. It could
8766 * result in non-forward-compatible dumps of WHEN clauses due to
8767 * under-parenthesization.
8768 *
8769 * NB: We need to see tgisinternal triggers in partitions, in case the
8770 * tgenabled flag has been changed from the parent.
8771 */
8772 appendPQExpBuffer(query,
8773 "SELECT t.tgrelid, t.tgname, "
8774 "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8775 "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
8776 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8777 "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8778 "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8779 "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
8780 "ORDER BY t.tgrelid, t.tgname",
8781 tbloids->data);
8782 }
8783 else if (fout->remoteVersion >= 110000)
8784 {
8785 /*
8786 * NB: We need to see tgisinternal triggers in partitions, in case the
8787 * tgenabled flag has been changed from the parent. No tgparentid in
8788 * version 11-12, so we have to match them via pg_depend.
8789 *
8790 * See above about pretty=true in pg_get_triggerdef.
8791 */
8792 appendPQExpBuffer(query,
8793 "SELECT t.tgrelid, t.tgname, "
8794 "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8795 "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
8796 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8797 "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8798 "LEFT JOIN pg_catalog.pg_depend AS d ON "
8799 " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8800 " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8801 " d.objid = t.oid "
8802 "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
8803 "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
8804 "ORDER BY t.tgrelid, t.tgname",
8805 tbloids->data);
8806 }
8807 else
8808 {
8809 /* See above about pretty=true in pg_get_triggerdef */
8810 appendPQExpBuffer(query,
8811 "SELECT t.tgrelid, t.tgname, "
8812 "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8813 "t.tgenabled, false as tgispartition, "
8814 "t.tableoid, t.oid "
8815 "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8816 "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8817 "WHERE NOT tgisinternal "
8818 "ORDER BY t.tgrelid, t.tgname",
8819 tbloids->data);
8820 }
8821
8822 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8823
8824 ntups = PQntuples(res);
8825
8826 i_tableoid = PQfnumber(res, "tableoid");
8827 i_oid = PQfnumber(res, "oid");
8828 i_tgrelid = PQfnumber(res, "tgrelid");
8829 i_tgname = PQfnumber(res, "tgname");
8830 i_tgenabled = PQfnumber(res, "tgenabled");
8831 i_tgispartition = PQfnumber(res, "tgispartition");
8832 i_tgdef = PQfnumber(res, "tgdef");
8833
8834 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
8835
8836 /*
8837 * Outer loop iterates once per table, not once per row. Incrementing of
8838 * j is handled by the inner loop.
8839 */
8840 curtblindx = -1;
8841 for (int j = 0; j < ntups;)
8842 {
8845 int numtrigs;
8846
8847 /* Count rows for this table */
8848 for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
8849 if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
8850 break;
8851
8852 /*
8853 * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8854 * order.
8855 */
8856 while (++curtblindx < numTables)
8857 {
8858 tbinfo = &tblinfo[curtblindx];
8859 if (tbinfo->dobj.catId.oid == tgrelid)
8860 break;
8861 }
8862 if (curtblindx >= numTables)
8863 pg_fatal("unrecognized table OID %u", tgrelid);
8864
8865 /* Save data for this table */
8866 tbinfo->triggers = tginfo + j;
8867 tbinfo->numTriggers = numtrigs;
8868
8869 for (int c = 0; c < numtrigs; c++, j++)
8870 {
8871 tginfo[j].dobj.objType = DO_TRIGGER;
8872 tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8873 tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8874 AssignDumpId(&tginfo[j].dobj);
8875 tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
8876 tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
8877 tginfo[j].tgtable = tbinfo;
8878 tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
8879 tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
8880 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
8881 }
8882 }
8883
8884 PQclear(res);
8885
8886 destroyPQExpBuffer(query);
8888}

References appendPQExpBuffer(), appendPQExpBufferChar(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_TRIGGER, DUMP_COMPONENT_DEFINITION, ExecuteSqlQuery(), fb(), i, j, pg_fatal, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, and PQntuples.

Referenced by getSchemaData().

◆ getTSConfigurations()

void getTSConfigurations ( Archive fout)

Definition at line 10369 of file pg_dump.c.

10370{
10371 PGresult *res;
10372 int ntups;
10373 int i;
10374 PQExpBuffer query;
10376 int i_tableoid;
10377 int i_oid;
10378 int i_cfgname;
10379 int i_cfgnamespace;
10380 int i_cfgowner;
10381 int i_cfgparser;
10382
10383 query = createPQExpBuffer();
10384
10385 appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
10386 "cfgnamespace, cfgowner, cfgparser "
10387 "FROM pg_ts_config");
10388
10389 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10390
10391 ntups = PQntuples(res);
10392
10393 cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
10394
10395 i_tableoid = PQfnumber(res, "tableoid");
10396 i_oid = PQfnumber(res, "oid");
10397 i_cfgname = PQfnumber(res, "cfgname");
10398 i_cfgnamespace = PQfnumber(res, "cfgnamespace");
10399 i_cfgowner = PQfnumber(res, "cfgowner");
10400 i_cfgparser = PQfnumber(res, "cfgparser");
10401
10402 for (i = 0; i < ntups; i++)
10403 {
10404 cfginfo[i].dobj.objType = DO_TSCONFIG;
10405 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10406 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10407 AssignDumpId(&cfginfo[i].dobj);
10408 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
10409 cfginfo[i].dobj.namespace =
10411 cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
10412 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
10413
10414 /* Decide whether we want to dump it */
10416 }
10417
10418 PQclear(res);
10419
10420 destroyPQExpBuffer(query);
10421}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_TSCONFIG, ExecuteSqlQuery(), fb(), findNamespace(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getTSDictionaries()

void getTSDictionaries ( Archive fout)

Definition at line 10244 of file pg_dump.c.

10245{
10246 PGresult *res;
10247 int ntups;
10248 int i;
10249 PQExpBuffer query;
10251 int i_tableoid;
10252 int i_oid;
10253 int i_dictname;
10254 int i_dictnamespace;
10255 int i_dictowner;
10256 int i_dicttemplate;
10257 int i_dictinitoption;
10258
10259 query = createPQExpBuffer();
10260
10261 appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
10262 "dictnamespace, dictowner, "
10263 "dicttemplate, dictinitoption "
10264 "FROM pg_ts_dict");
10265
10266 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10267
10268 ntups = PQntuples(res);
10269
10270 dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
10271
10272 i_tableoid = PQfnumber(res, "tableoid");
10273 i_oid = PQfnumber(res, "oid");
10274 i_dictname = PQfnumber(res, "dictname");
10275 i_dictnamespace = PQfnumber(res, "dictnamespace");
10276 i_dictowner = PQfnumber(res, "dictowner");
10277 i_dictinitoption = PQfnumber(res, "dictinitoption");
10278 i_dicttemplate = PQfnumber(res, "dicttemplate");
10279
10280 for (i = 0; i < ntups; i++)
10281 {
10282 dictinfo[i].dobj.objType = DO_TSDICT;
10283 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10284 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10285 AssignDumpId(&dictinfo[i].dobj);
10286 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
10287 dictinfo[i].dobj.namespace =
10289 dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
10290 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
10291 if (PQgetisnull(res, i, i_dictinitoption))
10292 dictinfo[i].dictinitoption = NULL;
10293 else
10294 dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
10295
10296 /* Decide whether we want to dump it */
10298 }
10299
10300 PQclear(res);
10301
10302 destroyPQExpBuffer(query);
10303}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_TSDICT, ExecuteSqlQuery(), fb(), findNamespace(), getRoleName(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getTSParsers()

void getTSParsers ( Archive fout)

Definition at line 10170 of file pg_dump.c.

10171{
10172 PGresult *res;
10173 int ntups;
10174 int i;
10175 PQExpBuffer query;
10177 int i_tableoid;
10178 int i_oid;
10179 int i_prsname;
10180 int i_prsnamespace;
10181 int i_prsstart;
10182 int i_prstoken;
10183 int i_prsend;
10184 int i_prsheadline;
10185 int i_prslextype;
10186
10187 query = createPQExpBuffer();
10188
10189 /*
10190 * find all text search objects, including builtin ones; we filter out
10191 * system-defined objects at dump-out time.
10192 */
10193
10194 appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
10195 "prsstart::oid, prstoken::oid, "
10196 "prsend::oid, prsheadline::oid, prslextype::oid "
10197 "FROM pg_ts_parser");
10198
10199 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10200
10201 ntups = PQntuples(res);
10202
10203 prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
10204
10205 i_tableoid = PQfnumber(res, "tableoid");
10206 i_oid = PQfnumber(res, "oid");
10207 i_prsname = PQfnumber(res, "prsname");
10208 i_prsnamespace = PQfnumber(res, "prsnamespace");
10209 i_prsstart = PQfnumber(res, "prsstart");
10210 i_prstoken = PQfnumber(res, "prstoken");
10211 i_prsend = PQfnumber(res, "prsend");
10212 i_prsheadline = PQfnumber(res, "prsheadline");
10213 i_prslextype = PQfnumber(res, "prslextype");
10214
10215 for (i = 0; i < ntups; i++)
10216 {
10217 prsinfo[i].dobj.objType = DO_TSPARSER;
10218 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10219 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10220 AssignDumpId(&prsinfo[i].dobj);
10221 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
10222 prsinfo[i].dobj.namespace =
10224 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
10225 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
10226 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
10227 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
10228 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
10229
10230 /* Decide whether we want to dump it */
10232 }
10233
10234 PQclear(res);
10235
10236 destroyPQExpBuffer(query);
10237}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_TSPARSER, ExecuteSqlQuery(), fb(), findNamespace(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getTSTemplates()

void getTSTemplates ( Archive fout)

Definition at line 10310 of file pg_dump.c.

10311{
10312 PGresult *res;
10313 int ntups;
10314 int i;
10315 PQExpBuffer query;
10317 int i_tableoid;
10318 int i_oid;
10319 int i_tmplname;
10320 int i_tmplnamespace;
10321 int i_tmplinit;
10322 int i_tmpllexize;
10323
10324 query = createPQExpBuffer();
10325
10326 appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
10327 "tmplnamespace, tmplinit::oid, tmpllexize::oid "
10328 "FROM pg_ts_template");
10329
10330 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10331
10332 ntups = PQntuples(res);
10333
10334 tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
10335
10336 i_tableoid = PQfnumber(res, "tableoid");
10337 i_oid = PQfnumber(res, "oid");
10338 i_tmplname = PQfnumber(res, "tmplname");
10339 i_tmplnamespace = PQfnumber(res, "tmplnamespace");
10340 i_tmplinit = PQfnumber(res, "tmplinit");
10341 i_tmpllexize = PQfnumber(res, "tmpllexize");
10342
10343 for (i = 0; i < ntups; i++)
10344 {
10345 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
10346 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10347 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10348 AssignDumpId(&tmplinfo[i].dobj);
10349 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
10350 tmplinfo[i].dobj.namespace =
10352 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
10353 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
10354
10355 /* Decide whether we want to dump it */
10357 }
10358
10359 PQclear(res);
10360
10361 destroyPQExpBuffer(query);
10362}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_TSTEMPLATE, ExecuteSqlQuery(), fb(), findNamespace(), i, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, and selectDumpableObject().

Referenced by getSchemaData().

◆ getTypes()

void getTypes ( Archive fout)

Definition at line 6212 of file pg_dump.c.

6213{
6214 PGresult *res;
6215 int ntups;
6216 int i;
6220 int i_tableoid;
6221 int i_oid;
6222 int i_typname;
6223 int i_typnamespace;
6224 int i_typacl;
6225 int i_acldefault;
6226 int i_typowner;
6227 int i_typelem;
6228 int i_typrelid;
6229 int i_typrelkind;
6230 int i_typtype;
6231 int i_typisdefined;
6232 int i_isarray;
6233 int i_typarray;
6234
6235 /*
6236 * we include even the built-in types because those may be used as array
6237 * elements by user-defined types
6238 *
6239 * we filter out the built-in types when we dump out the types
6240 *
6241 * same approach for undefined (shell) types and array types
6242 *
6243 * Note: as of 8.3 we can reliably detect whether a type is an
6244 * auto-generated array type by checking the element type's typarray.
6245 * (Before that the test is capable of generating false positives.) We
6246 * still check for name beginning with '_', though, so as to avoid the
6247 * cost of the subselect probe for all standard types. This would have to
6248 * be revisited if the backend ever allows renaming of array types.
6249 */
6250 appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
6251 "typnamespace, typacl, "
6252 "acldefault('T', typowner) AS acldefault, "
6253 "typowner, "
6254 "typelem, typrelid, typarray, "
6255 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
6256 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
6257 "typtype, typisdefined, "
6258 "typname[0] = '_' AND typelem != 0 AND "
6259 "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
6260 "FROM pg_type");
6261
6262 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6263
6264 ntups = PQntuples(res);
6265
6266 tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
6267
6268 i_tableoid = PQfnumber(res, "tableoid");
6269 i_oid = PQfnumber(res, "oid");
6270 i_typname = PQfnumber(res, "typname");
6271 i_typnamespace = PQfnumber(res, "typnamespace");
6272 i_typacl = PQfnumber(res, "typacl");
6273 i_acldefault = PQfnumber(res, "acldefault");
6274 i_typowner = PQfnumber(res, "typowner");
6275 i_typelem = PQfnumber(res, "typelem");
6276 i_typrelid = PQfnumber(res, "typrelid");
6277 i_typrelkind = PQfnumber(res, "typrelkind");
6278 i_typtype = PQfnumber(res, "typtype");
6279 i_typisdefined = PQfnumber(res, "typisdefined");
6280 i_isarray = PQfnumber(res, "isarray");
6281 i_typarray = PQfnumber(res, "typarray");
6282
6283 for (i = 0; i < ntups; i++)
6284 {
6285 tyinfo[i].dobj.objType = DO_TYPE;
6286 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6287 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6288 AssignDumpId(&tyinfo[i].dobj);
6289 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
6290 tyinfo[i].dobj.namespace =
6292 tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
6293 tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6294 tyinfo[i].dacl.privtype = 0;
6295 tyinfo[i].dacl.initprivs = NULL;
6296 tyinfo[i].ftypname = NULL; /* may get filled later */
6297 tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
6298 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
6299 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
6300 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
6301 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
6302 tyinfo[i].shellType = NULL;
6303
6304 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
6305 tyinfo[i].isDefined = true;
6306 else
6307 tyinfo[i].isDefined = false;
6308
6309 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
6310 tyinfo[i].isArray = true;
6311 else
6312 tyinfo[i].isArray = false;
6313
6314 tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
6315
6316 if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
6317 tyinfo[i].isMultirange = true;
6318 else
6319 tyinfo[i].isMultirange = false;
6320
6321 /* Decide whether we want to dump it */
6323
6324 /* Mark whether type has an ACL */
6325 if (!PQgetisnull(res, i, i_typacl))
6326 tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6327
6328 /*
6329 * If it's a domain, fetch info about its constraints, if any
6330 */
6331 tyinfo[i].nDomChecks = 0;
6332 tyinfo[i].domChecks = NULL;
6333 tyinfo[i].notnull = NULL;
6334 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6335 tyinfo[i].typtype == TYPTYPE_DOMAIN)
6337
6338 /*
6339 * If it's a base type, make a DumpableObject representing a shell
6340 * definition of the type. We will need to dump that ahead of the I/O
6341 * functions for the type. Similarly, range types need a shell
6342 * definition in case they have a canonicalize function.
6343 *
6344 * Note: the shell type doesn't have a catId. You might think it
6345 * should copy the base type's catId, but then it might capture the
6346 * pg_depend entries for the type, which we don't want.
6347 */
6348 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6349 (tyinfo[i].typtype == TYPTYPE_BASE ||
6350 tyinfo[i].typtype == TYPTYPE_RANGE))
6351 {
6353 stinfo->dobj.objType = DO_SHELL_TYPE;
6354 stinfo->dobj.catId = nilCatalogId;
6355 AssignDumpId(&stinfo->dobj);
6356 stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
6357 stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
6358 stinfo->baseType = &(tyinfo[i]);
6359 tyinfo[i].shellType = stinfo;
6360
6361 /*
6362 * Initially mark the shell type as not to be dumped. We'll only
6363 * dump it if the I/O or canonicalize functions need to be dumped;
6364 * this is taken care of while sorting dependencies.
6365 */
6366 stinfo->dobj.dump = DUMP_COMPONENT_NONE;
6367 }
6368 }
6369
6370 PQclear(res);
6371
6372 destroyPQExpBuffer(query);
6373}

References appendPQExpBufferStr(), AssignDumpId(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DO_SHELL_TYPE, DO_TYPE, DUMP_COMPONENT_ACL, DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_NONE, ExecuteSqlQuery(), fb(), findNamespace(), getDomainConstraints(), getRoleName(), i, nilCatalogId, pg_malloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetisnull, PQgetvalue, PQntuples, and selectDumpableType().

Referenced by getSchemaData().

◆ help()

static void help ( const char progname)
static

Definition at line 1321 of file pg_dump.c.

1322{
1323 printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
1324 printf(_("Usage:\n"));
1325 printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
1326
1327 printf(_("\nGeneral options:\n"));
1328 printf(_(" -f, --file=FILENAME output file or directory name\n"));
1329 printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
1330 " plain text (default))\n"));
1331 printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
1332 printf(_(" -v, --verbose verbose mode\n"));
1333 printf(_(" -V, --version output version information, then exit\n"));
1334 printf(_(" -Z, --compress=METHOD[:DETAIL]\n"
1335 " compress as specified\n"));
1336 printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
1337 printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
1338 printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
1339 printf(_(" -?, --help show this help, then exit\n"));
1340
1341 printf(_("\nOptions controlling the output content:\n"));
1342 printf(_(" -a, --data-only dump only the data, not the schema or statistics\n"));
1343 printf(_(" -b, --large-objects include large objects in dump\n"));
1344 printf(_(" --blobs (same as --large-objects, deprecated)\n"));
1345 printf(_(" -B, --no-large-objects exclude large objects in dump\n"));
1346 printf(_(" --no-blobs (same as --no-large-objects, deprecated)\n"));
1347 printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
1348 printf(_(" -C, --create include commands to create database in dump\n"));
1349 printf(_(" -e, --extension=PATTERN dump the specified extension(s) only\n"));
1350 printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
1351 printf(_(" -n, --schema=PATTERN dump the specified schema(s) only\n"));
1352 printf(_(" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
1353 printf(_(" -O, --no-owner skip restoration of object ownership in\n"
1354 " plain-text format\n"));
1355 printf(_(" -s, --schema-only dump only the schema, no data or statistics\n"));
1356 printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
1357 printf(_(" -t, --table=PATTERN dump only the specified table(s)\n"));
1358 printf(_(" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n"));
1359 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
1360 printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
1361 printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
1362 printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
1363 printf(_(" --disable-triggers disable triggers during data-only restore\n"));
1364 printf(_(" --enable-row-security enable row security (dump only content user has\n"
1365 " access to)\n"));
1366 printf(_(" --exclude-extension=PATTERN do NOT dump the specified extension(s)\n"));
1367 printf(_(" --exclude-table-and-children=PATTERN\n"
1368 " do NOT dump the specified table(s), including\n"
1369 " child and partition tables\n"));
1370 printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
1371 printf(_(" --exclude-table-data-and-children=PATTERN\n"
1372 " do NOT dump data for the specified table(s),\n"
1373 " including child and partition tables\n"));
1374 printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
1375 printf(_(" --filter=FILENAME include or exclude objects and data from dump\n"
1376 " based on expressions in FILENAME\n"));
1377 printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
1378 printf(_(" --include-foreign-data=PATTERN\n"
1379 " include data of foreign tables on foreign\n"
1380 " servers matching PATTERN\n"));
1381 printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
1382 printf(_(" --load-via-partition-root load partitions via the root table\n"));
1383 printf(_(" --no-comments do not dump comment commands\n"));
1384 printf(_(" --no-data do not dump data\n"));
1385 printf(_(" --no-policies do not dump row security policies\n"));
1386 printf(_(" --no-publications do not dump publications\n"));
1387 printf(_(" --no-schema do not dump schema\n"));
1388 printf(_(" --no-security-labels do not dump security label assignments\n"));
1389 printf(_(" --no-statistics do not dump statistics\n"));
1390 printf(_(" --no-subscriptions do not dump subscriptions\n"));
1391 printf(_(" --no-table-access-method do not dump table access methods\n"));
1392 printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
1393 printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
1394 printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
1395 printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
1396 printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
1397 printf(_(" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n"));
1398 printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
1399 printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
1400 printf(_(" --sequence-data include sequence data in dump\n"));
1401 printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
1402 printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
1403 printf(_(" --statistics dump the statistics\n"));
1404 printf(_(" --statistics-only dump only the statistics, not schema or data\n"));
1405 printf(_(" --strict-names require table and/or schema include patterns to\n"
1406 " match at least one entity each\n"));
1407 printf(_(" --table-and-children=PATTERN dump only the specified table(s), including\n"
1408 " child and partition tables\n"));
1409 printf(_(" --use-set-session-authorization\n"
1410 " use SET SESSION AUTHORIZATION commands instead of\n"
1411 " ALTER OWNER commands to set ownership\n"));
1412
1413 printf(_("\nConnection options:\n"));
1414 printf(_(" -d, --dbname=DBNAME database to dump\n"));
1415 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
1416 printf(_(" -p, --port=PORT database server port number\n"));
1417 printf(_(" -U, --username=NAME connect as specified database user\n"));
1418 printf(_(" -w, --no-password never prompt for password\n"));
1419 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
1420 printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
1421
1422 printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1423 "variable value is used.\n\n"));
1424 printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1425 printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
1426}

References _, fb(), printf, and progname.

◆ is_superuser()

static bool is_superuser ( Archive fout)
static

Definition at line 5081 of file pg_dump.c.

5082{
5084 const char *val;
5085
5086 val = PQparameterStatus(AH->connection, "is_superuser");
5087
5088 if (val && strcmp(val, "on") == 0)
5089 return true;
5090
5091 return false;
5092}

References _archiveHandle::connection, fb(), PQparameterStatus(), and val.

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 424 of file pg_dump.c.

425{
426 int c;
427 const char *filename = NULL;
428 const char *format = "p";
429 TableInfo *tblinfo;
430 int numTables;
432 int numObjs;
434 int i;
435 int optindex;
436 RestoreOptions *ropt;
437 Archive *fout; /* the script file */
438 bool g_verbose = false;
439 const char *dumpencoding = NULL;
440 const char *dumpsnapshot = NULL;
441 char *use_role = NULL;
442 int numWorkers = 1;
443 int plainText = 0;
446 pg_compress_specification compression_spec = {0};
447 char *compression_detail = NULL;
448 char *compression_algorithm_str = "none";
449 char *error_detail = NULL;
450 bool user_compression_defined = false;
452 bool data_only = false;
453 bool schema_only = false;
454 bool statistics_only = false;
455 bool with_statistics = false;
456 bool no_data = false;
457 bool no_schema = false;
458 bool no_statistics = false;
459
460 static DumpOptions dopt;
461
462 static struct option long_options[] = {
463 {"data-only", no_argument, NULL, 'a'},
464 {"blobs", no_argument, NULL, 'b'},
465 {"large-objects", no_argument, NULL, 'b'},
466 {"no-blobs", no_argument, NULL, 'B'},
467 {"no-large-objects", no_argument, NULL, 'B'},
468 {"clean", no_argument, NULL, 'c'},
469 {"create", no_argument, NULL, 'C'},
470 {"dbname", required_argument, NULL, 'd'},
471 {"extension", required_argument, NULL, 'e'},
472 {"file", required_argument, NULL, 'f'},
473 {"format", required_argument, NULL, 'F'},
474 {"host", required_argument, NULL, 'h'},
475 {"jobs", 1, NULL, 'j'},
476 {"no-reconnect", no_argument, NULL, 'R'},
477 {"no-owner", no_argument, NULL, 'O'},
478 {"port", required_argument, NULL, 'p'},
479 {"schema", required_argument, NULL, 'n'},
480 {"exclude-schema", required_argument, NULL, 'N'},
481 {"schema-only", no_argument, NULL, 's'},
482 {"superuser", required_argument, NULL, 'S'},
483 {"table", required_argument, NULL, 't'},
484 {"exclude-table", required_argument, NULL, 'T'},
485 {"no-password", no_argument, NULL, 'w'},
486 {"password", no_argument, NULL, 'W'},
487 {"username", required_argument, NULL, 'U'},
488 {"verbose", no_argument, NULL, 'v'},
489 {"no-privileges", no_argument, NULL, 'x'},
490 {"no-acl", no_argument, NULL, 'x'},
491 {"compress", required_argument, NULL, 'Z'},
492 {"encoding", required_argument, NULL, 'E'},
493 {"help", no_argument, NULL, '?'},
494 {"version", no_argument, NULL, 'V'},
495
496 /*
497 * the following options don't have an equivalent short option letter
498 */
499 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
500 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
501 {"column-inserts", no_argument, &dopt.column_inserts, 1},
502 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
503 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
504 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
505 {"exclude-table-data", required_argument, NULL, 4},
506 {"extra-float-digits", required_argument, NULL, 8},
507 {"if-exists", no_argument, &dopt.if_exists, 1},
508 {"inserts", no_argument, NULL, 9},
509 {"lock-wait-timeout", required_argument, NULL, 2},
510 {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
511 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
512 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
513 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
514 {"role", required_argument, NULL, 3},
515 {"section", required_argument, NULL, 5},
516 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
517 {"snapshot", required_argument, NULL, 6},
518 {"statistics", no_argument, NULL, 22},
519 {"statistics-only", no_argument, NULL, 18},
520 {"strict-names", no_argument, &strict_names, 1},
521 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
522 {"no-comments", no_argument, &dopt.no_comments, 1},
523 {"no-data", no_argument, NULL, 19},
524 {"no-policies", no_argument, &dopt.no_policies, 1},
525 {"no-publications", no_argument, &dopt.no_publications, 1},
526 {"no-schema", no_argument, NULL, 20},
527 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
528 {"no-statistics", no_argument, NULL, 21},
529 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
530 {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
531 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
532 {"no-sync", no_argument, NULL, 7},
533 {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
534 {"rows-per-insert", required_argument, NULL, 10},
535 {"include-foreign-data", required_argument, NULL, 11},
536 {"table-and-children", required_argument, NULL, 12},
537 {"exclude-table-and-children", required_argument, NULL, 13},
538 {"exclude-table-data-and-children", required_argument, NULL, 14},
539 {"sync-method", required_argument, NULL, 15},
540 {"filter", required_argument, NULL, 16},
541 {"exclude-extension", required_argument, NULL, 17},
542 {"sequence-data", no_argument, &dopt.sequence_data, 1},
543 {"restrict-key", required_argument, NULL, 25},
544
545 {NULL, 0, NULL, 0}
546 };
547
548 pg_logging_init(argv[0]);
550 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
551
552 /*
553 * Initialize what we need for parallel execution, especially for thread
554 * support on Windows.
555 */
557
558 progname = get_progname(argv[0]);
559
560 if (argc > 1)
561 {
562 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
563 {
564 help(progname);
565 exit_nicely(0);
566 }
567 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
568 {
569 puts("pg_dump (PostgreSQL) " PG_VERSION);
570 exit_nicely(0);
571 }
572 }
573
574 InitDumpOptions(&dopt);
575
576 while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
577 long_options, &optindex)) != -1)
578 {
579 switch (c)
580 {
581 case 'a': /* Dump data only */
582 data_only = true;
583 break;
584
585 case 'b': /* Dump LOs */
586 dopt.outputLOs = true;
587 break;
588
589 case 'B': /* Don't dump LOs */
590 dopt.dontOutputLOs = true;
591 break;
592
593 case 'c': /* clean (i.e., drop) schema prior to create */
594 dopt.outputClean = 1;
595 break;
596
597 case 'C': /* Create DB */
598 dopt.outputCreateDB = 1;
599 break;
600
601 case 'd': /* database name */
603 break;
604
605 case 'e': /* include extension(s) */
607 dopt.include_everything = false;
608 break;
609
610 case 'E': /* Dump encoding */
612 break;
613
614 case 'f':
616 break;
617
618 case 'F':
620 break;
621
622 case 'h': /* server host */
624 break;
625
626 case 'j': /* number of dump jobs */
627 if (!option_parse_int(optarg, "-j/--jobs", 1,
629 &numWorkers))
630 exit_nicely(1);
631 break;
632
633 case 'n': /* include schema(s) */
635 dopt.include_everything = false;
636 break;
637
638 case 'N': /* exclude schema(s) */
640 break;
641
642 case 'O': /* Don't reconnect to match owner */
643 dopt.outputNoOwner = 1;
644 break;
645
646 case 'p': /* server port */
648 break;
649
650 case 'R':
651 /* no-op, still accepted for backwards compatibility */
652 break;
653
654 case 's': /* dump schema only */
655 schema_only = true;
656 break;
657
658 case 'S': /* Username for superuser in plain text output */
660 break;
661
662 case 't': /* include table(s) */
664 dopt.include_everything = false;
665 break;
666
667 case 'T': /* exclude table(s) */
669 break;
670
671 case 'U':
673 break;
674
675 case 'v': /* verbose */
676 g_verbose = true;
678 break;
679
680 case 'w':
682 break;
683
684 case 'W':
686 break;
687
688 case 'x': /* skip ACL dump */
689 dopt.aclsSkip = true;
690 break;
691
692 case 'Z': /* Compression */
696 break;
697
698 case 0:
699 /* This covers the long options. */
700 break;
701
702 case 2: /* lock-wait-timeout */
704 break;
705
706 case 3: /* SET ROLE */
707 use_role = pg_strdup(optarg);
708 break;
709
710 case 4: /* exclude table(s) data */
712 break;
713
714 case 5: /* section */
716 break;
717
718 case 6: /* snapshot */
720 break;
721
722 case 7: /* no-sync */
723 dosync = false;
724 break;
725
726 case 8:
728 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
730 exit_nicely(1);
731 break;
732
733 case 9: /* inserts */
734
735 /*
736 * dump_inserts also stores --rows-per-insert, careful not to
737 * overwrite that.
738 */
739 if (dopt.dump_inserts == 0)
741 break;
742
743 case 10: /* rows per insert */
744 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
745 &dopt.dump_inserts))
746 exit_nicely(1);
747 break;
748
749 case 11: /* include foreign data */
751 optarg);
752 break;
753
754 case 12: /* include table(s) and their children */
756 optarg);
757 dopt.include_everything = false;
758 break;
759
760 case 13: /* exclude table(s) and their children */
762 optarg);
763 break;
764
765 case 14: /* exclude data of table(s) and children */
767 optarg);
768 break;
769
770 case 15:
772 exit_nicely(1);
773 break;
774
775 case 16: /* read object filters from file */
777 break;
778
779 case 17: /* exclude extension(s) */
781 optarg);
782 break;
783
784 case 18:
785 statistics_only = true;
786 break;
787
788 case 19:
789 no_data = true;
790 break;
791
792 case 20:
793 no_schema = true;
794 break;
795
796 case 21:
797 no_statistics = true;
798 break;
799
800 case 22:
801 with_statistics = true;
802 break;
803
804 case 25:
806 break;
807
808 default:
809 /* getopt_long already emitted a complaint */
810 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
811 exit_nicely(1);
812 }
813 }
814
815 /*
816 * Non-option argument specifies database name as long as it wasn't
817 * already specified with -d / --dbname
818 */
819 if (optind < argc && dopt.cparams.dbname == NULL)
820 dopt.cparams.dbname = argv[optind++];
821
822 /* Complain if any arguments remain */
823 if (optind < argc)
824 {
825 pg_log_error("too many command-line arguments (first is \"%s\")",
826 argv[optind]);
827 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
828 exit_nicely(1);
829 }
830
831 /* --column-inserts implies --inserts */
832 if (dopt.column_inserts && dopt.dump_inserts == 0)
834
835 /* reject conflicting "-only" options */
836 if (data_only && schema_only)
837 pg_fatal("options %s and %s cannot be used together",
838 "-s/--schema-only", "-a/--data-only");
840 pg_fatal("options %s and %s cannot be used together",
841 "-s/--schema-only", "--statistics-only");
843 pg_fatal("options %s and %s cannot be used together",
844 "-a/--data-only", "--statistics-only");
845
846 /* reject conflicting "-only" and "no-" options */
847 if (data_only && no_data)
848 pg_fatal("options %s and %s cannot be used together",
849 "-a/--data-only", "--no-data");
850 if (schema_only && no_schema)
851 pg_fatal("options %s and %s cannot be used together",
852 "-s/--schema-only", "--no-schema");
854 pg_fatal("options %s and %s cannot be used together",
855 "--statistics-only", "--no-statistics");
856
857 /* reject conflicting "no-" options */
859 pg_fatal("options %s and %s cannot be used together",
860 "--statistics", "--no-statistics");
861
862 /* reject conflicting "-only" options */
864 pg_fatal("options %s and %s cannot be used together",
865 "-a/--data-only", "--statistics");
867 pg_fatal("options %s and %s cannot be used together",
868 "-s/--schema-only", "--statistics");
869
871 pg_fatal("options %s and %s cannot be used together",
872 "-s/--schema-only", "--include-foreign-data");
873
874 if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
875 pg_fatal("option %s is not supported with parallel backup",
876 "--include-foreign-data");
877
878 if (data_only && dopt.outputClean)
879 pg_fatal("options %s and %s cannot be used together",
880 "-c/--clean", "-a/--data-only");
881
882 if (dopt.if_exists && !dopt.outputClean)
883 pg_fatal("option %s requires option %s",
884 "--if-exists", "-c/--clean");
885
886 /*
887 * Set derivative flags. Ambiguous or nonsensical combinations, e.g.
888 * "--schema-only --no-schema", will have already caused an error in one
889 * of the checks above.
890 */
891 dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
892 data_only) && !no_data;
893 dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
895 dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
897
898
899 /*
900 * --inserts are already implied above if --column-inserts or
901 * --rows-per-insert were specified.
902 */
903 if (dopt.do_nothing && dopt.dump_inserts == 0)
904 pg_fatal("option %s requires option %s, %s, or %s",
905 "--on-conflict-do-nothing",
906 "--inserts", "--rows-per-insert", "--column-inserts");
907
908 /* Identify archive format to emit */
910
911 /* archiveFormat specific setup */
912 if (archiveFormat == archNull)
913 {
914 plainText = 1;
915
916 /*
917 * If you don't provide a restrict key, one will be appointed for you.
918 */
919 if (!dopt.restrict_key)
921 if (!dopt.restrict_key)
922 pg_fatal("could not generate restrict key");
924 pg_fatal("invalid restrict key");
925 }
926 else if (dopt.restrict_key)
927 pg_fatal("option %s can only be used with %s",
928 "--restrict-key", "--format=plain");
929
930 /*
931 * Custom and directory formats are compressed by default with gzip when
932 * available, not the others. If gzip is not available, no compression is
933 * done by default.
934 */
937 {
938#ifdef HAVE_LIBZ
940#else
942#endif
943 }
944
945 /*
946 * Compression options
947 */
950 pg_fatal("unrecognized compression algorithm: \"%s\"",
952
954 &compression_spec);
956 if (error_detail != NULL)
957 pg_fatal("invalid compression specification: %s",
959
960 error_detail = supports_compression(compression_spec);
961 if (error_detail != NULL)
962 pg_fatal("%s", error_detail);
963
964 /*
965 * Disable support for zstd workers for now - these are based on
966 * threading, and it's unclear how it interacts with parallel dumps on
967 * platforms where that relies on threads too (e.g. Windows).
968 */
969 if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
970 pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
971 "workers");
972
973 /*
974 * If emitting an archive format, we always want to emit a DATABASE item,
975 * in case --create is specified at pg_restore time.
976 */
977 if (!plainText)
978 dopt.outputCreateDB = 1;
979
980 /* Parallel backup only in the directory archive format so far */
981 if (archiveFormat != archDirectory && numWorkers > 1)
982 pg_fatal("parallel backup only supported by the directory format");
983
984 /* Open the output file */
985 fout = CreateArchive(filename, archiveFormat, compression_spec,
987
988 /* Make dump options accessible right away */
989 SetArchiveOptions(fout, &dopt, NULL);
990
991 /* Register the cleanup hook */
993
994 /* Let the archiver know how noisy to be */
995 fout->verbose = g_verbose;
996
997
998 /*
999 * We allow the server to be back to 9.2, and up to any minor release of
1000 * our own major version. (See also version check in pg_dumpall.c.)
1001 */
1002 fout->minRemoteVersion = 90200;
1003 fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
1004
1005 fout->numWorkers = numWorkers;
1006
1007 /*
1008 * Open the database using the Archiver, so it knows about it. Errors mean
1009 * death.
1010 */
1011 ConnectDatabaseAhx(fout, &dopt.cparams, false);
1013
1014 /*
1015 * On hot standbys, never try to dump unlogged table data, since it will
1016 * just throw an error.
1017 */
1018 if (fout->isStandby)
1019 dopt.no_unlogged_table_data = true;
1020
1021 /*
1022 * Find the last built-in OID, if needed (prior to 8.1)
1023 *
1024 * With 8.1 and above, we can just use FirstNormalObjectId - 1.
1025 */
1027
1028 pg_log_info("last built-in OID is %u", g_last_builtin_oid);
1029
1030 /* Expand schema selection patterns into OID lists */
1032 {
1035 strict_names);
1037 pg_fatal("no matching schemas were found");
1038 }
1041 false);
1042 /* non-matching exclusion patterns aren't an error */
1043
1044 /* Expand table selection patterns into OID lists */
1047 strict_names, false);
1050 strict_names, true);
1054 pg_fatal("no matching tables were found");
1055
1058 false, false);
1061 false, true);
1062
1065 false, false);
1068 false, true);
1069
1072
1073 /* non-matching exclusion patterns aren't an error */
1074
1075 /* Expand extension selection patterns into OID lists */
1077 {
1080 strict_names);
1082 pg_fatal("no matching extensions were found");
1083 }
1086 false);
1087 /* non-matching exclusion patterns aren't an error */
1088
1089 /*
1090 * Dumping LOs is the default for dumps where an inclusion switch is not
1091 * used (an "include everything" dump). -B can be used to exclude LOs
1092 * from those dumps. -b can be used to include LOs even when an inclusion
1093 * switch is used.
1094 *
1095 * -s means "schema only" and LOs are data, not schema, so we never
1096 * include LOs when -s is used.
1097 */
1098 if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
1099 dopt.outputLOs = true;
1100
1101 /*
1102 * Collect role names so we can map object owner OIDs to names.
1103 */
1105
1106 /*
1107 * Now scan the database and create DumpableObject structs for all the
1108 * objects we intend to dump.
1109 */
1110 tblinfo = getSchemaData(fout, &numTables);
1111
1112 if (dopt.dumpData)
1113 {
1114 getTableData(&dopt, tblinfo, numTables, 0);
1116 if (!dopt.dumpSchema)
1118 }
1119
1120 if (!dopt.dumpData && dopt.sequence_data)
1121 getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
1122
1123 /*
1124 * For binary upgrade mode, dump pg_largeobject_metadata and the
1125 * associated pg_shdepend rows. This is faster to restore than the
1126 * equivalent set of large object commands. We can only do this for
1127 * upgrades from v12 and newer; in older versions, pg_largeobject_metadata
1128 * was created WITH OIDS, so the OID column is hidden and won't be dumped.
1129 */
1130 if (dopt.binary_upgrade && fout->remoteVersion >= 120000)
1131 {
1134
1137
1138 /*
1139 * Save pg_largeobject_metadata's dump ID for use as a dependency for
1140 * pg_shdepend and any large object comments/seclabels.
1141 */
1142 lo_metadata_dumpId = lo_metadata->dataObj->dobj.dumpId;
1144
1145 /*
1146 * Only dump large object shdepend rows for this database.
1147 */
1148 shdepend->dataObj->filtercond = "WHERE classid = 'pg_largeobject'::regclass "
1149 "AND dbid = (SELECT oid FROM pg_database "
1150 " WHERE datname = current_database())";
1151
1152 /*
1153 * If upgrading from v16 or newer, only dump large objects with
1154 * comments/seclabels. For these upgrades, pg_upgrade can copy/link
1155 * pg_largeobject_metadata's files (which is usually faster) but we
1156 * still need to dump LOs with comments/seclabels here so that the
1157 * subsequent COMMENT and SECURITY LABEL commands work. pg_upgrade
1158 * can't copy/link the files from older versions because aclitem
1159 * (needed by pg_largeobject_metadata.lomacl) changed its storage
1160 * format in v16.
1161 */
1162 if (fout->remoteVersion >= 160000)
1163 lo_metadata->dataObj->filtercond = "WHERE oid IN "
1164 "(SELECT objoid FROM pg_description "
1165 "WHERE classoid = " CppAsString2(LargeObjectRelationId) " "
1166 "UNION SELECT objoid FROM pg_seclabel "
1167 "WHERE classoid = " CppAsString2(LargeObjectRelationId) ")";
1168 }
1169
1170 /*
1171 * In binary-upgrade mode, we do not have to worry about the actual LO
1172 * data or the associated metadata that resides in the pg_largeobject and
1173 * pg_largeobject_metadata tables, respectively.
1174 *
1175 * However, we do need to collect LO information as there may be comments
1176 * or other information on LOs that we do need to dump out.
1177 */
1178 if (dopt.outputLOs || dopt.binary_upgrade)
1179 getLOs(fout);
1180
1181 /*
1182 * Collect dependency data to assist in ordering the objects.
1183 */
1185
1186 /*
1187 * Collect ACLs, comments, and security labels, if wanted.
1188 */
1189 if (!dopt.aclsSkip)
1191 if (!dopt.no_comments)
1193 if (!dopt.no_security_labels)
1195
1196 /* For binary upgrade mode, collect required pg_class information. */
1197 if (dopt.binary_upgrade)
1199
1200 /* Collect sequence information. */
1202
1203 /* Lastly, create dummy objects to represent the section boundaries */
1205
1206 /* Get pointers to all the known DumpableObjects */
1208
1209 /*
1210 * Add dummy dependencies to enforce the dump section ordering.
1211 */
1213
1214 /*
1215 * Sort the objects into a safe dump order (no forward references).
1216 *
1217 * We rely on dependency information to help us determine a safe order, so
1218 * the initial sort is mostly for cosmetic purposes: we sort by name to
1219 * ensure that logically identical schemas will dump identically.
1220 */
1222
1224 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
1225
1226 /*
1227 * Create archive TOC entries for all the objects to be dumped, in a safe
1228 * order.
1229 */
1230
1231 /*
1232 * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
1233 */
1237
1238 /* The database items are always next, unless we don't want them at all */
1239 if (dopt.outputCreateDB)
1241
1242 /* Now the rearrangeable objects. */
1243 for (i = 0; i < numObjs; i++)
1245
1246 /*
1247 * Set up options info to ensure we dump what we want.
1248 */
1249 ropt = NewRestoreOptions();
1250 ropt->filename = filename;
1251
1252 /* if you change this list, see dumpOptionsFromRestoreOptions */
1253 ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
1254 ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
1255 ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
1258 ropt->dropSchema = dopt.outputClean;
1259 ropt->dumpData = dopt.dumpData;
1260 ropt->dumpSchema = dopt.dumpSchema;
1261 ropt->dumpStatistics = dopt.dumpStatistics;
1262 ropt->if_exists = dopt.if_exists;
1263 ropt->column_inserts = dopt.column_inserts;
1264 ropt->dumpSections = dopt.dumpSections;
1265 ropt->aclsSkip = dopt.aclsSkip;
1266 ropt->superuser = dopt.outputSuperuser;
1267 ropt->createDB = dopt.outputCreateDB;
1268 ropt->noOwner = dopt.outputNoOwner;
1269 ropt->noTableAm = dopt.outputNoTableAm;
1270 ropt->noTablespace = dopt.outputNoTablespaces;
1272 ropt->use_setsessauth = dopt.use_setsessauth;
1274 ropt->dump_inserts = dopt.dump_inserts;
1275 ropt->no_comments = dopt.no_comments;
1276 ropt->no_policies = dopt.no_policies;
1277 ropt->no_publications = dopt.no_publications;
1280 ropt->lockWaitTimeout = dopt.lockWaitTimeout;
1283 ropt->sequence_data = dopt.sequence_data;
1284 ropt->binary_upgrade = dopt.binary_upgrade;
1285 ropt->restrict_key = dopt.restrict_key ? pg_strdup(dopt.restrict_key) : NULL;
1286
1287 ropt->compression_spec = compression_spec;
1288
1289 ropt->suppressDumpWarnings = true; /* We've already shown them */
1290
1291 SetArchiveOptions(fout, &dopt, ropt);
1292
1293 /* Mark which entries should be output */
1295
1296 /*
1297 * The archive's TOC entries are now marked as to which ones will actually
1298 * be output, so we can set up their dependency lists properly. This isn't
1299 * necessary for plain-text output, though.
1300 */
1301 if (!plainText)
1303
1304 /*
1305 * And finally we can do the actual output.
1306 *
1307 * Note: for non-plain-text output formats, the output file is written
1308 * inside CloseArchive(). This is, um, bizarre; but not worth changing
1309 * right now.
1310 */
1311 if (plainText)
1313
1315
1316 exit_nicely(0);
1317}

References _restoreOptions::aclsSkip, _dumpOptions::aclsSkip, addBoundaryDependencies(), addObjectDependency(), archCustom, archDirectory, archNull, archUnknown, _restoreOptions::binary_upgrade, _dumpOptions::binary_upgrade, BuildArchiveDependencies(), buildMatViewRefreshDependencies(), CloseArchive(), collectBinaryUpgradeClassOids(), collectComments(), collectRoleNames(), collectSecLabels(), collectSequences(), _restoreOptions::column_inserts, _dumpOptions::column_inserts, compression_algorithm, _restoreOptions::compression_spec, ConnectDatabaseAhx(), _restoreOptions::cparams, _dumpOptions::cparams, CppAsString2, CreateArchive(), createBoundaryObjects(), _restoreOptions::createDB, DATA_DIR_SYNC_METHOD_FSYNC, _connParams::dbname, _restoreOptions::disable_dollar_quoting, _dumpOptions::disable_dollar_quoting, _restoreOptions::disable_triggers, _dumpOptions::disable_triggers, _dumpOptions::do_nothing, _dumpOptions::dontOutputLOs, dosync, _restoreOptions::dropSchema, DUMP_DEFAULT_ROWS_PER_INSERT, _restoreOptions::dump_inserts, _dumpOptions::dump_inserts, _restoreOptions::dumpData, _dumpOptions::dumpData, dumpDatabase(), dumpDumpableObject(), dumpEncoding(), _restoreOptions::dumpSchema, _dumpOptions::dumpSchema, dumpSearchPath(), _restoreOptions::dumpSections, _dumpOptions::dumpSections, _restoreOptions::dumpStatistics, _dumpOptions::dumpStatistics, dumpStdStrings(), _restoreOptions::enable_row_security, _dumpOptions::enable_row_security, exit_nicely(), expand_extension_name_patterns(), expand_foreign_server_name_patterns(), expand_schema_name_patterns(), expand_table_name_patterns(), extension_exclude_oids, extension_exclude_patterns, extension_include_oids, extension_include_patterns, extra_float_digits, fb(), _restoreOptions::filename, filename, findTableByOid(), FirstNormalObjectId, foreign_servers_include_oids, foreign_servers_include_patterns, format, g_last_builtin_oid, generate_restrict_key(), get_progname(), getAdditionalACLs(), getDependencies(), getDumpableObjects(), getLOs(), getopt_long(), getSchemaData(), getTableData(), getTableDataFKConstraints(), have_extra_float_digits, SimpleOidList::head, SimpleStringList::head, help(), i, _restoreOptions::if_exists, _dumpOptions::if_exists, _restoreOptions::include_everything, _dumpOptions::include_everything, init_parallel_dump_utils(), InitDumpOptions(), lo_metadata_dumpId, _dumpOptions::load_via_partition_root, _restoreOptions::lockWaitTimeout, _dumpOptions::lockWaitTimeout, makeTableDataInfo(), NewRestoreOptions(), no_argument, _restoreOptions::no_comments, _dumpOptions::no_comments, no_data, _restoreOptions::no_policies, _dumpOptions::no_policies, _restoreOptions::no_publications, _dumpOptions::no_publications, no_schema, _restoreOptions::no_security_labels, _dumpOptions::no_security_labels, no_statistics, _restoreOptions::no_subscriptions, _dumpOptions::no_subscriptions, _dumpOptions::no_toast_compression, _dumpOptions::no_unlogged_table_data, _restoreOptions::noOwner, _restoreOptions::noTableAm, _restoreOptions::noTablespace, on_exit_close_archive(), optarg, optind, option_parse_int(), pg_compress_specification::options, _dumpOptions::outputClean, _dumpOptions::outputCreateDB, _dumpOptions::outputLOs, _dumpOptions::outputNoOwner, _dumpOptions::outputNoTableAm, _dumpOptions::outputNoTablespaces, _dumpOptions::outputSuperuser, parse_compress_algorithm(), parse_compress_options(), parse_compress_specification(), parse_sync_method(), parseArchiveFormat(), PG_COMPRESSION_OPTION_WORKERS, pg_fatal, pg_log_error, pg_log_error_hint, pg_log_info, pg_log_warning, PG_LOG_WARNING, pg_logging_increase_verbosity(), pg_logging_init(), pg_logging_set_level(), PG_MAX_JOBS, pg_strdup(), PG_TEXTDOMAIN, _connParams::pghost, _connParams::pgport, ProcessArchiveRestoreOptions(), progname, _connParams::promptPassword, quote_all_identifiers, read_dump_filters(), required_argument, RestoreArchive(), _restoreOptions::restrict_key, _dumpOptions::restrict_key, schema_exclude_oids, schema_exclude_patterns, schema_include_oids, schema_include_patterns, _restoreOptions::sequence_data, _dumpOptions::sequence_data, _dumpOptions::serializable_deferrable, set_dump_section(), set_pglocale_pgservice(), SetArchiveOptions(), setup_connection(), setupDumpWorker(), simple_string_list_append(), sortDumpableObjects(), sortDumpableObjectsByTypeName(), statistics_only, strict_names, _restoreOptions::superuser, supports_compression(), _restoreOptions::suppressDumpWarnings, sync_method, table_exclude_oids, table_exclude_patterns, table_exclude_patterns_and_children, table_include_oids, table_include_patterns, table_include_patterns_and_children, tabledata_exclude_oids, tabledata_exclude_patterns, tabledata_exclude_patterns_and_children, TRI_NO, TRI_YES, _restoreOptions::use_setsessauth, _dumpOptions::use_setsessauth, _connParams::username, valid_restrict_key(), validate_compress_specification(), and with_statistics.

◆ makeTableDataInfo()

static void makeTableDataInfo ( DumpOptions dopt,
TableInfo tbinfo 
)
static

Definition at line 3053 of file pg_dump.c.

3054{
3056
3057 /*
3058 * Nothing to do if we already decided to dump the table. This will
3059 * happen for "config" tables.
3060 */
3061 if (tbinfo->dataObj != NULL)
3062 return;
3063
3064 /* Skip VIEWs (no data to dump) */
3065 if (tbinfo->relkind == RELKIND_VIEW)
3066 return;
3067 /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
3068 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
3071 tbinfo->foreign_server)))
3072 return;
3073 /* Skip partitioned tables (data in partitions) */
3074 if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
3075 return;
3076
3077 /* Don't dump data in unlogged tables, if so requested */
3078 if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
3080 return;
3081
3082 /* Check that the data is not explicitly excluded */
3084 tbinfo->dobj.catId.oid))
3085 return;
3086
3087 /* OK, let's dump it */
3089
3090 if (tbinfo->relkind == RELKIND_MATVIEW)
3092 else if (tbinfo->relkind == RELKIND_SEQUENCE)
3093 tdinfo->dobj.objType = DO_SEQUENCE_SET;
3094 else
3095 tdinfo->dobj.objType = DO_TABLE_DATA;
3096
3097 /*
3098 * Note: use tableoid 0 so that this object won't be mistaken for
3099 * something that pg_depend entries apply to.
3100 */
3101 tdinfo->dobj.catId.tableoid = 0;
3102 tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3103 AssignDumpId(&tdinfo->dobj);
3104 tdinfo->dobj.name = tbinfo->dobj.name;
3105 tdinfo->dobj.namespace = tbinfo->dobj.namespace;
3106 tdinfo->tdtable = tbinfo;
3107 tdinfo->filtercond = NULL; /* might get set later */
3108 addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
3109
3110 /* A TableDataInfo contains data, of course */
3111 tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
3112
3113 tbinfo->dataObj = tdinfo;
3114
3115 /*
3116 * Materialized view statistics must be restored after the data, because
3117 * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
3118 *
3119 * The dependency is added here because the statistics objects are created
3120 * first.
3121 */
3122 if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
3123 {
3124 tbinfo->stats->section = SECTION_POST_DATA;
3125 addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
3126 }
3127
3128 /* Make sure that we'll collect per-column info for this table. */
3129 tbinfo->interesting = true;
3130}

References addObjectDependency(), AssignDumpId(), DO_REFRESH_MATVIEW, DO_SEQUENCE_SET, DO_TABLE_DATA, _tableDataInfo::dobj, DUMP_COMPONENT_DATA, fb(), foreign_servers_include_oids, SimpleOidList::head, _dumpOptions::no_unlogged_table_data, _dumpableObject::objType, pg_malloc(), SECTION_POST_DATA, simple_oid_list_member(), and tabledata_exclude_oids.

Referenced by getTableData(), main(), and processExtensionTables().

◆ nonemptyReloptions()

static bool nonemptyReloptions ( const char reloptions)
static

Definition at line 20686 of file pg_dump.c.

20687{
20688 /* Don't want to print it if it's just "{}" */
20689 return (reloptions != NULL && strlen(reloptions) > 2);
20690}

References fb().

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

◆ parse_sequence_type()

static SeqType parse_sequence_type ( const char name)
inlinestatic

Definition at line 19101 of file pg_dump.c.

19102{
19103 for (int i = 0; i < lengthof(SeqTypeNames); i++)
19104 {
19105 if (strcmp(SeqTypeNames[i], name) == 0)
19106 return (SeqType) i;
19107 }
19108
19109 pg_fatal("unrecognized sequence type: %s", name);
19110 return (SeqType) 0; /* keep compiler quiet */
19111}

References fb(), i, lengthof, name, pg_fatal, and SeqTypeNames.

Referenced by collectSequences(), and dumpSequence().

◆ parseArchiveFormat()

static ArchiveFormat parseArchiveFormat ( const char format,
ArchiveMode mode 
)
static

Definition at line 1639 of file pg_dump.c.

1640{
1642
1644
1645 if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1646 {
1647 /* This is used by pg_dumpall, and is not documented */
1650 }
1651 else if (pg_strcasecmp(format, "c") == 0)
1653 else if (pg_strcasecmp(format, "custom") == 0)
1655 else if (pg_strcasecmp(format, "d") == 0)
1657 else if (pg_strcasecmp(format, "directory") == 0)
1659 else if (pg_strcasecmp(format, "p") == 0)
1661 else if (pg_strcasecmp(format, "plain") == 0)
1663 else if (pg_strcasecmp(format, "t") == 0)
1665 else if (pg_strcasecmp(format, "tar") == 0)
1667 else
1668 pg_fatal("invalid output format \"%s\" specified", format);
1669 return archiveFormat;
1670}

References archCustom, archDirectory, archModeAppend, archModeWrite, archNull, archTar, fb(), format, mode, pg_fatal, and pg_strcasecmp().

Referenced by main().

◆ processExtensionTables()

void processExtensionTables ( Archive fout,
ExtensionInfo  extinfo[],
int  numExtensions 
)

Definition at line 20013 of file pg_dump.c.

20015{
20016 DumpOptions *dopt = fout->dopt;
20017 PQExpBuffer query;
20018 PGresult *res;
20019 int ntups,
20020 i;
20021 int i_conrelid,
20023
20024 /* Nothing to do if no extensions */
20025 if (numExtensions == 0)
20026 return;
20027
20028 /*
20029 * Identify extension configuration tables and create TableDataInfo
20030 * objects for them, ensuring their data will be dumped even though the
20031 * tables themselves won't be.
20032 *
20033 * Note that we create TableDataInfo objects even in schema-only mode, ie,
20034 * user data in a configuration table is treated like schema data. This
20035 * seems appropriate since system data in a config table would get
20036 * reloaded by CREATE EXTENSION. If the extension is not listed in the
20037 * list of extensions to be included, none of its data is dumped.
20038 */
20039 for (i = 0; i < numExtensions; i++)
20040 {
20042 char *extconfig = curext->extconfig;
20043 char *extcondition = curext->extcondition;
20044 char **extconfigarray = NULL;
20045 char **extconditionarray = NULL;
20046 int nconfigitems = 0;
20047 int nconditionitems = 0;
20048
20049 /*
20050 * Check if this extension is listed as to include in the dump. If
20051 * not, any table data associated with it is discarded.
20052 */
20055 curext->dobj.catId.oid))
20056 continue;
20057
20058 /*
20059 * Check if this extension is listed as to exclude in the dump. If
20060 * yes, any table data associated with it is discarded.
20061 */
20064 curext->dobj.catId.oid))
20065 continue;
20066
20067 if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
20068 {
20069 int j;
20070
20071 if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
20072 pg_fatal("could not parse %s array", "extconfig");
20073 if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
20074 pg_fatal("could not parse %s array", "extcondition");
20076 pg_fatal("mismatched number of configurations and conditions for extension");
20077
20078 for (j = 0; j < nconfigitems; j++)
20079 {
20082 bool dumpobj =
20083 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
20084
20086 if (configtbl == NULL)
20087 continue;
20088
20089 /*
20090 * Tables of not-to-be-dumped extensions shouldn't be dumped
20091 * unless the table or its schema is explicitly included
20092 */
20093 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
20094 {
20095 /* check table explicitly requested */
20096 if (table_include_oids.head != NULL &&
20098 configtbloid))
20099 dumpobj = true;
20100
20101 /* check table's schema explicitly requested */
20102 if (configtbl->dobj.namespace->dobj.dump &
20104 dumpobj = true;
20105 }
20106
20107 /* check table excluded by an exclusion switch */
20108 if (table_exclude_oids.head != NULL &&
20110 configtbloid))
20111 dumpobj = false;
20112
20113 /* check schema excluded by an exclusion switch */
20115 configtbl->dobj.namespace->dobj.catId.oid))
20116 dumpobj = false;
20117
20118 if (dumpobj)
20119 {
20121 if (configtbl->dataObj != NULL)
20122 {
20123 if (strlen(extconditionarray[j]) > 0)
20124 configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
20125 }
20126 }
20127 }
20128 }
20129 if (extconfigarray)
20133 }
20134
20135 /*
20136 * Now that all the TableDataInfo objects have been created for all the
20137 * extensions, check their FK dependencies and register them to try and
20138 * dump the data out in an order that they can be restored in.
20139 *
20140 * Note that this is not a problem for user tables as their FKs are
20141 * recreated after the data has been loaded.
20142 */
20143
20144 query = createPQExpBuffer();
20145
20146 printfPQExpBuffer(query,
20147 "SELECT conrelid, confrelid "
20148 "FROM pg_constraint "
20149 "JOIN pg_depend ON (objid = confrelid) "
20150 "WHERE contype = 'f' "
20151 "AND refclassid = 'pg_extension'::regclass "
20152 "AND classid = 'pg_class'::regclass;");
20153
20154 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
20155 ntups = PQntuples(res);
20156
20157 i_conrelid = PQfnumber(res, "conrelid");
20158 i_confrelid = PQfnumber(res, "confrelid");
20159
20160 /* Now get the dependencies and register them */
20161 for (i = 0; i < ntups; i++)
20162 {
20163 Oid conrelid,
20164 confrelid;
20166 *contable;
20167
20168 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
20169 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
20170 contable = findTableByOid(conrelid);
20171 reftable = findTableByOid(confrelid);
20172
20173 if (reftable == NULL ||
20174 reftable->dataObj == NULL ||
20175 contable == NULL ||
20176 contable->dataObj == NULL)
20177 continue;
20178
20179 /*
20180 * Make referencing TABLE_DATA object depend on the referenced table's
20181 * TABLE_DATA object.
20182 */
20183 addObjectDependency(&contable->dataObj->dobj,
20184 reftable->dataObj->dobj.dumpId);
20185 }
20186 PQclear(res);
20187 destroyPQExpBuffer(query);
20188}

References addObjectDependency(), atooid, createPQExpBuffer(), PQExpBufferData::data, _tableInfo::dataObj, destroyPQExpBuffer(), _tableDataInfo::dobj, DUMP_COMPONENT_DATA, DUMP_COMPONENT_DEFINITION, _dumpableObject::dumpId, ExecuteSqlQuery(), _extensionInfo::extconfig, extension_exclude_oids, extension_include_oids, fb(), findTableByOid(), free, SimpleOidList::head, i, j, makeTableDataInfo(), parsePGArray(), pg_fatal, pg_strdup(), PGRES_TUPLES_OK, PQclear, PQfnumber(), PQgetvalue, PQntuples, printfPQExpBuffer(), schema_exclude_oids, simple_oid_list_member(), table_exclude_oids, and table_include_oids.

Referenced by getSchemaData().

◆ prohibit_crossdb_refs()

static void prohibit_crossdb_refs ( PGconn conn,
const char dbname,
const char pattern 
)
static

Definition at line 1937 of file pg_dump.c.

1938{
1939 const char *db;
1940
1941 db = PQdb(conn);
1942 if (db == NULL)
1943 pg_fatal("You are currently not connected to a database.");
1944
1945 if (strcmp(db, dbname) != 0)
1946 pg_fatal("cross-database references are not implemented: %s",
1947 pattern);
1948}

References conn, dbname, fb(), pg_fatal, and PQdb().

Referenced by expand_schema_name_patterns(), and expand_table_name_patterns().

◆ read_dump_filters()

static void read_dump_filters ( const char filename,
DumpOptions dopt 
)
static

Definition at line 20717 of file pg_dump.c.

20718{
20720 char *objname;
20722 FilterObjectType objtype;
20723
20725
20726 while (filter_read_item(&fstate, &objname, &comtype, &objtype))
20727 {
20729 {
20730 switch (objtype)
20731 {
20733 break;
20740 pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
20741 "include",
20742 filter_object_type_name(objtype));
20743 exit_nicely(1);
20744 break; /* unreachable */
20745
20748 break;
20751 break;
20754 dopt->include_everything = false;
20755 break;
20758 dopt->include_everything = false;
20759 break;
20762 objname);
20763 dopt->include_everything = false;
20764 break;
20765 }
20766 }
20768 {
20769 switch (objtype)
20770 {
20772 break;
20778 pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
20779 "exclude",
20780 filter_object_type_name(objtype));
20781 exit_nicely(1);
20782 break;
20783
20786 break;
20789 objname);
20790 break;
20793 objname);
20794 break;
20797 break;
20800 break;
20803 objname);
20804 break;
20805 }
20806 }
20807 else
20808 {
20810 Assert(objtype == FILTER_OBJECT_TYPE_NONE);
20811 }
20812
20813 if (objname)
20814 free(objname);
20815 }
20816
20818}

References _, Assert, exit_nicely(), extension_exclude_patterns, extension_include_patterns, fb(), filename, FILTER_COMMAND_TYPE_EXCLUDE, FILTER_COMMAND_TYPE_INCLUDE, FILTER_COMMAND_TYPE_NONE, filter_free(), filter_init(), FILTER_OBJECT_TYPE_DATABASE, FILTER_OBJECT_TYPE_EXTENSION, FILTER_OBJECT_TYPE_FOREIGN_DATA, FILTER_OBJECT_TYPE_FUNCTION, FILTER_OBJECT_TYPE_INDEX, filter_object_type_name(), FILTER_OBJECT_TYPE_NONE, FILTER_OBJECT_TYPE_SCHEMA, FILTER_OBJECT_TYPE_TABLE, FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN, FILTER_OBJECT_TYPE_TABLE_DATA, FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN, FILTER_OBJECT_TYPE_TRIGGER, filter_read_item(), foreign_servers_include_patterns, free, _dumpOptions::include_everything, pg_log_filter_error(), schema_exclude_patterns, schema_include_patterns, simple_string_list_append(), table_exclude_patterns, table_exclude_patterns_and_children, table_include_patterns, table_include_patterns_and_children, tabledata_exclude_patterns, and tabledata_exclude_patterns_and_children.

Referenced by main().

◆ refreshMatViewData()

static void refreshMatViewData ( Archive fout,
const TableDataInfo tdinfo 
)
static

Definition at line 2999 of file pg_dump.c.

3000{
3001 TableInfo *tbinfo = tdinfo->tdtable;
3002 PQExpBuffer q;
3003
3004 /* If the materialized view is not flagged as populated, skip this. */
3005 if (!tbinfo->relispopulated)
3006 return;
3007
3008 q = createPQExpBuffer();
3009
3010 appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
3012
3013 if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
3015 tdinfo->dobj.catId, /* catalog ID */
3016 tdinfo->dobj.dumpId, /* dump ID */
3017 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
3018 .namespace = tbinfo->dobj.namespace->dobj.name,
3019 .owner = tbinfo->rolname,
3020 .description = "MATERIALIZED VIEW DATA",
3021 .section = SECTION_POST_DATA,
3022 .createStmt = q->data,
3023 .deps = tdinfo->dobj.dependencies,
3024 .nDeps = tdinfo->dobj.nDeps));
3025
3027}

References appendPQExpBuffer(), ARCHIVE_OPTS, ArchiveEntry(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), DUMP_COMPONENT_DATA, fb(), fmtQualifiedDumpable, and SECTION_POST_DATA.

Referenced by dumpDumpableObject().

◆ selectDumpableAccessMethod()

static void selectDumpableAccessMethod ( AccessMethodInfo method,
Archive fout 
)
static

Definition at line 2262 of file pg_dump.c.

2263{
2264 /* see getAccessMethods() comment about v9.6. */
2265 if (fout->remoteVersion < 90600)
2266 {
2267 method->dobj.dump = DUMP_COMPONENT_NONE;
2268 return;
2269 }
2270
2271 if (checkExtensionMembership(&method->dobj, fout))
2272 return; /* extension membership overrides all else */
2273
2274 /*
2275 * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
2276 * they do not support ACLs currently.
2277 */
2278 if (method->dobj.catId.oid <= g_last_builtin_oid)
2279 method->dobj.dump = DUMP_COMPONENT_NONE;
2280 else
2281 method->dobj.dump = fout->dopt->include_everything ?
2283}

References _dumpableObject::catId, checkExtensionMembership(), _accessMethodInfo::dobj, _dumpableObject::dump, DUMP_COMPONENT_ALL, DUMP_COMPONENT_NONE, fb(), g_last_builtin_oid, and CatalogId::oid.

Referenced by getAccessMethods().

◆ selectDumpableCast()

static void selectDumpableCast ( CastInfo cast,
Archive fout 
)
static

Definition at line 2204 of file pg_dump.c.

2205{
2206 if (checkExtensionMembership(&cast->dobj, fout))
2207 return; /* extension membership overrides all else */
2208
2209 /*
2210 * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
2211 * support ACLs currently.
2212 */
2213 if (cast->dobj.catId.oid <= g_last_builtin_oid)
2214 cast->dobj.dump = DUMP_COMPONENT_NONE;
2215 else
2216 cast->dobj.dump = fout->dopt->include_everything ?
2218}

References checkExtensionMembership(), DUMP_COMPONENT_ALL, DUMP_COMPONENT_NONE, fb(), and g_last_builtin_oid.

Referenced by getCasts().

◆ selectDumpableDefaultACL()

static void selectDumpableDefaultACL ( DefaultACLInfo dinfo,
DumpOptions dopt 
)
static

Definition at line 2182 of file pg_dump.c.

2183{
2184 /* Default ACLs can't be extension members */
2185
2186 if (dinfo->dobj.namespace)
2187 /* default ACLs are considered part of the namespace */
2188 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
2189 else
2190 dinfo->dobj.dump = dopt->include_everything ?
2192}

References DUMP_COMPONENT_ALL, DUMP_COMPONENT_NONE, fb(), and _dumpOptions::include_everything.

Referenced by getDefaultACLs().

◆ selectDumpableExtension()

static void selectDumpableExtension ( ExtensionInfo extinfo,
DumpOptions dopt 
)
static

Definition at line 2297 of file pg_dump.c.

2298{
2299 /*
2300 * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
2301 * change permissions on their member objects, if they wish to, and have
2302 * those changes preserved.
2303 */
2304 if (extinfo->dobj.catId.oid <= g_last_builtin_oid)
2305 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
2306 else
2307 {
2308 /* check if there is a list of extensions to dump */
2310 extinfo->dobj.dump = extinfo->dobj.dump_contains =
2312 extinfo->dobj.catId.oid) ?
2314 else
2315 extinfo->dobj.dump = extinfo->dobj.dump_contains =
2316 dopt->include_everything ?
2318
2319 /* check that the extension is not explicitly excluded */
2320 if (extinfo->dobj.dump &&
2322 extinfo->dobj.catId.oid))
2323 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
2324 }
2325}

References DUMP_COMPONENT_ACL, DUMP_COMPONENT_ALL, DUMP_COMPONENT_NONE, extension_exclude_oids, extension_include_oids, fb(), g_last_builtin_oid, SimpleOidList::head, _dumpOptions::include_everything, and simple_oid_list_member().

Referenced by getExtensions().

◆ selectDumpableNamespace()

static void selectDumpableNamespace ( NamespaceInfo nsinfo,
Archive fout 
)
static

Definition at line 2012 of file pg_dump.c.

2013{
2014 /*
2015 * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
2016 * and (for --clean) a DROP SCHEMA statement. (In the absence of
2017 * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
2018 */
2019 nsinfo->create = true;
2020
2021 /*
2022 * If specific tables are being dumped, do not dump any complete
2023 * namespaces. If specific namespaces are being dumped, dump just those
2024 * namespaces. Otherwise, dump all non-system namespaces.
2025 */
2027 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
2028 else if (schema_include_oids.head != NULL)
2029 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
2031 nsinfo->dobj.catId.oid) ?
2033 else if (fout->remoteVersion >= 90600 &&
2034 strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
2035 {
2036 /*
2037 * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
2038 * they are interesting (and not the original ACLs which were set at
2039 * initdb time, see pg_init_privs).
2040 */
2041 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
2042 }
2043 else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
2044 strcmp(nsinfo->dobj.name, "information_schema") == 0)
2045 {
2046 /* Other system schemas don't get dumped */
2047 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
2048 }
2049 else if (strcmp(nsinfo->dobj.name, "public") == 0)
2050 {
2051 /*
2052 * The public schema is a strange beast that sits in a sort of
2053 * no-mans-land between being a system object and a user object.
2054 * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
2055 * a comment and an indication of ownership. If the owner is the
2056 * default, omit that superfluous DUMP_COMPONENT_DEFINITION. Before
2057 * v15, the default owner was BOOTSTRAP_SUPERUSERID.
2058 */
2059 nsinfo->create = false;
2060 nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
2061 if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
2062 nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
2063 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
2064
2065 /*
2066 * Also, make like it has a comment even if it doesn't; this is so
2067 * that we'll emit a command to drop the comment, if appropriate.
2068 * (Without this, we'd not call dumpCommentExtended for it.)
2069 */
2070 nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
2071 }
2072 else
2073 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
2074
2075 /*
2076 * In any case, a namespace can be excluded by an exclusion switch
2077 */
2078 if (nsinfo->dobj.dump_contains &&
2080 nsinfo->dobj.catId.oid))
2081 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
2082
2083 /*
2084 * If the schema belongs to an extension, allow extension membership to
2085 * override the dump decision for the schema itself. However, this does
2086 * not change dump_contains, so this won't change what we do with objects
2087 * within the schema. (If they belong to the extension, they'll get
2088 * suppressed by it, otherwise not.)
2089 */
2091}

References checkExtensionMembership(), DUMP_COMPONENT_ACL, DUMP_COMPONENT_ALL, DUMP_COMPONENT_COMMENT, DUMP_COMPONENT_NONE, fb(), SimpleOidList::head, schema_exclude_oids, schema_include_oids, simple_oid_list_member(), and table_include_oids.

Referenced by getNamespaces().

◆ selectDumpableObject()

static void selectDumpableObject ( DumpableObject dobj,
Archive fout 
)
static

Definition at line 2372 of file pg_dump.c.

2373{
2374 if (checkExtensionMembership(dobj, fout))
2375 return; /* extension membership overrides all else */
2376
2377 /*
2378 * Default policy is to dump if parent namespace is dumpable, or for
2379 * non-namespace-associated items, dump if we're dumping "everything".
2380 */
2381 if (dobj->namespace)
2382 dobj->dump = dobj->namespace->dobj.dump_contains;
2383 else
2384 dobj->dump = fout->dopt->include_everything ?
2386}

References checkExtensionMembership(), _dumpableObject::dump, DUMP_COMPONENT_ALL, DUMP_COMPONENT_NONE, _dumpableObject::dump_contains, and fb().

Referenced by getAggregates(), getCollations(), getConversions(), getEventTriggers(), getForeignDataWrappers(), getForeignServers(), getFuncs(), getOpclasses(), getOperators(), getOpfamilies(), getPublications(), getSubscriptionRelations(), getSubscriptions(), getTransforms(), getTSConfigurations(), getTSDictionaries(), getTSParsers(), and getTSTemplates().

◆ selectDumpableProcLang()

static void selectDumpableProcLang ( ProcLangInfo plang,
Archive fout 
)
static

Definition at line 2229 of file pg_dump.c.

2230{
2231 if (checkExtensionMembership(&plang->dobj, fout))
2232 return; /* extension membership overrides all else */
2233
2234 /*
2235 * Only include procedural languages when we are dumping everything.
2236 *
2237 * For from-initdb procedural languages, only include ACLs, as we do for
2238 * the pg_catalog namespace. We need this because procedural languages do
2239 * not live in any namespace.
2240 */
2241 if (!fout->dopt->include_everything)
2242 plang->dobj.dump = DUMP_COMPONENT_NONE;
2243 else
2244 {
2245 if (plang->dobj.catId.oid <= g_last_builtin_oid)
2246 plang->dobj.dump = fout->remoteVersion < 90600 ?
2248 else
2249 plang->dobj.dump = DUMP_COMPONENT_ALL;
2250 }
2251}

References checkExtensionMembership(), DUMP_COMPONENT_ACL, DUMP_COMPONENT_ALL, DUMP_COMPONENT_NONE, fb(), and g_last_builtin_oid.

Referenced by getProcLangs().

◆ selectDumpablePublicationObject()

static void selectDumpablePublicationObject ( DumpableObject dobj,
Archive fout 
)
static

Definition at line 2336 of file pg_dump.c.

2337{
2338 if (checkExtensionMembership(dobj, fout))
2339 return; /* extension membership overrides all else */
2340
2341 dobj->dump = fout->dopt->include_everything ?
2343}

References checkExtensionMembership(), _dumpableObject::dump, DUMP_COMPONENT_ALL, DUMP_COMPONENT_NONE, and fb().

Referenced by getPublicationNamespaces(), and getPublicationTables().

◆ selectDumpableStatisticsObject()

static void selectDumpableStatisticsObject ( StatsExtInfo sobj,
Archive fout 
)
static

Definition at line 2354 of file pg_dump.c.

2355{
2356 if (checkExtensionMembership(&sobj->dobj, fout))
2357 return; /* extension membership overrides all else */
2358
2359 sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
2360 if (sobj->stattable == NULL ||
2361 !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
2362 sobj->dobj.dump = DUMP_COMPONENT_NONE;
2363}

References checkExtensionMembership(), DUMP_COMPONENT_DEFINITION, DUMP_COMPONENT_NONE, and fb().

Referenced by getExtendedStatistics().

◆ selectDumpableTable()

static void selectDumpableTable ( TableInfo tbinfo,
Archive fout 
)
static

Definition at line 2098 of file pg_dump.c.

2099{
2101 return; /* extension membership overrides all else */
2102
2103 /*
2104 * If specific tables are being dumped, dump just those tables; else, dump
2105 * according to the parent namespace's dump flag.
2106 */
2109 tbinfo->dobj.catId.oid) ?
2111 else
2112 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
2113
2114 /*
2115 * In any case, a table can be excluded by an exclusion switch
2116 */
2117 if (tbinfo->dobj.dump &&
2119 tbinfo->dobj.catId.oid))
2120 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
2121}

References checkExtensionMembership(), DUMP_COMPONENT_ALL, DUMP_COMPONENT_NONE, fb(), SimpleOidList::head, simple_oid_list_member(), table_exclude_oids, and table_include_oids.

Referenced by getTables().

◆ selectDumpableType()

static void selectDumpableType ( TypeInfo tyinfo,
Archive fout 
)
static

Definition at line 2137 of file pg_dump.c.

2138{
2139 /* skip complex types, except for standalone composite types */
2140 if (OidIsValid(tyinfo->typrelid) &&
2141 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
2142 {
2143 TableInfo *tytable = findTableByOid(tyinfo->typrelid);
2144
2145 tyinfo->dobj.objType = DO_DUMMY_TYPE;
2146 if (tytable != NULL)
2147 tyinfo->dobj.dump = tytable->dobj.dump;
2148 else
2149 tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
2150 return;
2151 }
2152
2153 /* skip auto-generated array and multirange types */
2154 if (tyinfo->isArray || tyinfo->isMultirange)
2155 {
2156 tyinfo->dobj.objType = DO_DUMMY_TYPE;
2157
2158 /*
2159 * Fall through to set the dump flag; we assume that the subsequent
2160 * rules will do the same thing as they would for the array's base
2161 * type or multirange's range type. (We cannot reliably look up the
2162 * base type here, since getTypes may not have processed it yet.)
2163 */
2164 }
2165
2167 return; /* extension membership overrides all else */
2168
2169 /* Dump based on if the contents of the namespace are being dumped */
2170 tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
2171}

References checkExtensionMembership(), DO_DUMMY_TYPE, DUMP_COMPONENT_NONE, fb(), findTableByOid(), and OidIsValid.

Referenced by getTypes().

◆ SequenceItemCmp()

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

Definition at line 19117 of file pg_dump.c.

19118{
19119 SequenceItem v1 = *((const SequenceItem *) p1);
19120 SequenceItem v2 = *((const SequenceItem *) p2);
19121
19122 return pg_cmp_u32(v1.oid, v2.oid);
19123}

References fb(), and pg_cmp_u32().

Referenced by dumpSequence(), and dumpSequenceData().

◆ set_restrict_relation_kind()

static void set_restrict_relation_kind ( Archive AH,
const char value 
)
static

Definition at line 5100 of file pg_dump.c.

5101{
5103 PGresult *res;
5104
5105 appendPQExpBuffer(query,
5106 "SELECT set_config(name, '%s', false) "
5107 "FROM pg_settings "
5108 "WHERE name = 'restrict_nonsystem_relation_kind'",
5109 value);
5110 res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
5111
5112 PQclear(res);
5113 destroyPQExpBuffer(query);
5114}

References appendPQExpBuffer(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), ExecuteSqlQuery(), PGRES_TUPLES_OK, PQclear, and value.

Referenced by dumpTableData_copy(), dumpTableData_insert(), and setup_connection().

◆ setup_connection()

static void setup_connection ( Archive AH,
const char dumpencoding,
const char dumpsnapshot,
char use_role 
)
static

Definition at line 1429 of file pg_dump.c.

1431{
1432 DumpOptions *dopt = AH->dopt;
1433 PGconn *conn = GetConnection(AH);
1434
1436
1437 /*
1438 * Set the client encoding if requested.
1439 */
1440 if (dumpencoding)
1441 {
1443 pg_fatal("invalid client encoding \"%s\" specified",
1444 dumpencoding);
1445 }
1446
1447 /*
1448 * Force standard_conforming_strings on, just in case we are dumping from
1449 * an old server that has it disabled. Without this, literals in views,
1450 * expressions, etc, would be incorrect for modern servers.
1451 */
1452 ExecuteSqlStatement(AH, "SET standard_conforming_strings = on");
1453
1454 /*
1455 * And reflect that to AH->std_strings. You might think that we should
1456 * just delete that variable and the code that checks it, but that would
1457 * be problematic for pg_restore, which at least for now should still cope
1458 * with archives containing the other setting (cf. processStdStringsEntry
1459 * in pg_backup_archiver.c).
1460 */
1461 AH->std_strings = true;
1462
1463 /*
1464 * Get the active encoding, so we know how to escape strings.
1465 */
1468
1469 /*
1470 * Set the role if requested. In a parallel dump worker, we'll be passed
1471 * use_role == NULL, but AH->use_role is already set (if user specified it
1472 * originally) and we should use that.
1473 */
1474 if (!use_role && AH->use_role)
1475 use_role = AH->use_role;
1476
1477 /* Set the role if requested */
1478 if (use_role)
1479 {
1481
1482 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1483 ExecuteSqlStatement(AH, query->data);
1484 destroyPQExpBuffer(query);
1485
1486 /* save it for possible later use by parallel workers */
1487 if (!AH->use_role)
1488 AH->use_role = pg_strdup(use_role);
1489 }
1490
1491 /* Set the datestyle to ISO to ensure the dump's portability */
1492 ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1493
1494 /* Likewise, avoid using sql_standard intervalstyle */
1495 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1496
1497 /*
1498 * Use an explicitly specified extra_float_digits if it has been provided.
1499 * Otherwise, set extra_float_digits so that we can dump float data
1500 * exactly (given correctly implemented float I/O code, anyway).
1501 */
1503 {
1505
1506 appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1508 ExecuteSqlStatement(AH, q->data);
1510 }
1511 else
1512 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1513
1514 /*
1515 * Disable synchronized scanning, to prevent unpredictable changes in row
1516 * ordering across a dump and reload.
1517 */
1518 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1519
1520 /*
1521 * Disable timeouts if supported.
1522 */
1523 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1524 if (AH->remoteVersion >= 90300)
1525 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1526 if (AH->remoteVersion >= 90600)
1527 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1528 if (AH->remoteVersion >= 170000)
1529 ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
1530
1531 /*
1532 * Quote all identifiers, if requested.
1533 */
1535 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1536
1537 /*
1538 * Adjust row-security mode, if supported.
1539 */
1540 if (AH->remoteVersion >= 90500)
1541 {
1542 if (dopt->enable_row_security)
1543 ExecuteSqlStatement(AH, "SET row_security = on");
1544 else
1545 ExecuteSqlStatement(AH, "SET row_security = off");
1546 }
1547
1548 /*
1549 * For security reasons, we restrict the expansion of non-system views and
1550 * access to foreign tables during the pg_dump process. This restriction
1551 * is adjusted when dumping foreign table data.
1552 */
1553 set_restrict_relation_kind(AH, "view, foreign-table");
1554
1555 /*
1556 * Initialize prepared-query state to "nothing prepared". We do this here
1557 * so that a parallel dump worker will have its own state.
1558 */
1559 AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
1560
1561 /*
1562 * Start transaction-snapshot mode transaction to dump consistent data.
1563 */
1564 ExecuteSqlStatement(AH, "BEGIN");
1565
1566 /*
1567 * To support the combination of serializable_deferrable with the jobs
1568 * option we use REPEATABLE READ for the worker connections that are
1569 * passed a snapshot. As long as the snapshot is acquired in a
1570 * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1571 * REPEATABLE READ transaction provides the appropriate integrity
1572 * guarantees. This is a kluge, but safe for back-patching.
1573 */
1574 if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1576 "SET TRANSACTION ISOLATION LEVEL "
1577 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1578 else
1580 "SET TRANSACTION ISOLATION LEVEL "
1581 "REPEATABLE READ, READ ONLY");
1582
1583 /*
1584 * If user specified a snapshot to use, select that. In a parallel dump
1585 * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1586 * is already set (if the server can handle it) and we should use that.
1587 */
1588 if (dumpsnapshot)
1590
1591 if (AH->sync_snapshot_id)
1592 {
1594
1595 appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
1597 ExecuteSqlStatement(AH, query->data);
1598 destroyPQExpBuffer(query);
1599 }
1600 else if (AH->numWorkers > 1)
1601 {
1602 if (AH->isStandby && AH->remoteVersion < 100000)
1603 pg_fatal("parallel dumps from standby servers are not supported by this server version");
1605 }
1606}

References ALWAYS_SECURE_SEARCH_PATH_SQL, appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralConn(), conn, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), Archive::dopt, _dumpOptions::enable_row_security, Archive::encoding, ExecuteSqlQueryForSingleRow(), ExecuteSqlStatement(), extra_float_digits, fb(), fmtId(), get_synchronized_snapshot(), GetConnection(), have_extra_float_digits, Archive::is_prepared, Archive::isStandby, NUM_PREP_QUERIES, Archive::numWorkers, pg_fatal, pg_malloc0(), pg_strdup(), PQclear, PQclientEncoding(), PQsetClientEncoding(), quote_all_identifiers, Archive::remoteVersion, _dumpOptions::serializable_deferrable, set_restrict_relation_kind(), setFmtEncoding(), Archive::std_strings, Archive::sync_snapshot_id, and Archive::use_role.

Referenced by main(), and setupDumpWorker().

◆ setupDumpWorker()

static void setupDumpWorker ( Archive AH)
static

Definition at line 1610 of file pg_dump.c.

1611{
1612 /*
1613 * We want to re-select all the same values the leader connection is
1614 * using. We'll have inherited directly-usable values in
1615 * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1616 * inherited encoding value back to a string to pass to setup_connection.
1617 */
1620 NULL,
1621 NULL);
1622}

References Archive::encoding, fb(), pg_encoding_to_char, and setup_connection().

Referenced by CreateArchive(), and main().

◆ shouldPrintColumn()

bool shouldPrintColumn ( const DumpOptions dopt,
const TableInfo tbinfo,
int  colno 
)

Definition at line 10155 of file pg_dump.c.

10156{
10157 if (dopt->binary_upgrade)
10158 return true;
10159 if (tbinfo->attisdropped[colno])
10160 return false;
10161 return (tbinfo->attislocal[colno] || tbinfo->ispartition);
10162}

References _dumpOptions::binary_upgrade, and fb().

Referenced by dumpTableSchema(), flagInhAttrs(), and getTableAttrs().

◆ StaticAssertDecl()

StaticAssertDecl ( lengthof(SeqTypeNames = =(SEQTYPE_BIGINT+1),
"array length mismatch"   
)

Variable Documentation

◆ binaryUpgradeClassOids

BinaryUpgradeClassOidItem* binaryUpgradeClassOids = NULL
static

Definition at line 210 of file pg_dump.c.

Referenced by binary_upgrade_set_pg_class_oids(), and collectBinaryUpgradeClassOids().

◆ comments

◆ compression_algorithm

pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE
static

Definition at line 159 of file pg_dump.c.

Referenced by main().

◆ dosync

bool dosync = true
static

Definition at line 152 of file pg_dump.c.

Referenced by _allocAH(), CreateArchive(), and main().

◆ extension_exclude_oids

SimpleOidList extension_exclude_oids = {NULL, NULL}
static

Definition at line 189 of file pg_dump.c.

189{NULL, NULL};

Referenced by main(), processExtensionTables(), and selectDumpableExtension().

◆ extension_exclude_patterns

SimpleStringList extension_exclude_patterns = {NULL, NULL}
static

Definition at line 188 of file pg_dump.c.

188{NULL, NULL};

Referenced by main(), and read_dump_filters().

◆ extension_include_oids

SimpleOidList extension_include_oids = {NULL, NULL}
static

Definition at line 186 of file pg_dump.c.

186{NULL, NULL};

Referenced by main(), processExtensionTables(), and selectDumpableExtension().

◆ extension_include_patterns

SimpleStringList extension_include_patterns = {NULL, NULL}
static

Definition at line 185 of file pg_dump.c.

185{NULL, NULL};

Referenced by main(), and read_dump_filters().

◆ extra_float_digits

int extra_float_digits
static

Definition at line 195 of file pg_dump.c.

Referenced by main(), and setup_connection().

◆ foreign_servers_include_oids

SimpleOidList foreign_servers_include_oids = {NULL, NULL}
static

Definition at line 183 of file pg_dump.c.

183{NULL, NULL};

Referenced by main(), and makeTableDataInfo().

◆ foreign_servers_include_patterns

SimpleStringList foreign_servers_include_patterns = {NULL, NULL}
static

Definition at line 182 of file pg_dump.c.

182{NULL, NULL};

Referenced by main(), and read_dump_filters().

◆ g_last_builtin_oid

Oid g_last_builtin_oid
static

◆ have_extra_float_digits

bool have_extra_float_digits = false
static

Definition at line 194 of file pg_dump.c.

Referenced by main(), and setup_connection().

◆ lo_metadata_dumpId

DumpId lo_metadata_dumpId
static

Definition at line 221 of file pg_dump.c.

Referenced by getLOs(), and main().

◆ nbinaryUpgradeClassOids

int nbinaryUpgradeClassOids = 0
static

Definition at line 211 of file pg_dump.c.

Referenced by binary_upgrade_set_pg_class_oids(), and collectBinaryUpgradeClassOids().

◆ ncomments

int ncomments = 0
static

◆ nilCatalogId

◆ nrolenames

int nrolenames = 0
static

Definition at line 199 of file pg_dump.c.

Referenced by collectRoleNames(), and getRoleName().

◆ nseclabels

int nseclabels = 0
static

Definition at line 207 of file pg_dump.c.

Referenced by collectSecLabels(), and findSecLabels().

◆ nsequences

int nsequences = 0
static

Definition at line 215 of file pg_dump.c.

Referenced by collectSequences(), dumpSequence(), and dumpSequenceData().

◆ rolenames

RoleNameItem* rolenames = NULL
static

Definition at line 198 of file pg_dump.c.

Referenced by collectRoleNames(), and getRoleName().

◆ schema_exclude_oids

SimpleOidList schema_exclude_oids = {NULL, NULL}
static

Definition at line 170 of file pg_dump.c.

170{NULL, NULL};

Referenced by main(), processExtensionTables(), and selectDumpableNamespace().

◆ schema_exclude_patterns

SimpleStringList schema_exclude_patterns = {NULL, NULL}
static

Definition at line 169 of file pg_dump.c.

169{NULL, NULL};

Referenced by main(), and read_dump_filters().

◆ schema_include_oids

SimpleOidList schema_include_oids = {NULL, NULL}
static

Definition at line 168 of file pg_dump.c.

168{NULL, NULL};

Referenced by main(), and selectDumpableNamespace().

◆ schema_include_patterns

SimpleStringList schema_include_patterns = {NULL, NULL}
static

Definition at line 167 of file pg_dump.c.

167{NULL, NULL};

Referenced by main(), and read_dump_filters().

◆ seclabels

SecLabelItem* seclabels = NULL
static

Definition at line 206 of file pg_dump.c.

Referenced by collectSecLabels(), and findSecLabels().

◆ SeqTypeNames

const char* const SeqTypeNames[]
static
Initial value:
=
{
[SEQTYPE_SMALLINT] = "smallint",
[SEQTYPE_INTEGER] = "integer",
[SEQTYPE_BIGINT] = "bigint",
}

Definition at line 119 of file pg_dump.c.

120{
121 [SEQTYPE_SMALLINT] = "smallint",
122 [SEQTYPE_INTEGER] = "integer",
123 [SEQTYPE_BIGINT] = "bigint",
124};

Referenced by dumpSequence(), and parse_sequence_type().

◆ sequences

◆ strict_names

int strict_names = 0
static

◆ table_exclude_oids

SimpleOidList table_exclude_oids = {NULL, NULL}
static

Definition at line 177 of file pg_dump.c.

177{NULL, NULL};

Referenced by main(), processExtensionTables(), and selectDumpableTable().

◆ table_exclude_patterns

SimpleStringList table_exclude_patterns = {NULL, NULL}
static

Definition at line 175 of file pg_dump.c.

175{NULL, NULL};

Referenced by main(), and read_dump_filters().

◆ table_exclude_patterns_and_children

SimpleStringList table_exclude_patterns_and_children = {NULL, NULL}
static

Definition at line 176 of file pg_dump.c.

176{NULL, NULL};

Referenced by main(), and read_dump_filters().

◆ table_include_oids

SimpleOidList table_include_oids = {NULL, NULL}
static

Definition at line 174 of file pg_dump.c.

174{NULL, NULL};

Referenced by main(), processExtensionTables(), selectDumpableNamespace(), and selectDumpableTable().

◆ table_include_patterns

SimpleStringList table_include_patterns = {NULL, NULL}
static

Definition at line 172 of file pg_dump.c.

172{NULL, NULL};

Referenced by main(), and read_dump_filters().

◆ table_include_patterns_and_children

SimpleStringList table_include_patterns_and_children = {NULL, NULL}
static

Definition at line 173 of file pg_dump.c.

173{NULL, NULL};

Referenced by main(), and read_dump_filters().

◆ tabledata_exclude_oids

SimpleOidList tabledata_exclude_oids = {NULL, NULL}
static

Definition at line 180 of file pg_dump.c.

180{NULL, NULL};

Referenced by main(), and makeTableDataInfo().

◆ tabledata_exclude_patterns

SimpleStringList tabledata_exclude_patterns = {NULL, NULL}
static

Definition at line 178 of file pg_dump.c.

178{NULL, NULL};

Referenced by main(), and read_dump_filters().

◆ tabledata_exclude_patterns_and_children

SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL}
static

Definition at line 179 of file pg_dump.c.

179{NULL, NULL};

Referenced by main(), and read_dump_filters().