TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_dump.c
4 : * pg_dump is a utility for dumping out a postgres database
5 : * into a script file.
6 : *
7 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
8 : * Portions Copyright (c) 1994, Regents of the University of California
9 : *
10 : * pg_dump will read the system catalogs in a database and dump out a
11 : * script that reproduces the schema in terms of SQL that is understood
12 : * by PostgreSQL
13 : *
14 : * Note that pg_dump runs in a transaction-snapshot mode transaction,
15 : * so it sees a consistent snapshot of the database including system
16 : * catalogs. However, it relies in part on various specialized backend
17 : * functions like pg_get_indexdef(), and those things tend to look at
18 : * the currently committed state. So it is possible to get 'cache
19 : * lookup failed' error if someone performs DDL changes while a dump is
20 : * happening. The window for this sort of thing is from the acquisition
21 : * of the transaction snapshot to getSchemaData() (when pg_dump acquires
22 : * AccessShareLock on every table it intends to dump). It isn't very large,
23 : * but it can happen.
24 : *
25 : * http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
26 : *
27 : * IDENTIFICATION
28 : * src/bin/pg_dump/pg_dump.c
29 : *
30 : *-------------------------------------------------------------------------
31 : */
32 : #include "postgres_fe.h"
33 :
34 : #include <unistd.h>
35 : #include <ctype.h>
36 : #include <limits.h>
37 : #ifdef HAVE_TERMIOS_H
38 : #include <termios.h>
39 : #endif
40 :
41 : #include "access/attnum.h"
42 : #include "access/sysattr.h"
43 : #include "access/transam.h"
44 : #include "catalog/pg_aggregate_d.h"
45 : #include "catalog/pg_am_d.h"
46 : #include "catalog/pg_attribute_d.h"
47 : #include "catalog/pg_authid_d.h"
48 : #include "catalog/pg_cast_d.h"
49 : #include "catalog/pg_class_d.h"
50 : #include "catalog/pg_default_acl_d.h"
51 : #include "catalog/pg_largeobject_d.h"
52 : #include "catalog/pg_largeobject_metadata_d.h"
53 : #include "catalog/pg_proc_d.h"
54 : #include "catalog/pg_subscription.h"
55 : #include "catalog/pg_trigger_d.h"
56 : #include "catalog/pg_type_d.h"
57 : #include "common/connect.h"
58 : #include "common/relpath.h"
59 : #include "compress_io.h"
60 : #include "dumputils.h"
61 : #include "fe_utils/option_utils.h"
62 : #include "fe_utils/string_utils.h"
63 : #include "getopt_long.h"
64 : #include "libpq/libpq-fs.h"
65 : #include "parallel.h"
66 : #include "pg_backup_db.h"
67 : #include "pg_backup_utils.h"
68 : #include "pg_dump.h"
69 : #include "storage/block.h"
70 :
71 : typedef struct
72 : {
73 : Oid roleoid; /* role's OID */
74 : const char *rolename; /* role's name */
75 : } RoleNameItem;
76 :
77 : typedef struct
78 : {
79 : const char *descr; /* comment for an object */
80 : Oid classoid; /* object class (catalog OID) */
81 : Oid objoid; /* object OID */
82 : int objsubid; /* subobject (table column #) */
83 : } CommentItem;
84 :
85 : typedef struct
86 : {
87 : const char *provider; /* label provider of this security label */
88 : const char *label; /* security label for an object */
89 : Oid classoid; /* object class (catalog OID) */
90 : Oid objoid; /* object OID */
91 : int objsubid; /* subobject (table column #) */
92 : } SecLabelItem;
93 :
94 : typedef enum OidOptions
95 : {
96 : zeroIsError = 1,
97 : zeroAsStar = 2,
98 : zeroAsNone = 4
99 : } OidOptions;
100 :
101 : /* global decls */
102 : static bool dosync = true; /* Issue fsync() to make dump durable on disk. */
103 :
104 : static Oid g_last_builtin_oid; /* value of the last builtin oid */
105 :
106 : /* The specified names/patterns should to match at least one entity */
107 : static int strict_names = 0;
108 :
109 : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
110 :
111 : /*
112 : * Object inclusion/exclusion lists
113 : *
114 : * The string lists record the patterns given by command-line switches,
115 : * which we then convert to lists of OIDs of matching objects.
116 : */
117 : static SimpleStringList schema_include_patterns = {NULL, NULL};
118 : static SimpleOidList schema_include_oids = {NULL, NULL};
119 : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
120 : static SimpleOidList schema_exclude_oids = {NULL, NULL};
121 :
122 : static SimpleStringList table_include_patterns = {NULL, NULL};
123 : static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
124 : static SimpleOidList table_include_oids = {NULL, NULL};
125 : static SimpleStringList table_exclude_patterns = {NULL, NULL};
126 : static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
127 : static SimpleOidList table_exclude_oids = {NULL, NULL};
128 : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
129 : static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
130 : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
131 :
132 : static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
133 : static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
134 :
135 : static SimpleStringList extension_include_patterns = {NULL, NULL};
136 : static SimpleOidList extension_include_oids = {NULL, NULL};
137 :
138 : static const CatalogId nilCatalogId = {0, 0};
139 :
140 : /* override for standard extra_float_digits setting */
141 : static bool have_extra_float_digits = false;
142 : static int extra_float_digits;
143 :
144 : /* sorted table of role names */
145 : static RoleNameItem *rolenames = NULL;
146 : static int nrolenames = 0;
147 :
148 : /* sorted table of comments */
149 : static CommentItem *comments = NULL;
150 : static int ncomments = 0;
151 :
152 : /* sorted table of security labels */
153 : static SecLabelItem *seclabels = NULL;
154 : static int nseclabels = 0;
155 :
156 : /*
157 : * The default number of rows per INSERT when
158 : * --inserts is specified without --rows-per-insert
159 : */
160 : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
161 :
162 : /*
163 : * Macro for producing quoted, schema-qualified name of a dumpable object.
164 : */
165 : #define fmtQualifiedDumpable(obj) \
166 : fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
167 : (obj)->dobj.name)
168 :
169 : static void help(const char *progname);
170 : static void setup_connection(Archive *AH,
171 : const char *dumpencoding, const char *dumpsnapshot,
172 : char *use_role);
173 : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
174 : static void expand_schema_name_patterns(Archive *fout,
175 : SimpleStringList *patterns,
176 : SimpleOidList *oids,
177 : bool strict_names);
178 : static void expand_extension_name_patterns(Archive *fout,
179 : SimpleStringList *patterns,
180 : SimpleOidList *oids,
181 : bool strict_names);
182 : static void expand_foreign_server_name_patterns(Archive *fout,
183 : SimpleStringList *patterns,
184 : SimpleOidList *oids);
185 : static void expand_table_name_patterns(Archive *fout,
186 : SimpleStringList *patterns,
187 : SimpleOidList *oids,
188 : bool strict_names,
189 : bool with_child_tables);
190 : static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
191 : const char *pattern);
192 :
193 : static NamespaceInfo *findNamespace(Oid nsoid);
194 : static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
195 : static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
196 : static const char *getRoleName(const char *roleoid_str);
197 : static void collectRoleNames(Archive *fout);
198 : static void getAdditionalACLs(Archive *fout);
199 : static void dumpCommentExtended(Archive *fout, const char *type,
200 : const char *name, const char *namespace,
201 : const char *owner, CatalogId catalogId,
202 : int subid, DumpId dumpId,
203 : const char *initdb_comment);
204 : static inline void dumpComment(Archive *fout, const char *type,
205 : const char *name, const char *namespace,
206 : const char *owner, CatalogId catalogId,
207 : int subid, DumpId dumpId);
208 : static int findComments(Oid classoid, Oid objoid, CommentItem **items);
209 : static void collectComments(Archive *fout);
210 : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
211 : const char *namespace, const char *owner,
212 : CatalogId catalogId, int subid, DumpId dumpId);
213 : static int findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
214 : static void collectSecLabels(Archive *fout);
215 : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
216 : static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
217 : static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
218 : static void dumpType(Archive *fout, const TypeInfo *tyinfo);
219 : static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
220 : static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
221 : static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
222 : static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
223 : static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
224 : static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
225 : static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
226 : PGresult *res);
227 : static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
228 : static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
229 : static void dumpFunc(Archive *fout, const FuncInfo *finfo);
230 : static void dumpCast(Archive *fout, const CastInfo *cast);
231 : static void dumpTransform(Archive *fout, const TransformInfo *transform);
232 : static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
233 : static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
234 : static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
235 : static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
236 : static void dumpCollation(Archive *fout, const CollInfo *collinfo);
237 : static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
238 : static void dumpRule(Archive *fout, const RuleInfo *rinfo);
239 : static void dumpAgg(Archive *fout, const AggInfo *agginfo);
240 : static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
241 : static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
242 : static void dumpTable(Archive *fout, const TableInfo *tbinfo);
243 : static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
244 : static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
245 : static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
246 : static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
247 : static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
248 : static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
249 : static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
250 : static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
251 : static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
252 : static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
253 : static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
254 : static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
255 : static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
256 : static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
257 : static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
258 : static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
259 : static void dumpUserMappings(Archive *fout,
260 : const char *servername, const char *namespace,
261 : const char *owner, CatalogId catalogId, DumpId dumpId);
262 : static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
263 :
264 : static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
265 : const char *type, const char *name, const char *subname,
266 : const char *nspname, const char *owner,
267 : const DumpableAcl *dacl);
268 :
269 : static void getDependencies(Archive *fout);
270 : static void BuildArchiveDependencies(Archive *fout);
271 : static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
272 : DumpId **dependencies, int *nDeps, int *allocDeps);
273 :
274 : static DumpableObject *createBoundaryObjects(void);
275 : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
276 : DumpableObject *boundaryObjs);
277 :
278 : static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
279 : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
280 : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
281 : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
282 : static void buildMatViewRefreshDependencies(Archive *fout);
283 : static void getTableDataFKConstraints(void);
284 : static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
285 : bool is_agg);
286 : static char *format_function_signature(Archive *fout,
287 : const FuncInfo *finfo, bool honor_quotes);
288 : static char *convertRegProcReference(const char *proc);
289 : static char *getFormattedOperatorName(const char *oproid);
290 : static char *convertTSFunction(Archive *fout, Oid funcOid);
291 : static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
292 : static void getLOs(Archive *fout);
293 : static void dumpLO(Archive *fout, const LoInfo *binfo);
294 : static int dumpLOs(Archive *fout, const void *arg);
295 : static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
296 : static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
297 : static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
298 : static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
299 : static void dumpDatabase(Archive *fout);
300 : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
301 : const char *dbname, Oid dboid);
302 : static void dumpEncoding(Archive *AH);
303 : static void dumpStdStrings(Archive *AH);
304 : static void dumpSearchPath(Archive *AH);
305 : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
306 : PQExpBuffer upgrade_buffer,
307 : Oid pg_type_oid,
308 : bool force_array_type,
309 : bool include_multirange_type);
310 : static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
311 : PQExpBuffer upgrade_buffer,
312 : const TableInfo *tbinfo);
313 : static void binary_upgrade_set_pg_class_oids(Archive *fout,
314 : PQExpBuffer upgrade_buffer,
315 : Oid pg_class_oid, bool is_index);
316 : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
317 : const DumpableObject *dobj,
318 : const char *objtype,
319 : const char *objname,
320 : const char *objnamespace);
321 : static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
322 : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
323 : static bool nonemptyReloptions(const char *reloptions);
324 : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
325 : const char *prefix, Archive *fout);
326 : static char *get_synchronized_snapshot(Archive *fout);
327 : static void setupDumpWorker(Archive *AH);
328 : static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
329 : static bool forcePartitionRootLoad(const TableInfo *tbinfo);
330 :
331 :
332 : int
333 GIC 181 : main(int argc, char **argv)
334 : {
335 : int c;
336 181 : const char *filename = NULL;
337 181 : const char *format = "p";
338 : TableInfo *tblinfo;
339 : int numTables;
340 : DumpableObject **dobjs;
341 : int numObjs;
342 ECB : DumpableObject *boundaryObjs;
343 : int i;
344 : int optindex;
345 : RestoreOptions *ropt;
346 : Archive *fout; /* the script file */
347 GIC 181 : bool g_verbose = false;
348 181 : const char *dumpencoding = NULL;
349 181 : const char *dumpsnapshot = NULL;
350 181 : char *use_role = NULL;
351 181 : int numWorkers = 1;
352 181 : int plainText = 0;
353 181 : ArchiveFormat archiveFormat = archUnknown;
354 : ArchiveMode archiveMode;
355 GNC 181 : pg_compress_specification compression_spec = {0};
356 181 : char *compression_detail = NULL;
357 181 : char *compression_algorithm_str = "none";
358 181 : char *error_detail = NULL;
359 181 : bool user_compression_defined = false;
360 ECB :
361 : static DumpOptions dopt;
362 :
363 : static struct option long_options[] = {
364 : {"data-only", no_argument, NULL, 'a'},
365 : {"blobs", no_argument, NULL, 'b'},
366 : {"large-objects", no_argument, NULL, 'b'},
367 : {"no-blobs", no_argument, NULL, 'B'},
368 : {"no-large-objects", no_argument, NULL, 'B'},
369 : {"clean", no_argument, NULL, 'c'},
370 : {"create", no_argument, NULL, 'C'},
371 : {"dbname", required_argument, NULL, 'd'},
372 : {"extension", required_argument, NULL, 'e'},
373 : {"file", required_argument, NULL, 'f'},
374 : {"format", required_argument, NULL, 'F'},
375 : {"host", required_argument, NULL, 'h'},
376 : {"jobs", 1, NULL, 'j'},
377 : {"no-reconnect", no_argument, NULL, 'R'},
378 : {"no-owner", no_argument, NULL, 'O'},
379 : {"port", required_argument, NULL, 'p'},
380 : {"schema", required_argument, NULL, 'n'},
381 : {"exclude-schema", required_argument, NULL, 'N'},
382 : {"schema-only", no_argument, NULL, 's'},
383 : {"superuser", required_argument, NULL, 'S'},
384 : {"table", required_argument, NULL, 't'},
385 : {"exclude-table", required_argument, NULL, 'T'},
386 : {"no-password", no_argument, NULL, 'w'},
387 : {"password", no_argument, NULL, 'W'},
388 : {"username", required_argument, NULL, 'U'},
389 : {"verbose", no_argument, NULL, 'v'},
390 : {"no-privileges", no_argument, NULL, 'x'},
391 : {"no-acl", no_argument, NULL, 'x'},
392 : {"compress", required_argument, NULL, 'Z'},
393 : {"encoding", required_argument, NULL, 'E'},
394 : {"help", no_argument, NULL, '?'},
395 : {"version", no_argument, NULL, 'V'},
396 :
397 : /*
398 : * the following options don't have an equivalent short option letter
399 : */
400 : {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
401 : {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
402 : {"column-inserts", no_argument, &dopt.column_inserts, 1},
403 : {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
404 : {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
405 : {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
406 : {"exclude-table-data", required_argument, NULL, 4},
407 : {"extra-float-digits", required_argument, NULL, 8},
408 : {"if-exists", no_argument, &dopt.if_exists, 1},
409 : {"inserts", no_argument, NULL, 9},
410 : {"lock-wait-timeout", required_argument, NULL, 2},
411 : {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
412 : {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
413 : {"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
414 : {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
415 : {"role", required_argument, NULL, 3},
416 : {"section", required_argument, NULL, 5},
417 : {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
418 : {"snapshot", required_argument, NULL, 6},
419 : {"strict-names", no_argument, &strict_names, 1},
420 : {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
421 : {"no-comments", no_argument, &dopt.no_comments, 1},
422 : {"no-publications", no_argument, &dopt.no_publications, 1},
423 : {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
424 : {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
425 : {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
426 : {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
427 : {"no-sync", no_argument, NULL, 7},
428 : {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
429 : {"rows-per-insert", required_argument, NULL, 10},
430 : {"include-foreign-data", required_argument, NULL, 11},
431 : {"table-and-children", required_argument, NULL, 12},
432 : {"exclude-table-and-children", required_argument, NULL, 13},
433 : {"exclude-table-data-and-children", required_argument, NULL, 14},
434 :
435 : {NULL, 0, NULL, 0}
436 : };
437 :
438 GIC 181 : pg_logging_init(argv[0]);
439 181 : pg_logging_set_level(PG_LOG_WARNING);
440 181 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
441 :
442 : /*
443 : * Initialize what we need for parallel execution, especially for thread
444 : * support on Windows.
445 : */
446 181 : init_parallel_dump_utils();
447 :
448 181 : progname = get_progname(argv[0]);
449 :
450 181 : if (argc > 1)
451 : {
452 181 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
453 : {
454 1 : help(progname);
455 1 : exit_nicely(0);
456 ECB : }
457 CBC 180 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
458 ECB : {
459 GIC 30 : puts("pg_dump (PostgreSQL) " PG_VERSION);
460 30 : exit_nicely(0);
461 : }
462 : }
463 :
464 CBC 150 : InitDumpOptions(&dopt);
465 :
466 627 : while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
467 GIC 627 : long_options, &optindex)) != -1)
468 ECB : {
469 GIC 481 : switch (c)
470 ECB : {
471 GIC 8 : case 'a': /* Dump data only */
472 CBC 8 : dopt.dataOnly = true;
473 8 : break;
474 :
475 GNC 1 : case 'b': /* Dump LOs */
476 1 : dopt.outputLOs = true;
477 CBC 1 : break;
478 ECB :
479 GNC 2 : case 'B': /* Don't dump LOs */
480 2 : dopt.dontOutputLOs = true;
481 GIC 2 : break;
482 ECB :
483 GIC 6 : case 'c': /* clean (i.e., drop) schema prior to create */
484 CBC 6 : dopt.outputClean = 1;
485 6 : break;
486 :
487 25 : case 'C': /* Create DB */
488 GIC 25 : dopt.outputCreateDB = 1;
489 CBC 25 : break;
490 ECB :
491 CBC 4 : case 'd': /* database name */
492 GIC 4 : dopt.cparams.dbname = pg_strdup(optarg);
493 CBC 4 : break;
494 ECB :
495 CBC 4 : case 'e': /* include extension(s) */
496 GIC 4 : simple_string_list_append(&extension_include_patterns, optarg);
497 CBC 4 : dopt.include_everything = false;
498 4 : break;
499 ECB :
500 GIC 2 : case 'E': /* Dump encoding */
501 CBC 2 : dumpencoding = pg_strdup(optarg);
502 2 : break;
503 ECB :
504 GIC 110 : case 'f':
505 CBC 110 : filename = pg_strdup(optarg);
506 110 : break;
507 ECB :
508 GIC 71 : case 'F':
509 CBC 71 : format = pg_strdup(optarg);
510 71 : break;
511 ECB :
512 GIC 6 : case 'h': /* server host */
513 CBC 6 : dopt.cparams.pghost = pg_strdup(optarg);
514 6 : break;
515 ECB :
516 CBC 12 : case 'j': /* number of dump jobs */
517 GIC 12 : if (!option_parse_int(optarg, "-j/--jobs", 1,
518 ECB : PG_MAX_JOBS,
519 : &numWorkers))
520 CBC 1 : exit_nicely(1);
521 GIC 11 : break;
522 ECB :
523 CBC 14 : case 'n': /* include schema(s) */
524 14 : simple_string_list_append(&schema_include_patterns, optarg);
525 GIC 14 : dopt.include_everything = false;
526 CBC 14 : break;
527 ECB :
528 CBC 1 : case 'N': /* exclude schema(s) */
529 GIC 1 : simple_string_list_append(&schema_exclude_patterns, optarg);
530 CBC 1 : break;
531 ECB :
532 CBC 2 : case 'O': /* Don't reconnect to match owner */
533 GIC 2 : dopt.outputNoOwner = 1;
534 CBC 2 : break;
535 ECB :
536 GIC 15 : case 'p': /* server port */
537 15 : dopt.cparams.pgport = pg_strdup(optarg);
538 CBC 15 : break;
539 ECB :
540 GIC 2 : case 'R':
541 ECB : /* no-op, still accepted for backwards compatibility */
542 CBC 2 : break;
543 ECB :
544 CBC 12 : case 's': /* dump schema only */
545 GIC 12 : dopt.schemaOnly = true;
546 CBC 12 : break;
547 ECB :
548 CBC 1 : case 'S': /* Username for superuser in plain text output */
549 GIC 1 : dopt.outputSuperuser = pg_strdup(optarg);
550 CBC 1 : break;
551 ECB :
552 CBC 8 : case 't': /* include table(s) */
553 GIC 8 : simple_string_list_append(&table_include_patterns, optarg);
554 CBC 8 : dopt.include_everything = false;
555 8 : break;
556 ECB :
557 GIC 2 : case 'T': /* exclude table(s) */
558 CBC 2 : simple_string_list_append(&table_exclude_patterns, optarg);
559 GIC 2 : break;
560 ECB :
561 GIC 7 : case 'U':
562 CBC 7 : dopt.cparams.username = pg_strdup(optarg);
563 7 : break;
564 ECB :
565 GIC 6 : case 'v': /* verbose */
566 CBC 6 : g_verbose = true;
567 6 : pg_logging_increase_verbosity();
568 6 : break;
569 :
570 1 : case 'w':
571 1 : dopt.cparams.promptPassword = TRI_NO;
572 1 : break;
573 ECB :
574 UIC 0 : case 'W':
575 LBC 0 : dopt.cparams.promptPassword = TRI_YES;
576 0 : break;
577 ECB :
578 GIC 2 : case 'x': /* skip ACL dump */
579 CBC 2 : dopt.aclsSkip = true;
580 2 : break;
581 ECB :
582 GNC 15 : case 'Z': /* Compression */
583 15 : parse_compress_options(optarg, &compression_algorithm_str,
584 : &compression_detail);
585 15 : user_compression_defined = true;
586 CBC 15 : break;
587 :
588 29 : case 0:
589 ECB : /* This covers the long options. */
590 CBC 29 : break;
591 :
592 GBC 2 : case 2: /* lock-wait-timeout */
593 2 : dopt.lockWaitTimeout = pg_strdup(optarg);
594 2 : break;
595 :
596 CBC 3 : case 3: /* SET ROLE */
597 3 : use_role = pg_strdup(optarg);
598 3 : break;
599 :
600 1 : case 4: /* exclude table(s) data */
601 1 : simple_string_list_append(&tabledata_exclude_patterns, optarg);
602 GIC 1 : break;
603 ECB :
604 CBC 6 : case 5: /* section */
605 GIC 6 : set_dump_section(optarg, &dopt.dumpSections);
606 CBC 6 : break;
607 :
608 LBC 0 : case 6: /* snapshot */
609 UIC 0 : dumpsnapshot = pg_strdup(optarg);
610 LBC 0 : break;
611 ECB :
612 CBC 88 : case 7: /* no-sync */
613 GIC 88 : dosync = false;
614 CBC 88 : break;
615 ECB :
616 CBC 1 : case 8:
617 GIC 1 : have_extra_float_digits = true;
618 CBC 1 : if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
619 ECB : &extra_float_digits))
620 CBC 1 : exit_nicely(1);
621 UIC 0 : break;
622 ECB :
623 CBC 2 : case 9: /* inserts */
624 ECB :
625 : /*
626 EUB : * dump_inserts also stores --rows-per-insert, careful not to
627 : * overwrite that.
628 : */
629 GIC 2 : if (dopt.dump_inserts == 0)
630 CBC 2 : dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
631 2 : break;
632 ECB :
633 GIC 2 : case 10: /* rows per insert */
634 CBC 2 : if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
635 ECB : &dopt.dump_inserts))
636 CBC 1 : exit_nicely(1);
637 GIC 1 : break;
638 ECB :
639 GBC 4 : case 11: /* include foreign data */
640 GIC 4 : simple_string_list_append(&foreign_servers_include_patterns,
641 ECB : optarg);
642 GIC 4 : break;
643 :
644 GNC 1 : case 12: /* include table(s) and their children */
645 1 : simple_string_list_append(&table_include_patterns_and_children,
646 : optarg);
647 1 : dopt.include_everything = false;
648 1 : break;
649 :
650 1 : case 13: /* exclude table(s) and their children */
651 1 : simple_string_list_append(&table_exclude_patterns_and_children,
652 : optarg);
653 1 : break;
654 :
655 1 : case 14: /* exclude data of table(s) and children */
656 1 : simple_string_list_append(&tabledata_exclude_patterns_and_children,
657 : optarg);
658 1 : break;
659 :
660 GIC 1 : default:
661 : /* getopt_long already emitted a complaint */
662 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
663 CBC 1 : exit_nicely(1);
664 ECB : }
665 : }
666 :
667 : /*
668 : * Non-option argument specifies database name as long as it wasn't
669 : * already specified with -d / --dbname
670 : */
671 CBC 146 : if (optind < argc && dopt.cparams.dbname == NULL)
672 GIC 116 : dopt.cparams.dbname = argv[optind++];
673 ECB :
674 : /* Complain if any arguments remain */
675 GIC 146 : if (optind < argc)
676 ECB : {
677 GIC 1 : pg_log_error("too many command-line arguments (first is \"%s\")",
678 ECB : argv[optind]);
679 CBC 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
680 GIC 1 : exit_nicely(1);
681 ECB : }
682 :
683 : /* --column-inserts implies --inserts */
684 CBC 145 : if (dopt.column_inserts && dopt.dump_inserts == 0)
685 1 : dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
686 :
687 ECB : /*
688 : * Binary upgrade mode implies dumping sequence data even in schema-only
689 : * mode. This is not exposed as a separate option, but kept separate
690 : * internally for clarity.
691 : */
692 CBC 145 : if (dopt.binary_upgrade)
693 GIC 8 : dopt.sequence_data = 1;
694 ECB :
695 GIC 145 : if (dopt.dataOnly && dopt.schemaOnly)
696 CBC 1 : pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
697 ECB :
698 GIC 144 : if (dopt.schemaOnly && foreign_servers_include_patterns.head != NULL)
699 1 : pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
700 :
701 143 : if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
702 1 : pg_fatal("option --include-foreign-data is not supported with parallel backup");
703 :
704 142 : if (dopt.dataOnly && dopt.outputClean)
705 CBC 1 : pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
706 ECB :
707 GIC 141 : if (dopt.if_exists && !dopt.outputClean)
708 1 : pg_fatal("option --if-exists requires option -c/--clean");
709 ECB :
710 : /*
711 : * --inserts are already implied above if --column-inserts or
712 : * --rows-per-insert were specified.
713 : */
714 CBC 140 : if (dopt.do_nothing && dopt.dump_inserts == 0)
715 GIC 1 : pg_fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
716 :
717 : /* Identify archive format to emit */
718 CBC 139 : archiveFormat = parseArchiveFormat(format, &archiveMode);
719 ECB :
720 : /* archiveFormat specific setup */
721 GIC 138 : if (archiveFormat == archNull)
722 112 : plainText = 1;
723 :
724 : /*
725 : * Compression options
726 : */
727 GNC 138 : if (!parse_compress_algorithm(compression_algorithm_str,
728 : &compression_algorithm))
729 1 : pg_fatal("unrecognized compression algorithm: \"%s\"",
730 : compression_algorithm_str);
731 :
732 137 : parse_compress_specification(compression_algorithm, compression_detail,
733 : &compression_spec);
734 137 : error_detail = validate_compress_specification(&compression_spec);
735 137 : if (error_detail != NULL)
736 3 : pg_fatal("invalid compression specification: %s",
737 : error_detail);
738 :
739 134 : error_detail = supports_compression(compression_spec);
740 134 : if (error_detail != NULL)
741 UNC 0 : pg_fatal("%s", error_detail);
742 :
743 : /*
744 : * Disable support for zstd workers for now - these are based on threading,
745 : * and it's unclear how it interacts with parallel dumps on platforms where
746 : * that relies on threads too (e.g. Windows).
747 : */
748 GNC 134 : if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
749 UNC 0 : pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
750 : "workers");
751 :
752 : /*
753 : * Custom and directory formats are compressed by default with gzip when
754 : * available, not the others.
755 : */
756 GNC 134 : if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
757 23 : !user_compression_defined)
758 ECB : {
759 : #ifdef HAVE_LIBZ
760 GNC 16 : parse_compress_specification(PG_COMPRESSION_GZIP, NULL,
761 : &compression_spec);
762 : #else
763 : /* Nothing to do in the default case */
764 : #endif
765 ECB : }
766 :
767 : /*
768 : * If emitting an archive format, we always want to emit a DATABASE item,
769 : * in case --create is specified at pg_restore time.
770 : */
771 GIC 134 : if (!plainText)
772 26 : dopt.outputCreateDB = 1;
773 :
774 ECB : /* Parallel backup only in the directory archive format so far */
775 CBC 134 : if (archiveFormat != archDirectory && numWorkers > 1)
776 GIC 1 : pg_fatal("parallel backup only supported by the directory format");
777 :
778 ECB : /* Open the output file */
779 GNC 133 : fout = CreateArchive(filename, archiveFormat, compression_spec,
780 : dosync, archiveMode, setupDumpWorker);
781 ECB :
782 : /* Make dump options accessible right away */
783 GIC 132 : SetArchiveOptions(fout, &dopt, NULL);
784 :
785 : /* Register the cleanup hook */
786 132 : on_exit_close_archive(fout);
787 ECB :
788 : /* Let the archiver know how noisy to be */
789 CBC 132 : fout->verbose = g_verbose;
790 :
791 :
792 ECB : /*
793 : * We allow the server to be back to 9.2, and up to any minor release of
794 : * our own major version. (See also version check in pg_dumpall.c.)
795 : */
796 CBC 132 : fout->minRemoteVersion = 90200;
797 GIC 132 : fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
798 :
799 CBC 132 : fout->numWorkers = numWorkers;
800 ECB :
801 EUB : /*
802 : * Open the database using the Archiver, so it knows about it. Errors mean
803 : * death.
804 : */
805 GIC 132 : ConnectDatabase(fout, &dopt.cparams, false);
806 131 : setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
807 :
808 ECB : /*
809 EUB : * On hot standbys, never try to dump unlogged table data, since it will
810 : * just throw an error.
811 : */
812 GIC 131 : if (fout->isStandby)
813 3 : dopt.no_unlogged_table_data = true;
814 :
815 : /*
816 ECB : * Find the last built-in OID, if needed (prior to 8.1)
817 : *
818 : * With 8.1 and above, we can just use FirstNormalObjectId - 1.
819 : */
820 CBC 131 : g_last_builtin_oid = FirstNormalObjectId - 1;
821 :
822 GIC 131 : pg_log_info("last built-in OID is %u", g_last_builtin_oid);
823 :
824 : /* Expand schema selection patterns into OID lists */
825 131 : if (schema_include_patterns.head != NULL)
826 : {
827 14 : expand_schema_name_patterns(fout, &schema_include_patterns,
828 : &schema_include_oids,
829 : strict_names);
830 8 : if (schema_include_oids.head == NULL)
831 CBC 1 : pg_fatal("no matching schemas were found");
832 ECB : }
833 GIC 124 : expand_schema_name_patterns(fout, &schema_exclude_patterns,
834 : &schema_exclude_oids,
835 ECB : false);
836 : /* non-matching exclusion patterns aren't an error */
837 :
838 : /* Expand table selection patterns into OID lists */
839 GNC 124 : expand_table_name_patterns(fout, &table_include_patterns,
840 : &table_include_oids,
841 : strict_names, false);
842 120 : expand_table_name_patterns(fout, &table_include_patterns_and_children,
843 : &table_include_oids,
844 : strict_names, true);
845 120 : if ((table_include_patterns.head != NULL ||
846 117 : table_include_patterns_and_children.head != NULL) &&
847 4 : table_include_oids.head == NULL)
848 1 : pg_fatal("no matching tables were found");
849 :
850 GIC 119 : expand_table_name_patterns(fout, &table_exclude_patterns,
851 : &table_exclude_oids,
852 : false, false);
853 GNC 119 : expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
854 : &table_exclude_oids,
855 : false, true);
856 :
857 GIC 119 : expand_table_name_patterns(fout, &tabledata_exclude_patterns,
858 : &tabledata_exclude_oids,
859 : false, false);
860 GNC 119 : expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
861 : &tabledata_exclude_oids,
862 : false, true);
863 :
864 GIC 119 : expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
865 ECB : &foreign_servers_include_oids);
866 :
867 : /* non-matching exclusion patterns aren't an error */
868 :
869 : /* Expand extension selection patterns into OID lists */
870 GIC 119 : if (extension_include_patterns.head != NULL)
871 : {
872 4 : expand_extension_name_patterns(fout, &extension_include_patterns,
873 : &extension_include_oids,
874 ECB : strict_names);
875 CBC 4 : if (extension_include_oids.head == NULL)
876 UIC 0 : pg_fatal("no matching extensions were found");
877 : }
878 :
879 : /*
880 : * Dumping LOs is the default for dumps where an inclusion switch is not
881 : * used (an "include everything" dump). -B can be used to exclude LOs
882 : * from those dumps. -b can be used to include LOs even when an
883 : * inclusion switch is used.
884 : *
885 : * -s means "schema only" and LOs are data, not schema, so we never
886 : * include LOs when -s is used.
887 : */
888 GNC 119 : if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputLOs)
889 96 : dopt.outputLOs = true;
890 :
891 ECB : /*
892 : * Collect role names so we can map object owner OIDs to names.
893 : */
894 CBC 119 : collectRoleNames(fout);
895 :
896 ECB : /*
897 : * Now scan the database and create DumpableObject structs for all the
898 : * objects we intend to dump.
899 : */
900 CBC 119 : tblinfo = getSchemaData(fout, &numTables);
901 :
902 118 : if (!dopt.schemaOnly)
903 : {
904 GIC 108 : getTableData(&dopt, tblinfo, numTables, 0);
905 108 : buildMatViewRefreshDependencies(fout);
906 108 : if (dopt.dataOnly)
907 6 : getTableDataFKConstraints();
908 ECB : }
909 :
910 GIC 118 : if (dopt.schemaOnly && dopt.sequence_data)
911 CBC 8 : getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
912 :
913 : /*
914 : * In binary-upgrade mode, we do not have to worry about the actual LO
915 ECB : * data or the associated metadata that resides in the pg_largeobject and
916 : * pg_largeobject_metadata tables, respectively.
917 : *
918 : * However, we do need to collect LO information as there may be
919 : * comments or other information on LOs that we do need to dump out.
920 : */
921 GNC 118 : if (dopt.outputLOs || dopt.binary_upgrade)
922 104 : getLOs(fout);
923 :
924 : /*
925 : * Collect dependency data to assist in ordering the objects.
926 ECB : */
927 GIC 118 : getDependencies(fout);
928 :
929 ECB : /*
930 : * Collect ACLs, comments, and security labels, if wanted.
931 : */
932 GIC 118 : if (!dopt.aclsSkip)
933 CBC 116 : getAdditionalACLs(fout);
934 GIC 118 : if (!dopt.no_comments)
935 118 : collectComments(fout);
936 118 : if (!dopt.no_security_labels)
937 118 : collectSecLabels(fout);
938 :
939 ECB : /* Lastly, create dummy objects to represent the section boundaries */
940 GIC 118 : boundaryObjs = createBoundaryObjects();
941 ECB :
942 : /* Get pointers to all the known DumpableObjects */
943 GIC 118 : getDumpableObjects(&dobjs, &numObjs);
944 ECB :
945 EUB : /*
946 : * Add dummy dependencies to enforce the dump section ordering.
947 : */
948 GIC 118 : addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
949 :
950 : /*
951 : * Sort the objects into a safe dump order (no forward references).
952 : *
953 : * We rely on dependency information to help us determine a safe order, so
954 : * the initial sort is mostly for cosmetic purposes: we sort by name to
955 : * ensure that logically identical schemas will dump identically.
956 : */
957 CBC 118 : sortDumpableObjectsByTypeName(dobjs, numObjs);
958 ECB :
959 GIC 118 : sortDumpableObjects(dobjs, numObjs,
960 118 : boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
961 :
962 : /*
963 ECB : * Create archive TOC entries for all the objects to be dumped, in a safe
964 : * order.
965 : */
966 :
967 : /*
968 : * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
969 : */
970 GIC 118 : dumpEncoding(fout);
971 CBC 118 : dumpStdStrings(fout);
972 GIC 118 : dumpSearchPath(fout);
973 ECB :
974 : /* The database items are always next, unless we don't want them at all */
975 CBC 118 : if (dopt.outputCreateDB)
976 50 : dumpDatabase(fout);
977 :
978 : /* Now the rearrangeable objects. */
979 510138 : for (i = 0; i < numObjs; i++)
980 510020 : dumpDumpableObject(fout, dobjs[i]);
981 :
982 : /*
983 : * Set up options info to ensure we dump what we want.
984 : */
985 GIC 118 : ropt = NewRestoreOptions();
986 118 : ropt->filename = filename;
987 :
988 : /* if you change this list, see dumpOptionsFromRestoreOptions */
989 118 : ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
990 CBC 118 : ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
991 118 : ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
992 GIC 118 : ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
993 118 : ropt->cparams.promptPassword = dopt.cparams.promptPassword;
994 118 : ropt->dropSchema = dopt.outputClean;
995 118 : ropt->dataOnly = dopt.dataOnly;
996 CBC 118 : ropt->schemaOnly = dopt.schemaOnly;
997 GIC 118 : ropt->if_exists = dopt.if_exists;
998 118 : ropt->column_inserts = dopt.column_inserts;
999 118 : ropt->dumpSections = dopt.dumpSections;
1000 118 : ropt->aclsSkip = dopt.aclsSkip;
1001 CBC 118 : ropt->superuser = dopt.outputSuperuser;
1002 118 : ropt->createDB = dopt.outputCreateDB;
1003 118 : ropt->noOwner = dopt.outputNoOwner;
1004 118 : ropt->noTableAm = dopt.outputNoTableAm;
1005 118 : ropt->noTablespace = dopt.outputNoTablespaces;
1006 118 : ropt->disable_triggers = dopt.disable_triggers;
1007 GIC 118 : ropt->use_setsessauth = dopt.use_setsessauth;
1008 118 : ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
1009 CBC 118 : ropt->dump_inserts = dopt.dump_inserts;
1010 GIC 118 : ropt->no_comments = dopt.no_comments;
1011 118 : ropt->no_publications = dopt.no_publications;
1012 CBC 118 : ropt->no_security_labels = dopt.no_security_labels;
1013 GIC 118 : ropt->no_subscriptions = dopt.no_subscriptions;
1014 118 : ropt->lockWaitTimeout = dopt.lockWaitTimeout;
1015 118 : ropt->include_everything = dopt.include_everything;
1016 118 : ropt->enable_row_security = dopt.enable_row_security;
1017 CBC 118 : ropt->sequence_data = dopt.sequence_data;
1018 GIC 118 : ropt->binary_upgrade = dopt.binary_upgrade;
1019 :
1020 GNC 118 : ropt->compression_spec = compression_spec;
1021 :
1022 GIC 118 : ropt->suppressDumpWarnings = true; /* We've already shown them */
1023 ECB :
1024 GIC 118 : SetArchiveOptions(fout, &dopt, ropt);
1025 ECB :
1026 : /* Mark which entries should be output */
1027 GIC 118 : ProcessArchiveRestoreOptions(fout);
1028 :
1029 : /*
1030 : * The archive's TOC entries are now marked as to which ones will actually
1031 : * be output, so we can set up their dependency lists properly. This isn't
1032 : * necessary for plain-text output, though.
1033 : */
1034 118 : if (!plainText)
1035 25 : BuildArchiveDependencies(fout);
1036 ECB :
1037 : /*
1038 : * And finally we can do the actual output.
1039 : *
1040 : * Note: for non-plain-text output formats, the output file is written
1041 : * inside CloseArchive(). This is, um, bizarre; but not worth changing
1042 : * right now.
1043 : */
1044 GIC 118 : if (plainText)
1045 CBC 93 : RestoreArchive(fout);
1046 ECB :
1047 GIC 117 : CloseArchive(fout);
1048 :
1049 117 : exit_nicely(0);
1050 : }
1051 ECB :
1052 :
1053 : static void
1054 GIC 1 : help(const char *progname)
1055 ECB : {
1056 CBC 1 : printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
1057 1 : printf(_("Usage:\n"));
1058 1 : printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
1059 ECB :
1060 CBC 1 : printf(_("\nGeneral options:\n"));
1061 1 : printf(_(" -f, --file=FILENAME output file or directory name\n"));
1062 1 : printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
1063 ECB : " plain text (default))\n"));
1064 CBC 1 : printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
1065 1 : printf(_(" -v, --verbose verbose mode\n"));
1066 1 : printf(_(" -V, --version output version information, then exit\n"));
1067 GNC 1 : printf(_(" -Z, --compress=METHOD[:LEVEL]\n"
1068 : " compress as specified\n"));
1069 CBC 1 : printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
1070 1 : printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
1071 1 : printf(_(" -?, --help show this help, then exit\n"));
1072 ECB :
1073 CBC 1 : printf(_("\nOptions controlling the output content:\n"));
1074 1 : printf(_(" -a, --data-only dump only the data, not the schema\n"));
1075 GNC 1 : printf(_(" -b, --large-objects include large objects in dump\n"
1076 : " --blobs (same as --large-objects, deprecated)\n"));
1077 1 : printf(_(" -B, --no-large-objects exclude large objects in dump\n"
1078 : " --no-blobs (same as --no-large-objects, deprecated)\n"));
1079 CBC 1 : printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
1080 1 : printf(_(" -C, --create include commands to create database in dump\n"));
1081 1 : printf(_(" -e, --extension=PATTERN dump the specified extension(s) only\n"));
1082 1 : printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
1083 1 : printf(_(" -n, --schema=PATTERN dump the specified schema(s) only\n"));
1084 1 : printf(_(" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
1085 1 : printf(_(" -O, --no-owner skip restoration of object ownership in\n"
1086 ECB : " plain-text format\n"));
1087 CBC 1 : printf(_(" -s, --schema-only dump only the schema, no data\n"));
1088 GIC 1 : printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
1089 GNC 1 : printf(_(" -t, --table=PATTERN dump only the specified table(s)\n"));
1090 GIC 1 : printf(_(" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n"));
1091 CBC 1 : printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
1092 GIC 1 : printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
1093 CBC 1 : printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
1094 GIC 1 : printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
1095 1 : printf(_(" --disable-triggers disable triggers during data-only restore\n"));
1096 CBC 1 : printf(_(" --enable-row-security enable row security (dump only content user has\n"
1097 : " access to)\n"));
1098 GNC 1 : printf(_(" --exclude-table-and-children=PATTERN\n"
1099 : " do NOT dump the specified table(s),\n"
1100 : " including child and partition tables\n"));
1101 GIC 1 : printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
1102 GNC 1 : printf(_(" --exclude-table-data-and-children=PATTERN\n"
1103 : " do NOT dump data for the specified table(s),\n"
1104 : " including child and partition tables\n"));
1105 GIC 1 : printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
1106 1 : printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
1107 1 : printf(_(" --include-foreign-data=PATTERN\n"
1108 : " include data of foreign tables on foreign\n"
1109 ECB : " servers matching PATTERN\n"));
1110 CBC 1 : printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
1111 GIC 1 : printf(_(" --load-via-partition-root load partitions via the root table\n"));
1112 1 : printf(_(" --no-comments do not dump comments\n"));
1113 1 : printf(_(" --no-publications do not dump publications\n"));
1114 1 : printf(_(" --no-security-labels do not dump security label assignments\n"));
1115 1 : printf(_(" --no-subscriptions do not dump subscriptions\n"));
1116 1 : printf(_(" --no-table-access-method do not dump table access methods\n"));
1117 1 : printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
1118 1 : printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
1119 CBC 1 : printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
1120 1 : printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
1121 GIC 1 : printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
1122 CBC 1 : printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
1123 GIC 1 : printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
1124 CBC 1 : printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
1125 GIC 1 : printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
1126 1 : printf(_(" --strict-names require table and/or schema include patterns to\n"
1127 : " match at least one entity each\n"));
1128 GNC 1 : printf(_(" --table-and-children=PATTERN dump only the specified table(s),\n"
1129 : " including child and partition tables\n"));
1130 GIC 1 : printf(_(" --use-set-session-authorization\n"
1131 ECB : " use SET SESSION AUTHORIZATION commands instead of\n"
1132 : " ALTER OWNER commands to set ownership\n"));
1133 :
1134 CBC 1 : printf(_("\nConnection options:\n"));
1135 1 : printf(_(" -d, --dbname=DBNAME database to dump\n"));
1136 GIC 1 : printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
1137 CBC 1 : printf(_(" -p, --port=PORT database server port number\n"));
1138 1 : printf(_(" -U, --username=NAME connect as specified database user\n"));
1139 1 : printf(_(" -w, --no-password never prompt for password\n"));
1140 GIC 1 : printf(_(" -W, --password force password prompt (should happen automatically)\n"));
1141 CBC 1 : printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
1142 ECB :
1143 CBC 1 : printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1144 ECB : "variable value is used.\n\n"));
1145 GIC 1 : printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1146 CBC 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
1147 1 : }
1148 ECB :
1149 : static void
1150 CBC 149 : setup_connection(Archive *AH, const char *dumpencoding,
1151 ECB : const char *dumpsnapshot, char *use_role)
1152 : {
1153 GIC 149 : DumpOptions *dopt = AH->dopt;
1154 CBC 149 : PGconn *conn = GetConnection(AH);
1155 : const char *std_strings;
1156 ECB :
1157 CBC 149 : PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1158 ECB :
1159 : /*
1160 : * Set the client encoding if requested.
1161 : */
1162 CBC 149 : if (dumpencoding)
1163 : {
1164 20 : if (PQsetClientEncoding(conn, dumpencoding) < 0)
1165 LBC 0 : pg_fatal("invalid client encoding \"%s\" specified",
1166 ECB : dumpencoding);
1167 : }
1168 :
1169 : /*
1170 : * Get the active encoding and the standard_conforming_strings setting, so
1171 : * we know how to escape strings.
1172 : */
1173 CBC 149 : AH->encoding = PQclientEncoding(conn);
1174 :
1175 149 : std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1176 GIC 149 : AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1177 :
1178 ECB : /*
1179 : * Set the role if requested. In a parallel dump worker, we'll be passed
1180 : * use_role == NULL, but AH->use_role is already set (if user specified it
1181 : * originally) and we should use that.
1182 : */
1183 CBC 149 : if (!use_role && AH->use_role)
1184 2 : use_role = AH->use_role;
1185 :
1186 : /* Set the role if requested */
1187 149 : if (use_role)
1188 ECB : {
1189 CBC 5 : PQExpBuffer query = createPQExpBuffer();
1190 ECB :
1191 CBC 5 : appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1192 5 : ExecuteSqlStatement(AH, query->data);
1193 5 : destroyPQExpBuffer(query);
1194 ECB :
1195 : /* save it for possible later use by parallel workers */
1196 CBC 5 : if (!AH->use_role)
1197 3 : AH->use_role = pg_strdup(use_role);
1198 ECB : }
1199 :
1200 : /* Set the datestyle to ISO to ensure the dump's portability */
1201 CBC 149 : ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1202 ECB :
1203 : /* Likewise, avoid using sql_standard intervalstyle */
1204 GIC 149 : ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1205 ECB :
1206 : /*
1207 : * Use an explicitly specified extra_float_digits if it has been provided.
1208 : * Otherwise, set extra_float_digits so that we can dump float data
1209 : * exactly (given correctly implemented float I/O code, anyway).
1210 : */
1211 CBC 149 : if (have_extra_float_digits)
1212 ECB : {
1213 LBC 0 : PQExpBuffer q = createPQExpBuffer();
1214 ECB :
1215 LBC 0 : appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1216 ECB : extra_float_digits);
1217 LBC 0 : ExecuteSqlStatement(AH, q->data);
1218 0 : destroyPQExpBuffer(q);
1219 : }
1220 ECB : else
1221 GIC 149 : ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1222 ECB :
1223 : /*
1224 : * Disable synchronized scanning, to prevent unpredictable changes in row
1225 : * ordering across a dump and reload.
1226 : */
1227 CBC 149 : ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1228 :
1229 : /*
1230 ECB : * Disable timeouts if supported.
1231 : */
1232 GIC 149 : ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1233 149 : if (AH->remoteVersion >= 90300)
1234 CBC 149 : ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1235 GIC 149 : if (AH->remoteVersion >= 90600)
1236 149 : ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1237 :
1238 : /*
1239 ECB : * Quote all identifiers, if requested.
1240 : */
1241 CBC 149 : if (quote_all_identifiers)
1242 GBC 6 : ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1243 :
1244 : /*
1245 : * Adjust row-security mode, if supported.
1246 : */
1247 GIC 149 : if (AH->remoteVersion >= 90500)
1248 : {
1249 149 : if (dopt->enable_row_security)
1250 LBC 0 : ExecuteSqlStatement(AH, "SET row_security = on");
1251 : else
1252 CBC 149 : ExecuteSqlStatement(AH, "SET row_security = off");
1253 ECB : }
1254 :
1255 : /*
1256 : * Initialize prepared-query state to "nothing prepared". We do this here
1257 : * so that a parallel dump worker will have its own state.
1258 : */
1259 GIC 149 : AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
1260 ECB :
1261 : /*
1262 : * Start transaction-snapshot mode transaction to dump consistent data.
1263 : */
1264 CBC 149 : ExecuteSqlStatement(AH, "BEGIN");
1265 :
1266 ECB : /*
1267 : * To support the combination of serializable_deferrable with the jobs
1268 : * option we use REPEATABLE READ for the worker connections that are
1269 : * passed a snapshot. As long as the snapshot is acquired in a
1270 : * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1271 : * REPEATABLE READ transaction provides the appropriate integrity
1272 : * guarantees. This is a kluge, but safe for back-patching.
1273 : */
1274 CBC 149 : if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1275 UIC 0 : ExecuteSqlStatement(AH,
1276 : "SET TRANSACTION ISOLATION LEVEL "
1277 : "SERIALIZABLE, READ ONLY, DEFERRABLE");
1278 ECB : else
1279 GIC 149 : ExecuteSqlStatement(AH,
1280 : "SET TRANSACTION ISOLATION LEVEL "
1281 ECB : "REPEATABLE READ, READ ONLY");
1282 :
1283 : /*
1284 : * If user specified a snapshot to use, select that. In a parallel dump
1285 : * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1286 : * is already set (if the server can handle it) and we should use that.
1287 : */
1288 CBC 149 : if (dumpsnapshot)
1289 UIC 0 : AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1290 EUB :
1291 GIC 149 : if (AH->sync_snapshot_id)
1292 EUB : {
1293 GIC 18 : PQExpBuffer query = createPQExpBuffer();
1294 EUB :
1295 GBC 18 : appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
1296 GIC 18 : appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1297 18 : ExecuteSqlStatement(AH, query->data);
1298 CBC 18 : destroyPQExpBuffer(query);
1299 : }
1300 GIC 131 : else if (AH->numWorkers > 1)
1301 : {
1302 9 : if (AH->isStandby && AH->remoteVersion < 100000)
1303 UIC 0 : pg_fatal("parallel dumps from standby servers are not supported by this server version");
1304 CBC 9 : AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1305 : }
1306 GIC 149 : }
1307 :
1308 : /* Set up connection for a parallel worker process */
1309 ECB : static void
1310 CBC 18 : setupDumpWorker(Archive *AH)
1311 ECB : {
1312 : /*
1313 : * We want to re-select all the same values the leader connection is
1314 : * using. We'll have inherited directly-usable values in
1315 : * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1316 : * inherited encoding value back to a string to pass to setup_connection.
1317 : */
1318 CBC 18 : setup_connection(AH,
1319 ECB : pg_encoding_to_char(AH->encoding),
1320 : NULL,
1321 : NULL);
1322 GIC 18 : }
1323 :
1324 ECB : static char *
1325 GIC 9 : get_synchronized_snapshot(Archive *fout)
1326 ECB : {
1327 GBC 9 : char *query = "SELECT pg_catalog.pg_export_snapshot()";
1328 : char *result;
1329 ECB : PGresult *res;
1330 :
1331 GIC 9 : res = ExecuteSqlQueryForSingleRow(fout, query);
1332 9 : result = pg_strdup(PQgetvalue(res, 0, 0));
1333 9 : PQclear(res);
1334 :
1335 9 : return result;
1336 ECB : }
1337 :
1338 : static ArchiveFormat
1339 GIC 139 : parseArchiveFormat(const char *format, ArchiveMode *mode)
1340 : {
1341 ECB : ArchiveFormat archiveFormat;
1342 :
1343 GIC 139 : *mode = archModeWrite;
1344 :
1345 139 : if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1346 : {
1347 : /* This is used by pg_dumpall, and is not documented */
1348 34 : archiveFormat = archNull;
1349 34 : *mode = archModeAppend;
1350 : }
1351 CBC 105 : else if (pg_strcasecmp(format, "c") == 0)
1352 GBC 2 : archiveFormat = archCustom;
1353 GIC 103 : else if (pg_strcasecmp(format, "custom") == 0)
1354 10 : archiveFormat = archCustom;
1355 93 : else if (pg_strcasecmp(format, "d") == 0)
1356 CBC 7 : archiveFormat = archDirectory;
1357 GIC 86 : else if (pg_strcasecmp(format, "directory") == 0)
1358 4 : archiveFormat = archDirectory;
1359 82 : else if (pg_strcasecmp(format, "p") == 0)
1360 74 : archiveFormat = archNull;
1361 8 : else if (pg_strcasecmp(format, "plain") == 0)
1362 4 : archiveFormat = archNull;
1363 4 : else if (pg_strcasecmp(format, "t") == 0)
1364 2 : archiveFormat = archTar;
1365 CBC 2 : else if (pg_strcasecmp(format, "tar") == 0)
1366 GBC 1 : archiveFormat = archTar;
1367 : else
1368 CBC 1 : pg_fatal("invalid output format \"%s\" specified", format);
1369 GIC 138 : return archiveFormat;
1370 ECB : }
1371 :
1372 : /*
1373 : * Find the OIDs of all schemas matching the given list of patterns,
1374 : * and append them to the given OID list.
1375 : */
1376 : static void
1377 CBC 138 : expand_schema_name_patterns(Archive *fout,
1378 : SimpleStringList *patterns,
1379 ECB : SimpleOidList *oids,
1380 EUB : bool strict_names)
1381 ECB : {
1382 : PQExpBuffer query;
1383 : PGresult *res;
1384 : SimpleStringListCell *cell;
1385 : int i;
1386 :
1387 CBC 138 : if (patterns->head == NULL)
1388 GIC 123 : return; /* nothing to do */
1389 :
1390 15 : query = createPQExpBuffer();
1391 :
1392 : /*
1393 : * The loop below runs multiple SELECTs might sometimes result in
1394 : * duplicate entries in the OID list, but we don't care.
1395 ECB : */
1396 :
1397 GIC 24 : for (cell = patterns->head; cell; cell = cell->next)
1398 : {
1399 ECB : PQExpBufferData dbbuf;
1400 : int dotcnt;
1401 :
1402 CBC 15 : appendPQExpBufferStr(query,
1403 : "SELECT oid FROM pg_catalog.pg_namespace n\n");
1404 15 : initPQExpBuffer(&dbbuf);
1405 GIC 15 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1406 : false, NULL, "n.nspname", NULL, NULL, &dbbuf,
1407 : &dotcnt);
1408 CBC 15 : if (dotcnt > 1)
1409 2 : pg_fatal("improper qualified name (too many dotted names): %s",
1410 ECB : cell->val);
1411 GIC 13 : else if (dotcnt == 1)
1412 CBC 3 : prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
1413 GIC 10 : termPQExpBuffer(&dbbuf);
1414 :
1415 10 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1416 CBC 10 : if (strict_names && PQntuples(res) == 0)
1417 GIC 1 : pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
1418 :
1419 17 : for (i = 0; i < PQntuples(res); i++)
1420 ECB : {
1421 GIC 8 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1422 ECB : }
1423 :
1424 GIC 9 : PQclear(res);
1425 CBC 9 : resetPQExpBuffer(query);
1426 ECB : }
1427 :
1428 CBC 9 : destroyPQExpBuffer(query);
1429 ECB : }
1430 :
1431 : /*
1432 : * Find the OIDs of all extensions matching the given list of patterns,
1433 : * and append them to the given OID list.
1434 : */
1435 : static void
1436 CBC 4 : expand_extension_name_patterns(Archive *fout,
1437 ECB : SimpleStringList *patterns,
1438 : SimpleOidList *oids,
1439 : bool strict_names)
1440 : {
1441 : PQExpBuffer query;
1442 : PGresult *res;
1443 : SimpleStringListCell *cell;
1444 : int i;
1445 :
1446 CBC 4 : if (patterns->head == NULL)
1447 UIC 0 : return; /* nothing to do */
1448 :
1449 GIC 4 : query = createPQExpBuffer();
1450 :
1451 : /*
1452 : * The loop below runs multiple SELECTs might sometimes result in
1453 : * duplicate entries in the OID list, but we don't care.
1454 ECB : */
1455 GIC 8 : for (cell = patterns->head; cell; cell = cell->next)
1456 : {
1457 : int dotcnt;
1458 :
1459 4 : appendPQExpBufferStr(query,
1460 : "SELECT oid FROM pg_catalog.pg_extension e\n");
1461 4 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1462 : false, NULL, "e.extname", NULL, NULL, NULL,
1463 : &dotcnt);
1464 CBC 4 : if (dotcnt > 0)
1465 LBC 0 : pg_fatal("improper qualified name (too many dotted names): %s",
1466 : cell->val);
1467 ECB :
1468 GIC 4 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1469 4 : if (strict_names && PQntuples(res) == 0)
1470 UIC 0 : pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
1471 :
1472 GIC 8 : for (i = 0; i < PQntuples(res); i++)
1473 : {
1474 CBC 4 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1475 : }
1476 :
1477 GIC 4 : PQclear(res);
1478 4 : resetPQExpBuffer(query);
1479 ECB : }
1480 :
1481 CBC 4 : destroyPQExpBuffer(query);
1482 ECB : }
1483 :
1484 : /*
1485 : * Find the OIDs of all foreign servers matching the given list of patterns,
1486 : * and append them to the given OID list.
1487 : */
1488 : static void
1489 CBC 119 : expand_foreign_server_name_patterns(Archive *fout,
1490 ECB : SimpleStringList *patterns,
1491 : SimpleOidList *oids)
1492 : {
1493 : PQExpBuffer query;
1494 : PGresult *res;
1495 : SimpleStringListCell *cell;
1496 : int i;
1497 :
1498 CBC 119 : if (patterns->head == NULL)
1499 GIC 117 : return; /* nothing to do */
1500 :
1501 CBC 2 : query = createPQExpBuffer();
1502 ECB :
1503 : /*
1504 : * The loop below runs multiple SELECTs might sometimes result in
1505 : * duplicate entries in the OID list, but we don't care.
1506 : */
1507 :
1508 GIC 4 : for (cell = patterns->head; cell; cell = cell->next)
1509 : {
1510 : int dotcnt;
1511 :
1512 2 : appendPQExpBufferStr(query,
1513 ECB : "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
1514 GIC 2 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1515 : false, NULL, "s.srvname", NULL, NULL, NULL,
1516 : &dotcnt);
1517 2 : if (dotcnt > 0)
1518 UIC 0 : pg_fatal("improper qualified name (too many dotted names): %s",
1519 : cell->val);
1520 :
1521 GIC 2 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1522 2 : if (PQntuples(res) == 0)
1523 LBC 0 : pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
1524 EUB :
1525 GIC 4 : for (i = 0; i < PQntuples(res); i++)
1526 CBC 2 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1527 :
1528 GIC 2 : PQclear(res);
1529 2 : resetPQExpBuffer(query);
1530 : }
1531 :
1532 CBC 2 : destroyPQExpBuffer(query);
1533 : }
1534 :
1535 : /*
1536 ECB : * Find the OIDs of all tables matching the given list of patterns,
1537 : * and append them to the given OID list. See also expand_dbname_patterns()
1538 : * in pg_dumpall.c
1539 : */
1540 : static void
1541 CBC 720 : expand_table_name_patterns(Archive *fout,
1542 EUB : SimpleStringList *patterns, SimpleOidList *oids,
1543 : bool strict_names, bool with_child_tables)
1544 : {
1545 ECB : PQExpBuffer query;
1546 : PGresult *res;
1547 EUB : SimpleStringListCell *cell;
1548 : int i;
1549 ECB :
1550 GIC 720 : if (patterns->head == NULL)
1551 CBC 707 : return; /* nothing to do */
1552 :
1553 GIC 13 : query = createPQExpBuffer();
1554 ECB :
1555 : /*
1556 : * this might sometimes result in duplicate entries in the OID list, but
1557 : * we don't care.
1558 : */
1559 :
1560 GIC 23 : for (cell = patterns->head; cell; cell = cell->next)
1561 : {
1562 : PQExpBufferData dbbuf;
1563 : int dotcnt;
1564 :
1565 : /*
1566 ECB : * Query must remain ABSOLUTELY devoid of unqualified names. This
1567 : * would be unnecessary given a pg_table_is_visible() variant taking a
1568 : * search_path argument.
1569 : *
1570 : * For with_child_tables, we start with the basic query's results and
1571 : * recursively search the inheritance tree to add child tables.
1572 : */
1573 GNC 14 : if (with_child_tables)
1574 : {
1575 3 : appendPQExpBuffer(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
1576 : }
1577 :
1578 GIC 14 : appendPQExpBuffer(query,
1579 : "SELECT c.oid"
1580 : "\nFROM pg_catalog.pg_class c"
1581 : "\n LEFT JOIN pg_catalog.pg_namespace n"
1582 : "\n ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1583 ECB : "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1584 : "\n (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1585 : RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1586 : RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1587 : RELKIND_PARTITIONED_TABLE);
1588 GIC 14 : initPQExpBuffer(&dbbuf);
1589 14 : processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1590 : false, "n.nspname", "c.relname", NULL,
1591 : "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
1592 : &dotcnt);
1593 CBC 14 : if (dotcnt > 2)
1594 GIC 1 : pg_fatal("improper relation name (too many dotted names): %s",
1595 : cell->val);
1596 13 : else if (dotcnt == 2)
1597 CBC 2 : prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
1598 GIC 11 : termPQExpBuffer(&dbbuf);
1599 ECB :
1600 GNC 11 : if (with_child_tables)
1601 : {
1602 3 : appendPQExpBuffer(query, "UNION"
1603 : "\nSELECT i.inhrelid"
1604 : "\nFROM partition_tree p"
1605 : "\n JOIN pg_catalog.pg_inherits i"
1606 : "\n ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
1607 : "\n)"
1608 : "\nSELECT relid FROM partition_tree");
1609 : }
1610 :
1611 GIC 11 : ExecuteSqlStatement(fout, "RESET search_path");
1612 11 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1613 CBC 11 : PQclear(ExecuteSqlQueryForSingleRow(fout,
1614 EUB : ALWAYS_SECURE_SEARCH_PATH_SQL));
1615 GIC 11 : if (strict_names && PQntuples(res) == 0)
1616 1 : pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
1617 ECB :
1618 CBC 31 : for (i = 0; i < PQntuples(res); i++)
1619 EUB : {
1620 GIC 21 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1621 ECB : }
1622 :
1623 GIC 10 : PQclear(res);
1624 CBC 10 : resetPQExpBuffer(query);
1625 ECB : }
1626 :
1627 GIC 9 : destroyPQExpBuffer(query);
1628 ECB : }
1629 :
1630 : /*
1631 : * Verifies that the connected database name matches the given database name,
1632 : * and if not, dies with an error about the given pattern.
1633 : *
1634 : * The 'dbname' argument should be a literal name parsed from 'pattern'.
1635 : */
1636 : static void
1637 CBC 5 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
1638 : {
1639 : const char *db;
1640 :
1641 GIC 5 : db = PQdb(conn);
1642 5 : if (db == NULL)
1643 UIC 0 : pg_fatal("You are currently not connected to a database.");
1644 :
1645 GIC 5 : if (strcmp(db, dbname) != 0)
1646 CBC 5 : pg_fatal("cross-database references are not implemented: %s",
1647 ECB : pattern);
1648 UIC 0 : }
1649 ECB :
1650 : /*
1651 : * checkExtensionMembership
1652 : * Determine whether object is an extension member, and if so,
1653 : * record an appropriate dependency and set the object's dump flag.
1654 : *
1655 : * It's important to call this for each object that could be an extension
1656 : * member. Generally, we integrate this with determining the object's
1657 : * to-be-dumped-ness, since extension membership overrides other rules for that.
1658 : *
1659 : * Returns true if object is an extension member, else false.
1660 : */
1661 : static bool
1662 GIC 445511 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1663 : {
1664 445511 : ExtensionInfo *ext = findOwningExtension(dobj->catId);
1665 :
1666 445511 : if (ext == NULL)
1667 445039 : return false;
1668 :
1669 CBC 472 : dobj->ext_member = true;
1670 :
1671 ECB : /* Record dependency so that getDependencies needn't deal with that */
1672 GIC 472 : addObjectDependency(dobj, ext->dobj.dumpId);
1673 :
1674 ECB : /*
1675 : * In 9.6 and above, mark the member object to have any non-initial ACL,
1676 : * policies, and security labels dumped.
1677 : *
1678 : * Note that any initial ACLs (see pg_init_privs) will be removed when we
1679 : * extract the information about the object. We don't provide support for
1680 : * initial policies and security labels and it seems unlikely for those to
1681 : * ever exist, but we may have to revisit this later.
1682 : *
1683 : * Prior to 9.6, we do not include any extension member components.
1684 : *
1685 : * In binary upgrades, we still dump all components of the members
1686 : * individually, since the idea is to exactly reproduce the database
1687 : * contents rather than replace the extension contents with something
1688 : * different.
1689 : */
1690 CBC 472 : if (fout->dopt->binary_upgrade)
1691 GIC 47 : dobj->dump = ext->dobj.dump;
1692 ECB : else
1693 : {
1694 CBC 425 : if (fout->remoteVersion < 90600)
1695 UIC 0 : dobj->dump = DUMP_COMPONENT_NONE;
1696 ECB : else
1697 GIC 425 : dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1698 ECB : DUMP_COMPONENT_SECLABEL |
1699 : DUMP_COMPONENT_POLICY);
1700 : }
1701 :
1702 GIC 472 : return true;
1703 : }
1704 :
1705 : /*
1706 : * selectDumpableNamespace: policy-setting subroutine
1707 ECB : * Mark a namespace as to be dumped or not
1708 : */
1709 : static void
1710 GIC 783 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1711 ECB : {
1712 : /*
1713 : * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
1714 : * and (for --clean) a DROP SCHEMA statement. (In the absence of
1715 : * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
1716 : */
1717 GIC 783 : nsinfo->create = true;
1718 :
1719 ECB : /*
1720 : * If specific tables are being dumped, do not dump any complete
1721 : * namespaces. If specific namespaces are being dumped, dump just those
1722 : * namespaces. Otherwise, dump all non-system namespaces.
1723 : */
1724 GIC 783 : if (table_include_oids.head != NULL)
1725 18 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1726 765 : else if (schema_include_oids.head != NULL)
1727 39 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1728 39 : simple_oid_list_member(&schema_include_oids,
1729 : nsinfo->dobj.catId.oid) ?
1730 39 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1731 726 : else if (fout->remoteVersion >= 90600 &&
1732 726 : strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1733 ECB : {
1734 : /*
1735 : * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1736 : * they are interesting (and not the original ACLs which were set at
1737 : * initdb time, see pg_init_privs).
1738 : */
1739 GBC 109 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1740 : }
1741 CBC 617 : else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1742 356 : strcmp(nsinfo->dobj.name, "information_schema") == 0)
1743 : {
1744 EUB : /* Other system schemas don't get dumped */
1745 GIC 370 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1746 : }
1747 247 : else if (strcmp(nsinfo->dobj.name, "public") == 0)
1748 : {
1749 : /*
1750 : * The public schema is a strange beast that sits in a sort of
1751 : * no-mans-land between being a system object and a user object.
1752 : * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
1753 : * a comment and an indication of ownership. If the owner is the
1754 : * default, omit that superfluous DUMP_COMPONENT_DEFINITION. Before
1755 : * v15, the default owner was BOOTSTRAP_SUPERUSERID.
1756 : */
1757 105 : nsinfo->create = false;
1758 CBC 105 : nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1759 GIC 105 : if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
1760 CBC 62 : nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
1761 GIC 105 : nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
1762 ECB :
1763 : /*
1764 : * Also, make like it has a comment even if it doesn't; this is so
1765 : * that we'll emit a command to drop the comment, if appropriate.
1766 : * (Without this, we'd not call dumpCommentExtended for it.)
1767 : */
1768 CBC 105 : nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
1769 : }
1770 : else
1771 GIC 142 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1772 :
1773 : /*
1774 : * In any case, a namespace can be excluded by an exclusion switch
1775 : */
1776 1146 : if (nsinfo->dobj.dump_contains &&
1777 363 : simple_oid_list_member(&schema_exclude_oids,
1778 : nsinfo->dobj.catId.oid))
1779 1 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1780 :
1781 : /*
1782 : * If the schema belongs to an extension, allow extension membership to
1783 : * override the dump decision for the schema itself. However, this does
1784 : * not change dump_contains, so this won't change what we do with objects
1785 : * within the schema. (If they belong to the extension, they'll get
1786 ECB : * suppressed by it, otherwise not.)
1787 : */
1788 GIC 783 : (void) checkExtensionMembership(&nsinfo->dobj, fout);
1789 783 : }
1790 ECB :
1791 EUB : /*
1792 : * selectDumpableTable: policy-setting subroutine
1793 ECB : * Mark a table as to be dumped or not
1794 : */
1795 : static void
1796 GIC 30467 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1797 : {
1798 CBC 30467 : if (checkExtensionMembership(&tbinfo->dobj, fout))
1799 GIC 198 : return; /* extension membership overrides all else */
1800 :
1801 : /*
1802 : * If specific tables are being dumped, dump just those tables; else, dump
1803 : * according to the parent namespace's dump flag.
1804 : */
1805 30269 : if (table_include_oids.head != NULL)
1806 CBC 1488 : tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1807 : tbinfo->dobj.catId.oid) ?
1808 GIC 744 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1809 : else
1810 29525 : tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1811 :
1812 : /*
1813 ECB : * In any case, a table can be excluded by an exclusion switch
1814 : */
1815 GIC 50701 : if (tbinfo->dobj.dump &&
1816 20432 : simple_oid_list_member(&table_exclude_oids,
1817 : tbinfo->dobj.catId.oid))
1818 6 : tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1819 : }
1820 ECB :
1821 : /*
1822 : * selectDumpableType: policy-setting subroutine
1823 : * Mark a type as to be dumped or not
1824 : *
1825 : * If it's a table's rowtype or an autogenerated array type, we also apply a
1826 : * special type code to facilitate sorting into the desired order. (We don't
1827 : * want to consider those to be ordinary types because that would bring tables
1828 : * up into the datatype part of the dump order.) We still set the object's
1829 : * dump flag; that's not going to cause the dummy type to be dumped, but we
1830 : * need it so that casts involving such types will be dumped correctly -- see
1831 : * dumpCast. This means the flag should be set the same as for the underlying
1832 : * object (the table or base type).
1833 : */
1834 : static void
1835 CBC 83866 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1836 : {
1837 ECB : /* skip complex types, except for standalone composite types */
1838 CBC 83866 : if (OidIsValid(tyinfo->typrelid) &&
1839 GIC 29911 : tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1840 : {
1841 CBC 29774 : TableInfo *tytable = findTableByOid(tyinfo->typrelid);
1842 :
1843 29774 : tyinfo->dobj.objType = DO_DUMMY_TYPE;
1844 GIC 29774 : if (tytable != NULL)
1845 29774 : tyinfo->dobj.dump = tytable->dobj.dump;
1846 : else
1847 UIC 0 : tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1848 GIC 29774 : return;
1849 : }
1850 :
1851 : /* skip auto-generated array types */
1852 54092 : if (tyinfo->isArray || tyinfo->isMultirange)
1853 ECB : {
1854 CBC 41015 : tyinfo->dobj.objType = DO_DUMMY_TYPE;
1855 ECB :
1856 : /*
1857 : * Fall through to set the dump flag; we assume that the subsequent
1858 : * rules will do the same thing as they would for the array's base
1859 : * type. (We cannot reliably look up the base type here, since
1860 : * getTypes may not have processed it yet.)
1861 : */
1862 : }
1863 :
1864 CBC 54092 : if (checkExtensionMembership(&tyinfo->dobj, fout))
1865 GIC 22 : return; /* extension membership overrides all else */
1866 :
1867 ECB : /* Dump based on if the contents of the namespace are being dumped */
1868 GIC 54070 : tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1869 : }
1870 :
1871 : /*
1872 ECB : * selectDumpableDefaultACL: policy-setting subroutine
1873 : * Mark a default ACL as to be dumped or not
1874 : *
1875 : * For per-schema default ACLs, dump if the schema is to be dumped.
1876 : * Otherwise dump if we are dumping "everything". Note that dataOnly
1877 : * and aclsSkip are checked separately.
1878 : */
1879 : static void
1880 GIC 180 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1881 : {
1882 : /* Default ACLs can't be extension members */
1883 :
1884 CBC 180 : if (dinfo->dobj.namespace)
1885 ECB : /* default ACLs are considered part of the namespace */
1886 GIC 90 : dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1887 : else
1888 90 : dinfo->dobj.dump = dopt->include_everything ?
1889 90 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1890 180 : }
1891 :
1892 ECB : /*
1893 : * selectDumpableCast: policy-setting subroutine
1894 : * Mark a cast as to be dumped or not
1895 : *
1896 : * Casts do not belong to any particular namespace (since they haven't got
1897 : * names), nor do they have identifiable owners. To distinguish user-defined
1898 : * casts from built-in ones, we must resort to checking whether the cast's
1899 : * OID is in the range reserved for initdb.
1900 : */
1901 : static void
1902 CBC 26389 : selectDumpableCast(CastInfo *cast, Archive *fout)
1903 : {
1904 26389 : if (checkExtensionMembership(&cast->dobj, fout))
1905 UIC 0 : return; /* extension membership overrides all else */
1906 ECB :
1907 : /*
1908 : * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1909 : * support ACLs currently.
1910 : */
1911 CBC 26389 : if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1912 26314 : cast->dobj.dump = DUMP_COMPONENT_NONE;
1913 : else
1914 75 : cast->dobj.dump = fout->dopt->include_everything ?
1915 GIC 75 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1916 : }
1917 :
1918 : /*
1919 : * selectDumpableProcLang: policy-setting subroutine
1920 : * Mark a procedural language as to be dumped or not
1921 : *
1922 : * Procedural languages do not belong to any particular namespace. To
1923 : * identify built-in languages, we must resort to checking whether the
1924 : * language's OID is in the range reserved for initdb.
1925 : */
1926 : static void
1927 163 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1928 : {
1929 163 : if (checkExtensionMembership(&plang->dobj, fout))
1930 118 : return; /* extension membership overrides all else */
1931 ECB :
1932 : /*
1933 : * Only include procedural languages when we are dumping everything.
1934 : *
1935 : * For from-initdb procedural languages, only include ACLs, as we do for
1936 : * the pg_catalog namespace. We need this because procedural languages do
1937 : * not live in any namespace.
1938 : */
1939 CBC 45 : if (!fout->dopt->include_everything)
1940 7 : plang->dobj.dump = DUMP_COMPONENT_NONE;
1941 ECB : else
1942 : {
1943 GBC 38 : if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1944 LBC 0 : plang->dobj.dump = fout->remoteVersion < 90600 ?
1945 UIC 0 : DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1946 : else
1947 GIC 38 : plang->dobj.dump = DUMP_COMPONENT_ALL;
1948 ECB : }
1949 : }
1950 :
1951 : /*
1952 : * selectDumpableAccessMethod: policy-setting subroutine
1953 : * Mark an access method as to be dumped or not
1954 : *
1955 : * Access methods do not belong to any particular namespace. To identify
1956 : * built-in access methods, we must resort to checking whether the
1957 : * method's OID is in the range reserved for initdb.
1958 : */
1959 : static void
1960 CBC 943 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
1961 ECB : {
1962 GIC 943 : if (checkExtensionMembership(&method->dobj, fout))
1963 22 : return; /* extension membership overrides all else */
1964 ECB :
1965 : /*
1966 : * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1967 : * they do not support ACLs currently.
1968 : */
1969 GIC 921 : if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1970 826 : method->dobj.dump = DUMP_COMPONENT_NONE;
1971 : else
1972 95 : method->dobj.dump = fout->dopt->include_everything ?
1973 95 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1974 : }
1975 :
1976 ECB : /*
1977 : * selectDumpableExtension: policy-setting subroutine
1978 : * Mark an extension as to be dumped or not
1979 : *
1980 : * Built-in extensions should be skipped except for checking ACLs, since we
1981 : * assume those will already be installed in the target database. We identify
1982 : * such extensions by their having OIDs in the range reserved for initdb.
1983 : * We dump all user-added extensions by default. No extensions are dumped
1984 : * if include_everything is false (i.e., a --schema or --table switch was
1985 : * given), except if --extension specifies a list of extensions to dump.
1986 : */
1987 : static void
1988 GIC 141 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
1989 : {
1990 : /*
1991 : * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
1992 : * change permissions on their member objects, if they wish to, and have
1993 : * those changes preserved.
1994 : */
1995 141 : if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1996 119 : extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1997 : else
1998 ECB : {
1999 : /* check if there is a list of extensions to dump */
2000 CBC 22 : if (extension_include_oids.head != NULL)
2001 GBC 4 : extinfo->dobj.dump = extinfo->dobj.dump_contains =
2002 GIC 4 : simple_oid_list_member(&extension_include_oids,
2003 : extinfo->dobj.catId.oid) ?
2004 4 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2005 : else
2006 18 : extinfo->dobj.dump = extinfo->dobj.dump_contains =
2007 CBC 18 : dopt->include_everything ?
2008 18 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2009 : }
2010 141 : }
2011 ECB :
2012 : /*
2013 : * selectDumpablePublicationObject: policy-setting subroutine
2014 : * Mark a publication object as to be dumped or not
2015 : *
2016 : * A publication can have schemas and tables which have schemas, but those are
2017 : * ignored in decision making, because publications are only dumped when we are
2018 : * dumping everything.
2019 : */
2020 : static void
2021 GIC 353 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
2022 : {
2023 CBC 353 : if (checkExtensionMembership(dobj, fout))
2024 UIC 0 : return; /* extension membership overrides all else */
2025 ECB :
2026 CBC 353 : dobj->dump = fout->dopt->include_everything ?
2027 GIC 353 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2028 : }
2029 :
2030 : /*
2031 : * selectDumpableObject: policy-setting subroutine
2032 : * Mark a generic dumpable object as to be dumped or not
2033 : *
2034 : * Use this only for object types without a special-case routine above.
2035 ECB : */
2036 : static void
2037 GIC 332321 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
2038 : {
2039 CBC 332321 : if (checkExtensionMembership(dobj, fout))
2040 GBC 90 : return; /* extension membership overrides all else */
2041 EUB :
2042 : /*
2043 ECB : * Default policy is to dump if parent namespace is dumpable, or for
2044 : * non-namespace-associated items, dump if we're dumping "everything".
2045 : */
2046 GIC 332231 : if (dobj->namespace)
2047 331719 : dobj->dump = dobj->namespace->dobj.dump_contains;
2048 : else
2049 512 : dobj->dump = fout->dopt->include_everything ?
2050 512 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2051 : }
2052 :
2053 : /*
2054 : * Dump a table's contents for loading using the COPY command
2055 : * - this routine is called by the Archiver when it wants the table
2056 ECB : * to be dumped.
2057 : */
2058 : static int
2059 CBC 2982 : dumpTableData_copy(Archive *fout, const void *dcontext)
2060 : {
2061 GIC 2982 : TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2062 2982 : TableInfo *tbinfo = tdinfo->tdtable;
2063 2982 : const char *classname = tbinfo->dobj.name;
2064 2982 : PQExpBuffer q = createPQExpBuffer();
2065 ECB :
2066 : /*
2067 : * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
2068 : * which uses it already.
2069 : */
2070 GIC 2982 : PQExpBuffer clistBuf = createPQExpBuffer();
2071 2982 : PGconn *conn = GetConnection(fout);
2072 : PGresult *res;
2073 : int ret;
2074 : char *copybuf;
2075 : const char *column_list;
2076 :
2077 2982 : pg_log_info("dumping contents of table \"%s.%s\"",
2078 : tbinfo->dobj.namespace->dobj.name, classname);
2079 :
2080 : /*
2081 : * Specify the column list explicitly so that we have no possibility of
2082 : * retrieving data in the wrong column order. (The default column
2083 : * ordering of COPY will not be what we want in certain corner cases
2084 ECB : * involving ADD COLUMN and inheritance.)
2085 : */
2086 GIC 2982 : column_list = fmtCopyColumnList(tbinfo, clistBuf);
2087 :
2088 : /*
2089 : * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
2090 : * a filter condition was specified. For other cases a simple COPY
2091 ECB : * suffices.
2092 : */
2093 GIC 2982 : if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2094 : {
2095 1 : appendPQExpBufferStr(q, "COPY (SELECT ");
2096 ECB : /* klugery to get rid of parens in column list */
2097 CBC 1 : if (strlen(column_list) > 2)
2098 ECB : {
2099 GIC 1 : appendPQExpBufferStr(q, column_list + 1);
2100 CBC 1 : q->data[q->len - 1] = ' ';
2101 : }
2102 ECB : else
2103 LBC 0 : appendPQExpBufferStr(q, "* ");
2104 ECB :
2105 GIC 2 : appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
2106 CBC 1 : fmtQualifiedDumpable(tbinfo),
2107 GIC 1 : tdinfo->filtercond ? tdinfo->filtercond : "");
2108 : }
2109 : else
2110 : {
2111 2981 : appendPQExpBuffer(q, "COPY %s %s TO stdout;",
2112 2981 : fmtQualifiedDumpable(tbinfo),
2113 : column_list);
2114 : }
2115 2982 : res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
2116 2981 : PQclear(res);
2117 CBC 2981 : destroyPQExpBuffer(clistBuf);
2118 :
2119 ECB : for (;;)
2120 EUB : {
2121 GIC 1694713 : ret = PQgetCopyData(conn, ©buf, 0);
2122 ECB :
2123 CBC 1694713 : if (ret < 0)
2124 GIC 2981 : break; /* done or error */
2125 :
2126 1691732 : if (copybuf)
2127 : {
2128 1691732 : WriteData(fout, copybuf, ret);
2129 1691732 : PQfreemem(copybuf);
2130 : }
2131 :
2132 : /* ----------
2133 ECB : * THROTTLE:
2134 : *
2135 : * There was considerable discussion in late July, 2000 regarding
2136 : * slowing down pg_dump when backing up large tables. Users with both
2137 : * slow & fast (multi-processor) machines experienced performance
2138 : * degradation when doing a backup.
2139 : *
2140 : * Initial attempts based on sleeping for a number of ms for each ms
2141 : * of work were deemed too complex, then a simple 'sleep in each loop'
2142 : * implementation was suggested. The latter failed because the loop
2143 : * was too tight. Finally, the following was implemented:
2144 : *
2145 : * If throttle is non-zero, then
2146 : * See how long since the last sleep.
2147 : * Work out how long to sleep (based on ratio).
2148 : * If sleep is more than 100ms, then
2149 : * sleep
2150 : * reset timer
2151 : * EndIf
2152 : * EndIf
2153 : *
2154 : * where the throttle value was the number of ms to sleep per ms of
2155 : * work. The calculation was done in each loop.
2156 : *
2157 : * Most of the hard work is done in the backend, and this solution
2158 : * still did not work particularly well: on slow machines, the ratio
2159 : * was 50:1, and on medium paced machines, 1:1, and on fast
2160 : * multi-processor machines, it had little or no effect, for reasons
2161 : * that were unclear.
2162 : *
2163 : * Further discussion ensued, and the proposal was dropped.
2164 : *
2165 : * For those people who want this feature, it can be implemented using
2166 : * gettimeofday in each loop, calculating the time since last sleep,
2167 : * multiplying that by the sleep ratio, then if the result is more
2168 : * than a preset 'minimum sleep time' (say 100ms), call the 'select'
2169 : * function to sleep for a subsecond period ie.
2170 : *
2171 : * select(0, NULL, NULL, NULL, &tvi);
2172 : *
2173 : * This will return after the interval specified in the structure tvi.
2174 : * Finally, call gettimeofday again to save the 'last sleep time'.
2175 : * ----------
2176 : */
2177 : }
2178 GIC 2981 : archprintf(fout, "\\.\n\n\n");
2179 :
2180 2981 : if (ret == -2)
2181 : {
2182 ECB : /* copy data transfer failed */
2183 UIC 0 : pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
2184 0 : pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2185 0 : pg_log_error_detail("Command was: %s", q->data);
2186 0 : exit_nicely(1);
2187 : }
2188 :
2189 ECB : /* Check command status and return to normal libpq state */
2190 GIC 2981 : res = PQgetResult(conn);
2191 CBC 2981 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
2192 : {
2193 LBC 0 : pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
2194 UIC 0 : pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2195 LBC 0 : pg_log_error_detail("Command was: %s", q->data);
2196 0 : exit_nicely(1);
2197 : }
2198 GIC 2981 : PQclear(res);
2199 EUB :
2200 : /* Do this to ensure we've pumped libpq back to idle state */
2201 CBC 2981 : if (PQgetResult(conn) != NULL)
2202 LBC 0 : pg_log_warning("unexpected extra results during COPY of table \"%s\"",
2203 ECB : classname);
2204 :
2205 GIC 2981 : destroyPQExpBuffer(q);
2206 2981 : return 1;
2207 ECB : }
2208 :
2209 : /*
2210 : * Dump table data using INSERT commands.
2211 : *
2212 : * Caution: when we restore from an archive file direct to database, the
2213 : * INSERT commands emitted by this function have to be parsed by
2214 : * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
2215 : * E'' strings, or dollar-quoted strings. So don't emit anything like that.
2216 : */
2217 : static int
2218 GIC 57 : dumpTableData_insert(Archive *fout, const void *dcontext)
2219 ECB : {
2220 CBC 57 : TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2221 GIC 57 : TableInfo *tbinfo = tdinfo->tdtable;
2222 CBC 57 : DumpOptions *dopt = fout->dopt;
2223 GIC 57 : PQExpBuffer q = createPQExpBuffer();
2224 CBC 57 : PQExpBuffer insertStmt = NULL;
2225 ECB : char *attgenerated;
2226 : PGresult *res;
2227 : int nfields,
2228 : i;
2229 GIC 57 : int rows_per_statement = dopt->dump_inserts;
2230 57 : int rows_this_statement = 0;
2231 :
2232 : /*
2233 : * If we're going to emit INSERTs with column names, the most efficient
2234 : * way to deal with generated columns is to exclude them entirely. For
2235 : * INSERTs without column names, we have to emit DEFAULT rather than the
2236 : * actual column value --- but we can save a few cycles by fetching nulls
2237 : * rather than the uninteresting-to-us value.
2238 : */
2239 57 : attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
2240 57 : appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
2241 57 : nfields = 0;
2242 191 : for (i = 0; i < tbinfo->numatts; i++)
2243 : {
2244 134 : if (tbinfo->attisdropped[i])
2245 2 : continue;
2246 132 : if (tbinfo->attgenerated[i] && dopt->column_inserts)
2247 5 : continue;
2248 127 : if (nfields > 0)
2249 77 : appendPQExpBufferStr(q, ", ");
2250 127 : if (tbinfo->attgenerated[i])
2251 5 : appendPQExpBufferStr(q, "NULL");
2252 : else
2253 122 : appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
2254 127 : attgenerated[nfields] = tbinfo->attgenerated[i];
2255 127 : nfields++;
2256 : }
2257 : /* Servers before 9.4 will complain about zero-column SELECT */
2258 57 : if (nfields == 0)
2259 7 : appendPQExpBufferStr(q, "NULL");
2260 57 : appendPQExpBuffer(q, " FROM ONLY %s",
2261 57 : fmtQualifiedDumpable(tbinfo));
2262 57 : if (tdinfo->filtercond)
2263 UIC 0 : appendPQExpBuffer(q, " %s", tdinfo->filtercond);
2264 :
2265 GIC 57 : ExecuteSqlStatement(fout, q->data);
2266 :
2267 : while (1)
2268 : {
2269 105 : res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
2270 : PGRES_TUPLES_OK);
2271 :
2272 : /* cross-check field count, allowing for dummy NULL if any */
2273 105 : if (nfields != PQnfields(res) &&
2274 CBC 10 : !(nfields == 0 && PQnfields(res) == 1))
2275 UIC 0 : pg_fatal("wrong number of fields retrieved from table \"%s\"",
2276 ECB : tbinfo->dobj.name);
2277 :
2278 : /*
2279 EUB : * First time through, we build as much of the INSERT statement as
2280 : * possible in "insertStmt", which we can then just print for each
2281 : * statement. If the table happens to have zero dumpable columns then
2282 : * this will be a complete statement, otherwise it will end in
2283 : * "VALUES" and be ready to have the row's column values printed.
2284 : */
2285 GIC 105 : if (insertStmt == NULL)
2286 ECB : {
2287 : TableInfo *targettab;
2288 :
2289 GBC 57 : insertStmt = createPQExpBuffer();
2290 EUB :
2291 : /*
2292 : * When load-via-partition-root is set or forced, get the root
2293 : * table name for the partition table, so that we can reload data
2294 ECB : * through the root table.
2295 : */
2296 GIC 57 : if (tbinfo->ispartition &&
2297 CBC 32 : (dopt->load_via_partition_root ||
2298 GBC 16 : forcePartitionRootLoad(tbinfo)))
2299 GIC 3 : targettab = getRootTableInfo(tbinfo);
2300 : else
2301 CBC 54 : targettab = tbinfo;
2302 ECB :
2303 GIC 57 : appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
2304 57 : fmtQualifiedDumpable(targettab));
2305 :
2306 : /* corner case for zero-column table */
2307 57 : if (nfields == 0)
2308 : {
2309 7 : appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
2310 : }
2311 : else
2312 : {
2313 : /* append the list of column names if required */
2314 CBC 50 : if (dopt->column_inserts)
2315 : {
2316 21 : appendPQExpBufferChar(insertStmt, '(');
2317 73 : for (int field = 0; field < nfields; field++)
2318 ECB : {
2319 CBC 52 : if (field > 0)
2320 31 : appendPQExpBufferStr(insertStmt, ", ");
2321 GIC 52 : appendPQExpBufferStr(insertStmt,
2322 52 : fmtId(PQfname(res, field)));
2323 : }
2324 21 : appendPQExpBufferStr(insertStmt, ") ");
2325 ECB : }
2326 :
2327 GIC 50 : if (tbinfo->needs_override)
2328 2 : appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
2329 :
2330 50 : appendPQExpBufferStr(insertStmt, "VALUES");
2331 : }
2332 : }
2333 :
2334 3174 : for (int tuple = 0; tuple < PQntuples(res); tuple++)
2335 ECB : {
2336 : /* Write the INSERT if not in the middle of a multi-row INSERT. */
2337 CBC 3069 : if (rows_this_statement == 0)
2338 3063 : archputs(insertStmt->data, fout);
2339 :
2340 ECB : /*
2341 : * If it is zero-column table then we've already written the
2342 : * complete statement, which will mean we've disobeyed
2343 : * --rows-per-insert when it's set greater than 1. We do support
2344 : * a way to make this multi-row with: SELECT UNION ALL SELECT
2345 : * UNION ALL ... but that's non-standard so we should avoid it
2346 : * given that using INSERTs is mostly only ever needed for
2347 : * cross-database exports.
2348 : */
2349 CBC 3069 : if (nfields == 0)
2350 6 : continue;
2351 ECB :
2352 : /* Emit a row heading */
2353 GIC 3063 : if (rows_per_statement == 1)
2354 CBC 3054 : archputs(" (", fout);
2355 9 : else if (rows_this_statement > 0)
2356 6 : archputs(",\n\t(", fout);
2357 ECB : else
2358 CBC 3 : archputs("\n\t(", fout);
2359 EUB :
2360 GIC 9245 : for (int field = 0; field < nfields; field++)
2361 ECB : {
2362 GIC 6182 : if (field > 0)
2363 3119 : archputs(", ", fout);
2364 6182 : if (attgenerated[field])
2365 ECB : {
2366 GIC 2 : archputs("DEFAULT", fout);
2367 2 : continue;
2368 : }
2369 CBC 6180 : if (PQgetisnull(res, tuple, field))
2370 ECB : {
2371 GBC 83 : archputs("NULL", fout);
2372 GIC 83 : continue;
2373 : }
2374 :
2375 : /* XXX This code is partially duplicated in ruleutils.c */
2376 6097 : switch (PQftype(res, field))
2377 : {
2378 4069 : case INT2OID:
2379 : case INT4OID:
2380 : case INT8OID:
2381 ECB : case OIDOID:
2382 : case FLOAT4OID:
2383 : case FLOAT8OID:
2384 : case NUMERICOID:
2385 : {
2386 : /*
2387 : * These types are printed without quotes unless
2388 : * they contain values that aren't accepted by the
2389 : * scanner unquoted (e.g., 'NaN'). Note that
2390 : * strtod() and friends might accept NaN, so we
2391 : * can't use that to test.
2392 : *
2393 : * In reality we only need to defend against
2394 : * infinity and NaN, so we need not get too crazy
2395 : * about pattern matching here.
2396 : */
2397 CBC 4069 : const char *s = PQgetvalue(res, tuple, field);
2398 :
2399 4069 : if (strspn(s, "0123456789 +-eE.") == strlen(s))
2400 4067 : archputs(s, fout);
2401 : else
2402 GIC 2 : archprintf(fout, "'%s'", s);
2403 ECB : }
2404 GIC 4069 : break;
2405 ECB :
2406 GIC 2 : case BITOID:
2407 : case VARBITOID:
2408 2 : archprintf(fout, "B'%s'",
2409 : PQgetvalue(res, tuple, field));
2410 CBC 2 : break;
2411 :
2412 4 : case BOOLOID:
2413 4 : if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2414 GIC 2 : archputs("true", fout);
2415 ECB : else
2416 CBC 2 : archputs("false", fout);
2417 4 : break;
2418 ECB :
2419 GIC 2022 : default:
2420 ECB : /* All other types are printed as string literals. */
2421 GIC 2022 : resetPQExpBuffer(q);
2422 2022 : appendStringLiteralAH(q,
2423 ECB : PQgetvalue(res, tuple, field),
2424 : fout);
2425 GIC 2022 : archputs(q->data, fout);
2426 CBC 2022 : break;
2427 : }
2428 : }
2429 :
2430 ECB : /* Terminate the row ... */
2431 GIC 3063 : archputs(")", fout);
2432 :
2433 ECB : /* ... and the statement, if the target no. of rows is reached */
2434 CBC 3063 : if (++rows_this_statement >= rows_per_statement)
2435 : {
2436 GIC 3056 : if (dopt->do_nothing)
2437 UIC 0 : archputs(" ON CONFLICT DO NOTHING;\n", fout);
2438 : else
2439 GIC 3056 : archputs(";\n", fout);
2440 : /* Reset the row counter */
2441 3056 : rows_this_statement = 0;
2442 : }
2443 : }
2444 :
2445 CBC 105 : if (PQntuples(res) <= 0)
2446 ECB : {
2447 GIC 57 : PQclear(res);
2448 57 : break;
2449 ECB : }
2450 CBC 48 : PQclear(res);
2451 ECB : }
2452 :
2453 : /* Terminate any statements that didn't make the row count. */
2454 CBC 57 : if (rows_this_statement > 0)
2455 : {
2456 1 : if (dopt->do_nothing)
2457 UIC 0 : archputs(" ON CONFLICT DO NOTHING;\n", fout);
2458 ECB : else
2459 CBC 1 : archputs(";\n", fout);
2460 ECB : }
2461 :
2462 CBC 57 : archputs("\n\n", fout);
2463 ECB :
2464 GIC 57 : ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2465 ECB :
2466 GIC 57 : destroyPQExpBuffer(q);
2467 CBC 57 : if (insertStmt != NULL)
2468 57 : destroyPQExpBuffer(insertStmt);
2469 GIC 57 : free(attgenerated);
2470 :
2471 57 : return 1;
2472 ECB : }
2473 :
2474 : /*
2475 : * getRootTableInfo:
2476 : * get the root TableInfo for the given partition table.
2477 : */
2478 : static TableInfo *
2479 GIC 9 : getRootTableInfo(const TableInfo *tbinfo)
2480 : {
2481 : TableInfo *parentTbinfo;
2482 :
2483 9 : Assert(tbinfo->ispartition);
2484 9 : Assert(tbinfo->numParents == 1);
2485 :
2486 9 : parentTbinfo = tbinfo->parents[0];
2487 9 : while (parentTbinfo->ispartition)
2488 : {
2489 UIC 0 : Assert(parentTbinfo->numParents == 1);
2490 0 : parentTbinfo = parentTbinfo->parents[0];
2491 : }
2492 :
2493 CBC 9 : return parentTbinfo;
2494 : }
2495 ECB :
2496 : /*
2497 : * forcePartitionRootLoad
2498 : * Check if we must force load_via_partition_root for this partition.
2499 : *
2500 : * This is required if any level of ancestral partitioned table has an
2501 : * unsafe partitioning scheme.
2502 : */
2503 : static bool
2504 CBC 865 : forcePartitionRootLoad(const TableInfo *tbinfo)
2505 : {
2506 ECB : TableInfo *parentTbinfo;
2507 :
2508 CBC 865 : Assert(tbinfo->ispartition);
2509 865 : Assert(tbinfo->numParents == 1);
2510 ECB :
2511 GIC 865 : parentTbinfo = tbinfo->parents[0];
2512 CBC 865 : if (parentTbinfo->unsafe_partitions)
2513 9 : return true;
2514 GIC 1072 : while (parentTbinfo->ispartition)
2515 ECB : {
2516 GIC 216 : Assert(parentTbinfo->numParents == 1);
2517 CBC 216 : parentTbinfo = parentTbinfo->parents[0];
2518 216 : if (parentTbinfo->unsafe_partitions)
2519 UIC 0 : return true;
2520 : }
2521 ECB :
2522 CBC 856 : return false;
2523 : }
2524 :
2525 : /*
2526 : * dumpTableData -
2527 ECB : * dump the contents of a single table
2528 : *
2529 : * Actually, this just makes an ArchiveEntry for the table contents.
2530 : */
2531 : static void
2532 CBC 3095 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
2533 EUB : {
2534 GIC 3095 : DumpOptions *dopt = fout->dopt;
2535 CBC 3095 : TableInfo *tbinfo = tdinfo->tdtable;
2536 GIC 3095 : PQExpBuffer copyBuf = createPQExpBuffer();
2537 CBC 3095 : PQExpBuffer clistBuf = createPQExpBuffer();
2538 : DataDumperPtr dumpFn;
2539 GIC 3095 : char *tdDefn = NULL;
2540 : char *copyStmt;
2541 ECB : const char *copyFrom;
2542 :
2543 : /* We had better have loaded per-column details about this table */
2544 CBC 3095 : Assert(tbinfo->interesting);
2545 :
2546 ECB : /*
2547 : * When load-via-partition-root is set or forced, get the root table name
2548 : * for the partition table, so that we can reload data through the root
2549 : * table. Then construct a comment to be inserted into the TOC entry's
2550 : * defn field, so that such cases can be identified reliably.
2551 : */
2552 CBC 3095 : if (tbinfo->ispartition &&
2553 GBC 1698 : (dopt->load_via_partition_root ||
2554 GIC 849 : forcePartitionRootLoad(tbinfo)))
2555 CBC 6 : {
2556 : TableInfo *parentTbinfo;
2557 :
2558 6 : parentTbinfo = getRootTableInfo(tbinfo);
2559 GIC 6 : copyFrom = fmtQualifiedDumpable(parentTbinfo);
2560 CBC 6 : printfPQExpBuffer(copyBuf, "-- load via partition root %s",
2561 : copyFrom);
2562 6 : tdDefn = pg_strdup(copyBuf->data);
2563 ECB : }
2564 : else
2565 CBC 3089 : copyFrom = fmtQualifiedDumpable(tbinfo);
2566 :
2567 3095 : if (dopt->dump_inserts == 0)
2568 : {
2569 : /* Dump/restore using COPY */
2570 GIC 3038 : dumpFn = dumpTableData_copy;
2571 : /* must use 2 steps here 'cause fmtId is nonreentrant */
2572 3038 : printfPQExpBuffer(copyBuf, "COPY %s ",
2573 : copyFrom);
2574 3038 : appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2575 ECB : fmtCopyColumnList(tbinfo, clistBuf));
2576 GIC 3038 : copyStmt = copyBuf->data;
2577 : }
2578 : else
2579 ECB : {
2580 : /* Restore using INSERT */
2581 GIC 57 : dumpFn = dumpTableData_insert;
2582 CBC 57 : copyStmt = NULL;
2583 ECB : }
2584 :
2585 EUB : /*
2586 : * Note: although the TableDataInfo is a full DumpableObject, we treat its
2587 : * dependency on its table as "special" and pass it to ArchiveEntry now.
2588 : * See comments for BuildArchiveDependencies.
2589 ECB : */
2590 GIC 3095 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2591 : {
2592 : TocEntry *te;
2593 :
2594 3095 : te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2595 3095 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2596 : .namespace = tbinfo->dobj.namespace->dobj.name,
2597 : .owner = tbinfo->rolname,
2598 : .description = "TABLE DATA",
2599 : .section = SECTION_DATA,
2600 ECB : .createStmt = tdDefn,
2601 : .copyStmt = copyStmt,
2602 : .deps = &(tbinfo->dobj.dumpId),
2603 : .nDeps = 1,
2604 : .dumpFn = dumpFn,
2605 : .dumpArg = tdinfo));
2606 :
2607 : /*
2608 : * Set the TocEntry's dataLength in case we are doing a parallel dump
2609 : * and want to order dump jobs by table size. We choose to measure
2610 : * dataLength in table pages (including TOAST pages) during dump, so
2611 : * no scaling is needed.
2612 : *
2613 : * However, relpages is declared as "integer" in pg_class, and hence
2614 : * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2615 EUB : * Cast so that we get the right interpretation of table sizes
2616 : * exceeding INT_MAX pages.
2617 : */
2618 CBC 3095 : te->dataLength = (BlockNumber) tbinfo->relpages;
2619 GIC 3095 : te->dataLength += (BlockNumber) tbinfo->toastpages;
2620 :
2621 : /*
2622 : * If pgoff_t is only 32 bits wide, the above refinement is useless,
2623 : * and instead we'd better worry about integer overflow. Clamp to
2624 : * INT_MAX if the correct result exceeds that.
2625 : */
2626 : if (sizeof(te->dataLength) == 4 &&
2627 : (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
2628 ECB : te->dataLength < 0))
2629 : te->dataLength = INT_MAX;
2630 : }
2631 :
2632 CBC 3095 : destroyPQExpBuffer(copyBuf);
2633 3095 : destroyPQExpBuffer(clistBuf);
2634 GIC 3095 : }
2635 ECB :
2636 : /*
2637 : * refreshMatViewData -
2638 : * load or refresh the contents of a single materialized view
2639 : *
2640 : * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2641 : * statement.
2642 : */
2643 : static void
2644 GIC 328 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
2645 : {
2646 328 : TableInfo *tbinfo = tdinfo->tdtable;
2647 : PQExpBuffer q;
2648 ECB :
2649 : /* If the materialized view is not flagged as populated, skip this. */
2650 CBC 328 : if (!tbinfo->relispopulated)
2651 74 : return;
2652 :
2653 GIC 254 : q = createPQExpBuffer();
2654 ECB :
2655 CBC 254 : appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2656 254 : fmtQualifiedDumpable(tbinfo));
2657 :
2658 254 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2659 GIC 254 : ArchiveEntry(fout,
2660 : tdinfo->dobj.catId, /* catalog ID */
2661 CBC 254 : tdinfo->dobj.dumpId, /* dump ID */
2662 GIC 254 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2663 ECB : .namespace = tbinfo->dobj.namespace->dobj.name,
2664 : .owner = tbinfo->rolname,
2665 : .description = "MATERIALIZED VIEW DATA",
2666 : .section = SECTION_POST_DATA,
2667 : .createStmt = q->data,
2668 : .deps = tdinfo->dobj.dependencies,
2669 : .nDeps = tdinfo->dobj.nDeps));
2670 :
2671 GIC 254 : destroyPQExpBuffer(q);
2672 ECB : }
2673 :
2674 : /*
2675 : * getTableData -
2676 : * set up dumpable objects representing the contents of tables
2677 : */
2678 : static void
2679 GIC 116 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2680 : {
2681 : int i;
2682 :
2683 30002 : for (i = 0; i < numTables; i++)
2684 : {
2685 29886 : if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2686 CBC 757 : (!relkind || tblinfo[i].relkind == relkind))
2687 GIC 4389 : makeTableDataInfo(dopt, &(tblinfo[i]));
2688 : }
2689 116 : }
2690 ECB :
2691 : /*
2692 : * Make a dumpable object for the data of this specific table
2693 : *
2694 : * Note: we make a TableDataInfo if and only if we are going to dump the
2695 : * table data; the "dump" field in such objects isn't very interesting.
2696 : */
2697 : static void
2698 GIC 4426 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
2699 : {
2700 : TableDataInfo *tdinfo;
2701 :
2702 : /*
2703 : * Nothing to do if we already decided to dump the table. This will
2704 : * happen for "config" tables.
2705 : */
2706 4426 : if (tbinfo->dataObj != NULL)
2707 1 : return;
2708 :
2709 : /* Skip VIEWs (no data to dump) */
2710 4425 : if (tbinfo->relkind == RELKIND_VIEW)
2711 225 : return;
2712 : /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
2713 4200 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
2714 CBC 41 : (foreign_servers_include_oids.head == NULL ||
2715 4 : !simple_oid_list_member(&foreign_servers_include_oids,
2716 : tbinfo->foreign_server)))
2717 GIC 40 : return;
2718 : /* Skip partitioned tables (data in partitions) */
2719 4160 : if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2720 390 : return;
2721 :
2722 : /* Don't dump data in unlogged tables, if so requested */
2723 3770 : if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2724 9 : dopt->no_unlogged_table_data)
2725 4 : return;
2726 :
2727 : /* Check that the data is not explicitly excluded */
2728 CBC 3766 : if (simple_oid_list_member(&tabledata_exclude_oids,
2729 ECB : tbinfo->dobj.catId.oid))
2730 CBC 5 : return;
2731 :
2732 : /* OK, let's dump it */
2733 GIC 3761 : tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2734 :
2735 3761 : if (tbinfo->relkind == RELKIND_MATVIEW)
2736 328 : tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2737 3433 : else if (tbinfo->relkind == RELKIND_SEQUENCE)
2738 338 : tdinfo->dobj.objType = DO_SEQUENCE_SET;
2739 : else
2740 CBC 3095 : tdinfo->dobj.objType = DO_TABLE_DATA;
2741 :
2742 ECB : /*
2743 : * Note: use tableoid 0 so that this object won't be mistaken for
2744 : * something that pg_depend entries apply to.
2745 : */
2746 CBC 3761 : tdinfo->dobj.catId.tableoid = 0;
2747 3761 : tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2748 GIC 3761 : AssignDumpId(&tdinfo->dobj);
2749 CBC 3761 : tdinfo->dobj.name = tbinfo->dobj.name;
2750 GIC 3761 : tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2751 CBC 3761 : tdinfo->tdtable = tbinfo;
2752 3761 : tdinfo->filtercond = NULL; /* might get set later */
2753 GIC 3761 : addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2754 ECB :
2755 : /* A TableDataInfo contains data, of course */
2756 GIC 3761 : tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
2757 ECB :
2758 CBC 3761 : tbinfo->dataObj = tdinfo;
2759 :
2760 : /* Make sure that we'll collect per-column info for this table. */
2761 GIC 3761 : tbinfo->interesting = true;
2762 : }
2763 :
2764 : /*
2765 : * The refresh for a materialized view must be dependent on the refresh for
2766 : * any materialized view that this one is dependent on.
2767 ECB : *
2768 : * This must be called after all the objects are created, but before they are
2769 : * sorted.
2770 : */
2771 : static void
2772 GIC 108 : buildMatViewRefreshDependencies(Archive *fout)
2773 : {
2774 : PQExpBuffer query;
2775 ECB : PGresult *res;
2776 : int ntups,
2777 : i;
2778 : int i_classid,
2779 : i_objid,
2780 : i_refobjid;
2781 :
2782 : /* No Mat Views before 9.3. */
2783 CBC 108 : if (fout->remoteVersion < 90300)
2784 UIC 0 : return;
2785 ECB :
2786 GIC 108 : query = createPQExpBuffer();
2787 :
2788 108 : appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2789 : "( "
2790 : "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2791 : "FROM pg_depend d1 "
2792 : "JOIN pg_class c1 ON c1.oid = d1.objid "
2793 : "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2794 ECB : " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2795 : "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2796 : "AND d2.objid = r1.oid "
2797 : "AND d2.refobjid <> d1.objid "
2798 : "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2799 : "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2800 : CppAsString2(RELKIND_VIEW) ") "
2801 : "WHERE d1.classid = 'pg_class'::regclass "
2802 : "UNION "
2803 : "SELECT w.objid, d3.refobjid, c3.relkind "
2804 : "FROM w "
2805 : "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2806 : "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2807 : "AND d3.objid = r3.oid "
2808 : "AND d3.refobjid <> w.refobjid "
2809 : "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2810 : "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2811 : CppAsString2(RELKIND_VIEW) ") "
2812 : ") "
2813 : "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2814 : "FROM w "
2815 : "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2816 :
2817 GIC 108 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2818 :
2819 CBC 108 : ntups = PQntuples(res);
2820 ECB :
2821 CBC 108 : i_classid = PQfnumber(res, "classid");
2822 GIC 108 : i_objid = PQfnumber(res, "objid");
2823 108 : i_refobjid = PQfnumber(res, "refobjid");
2824 ECB :
2825 GIC 378 : for (i = 0; i < ntups; i++)
2826 ECB : {
2827 : CatalogId objId;
2828 : CatalogId refobjId;
2829 : DumpableObject *dobj;
2830 : DumpableObject *refdobj;
2831 : TableInfo *tbinfo;
2832 : TableInfo *reftbinfo;
2833 :
2834 CBC 270 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2835 GIC 270 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
2836 CBC 270 : refobjId.tableoid = objId.tableoid;
2837 GIC 270 : refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2838 :
2839 270 : dobj = findObjectByCatalogId(objId);
2840 270 : if (dobj == NULL)
2841 36 : continue;
2842 ECB :
2843 CBC 270 : Assert(dobj->objType == DO_TABLE);
2844 270 : tbinfo = (TableInfo *) dobj;
2845 270 : Assert(tbinfo->relkind == RELKIND_MATVIEW);
2846 270 : dobj = (DumpableObject *) tbinfo->dataObj;
2847 270 : if (dobj == NULL)
2848 36 : continue;
2849 234 : Assert(dobj->objType == DO_REFRESH_MATVIEW);
2850 :
2851 GIC 234 : refdobj = findObjectByCatalogId(refobjId);
2852 CBC 234 : if (refdobj == NULL)
2853 UIC 0 : continue;
2854 ECB :
2855 GIC 234 : Assert(refdobj->objType == DO_TABLE);
2856 234 : reftbinfo = (TableInfo *) refdobj;
2857 CBC 234 : Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2858 GIC 234 : refdobj = (DumpableObject *) reftbinfo->dataObj;
2859 234 : if (refdobj == NULL)
2860 UIC 0 : continue;
2861 GIC 234 : Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2862 :
2863 234 : addObjectDependency(dobj, refdobj->dumpId);
2864 :
2865 234 : if (!reftbinfo->relispopulated)
2866 37 : tbinfo->relispopulated = false;
2867 : }
2868 ECB :
2869 GIC 108 : PQclear(res);
2870 :
2871 108 : destroyPQExpBuffer(query);
2872 : }
2873 :
2874 : /*
2875 : * getTableDataFKConstraints -
2876 : * add dump-order dependencies reflecting foreign key constraints
2877 : *
2878 : * This code is executed only in a data-only dump --- in schema+data dumps
2879 ECB : * we handle foreign key issues by not creating the FK constraints until
2880 EUB : * after the data is loaded. In a data-only dump, however, we want to
2881 : * order the table data objects in such a way that a table's referenced
2882 ECB : * tables are restored first. (In the presence of circular references or
2883 : * self-references this may be impossible; we'll detect and complain about
2884 : * that during the dependency sorting step.)
2885 : */
2886 : static void
2887 GIC 6 : getTableDataFKConstraints(void)
2888 : {
2889 : DumpableObject **dobjs;
2890 : int numObjs;
2891 : int i;
2892 :
2893 : /* Search through all the dumpable objects for FK constraints */
2894 6 : getDumpableObjects(&dobjs, &numObjs);
2895 25177 : for (i = 0; i < numObjs; i++)
2896 : {
2897 25171 : if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2898 : {
2899 6 : ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2900 : TableInfo *ftable;
2901 :
2902 : /* Not interesting unless both tables are to be dumped */
2903 6 : if (cinfo->contable == NULL ||
2904 6 : cinfo->contable->dataObj == NULL)
2905 3 : continue;
2906 3 : ftable = findTableByOid(cinfo->confrelid);
2907 3 : if (ftable == NULL ||
2908 3 : ftable->dataObj == NULL)
2909 UIC 0 : continue;
2910 :
2911 : /*
2912 : * Okay, make referencing table's TABLE_DATA object depend on the
2913 ECB : * referenced table's TABLE_DATA object.
2914 : */
2915 CBC 3 : addObjectDependency(&cinfo->contable->dataObj->dobj,
2916 GIC 3 : ftable->dataObj->dobj.dumpId);
2917 ECB : }
2918 : }
2919 CBC 6 : free(dobjs);
2920 GIC 6 : }
2921 ECB :
2922 :
2923 : /*
2924 : * dumpDatabase:
2925 : * dump the database definition
2926 : */
2927 : static void
2928 GIC 50 : dumpDatabase(Archive *fout)
2929 : {
2930 CBC 50 : DumpOptions *dopt = fout->dopt;
2931 50 : PQExpBuffer dbQry = createPQExpBuffer();
2932 50 : PQExpBuffer delQry = createPQExpBuffer();
2933 50 : PQExpBuffer creaQry = createPQExpBuffer();
2934 GIC 50 : PQExpBuffer labelq = createPQExpBuffer();
2935 CBC 50 : PGconn *conn = GetConnection(fout);
2936 ECB : PGresult *res;
2937 : int i_tableoid,
2938 : i_oid,
2939 : i_datname,
2940 : i_datdba,
2941 : i_encoding,
2942 : i_datlocprovider,
2943 : i_collate,
2944 : i_ctype,
2945 : i_daticulocale,
2946 : i_daticurules,
2947 : i_frozenxid,
2948 : i_minmxid,
2949 : i_datacl,
2950 EUB : i_acldefault,
2951 : i_datistemplate,
2952 ECB : i_datconnlimit,
2953 : i_datcollversion,
2954 : i_tablespace;
2955 : CatalogId dbCatId;
2956 : DumpId dbDumpId;
2957 EUB : DumpableAcl dbdacl;
2958 ECB : const char *datname,
2959 : *dba,
2960 : *encoding,
2961 : *datlocprovider,
2962 : *collate,
2963 : *ctype,
2964 : *iculocale,
2965 : *icurules,
2966 : *datistemplate,
2967 : *datconnlimit,
2968 : *tablespace;
2969 : uint32 frozenxid,
2970 : minmxid;
2971 : char *qdatname;
2972 :
2973 GIC 50 : pg_log_info("saving database definition");
2974 :
2975 : /*
2976 : * Fetch the database-level properties for this database.
2977 : */
2978 GNC 50 : appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
2979 : "datdba, "
2980 : "pg_encoding_to_char(encoding) AS encoding, "
2981 : "datcollate, datctype, datfrozenxid, "
2982 : "datacl, acldefault('d', datdba) AS acldefault, "
2983 : "datistemplate, datconnlimit, ");
2984 GIC 50 : if (fout->remoteVersion >= 90300)
2985 GNC 50 : appendPQExpBufferStr(dbQry, "datminmxid, ");
2986 : else
2987 UNC 0 : appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
2988 GIC 50 : if (fout->remoteVersion >= 150000)
2989 GNC 50 : appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale, datcollversion, ");
2990 : else
2991 UNC 0 : appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS daticulocale, NULL AS datcollversion, ");
2992 GNC 50 : if (fout->remoteVersion >= 160000)
2993 50 : appendPQExpBufferStr(dbQry, "daticurules, ");
2994 : else
2995 UNC 0 : appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
2996 GNC 50 : appendPQExpBufferStr(dbQry,
2997 : "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2998 : "shobj_description(oid, 'pg_database') AS description "
2999 : "FROM pg_database "
3000 : "WHERE datname = current_database()");
3001 ECB :
3002 GIC 50 : res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
3003 :
3004 50 : i_tableoid = PQfnumber(res, "tableoid");
3005 CBC 50 : i_oid = PQfnumber(res, "oid");
3006 50 : i_datname = PQfnumber(res, "datname");
3007 50 : i_datdba = PQfnumber(res, "datdba");
3008 50 : i_encoding = PQfnumber(res, "encoding");
3009 50 : i_datlocprovider = PQfnumber(res, "datlocprovider");
3010 50 : i_collate = PQfnumber(res, "datcollate");
3011 GBC 50 : i_ctype = PQfnumber(res, "datctype");
3012 GIC 50 : i_daticulocale = PQfnumber(res, "daticulocale");
3013 GNC 50 : i_daticurules = PQfnumber(res, "daticurules");
3014 GIC 50 : i_frozenxid = PQfnumber(res, "datfrozenxid");
3015 50 : i_minmxid = PQfnumber(res, "datminmxid");
3016 50 : i_datacl = PQfnumber(res, "datacl");
3017 50 : i_acldefault = PQfnumber(res, "acldefault");
3018 CBC 50 : i_datistemplate = PQfnumber(res, "datistemplate");
3019 50 : i_datconnlimit = PQfnumber(res, "datconnlimit");
3020 GIC 50 : i_datcollversion = PQfnumber(res, "datcollversion");
3021 50 : i_tablespace = PQfnumber(res, "tablespace");
3022 ECB :
3023 CBC 50 : dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
3024 GIC 50 : dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
3025 50 : datname = PQgetvalue(res, 0, i_datname);
3026 50 : dba = getRoleName(PQgetvalue(res, 0, i_datdba));
3027 50 : encoding = PQgetvalue(res, 0, i_encoding);
3028 50 : datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
3029 50 : collate = PQgetvalue(res, 0, i_collate);
3030 50 : ctype = PQgetvalue(res, 0, i_ctype);
3031 CBC 50 : if (!PQgetisnull(res, 0, i_daticulocale))
3032 GIC 50 : iculocale = PQgetvalue(res, 0, i_daticulocale);
3033 ECB : else
3034 LBC 0 : iculocale = NULL;
3035 GNC 50 : if (!PQgetisnull(res, 0, i_daticurules))
3036 UNC 0 : icurules = PQgetvalue(res, 0, i_daticurules);
3037 : else
3038 GNC 50 : icurules = NULL;
3039 CBC 50 : frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
3040 50 : minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
3041 50 : dbdacl.acl = PQgetvalue(res, 0, i_datacl);
3042 50 : dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
3043 GIC 50 : datistemplate = PQgetvalue(res, 0, i_datistemplate);
3044 50 : datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
3045 50 : tablespace = PQgetvalue(res, 0, i_tablespace);
3046 :
3047 50 : qdatname = pg_strdup(fmtId(datname));
3048 :
3049 : /*
3050 : * Prepare the CREATE DATABASE command. We must specify OID (if we want
3051 : * to preserve that), as well as the encoding, locale, and tablespace
3052 : * since those can't be altered later. Other DB properties are left to
3053 : * the DATABASE PROPERTIES entry, so that they can be applied after
3054 : * reconnecting to the target DB.
3055 : */
3056 50 : if (dopt->binary_upgrade)
3057 : {
3058 7 : appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0 OID = %u",
3059 : qdatname, dbCatId.oid);
3060 : }
3061 : else
3062 : {
3063 43 : appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
3064 : qdatname);
3065 : }
3066 50 : if (strlen(encoding) > 0)
3067 : {
3068 50 : appendPQExpBufferStr(creaQry, " ENCODING = ");
3069 50 : appendStringLiteralAH(creaQry, encoding, fout);
3070 : }
3071 :
3072 50 : appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
3073 50 : if (datlocprovider[0] == 'c')
3074 UIC 0 : appendPQExpBufferStr(creaQry, "libc");
3075 GIC 50 : else if (datlocprovider[0] == 'i')
3076 50 : appendPQExpBufferStr(creaQry, "icu");
3077 : else
3078 UIC 0 : pg_fatal("unrecognized locale provider: %s",
3079 : datlocprovider);
3080 ECB :
3081 GIC 50 : if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
3082 : {
3083 50 : appendPQExpBufferStr(creaQry, " LOCALE = ");
3084 50 : appendStringLiteralAH(creaQry, collate, fout);
3085 ECB : }
3086 : else
3087 : {
3088 UIC 0 : if (strlen(collate) > 0)
3089 : {
3090 0 : appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
3091 LBC 0 : appendStringLiteralAH(creaQry, collate, fout);
3092 ECB : }
3093 UIC 0 : if (strlen(ctype) > 0)
3094 EUB : {
3095 LBC 0 : appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
3096 0 : appendStringLiteralAH(creaQry, ctype, fout);
3097 : }
3098 EUB : }
3099 CBC 50 : if (iculocale)
3100 ECB : {
3101 GIC 50 : appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
3102 GBC 50 : appendStringLiteralAH(creaQry, iculocale, fout);
3103 ECB : }
3104 GNC 50 : if (icurules)
3105 : {
3106 UNC 0 : appendPQExpBufferStr(creaQry, " ICU_RULES = ");
3107 0 : appendStringLiteralAH(creaQry, icurules, fout);
3108 : }
3109 :
3110 : /*
3111 : * For binary upgrade, carry over the collation version. For normal
3112 : * dump/restore, omit the version, so that it is computed upon restore.
3113 : */
3114 CBC 50 : if (dopt->binary_upgrade)
3115 : {
3116 7 : if (!PQgetisnull(res, 0, i_datcollversion))
3117 ECB : {
3118 CBC 7 : appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
3119 7 : appendStringLiteralAH(creaQry,
3120 ECB : PQgetvalue(res, 0, i_datcollversion),
3121 : fout);
3122 : }
3123 : }
3124 :
3125 : /*
3126 : * Note: looking at dopt->outputNoTablespaces here is completely the wrong
3127 : * thing; the decision whether to specify a tablespace should be left till
3128 : * pg_restore, so that pg_restore --no-tablespaces applies. Ideally we'd
3129 : * label the DATABASE entry with the tablespace and let the normal
3130 : * tablespace selection logic work ... but CREATE DATABASE doesn't pay
3131 : * attention to default_tablespace, so that won't work.
3132 : */
3133 CBC 50 : if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
3134 UIC 0 : !dopt->outputNoTablespaces)
3135 LBC 0 : appendPQExpBuffer(creaQry, " TABLESPACE = %s",
3136 ECB : fmtId(tablespace));
3137 CBC 50 : appendPQExpBufferStr(creaQry, ";\n");
3138 ECB :
3139 CBC 50 : appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
3140 ECB : qdatname);
3141 :
3142 CBC 50 : dbDumpId = createDumpId();
3143 ECB :
3144 CBC 50 : ArchiveEntry(fout,
3145 : dbCatId, /* catalog ID */
3146 EUB : dbDumpId, /* dump ID */
3147 CBC 50 : ARCHIVE_OPTS(.tag = datname,
3148 EUB : .owner = dba,
3149 : .description = "DATABASE",
3150 ECB : .section = SECTION_PRE_DATA,
3151 : .createStmt = creaQry->data,
3152 : .dropStmt = delQry->data));
3153 :
3154 : /* Compute correct tag for archive entry */
3155 CBC 50 : appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
3156 ECB :
3157 : /* Dump DB comment if any */
3158 : {
3159 : /*
3160 : * 8.2 and up keep comments on shared objects in a shared table, so we
3161 : * cannot use the dumpComment() code used for other database objects.
3162 : * Be careful that the ArchiveEntry parameters match that function.
3163 : */
3164 GIC 50 : char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
3165 :
3166 50 : if (comment && *comment && !dopt->no_comments)
3167 : {
3168 CBC 20 : resetPQExpBuffer(dbQry);
3169 :
3170 ECB : /*
3171 : * Generates warning when loaded into a differently-named
3172 : * database.
3173 : */
3174 GIC 20 : appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
3175 CBC 20 : appendStringLiteralAH(dbQry, comment, fout);
3176 GIC 20 : appendPQExpBufferStr(dbQry, ";\n");
3177 :
3178 CBC 20 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
3179 GIC 20 : ARCHIVE_OPTS(.tag = labelq->data,
3180 ECB : .owner = dba,
3181 : .description = "COMMENT",
3182 : .section = SECTION_NONE,
3183 : .createStmt = dbQry->data,
3184 : .deps = &dbDumpId,
3185 : .nDeps = 1));
3186 EUB : }
3187 ECB : }
3188 :
3189 : /* Dump DB security label, if enabled */
3190 GBC 50 : if (!dopt->no_security_labels)
3191 : {
3192 : PGresult *shres;
3193 ECB : PQExpBuffer seclabelQry;
3194 :
3195 CBC 50 : seclabelQry = createPQExpBuffer();
3196 ECB :
3197 GIC 50 : buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
3198 50 : shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
3199 50 : resetPQExpBuffer(seclabelQry);
3200 GBC 50 : emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
3201 GIC 50 : if (seclabelQry->len > 0)
3202 UBC 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
3203 0 : ARCHIVE_OPTS(.tag = labelq->data,
3204 : .owner = dba,
3205 EUB : .description = "SECURITY LABEL",
3206 : .section = SECTION_NONE,
3207 : .createStmt = seclabelQry->data,
3208 : .deps = &dbDumpId,
3209 : .nDeps = 1));
3210 GIC 50 : destroyPQExpBuffer(seclabelQry);
3211 CBC 50 : PQclear(shres);
3212 : }
3213 ECB :
3214 : /*
3215 : * Dump ACL if any. Note that we do not support initial privileges
3216 : * (pg_init_privs) on databases.
3217 : */
3218 GBC 50 : dbdacl.privtype = 0;
3219 50 : dbdacl.initprivs = NULL;
3220 :
3221 GIC 50 : dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
3222 : qdatname, NULL, NULL,
3223 : dba, &dbdacl);
3224 :
3225 : /*
3226 ECB : * Now construct a DATABASE PROPERTIES archive entry to restore any
3227 : * non-default database-level properties. (The reason this must be
3228 : * separate is that we cannot put any additional commands into the TOC
3229 : * entry that has CREATE DATABASE. pg_restore would execute such a group
3230 : * in an implicit transaction block, and the backend won't allow CREATE
3231 : * DATABASE in that context.)
3232 : */
3233 GIC 50 : resetPQExpBuffer(creaQry);
3234 50 : resetPQExpBuffer(delQry);
3235 :
3236 50 : if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
3237 UIC 0 : appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
3238 : qdatname, datconnlimit);
3239 :
3240 GIC 50 : if (strcmp(datistemplate, "t") == 0)
3241 : {
3242 1 : appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
3243 : qdatname);
3244 :
3245 ECB : /*
3246 EUB : * The backend won't accept DROP DATABASE on a template database. We
3247 : * can deal with that by removing the template marking before the DROP
3248 : * gets issued. We'd prefer to use ALTER DATABASE IF EXISTS here, but
3249 ECB : * since no such command is currently supported, fake it with a direct
3250 : * UPDATE on pg_database.
3251 : */
3252 GIC 1 : appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
3253 : "SET datistemplate = false WHERE datname = ");
3254 CBC 1 : appendStringLiteralAH(delQry, datname, fout);
3255 GIC 1 : appendPQExpBufferStr(delQry, ";\n");
3256 ECB : }
3257 :
3258 : /* Add database-specific SET options */
3259 CBC 50 : dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
3260 :
3261 : /*
3262 : * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
3263 : * entry, too, for lack of a better place.
3264 : */
3265 GIC 50 : if (dopt->binary_upgrade)
3266 : {
3267 CBC 7 : appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
3268 GIC 7 : appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
3269 : "SET datfrozenxid = '%u', datminmxid = '%u'\n"
3270 : "WHERE datname = ",
3271 : frozenxid, minmxid);
3272 7 : appendStringLiteralAH(creaQry, datname, fout);
3273 7 : appendPQExpBufferStr(creaQry, ";\n");
3274 : }
3275 :
3276 CBC 50 : if (creaQry->len > 0)
3277 GIC 11 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
3278 CBC 11 : ARCHIVE_OPTS(.tag = datname,
3279 : .owner = dba,
3280 ECB : .description = "DATABASE PROPERTIES",
3281 : .section = SECTION_PRE_DATA,
3282 : .createStmt = creaQry->data,
3283 : .dropStmt = delQry->data,
3284 : .deps = &dbDumpId));
3285 :
3286 : /*
3287 : * pg_largeobject comes from the old system intact, so set its
3288 : * relfrozenxids, relminmxids and relfilenode.
3289 : */
3290 CBC 50 : if (dopt->binary_upgrade)
3291 ECB : {
3292 : PGresult *lo_res;
3293 GIC 7 : PQExpBuffer loFrozenQry = createPQExpBuffer();
3294 7 : PQExpBuffer loOutQry = createPQExpBuffer();
3295 7 : PQExpBuffer loHorizonQry = createPQExpBuffer();
3296 : int ii_relfrozenxid,
3297 : ii_relfilenode,
3298 : ii_oid,
3299 : ii_relminmxid;
3300 :
3301 : /*
3302 ECB : * pg_largeobject
3303 : */
3304 GIC 7 : if (fout->remoteVersion >= 90300)
3305 7 : appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
3306 : "FROM pg_catalog.pg_class\n"
3307 ECB : "WHERE oid IN (%u, %u);\n",
3308 : LargeObjectRelationId, LargeObjectLOidPNIndexId);
3309 : else
3310 LBC 0 : appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
3311 ECB : "FROM pg_catalog.pg_class\n"
3312 : "WHERE oid IN (%u, %u);\n",
3313 : LargeObjectRelationId, LargeObjectLOidPNIndexId);
3314 EUB :
3315 GBC 7 : lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
3316 :
3317 GIC 7 : ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
3318 7 : ii_relminmxid = PQfnumber(lo_res, "relminmxid");
3319 7 : ii_relfilenode = PQfnumber(lo_res, "relfilenode");
3320 7 : ii_oid = PQfnumber(lo_res, "oid");
3321 :
3322 CBC 7 : appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3323 7 : appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
3324 GIC 21 : for (int i = 0; i < PQntuples(lo_res); ++i)
3325 : {
3326 : Oid oid;
3327 : RelFileNumber relfilenumber;
3328 :
3329 14 : appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
3330 ECB : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3331 : "WHERE oid = %u;\n",
3332 GIC 14 : atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
3333 CBC 14 : atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
3334 GIC 14 : atooid(PQgetvalue(lo_res, i, ii_oid)));
3335 :
3336 14 : oid = atooid(PQgetvalue(lo_res, i, ii_oid));
3337 GNC 14 : relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
3338 :
3339 GIC 14 : if (oid == LargeObjectRelationId)
3340 7 : appendPQExpBuffer(loOutQry,
3341 : "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
3342 : relfilenumber);
3343 7 : else if (oid == LargeObjectLOidPNIndexId)
3344 7 : appendPQExpBuffer(loOutQry,
3345 ECB : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
3346 : relfilenumber);
3347 : }
3348 :
3349 GBC 7 : appendPQExpBufferStr(loOutQry,
3350 : "TRUNCATE pg_catalog.pg_largeobject;\n");
3351 GIC 7 : appendPQExpBufferStr(loOutQry, loHorizonQry->data);
3352 ECB :
3353 GIC 7 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
3354 CBC 7 : ARCHIVE_OPTS(.tag = "pg_largeobject",
3355 : .description = "pg_largeobject",
3356 : .section = SECTION_PRE_DATA,
3357 : .createStmt = loOutQry->data));
3358 :
3359 GIC 7 : PQclear(lo_res);
3360 :
3361 7 : destroyPQExpBuffer(loFrozenQry);
3362 7 : destroyPQExpBuffer(loHorizonQry);
3363 7 : destroyPQExpBuffer(loOutQry);
3364 ECB : }
3365 :
3366 CBC 50 : PQclear(res);
3367 ECB :
3368 GIC 50 : free(qdatname);
3369 50 : destroyPQExpBuffer(dbQry);
3370 50 : destroyPQExpBuffer(delQry);
3371 CBC 50 : destroyPQExpBuffer(creaQry);
3372 GIC 50 : destroyPQExpBuffer(labelq);
3373 50 : }
3374 :
3375 : /*
3376 : * Collect any database-specific or role-and-database-specific SET options
3377 ECB : * for this database, and append them to outbuf.
3378 : */
3379 : static void
3380 CBC 50 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
3381 : const char *dbname, Oid dboid)
3382 : {
3383 GIC 50 : PGconn *conn = GetConnection(AH);
3384 CBC 50 : PQExpBuffer buf = createPQExpBuffer();
3385 ECB : PGresult *res;
3386 :
3387 : /* First collect database-specific options */
3388 GNC 50 : printfPQExpBuffer(buf, "SELECT unnest(setconfig)");
3389 50 : if (AH->remoteVersion >= 160000)
3390 50 : appendPQExpBufferStr(buf, ", unnest(setuser)");
3391 50 : appendPQExpBuffer(buf, " FROM pg_db_role_setting "
3392 ECB : "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3393 : dboid);
3394 :
3395 GIC 50 : res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3396 :
3397 80 : for (int i = 0; i < PQntuples(res); i++)
3398 : {
3399 GNC 30 : char *userset = NULL;
3400 :
3401 30 : if (AH->remoteVersion >= 160000)
3402 30 : userset = PQgetvalue(res, i, 1);
3403 30 : makeAlterConfigCommand(conn, PQgetvalue(res, i, 0), userset,
3404 : "DATABASE", dbname, NULL, NULL,
3405 : outbuf);
3406 : }
3407 :
3408 GIC 50 : PQclear(res);
3409 :
3410 : /* Now look for role-and-database-specific options */
3411 GNC 50 : printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig)");
3412 50 : if (AH->remoteVersion >= 160000)
3413 50 : appendPQExpBufferStr(buf, ", unnest(setuser)");
3414 50 : appendPQExpBuffer(buf, " FROM pg_db_role_setting s, pg_roles r "
3415 : "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3416 ECB : dboid);
3417 :
3418 CBC 50 : res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3419 :
3420 GIC 50 : for (int i = 0; i < PQntuples(res); i++)
3421 : {
3422 UNC 0 : char *userset = NULL;
3423 :
3424 0 : if (AH->remoteVersion >= 160000)
3425 0 : userset = PQgetvalue(res, i, 2);
3426 0 : makeAlterConfigCommand(conn, PQgetvalue(res, i, 1), userset,
3427 UIC 0 : "ROLE", PQgetvalue(res, i, 0),
3428 : "DATABASE", dbname,
3429 : outbuf);
3430 : }
3431 :
3432 GIC 50 : PQclear(res);
3433 ECB :
3434 CBC 50 : destroyPQExpBuffer(buf);
3435 GIC 50 : }
3436 :
3437 : /*
3438 : * dumpEncoding: put the correct encoding into the archive
3439 EUB : */
3440 : static void
3441 GIC 118 : dumpEncoding(Archive *AH)
3442 : {
3443 118 : const char *encname = pg_encoding_to_char(AH->encoding);
3444 CBC 118 : PQExpBuffer qry = createPQExpBuffer();
3445 :
3446 118 : pg_log_info("saving encoding = %s", encname);
3447 ECB :
3448 CBC 118 : appendPQExpBufferStr(qry, "SET client_encoding = ");
3449 118 : appendStringLiteralAH(qry, encname, AH);
3450 GIC 118 : appendPQExpBufferStr(qry, ";\n");
3451 ECB :
3452 CBC 118 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
3453 118 : ARCHIVE_OPTS(.tag = "ENCODING",
3454 : .description = "ENCODING",
3455 : .section = SECTION_PRE_DATA,
3456 : .createStmt = qry->data));
3457 :
3458 118 : destroyPQExpBuffer(qry);
3459 GIC 118 : }
3460 :
3461 ECB :
3462 : /*
3463 : * dumpStdStrings: put the correct escape string behavior into the archive
3464 : */
3465 : static void
3466 CBC 118 : dumpStdStrings(Archive *AH)
3467 : {
3468 118 : const char *stdstrings = AH->std_strings ? "on" : "off";
3469 118 : PQExpBuffer qry = createPQExpBuffer();
3470 :
3471 GIC 118 : pg_log_info("saving standard_conforming_strings = %s",
3472 ECB : stdstrings);
3473 :
3474 GIC 118 : appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3475 : stdstrings);
3476 :
3477 118 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
3478 CBC 118 : ARCHIVE_OPTS(.tag = "STDSTRINGS",
3479 : .description = "STDSTRINGS",
3480 ECB : .section = SECTION_PRE_DATA,
3481 : .createStmt = qry->data));
3482 :
3483 CBC 118 : destroyPQExpBuffer(qry);
3484 GIC 118 : }
3485 :
3486 : /*
3487 : * dumpSearchPath: record the active search_path in the archive
3488 ECB : */
3489 : static void
3490 CBC 118 : dumpSearchPath(Archive *AH)
3491 ECB : {
3492 CBC 118 : PQExpBuffer qry = createPQExpBuffer();
3493 GIC 118 : PQExpBuffer path = createPQExpBuffer();
3494 : PGresult *res;
3495 CBC 118 : char **schemanames = NULL;
3496 GIC 118 : int nschemanames = 0;
3497 ECB : int i;
3498 :
3499 : /*
3500 : * We use the result of current_schemas(), not the search_path GUC,
3501 : * because that might contain wildcards such as "$user", which won't
3502 : * necessarily have the same value during restore. Also, this way avoids
3503 : * listing schemas that may appear in search_path but not actually exist,
3504 : * which seems like a prudent exclusion.
3505 : */
3506 GIC 118 : res = ExecuteSqlQueryForSingleRow(AH,
3507 : "SELECT pg_catalog.current_schemas(false)");
3508 :
3509 CBC 118 : if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3510 UIC 0 : pg_fatal("could not parse result of current_schemas()");
3511 :
3512 ECB : /*
3513 : * We use set_config(), not a simple "SET search_path" command, because
3514 : * the latter has less-clean behavior if the search path is empty. While
3515 : * that's likely to get fixed at some point, it seems like a good idea to
3516 : * be as backwards-compatible as possible in what we put into archives.
3517 : */
3518 CBC 118 : for (i = 0; i < nschemanames; i++)
3519 ECB : {
3520 LBC 0 : if (i > 0)
3521 UIC 0 : appendPQExpBufferStr(path, ", ");
3522 0 : appendPQExpBufferStr(path, fmtId(schemanames[i]));
3523 : }
3524 ECB :
3525 GIC 118 : appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3526 CBC 118 : appendStringLiteralAH(qry, path->data, AH);
3527 GIC 118 : appendPQExpBufferStr(qry, ", false);\n");
3528 ECB :
3529 GIC 118 : pg_log_info("saving search_path = %s", path->data);
3530 ECB :
3531 CBC 118 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
3532 118 : ARCHIVE_OPTS(.tag = "SEARCHPATH",
3533 : .description = "SEARCHPATH",
3534 : .section = SECTION_PRE_DATA,
3535 : .createStmt = qry->data));
3536 :
3537 ECB : /* Also save it in AH->searchpath, in case we're doing plain text dump */
3538 GIC 118 : AH->searchpath = pg_strdup(qry->data);
3539 :
3540 GNC 118 : free(schemanames);
3541 CBC 118 : PQclear(res);
3542 118 : destroyPQExpBuffer(qry);
3543 GIC 118 : destroyPQExpBuffer(path);
3544 118 : }
3545 :
3546 ECB :
3547 : /*
3548 : * getLOs:
3549 : * Collect schema-level data about large objects
3550 EUB : */
3551 : static void
3552 GNC 104 : getLOs(Archive *fout)
3553 EUB : {
3554 GBC 104 : DumpOptions *dopt = fout->dopt;
3555 GNC 104 : PQExpBuffer loQry = createPQExpBuffer();
3556 : LoInfo *loinfo;
3557 : DumpableObject *lodata;
3558 : PGresult *res;
3559 : int ntups;
3560 ECB : int i;
3561 : int i_oid;
3562 : int i_lomowner;
3563 : int i_lomacl;
3564 : int i_acldefault;
3565 :
3566 GIC 104 : pg_log_info("reading large objects");
3567 :
3568 : /* Fetch LO OIDs, and owner/ACL data */
3569 GNC 104 : appendPQExpBufferStr(loQry,
3570 : "SELECT oid, lomowner, lomacl, "
3571 : "acldefault('L', lomowner) AS acldefault "
3572 : "FROM pg_largeobject_metadata");
3573 :
3574 104 : res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
3575 :
3576 CBC 104 : i_oid = PQfnumber(res, "oid");
3577 104 : i_lomowner = PQfnumber(res, "lomowner");
3578 104 : i_lomacl = PQfnumber(res, "lomacl");
3579 GIC 104 : i_acldefault = PQfnumber(res, "acldefault");
3580 ECB :
3581 CBC 104 : ntups = PQntuples(res);
3582 :
3583 : /*
3584 : * Each large object has its own "BLOB" archive entry.
3585 : */
3586 GNC 104 : loinfo = (LoInfo *) pg_malloc(ntups * sizeof(LoInfo));
3587 ECB :
3588 GIC 193 : for (i = 0; i < ntups; i++)
3589 : {
3590 GNC 89 : loinfo[i].dobj.objType = DO_LARGE_OBJECT;
3591 89 : loinfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3592 89 : loinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3593 89 : AssignDumpId(&loinfo[i].dobj);
3594 ECB :
3595 GNC 89 : loinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3596 89 : loinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3597 89 : loinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
3598 89 : loinfo[i].dacl.privtype = 0;
3599 89 : loinfo[i].dacl.initprivs = NULL;
3600 89 : loinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_lomowner));
3601 :
3602 : /* LOs have data */
3603 89 : loinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
3604 :
3605 : /* Mark whether LO has an ACL */
3606 CBC 89 : if (!PQgetisnull(res, i, i_lomacl))
3607 GNC 37 : loinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
3608 :
3609 : /*
3610 : * In binary-upgrade mode for LOs, we do *not* dump out the LO
3611 ECB : * data, as it will be copied by pg_upgrade, which simply copies the
3612 : * pg_largeobject table. We *do* however dump out anything but the
3613 : * data, as pg_upgrade copies just pg_largeobject, but not
3614 : * pg_largeobject_metadata, after the dump is restored.
3615 : */
3616 GIC 89 : if (dopt->binary_upgrade)
3617 GNC 5 : loinfo[i].dobj.dump &= ~DUMP_COMPONENT_DATA;
3618 ECB : }
3619 :
3620 : /*
3621 : * If we have any large objects, a "BLOBS" archive entry is needed. This
3622 : * is just a placeholder for sorting; it carries no data now.
3623 : */
3624 CBC 104 : if (ntups > 0)
3625 : {
3626 GNC 42 : lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3627 42 : lodata->objType = DO_LARGE_OBJECT_DATA;
3628 42 : lodata->catId = nilCatalogId;
3629 42 : AssignDumpId(lodata);
3630 42 : lodata->name = pg_strdup("BLOBS");
3631 42 : lodata->components |= DUMP_COMPONENT_DATA;
3632 : }
3633 :
3634 CBC 104 : PQclear(res);
3635 GNC 104 : destroyPQExpBuffer(loQry);
3636 GIC 104 : }
3637 ECB :
3638 EUB : /*
3639 : * dumpLO
3640 : *
3641 : * dump the definition (metadata) of the given large object
3642 : */
3643 : static void
3644 GNC 89 : dumpLO(Archive *fout, const LoInfo *loinfo)
3645 : {
3646 CBC 89 : PQExpBuffer cquery = createPQExpBuffer();
3647 GIC 89 : PQExpBuffer dquery = createPQExpBuffer();
3648 EUB :
3649 GBC 89 : appendPQExpBuffer(cquery,
3650 EUB : "SELECT pg_catalog.lo_create('%s');\n",
3651 GNC 89 : loinfo->dobj.name);
3652 :
3653 CBC 89 : appendPQExpBuffer(dquery,
3654 ECB : "SELECT pg_catalog.lo_unlink('%s');\n",
3655 GNC 89 : loinfo->dobj.name);
3656 :
3657 89 : if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3658 89 : ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
3659 89 : ARCHIVE_OPTS(.tag = loinfo->dobj.name,
3660 : .owner = loinfo->rolname,
3661 : .description = "BLOB",
3662 : .section = SECTION_PRE_DATA,
3663 : .createStmt = cquery->data,
3664 : .dropStmt = dquery->data));
3665 :
3666 ECB : /* Dump comment if any */
3667 GNC 89 : if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3668 47 : dumpComment(fout, "LARGE OBJECT", loinfo->dobj.name,
3669 47 : NULL, loinfo->rolname,
3670 47 : loinfo->dobj.catId, 0, loinfo->dobj.dumpId);
3671 ECB :
3672 : /* Dump security label if any */
3673 GNC 89 : if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3674 UNC 0 : dumpSecLabel(fout, "LARGE OBJECT", loinfo->dobj.name,
3675 0 : NULL, loinfo->rolname,
3676 0 : loinfo->dobj.catId, 0, loinfo->dobj.dumpId);
3677 :
3678 : /* Dump ACL if any */
3679 GNC 89 : if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
3680 37 : dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId, "LARGE OBJECT",
3681 37 : loinfo->dobj.name, NULL,
3682 37 : NULL, loinfo->rolname, &loinfo->dacl);
3683 ECB :
3684 GIC 89 : destroyPQExpBuffer(cquery);
3685 89 : destroyPQExpBuffer(dquery);
3686 89 : }
3687 :
3688 : /*
3689 : * dumpLOs:
3690 : * dump the data contents of all large objects
3691 : */
3692 : static int
3693 GNC 38 : dumpLOs(Archive *fout, const void *arg)
3694 ECB : {
3695 : const char *loQry;
3696 : const char *loFetchQry;
3697 CBC 38 : PGconn *conn = GetConnection(fout);
3698 : PGresult *res;
3699 : char buf[LOBBUFSIZE];
3700 : int ntups;
3701 : int i;
3702 ECB : int cnt;
3703 :
3704 CBC 38 : pg_log_info("saving large objects");
3705 ECB :
3706 : /*
3707 : * Currently, we re-fetch all LO OIDs using a cursor. Consider scanning
3708 : * the already-in-memory dumpable objects instead...
3709 : */
3710 GNC 38 : loQry =
3711 : "DECLARE looid CURSOR FOR "
3712 : "SELECT oid FROM pg_largeobject_metadata ORDER BY 1";
3713 :
3714 38 : ExecuteSqlStatement(fout, loQry);
3715 :
3716 ECB : /* Command to fetch from cursor */
3717 GNC 38 : loFetchQry = "FETCH 1000 IN looid";
3718 ECB :
3719 : do
3720 : {
3721 : /* Do a fetch */
3722 GNC 76 : res = ExecuteSqlQuery(fout, loFetchQry, PGRES_TUPLES_OK);
3723 ECB :
3724 : /* Process the tuples, if any */
3725 CBC 76 : ntups = PQntuples(res);
3726 156 : for (i = 0; i < ntups; i++)
3727 ECB : {
3728 : Oid loOid;
3729 : int loFd;
3730 :
3731 GNC 80 : loOid = atooid(PQgetvalue(res, i, 0));
3732 : /* Open the LO */
3733 80 : loFd = lo_open(conn, loOid, INV_READ);
3734 CBC 80 : if (loFd == -1)
3735 LBC 0 : pg_fatal("could not open large object %u: %s",
3736 : loOid, PQerrorMessage(conn));
3737 :
3738 GNC 80 : StartLO(fout, loOid);
3739 :
3740 : /* Now read it in chunks, sending data to archive */
3741 : do
3742 : {
3743 GIC 122 : cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3744 CBC 122 : if (cnt < 0)
3745 LBC 0 : pg_fatal("error reading large object %u: %s",
3746 : loOid, PQerrorMessage(conn));
3747 :
3748 GIC 122 : WriteData(fout, buf, cnt);
3749 122 : } while (cnt > 0);
3750 :
3751 80 : lo_close(conn, loFd);
3752 ECB :
3753 GNC 80 : EndLO(fout, loOid);
3754 ECB : }
3755 :
3756 CBC 76 : PQclear(res);
3757 76 : } while (ntups > 0);
3758 ECB :
3759 CBC 38 : return 1;
3760 : }
3761 :
3762 ECB : /*
3763 : * getPolicies
3764 : * get information about all RLS policies on dumpable tables.
3765 : */
3766 : void
3767 GIC 118 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3768 : {
3769 : PQExpBuffer query;
3770 : PQExpBuffer tbloids;
3771 : PGresult *res;
3772 ECB : PolicyInfo *polinfo;
3773 : int i_oid;
3774 : int i_tableoid;
3775 : int i_polrelid;
3776 : int i_polname;
3777 : int i_polcmd;
3778 : int i_polpermissive;
3779 : int i_polroles;
3780 : int i_polqual;
3781 : int i_polwithcheck;
3782 : int i,
3783 : j,
3784 : ntups;
3785 :
3786 : /* No policies before 9.5 */
3787 CBC 118 : if (fout->remoteVersion < 90500)
3788 UIC 0 : return;
3789 :
3790 GIC 118 : query = createPQExpBuffer();
3791 118 : tbloids = createPQExpBuffer();
3792 :
3793 : /*
3794 : * Identify tables of interest, and check which ones have RLS enabled.
3795 ECB : */
3796 CBC 118 : appendPQExpBufferChar(tbloids, '{');
3797 30474 : for (i = 0; i < numTables; i++)
3798 ECB : {
3799 GIC 30356 : TableInfo *tbinfo = &tblinfo[i];
3800 :
3801 ECB : /* Ignore row security on tables not to be dumped */
3802 GBC 30356 : if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3803 25064 : continue;
3804 EUB :
3805 : /* It can't have RLS or policies if it's not a table */
3806 GIC 5292 : if (tbinfo->relkind != RELKIND_RELATION &&
3807 CBC 1551 : tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
3808 1079 : continue;
3809 ECB :
3810 : /* Add it to the list of table OIDs to be probed below */
3811 GIC 4213 : if (tbloids->len > 1) /* do we have more than the '{'? */
3812 CBC 4138 : appendPQExpBufferChar(tbloids, ',');
3813 4213 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
3814 ECB :
3815 : /* Is RLS enabled? (That's separate from whether it has policies) */
3816 GIC 4213 : if (tbinfo->rowsec)
3817 : {
3818 55 : tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
3819 :
3820 : /*
3821 ECB : * We represent RLS being enabled on a table by creating a
3822 : * PolicyInfo object with null polname.
3823 : *
3824 : * Note: use tableoid 0 so that this object won't be mistaken for
3825 : * something that pg_depend entries apply to.
3826 : */
3827 GIC 55 : polinfo = pg_malloc(sizeof(PolicyInfo));
3828 55 : polinfo->dobj.objType = DO_POLICY;
3829 55 : polinfo->dobj.catId.tableoid = 0;
3830 55 : polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3831 55 : AssignDumpId(&polinfo->dobj);
3832 CBC 55 : polinfo->dobj.namespace = tbinfo->dobj.namespace;
3833 GIC 55 : polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3834 55 : polinfo->poltable = tbinfo;
3835 55 : polinfo->polname = NULL;
3836 55 : polinfo->polcmd = '\0';
3837 55 : polinfo->polpermissive = 0;
3838 CBC 55 : polinfo->polroles = NULL;
3839 GIC 55 : polinfo->polqual = NULL;
3840 55 : polinfo->polwithcheck = NULL;
3841 : }
3842 ECB : }
3843 GIC 118 : appendPQExpBufferChar(tbloids, '}');
3844 :
3845 ECB : /*
3846 : * Now, read all RLS policies belonging to the tables of interest, and
3847 : * create PolicyInfo objects for them. (Note that we must filter the
3848 : * results server-side not locally, because we dare not apply pg_get_expr
3849 : * to tables we don't have lock on.)
3850 : */
3851 GIC 118 : pg_log_info("reading row-level security policies");
3852 :
3853 CBC 118 : printfPQExpBuffer(query,
3854 ECB : "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
3855 GIC 118 : if (fout->remoteVersion >= 100000)
3856 GNC 118 : appendPQExpBufferStr(query, "pol.polpermissive, ");
3857 : else
3858 UNC 0 : appendPQExpBufferStr(query, "'t' as polpermissive, ");
3859 CBC 118 : appendPQExpBuffer(query,
3860 : "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3861 ECB : " 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, "
3862 : "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3863 EUB : "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3864 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
3865 : "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
3866 ECB : tbloids->data);
3867 :
3868 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3869 :
3870 118 : ntups = PQntuples(res);
3871 CBC 118 : if (ntups > 0)
3872 ECB : {
3873 GBC 45 : i_oid = PQfnumber(res, "oid");
3874 GIC 45 : i_tableoid = PQfnumber(res, "tableoid");
3875 45 : i_polrelid = PQfnumber(res, "polrelid");
3876 CBC 45 : i_polname = PQfnumber(res, "polname");
3877 45 : i_polcmd = PQfnumber(res, "polcmd");
3878 GIC 45 : i_polpermissive = PQfnumber(res, "polpermissive");
3879 CBC 45 : i_polroles = PQfnumber(res, "polroles");
3880 GIC 45 : i_polqual = PQfnumber(res, "polqual");
3881 CBC 45 : i_polwithcheck = PQfnumber(res, "polwithcheck");
3882 :
3883 GIC 45 : polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3884 ECB :
3885 CBC 330 : for (j = 0; j < ntups; j++)
3886 : {
3887 285 : Oid polrelid = atooid(PQgetvalue(res, j, i_polrelid));
3888 GIC 285 : TableInfo *tbinfo = findTableByOid(polrelid);
3889 :
3890 285 : tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
3891 :
3892 285 : polinfo[j].dobj.objType = DO_POLICY;
3893 285 : polinfo[j].dobj.catId.tableoid =
3894 285 : atooid(PQgetvalue(res, j, i_tableoid));
3895 CBC 285 : polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3896 GIC 285 : AssignDumpId(&polinfo[j].dobj);
3897 285 : polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3898 285 : polinfo[j].poltable = tbinfo;
3899 285 : polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3900 285 : polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3901 :
3902 285 : polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3903 285 : polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3904 :
3905 285 : if (PQgetisnull(res, j, i_polroles))
3906 125 : polinfo[j].polroles = NULL;
3907 : else
3908 160 : polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3909 :
3910 285 : if (PQgetisnull(res, j, i_polqual))
3911 40 : polinfo[j].polqual = NULL;
3912 : else
3913 245 : polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3914 :
3915 CBC 285 : if (PQgetisnull(res, j, i_polwithcheck))
3916 GBC 150 : polinfo[j].polwithcheck = NULL;
3917 : else
3918 CBC 135 : polinfo[j].polwithcheck
3919 135 : = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3920 : }
3921 : }
3922 :
3923 GIC 118 : PQclear(res);
3924 ECB :
3925 CBC 118 : destroyPQExpBuffer(query);
3926 GIC 118 : destroyPQExpBuffer(tbloids);
3927 ECB : }
3928 :
3929 : /*
3930 : * dumpPolicy
3931 : * dump the definition of the given policy
3932 : */
3933 : static void
3934 CBC 340 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
3935 ECB : {
3936 CBC 340 : DumpOptions *dopt = fout->dopt;
3937 GIC 340 : TableInfo *tbinfo = polinfo->poltable;
3938 : PQExpBuffer query;
3939 ECB : PQExpBuffer delqry;
3940 : PQExpBuffer polprefix;
3941 : char *qtabname;
3942 : const char *cmd;
3943 : char *tag;
3944 :
3945 : /* Do nothing in data-only dump */
3946 CBC 340 : if (dopt->dataOnly)
3947 GIC 28 : return;
3948 :
3949 : /*
3950 : * If polname is NULL, then this record is just indicating that ROW LEVEL
3951 : * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3952 : * ROW LEVEL SECURITY.
3953 : */
3954 312 : if (polinfo->polname == NULL)
3955 ECB : {
3956 CBC 51 : query = createPQExpBuffer();
3957 ECB :
3958 CBC 51 : appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3959 51 : fmtQualifiedDumpable(tbinfo));
3960 ECB :
3961 : /*
3962 : * We must emit the ROW SECURITY object's dependency on its table
3963 : * explicitly, because it will not match anything in pg_depend (unlike
3964 : * the case for other PolicyInfo objects).
3965 : */
3966 CBC 51 : if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3967 51 : ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3968 51 : ARCHIVE_OPTS(.tag = polinfo->dobj.name,
3969 : .namespace = polinfo->dobj.namespace->dobj.name,
3970 : .owner = tbinfo->rolname,
3971 ECB : .description = "ROW SECURITY",
3972 : .section = SECTION_POST_DATA,
3973 : .createStmt = query->data,
3974 : .deps = &(tbinfo->dobj.dumpId),
3975 : .nDeps = 1));
3976 :
3977 GIC 51 : destroyPQExpBuffer(query);
3978 51 : return;
3979 ECB : }
3980 :
3981 CBC 261 : if (polinfo->polcmd == '*')
3982 GIC 87 : cmd = "";
3983 CBC 174 : else if (polinfo->polcmd == 'r')
3984 46 : cmd = " FOR SELECT";
3985 GIC 128 : else if (polinfo->polcmd == 'a')
3986 GBC 36 : cmd = " FOR INSERT";
3987 CBC 92 : else if (polinfo->polcmd == 'w')
3988 GIC 46 : cmd = " FOR UPDATE";
3989 46 : else if (polinfo->polcmd == 'd')
3990 46 : cmd = " FOR DELETE";
3991 : else
3992 UIC 0 : pg_fatal("unexpected policy command type: %c",
3993 : polinfo->polcmd);
3994 :
3995 GIC 261 : query = createPQExpBuffer();
3996 CBC 261 : delqry = createPQExpBuffer();
3997 GIC 261 : polprefix = createPQExpBuffer();
3998 ECB :
3999 CBC 261 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
4000 :
4001 261 : appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
4002 ECB :
4003 CBC 261 : appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
4004 261 : !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
4005 ECB :
4006 CBC 261 : if (polinfo->polroles != NULL)
4007 144 : appendPQExpBuffer(query, " TO %s", polinfo->polroles);
4008 ECB :
4009 CBC 261 : if (polinfo->polqual != NULL)
4010 GIC 225 : appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
4011 ECB :
4012 GIC 261 : if (polinfo->polwithcheck != NULL)
4013 CBC 123 : appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
4014 :
4015 261 : appendPQExpBufferStr(query, ";\n");
4016 ECB :
4017 GIC 261 : appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
4018 CBC 261 : appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
4019 :
4020 261 : appendPQExpBuffer(polprefix, "POLICY %s ON",
4021 261 : fmtId(polinfo->polname));
4022 ECB :
4023 CBC 261 : tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
4024 ECB :
4025 CBC 261 : if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4026 261 : ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
4027 261 : ARCHIVE_OPTS(.tag = tag,
4028 ECB : .namespace = polinfo->dobj.namespace->dobj.name,
4029 : .owner = tbinfo->rolname,
4030 : .description = "POLICY",
4031 : .section = SECTION_POST_DATA,
4032 : .createStmt = query->data,
4033 : .dropStmt = delqry->data));
4034 :
4035 GIC 261 : if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4036 LBC 0 : dumpComment(fout, polprefix->data, qtabname,
4037 UIC 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
4038 LBC 0 : polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
4039 ECB :
4040 GIC 261 : free(tag);
4041 CBC 261 : destroyPQExpBuffer(query);
4042 GIC 261 : destroyPQExpBuffer(delqry);
4043 CBC 261 : destroyPQExpBuffer(polprefix);
4044 261 : free(qtabname);
4045 : }
4046 ECB :
4047 : /*
4048 : * getPublications
4049 : * get information about publications
4050 : */
4051 : PublicationInfo *
4052 GIC 118 : getPublications(Archive *fout, int *numPublications)
4053 ECB : {
4054 CBC 118 : DumpOptions *dopt = fout->dopt;
4055 : PQExpBuffer query;
4056 : PGresult *res;
4057 : PublicationInfo *pubinfo;
4058 : int i_tableoid;
4059 : int i_oid;
4060 : int i_pubname;
4061 : int i_pubowner;
4062 ECB : int i_puballtables;
4063 : int i_pubinsert;
4064 : int i_pubupdate;
4065 : int i_pubdelete;
4066 : int i_pubtruncate;
4067 : int i_pubviaroot;
4068 : int i,
4069 : ntups;
4070 :
4071 GIC 118 : if (dopt->no_publications || fout->remoteVersion < 100000)
4072 : {
4073 UIC 0 : *numPublications = 0;
4074 LBC 0 : return NULL;
4075 ECB : }
4076 :
4077 GIC 118 : query = createPQExpBuffer();
4078 :
4079 118 : resetPQExpBuffer(query);
4080 :
4081 : /* Get the publications. */
4082 CBC 118 : if (fout->remoteVersion >= 130000)
4083 GNC 118 : appendPQExpBufferStr(query,
4084 : "SELECT p.tableoid, p.oid, p.pubname, "
4085 : "p.pubowner, "
4086 : "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate, p.pubviaroot "
4087 : "FROM pg_publication p");
4088 UIC 0 : else if (fout->remoteVersion >= 110000)
4089 UNC 0 : appendPQExpBufferStr(query,
4090 : "SELECT p.tableoid, p.oid, p.pubname, "
4091 : "p.pubowner, "
4092 : "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate, false AS pubviaroot "
4093 : "FROM pg_publication p");
4094 ECB : else
4095 UNC 0 : appendPQExpBufferStr(query,
4096 : "SELECT p.tableoid, p.oid, p.pubname, "
4097 : "p.pubowner, "
4098 : "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate, false AS pubviaroot "
4099 : "FROM pg_publication p");
4100 :
4101 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4102 :
4103 118 : ntups = PQntuples(res);
4104 :
4105 CBC 118 : i_tableoid = PQfnumber(res, "tableoid");
4106 118 : i_oid = PQfnumber(res, "oid");
4107 GIC 118 : i_pubname = PQfnumber(res, "pubname");
4108 118 : i_pubowner = PQfnumber(res, "pubowner");
4109 CBC 118 : i_puballtables = PQfnumber(res, "puballtables");
4110 118 : i_pubinsert = PQfnumber(res, "pubinsert");
4111 118 : i_pubupdate = PQfnumber(res, "pubupdate");
4112 118 : i_pubdelete = PQfnumber(res, "pubdelete");
4113 118 : i_pubtruncate = PQfnumber(res, "pubtruncate");
4114 118 : i_pubviaroot = PQfnumber(res, "pubviaroot");
4115 ECB :
4116 CBC 118 : pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
4117 ECB :
4118 CBC 298 : for (i = 0; i < ntups; i++)
4119 : {
4120 GBC 180 : pubinfo[i].dobj.objType = DO_PUBLICATION;
4121 GIC 180 : pubinfo[i].dobj.catId.tableoid =
4122 180 : atooid(PQgetvalue(res, i, i_tableoid));
4123 CBC 180 : pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4124 180 : AssignDumpId(&pubinfo[i].dobj);
4125 180 : pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
4126 GIC 180 : pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
4127 CBC 180 : pubinfo[i].puballtables =
4128 GIC 180 : (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
4129 CBC 180 : pubinfo[i].pubinsert =
4130 GIC 180 : (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
4131 CBC 180 : pubinfo[i].pubupdate =
4132 180 : (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
4133 GIC 180 : pubinfo[i].pubdelete =
4134 CBC 180 : (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
4135 180 : pubinfo[i].pubtruncate =
4136 GIC 180 : (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
4137 CBC 180 : pubinfo[i].pubviaroot =
4138 180 : (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
4139 :
4140 ECB : /* Decide whether we want to dump it */
4141 CBC 180 : selectDumpableObject(&(pubinfo[i].dobj), fout);
4142 : }
4143 118 : PQclear(res);
4144 :
4145 118 : destroyPQExpBuffer(query);
4146 ECB :
4147 GIC 118 : *numPublications = ntups;
4148 CBC 118 : return pubinfo;
4149 ECB : }
4150 :
4151 : /*
4152 : * dumpPublication
4153 : * dump the definition of the given publication
4154 : */
4155 : static void
4156 GIC 152 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
4157 : {
4158 152 : DumpOptions *dopt = fout->dopt;
4159 : PQExpBuffer delq;
4160 : PQExpBuffer query;
4161 : char *qpubname;
4162 152 : bool first = true;
4163 ECB :
4164 EUB : /* Do nothing in data-only dump */
4165 GBC 152 : if (dopt->dataOnly)
4166 12 : return;
4167 :
4168 CBC 140 : delq = createPQExpBuffer();
4169 140 : query = createPQExpBuffer();
4170 ECB :
4171 CBC 140 : qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
4172 ECB :
4173 GIC 140 : appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
4174 : qpubname);
4175 :
4176 140 : appendPQExpBuffer(query, "CREATE PUBLICATION %s",
4177 : qpubname);
4178 :
4179 140 : if (pubinfo->puballtables)
4180 CBC 35 : appendPQExpBufferStr(query, " FOR ALL TABLES");
4181 :
4182 140 : appendPQExpBufferStr(query, " WITH (publish = '");
4183 GIC 140 : if (pubinfo->pubinsert)
4184 : {
4185 105 : appendPQExpBufferStr(query, "insert");
4186 105 : first = false;
4187 : }
4188 :
4189 140 : if (pubinfo->pubupdate)
4190 : {
4191 105 : if (!first)
4192 105 : appendPQExpBufferStr(query, ", ");
4193 :
4194 105 : appendPQExpBufferStr(query, "update");
4195 105 : first = false;
4196 : }
4197 :
4198 140 : if (pubinfo->pubdelete)
4199 ECB : {
4200 GIC 105 : if (!first)
4201 GBC 105 : appendPQExpBufferStr(query, ", ");
4202 EUB :
4203 GIC 105 : appendPQExpBufferStr(query, "delete");
4204 105 : first = false;
4205 ECB : }
4206 :
4207 CBC 140 : if (pubinfo->pubtruncate)
4208 : {
4209 GIC 105 : if (!first)
4210 CBC 105 : appendPQExpBufferStr(query, ", ");
4211 ECB :
4212 GIC 105 : appendPQExpBufferStr(query, "truncate");
4213 105 : first = false;
4214 : }
4215 :
4216 GNC 140 : appendPQExpBufferChar(query, '\'');
4217 EUB :
4218 GIC 140 : if (pubinfo->pubviaroot)
4219 UIC 0 : appendPQExpBufferStr(query, ", publish_via_partition_root = true");
4220 :
4221 GIC 140 : appendPQExpBufferStr(query, ");\n");
4222 :
4223 GBC 140 : if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4224 GIC 140 : ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
4225 140 : ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
4226 : .owner = pubinfo->rolname,
4227 : .description = "PUBLICATION",
4228 : .section = SECTION_POST_DATA,
4229 ECB : .createStmt = query->data,
4230 : .dropStmt = delq->data));
4231 :
4232 GIC 140 : if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4233 CBC 35 : dumpComment(fout, "PUBLICATION", qpubname,
4234 35 : NULL, pubinfo->rolname,
4235 35 : pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4236 ECB :
4237 CBC 140 : if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4238 LBC 0 : dumpSecLabel(fout, "PUBLICATION", qpubname,
4239 0 : NULL, pubinfo->rolname,
4240 0 : pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4241 ECB :
4242 CBC 140 : destroyPQExpBuffer(delq);
4243 GIC 140 : destroyPQExpBuffer(query);
4244 CBC 140 : free(qpubname);
4245 : }
4246 ECB :
4247 : /*
4248 : * getPublicationNamespaces
4249 : * get information about publication membership for dumpable schemas.
4250 : */
4251 : void
4252 CBC 118 : getPublicationNamespaces(Archive *fout)
4253 ECB : {
4254 : PQExpBuffer query;
4255 : PGresult *res;
4256 : PublicationSchemaInfo *pubsinfo;
4257 CBC 118 : DumpOptions *dopt = fout->dopt;
4258 ECB : int i_tableoid;
4259 : int i_oid;
4260 : int i_pnpubid;
4261 : int i_pnnspid;
4262 : int i,
4263 : j,
4264 : ntups;
4265 :
4266 CBC 118 : if (dopt->no_publications || fout->remoteVersion < 150000)
4267 UIC 0 : return;
4268 :
4269 CBC 118 : query = createPQExpBuffer();
4270 :
4271 ECB : /* Collect all publication membership info. */
4272 GIC 118 : appendPQExpBufferStr(query,
4273 ECB : "SELECT tableoid, oid, pnpubid, pnnspid "
4274 : "FROM pg_catalog.pg_publication_namespace");
4275 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4276 ECB :
4277 GIC 118 : ntups = PQntuples(res);
4278 :
4279 118 : i_tableoid = PQfnumber(res, "tableoid");
4280 118 : i_oid = PQfnumber(res, "oid");
4281 118 : i_pnpubid = PQfnumber(res, "pnpubid");
4282 118 : i_pnnspid = PQfnumber(res, "pnnspid");
4283 :
4284 ECB : /* this allocation may be more than we need */
4285 GIC 118 : pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
4286 CBC 118 : j = 0;
4287 :
4288 GIC 208 : for (i = 0; i < ntups; i++)
4289 : {
4290 CBC 90 : Oid pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
4291 GIC 90 : Oid pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
4292 : PublicationInfo *pubinfo;
4293 ECB : NamespaceInfo *nspinfo;
4294 :
4295 : /*
4296 : * Ignore any entries for which we aren't interested in either the
4297 : * publication or the rel.
4298 : */
4299 CBC 90 : pubinfo = findPublicationByOid(pnpubid);
4300 GIC 90 : if (pubinfo == NULL)
4301 LBC 0 : continue;
4302 GIC 90 : nspinfo = findNamespaceByOid(pnnspid);
4303 90 : if (nspinfo == NULL)
4304 LBC 0 : continue;
4305 :
4306 : /*
4307 ECB : * We always dump publication namespaces unless the corresponding
4308 : * namespace is excluded from the dump.
4309 : */
4310 CBC 90 : if (nspinfo->dobj.dump == DUMP_COMPONENT_NONE)
4311 13 : continue;
4312 :
4313 ECB : /* OK, make a DumpableObject for this relationship */
4314 CBC 77 : pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
4315 GIC 77 : pubsinfo[j].dobj.catId.tableoid =
4316 77 : atooid(PQgetvalue(res, i, i_tableoid));
4317 CBC 77 : pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4318 GIC 77 : AssignDumpId(&pubsinfo[j].dobj);
4319 CBC 77 : pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
4320 77 : pubsinfo[j].dobj.name = nspinfo->dobj.name;
4321 GIC 77 : pubsinfo[j].publication = pubinfo;
4322 CBC 77 : pubsinfo[j].pubschema = nspinfo;
4323 ECB :
4324 : /* Decide whether we want to dump it */
4325 GIC 77 : selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
4326 ECB :
4327 GIC 77 : j++;
4328 ECB : }
4329 :
4330 GIC 118 : PQclear(res);
4331 CBC 118 : destroyPQExpBuffer(query);
4332 ECB : }
4333 :
4334 : /*
4335 : * getPublicationTables
4336 : * get information about publication membership for dumpable tables.
4337 : */
4338 : void
4339 GIC 118 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
4340 ECB : {
4341 : PQExpBuffer query;
4342 : PGresult *res;
4343 : PublicationRelInfo *pubrinfo;
4344 CBC 118 : DumpOptions *dopt = fout->dopt;
4345 : int i_tableoid;
4346 ECB : int i_oid;
4347 EUB : int i_prpubid;
4348 : int i_prrelid;
4349 ECB : int i_prrelqual;
4350 : int i_prattrs;
4351 : int i,
4352 : j,
4353 : ntups;
4354 :
4355 GIC 118 : if (dopt->no_publications || fout->remoteVersion < 100000)
4356 UIC 0 : return;
4357 :
4358 GIC 118 : query = createPQExpBuffer();
4359 :
4360 ECB : /* Collect all publication membership info. */
4361 CBC 118 : if (fout->remoteVersion >= 150000)
4362 118 : appendPQExpBufferStr(query,
4363 ECB : "SELECT tableoid, oid, prpubid, prrelid, "
4364 : "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
4365 : "(CASE\n"
4366 EUB : " WHEN pr.prattrs IS NOT NULL THEN\n"
4367 : " (SELECT array_agg(attname)\n"
4368 : " FROM\n"
4369 : " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
4370 ECB : " pg_catalog.pg_attribute\n"
4371 : " WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
4372 : " ELSE NULL END) prattrs "
4373 : "FROM pg_catalog.pg_publication_rel pr");
4374 : else
4375 UIC 0 : appendPQExpBufferStr(query,
4376 : "SELECT tableoid, oid, prpubid, prrelid, "
4377 : "NULL AS prrelqual, NULL AS prattrs "
4378 : "FROM pg_catalog.pg_publication_rel");
4379 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4380 ECB :
4381 GIC 118 : ntups = PQntuples(res);
4382 :
4383 118 : i_tableoid = PQfnumber(res, "tableoid");
4384 118 : i_oid = PQfnumber(res, "oid");
4385 CBC 118 : i_prpubid = PQfnumber(res, "prpubid");
4386 GIC 118 : i_prrelid = PQfnumber(res, "prrelid");
4387 118 : i_prrelqual = PQfnumber(res, "prrelqual");
4388 118 : i_prattrs = PQfnumber(res, "prattrs");
4389 :
4390 : /* this allocation may be more than we need */
4391 118 : pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
4392 118 : j = 0;
4393 :
4394 CBC 433 : for (i = 0; i < ntups; i++)
4395 EUB : {
4396 GIC 315 : Oid prpubid = atooid(PQgetvalue(res, i, i_prpubid));
4397 CBC 315 : Oid prrelid = atooid(PQgetvalue(res, i, i_prrelid));
4398 : PublicationInfo *pubinfo;
4399 : TableInfo *tbinfo;
4400 ECB :
4401 : /*
4402 : * Ignore any entries for which we aren't interested in either the
4403 : * publication or the rel.
4404 : */
4405 CBC 315 : pubinfo = findPublicationByOid(prpubid);
4406 GIC 315 : if (pubinfo == NULL)
4407 LBC 0 : continue;
4408 CBC 315 : tbinfo = findTableByOid(prrelid);
4409 315 : if (tbinfo == NULL)
4410 LBC 0 : continue;
4411 :
4412 : /*
4413 ECB : * Ignore publication membership of tables whose definitions are not
4414 : * to be dumped.
4415 : */
4416 CBC 315 : if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4417 GIC 39 : continue;
4418 ECB :
4419 : /* OK, make a DumpableObject for this relationship */
4420 GIC 276 : pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
4421 276 : pubrinfo[j].dobj.catId.tableoid =
4422 276 : atooid(PQgetvalue(res, i, i_tableoid));
4423 276 : pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4424 276 : AssignDumpId(&pubrinfo[j].dobj);
4425 276 : pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4426 276 : pubrinfo[j].dobj.name = tbinfo->dobj.name;
4427 CBC 276 : pubrinfo[j].publication = pubinfo;
4428 276 : pubrinfo[j].pubtable = tbinfo;
4429 GBC 276 : if (PQgetisnull(res, i, i_prrelqual))
4430 CBC 158 : pubrinfo[j].pubrelqual = NULL;
4431 ECB : else
4432 GBC 118 : pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
4433 :
4434 GIC 276 : if (!PQgetisnull(res, i, i_prattrs))
4435 : {
4436 : char **attnames;
4437 : int nattnames;
4438 ECB : PQExpBuffer attribs;
4439 :
4440 GIC 78 : if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
4441 : &attnames, &nattnames))
4442 LBC 0 : pg_fatal("could not parse %s array", "prattrs");
4443 CBC 78 : attribs = createPQExpBuffer();
4444 234 : for (int k = 0; k < nattnames; k++)
4445 ECB : {
4446 CBC 156 : if (k > 0)
4447 78 : appendPQExpBufferStr(attribs, ", ");
4448 ECB :
4449 CBC 156 : appendPQExpBufferStr(attribs, fmtId(attnames[k]));
4450 ECB : }
4451 GIC 78 : pubrinfo[j].pubrattrs = attribs->data;
4452 : }
4453 ECB : else
4454 GIC 198 : pubrinfo[j].pubrattrs = NULL;
4455 ECB :
4456 : /* Decide whether we want to dump it */
4457 GIC 276 : selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
4458 ECB :
4459 CBC 276 : j++;
4460 : }
4461 :
4462 GIC 118 : PQclear(res);
4463 118 : destroyPQExpBuffer(query);
4464 : }
4465 :
4466 : /*
4467 ECB : * dumpPublicationNamespace
4468 : * dump the definition of the given publication schema mapping.
4469 : */
4470 : static void
4471 GIC 75 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
4472 ECB : {
4473 GIC 75 : DumpOptions *dopt = fout->dopt;
4474 75 : NamespaceInfo *schemainfo = pubsinfo->pubschema;
4475 75 : PublicationInfo *pubinfo = pubsinfo->publication;
4476 : PQExpBuffer query;
4477 : char *tag;
4478 :
4479 : /* Do nothing in data-only dump */
4480 75 : if (dopt->dataOnly)
4481 6 : return;
4482 :
4483 CBC 69 : tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
4484 EUB :
4485 GIC 69 : query = createPQExpBuffer();
4486 ECB :
4487 GIC 69 : appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
4488 69 : appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
4489 ECB :
4490 : /*
4491 : * There is no point in creating drop query as the drop is done by schema
4492 : * drop.
4493 : */
4494 GIC 69 : if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4495 69 : ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
4496 69 : ARCHIVE_OPTS(.tag = tag,
4497 : .namespace = schemainfo->dobj.name,
4498 : .owner = pubinfo->rolname,
4499 : .description = "PUBLICATION TABLES IN SCHEMA",
4500 : .section = SECTION_POST_DATA,
4501 : .createStmt = query->data));
4502 :
4503 EUB : /* These objects can't currently have comments or seclabels */
4504 :
4505 GIC 69 : free(tag);
4506 69 : destroyPQExpBuffer(query);
4507 ECB : }
4508 :
4509 : /*
4510 : * dumpPublicationTable
4511 : * dump the definition of the given publication table mapping
4512 : */
4513 : static void
4514 CBC 256 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
4515 ECB : {
4516 CBC 256 : DumpOptions *dopt = fout->dopt;
4517 GIC 256 : PublicationInfo *pubinfo = pubrinfo->publication;
4518 256 : TableInfo *tbinfo = pubrinfo->pubtable;
4519 ECB : PQExpBuffer query;
4520 : char *tag;
4521 :
4522 : /* Do nothing in data-only dump */
4523 GIC 256 : if (dopt->dataOnly)
4524 CBC 21 : return;
4525 ECB :
4526 GIC 235 : tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
4527 :
4528 235 : query = createPQExpBuffer();
4529 :
4530 235 : appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4531 235 : fmtId(pubinfo->dobj.name));
4532 235 : appendPQExpBuffer(query, " %s",
4533 CBC 235 : fmtQualifiedDumpable(tbinfo));
4534 ECB :
4535 GBC 235 : if (pubrinfo->pubrattrs)
4536 CBC 68 : appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
4537 ECB :
4538 GBC 235 : if (pubrinfo->pubrelqual)
4539 : {
4540 : /*
4541 : * It's necessary to add parentheses around the expression because
4542 : * pg_get_expr won't supply the parentheses for things like WHERE
4543 : * TRUE.
4544 ECB : */
4545 CBC 101 : appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
4546 : }
4547 GIC 235 : appendPQExpBufferStr(query, ";\n");
4548 ECB :
4549 : /*
4550 : * There is no point in creating a drop query as the drop is done by table
4551 : * drop. (If you think to change this, see also _printTocEntry().)
4552 : * Although this object doesn't really have ownership as such, set the
4553 : * owner field anyway to ensure that the command is run by the correct
4554 : * role at restore time.
4555 : */
4556 CBC 235 : if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4557 235 : ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
4558 235 : ARCHIVE_OPTS(.tag = tag,
4559 : .namespace = tbinfo->dobj.namespace->dobj.name,
4560 ECB : .owner = pubinfo->rolname,
4561 : .description = "PUBLICATION TABLE",
4562 : .section = SECTION_POST_DATA,
4563 : .createStmt = query->data));
4564 :
4565 : /* These objects can't currently have comments or seclabels */
4566 :
4567 GIC 235 : free(tag);
4568 CBC 235 : destroyPQExpBuffer(query);
4569 : }
4570 EUB :
4571 ECB : /*
4572 : * Is the currently connected user a superuser?
4573 : */
4574 : static bool
4575 CBC 118 : is_superuser(Archive *fout)
4576 : {
4577 118 : ArchiveHandle *AH = (ArchiveHandle *) fout;
4578 : const char *val;
4579 ECB :
4580 GIC 118 : val = PQparameterStatus(AH->connection, "is_superuser");
4581 :
4582 CBC 118 : if (val && strcmp(val, "on") == 0)
4583 GIC 116 : return true;
4584 :
4585 CBC 2 : return false;
4586 : }
4587 ECB :
4588 : /*
4589 : * getSubscriptions
4590 : * get information about subscriptions
4591 : */
4592 : void
4593 GIC 118 : getSubscriptions(Archive *fout)
4594 : {
4595 118 : DumpOptions *dopt = fout->dopt;
4596 : PQExpBuffer query;
4597 : PGresult *res;
4598 : SubscriptionInfo *subinfo;
4599 ECB : int i_tableoid;
4600 : int i_oid;
4601 : int i_subname;
4602 : int i_subowner;
4603 : int i_substream;
4604 : int i_subtwophasestate;
4605 : int i_subdisableonerr;
4606 : int i_suborigin;
4607 : int i_subconninfo;
4608 : int i_subslotname;
4609 : int i_subsynccommit;
4610 : int i_subpublications;
4611 : int i_subbinary;
4612 : int i_subpasswordrequired;
4613 : int i,
4614 : ntups;
4615 :
4616 GIC 118 : if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4617 LBC 0 : return;
4618 ECB :
4619 GIC 118 : if (!is_superuser(fout))
4620 : {
4621 : int n;
4622 :
4623 2 : res = ExecuteSqlQuery(fout,
4624 ECB : "SELECT count(*) FROM pg_subscription "
4625 : "WHERE subdbid = (SELECT oid FROM pg_database"
4626 : " WHERE datname = current_database())",
4627 : PGRES_TUPLES_OK);
4628 GIC 2 : n = atoi(PQgetvalue(res, 0, 0));
4629 2 : if (n > 0)
4630 2 : pg_log_warning("subscriptions not dumped because current user is not a superuser");
4631 2 : PQclear(res);
4632 2 : return;
4633 : }
4634 :
4635 CBC 116 : query = createPQExpBuffer();
4636 ECB :
4637 : /* Get the subscriptions in current database. */
4638 GNC 116 : appendPQExpBufferStr(query,
4639 : "SELECT s.tableoid, s.oid, s.subname,\n"
4640 : " s.subowner,\n"
4641 : " s.subconninfo, s.subslotname, s.subsynccommit,\n"
4642 : " s.subpublications,\n");
4643 :
4644 CBC 116 : if (fout->remoteVersion >= 140000)
4645 GIC 116 : appendPQExpBufferStr(query, " s.subbinary,\n");
4646 ECB : else
4647 LBC 0 : appendPQExpBufferStr(query, " false AS subbinary,\n");
4648 ECB :
4649 GIC 116 : if (fout->remoteVersion >= 140000)
4650 116 : appendPQExpBufferStr(query, " s.substream,\n");
4651 : else
4652 UNC 0 : appendPQExpBufferStr(query, " 'f' AS substream,\n");
4653 ECB :
4654 CBC 116 : if (fout->remoteVersion >= 150000)
4655 GIC 116 : appendPQExpBufferStr(query,
4656 ECB : " s.subtwophasestate,\n"
4657 : " s.subdisableonerr,\n");
4658 : else
4659 UIC 0 : appendPQExpBuffer(query,
4660 ECB : " '%c' AS subtwophasestate,\n"
4661 : " false AS subdisableonerr,\n",
4662 : LOGICALREP_TWOPHASE_STATE_DISABLED);
4663 :
4664 GNC 116 : if (fout->remoteVersion >= 160000)
4665 116 : appendPQExpBufferStr(query,
4666 : " s.suborigin,\n"
4667 : " s.subpasswordrequired\n");
4668 : else
4669 UNC 0 : appendPQExpBuffer(query,
4670 : " '%s' AS suborigin,\n"
4671 : " 't' AS subpasswordrequired\n",
4672 : LOGICALREP_ORIGIN_ANY);
4673 :
4674 GIC 116 : appendPQExpBufferStr(query,
4675 ECB : "FROM pg_subscription s\n"
4676 : "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
4677 : " WHERE datname = current_database())");
4678 :
4679 GIC 116 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4680 :
4681 116 : ntups = PQntuples(res);
4682 :
4683 : /*
4684 : * Get subscription fields. We don't include subskiplsn in the dump as
4685 ECB : * after restoring the dump this value may no longer be relevant.
4686 : */
4687 CBC 116 : i_tableoid = PQfnumber(res, "tableoid");
4688 GIC 116 : i_oid = PQfnumber(res, "oid");
4689 116 : i_subname = PQfnumber(res, "subname");
4690 116 : i_subowner = PQfnumber(res, "subowner");
4691 116 : i_subconninfo = PQfnumber(res, "subconninfo");
4692 116 : i_subslotname = PQfnumber(res, "subslotname");
4693 116 : i_subsynccommit = PQfnumber(res, "subsynccommit");
4694 116 : i_subpublications = PQfnumber(res, "subpublications");
4695 116 : i_subbinary = PQfnumber(res, "subbinary");
4696 CBC 116 : i_substream = PQfnumber(res, "substream");
4697 116 : i_subtwophasestate = PQfnumber(res, "subtwophasestate");
4698 116 : i_subdisableonerr = PQfnumber(res, "subdisableonerr");
4699 GNC 116 : i_suborigin = PQfnumber(res, "suborigin");
4700 116 : i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
4701 :
4702 GIC 116 : subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4703 :
4704 245 : for (i = 0; i < ntups; i++)
4705 : {
4706 129 : subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4707 129 : subinfo[i].dobj.catId.tableoid =
4708 129 : atooid(PQgetvalue(res, i, i_tableoid));
4709 CBC 129 : subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4710 129 : AssignDumpId(&subinfo[i].dobj);
4711 GIC 129 : subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4712 129 : subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
4713 129 : subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
4714 129 : if (PQgetisnull(res, i, i_subslotname))
4715 UIC 0 : subinfo[i].subslotname = NULL;
4716 : else
4717 CBC 129 : subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
4718 GIC 258 : subinfo[i].subsynccommit =
4719 CBC 129 : pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4720 GIC 258 : subinfo[i].subpublications =
4721 129 : pg_strdup(PQgetvalue(res, i, i_subpublications));
4722 CBC 258 : subinfo[i].subbinary =
4723 GIC 129 : pg_strdup(PQgetvalue(res, i, i_subbinary));
4724 CBC 258 : subinfo[i].substream =
4725 129 : pg_strdup(PQgetvalue(res, i, i_substream));
4726 GIC 258 : subinfo[i].subtwophasestate =
4727 CBC 129 : pg_strdup(PQgetvalue(res, i, i_subtwophasestate));
4728 GIC 258 : subinfo[i].subdisableonerr =
4729 129 : pg_strdup(PQgetvalue(res, i, i_subdisableonerr));
4730 GNC 129 : subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
4731 258 : subinfo[i].subpasswordrequired =
4732 129 : pg_strdup(PQgetvalue(res, i, i_subpasswordrequired));
4733 :
4734 : /* Decide whether we want to dump it */
4735 GIC 129 : selectDumpableObject(&(subinfo[i].dobj), fout);
4736 : }
4737 116 : PQclear(res);
4738 ECB :
4739 GIC 116 : destroyPQExpBuffer(query);
4740 ECB : }
4741 :
4742 : /*
4743 : * dumpSubscription
4744 : * dump the definition of the given subscription
4745 : */
4746 : static void
4747 GIC 114 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
4748 : {
4749 114 : DumpOptions *dopt = fout->dopt;
4750 : PQExpBuffer delq;
4751 : PQExpBuffer query;
4752 : PQExpBuffer publications;
4753 : char *qsubname;
4754 114 : char **pubnames = NULL;
4755 114 : int npubnames = 0;
4756 : int i;
4757 114 : char two_phase_disabled[] = {LOGICALREP_TWOPHASE_STATE_DISABLED, '\0'};
4758 :
4759 : /* Do nothing in data-only dump */
4760 114 : if (dopt->dataOnly)
4761 CBC 9 : return;
4762 EUB :
4763 GIC 105 : delq = createPQExpBuffer();
4764 CBC 105 : query = createPQExpBuffer();
4765 :
4766 GIC 105 : qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4767 :
4768 CBC 105 : appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4769 : qsubname);
4770 :
4771 GIC 105 : appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4772 : qsubname);
4773 CBC 105 : appendStringLiteralAH(query, subinfo->subconninfo, fout);
4774 ECB :
4775 : /* Build list of quoted publications and append them to query. */
4776 CBC 105 : if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
4777 LBC 0 : pg_fatal("could not parse %s array", "subpublications");
4778 :
4779 GIC 105 : publications = createPQExpBuffer();
4780 CBC 210 : for (i = 0; i < npubnames; i++)
4781 : {
4782 GIC 105 : if (i > 0)
4783 LBC 0 : appendPQExpBufferStr(publications, ", ");
4784 :
4785 GIC 105 : appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4786 : }
4787 :
4788 105 : appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
4789 CBC 105 : if (subinfo->subslotname)
4790 105 : appendStringLiteralAH(query, subinfo->subslotname, fout);
4791 : else
4792 UBC 0 : appendPQExpBufferStr(query, "NONE");
4793 :
4794 CBC 105 : if (strcmp(subinfo->subbinary, "t") == 0)
4795 LBC 0 : appendPQExpBufferStr(query, ", binary = true");
4796 :
4797 GNC 105 : if (strcmp(subinfo->substream, "t") == 0)
4798 UIC 0 : appendPQExpBufferStr(query, ", streaming = on");
4799 GNC 105 : else if (strcmp(subinfo->substream, "p") == 0)
4800 UNC 0 : appendPQExpBufferStr(query, ", streaming = parallel");
4801 ECB :
4802 CBC 105 : if (strcmp(subinfo->subtwophasestate, two_phase_disabled) != 0)
4803 UIC 0 : appendPQExpBufferStr(query, ", two_phase = on");
4804 :
4805 GIC 105 : if (strcmp(subinfo->subdisableonerr, "t") == 0)
4806 UBC 0 : appendPQExpBufferStr(query, ", disable_on_error = true");
4807 :
4808 GNC 105 : if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
4809 35 : appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
4810 :
4811 GIC 105 : if (strcmp(subinfo->subsynccommit, "off") != 0)
4812 UIC 0 : appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4813 :
4814 GNC 105 : if (strcmp(subinfo->subpasswordrequired, "t") != 0)
4815 UNC 0 : appendPQExpBuffer(query, ", password_required = false");
4816 :
4817 CBC 105 : appendPQExpBufferStr(query, ");\n");
4818 ECB :
4819 GIC 105 : if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4820 105 : ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
4821 105 : ARCHIVE_OPTS(.tag = subinfo->dobj.name,
4822 EUB : .owner = subinfo->rolname,
4823 : .description = "SUBSCRIPTION",
4824 : .section = SECTION_POST_DATA,
4825 : .createStmt = query->data,
4826 : .dropStmt = delq->data));
4827 ECB :
4828 GIC 105 : if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4829 35 : dumpComment(fout, "SUBSCRIPTION", qsubname,
4830 35 : NULL, subinfo->rolname,
4831 35 : subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4832 ECB :
4833 GIC 105 : if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4834 LBC 0 : dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
4835 UIC 0 : NULL, subinfo->rolname,
4836 0 : subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4837 :
4838 GIC 105 : destroyPQExpBuffer(publications);
4839 GNC 105 : free(pubnames);
4840 ECB :
4841 CBC 105 : destroyPQExpBuffer(delq);
4842 105 : destroyPQExpBuffer(query);
4843 105 : free(qsubname);
4844 ECB : }
4845 :
4846 : /*
4847 : * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
4848 : * the object needs.
4849 : */
4850 : static void
4851 CBC 4296 : append_depends_on_extension(Archive *fout,
4852 ECB : PQExpBuffer create,
4853 : const DumpableObject *dobj,
4854 : const char *catalog,
4855 : const char *keyword,
4856 : const char *objname)
4857 : {
4858 CBC 4296 : if (dobj->depends_on_ext)
4859 ECB : {
4860 : char *nm;
4861 : PGresult *res;
4862 : PQExpBuffer query;
4863 : int ntups;
4864 : int i_extname;
4865 : int i;
4866 :
4867 EUB : /* dodge fmtId() non-reentrancy */
4868 GIC 38 : nm = pg_strdup(objname);
4869 ECB :
4870 CBC 38 : query = createPQExpBuffer();
4871 38 : appendPQExpBuffer(query,
4872 ECB : "SELECT e.extname "
4873 : "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
4874 : "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
4875 : "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
4876 : "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
4877 : catalog,
4878 CBC 38 : dobj->catId.oid);
4879 38 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4880 38 : ntups = PQntuples(res);
4881 38 : i_extname = PQfnumber(res, "extname");
4882 76 : for (i = 0; i < ntups; i++)
4883 ECB : {
4884 CBC 38 : appendPQExpBuffer(create, "ALTER %s %s DEPENDS ON EXTENSION %s;\n",
4885 : keyword, nm,
4886 GIC 38 : fmtId(PQgetvalue(res, i, i_extname)));
4887 ECB : }
4888 :
4889 CBC 38 : PQclear(res);
4890 GIC 38 : destroyPQExpBuffer(query);
4891 CBC 38 : pg_free(nm);
4892 : }
4893 GIC 4296 : }
4894 :
4895 : static Oid
4896 UIC 0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
4897 : {
4898 : /*
4899 ECB : * If the old version didn't assign an array type, but the new version
4900 : * does, we must select an unused type OID to assign. This currently only
4901 : * happens for domains, when upgrading pre-v11 to v11 and up.
4902 : *
4903 : * Note: local state here is kind of ugly, but we must have some, since we
4904 : * mustn't choose the same unused OID more than once.
4905 : */
4906 : static Oid next_possible_free_oid = FirstNormalObjectId;
4907 : PGresult *res;
4908 : bool is_dup;
4909 :
4910 : do
4911 : {
4912 LBC 0 : ++next_possible_free_oid;
4913 0 : printfPQExpBuffer(upgrade_query,
4914 : "SELECT EXISTS(SELECT 1 "
4915 ECB : "FROM pg_catalog.pg_type "
4916 : "WHERE oid = '%u'::pg_catalog.oid);",
4917 : next_possible_free_oid);
4918 LBC 0 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4919 UIC 0 : is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
4920 LBC 0 : PQclear(res);
4921 UIC 0 : } while (is_dup);
4922 :
4923 LBC 0 : return next_possible_free_oid;
4924 : }
4925 ECB :
4926 : static void
4927 GIC 771 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4928 ECB : PQExpBuffer upgrade_buffer,
4929 EUB : Oid pg_type_oid,
4930 : bool force_array_type,
4931 ECB : bool include_multirange_type)
4932 : {
4933 GIC 771 : PQExpBuffer upgrade_query = createPQExpBuffer();
4934 ECB : PGresult *res;
4935 EUB : Oid pg_type_array_oid;
4936 : Oid pg_type_multirange_oid;
4937 ECB : Oid pg_type_multirange_array_oid;
4938 :
4939 GIC 771 : appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4940 CBC 771 : appendPQExpBuffer(upgrade_buffer,
4941 ECB : "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4942 : pg_type_oid);
4943 :
4944 GBC 771 : appendPQExpBuffer(upgrade_query,
4945 : "SELECT typarray "
4946 ECB : "FROM pg_catalog.pg_type "
4947 EUB : "WHERE oid = '%u'::pg_catalog.oid;",
4948 : pg_type_oid);
4949 ECB :
4950 GBC 771 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4951 ECB :
4952 GBC 771 : pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4953 :
4954 CBC 771 : PQclear(res);
4955 EUB :
4956 GIC 771 : if (!OidIsValid(pg_type_array_oid) && force_array_type)
4957 LBC 0 : pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
4958 EUB :
4959 GIC 771 : if (OidIsValid(pg_type_array_oid))
4960 ECB : {
4961 CBC 769 : appendPQExpBufferStr(upgrade_buffer,
4962 : "\n-- For binary upgrade, must preserve pg_type array oid\n");
4963 769 : appendPQExpBuffer(upgrade_buffer,
4964 EUB : "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4965 : pg_type_array_oid);
4966 ECB : }
4967 EUB :
4968 : /*
4969 ECB : * Pre-set the multirange type oid and its own array type oid.
4970 : */
4971 CBC 771 : if (include_multirange_type)
4972 ECB : {
4973 CBC 6 : if (fout->remoteVersion >= 140000)
4974 : {
4975 GIC 6 : printfPQExpBuffer(upgrade_query,
4976 : "SELECT t.oid, t.typarray "
4977 : "FROM pg_catalog.pg_type t "
4978 : "JOIN pg_catalog.pg_range r "
4979 : "ON t.oid = r.rngmultitypid "
4980 ECB : "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
4981 : pg_type_oid);
4982 :
4983 CBC 6 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4984 :
4985 6 : pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
4986 GBC 6 : pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4987 EUB :
4988 GBC 6 : PQclear(res);
4989 : }
4990 ECB : else
4991 : {
4992 UIC 0 : pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
4993 LBC 0 : pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
4994 ECB : }
4995 :
4996 GIC 6 : appendPQExpBufferStr(upgrade_buffer,
4997 : "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
4998 6 : appendPQExpBuffer(upgrade_buffer,
4999 : "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5000 : pg_type_multirange_oid);
5001 6 : appendPQExpBufferStr(upgrade_buffer,
5002 : "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
5003 CBC 6 : appendPQExpBuffer(upgrade_buffer,
5004 : "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5005 : pg_type_multirange_array_oid);
5006 : }
5007 :
5008 GIC 771 : destroyPQExpBuffer(upgrade_query);
5009 771 : }
5010 ECB :
5011 : static void
5012 GIC 709 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
5013 : PQExpBuffer upgrade_buffer,
5014 : const TableInfo *tbinfo)
5015 : {
5016 709 : Oid pg_type_oid = tbinfo->reltype;
5017 :
5018 709 : if (OidIsValid(pg_type_oid))
5019 709 : binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
5020 ECB : pg_type_oid, false, false);
5021 GIC 709 : }
5022 ECB :
5023 : static void
5024 GIC 1028 : binary_upgrade_set_pg_class_oids(Archive *fout,
5025 : PQExpBuffer upgrade_buffer, Oid pg_class_oid,
5026 : bool is_index)
5027 : {
5028 1028 : PQExpBuffer upgrade_query = createPQExpBuffer();
5029 : PGresult *upgrade_res;
5030 : RelFileNumber relfilenumber;
5031 ECB : Oid toast_oid;
5032 : RelFileNumber toast_relfilenumber;
5033 : char relkind;
5034 : Oid toast_index_oid;
5035 : RelFileNumber toast_index_relfilenumber;
5036 :
5037 : /*
5038 : * Preserve the OID and relfilenumber of the table, table's index, table's
5039 : * toast table and toast table's index if any.
5040 : *
5041 : * One complexity is that the current table definition might not require
5042 : * the creation of a TOAST table, but the old database might have a TOAST
5043 : * table that was created earlier, before some wide columns were dropped.
5044 : * By setting the TOAST oid we force creation of the TOAST heap and index
5045 : * by the new backend, so we can copy the files during binary upgrade
5046 : * without worrying about this case.
5047 : */
5048 GBC 1028 : appendPQExpBuffer(upgrade_query,
5049 : "SELECT c.relkind, c.relfilenode, c.reltoastrelid, ct.relfilenode AS toast_relfilenode, i.indexrelid, cti.relfilenode AS toast_index_relfilenode "
5050 : "FROM pg_catalog.pg_class c LEFT JOIN "
5051 : "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
5052 : "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
5053 : "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
5054 : "WHERE c.oid = '%u'::pg_catalog.oid;",
5055 : pg_class_oid);
5056 :
5057 GIC 1028 : upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5058 :
5059 1028 : relkind = *PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "relkind"));
5060 :
5061 GNC 1028 : relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
5062 : PQfnumber(upgrade_res, "relfilenode")));
5063 GIC 1028 : toast_oid = atooid(PQgetvalue(upgrade_res, 0,
5064 EUB : PQfnumber(upgrade_res, "reltoastrelid")));
5065 GNC 1028 : toast_relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
5066 : PQfnumber(upgrade_res, "toast_relfilenode")));
5067 GIC 1028 : toast_index_oid = atooid(PQgetvalue(upgrade_res, 0,
5068 : PQfnumber(upgrade_res, "indexrelid")));
5069 GNC 1028 : toast_index_relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
5070 : PQfnumber(upgrade_res, "toast_index_relfilenode")));
5071 EUB :
5072 GBC 1028 : appendPQExpBufferStr(upgrade_buffer,
5073 EUB : "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
5074 :
5075 GBC 1028 : if (!is_index)
5076 : {
5077 GIC 773 : appendPQExpBuffer(upgrade_buffer,
5078 : "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
5079 ECB : pg_class_oid);
5080 :
5081 : /*
5082 : * Not every relation has storage. Also, in a pre-v12 database,
5083 : * partitioned tables have a relfilenumber, which should not be
5084 : * preserved when upgrading.
5085 : */
5086 GNC 773 : if (RelFileNumberIsValid(relfilenumber) && relkind != RELKIND_PARTITIONED_TABLE)
5087 GIC 628 : appendPQExpBuffer(upgrade_buffer,
5088 : "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
5089 : relfilenumber);
5090 :
5091 ECB : /*
5092 : * In a pre-v12 database, partitioned tables might be marked as having
5093 : * toast tables, but we should ignore them if so.
5094 : */
5095 GIC 773 : if (OidIsValid(toast_oid) &&
5096 ECB : relkind != RELKIND_PARTITIONED_TABLE)
5097 : {
5098 GIC 251 : appendPQExpBuffer(upgrade_buffer,
5099 : "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
5100 : toast_oid);
5101 251 : appendPQExpBuffer(upgrade_buffer,
5102 ECB : "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
5103 : toast_relfilenumber);
5104 :
5105 : /* every toast table has an index */
5106 CBC 251 : appendPQExpBuffer(upgrade_buffer,
5107 : "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5108 ECB : toast_index_oid);
5109 GBC 251 : appendPQExpBuffer(upgrade_buffer,
5110 : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5111 : toast_index_relfilenumber);
5112 : }
5113 ECB :
5114 GIC 773 : PQclear(upgrade_res);
5115 ECB : }
5116 : else
5117 : {
5118 : /* Preserve the OID and relfilenumber of the index */
5119 GIC 255 : appendPQExpBuffer(upgrade_buffer,
5120 : "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5121 : pg_class_oid);
5122 255 : appendPQExpBuffer(upgrade_buffer,
5123 ECB : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5124 : relfilenumber);
5125 : }
5126 :
5127 CBC 1028 : appendPQExpBufferChar(upgrade_buffer, '\n');
5128 :
5129 GIC 1028 : destroyPQExpBuffer(upgrade_query);
5130 1028 : }
5131 :
5132 : /*
5133 : * If the DumpableObject is a member of an extension, add a suitable
5134 : * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
5135 ECB : *
5136 : * For somewhat historical reasons, objname should already be quoted,
5137 : * but not objnamespace (if any).
5138 : */
5139 : static void
5140 CBC 1233 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
5141 : const DumpableObject *dobj,
5142 : const char *objtype,
5143 : const char *objname,
5144 EUB : const char *objnamespace)
5145 : {
5146 GIC 1233 : DumpableObject *extobj = NULL;
5147 : int i;
5148 ECB :
5149 GIC 1233 : if (!dobj->ext_member)
5150 CBC 1217 : return;
5151 :
5152 : /*
5153 ECB : * Find the parent extension. We could avoid this search if we wanted to
5154 : * add a link field to DumpableObject, but the space costs of that would
5155 : * be considerable. We assume that member objects could only have a
5156 : * direct dependency on their own extension, not any others.
5157 : */
5158 GIC 16 : for (i = 0; i < dobj->nDeps; i++)
5159 : {
5160 CBC 16 : extobj = findObjectByDumpId(dobj->dependencies[i]);
5161 16 : if (extobj && extobj->objType == DO_EXTENSION)
5162 GIC 16 : break;
5163 UIC 0 : extobj = NULL;
5164 ECB : }
5165 GIC 16 : if (extobj == NULL)
5166 UIC 0 : pg_fatal("could not find parent extension for %s %s",
5167 : objtype, objname);
5168 ECB :
5169 GIC 16 : appendPQExpBufferStr(upgrade_buffer,
5170 ECB : "\n-- For binary upgrade, handle extension membership the hard way\n");
5171 CBC 16 : appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
5172 GIC 16 : fmtId(extobj->name),
5173 ECB : objtype);
5174 GIC 16 : if (objnamespace && *objnamespace)
5175 13 : appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
5176 CBC 16 : appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
5177 : }
5178 :
5179 : /*
5180 ECB : * getNamespaces:
5181 : * read all namespaces in the system catalogs and return them in the
5182 : * NamespaceInfo* structure
5183 : *
5184 : * numNamespaces is set to the number of namespaces read in
5185 : */
5186 : NamespaceInfo *
5187 GIC 119 : getNamespaces(Archive *fout, int *numNamespaces)
5188 : {
5189 : PGresult *res;
5190 : int ntups;
5191 : int i;
5192 : PQExpBuffer query;
5193 : NamespaceInfo *nsinfo;
5194 : int i_tableoid;
5195 : int i_oid;
5196 : int i_nspname;
5197 : int i_nspowner;
5198 : int i_nspacl;
5199 : int i_acldefault;
5200 ECB :
5201 GIC 119 : query = createPQExpBuffer();
5202 :
5203 : /*
5204 : * we fetch all namespaces including system ones, so that every object we
5205 : * read in can be linked to a containing namespace.
5206 : */
5207 GNC 119 : appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
5208 : "n.nspowner, "
5209 : "n.nspacl, "
5210 : "acldefault('n', n.nspowner) AS acldefault "
5211 : "FROM pg_namespace n");
5212 :
5213 CBC 119 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5214 :
5215 119 : ntups = PQntuples(res);
5216 :
5217 119 : nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
5218 :
5219 119 : i_tableoid = PQfnumber(res, "tableoid");
5220 GIC 119 : i_oid = PQfnumber(res, "oid");
5221 CBC 119 : i_nspname = PQfnumber(res, "nspname");
5222 GIC 119 : i_nspowner = PQfnumber(res, "nspowner");
5223 119 : i_nspacl = PQfnumber(res, "nspacl");
5224 CBC 119 : i_acldefault = PQfnumber(res, "acldefault");
5225 :
5226 GIC 902 : for (i = 0; i < ntups; i++)
5227 ECB : {
5228 : const char *nspowner;
5229 :
5230 GIC 783 : nsinfo[i].dobj.objType = DO_NAMESPACE;
5231 783 : nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5232 783 : nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5233 783 : AssignDumpId(&nsinfo[i].dobj);
5234 783 : nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
5235 783 : nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
5236 783 : nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
5237 783 : nsinfo[i].dacl.privtype = 0;
5238 CBC 783 : nsinfo[i].dacl.initprivs = NULL;
5239 783 : nspowner = PQgetvalue(res, i, i_nspowner);
5240 GIC 783 : nsinfo[i].nspowner = atooid(nspowner);
5241 783 : nsinfo[i].rolname = getRoleName(nspowner);
5242 :
5243 : /* Decide whether to dump this namespace */
5244 783 : selectDumpableNamespace(&nsinfo[i], fout);
5245 :
5246 : /* Mark whether namespace has an ACL */
5247 CBC 783 : if (!PQgetisnull(res, i, i_nspacl))
5248 GIC 403 : nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5249 :
5250 ECB : /*
5251 : * We ignore any pg_init_privs.initprivs entry for the public schema
5252 : * and assume a predetermined default, for several reasons. First,
5253 : * dropping and recreating the schema removes its pg_init_privs entry,
5254 : * but an empty destination database starts with this ACL nonetheless.
5255 : * Second, we support dump/reload of public schema ownership changes.
5256 : * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
5257 : * initprivs continues to reflect the initial owner. Hence,
5258 : * synthesize the value that nspacl will have after the restore's
5259 : * ALTER SCHEMA OWNER. Third, this makes the destination database
5260 : * match the source's ACL, even if the latter was an initdb-default
5261 : * ACL, which changed in v15. An upgrade pulls in changes to most
5262 : * system object ACLs that the DBA had not customized. We've made the
5263 : * public schema depart from that, because changing its ACL so easily
5264 : * breaks applications.
5265 : */
5266 CBC 783 : if (strcmp(nsinfo[i].dobj.name, "public") == 0)
5267 : {
5268 GIC 115 : PQExpBuffer aclarray = createPQExpBuffer();
5269 115 : PQExpBuffer aclitem = createPQExpBuffer();
5270 :
5271 ECB : /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
5272 GIC 115 : appendPQExpBufferChar(aclarray, '{');
5273 115 : quoteAclUserName(aclitem, nsinfo[i].rolname);
5274 CBC 115 : appendPQExpBufferStr(aclitem, "=UC/");
5275 GIC 115 : quoteAclUserName(aclitem, nsinfo[i].rolname);
5276 115 : appendPGArray(aclarray, aclitem->data);
5277 115 : resetPQExpBuffer(aclitem);
5278 115 : appendPQExpBufferStr(aclitem, "=U/");
5279 CBC 115 : quoteAclUserName(aclitem, nsinfo[i].rolname);
5280 GIC 115 : appendPGArray(aclarray, aclitem->data);
5281 CBC 115 : appendPQExpBufferChar(aclarray, '}');
5282 ECB :
5283 GIC 115 : nsinfo[i].dacl.privtype = 'i';
5284 115 : nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
5285 115 : nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5286 :
5287 115 : destroyPQExpBuffer(aclarray);
5288 115 : destroyPQExpBuffer(aclitem);
5289 : }
5290 : }
5291 :
5292 CBC 119 : PQclear(res);
5293 GIC 119 : destroyPQExpBuffer(query);
5294 :
5295 119 : *numNamespaces = ntups;
5296 :
5297 119 : return nsinfo;
5298 ECB : }
5299 :
5300 : /*
5301 : * findNamespace:
5302 : * given a namespace OID, look up the info read by getNamespaces
5303 : */
5304 : static NamespaceInfo *
5305 GIC 446370 : findNamespace(Oid nsoid)
5306 : {
5307 : NamespaceInfo *nsinfo;
5308 :
5309 446370 : nsinfo = findNamespaceByOid(nsoid);
5310 CBC 446370 : if (nsinfo == NULL)
5311 UIC 0 : pg_fatal("schema with OID %u does not exist", nsoid);
5312 CBC 446370 : return nsinfo;
5313 ECB : }
5314 :
5315 EUB : /*
5316 : * getExtensions:
5317 ECB : * read all extensions in the system catalogs and return them in the
5318 EUB : * ExtensionInfo* structure
5319 : *
5320 : * numExtensions is set to the number of extensions read in
5321 ECB : */
5322 : ExtensionInfo *
5323 CBC 119 : getExtensions(Archive *fout, int *numExtensions)
5324 ECB : {
5325 GIC 119 : DumpOptions *dopt = fout->dopt;
5326 ECB : PGresult *res;
5327 : int ntups;
5328 : int i;
5329 : PQExpBuffer query;
5330 : ExtensionInfo *extinfo;
5331 : int i_tableoid;
5332 : int i_oid;
5333 : int i_extname;
5334 : int i_nspname;
5335 : int i_extrelocatable;
5336 : int i_extversion;
5337 : int i_extconfig;
5338 : int i_extcondition;
5339 :
5340 GIC 119 : query = createPQExpBuffer();
5341 :
5342 119 : appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
5343 : "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
5344 : "FROM pg_extension x "
5345 : "JOIN pg_namespace n ON n.oid = x.extnamespace");
5346 :
5347 119 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5348 :
5349 119 : ntups = PQntuples(res);
5350 :
5351 119 : extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
5352 :
5353 CBC 119 : i_tableoid = PQfnumber(res, "tableoid");
5354 GIC 119 : i_oid = PQfnumber(res, "oid");
5355 119 : i_extname = PQfnumber(res, "extname");
5356 119 : i_nspname = PQfnumber(res, "nspname");
5357 119 : i_extrelocatable = PQfnumber(res, "extrelocatable");
5358 119 : i_extversion = PQfnumber(res, "extversion");
5359 CBC 119 : i_extconfig = PQfnumber(res, "extconfig");
5360 GIC 119 : i_extcondition = PQfnumber(res, "extcondition");
5361 :
5362 260 : for (i = 0; i < ntups; i++)
5363 : {
5364 141 : extinfo[i].dobj.objType = DO_EXTENSION;
5365 CBC 141 : extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5366 GIC 141 : extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5367 CBC 141 : AssignDumpId(&extinfo[i].dobj);
5368 GIC 141 : extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
5369 CBC 141 : extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
5370 GIC 141 : extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
5371 CBC 141 : extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
5372 141 : extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
5373 141 : extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
5374 ECB :
5375 : /* Decide whether we want to dump it */
5376 CBC 141 : selectDumpableExtension(&(extinfo[i]), dopt);
5377 : }
5378 ECB :
5379 GIC 119 : PQclear(res);
5380 119 : destroyPQExpBuffer(query);
5381 :
5382 CBC 119 : *numExtensions = ntups;
5383 ECB :
5384 CBC 119 : return extinfo;
5385 ECB : }
5386 :
5387 : /*
5388 : * getTypes:
5389 : * read all types in the system catalogs and return them in the
5390 : * TypeInfo* structure
5391 : *
5392 : * numTypes is set to the number of types read in
5393 : *
5394 : * NB: this must run after getFuncs() because we assume we can do
5395 : * findFuncByOid().
5396 : */
5397 : TypeInfo *
5398 GIC 118 : getTypes(Archive *fout, int *numTypes)
5399 ECB : {
5400 : PGresult *res;
5401 : int ntups;
5402 : int i;
5403 GIC 118 : PQExpBuffer query = createPQExpBuffer();
5404 : TypeInfo *tyinfo;
5405 : ShellTypeInfo *stinfo;
5406 : int i_tableoid;
5407 : int i_oid;
5408 : int i_typname;
5409 : int i_typnamespace;
5410 : int i_typacl;
5411 : int i_acldefault;
5412 : int i_typowner;
5413 : int i_typelem;
5414 : int i_typrelid;
5415 : int i_typrelkind;
5416 : int i_typtype;
5417 : int i_typisdefined;
5418 ECB : int i_isarray;
5419 :
5420 : /*
5421 : * we include even the built-in types because those may be used as array
5422 : * elements by user-defined types
5423 : *
5424 : * we filter out the built-in types when we dump out the types
5425 : *
5426 : * same approach for undefined (shell) types and array types
5427 : *
5428 : * Note: as of 8.3 we can reliably detect whether a type is an
5429 : * auto-generated array type by checking the element type's typarray.
5430 : * (Before that the test is capable of generating false positives.) We
5431 : * still check for name beginning with '_', though, so as to avoid the
5432 : * cost of the subselect probe for all standard types. This would have to
5433 : * be revisited if the backend ever allows renaming of array types.
5434 : */
5435 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
5436 : "typnamespace, typacl, "
5437 : "acldefault('T', typowner) AS acldefault, "
5438 : "typowner, "
5439 : "typelem, typrelid, "
5440 : "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
5441 : "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
5442 : "typtype, typisdefined, "
5443 : "typname[0] = '_' AND typelem != 0 AND "
5444 : "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
5445 : "FROM pg_type");
5446 :
5447 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5448 :
5449 118 : ntups = PQntuples(res);
5450 :
5451 GIC 118 : tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
5452 :
5453 118 : i_tableoid = PQfnumber(res, "tableoid");
5454 118 : i_oid = PQfnumber(res, "oid");
5455 118 : i_typname = PQfnumber(res, "typname");
5456 118 : i_typnamespace = PQfnumber(res, "typnamespace");
5457 CBC 118 : i_typacl = PQfnumber(res, "typacl");
5458 GIC 118 : i_acldefault = PQfnumber(res, "acldefault");
5459 118 : i_typowner = PQfnumber(res, "typowner");
5460 118 : i_typelem = PQfnumber(res, "typelem");
5461 CBC 118 : i_typrelid = PQfnumber(res, "typrelid");
5462 118 : i_typrelkind = PQfnumber(res, "typrelkind");
5463 GBC 118 : i_typtype = PQfnumber(res, "typtype");
5464 CBC 118 : i_typisdefined = PQfnumber(res, "typisdefined");
5465 GIC 118 : i_isarray = PQfnumber(res, "isarray");
5466 :
5467 83984 : for (i = 0; i < ntups; i++)
5468 : {
5469 83866 : tyinfo[i].dobj.objType = DO_TYPE;
5470 83866 : tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5471 83866 : tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5472 83866 : AssignDumpId(&tyinfo[i].dobj);
5473 83866 : tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
5474 167732 : tyinfo[i].dobj.namespace =
5475 CBC 83866 : findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
5476 GIC 83866 : tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
5477 CBC 83866 : tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
5478 GIC 83866 : tyinfo[i].dacl.privtype = 0;
5479 83866 : tyinfo[i].dacl.initprivs = NULL;
5480 83866 : tyinfo[i].ftypname = NULL; /* may get filled later */
5481 83866 : tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
5482 83866 : tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
5483 83866 : tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
5484 83866 : tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
5485 83866 : tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
5486 83866 : tyinfo[i].shellType = NULL;
5487 :
5488 83866 : if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
5489 83816 : tyinfo[i].isDefined = true;
5490 : else
5491 50 : tyinfo[i].isDefined = false;
5492 ECB :
5493 GIC 83866 : if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
5494 CBC 40197 : tyinfo[i].isArray = true;
5495 : else
5496 GIC 43669 : tyinfo[i].isArray = false;
5497 :
5498 83866 : if (tyinfo[i].typtype == 'm')
5499 CBC 818 : tyinfo[i].isMultirange = true;
5500 : else
5501 83048 : tyinfo[i].isMultirange = false;
5502 :
5503 ECB : /* Decide whether we want to dump it */
5504 GIC 83866 : selectDumpableType(&tyinfo[i], fout);
5505 ECB :
5506 : /* Mark whether type has an ACL */
5507 CBC 83866 : if (!PQgetisnull(res, i, i_typacl))
5508 202 : tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5509 ECB :
5510 : /*
5511 : * If it's a domain, fetch info about its constraints, if any
5512 : */
5513 GIC 83866 : tyinfo[i].nDomChecks = 0;
5514 CBC 83866 : tyinfo[i].domChecks = NULL;
5515 GIC 83866 : if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
5516 CBC 10888 : tyinfo[i].typtype == TYPTYPE_DOMAIN)
5517 124 : getDomainConstraints(fout, &(tyinfo[i]));
5518 ECB :
5519 : /*
5520 : * If it's a base type, make a DumpableObject representing a shell
5521 : * definition of the type. We will need to dump that ahead of the I/O
5522 : * functions for the type. Similarly, range types need a shell
5523 : * definition in case they have a canonicalize function.
5524 : *
5525 : * Note: the shell type doesn't have a catId. You might think it
5526 : * should copy the base type's catId, but then it might capture the
5527 : * pg_depend entries for the type, which we don't want.
5528 : */
5529 GIC 83866 : if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
5530 10888 : (tyinfo[i].typtype == TYPTYPE_BASE ||
5531 CBC 5344 : tyinfo[i].typtype == TYPTYPE_RANGE))
5532 ECB : {
5533 GIC 5642 : stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
5534 CBC 5642 : stinfo->dobj.objType = DO_SHELL_TYPE;
5535 GIC 5642 : stinfo->dobj.catId = nilCatalogId;
5536 CBC 5642 : AssignDumpId(&stinfo->dobj);
5537 GIC 5642 : stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
5538 5642 : stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
5539 5642 : stinfo->baseType = &(tyinfo[i]);
5540 5642 : tyinfo[i].shellType = stinfo;
5541 :
5542 : /*
5543 : * Initially mark the shell type as not to be dumped. We'll only
5544 : * dump it if the I/O or canonicalize functions need to be dumped;
5545 : * this is taken care of while sorting dependencies.
5546 : */
5547 5642 : stinfo->dobj.dump = DUMP_COMPONENT_NONE;
5548 : }
5549 : }
5550 ECB :
5551 GIC 118 : *numTypes = ntups;
5552 :
5553 118 : PQclear(res);
5554 :
5555 CBC 118 : destroyPQExpBuffer(query);
5556 :
5557 GIC 118 : return tyinfo;
5558 : }
5559 :
5560 : /*
5561 : * getOperators:
5562 : * read all operators in the system catalogs and return them in the
5563 : * OprInfo* structure
5564 : *
5565 : * numOprs is set to the number of operators read in
5566 : */
5567 : OprInfo *
5568 118 : getOperators(Archive *fout, int *numOprs)
5569 : {
5570 : PGresult *res;
5571 : int ntups;
5572 : int i;
5573 118 : PQExpBuffer query = createPQExpBuffer();
5574 : OprInfo *oprinfo;
5575 : int i_tableoid;
5576 : int i_oid;
5577 : int i_oprname;
5578 : int i_oprnamespace;
5579 : int i_oprowner;
5580 : int i_oprkind;
5581 : int i_oprcode;
5582 :
5583 : /*
5584 : * find all operators, including builtin operators; we filter out
5585 : * system-defined operators at dump-out time.
5586 : */
5587 ECB :
5588 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
5589 : "oprnamespace, "
5590 : "oprowner, "
5591 : "oprkind, "
5592 : "oprcode::oid AS oprcode "
5593 : "FROM pg_operator");
5594 :
5595 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5596 :
5597 118 : ntups = PQntuples(res);
5598 118 : *numOprs = ntups;
5599 ECB :
5600 GIC 118 : oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
5601 ECB :
5602 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
5603 CBC 118 : i_oid = PQfnumber(res, "oid");
5604 GIC 118 : i_oprname = PQfnumber(res, "oprname");
5605 CBC 118 : i_oprnamespace = PQfnumber(res, "oprnamespace");
5606 118 : i_oprowner = PQfnumber(res, "oprowner");
5607 118 : i_oprkind = PQfnumber(res, "oprkind");
5608 118 : i_oprcode = PQfnumber(res, "oprcode");
5609 ECB :
5610 CBC 94514 : for (i = 0; i < ntups; i++)
5611 ECB : {
5612 CBC 94396 : oprinfo[i].dobj.objType = DO_OPERATOR;
5613 94396 : oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5614 94396 : oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5615 94396 : AssignDumpId(&oprinfo[i].dobj);
5616 94396 : oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
5617 188792 : oprinfo[i].dobj.namespace =
5618 GIC 94396 : findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
5619 CBC 94396 : oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
5620 GIC 94396 : oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
5621 CBC 94396 : oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
5622 ECB :
5623 : /* Decide whether we want to dump it */
5624 CBC 94396 : selectDumpableObject(&(oprinfo[i].dobj), fout);
5625 ECB : }
5626 :
5627 CBC 118 : PQclear(res);
5628 ECB :
5629 CBC 118 : destroyPQExpBuffer(query);
5630 ECB :
5631 CBC 118 : return oprinfo;
5632 ECB : }
5633 :
5634 : /*
5635 : * getCollations:
5636 : * read all collations in the system catalogs and return them in the
5637 : * CollInfo* structure
5638 : *
5639 : * numCollations is set to the number of collations read in
5640 : */
5641 : CollInfo *
5642 GIC 118 : getCollations(Archive *fout, int *numCollations)
5643 ECB : {
5644 : PGresult *res;
5645 : int ntups;
5646 : int i;
5647 : PQExpBuffer query;
5648 : CollInfo *collinfo;
5649 : int i_tableoid;
5650 : int i_oid;
5651 : int i_collname;
5652 : int i_collnamespace;
5653 : int i_collowner;
5654 :
5655 GIC 118 : query = createPQExpBuffer();
5656 ECB :
5657 : /*
5658 : * find all collations, including builtin collations; we filter out
5659 : * system-defined collations at dump-out time.
5660 : */
5661 :
5662 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
5663 : "collnamespace, "
5664 : "collowner "
5665 : "FROM pg_collation");
5666 ECB :
5667 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5668 ECB :
5669 CBC 118 : ntups = PQntuples(res);
5670 GIC 118 : *numCollations = ntups;
5671 :
5672 118 : collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5673 :
5674 118 : i_tableoid = PQfnumber(res, "tableoid");
5675 118 : i_oid = PQfnumber(res, "oid");
5676 118 : i_collname = PQfnumber(res, "collname");
5677 118 : i_collnamespace = PQfnumber(res, "collnamespace");
5678 118 : i_collowner = PQfnumber(res, "collowner");
5679 :
5680 172493 : for (i = 0; i < ntups; i++)
5681 ECB : {
5682 CBC 172375 : collinfo[i].dobj.objType = DO_COLLATION;
5683 172375 : collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5684 GIC 172375 : collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5685 CBC 172375 : AssignDumpId(&collinfo[i].dobj);
5686 172375 : collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5687 344750 : collinfo[i].dobj.namespace =
5688 172375 : findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
5689 172375 : collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
5690 ECB :
5691 : /* Decide whether we want to dump it */
5692 CBC 172375 : selectDumpableObject(&(collinfo[i].dobj), fout);
5693 : }
5694 :
5695 GIC 118 : PQclear(res);
5696 :
5697 118 : destroyPQExpBuffer(query);
5698 :
5699 CBC 118 : return collinfo;
5700 : }
5701 :
5702 : /*
5703 ECB : * getConversions:
5704 : * read all conversions in the system catalogs and return them in the
5705 : * ConvInfo* structure
5706 : *
5707 : * numConversions is set to the number of conversions read in
5708 : */
5709 : ConvInfo *
5710 GIC 118 : getConversions(Archive *fout, int *numConversions)
5711 : {
5712 : PGresult *res;
5713 : int ntups;
5714 : int i;
5715 : PQExpBuffer query;
5716 : ConvInfo *convinfo;
5717 : int i_tableoid;
5718 : int i_oid;
5719 : int i_conname;
5720 ECB : int i_connamespace;
5721 : int i_conowner;
5722 :
5723 GIC 118 : query = createPQExpBuffer();
5724 :
5725 ECB : /*
5726 : * find all conversions, including builtin conversions; we filter out
5727 : * system-defined conversions at dump-out time.
5728 : */
5729 :
5730 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
5731 : "connamespace, "
5732 : "conowner "
5733 : "FROM pg_conversion");
5734 :
5735 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5736 :
5737 118 : ntups = PQntuples(res);
5738 118 : *numConversions = ntups;
5739 :
5740 CBC 118 : convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5741 :
5742 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
5743 118 : i_oid = PQfnumber(res, "oid");
5744 118 : i_conname = PQfnumber(res, "conname");
5745 118 : i_connamespace = PQfnumber(res, "connamespace");
5746 118 : i_conowner = PQfnumber(res, "conowner");
5747 ECB :
5748 GIC 15267 : for (i = 0; i < ntups; i++)
5749 ECB : {
5750 CBC 15149 : convinfo[i].dobj.objType = DO_CONVERSION;
5751 GIC 15149 : convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5752 CBC 15149 : convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5753 GIC 15149 : AssignDumpId(&convinfo[i].dobj);
5754 CBC 15149 : convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5755 30298 : convinfo[i].dobj.namespace =
5756 15149 : findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
5757 15149 : convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
5758 ECB :
5759 : /* Decide whether we want to dump it */
5760 CBC 15149 : selectDumpableObject(&(convinfo[i].dobj), fout);
5761 : }
5762 ECB :
5763 GIC 118 : PQclear(res);
5764 ECB :
5765 CBC 118 : destroyPQExpBuffer(query);
5766 ECB :
5767 CBC 118 : return convinfo;
5768 ECB : }
5769 :
5770 : /*
5771 : * getAccessMethods:
5772 : * read all user-defined access methods in the system catalogs and return
5773 : * them in the AccessMethodInfo* structure
5774 : *
5775 : * numAccessMethods is set to the number of access methods read in
5776 : */
5777 : AccessMethodInfo *
5778 GIC 118 : getAccessMethods(Archive *fout, int *numAccessMethods)
5779 ECB : {
5780 : PGresult *res;
5781 : int ntups;
5782 : int i;
5783 : PQExpBuffer query;
5784 : AccessMethodInfo *aminfo;
5785 : int i_tableoid;
5786 : int i_oid;
5787 : int i_amname;
5788 : int i_amhandler;
5789 : int i_amtype;
5790 :
5791 : /* Before 9.6, there are no user-defined access methods */
5792 GIC 118 : if (fout->remoteVersion < 90600)
5793 : {
5794 LBC 0 : *numAccessMethods = 0;
5795 UIC 0 : return NULL;
5796 : }
5797 :
5798 GIC 118 : query = createPQExpBuffer();
5799 :
5800 : /* Select all access methods from pg_am table */
5801 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
5802 : "amhandler::pg_catalog.regproc AS amhandler "
5803 : "FROM pg_am");
5804 :
5805 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5806 :
5807 CBC 118 : ntups = PQntuples(res);
5808 GIC 118 : *numAccessMethods = ntups;
5809 :
5810 118 : aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
5811 :
5812 118 : i_tableoid = PQfnumber(res, "tableoid");
5813 118 : i_oid = PQfnumber(res, "oid");
5814 CBC 118 : i_amname = PQfnumber(res, "amname");
5815 GIC 118 : i_amhandler = PQfnumber(res, "amhandler");
5816 118 : i_amtype = PQfnumber(res, "amtype");
5817 :
5818 1061 : for (i = 0; i < ntups; i++)
5819 ECB : {
5820 GIC 943 : aminfo[i].dobj.objType = DO_ACCESS_METHOD;
5821 CBC 943 : aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5822 943 : aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5823 GIC 943 : AssignDumpId(&aminfo[i].dobj);
5824 CBC 943 : aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
5825 GIC 943 : aminfo[i].dobj.namespace = NULL;
5826 CBC 943 : aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5827 943 : aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
5828 ECB :
5829 : /* Decide whether we want to dump it */
5830 CBC 943 : selectDumpableAccessMethod(&(aminfo[i]), fout);
5831 : }
5832 ECB :
5833 GIC 118 : PQclear(res);
5834 ECB :
5835 CBC 118 : destroyPQExpBuffer(query);
5836 ECB :
5837 CBC 118 : return aminfo;
5838 ECB : }
5839 :
5840 :
5841 : /*
5842 : * getOpclasses:
5843 : * read all opclasses in the system catalogs and return them in the
5844 : * OpclassInfo* structure
5845 : *
5846 : * numOpclasses is set to the number of opclasses read in
5847 : */
5848 : OpclassInfo *
5849 CBC 118 : getOpclasses(Archive *fout, int *numOpclasses)
5850 : {
5851 ECB : PGresult *res;
5852 : int ntups;
5853 : int i;
5854 GIC 118 : PQExpBuffer query = createPQExpBuffer();
5855 : OpclassInfo *opcinfo;
5856 : int i_tableoid;
5857 : int i_oid;
5858 : int i_opcname;
5859 : int i_opcnamespace;
5860 : int i_opcowner;
5861 :
5862 ECB : /*
5863 : * find all opclasses, including builtin opclasses; we filter out
5864 : * system-defined opclasses at dump-out time.
5865 : */
5866 :
5867 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
5868 : "opcnamespace, "
5869 : "opcowner "
5870 : "FROM pg_opclass");
5871 :
5872 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5873 :
5874 118 : ntups = PQntuples(res);
5875 CBC 118 : *numOpclasses = ntups;
5876 :
5877 GIC 118 : opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5878 :
5879 118 : i_tableoid = PQfnumber(res, "tableoid");
5880 118 : i_oid = PQfnumber(res, "oid");
5881 118 : i_opcname = PQfnumber(res, "opcname");
5882 CBC 118 : i_opcnamespace = PQfnumber(res, "opcnamespace");
5883 GIC 118 : i_opcowner = PQfnumber(res, "opcowner");
5884 :
5885 21154 : for (i = 0; i < ntups; i++)
5886 : {
5887 CBC 21036 : opcinfo[i].dobj.objType = DO_OPCLASS;
5888 GIC 21036 : opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5889 CBC 21036 : opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5890 21036 : AssignDumpId(&opcinfo[i].dobj);
5891 GIC 21036 : opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5892 CBC 42072 : opcinfo[i].dobj.namespace =
5893 GIC 21036 : findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
5894 CBC 21036 : opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
5895 ECB :
5896 : /* Decide whether we want to dump it */
5897 CBC 21036 : selectDumpableObject(&(opcinfo[i].dobj), fout);
5898 ECB : }
5899 :
5900 CBC 118 : PQclear(res);
5901 :
5902 118 : destroyPQExpBuffer(query);
5903 ECB :
5904 CBC 118 : return opcinfo;
5905 ECB : }
5906 :
5907 : /*
5908 : * getOpfamilies:
5909 : * read all opfamilies in the system catalogs and return them in the
5910 : * OpfamilyInfo* structure
5911 : *
5912 : * numOpfamilies is set to the number of opfamilies read in
5913 : */
5914 : OpfamilyInfo *
5915 CBC 118 : getOpfamilies(Archive *fout, int *numOpfamilies)
5916 : {
5917 ECB : PGresult *res;
5918 : int ntups;
5919 : int i;
5920 : PQExpBuffer query;
5921 : OpfamilyInfo *opfinfo;
5922 : int i_tableoid;
5923 : int i_oid;
5924 : int i_opfname;
5925 : int i_opfnamespace;
5926 : int i_opfowner;
5927 :
5928 GIC 118 : query = createPQExpBuffer();
5929 :
5930 ECB : /*
5931 : * find all opfamilies, including builtin opfamilies; we filter out
5932 : * system-defined opfamilies at dump-out time.
5933 : */
5934 :
5935 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, opfname, "
5936 : "opfnamespace, "
5937 : "opfowner "
5938 : "FROM pg_opfamily");
5939 :
5940 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5941 :
5942 118 : ntups = PQntuples(res);
5943 118 : *numOpfamilies = ntups;
5944 ECB :
5945 GIC 118 : opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5946 EUB :
5947 GBC 118 : i_tableoid = PQfnumber(res, "tableoid");
5948 GIC 118 : i_oid = PQfnumber(res, "oid");
5949 118 : i_opfname = PQfnumber(res, "opfname");
5950 CBC 118 : i_opfnamespace = PQfnumber(res, "opfnamespace");
5951 GIC 118 : i_opfowner = PQfnumber(res, "opfowner");
5952 :
5953 CBC 17471 : for (i = 0; i < ntups; i++)
5954 : {
5955 GIC 17353 : opfinfo[i].dobj.objType = DO_OPFAMILY;
5956 17353 : opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5957 CBC 17353 : opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5958 GIC 17353 : AssignDumpId(&opfinfo[i].dobj);
5959 CBC 17353 : opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5960 34706 : opfinfo[i].dobj.namespace =
5961 GIC 17353 : findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
5962 CBC 17353 : opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
5963 :
5964 ECB : /* Decide whether we want to dump it */
5965 CBC 17353 : selectDumpableObject(&(opfinfo[i].dobj), fout);
5966 ECB : }
5967 :
5968 CBC 118 : PQclear(res);
5969 :
5970 118 : destroyPQExpBuffer(query);
5971 :
5972 118 : return opfinfo;
5973 ECB : }
5974 :
5975 : /*
5976 : * getAggregates:
5977 : * read all the user-defined aggregates in the system catalogs and
5978 : * return them in the AggInfo* structure
5979 : *
5980 : * numAggs is set to the number of aggregates read in
5981 : */
5982 : AggInfo *
5983 GIC 118 : getAggregates(Archive *fout, int *numAggs)
5984 : {
5985 CBC 118 : DumpOptions *dopt = fout->dopt;
5986 : PGresult *res;
5987 ECB : int ntups;
5988 : int i;
5989 CBC 118 : PQExpBuffer query = createPQExpBuffer();
5990 : AggInfo *agginfo;
5991 : int i_tableoid;
5992 : int i_oid;
5993 : int i_aggname;
5994 : int i_aggnamespace;
5995 : int i_pronargs;
5996 : int i_proargtypes;
5997 : int i_proowner;
5998 : int i_aggacl;
5999 : int i_acldefault;
6000 :
6001 ECB : /*
6002 : * Find all interesting aggregates. See comment in getFuncs() for the
6003 : * rationale behind the filtering logic.
6004 : */
6005 GIC 118 : if (fout->remoteVersion >= 90600)
6006 ECB : {
6007 : const char *agg_check;
6008 :
6009 GIC 236 : agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
6010 118 : : "p.proisagg");
6011 :
6012 118 : appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
6013 : "p.proname AS aggname, "
6014 : "p.pronamespace AS aggnamespace, "
6015 : "p.pronargs, p.proargtypes, "
6016 : "p.proowner, "
6017 : "p.proacl AS aggacl, "
6018 : "acldefault('f', p.proowner) AS acldefault "
6019 ECB : "FROM pg_proc p "
6020 : "LEFT JOIN pg_init_privs pip ON "
6021 : "(p.oid = pip.objoid "
6022 : "AND pip.classoid = 'pg_proc'::regclass "
6023 : "AND pip.objsubid = 0) "
6024 : "WHERE %s AND ("
6025 : "p.pronamespace != "
6026 : "(SELECT oid FROM pg_namespace "
6027 : "WHERE nspname = 'pg_catalog') OR "
6028 : "p.proacl IS DISTINCT FROM pip.initprivs",
6029 : agg_check);
6030 GIC 118 : if (dopt->binary_upgrade)
6031 CBC 8 : appendPQExpBufferStr(query,
6032 ECB : " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6033 : "classid = 'pg_proc'::regclass AND "
6034 : "objid = p.oid AND "
6035 : "refclassid = 'pg_extension'::regclass AND "
6036 : "deptype = 'e')");
6037 CBC 118 : appendPQExpBufferChar(query, ')');
6038 : }
6039 ECB : else
6040 : {
6041 UNC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
6042 : "pronamespace AS aggnamespace, "
6043 : "pronargs, proargtypes, "
6044 : "proowner, "
6045 : "proacl AS aggacl, "
6046 : "acldefault('f', proowner) AS acldefault "
6047 : "FROM pg_proc p "
6048 : "WHERE proisagg AND ("
6049 : "pronamespace != "
6050 : "(SELECT oid FROM pg_namespace "
6051 : "WHERE nspname = 'pg_catalog')");
6052 LBC 0 : if (dopt->binary_upgrade)
6053 UIC 0 : appendPQExpBufferStr(query,
6054 ECB : " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6055 : "classid = 'pg_proc'::regclass AND "
6056 : "objid = p.oid AND "
6057 : "refclassid = 'pg_extension'::regclass AND "
6058 : "deptype = 'e')");
6059 UIC 0 : appendPQExpBufferChar(query, ')');
6060 : }
6061 :
6062 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6063 :
6064 118 : ntups = PQntuples(res);
6065 118 : *numAggs = ntups;
6066 :
6067 CBC 118 : agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
6068 :
6069 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
6070 118 : i_oid = PQfnumber(res, "oid");
6071 118 : i_aggname = PQfnumber(res, "aggname");
6072 118 : i_aggnamespace = PQfnumber(res, "aggnamespace");
6073 118 : i_pronargs = PQfnumber(res, "pronargs");
6074 118 : i_proargtypes = PQfnumber(res, "proargtypes");
6075 118 : i_proowner = PQfnumber(res, "proowner");
6076 118 : i_aggacl = PQfnumber(res, "aggacl");
6077 118 : i_acldefault = PQfnumber(res, "acldefault");
6078 :
6079 420 : for (i = 0; i < ntups; i++)
6080 ECB : {
6081 GIC 302 : agginfo[i].aggfn.dobj.objType = DO_AGG;
6082 302 : agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6083 302 : agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6084 302 : AssignDumpId(&agginfo[i].aggfn.dobj);
6085 302 : agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
6086 604 : agginfo[i].aggfn.dobj.namespace =
6087 CBC 302 : findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
6088 GIC 302 : agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
6089 302 : agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6090 302 : agginfo[i].aggfn.dacl.privtype = 0;
6091 302 : agginfo[i].aggfn.dacl.initprivs = NULL;
6092 CBC 302 : agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
6093 GIC 302 : agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
6094 CBC 302 : agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
6095 302 : agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
6096 GIC 302 : if (agginfo[i].aggfn.nargs == 0)
6097 CBC 40 : agginfo[i].aggfn.argtypes = NULL;
6098 : else
6099 ECB : {
6100 CBC 262 : agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
6101 262 : parseOidArray(PQgetvalue(res, i, i_proargtypes),
6102 262 : agginfo[i].aggfn.argtypes,
6103 262 : agginfo[i].aggfn.nargs);
6104 : }
6105 ECB :
6106 : /* Decide whether we want to dump it */
6107 CBC 302 : selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
6108 ECB :
6109 : /* Mark whether aggregate has an ACL */
6110 CBC 302 : if (!PQgetisnull(res, i, i_aggacl))
6111 22 : agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
6112 ECB : }
6113 :
6114 CBC 118 : PQclear(res);
6115 :
6116 GIC 118 : destroyPQExpBuffer(query);
6117 ECB :
6118 GIC 118 : return agginfo;
6119 : }
6120 ECB :
6121 : /*
6122 : * getFuncs:
6123 : * read all the user-defined functions in the system catalogs and
6124 : * return them in the FuncInfo* structure
6125 : *
6126 : * numFuncs is set to the number of functions read in
6127 : */
6128 : FuncInfo *
6129 GIC 118 : getFuncs(Archive *fout, int *numFuncs)
6130 : {
6131 118 : DumpOptions *dopt = fout->dopt;
6132 : PGresult *res;
6133 : int ntups;
6134 : int i;
6135 CBC 118 : PQExpBuffer query = createPQExpBuffer();
6136 : FuncInfo *finfo;
6137 ECB : int i_tableoid;
6138 : int i_oid;
6139 : int i_proname;
6140 : int i_pronamespace;
6141 : int i_proowner;
6142 : int i_prolang;
6143 : int i_pronargs;
6144 : int i_proargtypes;
6145 : int i_prorettype;
6146 : int i_proacl;
6147 : int i_acldefault;
6148 :
6149 : /*
6150 : * Find all interesting functions. This is a bit complicated:
6151 : *
6152 : * 1. Always exclude aggregates; those are handled elsewhere.
6153 : *
6154 : * 2. Always exclude functions that are internally dependent on something
6155 : * else, since presumably those will be created as a result of creating
6156 : * the something else. This currently acts only to suppress constructor
6157 : * functions for range types. Note this is OK only because the
6158 : * constructors don't have any dependencies the range type doesn't have;
6159 : * otherwise we might not get creation ordering correct.
6160 : *
6161 : * 3. Otherwise, we normally exclude functions in pg_catalog. However, if
6162 : * they're members of extensions and we are in binary-upgrade mode then
6163 : * include them, since we want to dump extension members individually in
6164 : * that mode. Also, if they are used by casts or transforms then we need
6165 : * to gather the information about them, though they won't be dumped if
6166 : * they are built-in. Also, in 9.6 and up, include functions in
6167 : * pg_catalog if they have an ACL different from what's shown in
6168 : * pg_init_privs (so we have to join to pg_init_privs; annoying).
6169 : */
6170 GIC 118 : if (fout->remoteVersion >= 90600)
6171 : {
6172 : const char *not_agg_check;
6173 :
6174 236 : not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
6175 118 : : "NOT p.proisagg");
6176 :
6177 118 : appendPQExpBuffer(query,
6178 : "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
6179 : "p.pronargs, p.proargtypes, p.prorettype, "
6180 : "p.proacl, "
6181 : "acldefault('f', p.proowner) AS acldefault, "
6182 ECB : "p.pronamespace, "
6183 : "p.proowner "
6184 : "FROM pg_proc p "
6185 : "LEFT JOIN pg_init_privs pip ON "
6186 : "(p.oid = pip.objoid "
6187 : "AND pip.classoid = 'pg_proc'::regclass "
6188 : "AND pip.objsubid = 0) "
6189 : "WHERE %s"
6190 : "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6191 : "WHERE classid = 'pg_proc'::regclass AND "
6192 : "objid = p.oid AND deptype = 'i')"
6193 EUB : "\n AND ("
6194 : "\n pronamespace != "
6195 : "(SELECT oid FROM pg_namespace "
6196 : "WHERE nspname = 'pg_catalog')"
6197 : "\n OR EXISTS (SELECT 1 FROM pg_cast"
6198 : "\n WHERE pg_cast.oid > %u "
6199 : "\n AND p.oid = pg_cast.castfunc)"
6200 : "\n OR EXISTS (SELECT 1 FROM pg_transform"
6201 : "\n WHERE pg_transform.oid > %u AND "
6202 : "\n (p.oid = pg_transform.trffromsql"
6203 : "\n OR p.oid = pg_transform.trftosql))",
6204 : not_agg_check,
6205 : g_last_builtin_oid,
6206 : g_last_builtin_oid);
6207 GIC 118 : if (dopt->binary_upgrade)
6208 8 : appendPQExpBufferStr(query,
6209 : "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6210 : "classid = 'pg_proc'::regclass AND "
6211 EUB : "objid = p.oid AND "
6212 : "refclassid = 'pg_extension'::regclass AND "
6213 : "deptype = 'e')");
6214 CBC 118 : appendPQExpBufferStr(query,
6215 : "\n OR p.proacl IS DISTINCT FROM pip.initprivs");
6216 118 : appendPQExpBufferChar(query, ')');
6217 ECB : }
6218 : else
6219 : {
6220 UIC 0 : appendPQExpBuffer(query,
6221 ECB : "SELECT tableoid, oid, proname, prolang, "
6222 : "pronargs, proargtypes, prorettype, proacl, "
6223 : "acldefault('f', proowner) AS acldefault, "
6224 : "pronamespace, "
6225 : "proowner "
6226 : "FROM pg_proc p "
6227 : "WHERE NOT proisagg"
6228 : "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6229 : "WHERE classid = 'pg_proc'::regclass AND "
6230 : "objid = p.oid AND deptype = 'i')"
6231 : "\n AND ("
6232 : "\n pronamespace != "
6233 : "(SELECT oid FROM pg_namespace "
6234 : "WHERE nspname = 'pg_catalog')"
6235 : "\n OR EXISTS (SELECT 1 FROM pg_cast"
6236 : "\n WHERE pg_cast.oid > '%u'::oid"
6237 : "\n AND p.oid = pg_cast.castfunc)",
6238 : g_last_builtin_oid);
6239 :
6240 LBC 0 : if (fout->remoteVersion >= 90500)
6241 0 : appendPQExpBuffer(query,
6242 ECB : "\n OR EXISTS (SELECT 1 FROM pg_transform"
6243 : "\n WHERE pg_transform.oid > '%u'::oid"
6244 : "\n AND (p.oid = pg_transform.trffromsql"
6245 : "\n OR p.oid = pg_transform.trftosql))",
6246 : g_last_builtin_oid);
6247 :
6248 LBC 0 : if (dopt->binary_upgrade)
6249 0 : appendPQExpBufferStr(query,
6250 : "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6251 : "classid = 'pg_proc'::regclass AND "
6252 ECB : "objid = p.oid AND "
6253 : "refclassid = 'pg_extension'::regclass AND "
6254 : "deptype = 'e')");
6255 LBC 0 : appendPQExpBufferChar(query, ')');
6256 : }
6257 :
6258 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6259 ECB :
6260 GIC 118 : ntups = PQntuples(res);
6261 :
6262 CBC 118 : *numFuncs = ntups;
6263 ECB :
6264 GIC 118 : finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
6265 :
6266 CBC 118 : i_tableoid = PQfnumber(res, "tableoid");
6267 GIC 118 : i_oid = PQfnumber(res, "oid");
6268 CBC 118 : i_proname = PQfnumber(res, "proname");
6269 GIC 118 : i_pronamespace = PQfnumber(res, "pronamespace");
6270 CBC 118 : i_proowner = PQfnumber(res, "proowner");
6271 GIC 118 : i_prolang = PQfnumber(res, "prolang");
6272 118 : i_pronargs = PQfnumber(res, "pronargs");
6273 118 : i_proargtypes = PQfnumber(res, "proargtypes");
6274 118 : i_prorettype = PQfnumber(res, "prorettype");
6275 118 : i_proacl = PQfnumber(res, "proacl");
6276 118 : i_acldefault = PQfnumber(res, "acldefault");
6277 :
6278 3364 : for (i = 0; i < ntups; i++)
6279 : {
6280 3246 : finfo[i].dobj.objType = DO_FUNC;
6281 CBC 3246 : finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6282 GIC 3246 : finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6283 CBC 3246 : AssignDumpId(&finfo[i].dobj);
6284 GIC 3246 : finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
6285 6492 : finfo[i].dobj.namespace =
6286 3246 : findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
6287 CBC 3246 : finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
6288 GIC 3246 : finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6289 3246 : finfo[i].dacl.privtype = 0;
6290 3246 : finfo[i].dacl.initprivs = NULL;
6291 3246 : finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
6292 3246 : finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
6293 3246 : finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
6294 3246 : finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
6295 3246 : if (finfo[i].nargs == 0)
6296 737 : finfo[i].argtypes = NULL;
6297 : else
6298 : {
6299 2509 : finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
6300 2509 : parseOidArray(PQgetvalue(res, i, i_proargtypes),
6301 2509 : finfo[i].argtypes, finfo[i].nargs);
6302 : }
6303 :
6304 : /* Decide whether we want to dump it */
6305 3246 : selectDumpableObject(&(finfo[i].dobj), fout);
6306 :
6307 : /* Mark whether function has an ACL */
6308 3246 : if (!PQgetisnull(res, i, i_proacl))
6309 134 : finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6310 : }
6311 :
6312 118 : PQclear(res);
6313 :
6314 118 : destroyPQExpBuffer(query);
6315 :
6316 118 : return finfo;
6317 : }
6318 :
6319 : /*
6320 : * getTables
6321 : * read all the tables (no indexes) in the system catalogs,
6322 ECB : * and return them as an array of TableInfo structures
6323 : *
6324 : * *numTables is set to the number of tables read in
6325 : */
6326 : TableInfo *
6327 CBC 119 : getTables(Archive *fout, int *numTables)
6328 : {
6329 119 : DumpOptions *dopt = fout->dopt;
6330 : PGresult *res;
6331 : int ntups;
6332 : int i;
6333 GIC 119 : PQExpBuffer query = createPQExpBuffer();
6334 : TableInfo *tblinfo;
6335 : int i_reltableoid;
6336 : int i_reloid;
6337 : int i_relname;
6338 : int i_relnamespace;
6339 : int i_relkind;
6340 : int i_reltype;
6341 : int i_relowner;
6342 : int i_relchecks;
6343 : int i_relhasindex;
6344 : int i_relhasrules;
6345 : int i_relpages;
6346 : int i_toastpages;
6347 : int i_owning_tab;
6348 : int i_owning_col;
6349 : int i_reltablespace;
6350 : int i_relhasoids;
6351 : int i_relhastriggers;
6352 : int i_relpersistence;
6353 : int i_relispopulated;
6354 : int i_relreplident;
6355 : int i_relrowsec;
6356 : int i_relforcerowsec;
6357 : int i_relfrozenxid;
6358 : int i_toastfrozenxid;
6359 ECB : int i_toastoid;
6360 : int i_relminmxid;
6361 : int i_toastminmxid;
6362 : int i_reloptions;
6363 : int i_checkoption;
6364 : int i_toastreloptions;
6365 : int i_reloftype;
6366 : int i_foreignserver;
6367 : int i_amname;
6368 : int i_is_identity_sequence;
6369 : int i_relacl;
6370 : int i_acldefault;
6371 : int i_ispartition;
6372 EUB :
6373 : /*
6374 : * Find all the tables and table-like objects.
6375 : *
6376 : * We must fetch all tables in this phase because otherwise we cannot
6377 : * correctly identify inherited columns, owned sequences, etc.
6378 : *
6379 : * We include system catalogs, so that we can work if a user table is
6380 : * defined to inherit from a system catalog (pretty weird, but...)
6381 : *
6382 : * Note: in this phase we should collect only a minimal amount of
6383 : * information about each table, basically just enough to decide if it is
6384 : * interesting. In particular, since we do not yet have lock on any user
6385 : * table, we MUST NOT invoke any server-side data collection functions
6386 : * (for instance, pg_get_partkeydef()). Those are likely to fail or give
6387 : * wrong answers if any concurrent DDL is happening.
6388 : */
6389 :
6390 GNC 119 : appendPQExpBufferStr(query,
6391 : "SELECT c.tableoid, c.oid, c.relname, "
6392 : "c.relnamespace, c.relkind, c.reltype, "
6393 : "c.relowner, "
6394 : "c.relchecks, "
6395 : "c.relhasindex, c.relhasrules, c.relpages, "
6396 : "c.relhastriggers, "
6397 : "c.relpersistence, "
6398 : "c.reloftype, "
6399 : "c.relacl, "
6400 : "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
6401 : " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
6402 : "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
6403 : "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
6404 : "ELSE 0 END AS foreignserver, "
6405 : "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
6406 : "tc.oid AS toid, "
6407 : "tc.relpages AS toastpages, "
6408 : "tc.reloptions AS toast_reloptions, "
6409 : "d.refobjid AS owning_tab, "
6410 : "d.refobjsubid AS owning_col, "
6411 : "tsp.spcname AS reltablespace, ");
6412 ECB :
6413 GIC 119 : if (fout->remoteVersion >= 120000)
6414 CBC 119 : appendPQExpBufferStr(query,
6415 : "false AS relhasoids, ");
6416 ECB : else
6417 UIC 0 : appendPQExpBufferStr(query,
6418 ECB : "c.relhasoids, ");
6419 :
6420 CBC 119 : if (fout->remoteVersion >= 90300)
6421 119 : appendPQExpBufferStr(query,
6422 ECB : "c.relispopulated, ");
6423 : else
6424 LBC 0 : appendPQExpBufferStr(query,
6425 ECB : "'t' as relispopulated, ");
6426 :
6427 CBC 119 : if (fout->remoteVersion >= 90400)
6428 119 : appendPQExpBufferStr(query,
6429 : "c.relreplident, ");
6430 ECB : else
6431 UIC 0 : appendPQExpBufferStr(query,
6432 ECB : "'d' AS relreplident, ");
6433 :
6434 CBC 119 : if (fout->remoteVersion >= 90500)
6435 119 : appendPQExpBufferStr(query,
6436 ECB : "c.relrowsecurity, c.relforcerowsecurity, ");
6437 : else
6438 LBC 0 : appendPQExpBufferStr(query,
6439 ECB : "false AS relrowsecurity, "
6440 : "false AS relforcerowsecurity, ");
6441 :
6442 CBC 119 : if (fout->remoteVersion >= 90300)
6443 119 : appendPQExpBufferStr(query,
6444 ECB : "c.relminmxid, tc.relminmxid AS tminmxid, ");
6445 : else
6446 LBC 0 : appendPQExpBufferStr(query,
6447 ECB : "0 AS relminmxid, 0 AS tminmxid, ");
6448 :
6449 GIC 119 : if (fout->remoteVersion >= 90300)
6450 119 : appendPQExpBufferStr(query,
6451 ECB : "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6452 : "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6453 : "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
6454 : else
6455 UIC 0 : appendPQExpBufferStr(query,
6456 : "c.reloptions, NULL AS checkoption, ");
6457 ECB :
6458 GIC 119 : if (fout->remoteVersion >= 90600)
6459 119 : appendPQExpBufferStr(query,
6460 ECB : "am.amname, ");
6461 : else
6462 UIC 0 : appendPQExpBufferStr(query,
6463 : "NULL AS amname, ");
6464 ECB :
6465 GIC 119 : if (fout->remoteVersion >= 90600)
6466 CBC 119 : appendPQExpBufferStr(query,
6467 : "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
6468 ECB : else
6469 UIC 0 : appendPQExpBufferStr(query,
6470 : "false AS is_identity_sequence, ");
6471 :
6472 GIC 119 : if (fout->remoteVersion >= 100000)
6473 119 : appendPQExpBufferStr(query,
6474 : "c.relispartition AS ispartition ");
6475 : else
6476 UIC 0 : appendPQExpBufferStr(query,
6477 : "false AS ispartition ");
6478 :
6479 ECB : /*
6480 : * Left join to pg_depend to pick up dependency info linking sequences to
6481 : * their owning column, if any (note this dependency is AUTO except for
6482 : * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
6483 : * collect the spcname.
6484 : */
6485 CBC 119 : appendPQExpBufferStr(query,
6486 : "\nFROM pg_class c\n"
6487 : "LEFT JOIN pg_depend d ON "
6488 : "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
6489 : "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
6490 : "d.objsubid = 0 AND "
6491 : "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
6492 : "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
6493 :
6494 : /*
6495 : * In 9.6 and up, left join to pg_am to pick up the amname.
6496 : */
6497 GIC 119 : if (fout->remoteVersion >= 90600)
6498 119 : appendPQExpBufferStr(query,
6499 : "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
6500 :
6501 : /*
6502 : * We purposefully ignore toast OIDs for partitioned tables; the reason is
6503 : * that versions 10 and 11 have them, but later versions do not, so
6504 : * emitting them causes the upgrade to fail.
6505 : */
6506 119 : appendPQExpBufferStr(query,
6507 : "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
6508 : " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
6509 : " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
6510 :
6511 : /*
6512 : * Restrict to interesting relkinds (in particular, not indexes). Not all
6513 : * relkinds are possible in older servers, but it's not worth the trouble
6514 : * to emit a version-dependent list.
6515 : *
6516 : * Composite-type table entries won't be dumped as such, but we have to
6517 : * make a DumpableObject for them so that we can track dependencies of the
6518 : * composite type (pg_depend entries for columns of the composite type
6519 : * link to the pg_class entry not the pg_type entry).
6520 : */
6521 119 : appendPQExpBufferStr(query,
6522 : "WHERE c.relkind IN ("
6523 : CppAsString2(RELKIND_RELATION) ", "
6524 : CppAsString2(RELKIND_SEQUENCE) ", "
6525 : CppAsString2(RELKIND_VIEW) ", "
6526 : CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
6527 : CppAsString2(RELKIND_MATVIEW) ", "
6528 : CppAsString2(RELKIND_FOREIGN_TABLE) ", "
6529 : CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
6530 : "ORDER BY c.oid");
6531 :
6532 119 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6533 :
6534 119 : ntups = PQntuples(res);
6535 :
6536 119 : *numTables = ntups;
6537 :
6538 : /*
6539 : * Extract data from result and lock dumpable tables. We do the locking
6540 : * before anything else, to minimize the window wherein a table could
6541 : * disappear under us.
6542 ECB : *
6543 : * Note that we have to save info about all tables here, even when dumping
6544 : * only one, because we don't yet know which tables might be inheritance
6545 : * ancestors of the target table.
6546 : */
6547 GIC 119 : tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6548 :
6549 119 : i_reltableoid = PQfnumber(res, "tableoid");
6550 119 : i_reloid = PQfnumber(res, "oid");
6551 119 : i_relname = PQfnumber(res, "relname");
6552 119 : i_relnamespace = PQfnumber(res, "relnamespace");
6553 119 : i_relkind = PQfnumber(res, "relkind");
6554 119 : i_reltype = PQfnumber(res, "reltype");
6555 119 : i_relowner = PQfnumber(res, "relowner");
6556 119 : i_relchecks = PQfnumber(res, "relchecks");
6557 119 : i_relhasindex = PQfnumber(res, "relhasindex");
6558 119 : i_relhasrules = PQfnumber(res, "relhasrules");
6559 119 : i_relpages = PQfnumber(res, "relpages");
6560 119 : i_toastpages = PQfnumber(res, "toastpages");
6561 119 : i_owning_tab = PQfnumber(res, "owning_tab");
6562 119 : i_owning_col = PQfnumber(res, "owning_col");
6563 119 : i_reltablespace = PQfnumber(res, "reltablespace");
6564 119 : i_relhasoids = PQfnumber(res, "relhasoids");
6565 CBC 119 : i_relhastriggers = PQfnumber(res, "relhastriggers");
6566 119 : i_relpersistence = PQfnumber(res, "relpersistence");
6567 GIC 119 : i_relispopulated = PQfnumber(res, "relispopulated");
6568 119 : i_relreplident = PQfnumber(res, "relreplident");
6569 GBC 119 : i_relrowsec = PQfnumber(res, "relrowsecurity");
6570 GIC 119 : i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6571 119 : i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6572 CBC 119 : i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6573 119 : i_toastoid = PQfnumber(res, "toid");
6574 GIC 119 : i_relminmxid = PQfnumber(res, "relminmxid");
6575 119 : i_toastminmxid = PQfnumber(res, "tminmxid");
6576 GBC 119 : i_reloptions = PQfnumber(res, "reloptions");
6577 GIC 119 : i_checkoption = PQfnumber(res, "checkoption");
6578 119 : i_toastreloptions = PQfnumber(res, "toast_reloptions");
6579 CBC 119 : i_reloftype = PQfnumber(res, "reloftype");
6580 119 : i_foreignserver = PQfnumber(res, "foreignserver");
6581 GIC 119 : i_amname = PQfnumber(res, "amname");
6582 119 : i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6583 GBC 119 : i_relacl = PQfnumber(res, "relacl");
6584 GIC 119 : i_acldefault = PQfnumber(res, "acldefault");
6585 119 : i_ispartition = PQfnumber(res, "ispartition");
6586 ECB :
6587 CBC 119 : if (dopt->lockWaitTimeout)
6588 : {
6589 : /*
6590 EUB : * Arrange to fail instead of waiting forever for a table lock.
6591 : *
6592 : * NB: this coding assumes that the only queries issued within the
6593 : * following loop are LOCK TABLEs; else the timeout may be undesirably
6594 ECB : * applied to other things too.
6595 : */
6596 GIC 2 : resetPQExpBuffer(query);
6597 2 : appendPQExpBufferStr(query, "SET statement_timeout = ");
6598 GBC 2 : appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6599 GIC 2 : ExecuteSqlStatement(fout, query->data);
6600 : }
6601 ECB :
6602 GNC 119 : resetPQExpBuffer(query);
6603 :
6604 CBC 30724 : for (i = 0; i < ntups; i++)
6605 : {
6606 GIC 30605 : tblinfo[i].dobj.objType = DO_TABLE;
6607 30605 : tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6608 30605 : tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6609 GBC 30605 : AssignDumpId(&tblinfo[i].dobj);
6610 GIC 30605 : tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6611 61210 : tblinfo[i].dobj.namespace =
6612 CBC 30605 : findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
6613 30605 : tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
6614 GIC 30605 : tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6615 30605 : tblinfo[i].dacl.privtype = 0;
6616 GBC 30605 : tblinfo[i].dacl.initprivs = NULL;
6617 GIC 30605 : tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6618 30605 : tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
6619 CBC 30605 : tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
6620 30605 : tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6621 GIC 30605 : tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6622 30605 : tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6623 GBC 30605 : tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6624 GIC 30605 : if (PQgetisnull(res, i, i_toastpages))
6625 24303 : tblinfo[i].toastpages = 0;
6626 ECB : else
6627 CBC 6302 : tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
6628 GIC 30605 : if (PQgetisnull(res, i, i_owning_tab))
6629 : {
6630 GBC 30330 : tblinfo[i].owning_tab = InvalidOid;
6631 GIC 30330 : tblinfo[i].owning_col = 0;
6632 : }
6633 : else
6634 : {
6635 275 : tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6636 275 : tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6637 : }
6638 30605 : tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6639 CBC 30605 : tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6640 GIC 30605 : tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6641 30605 : tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6642 30605 : tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6643 30605 : tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6644 30605 : tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6645 30605 : tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6646 30605 : tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6647 30605 : tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6648 30605 : tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6649 30605 : tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6650 30605 : tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6651 CBC 30605 : tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6652 30605 : if (PQgetisnull(res, i, i_checkoption))
6653 GIC 30559 : tblinfo[i].checkoption = NULL;
6654 : else
6655 46 : tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6656 30605 : tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6657 30605 : tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
6658 30605 : tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
6659 30605 : if (PQgetisnull(res, i, i_amname))
6660 CBC 18182 : tblinfo[i].amname = NULL;
6661 : else
6662 GIC 12423 : tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
6663 30605 : tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6664 30605 : tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6665 :
6666 : /* other fields were zeroed above */
6667 :
6668 : /*
6669 : * Decide whether we want to dump this table.
6670 : */
6671 30605 : if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6672 138 : tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6673 : else
6674 30467 : selectDumpableTable(&tblinfo[i], fout);
6675 ECB :
6676 : /*
6677 : * Now, consider the table "interesting" if we need to dump its
6678 : * definition or its data. Later on, we'll skip a lot of data
6679 : * collection for uninteresting tables.
6680 : *
6681 : * Note: the "interesting" flag will also be set by flagInhTables for
6682 : * parents of interesting tables, so that we collect necessary
6683 : * inheritance info even when the parents are not themselves being
6684 : * dumped. This is the main reason why we need an "interesting" flag
6685 : * that's separate from the components-to-dump bitmask.
6686 : */
6687 GIC 30605 : tblinfo[i].interesting = (tblinfo[i].dobj.dump &
6688 ECB : (DUMP_COMPONENT_DEFINITION |
6689 GIC 30605 : DUMP_COMPONENT_DATA)) != 0;
6690 ECB :
6691 GIC 30605 : tblinfo[i].dummy_view = false; /* might get set during sort */
6692 30605 : tblinfo[i].postponed_def = false; /* might get set during sort */
6693 :
6694 : /* Tables have data */
6695 30605 : tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
6696 :
6697 : /* Mark whether table has an ACL */
6698 30605 : if (!PQgetisnull(res, i, i_relacl))
6699 24515 : tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6700 30605 : tblinfo[i].hascolumnACLs = false; /* may get set later */
6701 ECB :
6702 : /*
6703 : * Read-lock target tables to make sure they aren't DROPPED or altered
6704 : * in schema before we get around to dumping them.
6705 : *
6706 : * Note that we don't explicitly lock parents of the target tables; we
6707 : * assume our lock on the child is enough to prevent schema
6708 : * alterations to parent tables.
6709 : *
6710 : * NOTE: it'd be kinda nice to lock other relations too, not only
6711 : * plain or partitioned tables, but the backend doesn't presently
6712 : * allow that.
6713 : *
6714 : * We only need to lock the table for certain components; see
6715 : * pg_dump.h
6716 : */
6717 CBC 30605 : if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
6718 5328 : (tblinfo[i].relkind == RELKIND_RELATION ||
6719 1563 : tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
6720 ECB : {
6721 : /*
6722 : * Tables are locked in batches. When dumping from a remote
6723 : * server this can save a significant amount of time by reducing
6724 : * the number of round trips.
6725 : */
6726 GNC 4239 : if (query->len == 0)
6727 76 : appendPQExpBuffer(query, "LOCK TABLE %s",
6728 76 : fmtQualifiedDumpable(&tblinfo[i]));
6729 : else
6730 : {
6731 4163 : appendPQExpBuffer(query, ", %s",
6732 4163 : fmtQualifiedDumpable(&tblinfo[i]));
6733 :
6734 : /* Arbitrarily end a batch when query length reaches 100K. */
6735 4163 : if (query->len >= 100000)
6736 : {
6737 : /* Lock another batch of tables. */
6738 UNC 0 : appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
6739 0 : ExecuteSqlStatement(fout, query->data);
6740 0 : resetPQExpBuffer(query);
6741 : }
6742 : }
6743 ECB : }
6744 : }
6745 :
6746 GNC 119 : if (query->len != 0)
6747 : {
6748 : /* Lock the tables in the last batch. */
6749 76 : appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
6750 76 : ExecuteSqlStatement(fout, query->data);
6751 : }
6752 :
6753 CBC 118 : if (dopt->lockWaitTimeout)
6754 ECB : {
6755 CBC 2 : ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6756 ECB : }
6757 :
6758 CBC 118 : PQclear(res);
6759 ECB :
6760 CBC 118 : destroyPQExpBuffer(query);
6761 ECB :
6762 CBC 118 : return tblinfo;
6763 ECB : }
6764 :
6765 : /*
6766 : * getOwnedSeqs
6767 : * identify owned sequences and mark them as dumpable if owning table is
6768 : *
6769 : * We used to do this in getTables(), but it's better to do it after the
6770 : * index used by findTableByOid() has been set up.
6771 : */
6772 : void
6773 GIC 118 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6774 ECB : {
6775 : int i;
6776 :
6777 : /*
6778 : * Force sequences that are "owned" by table columns to be dumped whenever
6779 : * their owning table is being dumped.
6780 : */
6781 GIC 30474 : for (i = 0; i < numTables; i++)
6782 ECB : {
6783 GIC 30356 : TableInfo *seqinfo = &tblinfo[i];
6784 ECB : TableInfo *owning_tab;
6785 :
6786 CBC 30356 : if (!OidIsValid(seqinfo->owning_tab))
6787 30084 : continue; /* not an owned sequence */
6788 ECB :
6789 CBC 272 : owning_tab = findTableByOid(seqinfo->owning_tab);
6790 272 : if (owning_tab == NULL)
6791 LBC 0 : pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
6792 ECB : seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6793 :
6794 : /*
6795 : * Only dump identity sequences if we're going to dump the table that
6796 : * it belongs to.
6797 : */
6798 CBC 272 : if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
6799 21 : seqinfo->is_identity_sequence)
6800 ECB : {
6801 CBC 6 : seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
6802 6 : continue;
6803 ECB : }
6804 :
6805 : /*
6806 : * Otherwise we need to dump the components that are being dumped for
6807 : * the table and any components which the sequence is explicitly
6808 : * marked with.
6809 : *
6810 : * We can't simply use the set of components which are being dumped
6811 : * for the table as the table might be in an extension (and only the
6812 : * non-extension components, eg: ACLs if changed, security labels, and
6813 : * policies, are being dumped) while the sequence is not (and
6814 : * therefore the definition and other components should also be
6815 : * dumped).
6816 : *
6817 : * If the sequence is part of the extension then it should be properly
6818 : * marked by checkExtensionMembership() and this will be a no-op as
6819 : * the table will be equivalently marked.
6820 : */
6821 CBC 266 : seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6822 ECB :
6823 CBC 266 : if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6824 253 : seqinfo->interesting = true;
6825 ECB : }
6826 CBC 118 : }
6827 ECB :
6828 : /*
6829 : * getInherits
6830 : * read all the inheritance information
6831 : * from the system catalogs return them in the InhInfo* structure
6832 : *
6833 : * numInherits is set to the number of pairs read in
6834 : */
6835 : InhInfo *
6836 CBC 118 : getInherits(Archive *fout, int *numInherits)
6837 ECB : {
6838 : PGresult *res;
6839 : int ntups;
6840 : int i;
6841 CBC 118 : PQExpBuffer query = createPQExpBuffer();
6842 ECB : InhInfo *inhinfo;
6843 :
6844 : int i_inhrelid;
6845 : int i_inhparent;
6846 :
6847 : /* find all the inheritance information */
6848 GIC 118 : appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6849 ECB :
6850 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6851 :
6852 118 : ntups = PQntuples(res);
6853 :
6854 GIC 118 : *numInherits = ntups;
6855 :
6856 118 : inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6857 :
6858 118 : i_inhrelid = PQfnumber(res, "inhrelid");
6859 118 : i_inhparent = PQfnumber(res, "inhparent");
6860 :
6861 2272 : for (i = 0; i < ntups; i++)
6862 : {
6863 2154 : inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6864 2154 : inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6865 ECB : }
6866 :
6867 CBC 118 : PQclear(res);
6868 :
6869 118 : destroyPQExpBuffer(query);
6870 ECB :
6871 GIC 118 : return inhinfo;
6872 : }
6873 ECB :
6874 : /*
6875 : * getPartitioningInfo
6876 : * get information about partitioning
6877 : *
6878 : * For the most part, we only collect partitioning info about tables we
6879 : * intend to dump. However, this function has to consider all partitioned
6880 : * tables in the database, because we need to know about parents of partitions
6881 : * we are going to dump even if the parents themselves won't be dumped.
6882 : *
6883 : * Specifically, what we need to know is whether each partitioned table
6884 : * has an "unsafe" partitioning scheme that requires us to force
6885 : * load-via-partition-root mode for its children. Currently the only case
6886 : * for which we force that is hash partitioning on enum columns, since the
6887 : * hash codes depend on enum value OIDs which won't be replicated across
6888 : * dump-and-reload. There are other cases in which load-via-partition-root
6889 : * might be necessary, but we expect users to cope with them.
6890 : */
6891 : void
6892 GIC 118 : getPartitioningInfo(Archive *fout)
6893 : {
6894 : PQExpBuffer query;
6895 ECB : PGresult *res;
6896 : int ntups;
6897 :
6898 : /* hash partitioning didn't exist before v11 */
6899 GIC 118 : if (fout->remoteVersion < 110000)
6900 UIC 0 : return;
6901 : /* needn't bother if schema-only dump */
6902 GIC 118 : if (fout->dopt->schemaOnly)
6903 10 : return;
6904 ECB :
6905 CBC 108 : query = createPQExpBuffer();
6906 ECB :
6907 : /*
6908 : * Unsafe partitioning schemes are exactly those for which hash enum_ops
6909 : * appears among the partition opclasses. We needn't check partstrat.
6910 : *
6911 : * Note that this query may well retrieve info about tables we aren't
6912 : * going to dump and hence have no lock on. That's okay since we need not
6913 : * invoke any unsafe server-side functions.
6914 : */
6915 GIC 108 : appendPQExpBufferStr(query,
6916 EUB : "SELECT partrelid FROM pg_partitioned_table WHERE\n"
6917 : "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
6918 : "ON c.opcmethod = a.oid\n"
6919 : "WHERE opcname = 'enum_ops' "
6920 : "AND opcnamespace = 'pg_catalog'::regnamespace "
6921 : "AND amname = 'hash') = ANY(partclass)");
6922 :
6923 GIC 108 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6924 ECB :
6925 GIC 108 : ntups = PQntuples(res);
6926 :
6927 CBC 110 : for (int i = 0; i < ntups; i++)
6928 ECB : {
6929 GIC 2 : Oid tabrelid = atooid(PQgetvalue(res, i, 0));
6930 : TableInfo *tbinfo;
6931 ECB :
6932 GIC 2 : tbinfo = findTableByOid(tabrelid);
6933 CBC 2 : if (tbinfo == NULL)
6934 UIC 0 : pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
6935 : tabrelid);
6936 CBC 2 : tbinfo->unsafe_partitions = true;
6937 : }
6938 ECB :
6939 GIC 108 : PQclear(res);
6940 ECB :
6941 GIC 108 : destroyPQExpBuffer(query);
6942 : }
6943 :
6944 : /*
6945 : * getIndexes
6946 : * get information about every index on a dumpable table
6947 : *
6948 : * Note: index data is not returned directly to the caller, but it
6949 : * does get entered into the DumpableObject tables.
6950 : */
6951 ECB : void
6952 GIC 118 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6953 : {
6954 118 : PQExpBuffer query = createPQExpBuffer();
6955 118 : PQExpBuffer tbloids = createPQExpBuffer();
6956 : PGresult *res;
6957 : int ntups;
6958 : int curtblindx;
6959 ECB : IndxInfo *indxinfo;
6960 : int i_tableoid,
6961 : i_oid,
6962 : i_indrelid,
6963 : i_indexname,
6964 : i_parentidx,
6965 : i_indexdef,
6966 : i_indnkeyatts,
6967 : i_indnatts,
6968 : i_indkey,
6969 EUB : i_indisclustered,
6970 : i_indisreplident,
6971 : i_indnullsnotdistinct,
6972 : i_contype,
6973 : i_conname,
6974 : i_condeferrable,
6975 : i_condeferred,
6976 ECB : i_contableoid,
6977 : i_conoid,
6978 : i_condef,
6979 : i_tablespace,
6980 : i_indreloptions,
6981 : i_indstatcols,
6982 : i_indstatvals;
6983 :
6984 : /*
6985 : * We want to perform just one query against pg_index. However, we
6986 : * mustn't try to select every row of the catalog and then sort it out on
6987 : * the client side, because some of the server-side functions we need
6988 : * would be unsafe to apply to tables we don't have lock on. Hence, we
6989 : * build an array of the OIDs of tables we care about (and now have lock
6990 : * on!), and use a WHERE clause to constrain which rows are selected.
6991 : */
6992 GIC 118 : appendPQExpBufferChar(tbloids, '{');
6993 30474 : for (int i = 0; i < numTables; i++)
6994 : {
6995 30356 : TableInfo *tbinfo = &tblinfo[i];
6996 :
6997 30356 : if (!tbinfo->hasindex)
6998 21320 : continue;
6999 ECB :
7000 : /*
7001 : * We can ignore indexes of uninteresting tables.
7002 : */
7003 GIC 9036 : if (!tbinfo->interesting)
7004 CBC 7606 : continue;
7005 :
7006 : /* OK, we need info for this table */
7007 GIC 1430 : if (tbloids->len > 1) /* do we have more than the '{'? */
7008 1358 : appendPQExpBufferChar(tbloids, ',');
7009 1430 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
7010 : }
7011 118 : appendPQExpBufferChar(tbloids, '}');
7012 :
7013 GNC 118 : appendPQExpBufferStr(query,
7014 : "SELECT t.tableoid, t.oid, i.indrelid, "
7015 : "t.relname AS indexname, "
7016 : "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7017 : "i.indkey, i.indisclustered, "
7018 : "c.contype, c.conname, "
7019 : "c.condeferrable, c.condeferred, "
7020 : "c.tableoid AS contableoid, "
7021 : "c.oid AS conoid, "
7022 : "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
7023 : "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7024 : "t.reloptions AS indreloptions, ");
7025 :
7026 ECB :
7027 GIC 118 : if (fout->remoteVersion >= 90400)
7028 GNC 118 : appendPQExpBufferStr(query,
7029 : "i.indisreplident, ");
7030 ECB : else
7031 UNC 0 : appendPQExpBufferStr(query,
7032 : "false AS indisreplident, ");
7033 :
7034 CBC 118 : if (fout->remoteVersion >= 110000)
7035 GNC 118 : appendPQExpBufferStr(query,
7036 : "inh.inhparent AS parentidx, "
7037 : "i.indnkeyatts AS indnkeyatts, "
7038 : "i.indnatts AS indnatts, "
7039 : "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
7040 : " FROM pg_catalog.pg_attribute "
7041 : " WHERE attrelid = i.indexrelid AND "
7042 : " attstattarget >= 0) AS indstatcols, "
7043 : "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
7044 : " FROM pg_catalog.pg_attribute "
7045 : " WHERE attrelid = i.indexrelid AND "
7046 : " attstattarget >= 0) AS indstatvals, ");
7047 ECB : else
7048 UNC 0 : appendPQExpBufferStr(query,
7049 : "0 AS parentidx, "
7050 : "i.indnatts AS indnkeyatts, "
7051 : "i.indnatts AS indnatts, "
7052 : "'' AS indstatcols, "
7053 : "'' AS indstatvals, ");
7054 :
7055 GIC 118 : if (fout->remoteVersion >= 150000)
7056 GNC 118 : appendPQExpBufferStr(query,
7057 : "i.indnullsnotdistinct ");
7058 : else
7059 UNC 0 : appendPQExpBufferStr(query,
7060 : "false AS indnullsnotdistinct ");
7061 :
7062 : /*
7063 : * The point of the messy-looking outer join is to find a constraint that
7064 : * is related by an internal dependency link to the index. If we find one,
7065 : * create a CONSTRAINT entry linked to the INDEX entry. We assume an
7066 : * index won't have more than one internal dependency.
7067 : *
7068 : * Note: the check on conrelid is redundant, but useful because that
7069 : * column is indexed while conindid is not.
7070 ECB : */
7071 GIC 118 : if (fout->remoteVersion >= 110000)
7072 : {
7073 118 : appendPQExpBuffer(query,
7074 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7075 : "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7076 : "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7077 ECB : "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
7078 EUB : "LEFT JOIN pg_catalog.pg_constraint c "
7079 : "ON (i.indrelid = c.conrelid AND "
7080 ECB : "i.indexrelid = c.conindid AND "
7081 : "c.contype IN ('p','u','x')) "
7082 : "LEFT JOIN pg_catalog.pg_inherits inh "
7083 : "ON (inh.inhrelid = indexrelid) "
7084 : "WHERE (i.indisvalid OR t2.relkind = 'p') "
7085 : "AND i.indisready "
7086 : "ORDER BY i.indrelid, indexname",
7087 : tbloids->data);
7088 : }
7089 : else
7090 : {
7091 : /*
7092 : * the test on indisready is necessary in 9.2, and harmless in
7093 : * earlier/later versions
7094 : */
7095 UIC 0 : appendPQExpBuffer(query,
7096 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7097 : "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7098 : "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7099 : "LEFT JOIN pg_catalog.pg_constraint c "
7100 : "ON (i.indrelid = c.conrelid AND "
7101 ECB : "i.indexrelid = c.conindid AND "
7102 : "c.contype IN ('p','u','x')) "
7103 : "WHERE i.indisvalid AND i.indisready "
7104 : "ORDER BY i.indrelid, indexname",
7105 : tbloids->data);
7106 : }
7107 :
7108 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7109 :
7110 CBC 118 : ntups = PQntuples(res);
7111 ECB :
7112 GBC 118 : i_tableoid = PQfnumber(res, "tableoid");
7113 GIC 118 : i_oid = PQfnumber(res, "oid");
7114 CBC 118 : i_indrelid = PQfnumber(res, "indrelid");
7115 GIC 118 : i_indexname = PQfnumber(res, "indexname");
7116 118 : i_parentidx = PQfnumber(res, "parentidx");
7117 CBC 118 : i_indexdef = PQfnumber(res, "indexdef");
7118 GIC 118 : i_indnkeyatts = PQfnumber(res, "indnkeyatts");
7119 CBC 118 : i_indnatts = PQfnumber(res, "indnatts");
7120 GIC 118 : i_indkey = PQfnumber(res, "indkey");
7121 118 : i_indisclustered = PQfnumber(res, "indisclustered");
7122 118 : i_indisreplident = PQfnumber(res, "indisreplident");
7123 118 : i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
7124 118 : i_contype = PQfnumber(res, "contype");
7125 118 : i_conname = PQfnumber(res, "conname");
7126 118 : i_condeferrable = PQfnumber(res, "condeferrable");
7127 118 : i_condeferred = PQfnumber(res, "condeferred");
7128 118 : i_contableoid = PQfnumber(res, "contableoid");
7129 118 : i_conoid = PQfnumber(res, "conoid");
7130 CBC 118 : i_condef = PQfnumber(res, "condef");
7131 GIC 118 : i_tablespace = PQfnumber(res, "tablespace");
7132 CBC 118 : i_indreloptions = PQfnumber(res, "indreloptions");
7133 118 : i_indstatcols = PQfnumber(res, "indstatcols");
7134 GIC 118 : i_indstatvals = PQfnumber(res, "indstatvals");
7135 :
7136 118 : indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
7137 :
7138 : /*
7139 : * Outer loop iterates once per table, not once per row. Incrementing of
7140 : * j is handled by the inner loop.
7141 : */
7142 118 : curtblindx = -1;
7143 1544 : for (int j = 0; j < ntups;)
7144 : {
7145 1426 : Oid indrelid = atooid(PQgetvalue(res, j, i_indrelid));
7146 1426 : TableInfo *tbinfo = NULL;
7147 : int numinds;
7148 :
7149 : /* Count rows for this table */
7150 1848 : for (numinds = 1; numinds < ntups - j; numinds++)
7151 1776 : if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
7152 1354 : break;
7153 :
7154 : /*
7155 : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
7156 : * order.
7157 : */
7158 20553 : while (++curtblindx < numTables)
7159 : {
7160 20553 : tbinfo = &tblinfo[curtblindx];
7161 20553 : if (tbinfo->dobj.catId.oid == indrelid)
7162 1426 : break;
7163 : }
7164 1426 : if (curtblindx >= numTables)
7165 UIC 0 : pg_fatal("unrecognized table OID %u", indrelid);
7166 : /* cross-check that we only got requested tables */
7167 GIC 1426 : if (!tbinfo->hasindex ||
7168 1426 : !tbinfo->interesting)
7169 UIC 0 : pg_fatal("unexpected index data for table \"%s\"",
7170 ECB : tbinfo->dobj.name);
7171 :
7172 : /* Save data for this table */
7173 CBC 1426 : tbinfo->indexes = indxinfo + j;
7174 GIC 1426 : tbinfo->numIndexes = numinds;
7175 ECB :
7176 CBC 3274 : for (int c = 0; c < numinds; c++, j++)
7177 : {
7178 : char contype;
7179 :
7180 GIC 1848 : indxinfo[j].dobj.objType = DO_INDEX;
7181 CBC 1848 : indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7182 1848 : indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7183 GIC 1848 : AssignDumpId(&indxinfo[j].dobj);
7184 1848 : indxinfo[j].dobj.dump = tbinfo->dobj.dump;
7185 CBC 1848 : indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7186 1848 : indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7187 1848 : indxinfo[j].indextable = tbinfo;
7188 GIC 1848 : indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
7189 CBC 1848 : indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
7190 GIC 1848 : indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
7191 CBC 1848 : indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
7192 GIC 1848 : indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
7193 1848 : indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
7194 1848 : indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
7195 1848 : indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7196 1848 : parseOidArray(PQgetvalue(res, j, i_indkey),
7197 1848 : indxinfo[j].indkeys, indxinfo[j].indnattrs);
7198 1848 : indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
7199 1848 : indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
7200 1848 : indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
7201 1848 : indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
7202 1848 : indxinfo[j].partattaches = (SimplePtrList)
7203 : {
7204 : NULL, NULL
7205 ECB : };
7206 CBC 1848 : contype = *(PQgetvalue(res, j, i_contype));
7207 :
7208 GIC 1848 : if (contype == 'p' || contype == 'u' || contype == 'x')
7209 GBC 887 : {
7210 : /*
7211 : * If we found a constraint matching the index, create an
7212 ECB : * entry for it.
7213 : */
7214 : ConstraintInfo *constrinfo;
7215 :
7216 GIC 887 : constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
7217 887 : constrinfo->dobj.objType = DO_CONSTRAINT;
7218 887 : constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7219 887 : constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7220 887 : AssignDumpId(&constrinfo->dobj);
7221 887 : constrinfo->dobj.dump = tbinfo->dobj.dump;
7222 887 : constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7223 887 : constrinfo->dobj.namespace = tbinfo->dobj.namespace;
7224 887 : constrinfo->contable = tbinfo;
7225 887 : constrinfo->condomain = NULL;
7226 GBC 887 : constrinfo->contype = contype;
7227 GIC 887 : if (contype == 'x')
7228 10 : constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
7229 : else
7230 877 : constrinfo->condef = NULL;
7231 887 : constrinfo->confrelid = InvalidOid;
7232 887 : constrinfo->conindex = indxinfo[j].dobj.dumpId;
7233 CBC 887 : constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7234 887 : constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
7235 GIC 887 : constrinfo->conislocal = true;
7236 887 : constrinfo->separate = true;
7237 EUB :
7238 GIC 887 : indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
7239 : }
7240 : else
7241 : {
7242 : /* Plain secondary index */
7243 961 : indxinfo[j].indexconstraint = 0;
7244 : }
7245 : }
7246 : }
7247 :
7248 118 : PQclear(res);
7249 ECB :
7250 GIC 118 : destroyPQExpBuffer(query);
7251 CBC 118 : destroyPQExpBuffer(tbloids);
7252 GIC 118 : }
7253 :
7254 : /*
7255 : * getExtendedStatistics
7256 : * get information about extended-statistics objects.
7257 : *
7258 : * Note: extended statistics data is not returned directly to the caller, but
7259 : * it does get entered into the DumpableObject tables.
7260 : */
7261 : void
7262 118 : getExtendedStatistics(Archive *fout)
7263 : {
7264 : PQExpBuffer query;
7265 : PGresult *res;
7266 : StatsExtInfo *statsextinfo;
7267 : int ntups;
7268 : int i_tableoid;
7269 : int i_oid;
7270 : int i_stxname;
7271 : int i_stxnamespace;
7272 : int i_stxowner;
7273 EUB : int i_stattarget;
7274 : int i;
7275 :
7276 : /* Extended statistics were new in v10 */
7277 GIC 118 : if (fout->remoteVersion < 100000)
7278 UIC 0 : return;
7279 :
7280 GIC 118 : query = createPQExpBuffer();
7281 :
7282 118 : if (fout->remoteVersion < 130000)
7283 UNC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
7284 : "stxnamespace, stxowner, (-1) AS stxstattarget "
7285 : "FROM pg_catalog.pg_statistic_ext");
7286 ECB : else
7287 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
7288 : "stxnamespace, stxowner, stxstattarget "
7289 : "FROM pg_catalog.pg_statistic_ext");
7290 ECB :
7291 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7292 ECB :
7293 CBC 118 : ntups = PQntuples(res);
7294 ECB :
7295 CBC 118 : i_tableoid = PQfnumber(res, "tableoid");
7296 118 : i_oid = PQfnumber(res, "oid");
7297 118 : i_stxname = PQfnumber(res, "stxname");
7298 118 : i_stxnamespace = PQfnumber(res, "stxnamespace");
7299 118 : i_stxowner = PQfnumber(res, "stxowner");
7300 118 : i_stattarget = PQfnumber(res, "stxstattarget");
7301 ECB :
7302 CBC 118 : statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7303 ECB :
7304 CBC 273 : for (i = 0; i < ntups; i++)
7305 ECB : {
7306 CBC 155 : statsextinfo[i].dobj.objType = DO_STATSEXT;
7307 155 : statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7308 155 : statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7309 155 : AssignDumpId(&statsextinfo[i].dobj);
7310 155 : statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7311 310 : statsextinfo[i].dobj.namespace =
7312 155 : findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
7313 GIC 155 : statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
7314 CBC 155 : statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
7315 :
7316 : /* Decide whether we want to dump it */
7317 GIC 155 : selectDumpableObject(&(statsextinfo[i].dobj), fout);
7318 : }
7319 :
7320 CBC 118 : PQclear(res);
7321 118 : destroyPQExpBuffer(query);
7322 : }
7323 ECB :
7324 : /*
7325 : * getConstraints
7326 : *
7327 : * Get info about constraints on dumpable tables.
7328 : *
7329 : * Currently handles foreign keys only.
7330 : * Unique and primary key constraints are handled with indexes,
7331 : * while check constraints are processed in getTableAttrs().
7332 : */
7333 : void
7334 GIC 118 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7335 : {
7336 CBC 118 : PQExpBuffer query = createPQExpBuffer();
7337 GIC 118 : PQExpBuffer tbloids = createPQExpBuffer();
7338 ECB : PGresult *res;
7339 : int ntups;
7340 : int curtblindx;
7341 GIC 118 : TableInfo *tbinfo = NULL;
7342 ECB : ConstraintInfo *constrinfo;
7343 EUB : int i_contableoid,
7344 : i_conoid,
7345 ECB : i_conrelid,
7346 : i_conname,
7347 EUB : i_confrelid,
7348 : i_conindid,
7349 : i_condef;
7350 :
7351 ECB : /*
7352 : * We want to perform just one query against pg_constraint. However, we
7353 : * mustn't try to select every row of the catalog and then sort it out on
7354 : * the client side, because some of the server-side functions we need
7355 : * would be unsafe to apply to tables we don't have lock on. Hence, we
7356 : * build an array of the OIDs of tables we care about (and now have lock
7357 : * on!), and use a WHERE clause to constrain which rows are selected.
7358 : */
7359 CBC 118 : appendPQExpBufferChar(tbloids, '{');
7360 30474 : for (int i = 0; i < numTables; i++)
7361 ECB : {
7362 CBC 30356 : TableInfo *tinfo = &tblinfo[i];
7363 ECB :
7364 : /*
7365 : * For partitioned tables, foreign keys have no triggers so they must
7366 : * be included anyway in case some foreign keys are defined.
7367 : */
7368 CBC 30356 : if ((!tinfo->hastriggers &&
7369 29516 : tinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7370 1126 : !(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7371 29279 : continue;
7372 ECB :
7373 : /* OK, we need info for this table */
7374 CBC 1077 : if (tbloids->len > 1) /* do we have more than the '{'? */
7375 1025 : appendPQExpBufferChar(tbloids, ',');
7376 1077 : appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
7377 ECB : }
7378 CBC 118 : appendPQExpBufferChar(tbloids, '}');
7379 ECB :
7380 CBC 118 : appendPQExpBufferStr(query,
7381 : "SELECT c.tableoid, c.oid, "
7382 : "conrelid, conname, confrelid, ");
7383 GIC 118 : if (fout->remoteVersion >= 110000)
7384 CBC 118 : appendPQExpBufferStr(query, "conindid, ");
7385 : else
7386 LBC 0 : appendPQExpBufferStr(query, "0 AS conindid, ");
7387 CBC 118 : appendPQExpBuffer(query,
7388 : "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
7389 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7390 : "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
7391 : "WHERE contype = 'f' ",
7392 : tbloids->data);
7393 GIC 118 : if (fout->remoteVersion >= 110000)
7394 CBC 118 : appendPQExpBufferStr(query,
7395 ECB : "AND conparentid = 0 ");
7396 CBC 118 : appendPQExpBufferStr(query,
7397 ECB : "ORDER BY conrelid, conname");
7398 :
7399 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7400 ECB :
7401 CBC 118 : ntups = PQntuples(res);
7402 ECB :
7403 CBC 118 : i_contableoid = PQfnumber(res, "tableoid");
7404 118 : i_conoid = PQfnumber(res, "oid");
7405 118 : i_conrelid = PQfnumber(res, "conrelid");
7406 118 : i_conname = PQfnumber(res, "conname");
7407 GIC 118 : i_confrelid = PQfnumber(res, "confrelid");
7408 CBC 118 : i_conindid = PQfnumber(res, "conindid");
7409 118 : i_condef = PQfnumber(res, "condef");
7410 ECB :
7411 CBC 118 : constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7412 ECB :
7413 CBC 118 : curtblindx = -1;
7414 276 : for (int j = 0; j < ntups; j++)
7415 : {
7416 158 : Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
7417 : TableInfo *reftable;
7418 :
7419 : /*
7420 : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
7421 ECB : * order.
7422 : */
7423 GIC 158 : if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
7424 : {
7425 12809 : while (++curtblindx < numTables)
7426 ECB : {
7427 GIC 12809 : tbinfo = &tblinfo[curtblindx];
7428 CBC 12809 : if (tbinfo->dobj.catId.oid == conrelid)
7429 148 : break;
7430 ECB : }
7431 GIC 148 : if (curtblindx >= numTables)
7432 UIC 0 : pg_fatal("unrecognized table OID %u", conrelid);
7433 : }
7434 :
7435 GIC 158 : constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7436 158 : constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7437 158 : constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7438 158 : AssignDumpId(&constrinfo[j].dobj);
7439 158 : constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7440 CBC 158 : constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7441 GIC 158 : constrinfo[j].contable = tbinfo;
7442 158 : constrinfo[j].condomain = NULL;
7443 158 : constrinfo[j].contype = 'f';
7444 158 : constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7445 158 : constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7446 158 : constrinfo[j].conindex = 0;
7447 158 : constrinfo[j].condeferrable = false;
7448 158 : constrinfo[j].condeferred = false;
7449 158 : constrinfo[j].conislocal = true;
7450 158 : constrinfo[j].separate = true;
7451 :
7452 : /*
7453 : * Restoring an FK that points to a partitioned table requires that
7454 : * all partition indexes have been attached beforehand. Ensure that
7455 ECB : * happens by making the constraint depend on each index partition
7456 EUB : * attach object.
7457 : */
7458 CBC 158 : reftable = findTableByOid(constrinfo[j].confrelid);
7459 GIC 158 : if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
7460 ECB : {
7461 GBC 20 : Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));
7462 :
7463 GIC 20 : if (indexOid != InvalidOid)
7464 : {
7465 CBC 20 : for (int k = 0; k < reftable->numIndexes; k++)
7466 : {
7467 : IndxInfo *refidx;
7468 :
7469 ECB : /* not our index? */
7470 GIC 20 : if (reftable->indexes[k].dobj.catId.oid != indexOid)
7471 LBC 0 : continue;
7472 :
7473 CBC 20 : refidx = &reftable->indexes[k];
7474 20 : addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
7475 20 : break;
7476 ECB : }
7477 : }
7478 : }
7479 : }
7480 :
7481 GIC 118 : PQclear(res);
7482 ECB :
7483 GIC 118 : destroyPQExpBuffer(query);
7484 CBC 118 : destroyPQExpBuffer(tbloids);
7485 118 : }
7486 ECB :
7487 : /*
7488 : * addConstrChildIdxDeps
7489 : *
7490 : * Recursive subroutine for getConstraints
7491 : *
7492 : * Given an object representing a foreign key constraint and an index on the
7493 : * partitioned table it references, mark the constraint object as dependent
7494 : * on the DO_INDEX_ATTACH object of each index partition, recursively
7495 : * drilling down to their partitions if any. This ensures that the FK is not
7496 : * restored until the index is fully marked valid.
7497 : */
7498 : static void
7499 CBC 45 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
7500 : {
7501 : SimplePtrListCell *cell;
7502 :
7503 GIC 45 : Assert(dobj->objType == DO_FK_CONSTRAINT);
7504 :
7505 155 : for (cell = refidx->partattaches.head; cell; cell = cell->next)
7506 : {
7507 110 : IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
7508 :
7509 110 : addObjectDependency(dobj, attach->dobj.dumpId);
7510 :
7511 110 : if (attach->partitionIdx->partattaches.head != NULL)
7512 CBC 25 : addConstrChildIdxDeps(dobj, attach->partitionIdx);
7513 : }
7514 45 : }
7515 ECB :
7516 : /*
7517 : * getDomainConstraints
7518 : *
7519 : * Get info about constraints on a domain.
7520 : */
7521 : static void
7522 GIC 124 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7523 : {
7524 : int i;
7525 : ConstraintInfo *constrinfo;
7526 124 : PQExpBuffer query = createPQExpBuffer();
7527 : PGresult *res;
7528 : int i_tableoid,
7529 : i_oid,
7530 : i_conname,
7531 : i_consrc;
7532 : int ntups;
7533 :
7534 124 : if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
7535 : {
7536 : /* Set up query for constraint-specific details */
7537 CBC 44 : appendPQExpBufferStr(query,
7538 ECB : "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
7539 : "SELECT tableoid, oid, conname, "
7540 : "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7541 : "convalidated "
7542 : "FROM pg_catalog.pg_constraint "
7543 : "WHERE contypid = $1 "
7544 : "ORDER BY conname");
7545 :
7546 CBC 44 : ExecuteSqlStatement(fout, query->data);
7547 ECB :
7548 CBC 44 : fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
7549 ECB : }
7550 :
7551 GIC 124 : printfPQExpBuffer(query,
7552 ECB : "EXECUTE getDomainConstraints('%u')",
7553 : tyinfo->dobj.catId.oid);
7554 :
7555 GIC 124 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7556 ECB :
7557 GIC 124 : ntups = PQntuples(res);
7558 ECB :
7559 GIC 124 : i_tableoid = PQfnumber(res, "tableoid");
7560 124 : i_oid = PQfnumber(res, "oid");
7561 CBC 124 : i_conname = PQfnumber(res, "conname");
7562 124 : i_consrc = PQfnumber(res, "consrc");
7563 :
7564 GBC 124 : constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7565 ECB :
7566 GIC 124 : tyinfo->nDomChecks = ntups;
7567 124 : tyinfo->domChecks = constrinfo;
7568 :
7569 208 : for (i = 0; i < ntups; i++)
7570 : {
7571 CBC 84 : bool validated = PQgetvalue(res, i, 4)[0] == 't';
7572 ECB :
7573 GIC 84 : constrinfo[i].dobj.objType = DO_CONSTRAINT;
7574 CBC 84 : constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7575 GIC 84 : constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7576 84 : AssignDumpId(&constrinfo[i].dobj);
7577 CBC 84 : constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7578 GIC 84 : constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7579 CBC 84 : constrinfo[i].contable = NULL;
7580 GIC 84 : constrinfo[i].condomain = tyinfo;
7581 CBC 84 : constrinfo[i].contype = 'c';
7582 84 : constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7583 84 : constrinfo[i].confrelid = InvalidOid;
7584 84 : constrinfo[i].conindex = 0;
7585 84 : constrinfo[i].condeferrable = false;
7586 84 : constrinfo[i].condeferred = false;
7587 84 : constrinfo[i].conislocal = true;
7588 :
7589 84 : constrinfo[i].separate = !validated;
7590 :
7591 ECB : /*
7592 : * Make the domain depend on the constraint, ensuring it won't be
7593 : * output till any constraint dependencies are OK. If the constraint
7594 : * has not been validated, it's going to be dumped after the domain
7595 : * anyway, so this doesn't matter.
7596 : */
7597 GIC 84 : if (validated)
7598 84 : addObjectDependency(&tyinfo->dobj,
7599 84 : constrinfo[i].dobj.dumpId);
7600 : }
7601 ECB :
7602 GIC 124 : PQclear(res);
7603 ECB :
7604 GIC 124 : destroyPQExpBuffer(query);
7605 CBC 124 : }
7606 ECB :
7607 : /*
7608 : * getRules
7609 : * get basic information about every rule in the system
7610 EUB : *
7611 : * numRules is set to the number of rules read in
7612 : */
7613 ECB : RuleInfo *
7614 CBC 118 : getRules(Archive *fout, int *numRules)
7615 ECB : {
7616 : PGresult *res;
7617 : int ntups;
7618 : int i;
7619 CBC 118 : PQExpBuffer query = createPQExpBuffer();
7620 ECB : RuleInfo *ruleinfo;
7621 : int i_tableoid;
7622 : int i_oid;
7623 : int i_rulename;
7624 : int i_ruletable;
7625 : int i_ev_type;
7626 : int i_is_instead;
7627 : int i_ev_enabled;
7628 :
7629 GIC 118 : appendPQExpBufferStr(query, "SELECT "
7630 : "tableoid, oid, rulename, "
7631 : "ev_class AS ruletable, ev_type, is_instead, "
7632 : "ev_enabled "
7633 : "FROM pg_rewrite "
7634 : "ORDER BY oid");
7635 :
7636 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7637 ECB :
7638 GIC 118 : ntups = PQntuples(res);
7639 ECB :
7640 GIC 118 : *numRules = ntups;
7641 ECB :
7642 GIC 118 : ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7643 ECB :
7644 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
7645 118 : i_oid = PQfnumber(res, "oid");
7646 118 : i_rulename = PQfnumber(res, "rulename");
7647 118 : i_ruletable = PQfnumber(res, "ruletable");
7648 CBC 118 : i_ev_type = PQfnumber(res, "ev_type");
7649 GBC 118 : i_is_instead = PQfnumber(res, "is_instead");
7650 GIC 118 : i_ev_enabled = PQfnumber(res, "ev_enabled");
7651 ECB :
7652 CBC 17867 : for (i = 0; i < ntups; i++)
7653 ECB : {
7654 : Oid ruletableoid;
7655 :
7656 GIC 17749 : ruleinfo[i].dobj.objType = DO_RULE;
7657 17749 : ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7658 17749 : ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7659 CBC 17749 : AssignDumpId(&ruleinfo[i].dobj);
7660 GIC 17749 : ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7661 CBC 17749 : ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7662 17749 : ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7663 17749 : if (ruleinfo[i].ruletable == NULL)
7664 UIC 0 : pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
7665 : ruletableoid, ruleinfo[i].dobj.catId.oid);
7666 GIC 17749 : ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7667 17749 : ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7668 17749 : ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7669 17749 : ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7670 17749 : ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7671 17749 : if (ruleinfo[i].ruletable)
7672 : {
7673 : /*
7674 : * If the table is a view or materialized view, force its ON
7675 : * SELECT rule to be sorted before the view itself --- this
7676 : * ensures that any dependencies for the rule affect the table's
7677 ECB : * positioning. Other rules are forced to appear after their
7678 : * table.
7679 : */
7680 GIC 17749 : if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7681 CBC 565 : ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7682 GIC 17584 : ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7683 ECB : {
7684 GIC 17318 : addObjectDependency(&ruleinfo[i].ruletable->dobj,
7685 CBC 17318 : ruleinfo[i].dobj.dumpId);
7686 : /* We'll merge the rule into CREATE VIEW, if possible */
7687 17318 : ruleinfo[i].separate = false;
7688 : }
7689 ECB : else
7690 : {
7691 GIC 431 : addObjectDependency(&ruleinfo[i].dobj,
7692 CBC 431 : ruleinfo[i].ruletable->dobj.dumpId);
7693 GIC 431 : ruleinfo[i].separate = true;
7694 : }
7695 : }
7696 : else
7697 UIC 0 : ruleinfo[i].separate = true;
7698 : }
7699 :
7700 CBC 118 : PQclear(res);
7701 :
7702 GIC 118 : destroyPQExpBuffer(query);
7703 :
7704 CBC 118 : return ruleinfo;
7705 : }
7706 :
7707 : /*
7708 : * getTriggers
7709 : * get information about every trigger on a dumpable table
7710 : *
7711 : * Note: trigger data is not returned directly to the caller, but it
7712 ECB : * does get entered into the DumpableObject tables.
7713 : */
7714 : void
7715 CBC 118 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7716 : {
7717 GIC 118 : PQExpBuffer query = createPQExpBuffer();
7718 118 : PQExpBuffer tbloids = createPQExpBuffer();
7719 : PGresult *res;
7720 : int ntups;
7721 : int curtblindx;
7722 : TriggerInfo *tginfo;
7723 : int i_tableoid,
7724 ECB : i_oid,
7725 : i_tgrelid,
7726 : i_tgname,
7727 : i_tgfname,
7728 : i_tgtype,
7729 : i_tgnargs,
7730 : i_tgargs,
7731 : i_tgisconstraint,
7732 : i_tgconstrname,
7733 : i_tgconstrrelid,
7734 : i_tgconstrrelname,
7735 : i_tgenabled,
7736 : i_tgispartition,
7737 : i_tgdeferrable,
7738 : i_tginitdeferred,
7739 : i_tgdef;
7740 :
7741 : /*
7742 : * We want to perform just one query against pg_trigger. However, we
7743 : * mustn't try to select every row of the catalog and then sort it out on
7744 : * the client side, because some of the server-side functions we need
7745 : * would be unsafe to apply to tables we don't have lock on. Hence, we
7746 : * build an array of the OIDs of tables we care about (and now have lock
7747 : * on!), and use a WHERE clause to constrain which rows are selected.
7748 : */
7749 CBC 118 : appendPQExpBufferChar(tbloids, '{');
7750 GIC 30474 : for (int i = 0; i < numTables; i++)
7751 ECB : {
7752 CBC 30356 : TableInfo *tbinfo = &tblinfo[i];
7753 ECB :
7754 CBC 30356 : if (!tbinfo->hastriggers ||
7755 840 : !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7756 29565 : continue;
7757 ECB :
7758 : /* OK, we need info for this table */
7759 CBC 791 : if (tbloids->len > 1) /* do we have more than the '{'? */
7760 741 : appendPQExpBufferChar(tbloids, ',');
7761 791 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
7762 ECB : }
7763 CBC 118 : appendPQExpBufferChar(tbloids, '}');
7764 ECB :
7765 CBC 118 : if (fout->remoteVersion >= 150000)
7766 : {
7767 ECB : /*
7768 : * NB: think not to use pretty=true in pg_get_triggerdef. It could
7769 : * result in non-forward-compatible dumps of WHEN clauses due to
7770 : * under-parenthesization.
7771 : *
7772 : * NB: We need to see partition triggers in case the tgenabled flag
7773 : * has been changed from the parent.
7774 : */
7775 CBC 118 : appendPQExpBuffer(query,
7776 ECB : "SELECT t.tgrelid, t.tgname, "
7777 : "t.tgfoid::pg_catalog.regproc AS tgfname, "
7778 : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
7779 : "t.tgenabled, t.tableoid, t.oid, "
7780 : "t.tgparentid <> 0 AS tgispartition\n"
7781 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7782 : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
7783 : "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
7784 : "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
7785 : "OR t.tgenabled != u.tgenabled) "
7786 : "ORDER BY t.tgrelid, t.tgname",
7787 : tbloids->data);
7788 : }
7789 UIC 0 : else if (fout->remoteVersion >= 130000)
7790 : {
7791 : /*
7792 ECB : * NB: think not to use pretty=true in pg_get_triggerdef. It could
7793 : * result in non-forward-compatible dumps of WHEN clauses due to
7794 : * under-parenthesization.
7795 : *
7796 : * NB: We need to see tgisinternal triggers in partitions, in case the
7797 : * tgenabled flag has been changed from the parent.
7798 : */
7799 UIC 0 : appendPQExpBuffer(query,
7800 : "SELECT t.tgrelid, t.tgname, "
7801 : "t.tgfoid::pg_catalog.regproc AS tgfname, "
7802 : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
7803 : "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
7804 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7805 : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
7806 : "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
7807 ECB : "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
7808 : "ORDER BY t.tgrelid, t.tgname",
7809 : tbloids->data);
7810 : }
7811 UIC 0 : else if (fout->remoteVersion >= 110000)
7812 : {
7813 : /*
7814 ECB : * NB: We need to see tgisinternal triggers in partitions, in case the
7815 : * tgenabled flag has been changed from the parent. No tgparentid in
7816 : * version 11-12, so we have to match them via pg_depend.
7817 : *
7818 : * See above about pretty=true in pg_get_triggerdef.
7819 : */
7820 LBC 0 : appendPQExpBuffer(query,
7821 : "SELECT t.tgrelid, t.tgname, "
7822 ECB : "t.tgfoid::pg_catalog.regproc AS tgfname, "
7823 : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
7824 : "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
7825 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7826 : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
7827 : "LEFT JOIN pg_catalog.pg_depend AS d ON "
7828 : " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
7829 : " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
7830 : " d.objid = t.oid "
7831 : "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
7832 : "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
7833 : "ORDER BY t.tgrelid, t.tgname",
7834 : tbloids->data);
7835 : }
7836 : else
7837 : {
7838 : /* See above about pretty=true in pg_get_triggerdef */
7839 LBC 0 : appendPQExpBuffer(query,
7840 ECB : "SELECT t.tgrelid, t.tgname, "
7841 : "t.tgfoid::pg_catalog.regproc AS tgfname, "
7842 EUB : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
7843 : "t.tgenabled, false as tgispartition, "
7844 ECB : "t.tableoid, t.oid "
7845 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7846 : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
7847 : "WHERE NOT tgisinternal "
7848 : "ORDER BY t.tgrelid, t.tgname",
7849 : tbloids->data);
7850 : }
7851 :
7852 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7853 :
7854 118 : ntups = PQntuples(res);
7855 :
7856 118 : i_tableoid = PQfnumber(res, "tableoid");
7857 118 : i_oid = PQfnumber(res, "oid");
7858 CBC 118 : i_tgrelid = PQfnumber(res, "tgrelid");
7859 118 : i_tgname = PQfnumber(res, "tgname");
7860 118 : i_tgfname = PQfnumber(res, "tgfname");
7861 GIC 118 : i_tgtype = PQfnumber(res, "tgtype");
7862 CBC 118 : i_tgnargs = PQfnumber(res, "tgnargs");
7863 118 : i_tgargs = PQfnumber(res, "tgargs");
7864 GIC 118 : i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7865 CBC 118 : i_tgconstrname = PQfnumber(res, "tgconstrname");
7866 GIC 118 : i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7867 118 : i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7868 118 : i_tgenabled = PQfnumber(res, "tgenabled");
7869 CBC 118 : i_tgispartition = PQfnumber(res, "tgispartition");
7870 118 : i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7871 118 : i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7872 GIC 118 : i_tgdef = PQfnumber(res, "tgdef");
7873 :
7874 118 : tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7875 EUB :
7876 : /*
7877 : * Outer loop iterates once per table, not once per row. Incrementing of
7878 ECB : * j is handled by the inner loop.
7879 : */
7880 CBC 118 : curtblindx = -1;
7881 GIC 422 : for (int j = 0; j < ntups;)
7882 ECB : {
7883 GIC 304 : Oid tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
7884 304 : TableInfo *tbinfo = NULL;
7885 : int numtrigs;
7886 :
7887 : /* Count rows for this table */
7888 504 : for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
7889 454 : if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
7890 254 : break;
7891 :
7892 : /*
7893 ECB : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
7894 : * order.
7895 : */
7896 CBC 14801 : while (++curtblindx < numTables)
7897 : {
7898 GIC 14801 : tbinfo = &tblinfo[curtblindx];
7899 14801 : if (tbinfo->dobj.catId.oid == tgrelid)
7900 304 : break;
7901 : }
7902 304 : if (curtblindx >= numTables)
7903 UIC 0 : pg_fatal("unrecognized table OID %u", tgrelid);
7904 :
7905 : /* Save data for this table */
7906 GIC 304 : tbinfo->triggers = tginfo + j;
7907 304 : tbinfo->numTriggers = numtrigs;
7908 :
7909 808 : for (int c = 0; c < numtrigs; c++, j++)
7910 : {
7911 504 : tginfo[j].dobj.objType = DO_TRIGGER;
7912 504 : tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7913 504 : tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7914 504 : AssignDumpId(&tginfo[j].dobj);
7915 504 : tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7916 504 : tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7917 504 : tginfo[j].tgtable = tbinfo;
7918 504 : tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7919 504 : tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
7920 504 : if (i_tgdef >= 0)
7921 : {
7922 504 : tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7923 :
7924 : /* remaining fields are not valid if we have tgdef */
7925 504 : tginfo[j].tgfname = NULL;
7926 504 : tginfo[j].tgtype = 0;
7927 CBC 504 : tginfo[j].tgnargs = 0;
7928 504 : tginfo[j].tgargs = NULL;
7929 GIC 504 : tginfo[j].tgisconstraint = false;
7930 CBC 504 : tginfo[j].tgdeferrable = false;
7931 GIC 504 : tginfo[j].tginitdeferred = false;
7932 CBC 504 : tginfo[j].tgconstrname = NULL;
7933 504 : tginfo[j].tgconstrrelid = InvalidOid;
7934 504 : tginfo[j].tgconstrrelname = NULL;
7935 : }
7936 : else
7937 ECB : {
7938 LBC 0 : tginfo[j].tgdef = NULL;
7939 ECB :
7940 UIC 0 : tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7941 LBC 0 : tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7942 UIC 0 : tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7943 LBC 0 : tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7944 UIC 0 : tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7945 0 : tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7946 0 : tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7947 :
7948 0 : if (tginfo[j].tgisconstraint)
7949 : {
7950 0 : tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7951 0 : tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7952 0 : if (OidIsValid(tginfo[j].tgconstrrelid))
7953 ECB : {
7954 UIC 0 : if (PQgetisnull(res, j, i_tgconstrrelname))
7955 0 : pg_fatal("query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)",
7956 : tginfo[j].dobj.name,
7957 : tbinfo->dobj.name,
7958 : tginfo[j].tgconstrrelid);
7959 0 : tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7960 : }
7961 : else
7962 0 : tginfo[j].tgconstrrelname = NULL;
7963 : }
7964 : else
7965 : {
7966 0 : tginfo[j].tgconstrname = NULL;
7967 UBC 0 : tginfo[j].tgconstrrelid = InvalidOid;
7968 UIC 0 : tginfo[j].tgconstrrelname = NULL;
7969 : }
7970 : }
7971 : }
7972 : }
7973 :
7974 GIC 118 : PQclear(res);
7975 :
7976 118 : destroyPQExpBuffer(query);
7977 GBC 118 : destroyPQExpBuffer(tbloids);
7978 GIC 118 : }
7979 :
7980 : /*
7981 : * getEventTriggers
7982 : * get information about event triggers
7983 : */
7984 : EventTriggerInfo *
7985 118 : getEventTriggers(Archive *fout, int *numEventTriggers)
7986 : {
7987 : int i;
7988 : PQExpBuffer query;
7989 EUB : PGresult *res;
7990 : EventTriggerInfo *evtinfo;
7991 : int i_tableoid,
7992 : i_oid,
7993 : i_evtname,
7994 : i_evtevent,
7995 : i_evtowner,
7996 : i_evttags,
7997 : i_evtfname,
7998 : i_evtenabled;
7999 : int ntups;
8000 :
8001 : /* Before 9.3, there are no event triggers */
8002 GIC 118 : if (fout->remoteVersion < 90300)
8003 : {
8004 UIC 0 : *numEventTriggers = 0;
8005 0 : return NULL;
8006 : }
8007 :
8008 GIC 118 : query = createPQExpBuffer();
8009 :
8010 GNC 118 : appendPQExpBufferStr(query,
8011 : "SELECT e.tableoid, e.oid, evtname, evtenabled, "
8012 : "evtevent, evtowner, "
8013 : "array_to_string(array("
8014 : "select quote_literal(x) "
8015 : " from unnest(evttags) as t(x)), ', ') as evttags, "
8016 : "e.evtfoid::regproc as evtfname "
8017 : "FROM pg_event_trigger e "
8018 : "ORDER BY e.oid");
8019 :
8020 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8021 :
8022 118 : ntups = PQntuples(res);
8023 :
8024 118 : *numEventTriggers = ntups;
8025 :
8026 118 : evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
8027 :
8028 118 : i_tableoid = PQfnumber(res, "tableoid");
8029 118 : i_oid = PQfnumber(res, "oid");
8030 CBC 118 : i_evtname = PQfnumber(res, "evtname");
8031 GIC 118 : i_evtevent = PQfnumber(res, "evtevent");
8032 CBC 118 : i_evtowner = PQfnumber(res, "evtowner");
8033 GIC 118 : i_evttags = PQfnumber(res, "evttags");
8034 CBC 118 : i_evtfname = PQfnumber(res, "evtfname");
8035 118 : i_evtenabled = PQfnumber(res, "evtenabled");
8036 ECB :
8037 CBC 163 : for (i = 0; i < ntups; i++)
8038 ECB : {
8039 CBC 45 : evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
8040 45 : evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8041 45 : evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8042 45 : AssignDumpId(&evtinfo[i].dobj);
8043 45 : evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
8044 45 : evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
8045 45 : evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
8046 45 : evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
8047 45 : evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
8048 45 : evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
8049 45 : evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
8050 ECB :
8051 : /* Decide whether we want to dump it */
8052 CBC 45 : selectDumpableObject(&(evtinfo[i].dobj), fout);
8053 : }
8054 :
8055 GIC 118 : PQclear(res);
8056 :
8057 118 : destroyPQExpBuffer(query);
8058 ECB :
8059 CBC 118 : return evtinfo;
8060 : }
8061 ECB :
8062 : /*
8063 : * getProcLangs
8064 : * get basic information about every procedural language in the system
8065 : *
8066 : * numProcLangs is set to the number of langs read in
8067 : *
8068 : * NB: this must run after getFuncs() because we assume we can do
8069 : * findFuncByOid().
8070 : */
8071 : ProcLangInfo *
8072 GIC 118 : getProcLangs(Archive *fout, int *numProcLangs)
8073 : {
8074 ECB : PGresult *res;
8075 : int ntups;
8076 : int i;
8077 CBC 118 : PQExpBuffer query = createPQExpBuffer();
8078 ECB : ProcLangInfo *planginfo;
8079 : int i_tableoid;
8080 : int i_oid;
8081 EUB : int i_lanname;
8082 : int i_lanpltrusted;
8083 : int i_lanplcallfoid;
8084 ECB : int i_laninline;
8085 : int i_lanvalidator;
8086 : int i_lanacl;
8087 : int i_acldefault;
8088 : int i_lanowner;
8089 :
8090 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8091 : "lanname, lanpltrusted, lanplcallfoid, "
8092 : "laninline, lanvalidator, "
8093 : "lanacl, "
8094 : "acldefault('l', lanowner) AS acldefault, "
8095 : "lanowner "
8096 : "FROM pg_language "
8097 : "WHERE lanispl "
8098 : "ORDER BY oid");
8099 :
8100 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8101 :
8102 GIC 118 : ntups = PQntuples(res);
8103 ECB :
8104 CBC 118 : *numProcLangs = ntups;
8105 ECB :
8106 CBC 118 : planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
8107 ECB :
8108 CBC 118 : i_tableoid = PQfnumber(res, "tableoid");
8109 118 : i_oid = PQfnumber(res, "oid");
8110 118 : i_lanname = PQfnumber(res, "lanname");
8111 118 : i_lanpltrusted = PQfnumber(res, "lanpltrusted");
8112 118 : i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
8113 GIC 118 : i_laninline = PQfnumber(res, "laninline");
8114 118 : i_lanvalidator = PQfnumber(res, "lanvalidator");
8115 118 : i_lanacl = PQfnumber(res, "lanacl");
8116 GBC 118 : i_acldefault = PQfnumber(res, "acldefault");
8117 GIC 118 : i_lanowner = PQfnumber(res, "lanowner");
8118 EUB :
8119 GBC 281 : for (i = 0; i < ntups; i++)
8120 EUB : {
8121 GBC 163 : planginfo[i].dobj.objType = DO_PROCLANG;
8122 163 : planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8123 163 : planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8124 163 : AssignDumpId(&planginfo[i].dobj);
8125 :
8126 163 : planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
8127 GIC 163 : planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
8128 GBC 163 : planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
8129 163 : planginfo[i].dacl.privtype = 0;
8130 163 : planginfo[i].dacl.initprivs = NULL;
8131 GIC 163 : planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
8132 GBC 163 : planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
8133 163 : planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
8134 GIC 163 : planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
8135 163 : planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
8136 :
8137 EUB : /* Decide whether we want to dump it */
8138 GIC 163 : selectDumpableProcLang(&(planginfo[i]), fout);
8139 :
8140 EUB : /* Mark whether language has an ACL */
8141 GIC 163 : if (!PQgetisnull(res, i, i_lanacl))
8142 45 : planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
8143 : }
8144 EUB :
8145 GBC 118 : PQclear(res);
8146 EUB :
8147 GIC 118 : destroyPQExpBuffer(query);
8148 :
8149 118 : return planginfo;
8150 : }
8151 :
8152 ECB : /*
8153 : * getCasts
8154 : * get basic information about most casts in the system
8155 : *
8156 : * numCasts is set to the number of casts read in
8157 : *
8158 : * Skip casts from a range to its multirange, since we'll create those
8159 : * automatically.
8160 : */
8161 : CastInfo *
8162 GIC 118 : getCasts(Archive *fout, int *numCasts)
8163 ECB : {
8164 : PGresult *res;
8165 : int ntups;
8166 : int i;
8167 GIC 118 : PQExpBuffer query = createPQExpBuffer();
8168 : CastInfo *castinfo;
8169 : int i_tableoid;
8170 : int i_oid;
8171 : int i_castsource;
8172 : int i_casttarget;
8173 : int i_castfunc;
8174 : int i_castcontext;
8175 : int i_castmethod;
8176 :
8177 118 : if (fout->remoteVersion >= 140000)
8178 : {
8179 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8180 ECB : "castsource, casttarget, castfunc, castcontext, "
8181 : "castmethod "
8182 EUB : "FROM pg_cast c "
8183 : "WHERE NOT EXISTS ( "
8184 : "SELECT 1 FROM pg_range r "
8185 : "WHERE c.castsource = r.rngtypid "
8186 ECB : "AND c.casttarget = r.rngmultitypid "
8187 : ") "
8188 : "ORDER BY 3,4");
8189 : }
8190 : else
8191 : {
8192 UIC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8193 : "castsource, casttarget, castfunc, castcontext, "
8194 : "castmethod "
8195 : "FROM pg_cast ORDER BY 3,4");
8196 : }
8197 :
8198 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8199 :
8200 118 : ntups = PQntuples(res);
8201 :
8202 118 : *numCasts = ntups;
8203 :
8204 118 : castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
8205 :
8206 118 : i_tableoid = PQfnumber(res, "tableoid");
8207 118 : i_oid = PQfnumber(res, "oid");
8208 118 : i_castsource = PQfnumber(res, "castsource");
8209 118 : i_casttarget = PQfnumber(res, "casttarget");
8210 118 : i_castfunc = PQfnumber(res, "castfunc");
8211 118 : i_castcontext = PQfnumber(res, "castcontext");
8212 118 : i_castmethod = PQfnumber(res, "castmethod");
8213 ECB :
8214 GIC 26507 : for (i = 0; i < ntups; i++)
8215 ECB : {
8216 : PQExpBufferData namebuf;
8217 : TypeInfo *sTypeInfo;
8218 : TypeInfo *tTypeInfo;
8219 :
8220 CBC 26389 : castinfo[i].dobj.objType = DO_CAST;
8221 26389 : castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8222 26389 : castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8223 26389 : AssignDumpId(&castinfo[i].dobj);
8224 26389 : castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
8225 26389 : castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
8226 26389 : castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
8227 26389 : castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
8228 GIC 26389 : castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
8229 :
8230 ECB : /*
8231 : * Try to name cast as concatenation of typnames. This is only used
8232 : * for purposes of sorting. If we fail to find either type, the name
8233 : * will be an empty string.
8234 : */
8235 CBC 26389 : initPQExpBuffer(&namebuf);
8236 GIC 26389 : sTypeInfo = findTypeByOid(castinfo[i].castsource);
8237 CBC 26389 : tTypeInfo = findTypeByOid(castinfo[i].casttarget);
8238 GIC 26389 : if (sTypeInfo && tTypeInfo)
8239 26389 : appendPQExpBuffer(&namebuf, "%s %s",
8240 : sTypeInfo->dobj.name, tTypeInfo->dobj.name);
8241 26389 : castinfo[i].dobj.name = namebuf.data;
8242 :
8243 : /* Decide whether we want to dump it */
8244 26389 : selectDumpableCast(&(castinfo[i]), fout);
8245 : }
8246 :
8247 118 : PQclear(res);
8248 :
8249 118 : destroyPQExpBuffer(query);
8250 ECB :
8251 GIC 118 : return castinfo;
8252 : }
8253 :
8254 : static char *
8255 CBC 90 : get_language_name(Archive *fout, Oid langid)
8256 : {
8257 : PQExpBuffer query;
8258 : PGresult *res;
8259 : char *lanname;
8260 :
8261 GIC 90 : query = createPQExpBuffer();
8262 90 : appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
8263 90 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
8264 90 : lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
8265 90 : destroyPQExpBuffer(query);
8266 90 : PQclear(res);
8267 :
8268 CBC 90 : return lanname;
8269 : }
8270 :
8271 : /*
8272 : * getTransforms
8273 : * get basic information about every transform in the system
8274 : *
8275 : * numTransforms is set to the number of transforms read in
8276 : */
8277 : TransformInfo *
8278 118 : getTransforms(Archive *fout, int *numTransforms)
8279 : {
8280 ECB : PGresult *res;
8281 : int ntups;
8282 : int i;
8283 : PQExpBuffer query;
8284 : TransformInfo *transforminfo;
8285 : int i_tableoid;
8286 : int i_oid;
8287 : int i_trftype;
8288 : int i_trflang;
8289 : int i_trffromsql;
8290 : int i_trftosql;
8291 :
8292 : /* Transforms didn't exist pre-9.5 */
8293 CBC 118 : if (fout->remoteVersion < 90500)
8294 ECB : {
8295 LBC 0 : *numTransforms = 0;
8296 UIC 0 : return NULL;
8297 ECB : }
8298 :
8299 CBC 118 : query = createPQExpBuffer();
8300 ECB :
8301 CBC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8302 ECB : "trftype, trflang, trffromsql::oid, trftosql::oid "
8303 : "FROM pg_transform "
8304 : "ORDER BY 3,4");
8305 :
8306 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8307 ECB :
8308 CBC 118 : ntups = PQntuples(res);
8309 ECB :
8310 CBC 118 : *numTransforms = ntups;
8311 ECB :
8312 CBC 118 : transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8313 ECB :
8314 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
8315 118 : i_oid = PQfnumber(res, "oid");
8316 CBC 118 : i_trftype = PQfnumber(res, "trftype");
8317 GIC 118 : i_trflang = PQfnumber(res, "trflang");
8318 118 : i_trffromsql = PQfnumber(res, "trffromsql");
8319 CBC 118 : i_trftosql = PQfnumber(res, "trftosql");
8320 ECB :
8321 GIC 168 : for (i = 0; i < ntups; i++)
8322 : {
8323 ECB : PQExpBufferData namebuf;
8324 : TypeInfo *typeInfo;
8325 : char *lanname;
8326 :
8327 CBC 50 : transforminfo[i].dobj.objType = DO_TRANSFORM;
8328 GIC 50 : transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8329 50 : transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8330 50 : AssignDumpId(&transforminfo[i].dobj);
8331 50 : transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8332 50 : transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8333 50 : transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8334 50 : transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8335 :
8336 : /*
8337 : * Try to name transform as concatenation of type and language name.
8338 : * This is only used for purposes of sorting. If we fail to find
8339 : * either, the name will be an empty string.
8340 ECB : */
8341 GIC 50 : initPQExpBuffer(&namebuf);
8342 50 : typeInfo = findTypeByOid(transforminfo[i].trftype);
8343 50 : lanname = get_language_name(fout, transforminfo[i].trflang);
8344 50 : if (typeInfo && lanname)
8345 CBC 50 : appendPQExpBuffer(&namebuf, "%s %s",
8346 : typeInfo->dobj.name, lanname);
8347 GIC 50 : transforminfo[i].dobj.name = namebuf.data;
8348 50 : free(lanname);
8349 :
8350 : /* Decide whether we want to dump it */
8351 50 : selectDumpableObject(&(transforminfo[i].dobj), fout);
8352 : }
8353 :
8354 118 : PQclear(res);
8355 ECB :
8356 GIC 118 : destroyPQExpBuffer(query);
8357 ECB :
8358 GIC 118 : return transforminfo;
8359 : }
8360 :
8361 : /*
8362 : * getTableAttrs -
8363 : * for each interesting table, read info about its attributes
8364 : * (names, types, default values, CHECK constraints, etc)
8365 : *
8366 : * modifies tblinfo
8367 : */
8368 : void
8369 118 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8370 EUB : {
8371 GIC 118 : DumpOptions *dopt = fout->dopt;
8372 118 : PQExpBuffer q = createPQExpBuffer();
8373 118 : PQExpBuffer tbloids = createPQExpBuffer();
8374 118 : PQExpBuffer checkoids = createPQExpBuffer();
8375 GNC 118 : PQExpBuffer defaultoids = createPQExpBuffer();
8376 : PGresult *res;
8377 ECB : int ntups;
8378 : int curtblindx;
8379 : int i_attrelid;
8380 : int i_attnum;
8381 : int i_attname;
8382 : int i_atttypname;
8383 : int i_attstattarget;
8384 : int i_attstorage;
8385 : int i_typstorage;
8386 : int i_attidentity;
8387 : int i_attgenerated;
8388 : int i_attisdropped;
8389 : int i_attlen;
8390 : int i_attalign;
8391 : int i_attislocal;
8392 : int i_attnotnull;
8393 : int i_localnotnull;
8394 : int i_attoptions;
8395 : int i_attcollation;
8396 : int i_attcompression;
8397 : int i_attfdwoptions;
8398 : int i_attmissingval;
8399 : int i_atthasdef;
8400 :
8401 : /*
8402 : * We want to perform just one query against pg_attribute, and then just
8403 : * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
8404 : * (for CHECK constraints and for NOT NULL constraints). However, we
8405 : * mustn't try to select every row of those catalogs and then sort it out
8406 : * on the client side, because some of the server-side functions we need
8407 : * would be unsafe to apply to tables we don't have lock on. Hence, we
8408 : * build an array of the OIDs of tables we care about (and now have lock
8409 : * on!), and use a WHERE clause to constrain which rows are selected.
8410 : */
8411 GIC 118 : appendPQExpBufferChar(tbloids, '{');
8412 118 : appendPQExpBufferChar(checkoids, '{');
8413 GNC 118 : appendPQExpBufferChar(defaultoids, '{');
8414 GIC 30474 : for (int i = 0; i < numTables; i++)
8415 ECB : {
8416 CBC 30356 : TableInfo *tbinfo = &tblinfo[i];
8417 ECB :
8418 : /* Don't bother to collect info for sequences */
8419 CBC 30356 : if (tbinfo->relkind == RELKIND_SEQUENCE)
8420 GIC 445 : continue;
8421 ECB :
8422 : /* Don't bother with uninteresting tables, either */
8423 GIC 29911 : if (!tbinfo->interesting)
8424 CBC 25077 : continue;
8425 :
8426 : /* OK, we need info for this table */
8427 4834 : if (tbloids->len > 1) /* do we have more than the '{'? */
8428 GIC 4756 : appendPQExpBufferChar(tbloids, ',');
8429 CBC 4834 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8430 :
8431 4834 : if (tbinfo->ncheck > 0)
8432 : {
8433 : /* Also make a list of the ones with check constraints */
8434 GIC 465 : if (checkoids->len > 1) /* do we have more than the '{'? */
8435 CBC 397 : appendPQExpBufferChar(checkoids, ',');
8436 GIC 465 : appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
8437 : }
8438 : }
8439 118 : appendPQExpBufferChar(tbloids, '}');
8440 118 : appendPQExpBufferChar(checkoids, '}');
8441 ECB :
8442 : /*
8443 : * Find all the user attributes and their types.
8444 : *
8445 : * Since we only want to dump COLLATE clauses for attributes whose
8446 : * collation is different from their type's default, we use a CASE here to
8447 : * suppress uninteresting attcollations cheaply.
8448 : */
8449 GIC 118 : appendPQExpBufferStr(q,
8450 : "SELECT\n"
8451 : "a.attrelid,\n"
8452 : "a.attnum,\n"
8453 : "a.attname,\n"
8454 : "a.attstattarget,\n"
8455 : "a.attstorage,\n"
8456 : "t.typstorage,\n"
8457 : "a.atthasdef,\n"
8458 : "a.attisdropped,\n"
8459 : "a.attlen,\n"
8460 : "a.attalign,\n"
8461 : "a.attislocal,\n"
8462 : "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
8463 : "array_to_string(a.attoptions, ', ') AS attoptions,\n"
8464 : "CASE WHEN a.attcollation <> t.typcollation "
8465 : "THEN a.attcollation ELSE 0 END AS attcollation,\n"
8466 : "pg_catalog.array_to_string(ARRAY("
8467 : "SELECT pg_catalog.quote_ident(option_name) || "
8468 : "' ' || pg_catalog.quote_literal(option_value) "
8469 : "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8470 : "ORDER BY option_name"
8471 ECB : "), E',\n ') AS attfdwoptions,\n");
8472 :
8473 : /*
8474 : * Write out NOT NULL. In 16 and up we have to read pg_constraint, and we
8475 : * only print it for constraints that aren't connoinherit. A NULL result
8476 : * means there's no contype='n' row for the column, so we mustn't print
8477 : * anything then either. We also track conislocal so that we can handle
8478 : * the case of partitioned tables and binary upgrade especially.
8479 : */
8480 GNC 118 : if (fout->remoteVersion >= 160000)
8481 118 : appendPQExpBufferStr(q,
8482 : "co.connoinherit IS NOT NULL AS attnotnull,\n"
8483 : "coalesce(co.conislocal, false) AS local_notnull,\n");
8484 : else
8485 UNC 0 : appendPQExpBufferStr(q,
8486 : "a.attnotnull, false AS local_notnull,\n");
8487 :
8488 GBC 118 : if (fout->remoteVersion >= 140000)
8489 118 : appendPQExpBufferStr(q,
8490 : "a.attcompression AS attcompression,\n");
8491 : else
8492 LBC 0 : appendPQExpBufferStr(q,
8493 : "'' AS attcompression,\n");
8494 ECB :
8495 GIC 118 : if (fout->remoteVersion >= 100000)
8496 118 : appendPQExpBufferStr(q,
8497 : "a.attidentity,\n");
8498 : else
8499 LBC 0 : appendPQExpBufferStr(q,
8500 : "'' AS attidentity,\n");
8501 ECB :
8502 GIC 118 : if (fout->remoteVersion >= 110000)
8503 CBC 118 : appendPQExpBufferStr(q,
8504 : "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8505 ECB : "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8506 : else
8507 LBC 0 : appendPQExpBufferStr(q,
8508 ECB : "NULL AS attmissingval,\n");
8509 :
8510 CBC 118 : if (fout->remoteVersion >= 120000)
8511 118 : appendPQExpBufferStr(q,
8512 ECB : "a.attgenerated\n");
8513 : else
8514 LBC 0 : appendPQExpBufferStr(q,
8515 : "'' AS attgenerated\n");
8516 :
8517 : /* need left join to pg_type to not fail on dropped columns ... */
8518 GIC 118 : appendPQExpBuffer(q,
8519 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8520 ECB : "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
8521 : "LEFT JOIN pg_catalog.pg_type t "
8522 : "ON (a.atttypid = t.oid)\n",
8523 : tbloids->data);
8524 :
8525 : /* in 16, need pg_constraint for NOT NULLs */
8526 GNC 118 : if (fout->remoteVersion >= 160000)
8527 118 : appendPQExpBufferStr(q,
8528 : " LEFT JOIN pg_catalog.pg_constraint co ON "
8529 : "(a.attrelid = co.conrelid\n"
8530 : " AND co.contype = 'n' AND "
8531 : "co.conkey = array[a.attnum])\n");
8532 118 : appendPQExpBufferStr(q,
8533 : "WHERE a.attnum > 0::pg_catalog.int2\n"
8534 : "ORDER BY a.attrelid, a.attnum");
8535 :
8536 CBC 118 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8537 :
8538 GIC 118 : ntups = PQntuples(res);
8539 :
8540 118 : i_attrelid = PQfnumber(res, "attrelid");
8541 118 : i_attnum = PQfnumber(res, "attnum");
8542 118 : i_attname = PQfnumber(res, "attname");
8543 CBC 118 : i_atttypname = PQfnumber(res, "atttypname");
8544 118 : i_attstattarget = PQfnumber(res, "attstattarget");
8545 118 : i_attstorage = PQfnumber(res, "attstorage");
8546 118 : i_typstorage = PQfnumber(res, "typstorage");
8547 GIC 118 : i_attidentity = PQfnumber(res, "attidentity");
8548 CBC 118 : i_attgenerated = PQfnumber(res, "attgenerated");
8549 118 : i_attisdropped = PQfnumber(res, "attisdropped");
8550 GIC 118 : i_attlen = PQfnumber(res, "attlen");
8551 118 : i_attalign = PQfnumber(res, "attalign");
8552 CBC 118 : i_attislocal = PQfnumber(res, "attislocal");
8553 GIC 118 : i_attnotnull = PQfnumber(res, "attnotnull");
8554 GNC 118 : i_localnotnull = PQfnumber(res, "local_notnull");
8555 GIC 118 : i_attoptions = PQfnumber(res, "attoptions");
8556 CBC 118 : i_attcollation = PQfnumber(res, "attcollation");
8557 GIC 118 : i_attcompression = PQfnumber(res, "attcompression");
8558 CBC 118 : i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8559 GIC 118 : i_attmissingval = PQfnumber(res, "attmissingval");
8560 CBC 118 : i_atthasdef = PQfnumber(res, "atthasdef");
8561 :
8562 : /* Within the next loop, we'll accumulate OIDs of tables with defaults */
8563 GNC 118 : resetPQExpBuffer(defaultoids);
8564 118 : appendPQExpBufferChar(defaultoids, '{');
8565 :
8566 : /*
8567 : * Outer loop iterates once per table, not once per row. Incrementing of
8568 : * r is handled by the inner loop.
8569 : */
8570 GIC 118 : curtblindx = -1;
8571 CBC 4816 : for (int r = 0; r < ntups;)
8572 : {
8573 4698 : Oid attrelid = atooid(PQgetvalue(res, r, i_attrelid));
8574 4698 : TableInfo *tbinfo = NULL;
8575 ECB : int numatts;
8576 : bool hasdefaults;
8577 :
8578 : /* Count rows for this table */
8579 GIC 17438 : for (numatts = 1; numatts < ntups - r; numatts++)
8580 17363 : if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
8581 4623 : break;
8582 :
8583 : /*
8584 : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8585 : * order.
8586 : */
8587 21275 : while (++curtblindx < numTables)
8588 : {
8589 21275 : tbinfo = &tblinfo[curtblindx];
8590 21275 : if (tbinfo->dobj.catId.oid == attrelid)
8591 4698 : break;
8592 : }
8593 4698 : if (curtblindx >= numTables)
8594 UIC 0 : pg_fatal("unrecognized table OID %u", attrelid);
8595 : /* cross-check that we only got requested tables */
8596 GIC 4698 : if (tbinfo->relkind == RELKIND_SEQUENCE ||
8597 4698 : !tbinfo->interesting)
8598 UIC 0 : pg_fatal("unexpected column data for table \"%s\"",
8599 : tbinfo->dobj.name);
8600 :
8601 : /* Save data for this table */
8602 GIC 4698 : tbinfo->numatts = numatts;
8603 4698 : tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
8604 4698 : tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
8605 4698 : tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
8606 4698 : tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
8607 4698 : tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
8608 4698 : tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
8609 4698 : tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
8610 4698 : tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
8611 4698 : tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
8612 CBC 4698 : tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
8613 4698 : tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
8614 4698 : tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
8615 4698 : tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
8616 GIC 4698 : tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
8617 CBC 4698 : tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
8618 GIC 4698 : tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
8619 4698 : tbinfo->notnull = (bool *) pg_malloc(numatts * sizeof(bool));
8620 GNC 4698 : tbinfo->localNotNull = (bool *) pg_malloc(numatts * sizeof(bool));
8621 CBC 4698 : tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
8622 GIC 4698 : hasdefaults = false;
8623 :
8624 CBC 22136 : for (int j = 0; j < numatts; j++, r++)
8625 ECB : {
8626 GIC 17438 : if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
8627 UIC 0 : pg_fatal("invalid column numbering in table \"%s\"",
8628 ECB : tbinfo->dobj.name);
8629 CBC 17438 : tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
8630 17438 : tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
8631 17438 : tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
8632 GIC 17438 : tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
8633 17438 : tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
8634 CBC 17438 : tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
8635 17438 : tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
8636 17438 : tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8637 GIC 17438 : tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
8638 17438 : tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
8639 CBC 17438 : tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
8640 17438 : tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
8641 GIC 17438 : tbinfo->notnull[j] = (PQgetvalue(res, r, i_attnotnull)[0] == 't');
8642 GNC 17438 : tbinfo->localNotNull[j] = (PQgetvalue(res, r, i_localnotnull)[0] == 't');
8643 GIC 17438 : tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
8644 17438 : tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
8645 17438 : tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
8646 17438 : tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
8647 17438 : tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
8648 17438 : tbinfo->attrdefs[j] = NULL; /* fix below */
8649 17438 : if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
8650 CBC 882 : hasdefaults = true;
8651 : }
8652 :
8653 GIC 4698 : if (hasdefaults)
8654 : {
8655 : /* Collect OIDs of interesting tables that have defaults */
8656 GNC 728 : if (defaultoids->len > 1) /* do we have more than the '{'? */
8657 677 : appendPQExpBufferChar(defaultoids, ',');
8658 728 : appendPQExpBuffer(defaultoids, "%u", tbinfo->dobj.catId.oid);
8659 : }
8660 : }
8661 :
8662 GIC 118 : PQclear(res);
8663 :
8664 : /*
8665 : * Now get info about column defaults. This is skipped for a data-only
8666 : * dump, as it is only needed for table schemas.
8667 : */
8668 GNC 118 : if (!dopt->dataOnly && defaultoids->len > 1)
8669 : {
8670 : AttrDefInfo *attrdefs;
8671 : int numDefaults;
8672 GIC 47 : TableInfo *tbinfo = NULL;
8673 :
8674 47 : pg_log_info("finding table default expressions");
8675 :
8676 GNC 47 : appendPQExpBufferChar(defaultoids, '}');
8677 :
8678 GIC 47 : printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
8679 ECB : "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
8680 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8681 : "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
8682 : "ORDER BY a.adrelid, a.adnum",
8683 : defaultoids->data);
8684 EUB :
8685 GIC 47 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8686 :
8687 CBC 47 : numDefaults = PQntuples(res);
8688 47 : attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8689 :
8690 GIC 47 : curtblindx = -1;
8691 GBC 889 : for (int j = 0; j < numDefaults; j++)
8692 : {
8693 GIC 842 : Oid adtableoid = atooid(PQgetvalue(res, j, 0));
8694 CBC 842 : Oid adoid = atooid(PQgetvalue(res, j, 1));
8695 842 : Oid adrelid = atooid(PQgetvalue(res, j, 2));
8696 GIC 842 : int adnum = atoi(PQgetvalue(res, j, 3));
8697 842 : char *adsrc = PQgetvalue(res, j, 4);
8698 EUB :
8699 : /*
8700 : * Locate the associated TableInfo; we rely on tblinfo[] being in
8701 ECB : * OID order.
8702 : */
8703 GIC 842 : if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
8704 : {
8705 14977 : while (++curtblindx < numTables)
8706 EUB : {
8707 GIC 14977 : tbinfo = &tblinfo[curtblindx];
8708 14977 : if (tbinfo->dobj.catId.oid == adrelid)
8709 CBC 694 : break;
8710 ECB : }
8711 GIC 694 : if (curtblindx >= numTables)
8712 UIC 0 : pg_fatal("unrecognized table OID %u", adrelid);
8713 EUB : }
8714 :
8715 GIC 842 : if (adnum <= 0 || adnum > tbinfo->numatts)
8716 UIC 0 : pg_fatal("invalid adnum value %d for table \"%s\"",
8717 ECB : adnum, tbinfo->dobj.name);
8718 :
8719 : /*
8720 : * dropped columns shouldn't have defaults, but just in case,
8721 : * ignore 'em
8722 : */
8723 GIC 842 : if (tbinfo->attisdropped[adnum - 1])
8724 UIC 0 : continue;
8725 ECB :
8726 CBC 842 : attrdefs[j].dobj.objType = DO_ATTRDEF;
8727 GIC 842 : attrdefs[j].dobj.catId.tableoid = adtableoid;
8728 842 : attrdefs[j].dobj.catId.oid = adoid;
8729 842 : AssignDumpId(&attrdefs[j].dobj);
8730 842 : attrdefs[j].adtable = tbinfo;
8731 CBC 842 : attrdefs[j].adnum = adnum;
8732 GIC 842 : attrdefs[j].adef_expr = pg_strdup(adsrc);
8733 :
8734 842 : attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8735 CBC 842 : attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8736 :
8737 842 : attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8738 :
8739 ECB : /*
8740 : * Figure out whether the default/generation expression should be
8741 : * dumped as part of the main CREATE TABLE (or similar) command or
8742 : * as a separate ALTER TABLE (or similar) command. The preference
8743 : * is to put it into the CREATE command, but in some cases that's
8744 : * not possible.
8745 : */
8746 CBC 842 : if (tbinfo->attgenerated[adnum - 1])
8747 ECB : {
8748 : /*
8749 : * Column generation expressions cannot be dumped separately,
8750 : * because there is no syntax for it. By setting separate to
8751 : * false here we prevent the "default" from being processed as
8752 : * its own dumpable object. Later, flagInhAttrs() will mark
8753 : * it as not to be dumped at all, if possible (that is, if it
8754 : * can be inherited from a parent).
8755 : */
8756 CBC 360 : attrdefs[j].separate = false;
8757 ECB : }
8758 GIC 482 : else if (tbinfo->relkind == RELKIND_VIEW)
8759 : {
8760 : /*
8761 : * Defaults on a VIEW must always be dumped as separate ALTER
8762 : * TABLE commands.
8763 ECB : */
8764 CBC 36 : attrdefs[j].separate = true;
8765 : }
8766 446 : else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8767 ECB : {
8768 : /* column will be suppressed, print default separately */
8769 GIC 4 : attrdefs[j].separate = true;
8770 : }
8771 : else
8772 ECB : {
8773 CBC 442 : attrdefs[j].separate = false;
8774 ECB : }
8775 :
8776 GIC 842 : if (!attrdefs[j].separate)
8777 : {
8778 : /*
8779 : * Mark the default as needing to appear before the table, so
8780 ECB : * that any dependencies it has must be emitted before the
8781 : * CREATE TABLE. If this is not possible, we'll change to
8782 : * "separate" mode while sorting dependencies.
8783 : */
8784 CBC 802 : addObjectDependency(&tbinfo->dobj,
8785 GIC 802 : attrdefs[j].dobj.dumpId);
8786 ECB : }
8787 EUB :
8788 GIC 842 : tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8789 ECB : }
8790 :
8791 GBC 47 : PQclear(res);
8792 : }
8793 :
8794 : /*
8795 ECB : * Get info about table CHECK constraints. This is skipped for a
8796 : * data-only dump, as it is only needed for table schemas.
8797 : */
8798 CBC 118 : if (!dopt->dataOnly && checkoids->len > 2)
8799 ECB : {
8800 : ConstraintInfo *constrs;
8801 : int numConstrs;
8802 : int i_tableoid;
8803 : int i_oid;
8804 : int i_conrelid;
8805 : int i_conname;
8806 : int i_consrc;
8807 : int i_conislocal;
8808 : int i_convalidated;
8809 :
8810 CBC 63 : pg_log_info("finding table check constraints");
8811 ECB :
8812 CBC 63 : resetPQExpBuffer(q);
8813 63 : appendPQExpBuffer(q,
8814 ECB : "SELECT c.tableoid, c.oid, conrelid, conname, "
8815 : "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
8816 : "conislocal, convalidated "
8817 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8818 : "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
8819 : "WHERE contype = 'c' "
8820 EUB : "ORDER BY c.conrelid, c.conname",
8821 : checkoids->data);
8822 ECB :
8823 CBC 63 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8824 ECB :
8825 CBC 63 : numConstrs = PQntuples(res);
8826 63 : constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8827 ECB :
8828 CBC 63 : i_tableoid = PQfnumber(res, "tableoid");
8829 63 : i_oid = PQfnumber(res, "oid");
8830 63 : i_conrelid = PQfnumber(res, "conrelid");
8831 63 : i_conname = PQfnumber(res, "conname");
8832 63 : i_consrc = PQfnumber(res, "consrc");
8833 63 : i_conislocal = PQfnumber(res, "conislocal");
8834 63 : i_convalidated = PQfnumber(res, "convalidated");
8835 ECB :
8836 : /* As above, this loop iterates once per table, not once per row */
8837 CBC 63 : curtblindx = -1;
8838 502 : for (int j = 0; j < numConstrs;)
8839 ECB : {
8840 CBC 439 : Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
8841 439 : TableInfo *tbinfo = NULL;
8842 ECB : int numcons;
8843 :
8844 : /* Count rows for this table */
8845 GIC 577 : for (numcons = 1; numcons < numConstrs - j; numcons++)
8846 CBC 514 : if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
8847 GIC 376 : break;
8848 :
8849 ECB : /*
8850 : * Locate the associated TableInfo; we rely on tblinfo[] being in
8851 : * OID order.
8852 : */
8853 GIC 17496 : while (++curtblindx < numTables)
8854 : {
8855 CBC 17496 : tbinfo = &tblinfo[curtblindx];
8856 GIC 17496 : if (tbinfo->dobj.catId.oid == conrelid)
8857 439 : break;
8858 : }
8859 439 : if (curtblindx >= numTables)
8860 UIC 0 : pg_fatal("unrecognized table OID %u", conrelid);
8861 ECB :
8862 GIC 439 : if (numcons != tbinfo->ncheck)
8863 : {
8864 UIC 0 : pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
8865 ECB : "expected %d check constraints on table \"%s\" but found %d",
8866 : tbinfo->ncheck),
8867 : tbinfo->ncheck, tbinfo->dobj.name, numcons);
8868 UIC 0 : pg_log_error_hint("The system catalogs might be corrupted.");
8869 LBC 0 : exit_nicely(1);
8870 : }
8871 ECB :
8872 GIC 439 : tbinfo->checkexprs = constrs + j;
8873 :
8874 1016 : for (int c = 0; c < numcons; c++, j++)
8875 : {
8876 577 : bool validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
8877 :
8878 CBC 577 : constrs[j].dobj.objType = DO_CONSTRAINT;
8879 GIC 577 : constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8880 CBC 577 : constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8881 577 : AssignDumpId(&constrs[j].dobj);
8882 GIC 577 : constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
8883 CBC 577 : constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8884 577 : constrs[j].contable = tbinfo;
8885 GIC 577 : constrs[j].condomain = NULL;
8886 CBC 577 : constrs[j].contype = 'c';
8887 577 : constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
8888 577 : constrs[j].confrelid = InvalidOid;
8889 577 : constrs[j].conindex = 0;
8890 577 : constrs[j].condeferrable = false;
8891 GIC 577 : constrs[j].condeferred = false;
8892 577 : constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
8893 :
8894 : /*
8895 : * An unvalidated constraint needs to be dumped separately, so
8896 ECB : * that potentially-violating existing data is loaded before
8897 : * the constraint.
8898 : */
8899 GIC 577 : constrs[j].separate = !validated;
8900 ECB :
8901 CBC 577 : constrs[j].dobj.dump = tbinfo->dobj.dump;
8902 ECB :
8903 : /*
8904 : * Mark the constraint as needing to appear before the table
8905 EUB : * --- this is so that any other dependencies of the
8906 : * constraint will be emitted before we try to create the
8907 : * table. If the constraint is to be dumped separately, it
8908 ECB : * will be dumped after data is loaded anyway, so don't do it.
8909 EUB : * (There's an automatic dependency in the opposite direction
8910 : * anyway, so don't need to add one manually here.)
8911 : */
8912 GIC 577 : if (!constrs[j].separate)
8913 542 : addObjectDependency(&tbinfo->dobj,
8914 542 : constrs[j].dobj.dumpId);
8915 :
8916 ECB : /*
8917 EUB : * We will detect later whether the constraint must be split
8918 : * out from the table definition.
8919 ECB : */
8920 : }
8921 : }
8922 :
8923 CBC 63 : PQclear(res);
8924 ECB : }
8925 :
8926 : /*
8927 : * Get info about table NOT NULL constraints. This is skipped for a
8928 : * data-only dump, as it is only needed for table schemas.
8929 : *
8930 : * Optimizing for tables that have no NOT NULL constraint seems
8931 : * pointless, so we don't try.
8932 : */
8933 GNC 118 : if (!dopt->dataOnly)
8934 : {
8935 : ConstraintInfo *constrs;
8936 : int numConstrs;
8937 : int i_tableoid;
8938 : int i_oid;
8939 : int i_conrelid;
8940 : int i_conname;
8941 : int i_condef;
8942 : int i_conislocal;
8943 :
8944 112 : pg_log_info("finding table not null constraints");
8945 :
8946 : /*
8947 : * Only constraints marked connoinherit need to be handled here;
8948 : * the normal constraints are instead handled by writing NOT NULL
8949 : * when each column is defined.
8950 : */
8951 112 : resetPQExpBuffer(q);
8952 112 : appendPQExpBuffer(q,
8953 : "SELECT co.tableoid, co.oid, conrelid, conname, "
8954 : "pg_catalog.pg_get_constraintdef(co.oid) AS condef,\n"
8955 : " conislocal, coninhcount, connoinherit "
8956 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8957 : "JOIN pg_catalog.pg_constraint co ON (src.tbloid = co.conrelid)\n"
8958 : "JOIN pg_catalog.pg_class c ON (conrelid = c.oid)\n"
8959 : "WHERE contype = 'n' AND connoinherit\n"
8960 : "ORDER BY co.conrelid, co.conname",
8961 : tbloids->data);
8962 :
8963 112 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8964 :
8965 112 : numConstrs = PQntuples(res);
8966 112 : constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8967 :
8968 112 : i_tableoid = PQfnumber(res, "tableoid");
8969 112 : i_oid = PQfnumber(res, "oid");
8970 112 : i_conrelid = PQfnumber(res, "conrelid");
8971 112 : i_conname = PQfnumber(res, "conname");
8972 112 : i_condef = PQfnumber(res, "condef");
8973 112 : i_conislocal = PQfnumber(res, "conislocal");
8974 :
8975 : /* As above, this loop iterates once per table, not once per row */
8976 112 : curtblindx = -1;
8977 112 : for (int j = 0; j < numConstrs;)
8978 : {
8979 UNC 0 : Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
8980 0 : TableInfo *tbinfo = NULL;
8981 : int numcons;
8982 :
8983 : /* Count rows for this table */
8984 0 : for (numcons = 1; numcons < numConstrs - j; numcons++)
8985 0 : if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
8986 0 : break;
8987 :
8988 : /*
8989 : * Locate the associated TableInfo; we rely on tblinfo[] being in
8990 : * OID order.
8991 : */
8992 0 : while (++curtblindx < numTables)
8993 : {
8994 0 : tbinfo = &tblinfo[curtblindx];
8995 0 : if (tbinfo->dobj.catId.oid == conrelid)
8996 0 : break;
8997 : }
8998 0 : if (curtblindx >= numTables)
8999 0 : pg_fatal("unrecognized table OID %u", conrelid);
9000 :
9001 0 : for (int c = 0; c < numcons; c++, j++)
9002 : {
9003 0 : constrs[j].dobj.objType = DO_CONSTRAINT;
9004 0 : constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9005 0 : constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
9006 0 : AssignDumpId(&constrs[j].dobj);
9007 0 : constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
9008 0 : constrs[j].dobj.namespace = tbinfo->dobj.namespace;
9009 0 : constrs[j].contable = tbinfo;
9010 0 : constrs[j].condomain = NULL;
9011 0 : constrs[j].contype = 'n';
9012 0 : constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
9013 0 : constrs[j].confrelid = InvalidOid;
9014 0 : constrs[j].conindex = 0;
9015 0 : constrs[j].condeferrable = false;
9016 0 : constrs[j].condeferred = false;
9017 0 : constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9018 :
9019 0 : constrs[j].separate = true;
9020 :
9021 0 : constrs[j].dobj.dump = tbinfo->dobj.dump;
9022 : }
9023 : }
9024 :
9025 GNC 112 : PQclear(res);
9026 : }
9027 :
9028 GIC 118 : destroyPQExpBuffer(q);
9029 CBC 118 : destroyPQExpBuffer(tbloids);
9030 118 : destroyPQExpBuffer(checkoids);
9031 GNC 118 : destroyPQExpBuffer(defaultoids);
9032 GIC 118 : }
9033 ECB :
9034 : /*
9035 : * Test whether a column should be printed as part of table's CREATE TABLE.
9036 : * Column number is zero-based.
9037 : *
9038 : * Normally this is always true, but it's false for dropped columns, as well
9039 : * as those that were inherited without any local definition. (If we print
9040 : * such a column it will mistakenly get pg_attribute.attislocal set to true.)
9041 : * For partitions, it's always true, because we want the partitions to be
9042 : * created independently and ATTACH PARTITION used afterwards.
9043 : *
9044 : * In binary_upgrade mode, we must print all columns and fix the attislocal/
9045 : * attisdropped state later, so as to keep control of the physical column
9046 : * order.
9047 : *
9048 : * This function exists because there are scattered nonobvious places that
9049 : * must be kept in sync with this decision.
9050 : */
9051 : bool
9052 CBC 32712 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
9053 : {
9054 32712 : if (dopt->binary_upgrade)
9055 GIC 5634 : return true;
9056 27078 : if (tbinfo->attisdropped[colno])
9057 347 : return false;
9058 26731 : return (tbinfo->attislocal[colno] || tbinfo->ispartition);
9059 : }
9060 ECB :
9061 :
9062 : /*
9063 : * getTSParsers:
9064 : * read all text search parsers in the system catalogs and return them
9065 : * in the TSParserInfo* structure
9066 : *
9067 : * numTSParsers is set to the number of parsers read in
9068 : */
9069 : TSParserInfo *
9070 GIC 118 : getTSParsers(Archive *fout, int *numTSParsers)
9071 : {
9072 ECB : PGresult *res;
9073 : int ntups;
9074 : int i;
9075 : PQExpBuffer query;
9076 : TSParserInfo *prsinfo;
9077 : int i_tableoid;
9078 : int i_oid;
9079 : int i_prsname;
9080 : int i_prsnamespace;
9081 : int i_prsstart;
9082 : int i_prstoken;
9083 : int i_prsend;
9084 : int i_prsheadline;
9085 : int i_prslextype;
9086 :
9087 CBC 118 : query = createPQExpBuffer();
9088 :
9089 : /*
9090 : * find all text search objects, including builtin ones; we filter out
9091 : * system-defined objects at dump-out time.
9092 : */
9093 :
9094 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
9095 : "prsstart::oid, prstoken::oid, "
9096 : "prsend::oid, prsheadline::oid, prslextype::oid "
9097 : "FROM pg_ts_parser");
9098 :
9099 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9100 :
9101 118 : ntups = PQntuples(res);
9102 118 : *numTSParsers = ntups;
9103 :
9104 118 : prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
9105 :
9106 CBC 118 : i_tableoid = PQfnumber(res, "tableoid");
9107 GIC 118 : i_oid = PQfnumber(res, "oid");
9108 CBC 118 : i_prsname = PQfnumber(res, "prsname");
9109 118 : i_prsnamespace = PQfnumber(res, "prsnamespace");
9110 GIC 118 : i_prsstart = PQfnumber(res, "prsstart");
9111 118 : i_prstoken = PQfnumber(res, "prstoken");
9112 118 : i_prsend = PQfnumber(res, "prsend");
9113 118 : i_prsheadline = PQfnumber(res, "prsheadline");
9114 118 : i_prslextype = PQfnumber(res, "prslextype");
9115 :
9116 281 : for (i = 0; i < ntups; i++)
9117 : {
9118 163 : prsinfo[i].dobj.objType = DO_TSPARSER;
9119 CBC 163 : prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9120 GIC 163 : prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9121 CBC 163 : AssignDumpId(&prsinfo[i].dobj);
9122 163 : prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
9123 GIC 326 : prsinfo[i].dobj.namespace =
9124 CBC 163 : findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
9125 163 : prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
9126 163 : prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
9127 163 : prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
9128 163 : prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
9129 163 : prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
9130 ECB :
9131 : /* Decide whether we want to dump it */
9132 GIC 163 : selectDumpableObject(&(prsinfo[i].dobj), fout);
9133 ECB : }
9134 :
9135 GIC 118 : PQclear(res);
9136 ECB :
9137 CBC 118 : destroyPQExpBuffer(query);
9138 :
9139 GIC 118 : return prsinfo;
9140 : }
9141 ECB :
9142 : /*
9143 : * getTSDictionaries:
9144 : * read all text search dictionaries in the system catalogs and return them
9145 : * in the TSDictInfo* structure
9146 : *
9147 : * numTSDicts is set to the number of dictionaries read in
9148 : */
9149 : TSDictInfo *
9150 GIC 118 : getTSDictionaries(Archive *fout, int *numTSDicts)
9151 ECB : {
9152 : PGresult *res;
9153 : int ntups;
9154 : int i;
9155 : PQExpBuffer query;
9156 EUB : TSDictInfo *dictinfo;
9157 : int i_tableoid;
9158 ECB : int i_oid;
9159 : int i_dictname;
9160 EUB : int i_dictnamespace;
9161 : int i_dictowner;
9162 : int i_dicttemplate;
9163 : int i_dictinitoption;
9164 :
9165 GBC 118 : query = createPQExpBuffer();
9166 :
9167 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
9168 : "dictnamespace, dictowner, "
9169 : "dicttemplate, dictinitoption "
9170 : "FROM pg_ts_dict");
9171 :
9172 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9173 :
9174 118 : ntups = PQntuples(res);
9175 118 : *numTSDicts = ntups;
9176 ECB :
9177 CBC 118 : dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
9178 ECB :
9179 CBC 118 : i_tableoid = PQfnumber(res, "tableoid");
9180 118 : i_oid = PQfnumber(res, "oid");
9181 118 : i_dictname = PQfnumber(res, "dictname");
9182 118 : i_dictnamespace = PQfnumber(res, "dictnamespace");
9183 118 : i_dictowner = PQfnumber(res, "dictowner");
9184 118 : i_dictinitoption = PQfnumber(res, "dictinitoption");
9185 118 : i_dicttemplate = PQfnumber(res, "dicttemplate");
9186 ECB :
9187 CBC 3630 : for (i = 0; i < ntups; i++)
9188 ECB : {
9189 GIC 3512 : dictinfo[i].dobj.objType = DO_TSDICT;
9190 3512 : dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9191 3512 : dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9192 3512 : AssignDumpId(&dictinfo[i].dobj);
9193 3512 : dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
9194 7024 : dictinfo[i].dobj.namespace =
9195 CBC 3512 : findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
9196 GIC 3512 : dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
9197 CBC 3512 : dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
9198 GIC 3512 : if (PQgetisnull(res, i, i_dictinitoption))
9199 163 : dictinfo[i].dictinitoption = NULL;
9200 : else
9201 3349 : dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
9202 :
9203 : /* Decide whether we want to dump it */
9204 3512 : selectDumpableObject(&(dictinfo[i].dobj), fout);
9205 : }
9206 :
9207 118 : PQclear(res);
9208 ECB :
9209 CBC 118 : destroyPQExpBuffer(query);
9210 ECB :
9211 GIC 118 : return dictinfo;
9212 : }
9213 :
9214 : /*
9215 : * getTSTemplates:
9216 : * read all text search templates in the system catalogs and return them
9217 : * in the TSTemplateInfo* structure
9218 : *
9219 ECB : * numTSTemplates is set to the number of templates read in
9220 : */
9221 : TSTemplateInfo *
9222 GIC 118 : getTSTemplates(Archive *fout, int *numTSTemplates)
9223 : {
9224 : PGresult *res;
9225 : int ntups;
9226 : int i;
9227 : PQExpBuffer query;
9228 : TSTemplateInfo *tmplinfo;
9229 ECB : int i_tableoid;
9230 : int i_oid;
9231 : int i_tmplname;
9232 : int i_tmplnamespace;
9233 : int i_tmplinit;
9234 : int i_tmpllexize;
9235 :
9236 GIC 118 : query = createPQExpBuffer();
9237 :
9238 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
9239 : "tmplnamespace, tmplinit::oid, tmpllexize::oid "
9240 ECB : "FROM pg_ts_template");
9241 :
9242 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9243 :
9244 118 : ntups = PQntuples(res);
9245 118 : *numTSTemplates = ntups;
9246 :
9247 CBC 118 : tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
9248 ECB :
9249 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
9250 118 : i_oid = PQfnumber(res, "oid");
9251 118 : i_tmplname = PQfnumber(res, "tmplname");
9252 118 : i_tmplnamespace = PQfnumber(res, "tmplnamespace");
9253 118 : i_tmplinit = PQfnumber(res, "tmplinit");
9254 118 : i_tmpllexize = PQfnumber(res, "tmpllexize");
9255 :
9256 753 : for (i = 0; i < ntups; i++)
9257 : {
9258 635 : tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
9259 CBC 635 : tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9260 GIC 635 : tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9261 CBC 635 : AssignDumpId(&tmplinfo[i].dobj);
9262 635 : tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
9263 GIC 1270 : tmplinfo[i].dobj.namespace =
9264 CBC 635 : findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
9265 635 : tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
9266 635 : tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
9267 ECB :
9268 : /* Decide whether we want to dump it */
9269 CBC 635 : selectDumpableObject(&(tmplinfo[i].dobj), fout);
9270 : }
9271 :
9272 118 : PQclear(res);
9273 ECB :
9274 GIC 118 : destroyPQExpBuffer(query);
9275 EUB :
9276 GBC 118 : return tmplinfo;
9277 : }
9278 :
9279 : /*
9280 EUB : * getTSConfigurations:
9281 : * read all text search configurations in the system catalogs and return
9282 : * them in the TSConfigInfo* structure
9283 : *
9284 : * numTSConfigs is set to the number of configurations read in
9285 : */
9286 : TSConfigInfo *
9287 GIC 118 : getTSConfigurations(Archive *fout, int *numTSConfigs)
9288 EUB : {
9289 : PGresult *res;
9290 : int ntups;
9291 : int i;
9292 : PQExpBuffer query;
9293 : TSConfigInfo *cfginfo;
9294 : int i_tableoid;
9295 : int i_oid;
9296 : int i_cfgname;
9297 : int i_cfgnamespace;
9298 : int i_cfgowner;
9299 : int i_cfgparser;
9300 :
9301 GBC 118 : query = createPQExpBuffer();
9302 EUB :
9303 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
9304 : "cfgnamespace, cfgowner, cfgparser "
9305 : "FROM pg_ts_config");
9306 EUB :
9307 GBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9308 EUB :
9309 GBC 118 : ntups = PQntuples(res);
9310 118 : *numTSConfigs = ntups;
9311 EUB :
9312 GBC 118 : cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
9313 EUB :
9314 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
9315 GBC 118 : i_oid = PQfnumber(res, "oid");
9316 GIC 118 : i_cfgname = PQfnumber(res, "cfgname");
9317 GBC 118 : i_cfgnamespace = PQfnumber(res, "cfgnamespace");
9318 GIC 118 : i_cfgowner = PQfnumber(res, "cfgowner");
9319 118 : i_cfgparser = PQfnumber(res, "cfgparser");
9320 :
9321 CBC 3605 : for (i = 0; i < ntups; i++)
9322 : {
9323 GIC 3487 : cfginfo[i].dobj.objType = DO_TSCONFIG;
9324 CBC 3487 : cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9325 3487 : cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9326 3487 : AssignDumpId(&cfginfo[i].dobj);
9327 3487 : cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
9328 6974 : cfginfo[i].dobj.namespace =
9329 GIC 3487 : findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
9330 3487 : cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
9331 3487 : cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
9332 :
9333 : /* Decide whether we want to dump it */
9334 3487 : selectDumpableObject(&(cfginfo[i].dobj), fout);
9335 : }
9336 :
9337 118 : PQclear(res);
9338 :
9339 118 : destroyPQExpBuffer(query);
9340 :
9341 118 : return cfginfo;
9342 : }
9343 :
9344 : /*
9345 : * getForeignDataWrappers:
9346 : * read all foreign-data wrappers in the system catalogs and return
9347 : * them in the FdwInfo* structure
9348 ECB : *
9349 : * numForeignDataWrappers is set to the number of fdws read in
9350 : */
9351 : FdwInfo *
9352 CBC 118 : getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
9353 ECB : {
9354 : PGresult *res;
9355 : int ntups;
9356 : int i;
9357 : PQExpBuffer query;
9358 : FdwInfo *fdwinfo;
9359 : int i_tableoid;
9360 : int i_oid;
9361 : int i_fdwname;
9362 : int i_fdwowner;
9363 : int i_fdwhandler;
9364 : int i_fdwvalidator;
9365 : int i_fdwacl;
9366 : int i_acldefault;
9367 : int i_fdwoptions;
9368 :
9369 GIC 118 : query = createPQExpBuffer();
9370 :
9371 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
9372 : "fdwowner, "
9373 : "fdwhandler::pg_catalog.regproc, "
9374 : "fdwvalidator::pg_catalog.regproc, "
9375 : "fdwacl, "
9376 : "acldefault('F', fdwowner) AS acldefault, "
9377 : "array_to_string(ARRAY("
9378 : "SELECT quote_ident(option_name) || ' ' || "
9379 : "quote_literal(option_value) "
9380 : "FROM pg_options_to_table(fdwoptions) "
9381 : "ORDER BY option_name"
9382 : "), E',\n ') AS fdwoptions "
9383 : "FROM pg_foreign_data_wrapper");
9384 :
9385 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9386 :
9387 118 : ntups = PQntuples(res);
9388 118 : *numForeignDataWrappers = ntups;
9389 :
9390 CBC 118 : fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
9391 :
9392 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
9393 118 : i_oid = PQfnumber(res, "oid");
9394 118 : i_fdwname = PQfnumber(res, "fdwname");
9395 CBC 118 : i_fdwowner = PQfnumber(res, "fdwowner");
9396 GIC 118 : i_fdwhandler = PQfnumber(res, "fdwhandler");
9397 CBC 118 : i_fdwvalidator = PQfnumber(res, "fdwvalidator");
9398 118 : i_fdwacl = PQfnumber(res, "fdwacl");
9399 GIC 118 : i_acldefault = PQfnumber(res, "acldefault");
9400 CBC 118 : i_fdwoptions = PQfnumber(res, "fdwoptions");
9401 :
9402 170 : for (i = 0; i < ntups; i++)
9403 ECB : {
9404 CBC 52 : fdwinfo[i].dobj.objType = DO_FDW;
9405 52 : fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9406 52 : fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9407 52 : AssignDumpId(&fdwinfo[i].dobj);
9408 52 : fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
9409 52 : fdwinfo[i].dobj.namespace = NULL;
9410 52 : fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
9411 GIC 52 : fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9412 CBC 52 : fdwinfo[i].dacl.privtype = 0;
9413 GIC 52 : fdwinfo[i].dacl.initprivs = NULL;
9414 CBC 52 : fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
9415 52 : fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
9416 52 : fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
9417 52 : fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
9418 ECB :
9419 : /* Decide whether we want to dump it */
9420 CBC 52 : selectDumpableObject(&(fdwinfo[i].dobj), fout);
9421 ECB :
9422 : /* Mark whether FDW has an ACL */
9423 CBC 52 : if (!PQgetisnull(res, i, i_fdwacl))
9424 45 : fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9425 ECB : }
9426 :
9427 GIC 118 : PQclear(res);
9428 ECB :
9429 GIC 118 : destroyPQExpBuffer(query);
9430 :
9431 CBC 118 : return fdwinfo;
9432 : }
9433 ECB :
9434 : /*
9435 : * getForeignServers:
9436 : * read all foreign servers in the system catalogs and return
9437 : * them in the ForeignServerInfo * structure
9438 : *
9439 : * numForeignServers is set to the number of servers read in
9440 : */
9441 : ForeignServerInfo *
9442 GIC 118 : getForeignServers(Archive *fout, int *numForeignServers)
9443 : {
9444 : PGresult *res;
9445 : int ntups;
9446 ECB : int i;
9447 : PQExpBuffer query;
9448 : ForeignServerInfo *srvinfo;
9449 : int i_tableoid;
9450 : int i_oid;
9451 : int i_srvname;
9452 : int i_srvowner;
9453 : int i_srvfdw;
9454 : int i_srvtype;
9455 : int i_srvversion;
9456 : int i_srvacl;
9457 : int i_acldefault;
9458 : int i_srvoptions;
9459 :
9460 GIC 118 : query = createPQExpBuffer();
9461 ECB :
9462 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
9463 : "srvowner, "
9464 : "srvfdw, srvtype, srvversion, srvacl, "
9465 : "acldefault('S', srvowner) AS acldefault, "
9466 : "array_to_string(ARRAY("
9467 : "SELECT quote_ident(option_name) || ' ' || "
9468 : "quote_literal(option_value) "
9469 : "FROM pg_options_to_table(srvoptions) "
9470 : "ORDER BY option_name"
9471 : "), E',\n ') AS srvoptions "
9472 : "FROM pg_foreign_server");
9473 ECB :
9474 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9475 ECB :
9476 CBC 118 : ntups = PQntuples(res);
9477 118 : *numForeignServers = ntups;
9478 ECB :
9479 CBC 118 : srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9480 ECB :
9481 CBC 118 : i_tableoid = PQfnumber(res, "tableoid");
9482 GIC 118 : i_oid = PQfnumber(res, "oid");
9483 CBC 118 : i_srvname = PQfnumber(res, "srvname");
9484 GIC 118 : i_srvowner = PQfnumber(res, "srvowner");
9485 CBC 118 : i_srvfdw = PQfnumber(res, "srvfdw");
9486 118 : i_srvtype = PQfnumber(res, "srvtype");
9487 118 : i_srvversion = PQfnumber(res, "srvversion");
9488 118 : i_srvacl = PQfnumber(res, "srvacl");
9489 118 : i_acldefault = PQfnumber(res, "acldefault");
9490 118 : i_srvoptions = PQfnumber(res, "srvoptions");
9491 ECB :
9492 CBC 174 : for (i = 0; i < ntups; i++)
9493 ECB : {
9494 CBC 56 : srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9495 56 : srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9496 GIC 56 : srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9497 CBC 56 : AssignDumpId(&srvinfo[i].dobj);
9498 GIC 56 : srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9499 56 : srvinfo[i].dobj.namespace = NULL;
9500 CBC 56 : srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9501 GIC 56 : srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9502 56 : srvinfo[i].dacl.privtype = 0;
9503 CBC 56 : srvinfo[i].dacl.initprivs = NULL;
9504 GIC 56 : srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
9505 CBC 56 : srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9506 GIC 56 : srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9507 CBC 56 : srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9508 GIC 56 : srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9509 :
9510 : /* Decide whether we want to dump it */
9511 56 : selectDumpableObject(&(srvinfo[i].dobj), fout);
9512 :
9513 : /* Servers have user mappings */
9514 56 : srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
9515 :
9516 : /* Mark whether server has an ACL */
9517 56 : if (!PQgetisnull(res, i, i_srvacl))
9518 CBC 45 : srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9519 : }
9520 :
9521 GIC 118 : PQclear(res);
9522 :
9523 118 : destroyPQExpBuffer(query);
9524 :
9525 118 : return srvinfo;
9526 : }
9527 :
9528 : /*
9529 : * getDefaultACLs:
9530 : * read all default ACL information in the system catalogs and return
9531 : * them in the DefaultACLInfo structure
9532 ECB : *
9533 : * numDefaultACLs is set to the number of ACLs read in
9534 : */
9535 : DefaultACLInfo *
9536 GIC 118 : getDefaultACLs(Archive *fout, int *numDefaultACLs)
9537 : {
9538 CBC 118 : DumpOptions *dopt = fout->dopt;
9539 : DefaultACLInfo *daclinfo;
9540 ECB : PQExpBuffer query;
9541 : PGresult *res;
9542 : int i_oid;
9543 : int i_tableoid;
9544 : int i_defaclrole;
9545 : int i_defaclnamespace;
9546 : int i_defaclobjtype;
9547 : int i_defaclacl;
9548 : int i_acldefault;
9549 : int i,
9550 : ntups;
9551 :
9552 CBC 118 : query = createPQExpBuffer();
9553 :
9554 ECB : /*
9555 : * Global entries (with defaclnamespace=0) replace the hard-wired default
9556 : * ACL for their object type. We should dump them as deltas from the
9557 : * default ACL, since that will be used as a starting point for
9558 : * interpreting the ALTER DEFAULT PRIVILEGES commands. On the other hand,
9559 : * non-global entries can only add privileges not revoke them. We must
9560 : * dump those as-is (i.e., as deltas from an empty ACL).
9561 : *
9562 : * We can use defaclobjtype as the object type for acldefault(), except
9563 : * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
9564 : * 's'.
9565 : */
9566 GNC 118 : appendPQExpBufferStr(query,
9567 : "SELECT oid, tableoid, "
9568 : "defaclrole, "
9569 : "defaclnamespace, "
9570 : "defaclobjtype, "
9571 : "defaclacl, "
9572 : "CASE WHEN defaclnamespace = 0 THEN "
9573 : "acldefault(CASE WHEN defaclobjtype = 'S' "
9574 : "THEN 's'::\"char\" ELSE defaclobjtype END, "
9575 : "defaclrole) ELSE '{}' END AS acldefault "
9576 : "FROM pg_default_acl");
9577 :
9578 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9579 :
9580 118 : ntups = PQntuples(res);
9581 118 : *numDefaultACLs = ntups;
9582 :
9583 CBC 118 : daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9584 :
9585 GIC 118 : i_oid = PQfnumber(res, "oid");
9586 118 : i_tableoid = PQfnumber(res, "tableoid");
9587 118 : i_defaclrole = PQfnumber(res, "defaclrole");
9588 118 : i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9589 118 : i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9590 118 : i_defaclacl = PQfnumber(res, "defaclacl");
9591 118 : i_acldefault = PQfnumber(res, "acldefault");
9592 :
9593 298 : for (i = 0; i < ntups; i++)
9594 : {
9595 180 : Oid nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9596 :
9597 CBC 180 : daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9598 GIC 180 : daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9599 CBC 180 : daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9600 GIC 180 : AssignDumpId(&daclinfo[i].dobj);
9601 : /* cheesy ... is it worth coming up with a better object name? */
9602 180 : daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9603 ECB :
9604 GIC 180 : if (nspid != InvalidOid)
9605 CBC 90 : daclinfo[i].dobj.namespace = findNamespace(nspid);
9606 ECB : else
9607 GIC 90 : daclinfo[i].dobj.namespace = NULL;
9608 ECB :
9609 GIC 180 : daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9610 CBC 180 : daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9611 180 : daclinfo[i].dacl.privtype = 0;
9612 180 : daclinfo[i].dacl.initprivs = NULL;
9613 180 : daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
9614 180 : daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9615 ECB :
9616 : /* Default ACLs are ACLs, of course */
9617 CBC 180 : daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9618 :
9619 ECB : /* Decide whether we want to dump it */
9620 CBC 180 : selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9621 ECB : }
9622 :
9623 CBC 118 : PQclear(res);
9624 ECB :
9625 CBC 118 : destroyPQExpBuffer(query);
9626 ECB :
9627 CBC 118 : return daclinfo;
9628 : }
9629 :
9630 ECB : /*
9631 : * getRoleName -- look up the name of a role, given its OID
9632 : *
9633 : * In current usage, we don't expect failures, so error out for a bad OID.
9634 : */
9635 : static const char *
9636 GIC 447209 : getRoleName(const char *roleoid_str)
9637 ECB : {
9638 GIC 447209 : Oid roleoid = atooid(roleoid_str);
9639 :
9640 : /*
9641 : * Do binary search to find the appropriate item.
9642 : */
9643 447209 : if (nrolenames > 0)
9644 : {
9645 447209 : RoleNameItem *low = &rolenames[0];
9646 447209 : RoleNameItem *high = &rolenames[nrolenames - 1];
9647 :
9648 CBC 1789024 : while (low <= high)
9649 : {
9650 GIC 1789024 : RoleNameItem *middle = low + (high - low) / 2;
9651 :
9652 1789024 : if (roleoid < middle->roleoid)
9653 1340620 : high = middle - 1;
9654 448404 : else if (roleoid > middle->roleoid)
9655 1195 : low = middle + 1;
9656 : else
9657 447209 : return middle->rolename; /* found a match */
9658 : }
9659 : }
9660 :
9661 UIC 0 : pg_fatal("role with OID %u does not exist", roleoid);
9662 : return NULL; /* keep compiler quiet */
9663 : }
9664 :
9665 ECB : /*
9666 : * collectRoleNames --
9667 : *
9668 : * Construct a table of all known roles.
9669 : * The table is sorted by OID for speed in lookup.
9670 : */
9671 : static void
9672 GIC 119 : collectRoleNames(Archive *fout)
9673 : {
9674 : PGresult *res;
9675 : const char *query;
9676 : int i;
9677 :
9678 119 : query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
9679 :
9680 119 : res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
9681 ECB :
9682 GIC 119 : nrolenames = PQntuples(res);
9683 ECB :
9684 CBC 119 : rolenames = (RoleNameItem *) pg_malloc(nrolenames * sizeof(RoleNameItem));
9685 :
9686 2199 : for (i = 0; i < nrolenames; i++)
9687 : {
9688 2080 : rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
9689 2080 : rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
9690 ECB : }
9691 :
9692 CBC 119 : PQclear(res);
9693 119 : }
9694 ECB :
9695 : /*
9696 : * getAdditionalACLs
9697 : *
9698 : * We have now created all the DumpableObjects, and collected the ACL data
9699 : * that appears in the directly-associated catalog entries. However, there's
9700 : * more ACL-related info to collect. If any of a table's columns have ACLs,
9701 : * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
9702 : * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
9703 : * Also, in versions having the pg_init_privs catalog, read that and load the
9704 : * information into the relevant DumpableObjects.
9705 : */
9706 : static void
9707 CBC 116 : getAdditionalACLs(Archive *fout)
9708 ECB : {
9709 CBC 116 : PQExpBuffer query = createPQExpBuffer();
9710 ECB : PGresult *res;
9711 : int ntups,
9712 : i;
9713 :
9714 : /* Check for per-column ACLs */
9715 GIC 116 : appendPQExpBufferStr(query,
9716 ECB : "SELECT DISTINCT attrelid FROM pg_attribute "
9717 : "WHERE attacl IS NOT NULL");
9718 :
9719 CBC 116 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9720 ECB :
9721 GIC 116 : ntups = PQntuples(res);
9722 351 : for (i = 0; i < ntups; i++)
9723 ECB : {
9724 GIC 235 : Oid relid = atooid(PQgetvalue(res, i, 0));
9725 ECB : TableInfo *tblinfo;
9726 :
9727 CBC 235 : tblinfo = findTableByOid(relid);
9728 : /* OK to ignore tables we haven't got a DumpableObject for */
9729 GIC 235 : if (tblinfo)
9730 : {
9731 235 : tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
9732 235 : tblinfo->hascolumnACLs = true;
9733 : }
9734 : }
9735 116 : PQclear(res);
9736 :
9737 : /* Fetch initial-privileges data */
9738 CBC 116 : if (fout->remoteVersion >= 90600)
9739 : {
9740 GIC 116 : printfPQExpBuffer(query,
9741 : "SELECT objoid, classoid, objsubid, privtype, initprivs "
9742 : "FROM pg_init_privs");
9743 :
9744 116 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9745 :
9746 116 : ntups = PQntuples(res);
9747 25863 : for (i = 0; i < ntups; i++)
9748 : {
9749 25747 : Oid objoid = atooid(PQgetvalue(res, i, 0));
9750 25747 : Oid classoid = atooid(PQgetvalue(res, i, 1));
9751 25747 : int objsubid = atoi(PQgetvalue(res, i, 2));
9752 25747 : char privtype = *(PQgetvalue(res, i, 3));
9753 25747 : char *initprivs = PQgetvalue(res, i, 4);
9754 : CatalogId objId;
9755 : DumpableObject *dobj;
9756 ECB :
9757 GIC 25747 : objId.tableoid = classoid;
9758 CBC 25747 : objId.oid = objoid;
9759 GIC 25747 : dobj = findObjectByCatalogId(objId);
9760 : /* OK to ignore entries we haven't got a DumpableObject for */
9761 25747 : if (dobj)
9762 : {
9763 : /* Cope with sub-object initprivs */
9764 18599 : if (objsubid != 0)
9765 : {
9766 1877 : if (dobj->objType == DO_TABLE)
9767 : {
9768 : /* For a column initpriv, set the table's ACL flags */
9769 1877 : dobj->components |= DUMP_COMPONENT_ACL;
9770 CBC 1877 : ((TableInfo *) dobj)->hascolumnACLs = true;
9771 : }
9772 ECB : else
9773 LBC 0 : pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
9774 : classoid, objoid, objsubid);
9775 CBC 1989 : continue;
9776 : }
9777 ECB :
9778 : /*
9779 : * We ignore any pg_init_privs.initprivs entry for the public
9780 : * schema, as explained in getNamespaces().
9781 : */
9782 CBC 16722 : if (dobj->objType == DO_NAMESPACE &&
9783 228 : strcmp(dobj->name, "public") == 0)
9784 112 : continue;
9785 ECB :
9786 : /* Else it had better be of a type we think has ACLs */
9787 GIC 16610 : if (dobj->objType == DO_NAMESPACE ||
9788 CBC 16494 : dobj->objType == DO_TYPE ||
9789 GIC 16473 : dobj->objType == DO_FUNC ||
9790 CBC 16387 : dobj->objType == DO_AGG ||
9791 16366 : dobj->objType == DO_TABLE ||
9792 LBC 0 : dobj->objType == DO_PROCLANG ||
9793 0 : dobj->objType == DO_FDW ||
9794 0 : dobj->objType == DO_FOREIGN_SERVER)
9795 CBC 16610 : {
9796 16610 : DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
9797 ECB :
9798 CBC 16610 : daobj->dacl.privtype = privtype;
9799 16610 : daobj->dacl.initprivs = pstrdup(initprivs);
9800 ECB : }
9801 : else
9802 LBC 0 : pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
9803 ECB : classoid, objoid, objsubid);
9804 : }
9805 : }
9806 GIC 116 : PQclear(res);
9807 ECB : }
9808 :
9809 GIC 116 : destroyPQExpBuffer(query);
9810 CBC 116 : }
9811 :
9812 : /*
9813 ECB : * dumpCommentExtended --
9814 : *
9815 : * This routine is used to dump any comments associated with the
9816 : * object handed to this routine. The routine takes the object type
9817 : * and object name (ready to print, except for schema decoration), plus
9818 : * the namespace and owner of the object (for labeling the ArchiveEntry),
9819 : * plus catalog ID and subid which are the lookup key for pg_description,
9820 : * plus the dump ID for the object (for setting a dependency).
9821 : * If a matching pg_description entry is found, it is dumped.
9822 : *
9823 : * Note: in some cases, such as comments for triggers and rules, the "type"
9824 : * string really looks like, e.g., "TRIGGER name ON". This is a bit of a hack
9825 : * but it doesn't seem worth complicating the API for all callers to make
9826 : * it cleaner.
9827 : *
9828 : * Note: although this routine takes a dumpId for dependency purposes,
9829 : * that purpose is just to mark the dependency in the emitted dump file
9830 : * for possible future use by pg_restore. We do NOT use it for determining
9831 : * ordering of the comment in the dump file, because this routine is called
9832 : * after dependency sorting occurs. This routine should be called just after
9833 : * calling ArchiveEntry() for the specified object.
9834 : */
9835 : static void
9836 GIC 742 : dumpCommentExtended(Archive *fout, const char *type,
9837 : const char *name, const char *namespace,
9838 : const char *owner, CatalogId catalogId,
9839 : int subid, DumpId dumpId,
9840 : const char *initdb_comment)
9841 : {
9842 742 : DumpOptions *dopt = fout->dopt;
9843 : CommentItem *comments;
9844 : int ncomments;
9845 :
9846 : /* do nothing, if --no-comments is supplied */
9847 742 : if (dopt->no_comments)
9848 LBC 0 : return;
9849 :
9850 : /* Comments are schema not data ... except LO comments are data */
9851 GIC 742 : if (strcmp(type, "LARGE OBJECT") != 0)
9852 : {
9853 695 : if (dopt->dataOnly)
9854 UIC 0 : return;
9855 : }
9856 : else
9857 : {
9858 : /* We do dump LO comments in binary-upgrade mode */
9859 GIC 47 : if (dopt->schemaOnly && !dopt->binary_upgrade)
9860 UIC 0 : return;
9861 : }
9862 ECB :
9863 : /* Search for comments associated with catalogId, using table */
9864 GIC 742 : ncomments = findComments(catalogId.tableoid, catalogId.oid,
9865 : &comments);
9866 :
9867 : /* Is there one matching the subid? */
9868 742 : while (ncomments > 0)
9869 : {
9870 702 : if (comments->objsubid == subid)
9871 702 : break;
9872 UIC 0 : comments++;
9873 0 : ncomments--;
9874 ECB : }
9875 :
9876 CBC 742 : if (initdb_comment != NULL)
9877 ECB : {
9878 : static CommentItem empty_comment = {.descr = ""};
9879 :
9880 : /*
9881 : * initdb creates this object with a comment. Skip dumping the
9882 : * initdb-provided comment, which would complicate matters for
9883 : * non-superuser use of pg_dump. When the DBA has removed initdb's
9884 : * comment, replicate that.
9885 : */
9886 CBC 93 : if (ncomments == 0)
9887 ECB : {
9888 GIC 4 : comments = &empty_comment;
9889 CBC 4 : ncomments = 1;
9890 : }
9891 89 : else if (strcmp(comments->descr, initdb_comment) == 0)
9892 GIC 89 : ncomments = 0;
9893 ECB : }
9894 :
9895 : /* If a comment exists, build COMMENT ON statement */
9896 CBC 742 : if (ncomments > 0)
9897 : {
9898 617 : PQExpBuffer query = createPQExpBuffer();
9899 GIC 617 : PQExpBuffer tag = createPQExpBuffer();
9900 ECB :
9901 CBC 617 : appendPQExpBuffer(query, "COMMENT ON %s ", type);
9902 GIC 617 : if (namespace && *namespace)
9903 CBC 471 : appendPQExpBuffer(query, "%s.", fmtId(namespace));
9904 GIC 617 : appendPQExpBuffer(query, "%s IS ", name);
9905 CBC 617 : appendStringLiteralAH(query, comments->descr, fout);
9906 617 : appendPQExpBufferStr(query, ";\n");
9907 ECB :
9908 CBC 617 : appendPQExpBuffer(tag, "%s %s", type, name);
9909 ECB :
9910 : /*
9911 : * We mark comments as SECTION_NONE because they really belong in the
9912 : * same section as their parent, whether that is pre-data or
9913 : * post-data.
9914 : */
9915 GIC 617 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
9916 CBC 617 : ARCHIVE_OPTS(.tag = tag->data,
9917 : .namespace = namespace,
9918 : .owner = owner,
9919 ECB : .description = "COMMENT",
9920 : .section = SECTION_NONE,
9921 : .createStmt = query->data,
9922 : .deps = &dumpId,
9923 : .nDeps = 1));
9924 :
9925 GIC 617 : destroyPQExpBuffer(query);
9926 617 : destroyPQExpBuffer(tag);
9927 : }
9928 : }
9929 :
9930 : /*
9931 : * dumpComment --
9932 ECB : *
9933 : * Typical simplification of the above function.
9934 : */
9935 : static inline void
9936 GIC 641 : dumpComment(Archive *fout, const char *type,
9937 : const char *name, const char *namespace,
9938 : const char *owner, CatalogId catalogId,
9939 ECB : int subid, DumpId dumpId)
9940 : {
9941 CBC 641 : dumpCommentExtended(fout, type, name, namespace, owner,
9942 ECB : catalogId, subid, dumpId, NULL);
9943 GIC 641 : }
9944 ECB :
9945 : /*
9946 : * dumpTableComment --
9947 : *
9948 : * As above, but dump comments for both the specified table (or view)
9949 : * and its columns.
9950 : */
9951 : static void
9952 GIC 82 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
9953 ECB : const char *reltypename)
9954 : {
9955 GIC 82 : DumpOptions *dopt = fout->dopt;
9956 : CommentItem *comments;
9957 EUB : int ncomments;
9958 : PQExpBuffer query;
9959 : PQExpBuffer tag;
9960 :
9961 : /* do nothing, if --no-comments is supplied */
9962 GIC 82 : if (dopt->no_comments)
9963 UIC 0 : return;
9964 :
9965 : /* Comments are SCHEMA not data */
9966 GIC 82 : if (dopt->dataOnly)
9967 UIC 0 : return;
9968 ECB :
9969 : /* Search for comments associated with relation, using table */
9970 GIC 82 : ncomments = findComments(tbinfo->dobj.catId.tableoid,
9971 82 : tbinfo->dobj.catId.oid,
9972 : &comments);
9973 :
9974 ECB : /* If comments exist, build COMMENT ON statements */
9975 GIC 82 : if (ncomments <= 0)
9976 LBC 0 : return;
9977 :
9978 CBC 82 : query = createPQExpBuffer();
9979 GIC 82 : tag = createPQExpBuffer();
9980 ECB :
9981 GIC 236 : while (ncomments > 0)
9982 ECB : {
9983 GIC 154 : const char *descr = comments->descr;
9984 CBC 154 : int objsubid = comments->objsubid;
9985 ECB :
9986 GIC 154 : if (objsubid == 0)
9987 : {
9988 CBC 36 : resetPQExpBuffer(tag);
9989 36 : appendPQExpBuffer(tag, "%s %s", reltypename,
9990 GIC 36 : fmtId(tbinfo->dobj.name));
9991 :
9992 36 : resetPQExpBuffer(query);
9993 36 : appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9994 36 : fmtQualifiedDumpable(tbinfo));
9995 36 : appendStringLiteralAH(query, descr, fout);
9996 36 : appendPQExpBufferStr(query, ";\n");
9997 :
9998 36 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
9999 36 : ARCHIVE_OPTS(.tag = tag->data,
10000 : .namespace = tbinfo->dobj.namespace->dobj.name,
10001 : .owner = tbinfo->rolname,
10002 : .description = "COMMENT",
10003 ECB : .section = SECTION_NONE,
10004 : .createStmt = query->data,
10005 : .deps = &(tbinfo->dobj.dumpId),
10006 : .nDeps = 1));
10007 : }
10008 GIC 118 : else if (objsubid > 0 && objsubid <= tbinfo->numatts)
10009 : {
10010 118 : resetPQExpBuffer(tag);
10011 CBC 118 : appendPQExpBuffer(tag, "COLUMN %s.",
10012 GIC 118 : fmtId(tbinfo->dobj.name));
10013 118 : appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
10014 :
10015 CBC 118 : resetPQExpBuffer(query);
10016 GIC 118 : appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
10017 CBC 118 : fmtQualifiedDumpable(tbinfo));
10018 118 : appendPQExpBuffer(query, "%s IS ",
10019 GIC 118 : fmtId(tbinfo->attnames[objsubid - 1]));
10020 CBC 118 : appendStringLiteralAH(query, descr, fout);
10021 GIC 118 : appendPQExpBufferStr(query, ";\n");
10022 :
10023 CBC 118 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
10024 GIC 118 : ARCHIVE_OPTS(.tag = tag->data,
10025 ECB : .namespace = tbinfo->dobj.namespace->dobj.name,
10026 : .owner = tbinfo->rolname,
10027 : .description = "COMMENT",
10028 : .section = SECTION_NONE,
10029 : .createStmt = query->data,
10030 : .deps = &(tbinfo->dobj.dumpId),
10031 : .nDeps = 1));
10032 : }
10033 :
10034 CBC 154 : comments++;
10035 GIC 154 : ncomments--;
10036 ECB : }
10037 :
10038 GIC 82 : destroyPQExpBuffer(query);
10039 82 : destroyPQExpBuffer(tag);
10040 ECB : }
10041 :
10042 : /*
10043 : * findComments --
10044 : *
10045 : * Find the comment(s), if any, associated with the given object. All the
10046 : * objsubid values associated with the given classoid/objoid are found with
10047 : * one search.
10048 : */
10049 : static int
10050 GIC 860 : findComments(Oid classoid, Oid objoid, CommentItem **items)
10051 : {
10052 860 : CommentItem *middle = NULL;
10053 ECB : CommentItem *low;
10054 : CommentItem *high;
10055 : int nmatch;
10056 :
10057 : /*
10058 : * Do binary search to find some item matching the object.
10059 : */
10060 CBC 860 : low = &comments[0];
10061 GIC 860 : high = &comments[ncomments - 1];
10062 CBC 8410 : while (low <= high)
10063 : {
10064 GIC 8370 : middle = low + (high - low) / 2;
10065 ECB :
10066 CBC 8370 : if (classoid < middle->classoid)
10067 GIC 3522 : high = middle - 1;
10068 4848 : else if (classoid > middle->classoid)
10069 GBC 2370 : low = middle + 1;
10070 GIC 2478 : else if (objoid < middle->objoid)
10071 CBC 199 : high = middle - 1;
10072 GIC 2279 : else if (objoid > middle->objoid)
10073 1459 : low = middle + 1;
10074 : else
10075 820 : break; /* found a match */
10076 : }
10077 :
10078 CBC 860 : if (low > high) /* no matches */
10079 ECB : {
10080 CBC 40 : *items = NULL;
10081 GIC 40 : return 0;
10082 : }
10083 ECB :
10084 : /*
10085 : * Now determine how many items match the object. The search loop
10086 : * invariant still holds: only items between low and high inclusive could
10087 : * match.
10088 EUB : */
10089 GBC 820 : nmatch = 1;
10090 820 : while (middle > low)
10091 ECB : {
10092 CBC 497 : if (classoid != middle[-1].classoid ||
10093 GIC 412 : objoid != middle[-1].objoid)
10094 ECB : break;
10095 LBC 0 : middle--;
10096 UIC 0 : nmatch++;
10097 : }
10098 EUB :
10099 GIC 820 : *items = middle;
10100 :
10101 820 : middle += nmatch;
10102 CBC 892 : while (middle <= high)
10103 : {
10104 GIC 539 : if (classoid != middle->classoid ||
10105 CBC 164 : objoid != middle->objoid)
10106 ECB : break;
10107 GIC 72 : middle++;
10108 72 : nmatch++;
10109 : }
10110 :
10111 820 : return nmatch;
10112 : }
10113 :
10114 : /*
10115 : * collectComments --
10116 : *
10117 : * Construct a table of all comments available for database objects;
10118 : * also set the has-comment component flag for each relevant object.
10119 : *
10120 : * We used to do per-object queries for the comments, but it's much faster
10121 : * to pull them all over at once, and on most databases the memory cost
10122 : * isn't high.
10123 : *
10124 : * The table is sorted by classoid/objid/objsubid for speed in lookup.
10125 : */
10126 : static void
10127 118 : collectComments(Archive *fout)
10128 : {
10129 : PGresult *res;
10130 : PQExpBuffer query;
10131 : int i_description;
10132 ECB : int i_classoid;
10133 : int i_objoid;
10134 : int i_objsubid;
10135 : int ntups;
10136 : int i;
10137 : DumpableObject *dobj;
10138 :
10139 GIC 118 : query = createPQExpBuffer();
10140 :
10141 118 : appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
10142 : "FROM pg_catalog.pg_description "
10143 ECB : "ORDER BY classoid, objoid, objsubid");
10144 EUB :
10145 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10146 :
10147 ECB : /* Construct lookup table containing OIDs in numeric form */
10148 :
10149 CBC 118 : i_description = PQfnumber(res, "description");
10150 GBC 118 : i_classoid = PQfnumber(res, "classoid");
10151 GIC 118 : i_objoid = PQfnumber(res, "objoid");
10152 118 : i_objsubid = PQfnumber(res, "objsubid");
10153 :
10154 118 : ntups = PQntuples(res);
10155 ECB :
10156 GBC 118 : comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
10157 GIC 118 : ncomments = 0;
10158 118 : dobj = NULL;
10159 :
10160 CBC 614578 : for (i = 0; i < ntups; i++)
10161 : {
10162 : CatalogId objId;
10163 : int subid;
10164 ECB :
10165 GIC 614460 : objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
10166 CBC 614460 : objId.oid = atooid(PQgetvalue(res, i, i_objoid));
10167 614460 : subid = atoi(PQgetvalue(res, i, i_objsubid));
10168 EUB :
10169 : /* We needn't remember comments that don't match any dumpable object */
10170 GIC 614460 : if (dobj == NULL ||
10171 226096 : dobj->catId.tableoid != objId.tableoid ||
10172 CBC 224565 : dobj->catId.oid != objId.oid)
10173 GIC 614370 : dobj = findObjectByCatalogId(objId);
10174 614460 : if (dobj == NULL)
10175 388250 : continue;
10176 :
10177 : /*
10178 : * Comments on columns of composite types are linked to the type's
10179 : * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
10180 : * in the type's own DumpableObject.
10181 : */
10182 CBC 226210 : if (subid != 0 && dobj->objType == DO_TABLE &&
10183 GIC 190 : ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
10184 CBC 45 : {
10185 ECB : TypeInfo *cTypeInfo;
10186 :
10187 CBC 45 : cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
10188 45 : if (cTypeInfo)
10189 GIC 45 : cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
10190 : }
10191 : else
10192 CBC 226165 : dobj->components |= DUMP_COMPONENT_COMMENT;
10193 :
10194 226210 : comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
10195 226210 : comments[ncomments].classoid = objId.tableoid;
10196 GIC 226210 : comments[ncomments].objoid = objId.oid;
10197 CBC 226210 : comments[ncomments].objsubid = subid;
10198 226210 : ncomments++;
10199 ECB : }
10200 :
10201 CBC 118 : PQclear(res);
10202 118 : destroyPQExpBuffer(query);
10203 GIC 118 : }
10204 ECB :
10205 : /*
10206 : * dumpDumpableObject
10207 : *
10208 : * This routine and its subsidiaries are responsible for creating
10209 : * ArchiveEntries (TOC objects) for each object to be dumped.
10210 : */
10211 : static void
10212 CBC 510020 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
10213 : {
10214 : /*
10215 : * Clear any dump-request bits for components that don't exist for this
10216 : * object. (This makes it safe to initially use DUMP_COMPONENT_ALL as the
10217 : * request for every kind of object.)
10218 : */
10219 GIC 510020 : dobj->dump &= dobj->components;
10220 :
10221 ECB : /* Now, short-circuit if there's nothing to be done here. */
10222 CBC 510020 : if (dobj->dump == 0)
10223 GIC 462464 : return;
10224 :
10225 47556 : switch (dobj->objType)
10226 : {
10227 339 : case DO_NAMESPACE:
10228 339 : dumpNamespace(fout, (const NamespaceInfo *) dobj);
10229 339 : break;
10230 18 : case DO_EXTENSION:
10231 18 : dumpExtension(fout, (const ExtensionInfo *) dobj);
10232 CBC 18 : break;
10233 GIC 523 : case DO_TYPE:
10234 523 : dumpType(fout, (const TypeInfo *) dobj);
10235 523 : break;
10236 74 : case DO_SHELL_TYPE:
10237 CBC 74 : dumpShellType(fout, (const ShellTypeInfo *) dobj);
10238 GIC 74 : break;
10239 CBC 1715 : case DO_FUNC:
10240 GIC 1715 : dumpFunc(fout, (const FuncInfo *) dobj);
10241 1715 : break;
10242 292 : case DO_AGG:
10243 292 : dumpAgg(fout, (const AggInfo *) dobj);
10244 292 : break;
10245 108 : case DO_OPERATOR:
10246 108 : dumpOpr(fout, (const OprInfo *) dobj);
10247 108 : break;
10248 CBC 82 : case DO_ACCESS_METHOD:
10249 GIC 82 : dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
10250 82 : break;
10251 CBC 132 : case DO_OPCLASS:
10252 GIC 132 : dumpOpclass(fout, (const OpclassInfo *) dobj);
10253 132 : break;
10254 113 : case DO_OPFAMILY:
10255 113 : dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
10256 113 : break;
10257 81 : case DO_COLLATION:
10258 CBC 81 : dumpCollation(fout, (const CollInfo *) dobj);
10259 GBC 81 : break;
10260 GIC 39 : case DO_CONVERSION:
10261 39 : dumpConversion(fout, (const ConvInfo *) dobj);
10262 CBC 39 : break;
10263 GBC 20378 : case DO_TABLE:
10264 GIC 20378 : dumpTable(fout, (const TableInfo *) dobj);
10265 20378 : break;
10266 CBC 1166 : case DO_TABLE_ATTACH:
10267 1166 : dumpTableAttach(fout, (const TableAttachInfo *) dobj);
10268 GIC 1166 : break;
10269 793 : case DO_ATTRDEF:
10270 793 : dumpAttrDef(fout, (const AttrDefInfo *) dobj);
10271 CBC 793 : break;
10272 GBC 1842 : case DO_INDEX:
10273 GIC 1842 : dumpIndex(fout, (const IndxInfo *) dobj);
10274 CBC 1842 : break;
10275 567 : case DO_INDEX_ATTACH:
10276 GIC 567 : dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
10277 CBC 567 : break;
10278 GIC 137 : case DO_STATSEXT:
10279 CBC 137 : dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
10280 137 : break;
10281 GIC 328 : case DO_REFRESH_MATVIEW:
10282 CBC 328 : refreshMatViewData(fout, (const TableDataInfo *) dobj);
10283 GIC 328 : break;
10284 CBC 821 : case DO_RULE:
10285 821 : dumpRule(fout, (const RuleInfo *) dobj);
10286 821 : break;
10287 GIC 504 : case DO_TRIGGER:
10288 CBC 504 : dumpTrigger(fout, (const TriggerInfo *) dobj);
10289 504 : break;
10290 38 : case DO_EVENT_TRIGGER:
10291 38 : dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
10292 38 : break;
10293 GIC 1526 : case DO_CONSTRAINT:
10294 CBC 1526 : dumpConstraint(fout, (const ConstraintInfo *) dobj);
10295 1526 : break;
10296 GIC 158 : case DO_FK_CONSTRAINT:
10297 158 : dumpConstraint(fout, (const ConstraintInfo *) dobj);
10298 158 : break;
10299 83 : case DO_PROCLANG:
10300 83 : dumpProcLang(fout, (const ProcLangInfo *) dobj);
10301 83 : break;
10302 68 : case DO_CAST:
10303 68 : dumpCast(fout, (const CastInfo *) dobj);
10304 CBC 68 : break;
10305 GIC 43 : case DO_TRANSFORM:
10306 CBC 43 : dumpTransform(fout, (const TransformInfo *) dobj);
10307 43 : break;
10308 338 : case DO_SEQUENCE_SET:
10309 338 : dumpSequenceData(fout, (const TableDataInfo *) dobj);
10310 GIC 338 : break;
10311 CBC 3095 : case DO_TABLE_DATA:
10312 3095 : dumpTableData(fout, (const TableDataInfo *) dobj);
10313 3095 : break;
10314 10382 : case DO_DUMMY_TYPE:
10315 ECB : /* table rowtypes and array types are never dumped separately */
10316 CBC 10382 : break;
10317 39 : case DO_TSPARSER:
10318 GIC 39 : dumpTSParser(fout, (const TSParserInfo *) dobj);
10319 CBC 39 : break;
10320 84 : case DO_TSDICT:
10321 GIC 84 : dumpTSDictionary(fout, (const TSDictInfo *) dobj);
10322 84 : break;
10323 39 : case DO_TSTEMPLATE:
10324 39 : dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
10325 39 : break;
10326 59 : case DO_TSCONFIG:
10327 59 : dumpTSConfig(fout, (const TSConfigInfo *) dobj);
10328 59 : break;
10329 45 : case DO_FDW:
10330 CBC 45 : dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
10331 45 : break;
10332 GIC 49 : case DO_FOREIGN_SERVER:
10333 49 : dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
10334 CBC 49 : break;
10335 154 : case DO_DEFAULT_ACL:
10336 GIC 154 : dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
10337 154 : break;
10338 GNC 89 : case DO_LARGE_OBJECT:
10339 89 : dumpLO(fout, (const LoInfo *) dobj);
10340 GIC 89 : break;
10341 GNC 42 : case DO_LARGE_OBJECT_DATA:
10342 GIC 42 : if (dobj->dump & DUMP_COMPONENT_DATA)
10343 : {
10344 : TocEntry *te;
10345 :
10346 CBC 42 : te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
10347 GIC 42 : ARCHIVE_OPTS(.tag = dobj->name,
10348 ECB : .description = "BLOBS",
10349 : .section = SECTION_DATA,
10350 : .dumpFn = dumpLOs));
10351 :
10352 : /*
10353 : * Set the TocEntry's dataLength in case we are doing a
10354 : * parallel dump and want to order dump jobs by table size.
10355 : * (We need some size estimate for every TocEntry with a
10356 : * DataDumper function.) We don't currently have any cheap
10357 : * way to estimate the size of LOs, but it doesn't matter;
10358 : * let's just set the size to a large value so parallel dumps
10359 : * will launch this job first. If there's lots of LOs, we
10360 : * win, and if there aren't, we don't lose much. (If you want
10361 : * to improve on this, really what you should be thinking
10362 : * about is allowing LO dumping to be parallelized, not just
10363 : * getting a smarter estimate for the single TOC entry.)
10364 : */
10365 CBC 42 : te->dataLength = INT_MAX;
10366 ECB : }
10367 CBC 42 : break;
10368 340 : case DO_POLICY:
10369 340 : dumpPolicy(fout, (const PolicyInfo *) dobj);
10370 GIC 340 : break;
10371 CBC 152 : case DO_PUBLICATION:
10372 GIC 152 : dumpPublication(fout, (const PublicationInfo *) dobj);
10373 152 : break;
10374 CBC 256 : case DO_PUBLICATION_REL:
10375 GIC 256 : dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
10376 CBC 256 : break;
10377 75 : case DO_PUBLICATION_TABLE_IN_SCHEMA:
10378 GIC 75 : dumpPublicationNamespace(fout,
10379 : (const PublicationSchemaInfo *) dobj);
10380 75 : break;
10381 114 : case DO_SUBSCRIPTION:
10382 114 : dumpSubscription(fout, (const SubscriptionInfo *) dobj);
10383 114 : break;
10384 236 : case DO_PRE_DATA_BOUNDARY:
10385 ECB : case DO_POST_DATA_BOUNDARY:
10386 : /* never dumped, nothing to do */
10387 GIC 236 : break;
10388 ECB : }
10389 : }
10390 :
10391 EUB : /*
10392 : * dumpNamespace
10393 : * writes out to fout the queries to recreate a user-defined namespace
10394 : */
10395 ECB : static void
10396 GIC 339 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
10397 ECB : {
10398 CBC 339 : DumpOptions *dopt = fout->dopt;
10399 : PQExpBuffer q;
10400 ECB : PQExpBuffer delq;
10401 : char *qnspname;
10402 :
10403 : /* Do nothing in data-only dump */
10404 CBC 339 : if (dopt->dataOnly)
10405 GIC 16 : return;
10406 :
10407 CBC 323 : q = createPQExpBuffer();
10408 GIC 323 : delq = createPQExpBuffer();
10409 :
10410 323 : qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
10411 :
10412 323 : if (nspinfo->create)
10413 : {
10414 224 : appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
10415 224 : appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
10416 : }
10417 : else
10418 : {
10419 : /* see selectDumpableNamespace() */
10420 99 : appendPQExpBufferStr(delq,
10421 : "-- *not* dropping schema, since initdb creates it\n");
10422 99 : appendPQExpBufferStr(q,
10423 ECB : "-- *not* creating schema, since initdb creates it\n");
10424 : }
10425 :
10426 GIC 323 : if (dopt->binary_upgrade)
10427 28 : binary_upgrade_extension_member(q, &nspinfo->dobj,
10428 : "SCHEMA", qnspname, NULL);
10429 :
10430 323 : if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10431 160 : ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
10432 160 : ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
10433 : .owner = nspinfo->rolname,
10434 : .description = "SCHEMA",
10435 ECB : .section = SECTION_PRE_DATA,
10436 : .createStmt = q->data,
10437 : .dropStmt = delq->data));
10438 :
10439 : /* Dump Schema Comments and Security Labels */
10440 GIC 323 : if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10441 ECB : {
10442 GIC 101 : const char *initdb_comment = NULL;
10443 :
10444 101 : if (!nspinfo->create && strcmp(qnspname, "public") == 0)
10445 CBC 93 : initdb_comment = "standard public schema";
10446 101 : dumpCommentExtended(fout, "SCHEMA", qnspname,
10447 101 : NULL, nspinfo->rolname,
10448 101 : nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
10449 : initdb_comment);
10450 ECB : }
10451 :
10452 CBC 323 : if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10453 LBC 0 : dumpSecLabel(fout, "SCHEMA", qnspname,
10454 0 : NULL, nspinfo->rolname,
10455 UIC 0 : nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
10456 ECB :
10457 GIC 323 : if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
10458 241 : dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
10459 : qnspname, NULL, NULL,
10460 241 : nspinfo->rolname, &nspinfo->dacl);
10461 ECB :
10462 CBC 323 : free(qnspname);
10463 ECB :
10464 GIC 323 : destroyPQExpBuffer(q);
10465 323 : destroyPQExpBuffer(delq);
10466 ECB : }
10467 :
10468 : /*
10469 : * dumpExtension
10470 : * writes out to fout the queries to recreate an extension
10471 : */
10472 : static void
10473 GIC 18 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
10474 : {
10475 18 : DumpOptions *dopt = fout->dopt;
10476 : PQExpBuffer q;
10477 : PQExpBuffer delq;
10478 ECB : char *qextname;
10479 :
10480 : /* Do nothing in data-only dump */
10481 GIC 18 : if (dopt->dataOnly)
10482 1 : return;
10483 ECB :
10484 CBC 17 : q = createPQExpBuffer();
10485 17 : delq = createPQExpBuffer();
10486 :
10487 GIC 17 : qextname = pg_strdup(fmtId(extinfo->dobj.name));
10488 ECB :
10489 GIC 17 : appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
10490 ECB :
10491 CBC 17 : if (!dopt->binary_upgrade)
10492 ECB : {
10493 : /*
10494 : * In a regular dump, we simply create the extension, intentionally
10495 : * not specifying a version, so that the destination installation's
10496 : * default version is used.
10497 : *
10498 : * Use of IF NOT EXISTS here is unlike our behavior for other object
10499 : * types; but there are various scenarios in which it's convenient to
10500 : * manually create the desired extension before restoring, so we
10501 : * prefer to allow it to exist already.
10502 : */
10503 GIC 16 : appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
10504 16 : qextname, fmtId(extinfo->namespace));
10505 : }
10506 : else
10507 : {
10508 ECB : /*
10509 : * In binary-upgrade mode, it's critical to reproduce the state of the
10510 : * database exactly, so our procedure is to create an empty extension,
10511 : * restore all the contained objects normally, and add them to the
10512 : * extension one by one. This function performs just the first of
10513 : * those steps. binary_upgrade_extension_member() takes care of
10514 : * adding member objects as they're created.
10515 : */
10516 : int i;
10517 : int n;
10518 :
10519 CBC 1 : appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
10520 :
10521 ECB : /*
10522 : * We unconditionally create the extension, so we must drop it if it
10523 : * exists. This could happen if the user deleted 'plpgsql' and then
10524 : * readded it, causing its oid to be greater than g_last_builtin_oid.
10525 : */
10526 CBC 1 : appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
10527 ECB :
10528 CBC 1 : appendPQExpBufferStr(q,
10529 ECB : "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
10530 CBC 1 : appendStringLiteralAH(q, extinfo->dobj.name, fout);
10531 1 : appendPQExpBufferStr(q, ", ");
10532 1 : appendStringLiteralAH(q, extinfo->namespace, fout);
10533 1 : appendPQExpBufferStr(q, ", ");
10534 1 : appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
10535 1 : appendStringLiteralAH(q, extinfo->extversion, fout);
10536 1 : appendPQExpBufferStr(q, ", ");
10537 ECB :
10538 : /*
10539 : * Note that we're pushing extconfig (an OID array) back into
10540 : * pg_extension exactly as-is. This is OK because pg_class OIDs are
10541 : * preserved in binary upgrade.
10542 : */
10543 CBC 1 : if (strlen(extinfo->extconfig) > 2)
10544 1 : appendStringLiteralAH(q, extinfo->extconfig, fout);
10545 ECB : else
10546 LBC 0 : appendPQExpBufferStr(q, "NULL");
10547 CBC 1 : appendPQExpBufferStr(q, ", ");
10548 1 : if (strlen(extinfo->extcondition) > 2)
10549 1 : appendStringLiteralAH(q, extinfo->extcondition, fout);
10550 ECB : else
10551 LBC 0 : appendPQExpBufferStr(q, "NULL");
10552 CBC 1 : appendPQExpBufferStr(q, ", ");
10553 1 : appendPQExpBufferStr(q, "ARRAY[");
10554 1 : n = 0;
10555 2 : for (i = 0; i < extinfo->dobj.nDeps; i++)
10556 ECB : {
10557 : DumpableObject *extobj;
10558 :
10559 CBC 1 : extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
10560 1 : if (extobj && extobj->objType == DO_EXTENSION)
10561 ECB : {
10562 LBC 0 : if (n++ > 0)
10563 0 : appendPQExpBufferChar(q, ',');
10564 0 : appendStringLiteralAH(q, extobj->name, fout);
10565 ECB : }
10566 : }
10567 CBC 1 : appendPQExpBufferStr(q, "]::pg_catalog.text[]");
10568 1 : appendPQExpBufferStr(q, ");\n");
10569 ECB : }
10570 :
10571 CBC 17 : if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10572 17 : ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
10573 17 : ARCHIVE_OPTS(.tag = extinfo->dobj.name,
10574 ECB : .description = "EXTENSION",
10575 : .section = SECTION_PRE_DATA,
10576 : .createStmt = q->data,
10577 : .dropStmt = delq->data));
10578 :
10579 : /* Dump Extension Comments and Security Labels */
10580 CBC 17 : if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10581 17 : dumpComment(fout, "EXTENSION", qextname,
10582 ECB : NULL, "",
10583 CBC 17 : extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10584 ECB :
10585 CBC 17 : if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10586 LBC 0 : dumpSecLabel(fout, "EXTENSION", qextname,
10587 ECB : NULL, "",
10588 LBC 0 : extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10589 ECB :
10590 CBC 17 : free(qextname);
10591 ECB :
10592 CBC 17 : destroyPQExpBuffer(q);
10593 17 : destroyPQExpBuffer(delq);
10594 ECB : }
10595 :
10596 : /*
10597 : * dumpType
10598 : * writes out to fout the queries to recreate a user-defined type
10599 : */
10600 : static void
10601 CBC 523 : dumpType(Archive *fout, const TypeInfo *tyinfo)
10602 ECB : {
10603 CBC 523 : DumpOptions *dopt = fout->dopt;
10604 ECB :
10605 : /* Do nothing in data-only dump */
10606 CBC 523 : if (dopt->dataOnly)
10607 22 : return;
10608 ECB :
10609 : /* Dump out in proper style */
10610 CBC 501 : if (tyinfo->typtype == TYPTYPE_BASE)
10611 GIC 71 : dumpBaseType(fout, tyinfo);
10612 CBC 430 : else if (tyinfo->typtype == TYPTYPE_DOMAIN)
10613 121 : dumpDomain(fout, tyinfo);
10614 309 : else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
10615 123 : dumpCompositeType(fout, tyinfo);
10616 186 : else if (tyinfo->typtype == TYPTYPE_ENUM)
10617 53 : dumpEnumType(fout, tyinfo);
10618 133 : else if (tyinfo->typtype == TYPTYPE_RANGE)
10619 92 : dumpRangeType(fout, tyinfo);
10620 41 : else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
10621 41 : dumpUndefinedType(fout, tyinfo);
10622 ECB : else
10623 LBC 0 : pg_log_warning("typtype of data type \"%s\" appears to be invalid",
10624 ECB : tyinfo->dobj.name);
10625 : }
10626 :
10627 : /*
10628 : * dumpEnumType
10629 : * writes out to fout the queries to recreate a user-defined enum type
10630 : */
10631 : static void
10632 CBC 53 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
10633 ECB : {
10634 CBC 53 : DumpOptions *dopt = fout->dopt;
10635 53 : PQExpBuffer q = createPQExpBuffer();
10636 53 : PQExpBuffer delq = createPQExpBuffer();
10637 53 : PQExpBuffer query = createPQExpBuffer();
10638 ECB : PGresult *res;
10639 : int num,
10640 : i;
10641 : Oid enum_oid;
10642 : char *qtypname;
10643 : char *qualtypname;
10644 : char *label;
10645 : int i_enumlabel;
10646 : int i_oid;
10647 :
10648 GIC 53 : if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
10649 : {
10650 : /* Set up query for enum-specific details */
10651 43 : appendPQExpBufferStr(query,
10652 : "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
10653 : "SELECT oid, enumlabel "
10654 : "FROM pg_catalog.pg_enum "
10655 : "WHERE enumtypid = $1 "
10656 : "ORDER BY enumsortorder");
10657 :
10658 43 : ExecuteSqlStatement(fout, query->data);
10659 :
10660 43 : fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
10661 ECB : }
10662 :
10663 CBC 53 : printfPQExpBuffer(query,
10664 ECB : "EXECUTE dumpEnumType('%u')",
10665 CBC 53 : tyinfo->dobj.catId.oid);
10666 ECB :
10667 CBC 53 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10668 ECB :
10669 CBC 53 : num = PQntuples(res);
10670 ECB :
10671 CBC 53 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10672 53 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10673 ECB :
10674 : /*
10675 : * CASCADE shouldn't be required here as for normal types since the I/O
10676 : * functions are generic and do not get dropped.
10677 : */
10678 CBC 53 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10679 ECB :
10680 CBC 53 : if (dopt->binary_upgrade)
10681 GIC 4 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
10682 4 : tyinfo->dobj.catId.oid,
10683 ECB : false, false);
10684 :
10685 GIC 53 : appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10686 : qualtypname);
10687 :
10688 53 : if (!dopt->binary_upgrade)
10689 : {
10690 49 : i_enumlabel = PQfnumber(res, "enumlabel");
10691 :
10692 ECB : /* Labels with server-assigned oids */
10693 GIC 350 : for (i = 0; i < num; i++)
10694 ECB : {
10695 GIC 301 : label = PQgetvalue(res, i, i_enumlabel);
10696 301 : if (i > 0)
10697 252 : appendPQExpBufferChar(q, ',');
10698 301 : appendPQExpBufferStr(q, "\n ");
10699 301 : appendStringLiteralAH(q, label, fout);
10700 ECB : }
10701 : }
10702 :
10703 CBC 53 : appendPQExpBufferStr(q, "\n);\n");
10704 ECB :
10705 GIC 53 : if (dopt->binary_upgrade)
10706 ECB : {
10707 GIC 4 : i_oid = PQfnumber(res, "oid");
10708 CBC 4 : i_enumlabel = PQfnumber(res, "enumlabel");
10709 :
10710 ECB : /* Labels with dump-assigned (preserved) oids */
10711 CBC 51 : for (i = 0; i < num; i++)
10712 : {
10713 GIC 47 : enum_oid = atooid(PQgetvalue(res, i, i_oid));
10714 47 : label = PQgetvalue(res, i, i_enumlabel);
10715 :
10716 CBC 47 : if (i == 0)
10717 GIC 4 : appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10718 CBC 47 : appendPQExpBuffer(q,
10719 : "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10720 : enum_oid);
10721 GIC 47 : appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10722 CBC 47 : appendStringLiteralAH(q, label, fout);
10723 47 : appendPQExpBufferStr(q, ";\n\n");
10724 : }
10725 : }
10726 ECB :
10727 CBC 53 : if (dopt->binary_upgrade)
10728 4 : binary_upgrade_extension_member(q, &tyinfo->dobj,
10729 : "TYPE", qtypname,
10730 GIC 4 : tyinfo->dobj.namespace->dobj.name);
10731 :
10732 53 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10733 53 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10734 53 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10735 : .namespace = tyinfo->dobj.namespace->dobj.name,
10736 ECB : .owner = tyinfo->rolname,
10737 : .description = "TYPE",
10738 : .section = SECTION_PRE_DATA,
10739 : .createStmt = q->data,
10740 : .dropStmt = delq->data));
10741 :
10742 : /* Dump Type Comments and Security Labels */
10743 CBC 53 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10744 36 : dumpComment(fout, "TYPE", qtypname,
10745 GIC 36 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10746 36 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10747 :
10748 CBC 53 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10749 UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
10750 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10751 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10752 :
10753 CBC 53 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10754 36 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10755 : qtypname, NULL,
10756 36 : tyinfo->dobj.namespace->dobj.name,
10757 GIC 36 : tyinfo->rolname, &tyinfo->dacl);
10758 ECB :
10759 GIC 53 : PQclear(res);
10760 CBC 53 : destroyPQExpBuffer(q);
10761 53 : destroyPQExpBuffer(delq);
10762 GIC 53 : destroyPQExpBuffer(query);
10763 53 : free(qtypname);
10764 53 : free(qualtypname);
10765 53 : }
10766 :
10767 : /*
10768 : * dumpRangeType
10769 ECB : * writes out to fout the queries to recreate a user-defined range type
10770 : */
10771 : static void
10772 GIC 92 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
10773 : {
10774 92 : DumpOptions *dopt = fout->dopt;
10775 92 : PQExpBuffer q = createPQExpBuffer();
10776 92 : PQExpBuffer delq = createPQExpBuffer();
10777 CBC 92 : PQExpBuffer query = createPQExpBuffer();
10778 ECB : PGresult *res;
10779 : Oid collationOid;
10780 : char *qtypname;
10781 : char *qualtypname;
10782 : char *procname;
10783 :
10784 GIC 92 : if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
10785 ECB : {
10786 : /* Set up query for range-specific details */
10787 CBC 41 : appendPQExpBufferStr(query,
10788 : "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
10789 :
10790 GIC 41 : appendPQExpBufferStr(query,
10791 : "SELECT ");
10792 :
10793 41 : if (fout->remoteVersion >= 140000)
10794 41 : appendPQExpBufferStr(query,
10795 : "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
10796 : else
10797 UIC 0 : appendPQExpBufferStr(query,
10798 : "NULL AS rngmultitype, ");
10799 ECB :
10800 CBC 41 : appendPQExpBufferStr(query,
10801 : "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10802 : "opc.opcname AS opcname, "
10803 : "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10804 : " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10805 : "opc.opcdefault, "
10806 : "CASE WHEN rngcollation = st.typcollation THEN 0 "
10807 : " ELSE rngcollation END AS collation, "
10808 : "rngcanonical, rngsubdiff "
10809 : "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10810 : " pg_catalog.pg_opclass opc "
10811 : "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10812 : "rngtypid = $1");
10813 :
10814 GIC 41 : ExecuteSqlStatement(fout, query->data);
10815 ECB :
10816 GIC 41 : fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
10817 : }
10818 :
10819 92 : printfPQExpBuffer(query,
10820 : "EXECUTE dumpRangeType('%u')",
10821 92 : tyinfo->dobj.catId.oid);
10822 ECB :
10823 GIC 92 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
10824 ECB :
10825 GIC 92 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10826 CBC 92 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10827 ECB :
10828 : /*
10829 : * CASCADE shouldn't be required here as for normal types since the I/O
10830 : * functions are generic and do not get dropped.
10831 : */
10832 CBC 92 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10833 :
10834 GIC 92 : if (dopt->binary_upgrade)
10835 6 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
10836 6 : tyinfo->dobj.catId.oid,
10837 : false, true);
10838 :
10839 CBC 92 : appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10840 ECB : qualtypname);
10841 :
10842 GBC 92 : appendPQExpBuffer(q, "\n subtype = %s",
10843 ECB : PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10844 :
10845 CBC 92 : if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
10846 GIC 92 : appendPQExpBuffer(q, ",\n multirange_type_name = %s",
10847 EUB : PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
10848 ECB :
10849 : /* print subtype_opclass only if not default for subtype */
10850 CBC 92 : if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10851 ECB : {
10852 GIC 36 : char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10853 36 : char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10854 :
10855 CBC 36 : appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
10856 ECB : fmtId(nspname));
10857 GIC 36 : appendPQExpBufferStr(q, fmtId(opcname));
10858 EUB : }
10859 :
10860 GBC 92 : collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10861 GIC 92 : if (OidIsValid(collationOid))
10862 : {
10863 CBC 41 : CollInfo *coll = findCollationByOid(collationOid);
10864 ECB :
10865 GIC 41 : if (coll)
10866 41 : appendPQExpBuffer(q, ",\n collation = %s",
10867 CBC 41 : fmtQualifiedDumpable(coll));
10868 ECB : }
10869 :
10870 GIC 92 : procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10871 92 : if (strcmp(procname, "-") != 0)
10872 UIC 0 : appendPQExpBuffer(q, ",\n canonical = %s", procname);
10873 :
10874 GIC 92 : procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10875 92 : if (strcmp(procname, "-") != 0)
10876 CBC 5 : appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
10877 ECB :
10878 GIC 92 : appendPQExpBufferStr(q, "\n);\n");
10879 ECB :
10880 GIC 92 : if (dopt->binary_upgrade)
10881 CBC 6 : binary_upgrade_extension_member(q, &tyinfo->dobj,
10882 EUB : "TYPE", qtypname,
10883 GIC 6 : tyinfo->dobj.namespace->dobj.name);
10884 EUB :
10885 GIC 92 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10886 CBC 92 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10887 GIC 92 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10888 ECB : .namespace = tyinfo->dobj.namespace->dobj.name,
10889 : .owner = tyinfo->rolname,
10890 : .description = "TYPE",
10891 : .section = SECTION_PRE_DATA,
10892 : .createStmt = q->data,
10893 : .dropStmt = delq->data));
10894 :
10895 : /* Dump Type Comments and Security Labels */
10896 GIC 92 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10897 CBC 36 : dumpComment(fout, "TYPE", qtypname,
10898 GIC 36 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10899 CBC 36 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10900 :
10901 GIC 92 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10902 LBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
10903 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10904 UIC 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10905 :
10906 CBC 92 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10907 36 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10908 ECB : qtypname, NULL,
10909 CBC 36 : tyinfo->dobj.namespace->dobj.name,
10910 36 : tyinfo->rolname, &tyinfo->dacl);
10911 ECB :
10912 CBC 92 : PQclear(res);
10913 92 : destroyPQExpBuffer(q);
10914 92 : destroyPQExpBuffer(delq);
10915 92 : destroyPQExpBuffer(query);
10916 92 : free(qtypname);
10917 92 : free(qualtypname);
10918 GIC 92 : }
10919 EUB :
10920 : /*
10921 : * dumpUndefinedType
10922 : * writes out to fout the queries to recreate a !typisdefined type
10923 : *
10924 : * This is a shell type, but we use different terminology to distinguish
10925 : * this case from where we have to emit a shell type definition to break
10926 : * circular dependencies. An undefined type shouldn't ever have anything
10927 : * depending on it.
10928 ECB : */
10929 : static void
10930 CBC 41 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
10931 ECB : {
10932 CBC 41 : DumpOptions *dopt = fout->dopt;
10933 41 : PQExpBuffer q = createPQExpBuffer();
10934 GIC 41 : PQExpBuffer delq = createPQExpBuffer();
10935 : char *qtypname;
10936 : char *qualtypname;
10937 :
10938 41 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10939 41 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10940 :
10941 41 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10942 :
10943 41 : if (dopt->binary_upgrade)
10944 CBC 2 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
10945 GIC 2 : tyinfo->dobj.catId.oid,
10946 : false, false);
10947 ECB :
10948 GIC 41 : appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10949 : qualtypname);
10950 :
10951 41 : if (dopt->binary_upgrade)
10952 2 : binary_upgrade_extension_member(q, &tyinfo->dobj,
10953 : "TYPE", qtypname,
10954 CBC 2 : tyinfo->dobj.namespace->dobj.name);
10955 :
10956 41 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10957 GIC 41 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10958 41 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10959 ECB : .namespace = tyinfo->dobj.namespace->dobj.name,
10960 : .owner = tyinfo->rolname,
10961 : .description = "TYPE",
10962 : .section = SECTION_PRE_DATA,
10963 : .createStmt = q->data,
10964 : .dropStmt = delq->data));
10965 :
10966 : /* Dump Type Comments and Security Labels */
10967 CBC 41 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10968 36 : dumpComment(fout, "TYPE", qtypname,
10969 GIC 36 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10970 36 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10971 :
10972 41 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10973 UIC 0 : dumpSecLabel(fout, "TYPE", qtypname,
10974 LBC 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10975 UIC 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10976 ECB :
10977 CBC 41 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10978 LBC 0 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10979 : qtypname, NULL,
10980 UIC 0 : tyinfo->dobj.namespace->dobj.name,
10981 LBC 0 : tyinfo->rolname, &tyinfo->dacl);
10982 :
10983 GIC 41 : destroyPQExpBuffer(q);
10984 CBC 41 : destroyPQExpBuffer(delq);
10985 GIC 41 : free(qtypname);
10986 CBC 41 : free(qualtypname);
10987 GIC 41 : }
10988 :
10989 ECB : /*
10990 : * dumpBaseType
10991 : * writes out to fout the queries to recreate a user-defined base type
10992 : */
10993 : static void
10994 CBC 71 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
10995 ECB : {
10996 GIC 71 : DumpOptions *dopt = fout->dopt;
10997 71 : PQExpBuffer q = createPQExpBuffer();
10998 71 : PQExpBuffer delq = createPQExpBuffer();
10999 CBC 71 : PQExpBuffer query = createPQExpBuffer();
11000 : PGresult *res;
11001 ECB : char *qtypname;
11002 : char *qualtypname;
11003 : char *typlen;
11004 : char *typinput;
11005 : char *typoutput;
11006 : char *typreceive;
11007 : char *typsend;
11008 : char *typmodin;
11009 : char *typmodout;
11010 : char *typanalyze;
11011 : char *typsubscript;
11012 : Oid typreceiveoid;
11013 : Oid typsendoid;
11014 : Oid typmodinoid;
11015 : Oid typmodoutoid;
11016 : Oid typanalyzeoid;
11017 : Oid typsubscriptoid;
11018 : char *typcategory;
11019 : char *typispreferred;
11020 : char *typdelim;
11021 : char *typbyval;
11022 : char *typalign;
11023 : char *typstorage;
11024 : char *typcollatable;
11025 : char *typdefault;
11026 CBC 71 : bool typdefault_is_literal = false;
11027 :
11028 71 : if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
11029 ECB : {
11030 : /* Set up query for type-specific details */
11031 GIC 41 : appendPQExpBufferStr(query,
11032 : "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
11033 : "SELECT typlen, "
11034 : "typinput, typoutput, typreceive, typsend, "
11035 : "typreceive::pg_catalog.oid AS typreceiveoid, "
11036 : "typsend::pg_catalog.oid AS typsendoid, "
11037 : "typanalyze, "
11038 : "typanalyze::pg_catalog.oid AS typanalyzeoid, "
11039 ECB : "typdelim, typbyval, typalign, typstorage, "
11040 : "typmodin, typmodout, "
11041 : "typmodin::pg_catalog.oid AS typmodinoid, "
11042 : "typmodout::pg_catalog.oid AS typmodoutoid, "
11043 : "typcategory, typispreferred, "
11044 : "(typcollation <> 0) AS typcollatable, "
11045 EUB : "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
11046 :
11047 GBC 41 : if (fout->remoteVersion >= 140000)
11048 GIC 41 : appendPQExpBufferStr(query,
11049 ECB : "typsubscript, "
11050 : "typsubscript::pg_catalog.oid AS typsubscriptoid ");
11051 : else
11052 LBC 0 : appendPQExpBufferStr(query,
11053 ECB : "'-' AS typsubscript, 0 AS typsubscriptoid ");
11054 :
11055 CBC 41 : appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
11056 ECB : "WHERE oid = $1");
11057 :
11058 CBC 41 : ExecuteSqlStatement(fout, query->data);
11059 ECB :
11060 CBC 41 : fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
11061 ECB : }
11062 :
11063 GIC 71 : printfPQExpBuffer(query,
11064 : "EXECUTE dumpBaseType('%u')",
11065 71 : tyinfo->dobj.catId.oid);
11066 :
11067 71 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
11068 ECB :
11069 GIC 71 : typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
11070 CBC 71 : typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
11071 71 : typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
11072 71 : typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
11073 71 : typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
11074 GIC 71 : typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
11075 71 : typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
11076 71 : typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
11077 71 : typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
11078 71 : typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
11079 71 : typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
11080 CBC 71 : typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
11081 GIC 71 : typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
11082 71 : typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
11083 CBC 71 : typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
11084 GIC 71 : typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
11085 71 : typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
11086 CBC 71 : typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
11087 GIC 71 : typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
11088 71 : typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
11089 CBC 71 : typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
11090 71 : typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
11091 GIC 71 : if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
11092 UIC 0 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
11093 GBC 71 : else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
11094 : {
11095 GIC 46 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
11096 CBC 46 : typdefault_is_literal = true; /* it needs quotes */
11097 : }
11098 : else
11099 GIC 25 : typdefault = NULL;
11100 :
11101 71 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11102 71 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11103 :
11104 : /*
11105 : * The reason we include CASCADE is that the circular dependency between
11106 : * the type and its I/O functions makes it impossible to drop the type any
11107 : * other way.
11108 : */
11109 71 : appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
11110 ECB :
11111 : /*
11112 : * We might already have a shell type, but setting pg_type_oid is
11113 : * harmless, and in any case we'd better set the array type OID.
11114 : */
11115 CBC 71 : if (dopt->binary_upgrade)
11116 GIC 8 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
11117 CBC 8 : tyinfo->dobj.catId.oid,
11118 : false, false);
11119 ECB :
11120 GIC 71 : appendPQExpBuffer(q,
11121 ECB : "CREATE TYPE %s (\n"
11122 : " INTERNALLENGTH = %s",
11123 : qualtypname,
11124 GIC 71 : (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
11125 :
11126 : /* regproc result is sufficiently quoted already */
11127 71 : appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
11128 CBC 71 : appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
11129 GIC 71 : if (OidIsValid(typreceiveoid))
11130 LBC 0 : appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
11131 CBC 71 : if (OidIsValid(typsendoid))
11132 LBC 0 : appendPQExpBuffer(q, ",\n SEND = %s", typsend);
11133 GIC 71 : if (OidIsValid(typmodinoid))
11134 5 : appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
11135 CBC 71 : if (OidIsValid(typmodoutoid))
11136 GIC 5 : appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
11137 71 : if (OidIsValid(typanalyzeoid))
11138 LBC 0 : appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
11139 :
11140 GIC 71 : if (strcmp(typcollatable, "t") == 0)
11141 LBC 0 : appendPQExpBufferStr(q, ",\n COLLATABLE = true");
11142 ECB :
11143 GIC 71 : if (typdefault != NULL)
11144 : {
11145 46 : appendPQExpBufferStr(q, ",\n DEFAULT = ");
11146 CBC 46 : if (typdefault_is_literal)
11147 GIC 46 : appendStringLiteralAH(q, typdefault, fout);
11148 ECB : else
11149 LBC 0 : appendPQExpBufferStr(q, typdefault);
11150 : }
11151 ECB :
11152 GIC 71 : if (OidIsValid(typsubscriptoid))
11153 CBC 5 : appendPQExpBuffer(q, ",\n SUBSCRIPT = %s", typsubscript);
11154 :
11155 GIC 71 : if (OidIsValid(tyinfo->typelem))
11156 CBC 5 : appendPQExpBuffer(q, ",\n ELEMENT = %s",
11157 5 : getFormattedTypeName(fout, tyinfo->typelem,
11158 : zeroIsError));
11159 ECB :
11160 GIC 71 : if (strcmp(typcategory, "U") != 0)
11161 ECB : {
11162 CBC 5 : appendPQExpBufferStr(q, ",\n CATEGORY = ");
11163 5 : appendStringLiteralAH(q, typcategory, fout);
11164 : }
11165 :
11166 71 : if (strcmp(typispreferred, "t") == 0)
11167 5 : appendPQExpBufferStr(q, ",\n PREFERRED = true");
11168 EUB :
11169 GIC 71 : if (typdelim && strcmp(typdelim, ",") != 0)
11170 ECB : {
11171 LBC 0 : appendPQExpBufferStr(q, ",\n DELIMITER = ");
11172 0 : appendStringLiteralAH(q, typdelim, fout);
11173 : }
11174 ECB :
11175 GIC 71 : if (*typalign == TYPALIGN_CHAR)
11176 LBC 0 : appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
11177 CBC 71 : else if (*typalign == TYPALIGN_SHORT)
11178 UIC 0 : appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
11179 CBC 71 : else if (*typalign == TYPALIGN_INT)
11180 GIC 56 : appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
11181 CBC 15 : else if (*typalign == TYPALIGN_DOUBLE)
11182 15 : appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
11183 ECB :
11184 GIC 71 : if (*typstorage == TYPSTORAGE_PLAIN)
11185 71 : appendPQExpBufferStr(q, ",\n STORAGE = plain");
11186 UIC 0 : else if (*typstorage == TYPSTORAGE_EXTERNAL)
11187 0 : appendPQExpBufferStr(q, ",\n STORAGE = external");
11188 0 : else if (*typstorage == TYPSTORAGE_EXTENDED)
11189 0 : appendPQExpBufferStr(q, ",\n STORAGE = extended");
11190 0 : else if (*typstorage == TYPSTORAGE_MAIN)
11191 0 : appendPQExpBufferStr(q, ",\n STORAGE = main");
11192 ECB :
11193 CBC 71 : if (strcmp(typbyval, "t") == 0)
11194 51 : appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
11195 ECB :
11196 GIC 71 : appendPQExpBufferStr(q, "\n);\n");
11197 ECB :
11198 GBC 71 : if (dopt->binary_upgrade)
11199 8 : binary_upgrade_extension_member(q, &tyinfo->dobj,
11200 EUB : "TYPE", qtypname,
11201 GIC 8 : tyinfo->dobj.namespace->dobj.name);
11202 ECB :
11203 CBC 71 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11204 GIC 71 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11205 CBC 71 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11206 ECB : .namespace = tyinfo->dobj.namespace->dobj.name,
11207 : .owner = tyinfo->rolname,
11208 : .description = "TYPE",
11209 : .section = SECTION_PRE_DATA,
11210 : .createStmt = q->data,
11211 : .dropStmt = delq->data));
11212 :
11213 : /* Dump Type Comments and Security Labels */
11214 CBC 71 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11215 GIC 36 : dumpComment(fout, "TYPE", qtypname,
11216 36 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11217 36 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11218 :
11219 71 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11220 UIC 0 : dumpSecLabel(fout, "TYPE", qtypname,
11221 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11222 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11223 :
11224 GIC 71 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11225 36 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11226 ECB : qtypname, NULL,
11227 GIC 36 : tyinfo->dobj.namespace->dobj.name,
11228 CBC 36 : tyinfo->rolname, &tyinfo->dacl);
11229 ECB :
11230 CBC 71 : PQclear(res);
11231 GIC 71 : destroyPQExpBuffer(q);
11232 71 : destroyPQExpBuffer(delq);
11233 71 : destroyPQExpBuffer(query);
11234 CBC 71 : free(qtypname);
11235 71 : free(qualtypname);
11236 GIC 71 : }
11237 ECB :
11238 : /*
11239 : * dumpDomain
11240 : * writes out to fout the queries to recreate a user-defined domain
11241 : */
11242 : static void
11243 GIC 121 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
11244 ECB : {
11245 GIC 121 : DumpOptions *dopt = fout->dopt;
11246 121 : PQExpBuffer q = createPQExpBuffer();
11247 CBC 121 : PQExpBuffer delq = createPQExpBuffer();
11248 121 : PQExpBuffer query = createPQExpBuffer();
11249 : PGresult *res;
11250 ECB : int i;
11251 : char *qtypname;
11252 : char *qualtypname;
11253 : char *typnotnull;
11254 : char *typdefn;
11255 : char *typdefault;
11256 : Oid typcollation;
11257 GIC 121 : bool typdefault_is_literal = false;
11258 :
11259 121 : if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
11260 : {
11261 : /* Set up query for domain-specific details */
11262 41 : appendPQExpBufferStr(query,
11263 ECB : "PREPARE dumpDomain(pg_catalog.oid) AS\n");
11264 :
11265 CBC 41 : appendPQExpBufferStr(query, "SELECT t.typnotnull, "
11266 ECB : "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
11267 : "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
11268 : "t.typdefault, "
11269 EUB : "CASE WHEN t.typcollation <> u.typcollation "
11270 : "THEN t.typcollation ELSE 0 END AS typcollation "
11271 : "FROM pg_catalog.pg_type t "
11272 : "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
11273 ECB : "WHERE t.oid = $1");
11274 EUB :
11275 GIC 41 : ExecuteSqlStatement(fout, query->data);
11276 EUB :
11277 GBC 41 : fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
11278 : }
11279 ECB :
11280 CBC 121 : printfPQExpBuffer(query,
11281 ECB : "EXECUTE dumpDomain('%u')",
11282 CBC 121 : tyinfo->dobj.catId.oid);
11283 ECB :
11284 GIC 121 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
11285 :
11286 121 : typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
11287 121 : typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
11288 121 : if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
11289 41 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
11290 CBC 80 : else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
11291 : {
11292 LBC 0 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
11293 0 : typdefault_is_literal = true; /* it needs quotes */
11294 ECB : }
11295 : else
11296 GIC 80 : typdefault = NULL;
11297 121 : typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
11298 :
11299 121 : if (dopt->binary_upgrade)
11300 18 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
11301 18 : tyinfo->dobj.catId.oid,
11302 : true, /* force array type */
11303 : false); /* force multirange type */
11304 :
11305 121 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11306 121 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11307 :
11308 121 : appendPQExpBuffer(q,
11309 : "CREATE DOMAIN %s AS %s",
11310 : qualtypname,
11311 : typdefn);
11312 :
11313 : /* Print collation only if different from base type's collation */
11314 121 : if (OidIsValid(typcollation))
11315 : {
11316 : CollInfo *coll;
11317 :
11318 36 : coll = findCollationByOid(typcollation);
11319 36 : if (coll)
11320 36 : appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
11321 : }
11322 ECB :
11323 GIC 121 : if (typnotnull[0] == 't')
11324 CBC 10 : appendPQExpBufferStr(q, " NOT NULL");
11325 :
11326 GIC 121 : if (typdefault != NULL)
11327 ECB : {
11328 GIC 41 : appendPQExpBufferStr(q, " DEFAULT ");
11329 41 : if (typdefault_is_literal)
11330 UIC 0 : appendStringLiteralAH(q, typdefault, fout);
11331 : else
11332 GIC 41 : appendPQExpBufferStr(q, typdefault);
11333 : }
11334 :
11335 121 : PQclear(res);
11336 :
11337 : /*
11338 : * Add any CHECK constraints for the domain
11339 : */
11340 202 : for (i = 0; i < tyinfo->nDomChecks; i++)
11341 : {
11342 81 : ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
11343 ECB :
11344 CBC 81 : if (!domcheck->separate)
11345 GIC 81 : appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
11346 81 : fmtId(domcheck->dobj.name), domcheck->condef);
11347 : }
11348 EUB :
11349 GIC 121 : appendPQExpBufferStr(q, ";\n");
11350 :
11351 CBC 121 : appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
11352 :
11353 GIC 121 : if (dopt->binary_upgrade)
11354 CBC 18 : binary_upgrade_extension_member(q, &tyinfo->dobj,
11355 : "DOMAIN", qtypname,
11356 18 : tyinfo->dobj.namespace->dobj.name);
11357 :
11358 GIC 121 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11359 CBC 121 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11360 GIC 121 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11361 ECB : .namespace = tyinfo->dobj.namespace->dobj.name,
11362 : .owner = tyinfo->rolname,
11363 : .description = "DOMAIN",
11364 : .section = SECTION_PRE_DATA,
11365 : .createStmt = q->data,
11366 : .dropStmt = delq->data));
11367 :
11368 : /* Dump Domain Comments and Security Labels */
11369 CBC 121 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11370 LBC 0 : dumpComment(fout, "DOMAIN", qtypname,
11371 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11372 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11373 ECB :
11374 CBC 121 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11375 LBC 0 : dumpSecLabel(fout, "DOMAIN", qtypname,
11376 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11377 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11378 ECB :
11379 CBC 121 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11380 36 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11381 ECB : qtypname, NULL,
11382 CBC 36 : tyinfo->dobj.namespace->dobj.name,
11383 36 : tyinfo->rolname, &tyinfo->dacl);
11384 ECB :
11385 : /* Dump any per-constraint comments */
11386 CBC 202 : for (i = 0; i < tyinfo->nDomChecks; i++)
11387 ECB : {
11388 GBC 81 : ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
11389 CBC 81 : PQExpBuffer conprefix = createPQExpBuffer();
11390 :
11391 81 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
11392 81 : fmtId(domcheck->dobj.name));
11393 :
11394 GIC 81 : if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
11395 CBC 36 : dumpComment(fout, conprefix->data, qtypname,
11396 GIC 36 : tyinfo->dobj.namespace->dobj.name,
11397 CBC 36 : tyinfo->rolname,
11398 36 : domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
11399 :
11400 GIC 81 : destroyPQExpBuffer(conprefix);
11401 : }
11402 :
11403 121 : destroyPQExpBuffer(q);
11404 121 : destroyPQExpBuffer(delq);
11405 CBC 121 : destroyPQExpBuffer(query);
11406 GIC 121 : free(qtypname);
11407 121 : free(qualtypname);
11408 121 : }
11409 :
11410 : /*
11411 ECB : * dumpCompositeType
11412 : * writes out to fout the queries to recreate a user-defined stand-alone
11413 : * composite type
11414 : */
11415 : static void
11416 CBC 123 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
11417 : {
11418 GIC 123 : DumpOptions *dopt = fout->dopt;
11419 123 : PQExpBuffer q = createPQExpBuffer();
11420 CBC 123 : PQExpBuffer dropped = createPQExpBuffer();
11421 GIC 123 : PQExpBuffer delq = createPQExpBuffer();
11422 123 : PQExpBuffer query = createPQExpBuffer();
11423 ECB : PGresult *res;
11424 : char *qtypname;
11425 : char *qualtypname;
11426 EUB : int ntups;
11427 ECB : int i_attname;
11428 EUB : int i_atttypdefn;
11429 ECB : int i_attlen;
11430 : int i_attalign;
11431 : int i_attisdropped;
11432 : int i_attcollation;
11433 : int i;
11434 EUB : int actual_atts;
11435 :
11436 CBC 123 : if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
11437 EUB : {
11438 : /*
11439 ECB : * Set up query for type-specific details.
11440 : *
11441 : * Since we only want to dump COLLATE clauses for attributes whose
11442 : * collation is different from their type's default, we use a CASE
11443 : * here to suppress uninteresting attcollations cheaply. atttypid
11444 : * will be 0 for dropped columns; collation does not matter for those.
11445 EUB : */
11446 GIC 58 : appendPQExpBufferStr(query,
11447 : "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
11448 ECB : "SELECT a.attname, a.attnum, "
11449 : "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
11450 : "a.attlen, a.attalign, a.attisdropped, "
11451 : "CASE WHEN a.attcollation <> at.typcollation "
11452 : "THEN a.attcollation ELSE 0 END AS attcollation "
11453 : "FROM pg_catalog.pg_type ct "
11454 : "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
11455 : "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
11456 : "WHERE ct.oid = $1 "
11457 : "ORDER BY a.attnum");
11458 :
11459 CBC 58 : ExecuteSqlStatement(fout, query->data);
11460 :
11461 GIC 58 : fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
11462 ECB : }
11463 :
11464 GIC 123 : printfPQExpBuffer(query,
11465 ECB : "EXECUTE dumpCompositeType('%u')",
11466 GIC 123 : tyinfo->dobj.catId.oid);
11467 EUB :
11468 GBC 123 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11469 :
11470 GIC 123 : ntups = PQntuples(res);
11471 ECB :
11472 GBC 123 : i_attname = PQfnumber(res, "attname");
11473 CBC 123 : i_atttypdefn = PQfnumber(res, "atttypdefn");
11474 GBC 123 : i_attlen = PQfnumber(res, "attlen");
11475 CBC 123 : i_attalign = PQfnumber(res, "attalign");
11476 123 : i_attisdropped = PQfnumber(res, "attisdropped");
11477 123 : i_attcollation = PQfnumber(res, "attcollation");
11478 ECB :
11479 GIC 123 : if (dopt->binary_upgrade)
11480 ECB : {
11481 CBC 16 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
11482 GBC 16 : tyinfo->dobj.catId.oid,
11483 EUB : false, false);
11484 GBC 16 : binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
11485 EUB : }
11486 :
11487 GBC 123 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11488 GIC 123 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11489 ECB :
11490 CBC 123 : appendPQExpBuffer(q, "CREATE TYPE %s AS (",
11491 : qualtypname);
11492 ECB :
11493 GIC 123 : actual_atts = 0;
11494 CBC 382 : for (i = 0; i < ntups; i++)
11495 ECB : {
11496 : char *attname;
11497 : char *atttypdefn;
11498 : char *attlen;
11499 : char *attalign;
11500 : bool attisdropped;
11501 : Oid attcollation;
11502 :
11503 GIC 259 : attname = PQgetvalue(res, i, i_attname);
11504 259 : atttypdefn = PQgetvalue(res, i, i_atttypdefn);
11505 259 : attlen = PQgetvalue(res, i, i_attlen);
11506 259 : attalign = PQgetvalue(res, i, i_attalign);
11507 259 : attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
11508 259 : attcollation = atooid(PQgetvalue(res, i, i_attcollation));
11509 :
11510 CBC 259 : if (attisdropped && !dopt->binary_upgrade)
11511 8 : continue;
11512 ECB :
11513 : /* Format properly if not first attr */
11514 GIC 251 : if (actual_atts++ > 0)
11515 CBC 128 : appendPQExpBufferChar(q, ',');
11516 GBC 251 : appendPQExpBufferStr(q, "\n\t");
11517 EUB :
11518 GBC 251 : if (!attisdropped)
11519 : {
11520 CBC 249 : appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
11521 ECB :
11522 : /* Add collation if not default for the column type */
11523 CBC 249 : if (OidIsValid(attcollation))
11524 ECB : {
11525 : CollInfo *coll;
11526 :
11527 LBC 0 : coll = findCollationByOid(attcollation);
11528 0 : if (coll)
11529 0 : appendPQExpBuffer(q, " COLLATE %s",
11530 0 : fmtQualifiedDumpable(coll));
11531 ECB : }
11532 : }
11533 : else
11534 : {
11535 : /*
11536 : * This is a dropped attribute and we're in binary_upgrade mode.
11537 : * Insert a placeholder for it in the CREATE TYPE command, and set
11538 : * length and alignment with direct UPDATE to the catalogs
11539 : * afterwards. See similar code in dumpTableSchema().
11540 : */
11541 CBC 2 : appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
11542 ECB :
11543 : /* stash separately for insertion after the CREATE TYPE */
11544 CBC 2 : appendPQExpBufferStr(dropped,
11545 : "\n-- For binary upgrade, recreate dropped column.\n");
11546 GIC 2 : appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
11547 : "SET attlen = %s, "
11548 : "attalign = '%s', attbyval = false\n"
11549 : "WHERE attname = ", attlen, attalign);
11550 2 : appendStringLiteralAH(dropped, attname, fout);
11551 2 : appendPQExpBufferStr(dropped, "\n AND attrelid = ");
11552 2 : appendStringLiteralAH(dropped, qualtypname, fout);
11553 CBC 2 : appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
11554 :
11555 2 : appendPQExpBuffer(dropped, "ALTER TYPE %s ",
11556 : qualtypname);
11557 GIC 2 : appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
11558 ECB : fmtId(attname));
11559 : }
11560 : }
11561 CBC 123 : appendPQExpBufferStr(q, "\n);\n");
11562 GIC 123 : appendPQExpBufferStr(q, dropped->data);
11563 :
11564 123 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11565 :
11566 123 : if (dopt->binary_upgrade)
11567 16 : binary_upgrade_extension_member(q, &tyinfo->dobj,
11568 : "TYPE", qtypname,
11569 16 : tyinfo->dobj.namespace->dobj.name);
11570 :
11571 CBC 123 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11572 GIC 107 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11573 CBC 107 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11574 : .namespace = tyinfo->dobj.namespace->dobj.name,
11575 : .owner = tyinfo->rolname,
11576 ECB : .description = "TYPE",
11577 : .section = SECTION_PRE_DATA,
11578 : .createStmt = q->data,
11579 : .dropStmt = delq->data));
11580 :
11581 :
11582 : /* Dump Type Comments and Security Labels */
11583 CBC 123 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11584 36 : dumpComment(fout, "TYPE", qtypname,
11585 36 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11586 36 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11587 :
11588 GBC 123 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11589 UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
11590 UIC 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11591 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11592 ECB :
11593 CBC 123 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11594 GIC 17 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11595 ECB : qtypname, NULL,
11596 CBC 17 : tyinfo->dobj.namespace->dobj.name,
11597 17 : tyinfo->rolname, &tyinfo->dacl);
11598 :
11599 : /* Dump any per-column comments */
11600 GIC 123 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11601 CBC 36 : dumpCompositeTypeColComments(fout, tyinfo, res);
11602 ECB :
11603 GIC 123 : PQclear(res);
11604 CBC 123 : destroyPQExpBuffer(q);
11605 GIC 123 : destroyPQExpBuffer(dropped);
11606 123 : destroyPQExpBuffer(delq);
11607 123 : destroyPQExpBuffer(query);
11608 123 : free(qtypname);
11609 123 : free(qualtypname);
11610 CBC 123 : }
11611 :
11612 : /*
11613 : * dumpCompositeTypeColComments
11614 ECB : * writes out to fout the queries to recreate comments on the columns of
11615 : * a user-defined stand-alone composite type.
11616 : *
11617 : * The caller has already made a query to collect the names and attnums
11618 : * of the type's columns, so we just pass that result into here rather
11619 : * than reading them again.
11620 : */
11621 : static void
11622 CBC 36 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
11623 : PGresult *res)
11624 ECB : {
11625 : CommentItem *comments;
11626 EUB : int ncomments;
11627 : PQExpBuffer query;
11628 ECB : PQExpBuffer target;
11629 : int i;
11630 : int ntups;
11631 : int i_attname;
11632 : int i_attnum;
11633 : int i_attisdropped;
11634 :
11635 : /* do nothing, if --no-comments is supplied */
11636 CBC 36 : if (fout->dopt->no_comments)
11637 UIC 0 : return;
11638 ECB :
11639 : /* Search for comments associated with type's pg_class OID */
11640 CBC 36 : ncomments = findComments(RelationRelationId, tyinfo->typrelid,
11641 ECB : &comments);
11642 :
11643 : /* If no comments exist, we're done */
11644 GIC 36 : if (ncomments <= 0)
11645 LBC 0 : return;
11646 :
11647 ECB : /* Build COMMENT ON statements */
11648 GIC 36 : query = createPQExpBuffer();
11649 CBC 36 : target = createPQExpBuffer();
11650 ECB :
11651 GIC 36 : ntups = PQntuples(res);
11652 CBC 36 : i_attnum = PQfnumber(res, "attnum");
11653 GIC 36 : i_attname = PQfnumber(res, "attname");
11654 CBC 36 : i_attisdropped = PQfnumber(res, "attisdropped");
11655 72 : while (ncomments > 0)
11656 ECB : {
11657 : const char *attname;
11658 :
11659 GIC 36 : attname = NULL;
11660 36 : for (i = 0; i < ntups; i++)
11661 : {
11662 36 : if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
11663 36 : PQgetvalue(res, i, i_attisdropped)[0] != 't')
11664 : {
11665 CBC 36 : attname = PQgetvalue(res, i, i_attname);
11666 GBC 36 : break;
11667 EUB : }
11668 : }
11669 GIC 36 : if (attname) /* just in case we don't find it */
11670 ECB : {
11671 GBC 36 : const char *descr = comments->descr;
11672 EUB :
11673 GBC 36 : resetPQExpBuffer(target);
11674 GIC 36 : appendPQExpBuffer(target, "COLUMN %s.",
11675 CBC 36 : fmtId(tyinfo->dobj.name));
11676 36 : appendPQExpBufferStr(target, fmtId(attname));
11677 :
11678 36 : resetPQExpBuffer(query);
11679 36 : appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11680 GIC 36 : fmtQualifiedDumpable(tyinfo));
11681 36 : appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11682 CBC 36 : appendStringLiteralAH(query, descr, fout);
11683 GIC 36 : appendPQExpBufferStr(query, ";\n");
11684 ECB :
11685 CBC 36 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
11686 GIC 36 : ARCHIVE_OPTS(.tag = target->data,
11687 ECB : .namespace = tyinfo->dobj.namespace->dobj.name,
11688 : .owner = tyinfo->rolname,
11689 : .description = "COMMENT",
11690 : .section = SECTION_NONE,
11691 : .createStmt = query->data,
11692 : .deps = &(tyinfo->dobj.dumpId),
11693 : .nDeps = 1));
11694 : }
11695 :
11696 CBC 36 : comments++;
11697 GIC 36 : ncomments--;
11698 : }
11699 ECB :
11700 CBC 36 : destroyPQExpBuffer(query);
11701 36 : destroyPQExpBuffer(target);
11702 ECB : }
11703 :
11704 : /*
11705 : * dumpShellType
11706 : * writes out to fout the queries to create a shell type
11707 : *
11708 : * We dump a shell definition in advance of the I/O functions for the type.
11709 : */
11710 : static void
11711 GIC 74 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
11712 ECB : {
11713 GIC 74 : DumpOptions *dopt = fout->dopt;
11714 ECB : PQExpBuffer q;
11715 :
11716 : /* Do nothing in data-only dump */
11717 CBC 74 : if (dopt->dataOnly)
11718 3 : return;
11719 :
11720 GIC 71 : q = createPQExpBuffer();
11721 :
11722 : /*
11723 : * Note the lack of a DROP command for the shell type; any required DROP
11724 : * is driven off the base type entry, instead. This interacts with
11725 : * _printTocEntry()'s use of the presence of a DROP command to decide
11726 : * whether an entry needs an ALTER OWNER command. We don't want to alter
11727 : * the shell type's owner immediately on creation; that should happen only
11728 : * after it's filled in, otherwise the backend complains.
11729 : */
11730 :
11731 71 : if (dopt->binary_upgrade)
11732 CBC 8 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
11733 GIC 8 : stinfo->baseType->dobj.catId.oid,
11734 : false, false);
11735 :
11736 71 : appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11737 71 : fmtQualifiedDumpable(stinfo));
11738 :
11739 71 : if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11740 71 : ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11741 71 : ARCHIVE_OPTS(.tag = stinfo->dobj.name,
11742 ECB : .namespace = stinfo->dobj.namespace->dobj.name,
11743 : .owner = stinfo->baseType->rolname,
11744 : .description = "SHELL TYPE",
11745 : .section = SECTION_PRE_DATA,
11746 : .createStmt = q->data));
11747 :
11748 GIC 71 : destroyPQExpBuffer(q);
11749 : }
11750 :
11751 : /*
11752 : * dumpProcLang
11753 : * writes out to fout the queries to recreate a user-defined
11754 : * procedural language
11755 ECB : */
11756 : static void
11757 CBC 83 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
11758 : {
11759 GIC 83 : DumpOptions *dopt = fout->dopt;
11760 ECB : PQExpBuffer defqry;
11761 : PQExpBuffer delqry;
11762 : bool useParams;
11763 : char *qlanname;
11764 : FuncInfo *funcInfo;
11765 GIC 83 : FuncInfo *inlineInfo = NULL;
11766 CBC 83 : FuncInfo *validatorInfo = NULL;
11767 :
11768 ECB : /* Do nothing in data-only dump */
11769 CBC 83 : if (dopt->dataOnly)
11770 7 : return;
11771 ECB :
11772 : /*
11773 : * Try to find the support function(s). It is not an error if we don't
11774 : * find them --- if the functions are in the pg_catalog schema, as is
11775 : * standard in 8.1 and up, then we won't have loaded them. (In this case
11776 : * we will emit a parameterless CREATE LANGUAGE command, which will
11777 : * require PL template knowledge in the backend to reload.)
11778 : */
11779 :
11780 CBC 76 : funcInfo = findFuncByOid(plang->lanplcallfoid);
11781 GIC 76 : if (funcInfo != NULL && !funcInfo->dobj.dump)
11782 2 : funcInfo = NULL; /* treat not-dumped same as not-found */
11783 ECB :
11784 CBC 76 : if (OidIsValid(plang->laninline))
11785 : {
11786 41 : inlineInfo = findFuncByOid(plang->laninline);
11787 GIC 41 : if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11788 1 : inlineInfo = NULL;
11789 ECB : }
11790 :
11791 GIC 76 : if (OidIsValid(plang->lanvalidator))
11792 : {
11793 41 : validatorInfo = findFuncByOid(plang->lanvalidator);
11794 41 : if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11795 1 : validatorInfo = NULL;
11796 : }
11797 :
11798 : /*
11799 ECB : * If the functions are dumpable then emit a complete CREATE LANGUAGE with
11800 : * parameters. Otherwise, we'll write a parameterless command, which will
11801 : * be interpreted as CREATE EXTENSION.
11802 : */
11803 CBC 34 : useParams = (funcInfo != NULL &&
11804 144 : (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11805 GIC 34 : (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11806 ECB :
11807 CBC 76 : defqry = createPQExpBuffer();
11808 GIC 76 : delqry = createPQExpBuffer();
11809 :
11810 CBC 76 : qlanname = pg_strdup(fmtId(plang->dobj.name));
11811 ECB :
11812 CBC 76 : appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11813 : qlanname);
11814 ECB :
11815 GIC 76 : if (useParams)
11816 ECB : {
11817 GIC 34 : appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11818 34 : plang->lanpltrusted ? "TRUSTED " : "",
11819 ECB : qlanname);
11820 GIC 34 : appendPQExpBuffer(defqry, " HANDLER %s",
11821 34 : fmtQualifiedDumpable(funcInfo));
11822 34 : if (OidIsValid(plang->laninline))
11823 UBC 0 : appendPQExpBuffer(defqry, " INLINE %s",
11824 0 : fmtQualifiedDumpable(inlineInfo));
11825 GBC 34 : if (OidIsValid(plang->lanvalidator))
11826 UBC 0 : appendPQExpBuffer(defqry, " VALIDATOR %s",
11827 UIC 0 : fmtQualifiedDumpable(validatorInfo));
11828 : }
11829 : else
11830 : {
11831 : /*
11832 : * If not dumping parameters, then use CREATE OR REPLACE so that the
11833 : * command will not fail if the language is preinstalled in the target
11834 : * database.
11835 : *
11836 : * Modern servers will interpret this as CREATE EXTENSION IF NOT
11837 ECB : * EXISTS; perhaps we should emit that instead? But it might just add
11838 : * confusion.
11839 : */
11840 CBC 42 : appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11841 : qlanname);
11842 ECB : }
11843 GIC 76 : appendPQExpBufferStr(defqry, ";\n");
11844 :
11845 76 : if (dopt->binary_upgrade)
11846 CBC 2 : binary_upgrade_extension_member(defqry, &plang->dobj,
11847 ECB : "LANGUAGE", qlanname, NULL);
11848 :
11849 CBC 76 : if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11850 GIC 35 : ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11851 CBC 35 : ARCHIVE_OPTS(.tag = plang->dobj.name,
11852 : .owner = plang->lanowner,
11853 ECB : .description = "PROCEDURAL LANGUAGE",
11854 : .section = SECTION_PRE_DATA,
11855 : .createStmt = defqry->data,
11856 : .dropStmt = delqry->data,
11857 : ));
11858 :
11859 : /* Dump Proc Lang Comments and Security Labels */
11860 CBC 76 : if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11861 UIC 0 : dumpComment(fout, "LANGUAGE", qlanname,
11862 LBC 0 : NULL, plang->lanowner,
11863 0 : plang->dobj.catId, 0, plang->dobj.dumpId);
11864 :
11865 CBC 76 : if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11866 UIC 0 : dumpSecLabel(fout, "LANGUAGE", qlanname,
11867 LBC 0 : NULL, plang->lanowner,
11868 0 : plang->dobj.catId, 0, plang->dobj.dumpId);
11869 ECB :
11870 GIC 76 : if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11871 41 : dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
11872 : qlanname, NULL, NULL,
11873 41 : plang->lanowner, &plang->dacl);
11874 :
11875 76 : free(qlanname);
11876 :
11877 76 : destroyPQExpBuffer(defqry);
11878 76 : destroyPQExpBuffer(delqry);
11879 ECB : }
11880 :
11881 : /*
11882 : * format_function_arguments: generate function name and argument list
11883 : *
11884 : * This is used when we can rely on pg_get_function_arguments to format
11885 EUB : * the argument list. Note, however, that pg_get_function_arguments
11886 : * does not special-case zero-argument aggregates.
11887 : */
11888 : static char *
11889 CBC 3948 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
11890 ECB : {
11891 : PQExpBufferData fn;
11892 :
11893 CBC 3948 : initPQExpBuffer(&fn);
11894 GIC 3948 : appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11895 3948 : if (is_agg && finfo->nargs == 0)
11896 CBC 80 : appendPQExpBufferStr(&fn, "(*)");
11897 ECB : else
11898 GIC 3868 : appendPQExpBuffer(&fn, "(%s)", funcargs);
11899 CBC 3948 : return fn.data;
11900 ECB : }
11901 :
11902 : /*
11903 : * format_function_signature: generate function name and argument list
11904 : *
11905 : * Only a minimal list of input argument types is generated; this is
11906 : * sufficient to reference the function, but not to define it.
11907 : *
11908 : * If honor_quotes is false then the function name is never quoted.
11909 : * This is appropriate for use in TOC tags, but not in SQL commands.
11910 : */
11911 : static char *
11912 GIC 2094 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
11913 : {
11914 : PQExpBufferData fn;
11915 : int j;
11916 :
11917 2094 : initPQExpBuffer(&fn);
11918 CBC 2094 : if (honor_quotes)
11919 GIC 408 : appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11920 : else
11921 1686 : appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11922 3890 : for (j = 0; j < finfo->nargs; j++)
11923 : {
11924 1796 : if (j > 0)
11925 415 : appendPQExpBufferStr(&fn, ", ");
11926 :
11927 1796 : appendPQExpBufferStr(&fn,
11928 1796 : getFormattedTypeName(fout, finfo->argtypes[j],
11929 : zeroIsError));
11930 : }
11931 2094 : appendPQExpBufferChar(&fn, ')');
11932 CBC 2094 : return fn.data;
11933 EUB : }
11934 :
11935 :
11936 ECB : /*
11937 : * dumpFunc:
11938 : * dump out one function
11939 : */
11940 : static void
11941 GBC 1715 : dumpFunc(Archive *fout, const FuncInfo *finfo)
11942 : {
11943 GIC 1715 : DumpOptions *dopt = fout->dopt;
11944 ECB : PQExpBuffer query;
11945 : PQExpBuffer q;
11946 : PQExpBuffer delqry;
11947 : PQExpBuffer asPart;
11948 : PGresult *res;
11949 : char *funcsig; /* identity signature */
11950 CBC 1715 : char *funcfullsig = NULL; /* full signature */
11951 ECB : char *funcsig_tag;
11952 : char *qual_funcsig;
11953 : char *proretset;
11954 : char *prosrc;
11955 : char *probin;
11956 : char *prosqlbody;
11957 : char *funcargs;
11958 : char *funciargs;
11959 : char *funcresult;
11960 : char *protrftypes;
11961 : char *prokind;
11962 : char *provolatile;
11963 : char *proisstrict;
11964 : char *prosecdef;
11965 : char *proleakproof;
11966 : char *proconfig;
11967 : char *procost;
11968 : char *prorows;
11969 : char *prosupport;
11970 : char *proparallel;
11971 : char *lanname;
11972 CBC 1715 : char **configitems = NULL;
11973 GIC 1715 : int nconfigitems = 0;
11974 ECB : const char *keyword;
11975 :
11976 : /* Do nothing in data-only dump */
11977 CBC 1715 : if (dopt->dataOnly)
11978 29 : return;
11979 :
11980 1686 : query = createPQExpBuffer();
11981 1686 : q = createPQExpBuffer();
11982 GIC 1686 : delqry = createPQExpBuffer();
11983 1686 : asPart = createPQExpBuffer();
11984 :
11985 1686 : if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
11986 : {
11987 : /* Set up query for function-specific details */
11988 59 : appendPQExpBufferStr(query,
11989 : "PREPARE dumpFunc(pg_catalog.oid) AS\n");
11990 :
11991 CBC 59 : appendPQExpBufferStr(query,
11992 ECB : "SELECT\n"
11993 : "proretset,\n"
11994 : "prosrc,\n"
11995 : "probin,\n"
11996 : "provolatile,\n"
11997 : "proisstrict,\n"
11998 : "prosecdef,\n"
11999 : "lanname,\n"
12000 : "proconfig,\n"
12001 : "procost,\n"
12002 : "prorows,\n"
12003 : "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
12004 : "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
12005 : "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
12006 : "proleakproof,\n");
12007 :
12008 CBC 59 : if (fout->remoteVersion >= 90500)
12009 GIC 59 : appendPQExpBufferStr(query,
12010 : "array_to_string(protrftypes, ' ') AS protrftypes,\n");
12011 : else
12012 LBC 0 : appendPQExpBufferStr(query,
12013 ECB : "NULL AS protrftypes,\n");
12014 :
12015 CBC 59 : if (fout->remoteVersion >= 90600)
12016 GIC 59 : appendPQExpBufferStr(query,
12017 : "proparallel,\n");
12018 : else
12019 UIC 0 : appendPQExpBufferStr(query,
12020 : "'u' AS proparallel,\n");
12021 :
12022 GIC 59 : if (fout->remoteVersion >= 110000)
12023 59 : appendPQExpBufferStr(query,
12024 : "prokind,\n");
12025 : else
12026 LBC 0 : appendPQExpBufferStr(query,
12027 ECB : "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
12028 :
12029 GIC 59 : if (fout->remoteVersion >= 120000)
12030 59 : appendPQExpBufferStr(query,
12031 ECB : "prosupport,\n");
12032 : else
12033 UIC 0 : appendPQExpBufferStr(query,
12034 ECB : "'-' AS prosupport,\n");
12035 :
12036 CBC 59 : if (fout->remoteVersion >= 140000)
12037 GIC 59 : appendPQExpBufferStr(query,
12038 : "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
12039 : else
12040 UIC 0 : appendPQExpBufferStr(query,
12041 : "NULL AS prosqlbody\n");
12042 :
12043 CBC 59 : appendPQExpBufferStr(query,
12044 : "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
12045 : "WHERE p.oid = $1 "
12046 : "AND l.oid = p.prolang");
12047 :
12048 GIC 59 : ExecuteSqlStatement(fout, query->data);
12049 :
12050 59 : fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
12051 : }
12052 ECB :
12053 GIC 1686 : printfPQExpBuffer(query,
12054 ECB : "EXECUTE dumpFunc('%u')",
12055 GIC 1686 : finfo->dobj.catId.oid);
12056 :
12057 1686 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
12058 :
12059 1686 : proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
12060 CBC 1686 : if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
12061 ECB : {
12062 GIC 1671 : prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
12063 1671 : probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
12064 CBC 1671 : prosqlbody = NULL;
12065 ECB : }
12066 : else
12067 : {
12068 GIC 15 : prosrc = NULL;
12069 15 : probin = NULL;
12070 15 : prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
12071 : }
12072 1686 : funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
12073 1686 : funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
12074 1686 : funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
12075 CBC 1686 : protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
12076 1686 : prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
12077 1686 : provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
12078 GIC 1686 : proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
12079 CBC 1686 : prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
12080 GIC 1686 : proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
12081 CBC 1686 : proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
12082 1686 : procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
12083 1686 : prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
12084 GIC 1686 : prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
12085 1686 : proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
12086 CBC 1686 : lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
12087 :
12088 ECB : /*
12089 : * See backend/commands/functioncmds.c for details of how the 'AS' clause
12090 : * is used.
12091 : */
12092 GIC 1686 : if (prosqlbody)
12093 : {
12094 15 : appendPQExpBufferStr(asPart, prosqlbody);
12095 : }
12096 1671 : else if (probin[0] != '\0')
12097 : {
12098 CBC 151 : appendPQExpBufferStr(asPart, "AS ");
12099 151 : appendStringLiteralAH(asPart, probin, fout);
12100 151 : if (prosrc[0] != '\0')
12101 : {
12102 151 : appendPQExpBufferStr(asPart, ", ");
12103 ECB :
12104 : /*
12105 : * where we have bin, use dollar quoting if allowed and src
12106 : * contains quote or backslash; else use regular quoting.
12107 : */
12108 GIC 151 : if (dopt->disable_dollar_quoting ||
12109 151 : (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
12110 CBC 151 : appendStringLiteralAH(asPart, prosrc, fout);
12111 : else
12112 LBC 0 : appendStringLiteralDQ(asPart, prosrc, NULL);
12113 ECB : }
12114 : }
12115 : else
12116 : {
12117 CBC 1520 : appendPQExpBufferStr(asPart, "AS ");
12118 EUB : /* with no bin, dollar quote src unconditionally if allowed */
12119 GBC 1520 : if (dopt->disable_dollar_quoting)
12120 LBC 0 : appendStringLiteralAH(asPart, prosrc, fout);
12121 EUB : else
12122 GBC 1520 : appendStringLiteralDQ(asPart, prosrc, NULL);
12123 : }
12124 :
12125 GIC 1686 : if (*proconfig)
12126 : {
12127 15 : if (!parsePGArray(proconfig, &configitems, &nconfigitems))
12128 UIC 0 : pg_fatal("could not parse %s array", "proconfig");
12129 : }
12130 : else
12131 : {
12132 GIC 1671 : configitems = NULL;
12133 1671 : nconfigitems = 0;
12134 : }
12135 ECB :
12136 GIC 1686 : funcfullsig = format_function_arguments(finfo, funcargs, false);
12137 1686 : funcsig = format_function_arguments(finfo, funciargs, false);
12138 ECB :
12139 GIC 1686 : funcsig_tag = format_function_signature(fout, finfo, false);
12140 ECB :
12141 CBC 1686 : qual_funcsig = psprintf("%s.%s",
12142 GIC 1686 : fmtId(finfo->dobj.namespace->dobj.name),
12143 : funcsig);
12144 ECB :
12145 CBC 1686 : if (prokind[0] == PROKIND_PROCEDURE)
12146 81 : keyword = "PROCEDURE";
12147 : else
12148 GIC 1605 : keyword = "FUNCTION"; /* works for window functions too */
12149 :
12150 1686 : appendPQExpBuffer(delqry, "DROP %s %s;\n",
12151 : keyword, qual_funcsig);
12152 :
12153 3372 : appendPQExpBuffer(q, "CREATE %s %s.%s",
12154 : keyword,
12155 CBC 1686 : fmtId(finfo->dobj.namespace->dobj.name),
12156 EUB : funcfullsig ? funcfullsig :
12157 : funcsig);
12158 :
12159 GIC 1686 : if (prokind[0] == PROKIND_PROCEDURE)
12160 ECB : /* no result type to output */ ;
12161 GBC 1605 : else if (funcresult)
12162 1605 : appendPQExpBuffer(q, " RETURNS %s", funcresult);
12163 EUB : else
12164 UIC 0 : appendPQExpBuffer(q, " RETURNS %s%s",
12165 LBC 0 : (proretset[0] == 't') ? "SETOF " : "",
12166 0 : getFormattedTypeName(fout, finfo->prorettype,
12167 : zeroIsError));
12168 ECB :
12169 GIC 1686 : appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
12170 ECB :
12171 GIC 1686 : if (*protrftypes)
12172 ECB : {
12173 LBC 0 : Oid *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
12174 : int i;
12175 :
12176 UIC 0 : appendPQExpBufferStr(q, " TRANSFORM ");
12177 0 : parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
12178 0 : for (i = 0; typeids[i]; i++)
12179 : {
12180 0 : if (i != 0)
12181 0 : appendPQExpBufferStr(q, ", ");
12182 0 : appendPQExpBuffer(q, "FOR TYPE %s",
12183 0 : getFormattedTypeName(fout, typeids[i], zeroAsNone));
12184 ECB : }
12185 : }
12186 :
12187 GIC 1686 : if (prokind[0] == PROKIND_WINDOW)
12188 CBC 5 : appendPQExpBufferStr(q, " WINDOW");
12189 ECB :
12190 CBC 1686 : if (provolatile[0] != PROVOLATILE_VOLATILE)
12191 ECB : {
12192 GIC 352 : if (provolatile[0] == PROVOLATILE_IMMUTABLE)
12193 CBC 332 : appendPQExpBufferStr(q, " IMMUTABLE");
12194 20 : else if (provolatile[0] == PROVOLATILE_STABLE)
12195 GIC 20 : appendPQExpBufferStr(q, " STABLE");
12196 UIC 0 : else if (provolatile[0] != PROVOLATILE_VOLATILE)
12197 0 : pg_fatal("unrecognized provolatile value for function \"%s\"",
12198 : finfo->dobj.name);
12199 : }
12200 :
12201 GIC 1686 : if (proisstrict[0] == 't')
12202 357 : appendPQExpBufferStr(q, " STRICT");
12203 :
12204 1686 : if (prosecdef[0] == 't')
12205 UIC 0 : appendPQExpBufferStr(q, " SECURITY DEFINER");
12206 :
12207 CBC 1686 : if (proleakproof[0] == 't')
12208 GIC 10 : appendPQExpBufferStr(q, " LEAKPROOF");
12209 :
12210 : /*
12211 : * COST and ROWS are emitted only if present and not default, so as not to
12212 ECB : * break backwards-compatibility of the dump without need. Keep this code
12213 : * in sync with the defaults in functioncmds.c.
12214 : */
12215 GIC 1686 : if (strcmp(procost, "0") != 0)
12216 ECB : {
12217 CBC 1686 : if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
12218 : {
12219 ECB : /* default cost is 1 */
12220 CBC 388 : if (strcmp(procost, "1") != 0)
12221 UIC 0 : appendPQExpBuffer(q, " COST %s", procost);
12222 ECB : }
12223 : else
12224 : {
12225 : /* default cost is 100 */
12226 CBC 1298 : if (strcmp(procost, "100") != 0)
12227 5 : appendPQExpBuffer(q, " COST %s", procost);
12228 : }
12229 : }
12230 GIC 1686 : if (proretset[0] == 't' &&
12231 155 : strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
12232 UIC 0 : appendPQExpBuffer(q, " ROWS %s", prorows);
12233 :
12234 GIC 1686 : if (strcmp(prosupport, "-") != 0)
12235 : {
12236 ECB : /* We rely on regprocout to provide quoting and qualification */
12237 GIC 46 : appendPQExpBuffer(q, " SUPPORT %s", prosupport);
12238 ECB : }
12239 :
12240 GIC 1686 : if (proparallel[0] != PROPARALLEL_UNSAFE)
12241 : {
12242 120 : if (proparallel[0] == PROPARALLEL_SAFE)
12243 115 : appendPQExpBufferStr(q, " PARALLEL SAFE");
12244 5 : else if (proparallel[0] == PROPARALLEL_RESTRICTED)
12245 CBC 5 : appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
12246 UIC 0 : else if (proparallel[0] != PROPARALLEL_UNSAFE)
12247 0 : pg_fatal("unrecognized proparallel value for function \"%s\"",
12248 : finfo->dobj.name);
12249 : }
12250 :
12251 GNC 1721 : for (int i = 0; i < nconfigitems; i++)
12252 : {
12253 : /* we feel free to scribble on configitems[] here */
12254 GIC 35 : char *configitem = configitems[i];
12255 : char *pos;
12256 :
12257 35 : pos = strchr(configitem, '=');
12258 35 : if (pos == NULL)
12259 UIC 0 : continue;
12260 GIC 35 : *pos++ = '\0';
12261 35 : appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
12262 :
12263 : /*
12264 : * Variables that are marked GUC_LIST_QUOTE were already fully quoted
12265 : * by flatten_set_variable_args() before they were put into the
12266 : * proconfig array. However, because the quoting rules used there
12267 ECB : * aren't exactly like SQL's, we have to break the list value apart
12268 : * and then quote the elements as string literals. (The elements may
12269 : * be double-quoted as-is, but we can't just feed them to the SQL
12270 : * parser; it would do the wrong thing with elements that are
12271 : * zero-length or longer than NAMEDATALEN.)
12272 : *
12273 : * Variables that are not so marked should just be emitted as simple
12274 : * string literals. If the variable is not known to
12275 : * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
12276 : * to use GUC_LIST_QUOTE for extension variables.
12277 : */
12278 CBC 35 : if (variable_is_guc_list_quote(configitem))
12279 : {
12280 ECB : char **namelist;
12281 : char **nameptr;
12282 :
12283 : /* Parse string into list of identifiers */
12284 : /* this shouldn't fail really */
12285 GIC 10 : if (SplitGUCList(pos, ',', &namelist))
12286 ECB : {
12287 GIC 35 : for (nameptr = namelist; *nameptr; nameptr++)
12288 : {
12289 25 : if (nameptr != namelist)
12290 15 : appendPQExpBufferStr(q, ", ");
12291 25 : appendStringLiteralAH(q, *nameptr, fout);
12292 : }
12293 : }
12294 10 : pg_free(namelist);
12295 : }
12296 : else
12297 25 : appendStringLiteralAH(q, pos, fout);
12298 : }
12299 :
12300 1686 : appendPQExpBuffer(q, "\n %s;\n", asPart->data);
12301 :
12302 1686 : append_depends_on_extension(fout, q, &finfo->dobj,
12303 ECB : "pg_catalog.pg_proc", keyword,
12304 : qual_funcsig);
12305 :
12306 GIC 1686 : if (dopt->binary_upgrade)
12307 GBC 277 : binary_upgrade_extension_member(q, &finfo->dobj,
12308 : keyword, funcsig,
12309 GIC 277 : finfo->dobj.namespace->dobj.name);
12310 ECB :
12311 CBC 1686 : if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12312 GIC 1584 : ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
12313 1584 : ARCHIVE_OPTS(.tag = funcsig_tag,
12314 EUB : .namespace = finfo->dobj.namespace->dobj.name,
12315 : .owner = finfo->rolname,
12316 : .description = keyword,
12317 ECB : .section = SECTION_PRE_DATA,
12318 : .createStmt = q->data,
12319 : .dropStmt = delqry->data));
12320 :
12321 EUB : /* Dump Function Comments and Security Labels */
12322 GIC 1686 : if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12323 UIC 0 : dumpComment(fout, keyword, funcsig,
12324 LBC 0 : finfo->dobj.namespace->dobj.name, finfo->rolname,
12325 0 : finfo->dobj.catId, 0, finfo->dobj.dumpId);
12326 :
12327 GIC 1686 : if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12328 UBC 0 : dumpSecLabel(fout, keyword, funcsig,
12329 UIC 0 : finfo->dobj.namespace->dobj.name, finfo->rolname,
12330 0 : finfo->dobj.catId, 0, finfo->dobj.dumpId);
12331 ECB :
12332 CBC 1686 : if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
12333 GIC 104 : dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
12334 : funcsig, NULL,
12335 GBC 104 : finfo->dobj.namespace->dobj.name,
12336 GIC 104 : finfo->rolname, &finfo->dacl);
12337 :
12338 CBC 1686 : PQclear(res);
12339 :
12340 GIC 1686 : destroyPQExpBuffer(query);
12341 1686 : destroyPQExpBuffer(q);
12342 1686 : destroyPQExpBuffer(delqry);
12343 CBC 1686 : destroyPQExpBuffer(asPart);
12344 GIC 1686 : free(funcsig);
12345 GNC 1686 : free(funcfullsig);
12346 GIC 1686 : free(funcsig_tag);
12347 CBC 1686 : free(qual_funcsig);
12348 GNC 1686 : free(configitems);
12349 : }
12350 ECB :
12351 :
12352 : /*
12353 : * Dump a user-defined cast
12354 : */
12355 : static void
12356 CBC 68 : dumpCast(Archive *fout, const CastInfo *cast)
12357 ECB : {
12358 GIC 68 : DumpOptions *dopt = fout->dopt;
12359 : PQExpBuffer defqry;
12360 : PQExpBuffer delqry;
12361 ECB : PQExpBuffer labelq;
12362 : PQExpBuffer castargs;
12363 CBC 68 : FuncInfo *funcInfo = NULL;
12364 : const char *sourceType;
12365 ECB : const char *targetType;
12366 :
12367 : /* Do nothing in data-only dump */
12368 CBC 68 : if (dopt->dataOnly)
12369 3 : return;
12370 ECB :
12371 : /* Cannot dump if we don't have the cast function's info */
12372 CBC 65 : if (OidIsValid(cast->castfunc))
12373 ECB : {
12374 CBC 40 : funcInfo = findFuncByOid(cast->castfunc);
12375 40 : if (funcInfo == NULL)
12376 LBC 0 : pg_fatal("could not find function definition for function with OID %u",
12377 ECB : cast->castfunc);
12378 : }
12379 :
12380 GIC 65 : defqry = createPQExpBuffer();
12381 65 : delqry = createPQExpBuffer();
12382 65 : labelq = createPQExpBuffer();
12383 65 : castargs = createPQExpBuffer();
12384 :
12385 CBC 65 : sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12386 GIC 65 : targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12387 CBC 65 : appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12388 : sourceType, targetType);
12389 ECB :
12390 GIC 65 : appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12391 ECB : sourceType, targetType);
12392 :
12393 CBC 65 : switch (cast->castmethod)
12394 : {
12395 25 : case COERCION_METHOD_BINARY:
12396 GIC 25 : appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12397 25 : break;
12398 UIC 0 : case COERCION_METHOD_INOUT:
12399 0 : appendPQExpBufferStr(defqry, "WITH INOUT");
12400 0 : break;
12401 CBC 40 : case COERCION_METHOD_FUNCTION:
12402 40 : if (funcInfo)
12403 ECB : {
12404 GIC 40 : char *fsig = format_function_signature(fout, funcInfo, true);
12405 EUB :
12406 : /*
12407 : * Always qualify the function name (format_function_signature
12408 : * won't qualify it).
12409 : */
12410 CBC 40 : appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12411 GIC 40 : fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12412 CBC 40 : free(fsig);
12413 EUB : }
12414 : else
12415 LBC 0 : pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
12416 GIC 40 : break;
12417 UIC 0 : default:
12418 LBC 0 : pg_log_warning("bogus value in pg_cast.castmethod field");
12419 : }
12420 ECB :
12421 GBC 65 : if (cast->castcontext == 'a')
12422 GIC 35 : appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12423 30 : else if (cast->castcontext == 'i')
12424 10 : appendPQExpBufferStr(defqry, " AS IMPLICIT");
12425 CBC 65 : appendPQExpBufferStr(defqry, ";\n");
12426 ECB :
12427 GIC 65 : appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12428 : sourceType, targetType);
12429 ECB :
12430 CBC 65 : appendPQExpBuffer(castargs, "(%s AS %s)",
12431 : sourceType, targetType);
12432 ECB :
12433 GIC 65 : if (dopt->binary_upgrade)
12434 CBC 7 : binary_upgrade_extension_member(defqry, &cast->dobj,
12435 7 : "CAST", castargs->data, NULL);
12436 :
12437 GIC 65 : if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12438 CBC 65 : ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12439 65 : ARCHIVE_OPTS(.tag = labelq->data,
12440 : .description = "CAST",
12441 ECB : .section = SECTION_PRE_DATA,
12442 : .createStmt = defqry->data,
12443 : .dropStmt = delqry->data));
12444 :
12445 : /* Dump Cast Comments */
12446 CBC 65 : if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12447 UIC 0 : dumpComment(fout, "CAST", castargs->data,
12448 ECB : NULL, "",
12449 UIC 0 : cast->dobj.catId, 0, cast->dobj.dumpId);
12450 :
12451 GIC 65 : destroyPQExpBuffer(defqry);
12452 CBC 65 : destroyPQExpBuffer(delqry);
12453 GIC 65 : destroyPQExpBuffer(labelq);
12454 CBC 65 : destroyPQExpBuffer(castargs);
12455 ECB : }
12456 :
12457 EUB : /*
12458 : * Dump a transform
12459 : */
12460 : static void
12461 GIC 43 : dumpTransform(Archive *fout, const TransformInfo *transform)
12462 ECB : {
12463 GIC 43 : DumpOptions *dopt = fout->dopt;
12464 ECB : PQExpBuffer defqry;
12465 : PQExpBuffer delqry;
12466 EUB : PQExpBuffer labelq;
12467 : PQExpBuffer transformargs;
12468 GIC 43 : FuncInfo *fromsqlFuncInfo = NULL;
12469 GBC 43 : FuncInfo *tosqlFuncInfo = NULL;
12470 EUB : char *lanname;
12471 : const char *transformType;
12472 :
12473 : /* Do nothing in data-only dump */
12474 GBC 43 : if (dopt->dataOnly)
12475 3 : return;
12476 EUB :
12477 : /* Cannot dump if we don't have the transform functions' info */
12478 GIC 40 : if (OidIsValid(transform->trffromsql))
12479 : {
12480 CBC 40 : fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12481 40 : if (fromsqlFuncInfo == NULL)
12482 UIC 0 : pg_fatal("could not find function definition for function with OID %u",
12483 ECB : transform->trffromsql);
12484 : }
12485 CBC 40 : if (OidIsValid(transform->trftosql))
12486 ECB : {
12487 CBC 40 : tosqlFuncInfo = findFuncByOid(transform->trftosql);
12488 40 : if (tosqlFuncInfo == NULL)
12489 UBC 0 : pg_fatal("could not find function definition for function with OID %u",
12490 EUB : transform->trftosql);
12491 : }
12492 :
12493 GIC 40 : defqry = createPQExpBuffer();
12494 CBC 40 : delqry = createPQExpBuffer();
12495 40 : labelq = createPQExpBuffer();
12496 GIC 40 : transformargs = createPQExpBuffer();
12497 ECB :
12498 GBC 40 : lanname = get_language_name(fout, transform->trflang);
12499 GIC 40 : transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12500 ECB :
12501 CBC 40 : appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12502 : transformType, lanname);
12503 :
12504 GIC 40 : appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12505 : transformType, lanname);
12506 :
12507 40 : if (!transform->trffromsql && !transform->trftosql)
12508 LBC 0 : pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
12509 :
12510 CBC 40 : if (transform->trffromsql)
12511 : {
12512 GIC 40 : if (fromsqlFuncInfo)
12513 ECB : {
12514 GBC 40 : char *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12515 :
12516 : /*
12517 : * Always qualify the function name (format_function_signature
12518 : * won't qualify it).
12519 ECB : */
12520 CBC 40 : appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12521 GIC 40 : fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12522 40 : free(fsig);
12523 ECB : }
12524 : else
12525 UBC 0 : pg_log_warning("bogus value in pg_transform.trffromsql field");
12526 : }
12527 ECB :
12528 GIC 40 : if (transform->trftosql)
12529 : {
12530 CBC 40 : if (transform->trffromsql)
12531 GIC 40 : appendPQExpBufferStr(defqry, ", ");
12532 :
12533 CBC 40 : if (tosqlFuncInfo)
12534 : {
12535 40 : char *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12536 ECB :
12537 : /*
12538 : * Always qualify the function name (format_function_signature
12539 EUB : * won't qualify it).
12540 : */
12541 GIC 40 : appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12542 40 : fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12543 40 : free(fsig);
12544 ECB : }
12545 : else
12546 UIC 0 : pg_log_warning("bogus value in pg_transform.trftosql field");
12547 ECB : }
12548 :
12549 GIC 40 : appendPQExpBufferStr(defqry, ");\n");
12550 ECB :
12551 CBC 40 : appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12552 EUB : transformType, lanname);
12553 ECB :
12554 CBC 40 : appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12555 : transformType, lanname);
12556 :
12557 GIC 40 : if (dopt->binary_upgrade)
12558 2 : binary_upgrade_extension_member(defqry, &transform->dobj,
12559 2 : "TRANSFORM", transformargs->data, NULL);
12560 :
12561 40 : if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12562 40 : ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12563 40 : ARCHIVE_OPTS(.tag = labelq->data,
12564 : .description = "TRANSFORM",
12565 : .section = SECTION_PRE_DATA,
12566 : .createStmt = defqry->data,
12567 : .dropStmt = delqry->data,
12568 : .deps = transform->dobj.dependencies,
12569 : .nDeps = transform->dobj.nDeps));
12570 :
12571 ECB : /* Dump Transform Comments */
12572 GIC 40 : if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12573 UIC 0 : dumpComment(fout, "TRANSFORM", transformargs->data,
12574 : NULL, "",
12575 0 : transform->dobj.catId, 0, transform->dobj.dumpId);
12576 :
12577 GIC 40 : free(lanname);
12578 CBC 40 : destroyPQExpBuffer(defqry);
12579 GIC 40 : destroyPQExpBuffer(delqry);
12580 CBC 40 : destroyPQExpBuffer(labelq);
12581 GIC 40 : destroyPQExpBuffer(transformargs);
12582 ECB : }
12583 :
12584 :
12585 : /*
12586 : * dumpOpr
12587 : * write out a single operator definition
12588 : */
12589 : static void
12590 CBC 108 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
12591 : {
12592 GIC 108 : DumpOptions *dopt = fout->dopt;
12593 ECB : PQExpBuffer query;
12594 : PQExpBuffer q;
12595 : PQExpBuffer delq;
12596 : PQExpBuffer oprid;
12597 : PQExpBuffer details;
12598 : PGresult *res;
12599 : int i_oprkind;
12600 : int i_oprcode;
12601 : int i_oprleft;
12602 : int i_oprright;
12603 : int i_oprcom;
12604 : int i_oprnegate;
12605 : int i_oprrest;
12606 : int i_oprjoin;
12607 : int i_oprcanmerge;
12608 : int i_oprcanhash;
12609 : char *oprkind;
12610 : char *oprcode;
12611 : char *oprleft;
12612 : char *oprright;
12613 : char *oprcom;
12614 : char *oprnegate;
12615 : char *oprrest;
12616 EUB : char *oprjoin;
12617 : char *oprcanmerge;
12618 : char *oprcanhash;
12619 : char *oprregproc;
12620 ECB : char *oprref;
12621 EUB :
12622 : /* Do nothing in data-only dump */
12623 GBC 108 : if (dopt->dataOnly)
12624 GIC 3 : return;
12625 ECB :
12626 : /*
12627 : * some operators are invalid because they were the result of user
12628 : * defining operators before commutators exist
12629 : */
12630 GIC 105 : if (!OidIsValid(oprinfo->oprcode))
12631 CBC 14 : return;
12632 :
12633 91 : query = createPQExpBuffer();
12634 91 : q = createPQExpBuffer();
12635 91 : delq = createPQExpBuffer();
12636 91 : oprid = createPQExpBuffer();
12637 91 : details = createPQExpBuffer();
12638 ECB :
12639 CBC 91 : if (!fout->is_prepared[PREPQUERY_DUMPOPR])
12640 ECB : {
12641 : /* Set up query for operator-specific details */
12642 GIC 41 : appendPQExpBufferStr(query,
12643 : "PREPARE dumpOpr(pg_catalog.oid) AS\n"
12644 : "SELECT oprkind, "
12645 : "oprcode::pg_catalog.regprocedure, "
12646 : "oprleft::pg_catalog.regtype, "
12647 : "oprright::pg_catalog.regtype, "
12648 : "oprcom, "
12649 ECB : "oprnegate, "
12650 : "oprrest::pg_catalog.regprocedure, "
12651 : "oprjoin::pg_catalog.regprocedure, "
12652 : "oprcanmerge, oprcanhash "
12653 : "FROM pg_catalog.pg_operator "
12654 : "WHERE oid = $1");
12655 :
12656 CBC 41 : ExecuteSqlStatement(fout, query->data);
12657 :
12658 GIC 41 : fout->is_prepared[PREPQUERY_DUMPOPR] = true;
12659 : }
12660 :
12661 CBC 91 : printfPQExpBuffer(query,
12662 ECB : "EXECUTE dumpOpr('%u')",
12663 GIC 91 : oprinfo->dobj.catId.oid);
12664 :
12665 CBC 91 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
12666 :
12667 91 : i_oprkind = PQfnumber(res, "oprkind");
12668 91 : i_oprcode = PQfnumber(res, "oprcode");
12669 GBC 91 : i_oprleft = PQfnumber(res, "oprleft");
12670 GIC 91 : i_oprright = PQfnumber(res, "oprright");
12671 91 : i_oprcom = PQfnumber(res, "oprcom");
12672 91 : i_oprnegate = PQfnumber(res, "oprnegate");
12673 CBC 91 : i_oprrest = PQfnumber(res, "oprrest");
12674 91 : i_oprjoin = PQfnumber(res, "oprjoin");
12675 91 : i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12676 91 : i_oprcanhash = PQfnumber(res, "oprcanhash");
12677 :
12678 91 : oprkind = PQgetvalue(res, 0, i_oprkind);
12679 91 : oprcode = PQgetvalue(res, 0, i_oprcode);
12680 91 : oprleft = PQgetvalue(res, 0, i_oprleft);
12681 GIC 91 : oprright = PQgetvalue(res, 0, i_oprright);
12682 91 : oprcom = PQgetvalue(res, 0, i_oprcom);
12683 CBC 91 : oprnegate = PQgetvalue(res, 0, i_oprnegate);
12684 GIC 91 : oprrest = PQgetvalue(res, 0, i_oprrest);
12685 91 : oprjoin = PQgetvalue(res, 0, i_oprjoin);
12686 CBC 91 : oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12687 GIC 91 : oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12688 ECB :
12689 : /* In PG14 upwards postfix operator support does not exist anymore. */
12690 CBC 91 : if (strcmp(oprkind, "r") == 0)
12691 UBC 0 : pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
12692 EUB : oprcode);
12693 :
12694 CBC 91 : oprregproc = convertRegProcReference(oprcode);
12695 91 : if (oprregproc)
12696 : {
12697 91 : appendPQExpBuffer(details, " FUNCTION = %s", oprregproc);
12698 GIC 91 : free(oprregproc);
12699 : }
12700 :
12701 91 : appendPQExpBuffer(oprid, "%s (",
12702 91 : oprinfo->dobj.name);
12703 ECB :
12704 : /*
12705 : * right unary means there's a left arg and left unary means there's a
12706 : * right arg. (Although the "r" case is dead code for PG14 and later,
12707 : * continue to support it in case we're dumping from an old server.)
12708 EUB : */
12709 CBC 91 : if (strcmp(oprkind, "r") == 0 ||
12710 GBC 91 : strcmp(oprkind, "b") == 0)
12711 EUB : {
12712 GIC 71 : appendPQExpBuffer(details, ",\n LEFTARG = %s", oprleft);
12713 71 : appendPQExpBufferStr(oprid, oprleft);
12714 ECB : }
12715 : else
12716 CBC 20 : appendPQExpBufferStr(oprid, "NONE");
12717 ECB :
12718 CBC 91 : if (strcmp(oprkind, "l") == 0 ||
12719 GIC 71 : strcmp(oprkind, "b") == 0)
12720 ECB : {
12721 GIC 91 : appendPQExpBuffer(details, ",\n RIGHTARG = %s", oprright);
12722 91 : appendPQExpBuffer(oprid, ", %s)", oprright);
12723 ECB : }
12724 : else
12725 UIC 0 : appendPQExpBufferStr(oprid, ", NONE)");
12726 ECB :
12727 CBC 91 : oprref = getFormattedOperatorName(oprcom);
12728 91 : if (oprref)
12729 : {
12730 20 : appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
12731 20 : free(oprref);
12732 ECB : }
12733 :
12734 GIC 91 : oprref = getFormattedOperatorName(oprnegate);
12735 91 : if (oprref)
12736 : {
12737 5 : appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
12738 5 : free(oprref);
12739 ECB : }
12740 EUB :
12741 GIC 91 : if (strcmp(oprcanmerge, "t") == 0)
12742 GBC 20 : appendPQExpBufferStr(details, ",\n MERGES");
12743 :
12744 CBC 91 : if (strcmp(oprcanhash, "t") == 0)
12745 LBC 0 : appendPQExpBufferStr(details, ",\n HASHES");
12746 ECB :
12747 CBC 91 : oprregproc = convertRegProcReference(oprrest);
12748 GIC 91 : if (oprregproc)
12749 : {
12750 20 : appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
12751 20 : free(oprregproc);
12752 : }
12753 :
12754 CBC 91 : oprregproc = convertRegProcReference(oprjoin);
12755 GIC 91 : if (oprregproc)
12756 ECB : {
12757 GIC 20 : appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
12758 20 : free(oprregproc);
12759 : }
12760 :
12761 CBC 91 : appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12762 91 : fmtId(oprinfo->dobj.namespace->dobj.name),
12763 : oprid->data);
12764 :
12765 GIC 91 : appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12766 91 : fmtId(oprinfo->dobj.namespace->dobj.name),
12767 CBC 91 : oprinfo->dobj.name, details->data);
12768 ECB :
12769 GIC 91 : if (dopt->binary_upgrade)
12770 12 : binary_upgrade_extension_member(q, &oprinfo->dobj,
12771 CBC 12 : "OPERATOR", oprid->data,
12772 GIC 12 : oprinfo->dobj.namespace->dobj.name);
12773 ECB :
12774 CBC 91 : if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12775 GBC 91 : ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12776 GIC 91 : ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
12777 : .namespace = oprinfo->dobj.namespace->dobj.name,
12778 ECB : .owner = oprinfo->rolname,
12779 : .description = "OPERATOR",
12780 : .section = SECTION_PRE_DATA,
12781 : .createStmt = q->data,
12782 EUB : .dropStmt = delq->data));
12783 :
12784 : /* Dump Operator Comments */
12785 GIC 91 : if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12786 LBC 0 : dumpComment(fout, "OPERATOR", oprid->data,
12787 0 : oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12788 0 : oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12789 ECB :
12790 GIC 91 : PQclear(res);
12791 ECB :
12792 CBC 91 : destroyPQExpBuffer(query);
12793 GIC 91 : destroyPQExpBuffer(q);
12794 CBC 91 : destroyPQExpBuffer(delq);
12795 GIC 91 : destroyPQExpBuffer(oprid);
12796 91 : destroyPQExpBuffer(details);
12797 ECB : }
12798 :
12799 : /*
12800 : * Convert a function reference obtained from pg_operator
12801 EUB : *
12802 : * Returns allocated string of what to print, or NULL if function references
12803 ECB : * is InvalidOid. Returned string is expected to be free'd by the caller.
12804 : *
12805 : * The input is a REGPROCEDURE display; we have to strip the argument-types
12806 : * part.
12807 : */
12808 : static char *
12809 GIC 273 : convertRegProcReference(const char *proc)
12810 : {
12811 : char *name;
12812 : char *paren;
12813 ECB : bool inquote;
12814 :
12815 : /* In all cases "-" means a null reference */
12816 GIC 273 : if (strcmp(proc, "-") == 0)
12817 142 : return NULL;
12818 EUB :
12819 GIC 131 : name = pg_strdup(proc);
12820 : /* find non-double-quoted left paren */
12821 CBC 131 : inquote = false;
12822 GIC 1462 : for (paren = name; *paren; paren++)
12823 ECB : {
12824 CBC 1462 : if (*paren == '(' && !inquote)
12825 : {
12826 131 : *paren = '\0';
12827 GIC 131 : break;
12828 ECB : }
12829 GIC 1331 : if (*paren == '"')
12830 50 : inquote = !inquote;
12831 : }
12832 131 : return name;
12833 : }
12834 ECB :
12835 : /*
12836 : * getFormattedOperatorName - retrieve the operator name for the
12837 : * given operator OID (presented in string form).
12838 : *
12839 EUB : * Returns an allocated string, or NULL if the given OID is invalid.
12840 : * Caller is responsible for free'ing result string.
12841 : *
12842 ECB : * What we produce has the format "OPERATOR(schema.oprname)". This is only
12843 : * useful in commands where the operator's argument types can be inferred from
12844 : * context. We always schema-qualify the name, though. The predecessor to
12845 : * this code tried to skip the schema qualification if possible, but that led
12846 : * to wrong results in corner cases, such as if an operator and its negator
12847 : * are in different schemas.
12848 : */
12849 : static char *
12850 CBC 470 : getFormattedOperatorName(const char *oproid)
12851 ECB : {
12852 : OprInfo *oprInfo;
12853 :
12854 : /* In all cases "0" means a null reference */
12855 CBC 470 : if (strcmp(oproid, "0") == 0)
12856 445 : return NULL;
12857 :
12858 GIC 25 : oprInfo = findOprByOid(atooid(oproid));
12859 25 : if (oprInfo == NULL)
12860 : {
12861 UIC 0 : pg_log_warning("could not find operator with OID %s",
12862 : oproid);
12863 0 : return NULL;
12864 : }
12865 ECB :
12866 GBC 25 : return psprintf("OPERATOR(%s.%s)",
12867 GIC 25 : fmtId(oprInfo->dobj.namespace->dobj.name),
12868 EUB : oprInfo->dobj.name);
12869 : }
12870 ECB :
12871 : /*
12872 : * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12873 : *
12874 : * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12875 : * argument lists of these functions are predetermined. Note that the
12876 : * caller should ensure we are in the proper schema, because the results
12877 : * are search path dependent!
12878 : */
12879 : static char *
12880 GIC 180 : convertTSFunction(Archive *fout, Oid funcOid)
12881 : {
12882 : char *result;
12883 ECB : char query[128];
12884 : PGresult *res;
12885 :
12886 GIC 180 : snprintf(query, sizeof(query),
12887 : "SELECT '%u'::pg_catalog.regproc", funcOid);
12888 180 : res = ExecuteSqlQueryForSingleRow(fout, query);
12889 :
12890 180 : result = pg_strdup(PQgetvalue(res, 0, 0));
12891 :
12892 180 : PQclear(res);
12893 :
12894 180 : return result;
12895 : }
12896 :
12897 : /*
12898 : * dumpAccessMethod
12899 : * write out a single access method definition
12900 : */
12901 : static void
12902 82 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
12903 : {
12904 82 : DumpOptions *dopt = fout->dopt;
12905 : PQExpBuffer q;
12906 : PQExpBuffer delq;
12907 : char *qamname;
12908 :
12909 : /* Do nothing in data-only dump */
12910 82 : if (dopt->dataOnly)
12911 6 : return;
12912 :
12913 76 : q = createPQExpBuffer();
12914 76 : delq = createPQExpBuffer();
12915 :
12916 CBC 76 : qamname = pg_strdup(fmtId(aminfo->dobj.name));
12917 ECB :
12918 GIC 76 : appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12919 :
12920 76 : switch (aminfo->amtype)
12921 : {
12922 36 : case AMTYPE_INDEX:
12923 CBC 36 : appendPQExpBufferStr(q, "TYPE INDEX ");
12924 36 : break;
12925 GIC 40 : case AMTYPE_TABLE:
12926 CBC 40 : appendPQExpBufferStr(q, "TYPE TABLE ");
12927 40 : break;
12928 LBC 0 : default:
12929 0 : pg_log_warning("invalid type \"%c\" of access method \"%s\"",
12930 ECB : aminfo->amtype, qamname);
12931 UIC 0 : destroyPQExpBuffer(q);
12932 LBC 0 : destroyPQExpBuffer(delq);
12933 UIC 0 : free(qamname);
12934 0 : return;
12935 ECB : }
12936 :
12937 GIC 76 : appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12938 :
12939 76 : appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12940 : qamname);
12941 :
12942 76 : if (dopt->binary_upgrade)
12943 4 : binary_upgrade_extension_member(q, &aminfo->dobj,
12944 : "ACCESS METHOD", qamname, NULL);
12945 :
12946 76 : if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12947 76 : ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12948 76 : ARCHIVE_OPTS(.tag = aminfo->dobj.name,
12949 ECB : .description = "ACCESS METHOD",
12950 : .section = SECTION_PRE_DATA,
12951 : .createStmt = q->data,
12952 : .dropStmt = delq->data));
12953 :
12954 : /* Dump Access Method Comments */
12955 GIC 76 : if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12956 LBC 0 : dumpComment(fout, "ACCESS METHOD", qamname,
12957 : NULL, "",
12958 0 : aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12959 :
12960 CBC 76 : destroyPQExpBuffer(q);
12961 76 : destroyPQExpBuffer(delq);
12962 76 : free(qamname);
12963 ECB : }
12964 :
12965 : /*
12966 : * dumpOpclass
12967 : * write out a single operator class definition
12968 : */
12969 : static void
12970 GIC 132 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
12971 ECB : {
12972 CBC 132 : DumpOptions *dopt = fout->dopt;
12973 ECB : PQExpBuffer query;
12974 : PQExpBuffer q;
12975 : PQExpBuffer delq;
12976 : PQExpBuffer nameusing;
12977 : PGresult *res;
12978 : int ntups;
12979 : int i_opcintype;
12980 : int i_opckeytype;
12981 : int i_opcdefault;
12982 : int i_opcfamily;
12983 : int i_opcfamilyname;
12984 EUB : int i_opcfamilynsp;
12985 : int i_amname;
12986 : int i_amopstrategy;
12987 ECB : int i_amopopr;
12988 : int i_sortfamily;
12989 : int i_sortfamilynsp;
12990 : int i_amprocnum;
12991 : int i_amproc;
12992 : int i_amproclefttype;
12993 : int i_amprocrighttype;
12994 : char *opcintype;
12995 : char *opckeytype;
12996 : char *opcdefault;
12997 : char *opcfamily;
12998 : char *opcfamilyname;
12999 : char *opcfamilynsp;
13000 : char *amname;
13001 : char *amopstrategy;
13002 : char *amopopr;
13003 : char *sortfamily;
13004 : char *sortfamilynsp;
13005 : char *amprocnum;
13006 : char *amproc;
13007 : char *amproclefttype;
13008 : char *amprocrighttype;
13009 : bool needComma;
13010 : int i;
13011 :
13012 : /* Do nothing in data-only dump */
13013 GIC 132 : if (dopt->dataOnly)
13014 CBC 9 : return;
13015 ECB :
13016 GIC 123 : query = createPQExpBuffer();
13017 123 : q = createPQExpBuffer();
13018 GBC 123 : delq = createPQExpBuffer();
13019 GIC 123 : nameusing = createPQExpBuffer();
13020 ECB :
13021 : /* Get additional fields from the pg_opclass row */
13022 GIC 123 : appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
13023 ECB : "opckeytype::pg_catalog.regtype, "
13024 : "opcdefault, opcfamily, "
13025 : "opfname AS opcfamilyname, "
13026 : "nspname AS opcfamilynsp, "
13027 : "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
13028 : "FROM pg_catalog.pg_opclass c "
13029 : "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
13030 : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13031 : "WHERE c.oid = '%u'::pg_catalog.oid",
13032 GIC 123 : opcinfo->dobj.catId.oid);
13033 :
13034 CBC 123 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13035 ECB :
13036 GIC 123 : i_opcintype = PQfnumber(res, "opcintype");
13037 CBC 123 : i_opckeytype = PQfnumber(res, "opckeytype");
13038 GBC 123 : i_opcdefault = PQfnumber(res, "opcdefault");
13039 GIC 123 : i_opcfamily = PQfnumber(res, "opcfamily");
13040 CBC 123 : i_opcfamilyname = PQfnumber(res, "opcfamilyname");
13041 123 : i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
13042 GIC 123 : i_amname = PQfnumber(res, "amname");
13043 ECB :
13044 : /* opcintype may still be needed after we PQclear res */
13045 GIC 123 : opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
13046 123 : opckeytype = PQgetvalue(res, 0, i_opckeytype);
13047 CBC 123 : opcdefault = PQgetvalue(res, 0, i_opcdefault);
13048 ECB : /* opcfamily will still be needed after we PQclear res */
13049 GIC 123 : opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
13050 CBC 123 : opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
13051 123 : opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
13052 : /* amname will still be needed after we PQclear res */
13053 GIC 123 : amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13054 ECB :
13055 CBC 123 : appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
13056 GIC 123 : fmtQualifiedDumpable(opcinfo));
13057 123 : appendPQExpBuffer(delq, " USING %s;\n",
13058 ECB : fmtId(amname));
13059 :
13060 : /* Build the fixed portion of the CREATE command */
13061 GIC 123 : appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
13062 CBC 123 : fmtQualifiedDumpable(opcinfo));
13063 123 : if (strcmp(opcdefault, "t") == 0)
13064 LBC 0 : appendPQExpBufferStr(q, "DEFAULT ");
13065 CBC 123 : appendPQExpBuffer(q, "FOR TYPE %s USING %s",
13066 : opcintype,
13067 ECB : fmtId(amname));
13068 CBC 123 : if (strlen(opcfamilyname) > 0)
13069 ECB : {
13070 GIC 123 : appendPQExpBufferStr(q, " FAMILY ");
13071 123 : appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
13072 123 : appendPQExpBufferStr(q, fmtId(opcfamilyname));
13073 : }
13074 123 : appendPQExpBufferStr(q, " AS\n ");
13075 :
13076 123 : needComma = false;
13077 :
13078 CBC 123 : if (strcmp(opckeytype, "-") != 0)
13079 EUB : {
13080 UBC 0 : appendPQExpBuffer(q, "STORAGE %s",
13081 EUB : opckeytype);
13082 UIC 0 : needComma = true;
13083 ECB : }
13084 :
13085 CBC 123 : PQclear(res);
13086 ECB :
13087 : /*
13088 : * Now fetch and print the OPERATOR entries (pg_amop rows).
13089 : *
13090 : * Print only those opfamily members that are tied to the opclass by
13091 : * pg_depend entries.
13092 : */
13093 GIC 123 : resetPQExpBuffer(query);
13094 123 : appendPQExpBuffer(query, "SELECT amopstrategy, "
13095 : "amopopr::pg_catalog.regoperator, "
13096 : "opfname AS sortfamily, "
13097 : "nspname AS sortfamilynsp "
13098 : "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13099 : "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13100 : "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13101 : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13102 ECB : "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13103 : "AND refobjid = '%u'::pg_catalog.oid "
13104 : "AND amopfamily = '%s'::pg_catalog.oid "
13105 : "ORDER BY amopstrategy",
13106 GIC 123 : opcinfo->dobj.catId.oid,
13107 : opcfamily);
13108 :
13109 CBC 123 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13110 ECB :
13111 GIC 123 : ntups = PQntuples(res);
13112 ECB :
13113 GIC 123 : i_amopstrategy = PQfnumber(res, "amopstrategy");
13114 CBC 123 : i_amopopr = PQfnumber(res, "amopopr");
13115 123 : i_sortfamily = PQfnumber(res, "sortfamily");
13116 GIC 123 : i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
13117 ECB :
13118 GIC 349 : for (i = 0; i < ntups; i++)
13119 ECB : {
13120 CBC 226 : amopstrategy = PQgetvalue(res, i, i_amopstrategy);
13121 GIC 226 : amopopr = PQgetvalue(res, i, i_amopopr);
13122 CBC 226 : sortfamily = PQgetvalue(res, i, i_sortfamily);
13123 226 : sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
13124 :
13125 226 : if (needComma)
13126 GIC 144 : appendPQExpBufferStr(q, " ,\n ");
13127 :
13128 226 : appendPQExpBuffer(q, "OPERATOR %s %s",
13129 : amopstrategy, amopopr);
13130 :
13131 226 : if (strlen(sortfamily) > 0)
13132 : {
13133 UIC 0 : appendPQExpBufferStr(q, " FOR ORDER BY ");
13134 0 : appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13135 0 : appendPQExpBufferStr(q, fmtId(sortfamily));
13136 : }
13137 :
13138 GIC 226 : needComma = true;
13139 : }
13140 :
13141 123 : PQclear(res);
13142 :
13143 ECB : /*
13144 : * Now fetch and print the FUNCTION entries (pg_amproc rows).
13145 : *
13146 : * Print only those opfamily members that are tied to the opclass by
13147 : * pg_depend entries.
13148 : *
13149 : * We print the amproclefttype/amprocrighttype even though in most cases
13150 : * the backend could deduce the right values, because of the corner case
13151 : * of a btree sort support function for a cross-type comparison.
13152 : */
13153 GIC 123 : resetPQExpBuffer(query);
13154 EUB :
13155 GIC 123 : appendPQExpBuffer(query, "SELECT amprocnum, "
13156 EUB : "amproc::pg_catalog.regprocedure, "
13157 : "amproclefttype::pg_catalog.regtype, "
13158 : "amprocrighttype::pg_catalog.regtype "
13159 ECB : "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13160 : "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13161 : "AND refobjid = '%u'::pg_catalog.oid "
13162 : "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13163 : "AND objid = ap.oid "
13164 : "ORDER BY amprocnum",
13165 GIC 123 : opcinfo->dobj.catId.oid);
13166 :
13167 123 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13168 :
13169 123 : ntups = PQntuples(res);
13170 :
13171 123 : i_amprocnum = PQfnumber(res, "amprocnum");
13172 123 : i_amproc = PQfnumber(res, "amproc");
13173 CBC 123 : i_amproclefttype = PQfnumber(res, "amproclefttype");
13174 GIC 123 : i_amprocrighttype = PQfnumber(res, "amprocrighttype");
13175 :
13176 159 : for (i = 0; i < ntups; i++)
13177 : {
13178 36 : amprocnum = PQgetvalue(res, i, i_amprocnum);
13179 CBC 36 : amproc = PQgetvalue(res, i, i_amproc);
13180 GIC 36 : amproclefttype = PQgetvalue(res, i, i_amproclefttype);
13181 CBC 36 : amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
13182 :
13183 36 : if (needComma)
13184 GIC 36 : appendPQExpBufferStr(q, " ,\n ");
13185 ECB :
13186 GIC 36 : appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
13187 ECB :
13188 GIC 36 : if (*amproclefttype && *amprocrighttype)
13189 36 : appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
13190 :
13191 36 : appendPQExpBuffer(q, " %s", amproc);
13192 :
13193 36 : needComma = true;
13194 : }
13195 ECB :
13196 GIC 123 : PQclear(res);
13197 ECB :
13198 : /*
13199 : * If needComma is still false it means we haven't added anything after
13200 : * the AS keyword. To avoid printing broken SQL, append a dummy STORAGE
13201 : * clause with the same datatype. This isn't sanctioned by the
13202 : * documentation, but actually DefineOpClass will treat it as a no-op.
13203 : */
13204 CBC 123 : if (!needComma)
13205 GIC 41 : appendPQExpBuffer(q, "STORAGE %s", opcintype);
13206 ECB :
13207 CBC 123 : appendPQExpBufferStr(q, ";\n");
13208 :
13209 123 : appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
13210 GIC 123 : appendPQExpBuffer(nameusing, " USING %s",
13211 ECB : fmtId(amname));
13212 :
13213 CBC 123 : if (dopt->binary_upgrade)
13214 GIC 6 : binary_upgrade_extension_member(q, &opcinfo->dobj,
13215 CBC 6 : "OPERATOR CLASS", nameusing->data,
13216 6 : opcinfo->dobj.namespace->dobj.name);
13217 ECB :
13218 CBC 123 : if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13219 123 : ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
13220 123 : ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
13221 EUB : .namespace = opcinfo->dobj.namespace->dobj.name,
13222 : .owner = opcinfo->rolname,
13223 : .description = "OPERATOR CLASS",
13224 : .section = SECTION_PRE_DATA,
13225 : .createStmt = q->data,
13226 : .dropStmt = delq->data));
13227 :
13228 : /* Dump Operator Class Comments */
13229 GIC 123 : if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13230 LBC 0 : dumpComment(fout, "OPERATOR CLASS", nameusing->data,
13231 UIC 0 : opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
13232 LBC 0 : opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13233 :
13234 GIC 123 : free(opcintype);
13235 CBC 123 : free(opcfamily);
13236 123 : free(amname);
13237 GIC 123 : destroyPQExpBuffer(query);
13238 123 : destroyPQExpBuffer(q);
13239 CBC 123 : destroyPQExpBuffer(delq);
13240 123 : destroyPQExpBuffer(nameusing);
13241 ECB : }
13242 :
13243 : /*
13244 : * dumpOpfamily
13245 : * write out a single operator family definition
13246 : *
13247 : * Note: this also dumps any "loose" operator members that aren't bound to a
13248 : * specific opclass within the opfamily.
13249 EUB : */
13250 : static void
13251 GBC 113 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
13252 : {
13253 CBC 113 : DumpOptions *dopt = fout->dopt;
13254 ECB : PQExpBuffer query;
13255 : PQExpBuffer q;
13256 : PQExpBuffer delq;
13257 : PQExpBuffer nameusing;
13258 : PGresult *res;
13259 : PGresult *res_ops;
13260 : PGresult *res_procs;
13261 : int ntups;
13262 : int i_amname;
13263 : int i_amopstrategy;
13264 : int i_amopopr;
13265 : int i_sortfamily;
13266 : int i_sortfamilynsp;
13267 : int i_amprocnum;
13268 : int i_amproc;
13269 : int i_amproclefttype;
13270 : int i_amprocrighttype;
13271 : char *amname;
13272 : char *amopstrategy;
13273 : char *amopopr;
13274 : char *sortfamily;
13275 : char *sortfamilynsp;
13276 : char *amprocnum;
13277 : char *amproc;
13278 : char *amproclefttype;
13279 : char *amprocrighttype;
13280 : bool needComma;
13281 : int i;
13282 :
13283 : /* Do nothing in data-only dump */
13284 GIC 113 : if (dopt->dataOnly)
13285 6 : return;
13286 :
13287 107 : query = createPQExpBuffer();
13288 107 : q = createPQExpBuffer();
13289 107 : delq = createPQExpBuffer();
13290 107 : nameusing = createPQExpBuffer();
13291 :
13292 : /*
13293 : * Fetch only those opfamily members that are tied directly to the
13294 : * opfamily by pg_depend entries.
13295 : */
13296 107 : appendPQExpBuffer(query, "SELECT amopstrategy, "
13297 : "amopopr::pg_catalog.regoperator, "
13298 : "opfname AS sortfamily, "
13299 : "nspname AS sortfamilynsp "
13300 : "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13301 : "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13302 : "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13303 : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13304 : "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13305 : "AND refobjid = '%u'::pg_catalog.oid "
13306 ECB : "AND amopfamily = '%u'::pg_catalog.oid "
13307 : "ORDER BY amopstrategy",
13308 GIC 107 : opfinfo->dobj.catId.oid,
13309 CBC 107 : opfinfo->dobj.catId.oid);
13310 ECB :
13311 CBC 107 : res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13312 ECB :
13313 GIC 107 : resetPQExpBuffer(query);
13314 :
13315 CBC 107 : appendPQExpBuffer(query, "SELECT amprocnum, "
13316 : "amproc::pg_catalog.regprocedure, "
13317 : "amproclefttype::pg_catalog.regtype, "
13318 : "amprocrighttype::pg_catalog.regtype "
13319 : "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13320 : "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13321 : "AND refobjid = '%u'::pg_catalog.oid "
13322 : "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13323 : "AND objid = ap.oid "
13324 : "ORDER BY amprocnum",
13325 107 : opfinfo->dobj.catId.oid);
13326 :
13327 107 : res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13328 :
13329 ECB : /* Get additional fields from the pg_opfamily row */
13330 CBC 107 : resetPQExpBuffer(query);
13331 ECB :
13332 CBC 107 : appendPQExpBuffer(query, "SELECT "
13333 ECB : "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13334 : "FROM pg_catalog.pg_opfamily "
13335 : "WHERE oid = '%u'::pg_catalog.oid",
13336 GIC 107 : opfinfo->dobj.catId.oid);
13337 :
13338 CBC 107 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13339 ECB :
13340 CBC 107 : i_amname = PQfnumber(res, "amname");
13341 :
13342 ECB : /* amname will still be needed after we PQclear res */
13343 CBC 107 : amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13344 ECB :
13345 GIC 107 : appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13346 CBC 107 : fmtQualifiedDumpable(opfinfo));
13347 GIC 107 : appendPQExpBuffer(delq, " USING %s;\n",
13348 ECB : fmtId(amname));
13349 :
13350 : /* Build the fixed portion of the CREATE command */
13351 GIC 107 : appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13352 107 : fmtQualifiedDumpable(opfinfo));
13353 107 : appendPQExpBuffer(q, " USING %s;\n",
13354 ECB : fmtId(amname));
13355 :
13356 CBC 107 : PQclear(res);
13357 EUB :
13358 ECB : /* Do we need an ALTER to add loose members? */
13359 GIC 107 : if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13360 : {
13361 CBC 51 : appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13362 GIC 51 : fmtQualifiedDumpable(opfinfo));
13363 CBC 51 : appendPQExpBuffer(q, " USING %s ADD\n ",
13364 ECB : fmtId(amname));
13365 :
13366 GIC 51 : needComma = false;
13367 ECB :
13368 : /*
13369 : * Now fetch and print the OPERATOR entries (pg_amop rows).
13370 : */
13371 CBC 51 : ntups = PQntuples(res_ops);
13372 :
13373 GBC 51 : i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13374 GIC 51 : i_amopopr = PQfnumber(res_ops, "amopopr");
13375 GBC 51 : i_sortfamily = PQfnumber(res_ops, "sortfamily");
13376 GIC 51 : i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13377 :
13378 CBC 231 : for (i = 0; i < ntups; i++)
13379 : {
13380 GIC 180 : amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13381 180 : amopopr = PQgetvalue(res_ops, i, i_amopopr);
13382 180 : sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13383 180 : sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13384 :
13385 180 : if (needComma)
13386 CBC 144 : appendPQExpBufferStr(q, " ,\n ");
13387 ECB :
13388 GIC 180 : appendPQExpBuffer(q, "OPERATOR %s %s",
13389 : amopstrategy, amopopr);
13390 :
13391 180 : if (strlen(sortfamily) > 0)
13392 : {
13393 UIC 0 : appendPQExpBufferStr(q, " FOR ORDER BY ");
13394 0 : appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13395 0 : appendPQExpBufferStr(q, fmtId(sortfamily));
13396 : }
13397 :
13398 GIC 180 : needComma = true;
13399 ECB : }
13400 :
13401 : /*
13402 : * Now fetch and print the FUNCTION entries (pg_amproc rows).
13403 : */
13404 CBC 51 : ntups = PQntuples(res_procs);
13405 :
13406 51 : i_amprocnum = PQfnumber(res_procs, "amprocnum");
13407 51 : i_amproc = PQfnumber(res_procs, "amproc");
13408 51 : i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13409 51 : i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13410 :
13411 246 : for (i = 0; i < ntups; i++)
13412 : {
13413 195 : amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13414 195 : amproc = PQgetvalue(res_procs, i, i_amproc);
13415 195 : amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13416 195 : amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13417 :
13418 195 : if (needComma)
13419 180 : appendPQExpBufferStr(q, " ,\n ");
13420 :
13421 195 : appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13422 : amprocnum, amproclefttype, amprocrighttype,
13423 : amproc);
13424 ECB :
13425 GIC 195 : needComma = true;
13426 EUB : }
13427 :
13428 GBC 51 : appendPQExpBufferStr(q, ";\n");
13429 : }
13430 :
13431 CBC 107 : appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13432 GIC 107 : appendPQExpBuffer(nameusing, " USING %s",
13433 : fmtId(amname));
13434 ECB :
13435 GIC 107 : if (dopt->binary_upgrade)
13436 9 : binary_upgrade_extension_member(q, &opfinfo->dobj,
13437 9 : "OPERATOR FAMILY", nameusing->data,
13438 9 : opfinfo->dobj.namespace->dobj.name);
13439 :
13440 107 : if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13441 107 : ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13442 107 : ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
13443 : .namespace = opfinfo->dobj.namespace->dobj.name,
13444 : .owner = opfinfo->rolname,
13445 : .description = "OPERATOR FAMILY",
13446 ECB : .section = SECTION_PRE_DATA,
13447 : .createStmt = q->data,
13448 : .dropStmt = delq->data));
13449 :
13450 : /* Dump Operator Family Comments */
13451 GIC 107 : if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13452 UIC 0 : dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13453 0 : opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13454 0 : opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13455 :
13456 GIC 107 : free(amname);
13457 107 : PQclear(res_ops);
13458 CBC 107 : PQclear(res_procs);
13459 GIC 107 : destroyPQExpBuffer(query);
13460 CBC 107 : destroyPQExpBuffer(q);
13461 GIC 107 : destroyPQExpBuffer(delq);
13462 CBC 107 : destroyPQExpBuffer(nameusing);
13463 : }
13464 ECB :
13465 : /*
13466 : * dumpCollation
13467 : * write out a single collation definition
13468 : */
13469 : static void
13470 GIC 81 : dumpCollation(Archive *fout, const CollInfo *collinfo)
13471 ECB : {
13472 CBC 81 : DumpOptions *dopt = fout->dopt;
13473 ECB : PQExpBuffer query;
13474 : PQExpBuffer q;
13475 : PQExpBuffer delq;
13476 : char *qcollname;
13477 : PGresult *res;
13478 : int i_collprovider;
13479 : int i_collisdeterministic;
13480 : int i_collcollate;
13481 : int i_collctype;
13482 : int i_colliculocale;
13483 : int i_collicurules;
13484 : const char *collprovider;
13485 : const char *collcollate;
13486 : const char *collctype;
13487 : const char *colliculocale;
13488 : const char *collicurules;
13489 :
13490 : /* Do nothing in data-only dump */
13491 CBC 81 : if (dopt->dataOnly)
13492 GIC 6 : return;
13493 :
13494 75 : query = createPQExpBuffer();
13495 75 : q = createPQExpBuffer();
13496 75 : delq = createPQExpBuffer();
13497 :
13498 75 : qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13499 ECB :
13500 : /* Get collation-specific details */
13501 GIC 75 : appendPQExpBufferStr(query, "SELECT ");
13502 ECB :
13503 GIC 75 : if (fout->remoteVersion >= 100000)
13504 CBC 75 : appendPQExpBufferStr(query,
13505 ECB : "collprovider, "
13506 : "collversion, ");
13507 : else
13508 LBC 0 : appendPQExpBufferStr(query,
13509 ECB : "'c' AS collprovider, "
13510 : "NULL AS collversion, ");
13511 :
13512 GIC 75 : if (fout->remoteVersion >= 120000)
13513 CBC 75 : appendPQExpBufferStr(query,
13514 ECB : "collisdeterministic, ");
13515 : else
13516 UIC 0 : appendPQExpBufferStr(query,
13517 : "true AS collisdeterministic, ");
13518 :
13519 GIC 75 : if (fout->remoteVersion >= 150000)
13520 75 : appendPQExpBufferStr(query,
13521 : "colliculocale, ");
13522 : else
13523 UIC 0 : appendPQExpBufferStr(query,
13524 ECB : "NULL AS colliculocale, ");
13525 EUB :
13526 GNC 75 : if (fout->remoteVersion >= 160000)
13527 75 : appendPQExpBufferStr(query,
13528 : "collicurules, ");
13529 : else
13530 UNC 0 : appendPQExpBufferStr(query,
13531 : "NULL AS collicurules, ");
13532 :
13533 GBC 75 : appendPQExpBuffer(query,
13534 EUB : "collcollate, "
13535 : "collctype "
13536 ECB : "FROM pg_catalog.pg_collation c "
13537 : "WHERE c.oid = '%u'::pg_catalog.oid",
13538 CBC 75 : collinfo->dobj.catId.oid);
13539 ECB :
13540 CBC 75 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13541 ECB :
13542 CBC 75 : i_collprovider = PQfnumber(res, "collprovider");
13543 GIC 75 : i_collisdeterministic = PQfnumber(res, "collisdeterministic");
13544 75 : i_collcollate = PQfnumber(res, "collcollate");
13545 75 : i_collctype = PQfnumber(res, "collctype");
13546 75 : i_colliculocale = PQfnumber(res, "colliculocale");
13547 GNC 75 : i_collicurules = PQfnumber(res, "collicurules");
13548 :
13549 GIC 75 : collprovider = PQgetvalue(res, 0, i_collprovider);
13550 :
13551 75 : if (!PQgetisnull(res, 0, i_collcollate))
13552 35 : collcollate = PQgetvalue(res, 0, i_collcollate);
13553 : else
13554 CBC 40 : collcollate = NULL;
13555 :
13556 75 : if (!PQgetisnull(res, 0, i_collctype))
13557 GIC 35 : collctype = PQgetvalue(res, 0, i_collctype);
13558 : else
13559 40 : collctype = NULL;
13560 :
13561 75 : if (!PQgetisnull(res, 0, i_colliculocale))
13562 40 : colliculocale = PQgetvalue(res, 0, i_colliculocale);
13563 : else
13564 35 : colliculocale = NULL;
13565 :
13566 GNC 75 : if (!PQgetisnull(res, 0, i_collicurules))
13567 UNC 0 : collicurules = PQgetvalue(res, 0, i_collicurules);
13568 : else
13569 GNC 75 : collicurules = NULL;
13570 :
13571 GIC 75 : appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13572 75 : fmtQualifiedDumpable(collinfo));
13573 :
13574 75 : appendPQExpBuffer(q, "CREATE COLLATION %s (",
13575 75 : fmtQualifiedDumpable(collinfo));
13576 :
13577 75 : appendPQExpBufferStr(q, "provider = ");
13578 75 : if (collprovider[0] == 'c')
13579 35 : appendPQExpBufferStr(q, "libc");
13580 40 : else if (collprovider[0] == 'i')
13581 40 : appendPQExpBufferStr(q, "icu");
13582 UIC 0 : else if (collprovider[0] == 'd')
13583 : /* to allow dumping pg_catalog; not accepted on input */
13584 0 : appendPQExpBufferStr(q, "default");
13585 : else
13586 0 : pg_fatal("unrecognized collation provider: %s",
13587 : collprovider);
13588 :
13589 GIC 75 : if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
13590 UIC 0 : appendPQExpBufferStr(q, ", deterministic = false");
13591 :
13592 CBC 75 : if (colliculocale != NULL)
13593 ECB : {
13594 GIC 40 : appendPQExpBufferStr(q, ", locale = ");
13595 CBC 40 : appendStringLiteralAH(q, colliculocale, fout);
13596 ECB : }
13597 : else
13598 : {
13599 GIC 35 : Assert(collcollate != NULL);
13600 35 : Assert(collctype != NULL);
13601 :
13602 35 : if (strcmp(collcollate, collctype) == 0)
13603 : {
13604 CBC 35 : appendPQExpBufferStr(q, ", locale = ");
13605 GIC 35 : appendStringLiteralAH(q, collcollate, fout);
13606 : }
13607 : else
13608 : {
13609 UIC 0 : appendPQExpBufferStr(q, ", lc_collate = ");
13610 0 : appendStringLiteralAH(q, collcollate, fout);
13611 0 : appendPQExpBufferStr(q, ", lc_ctype = ");
13612 0 : appendStringLiteralAH(q, collctype, fout);
13613 : }
13614 : }
13615 :
13616 GNC 75 : if (collicurules)
13617 : {
13618 UNC 0 : appendPQExpBufferStr(q, ", rules = ");
13619 0 : appendStringLiteralAH(q, collicurules, fout);
13620 : }
13621 :
13622 ECB : /*
13623 : * For binary upgrade, carry over the collation version. For normal
13624 : * dump/restore, omit the version, so that it is computed upon restore.
13625 : */
13626 GIC 75 : if (dopt->binary_upgrade)
13627 ECB : {
13628 : int i_collversion;
13629 :
13630 GIC 3 : i_collversion = PQfnumber(res, "collversion");
13631 3 : if (!PQgetisnull(res, 0, i_collversion))
13632 : {
13633 2 : appendPQExpBufferStr(q, ", version = ");
13634 2 : appendStringLiteralAH(q,
13635 : PQgetvalue(res, 0, i_collversion),
13636 : fout);
13637 : }
13638 : }
13639 ECB :
13640 GIC 75 : appendPQExpBufferStr(q, ");\n");
13641 ECB :
13642 GIC 75 : if (dopt->binary_upgrade)
13643 3 : binary_upgrade_extension_member(q, &collinfo->dobj,
13644 ECB : "COLLATION", qcollname,
13645 GIC 3 : collinfo->dobj.namespace->dobj.name);
13646 ECB :
13647 GIC 75 : if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13648 75 : ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13649 75 : ARCHIVE_OPTS(.tag = collinfo->dobj.name,
13650 ECB : .namespace = collinfo->dobj.namespace->dobj.name,
13651 : .owner = collinfo->rolname,
13652 : .description = "COLLATION",
13653 : .section = SECTION_PRE_DATA,
13654 : .createStmt = q->data,
13655 : .dropStmt = delq->data));
13656 :
13657 : /* Dump Collation Comments */
13658 GIC 75 : if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13659 CBC 35 : dumpComment(fout, "COLLATION", qcollname,
13660 35 : collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13661 35 : collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13662 :
13663 GIC 75 : PQclear(res);
13664 :
13665 CBC 75 : destroyPQExpBuffer(query);
13666 75 : destroyPQExpBuffer(q);
13667 75 : destroyPQExpBuffer(delq);
13668 GIC 75 : free(qcollname);
13669 : }
13670 ECB :
13671 : /*
13672 : * dumpConversion
13673 : * write out a single conversion definition
13674 : */
13675 : static void
13676 CBC 39 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
13677 ECB : {
13678 GIC 39 : DumpOptions *dopt = fout->dopt;
13679 : PQExpBuffer query;
13680 ECB : PQExpBuffer q;
13681 : PQExpBuffer delq;
13682 : char *qconvname;
13683 : PGresult *res;
13684 : int i_conforencoding;
13685 : int i_contoencoding;
13686 : int i_conproc;
13687 : int i_condefault;
13688 : const char *conforencoding;
13689 : const char *contoencoding;
13690 : const char *conproc;
13691 : bool condefault;
13692 :
13693 : /* Do nothing in data-only dump */
13694 CBC 39 : if (dopt->dataOnly)
13695 3 : return;
13696 ECB :
13697 CBC 36 : query = createPQExpBuffer();
13698 GIC 36 : q = createPQExpBuffer();
13699 CBC 36 : delq = createPQExpBuffer();
13700 ECB :
13701 GIC 36 : qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13702 ECB :
13703 : /* Get conversion-specific details */
13704 GIC 36 : appendPQExpBuffer(query, "SELECT "
13705 ECB : "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13706 : "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13707 EUB : "conproc, condefault "
13708 : "FROM pg_catalog.pg_conversion c "
13709 : "WHERE c.oid = '%u'::pg_catalog.oid",
13710 GIC 36 : convinfo->dobj.catId.oid);
13711 :
13712 CBC 36 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13713 :
13714 GIC 36 : i_conforencoding = PQfnumber(res, "conforencoding");
13715 36 : i_contoencoding = PQfnumber(res, "contoencoding");
13716 36 : i_conproc = PQfnumber(res, "conproc");
13717 36 : i_condefault = PQfnumber(res, "condefault");
13718 ECB :
13719 GIC 36 : conforencoding = PQgetvalue(res, 0, i_conforencoding);
13720 CBC 36 : contoencoding = PQgetvalue(res, 0, i_contoencoding);
13721 36 : conproc = PQgetvalue(res, 0, i_conproc);
13722 36 : condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13723 ECB :
13724 GIC 36 : appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13725 CBC 36 : fmtQualifiedDumpable(convinfo));
13726 :
13727 36 : appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13728 ECB : (condefault) ? "DEFAULT " : "",
13729 CBC 36 : fmtQualifiedDumpable(convinfo));
13730 36 : appendStringLiteralAH(q, conforencoding, fout);
13731 GIC 36 : appendPQExpBufferStr(q, " TO ");
13732 CBC 36 : appendStringLiteralAH(q, contoencoding, fout);
13733 ECB : /* regproc output is already sufficiently quoted */
13734 GIC 36 : appendPQExpBuffer(q, " FROM %s;\n", conproc);
13735 ECB :
13736 GIC 36 : if (dopt->binary_upgrade)
13737 1 : binary_upgrade_extension_member(q, &convinfo->dobj,
13738 : "CONVERSION", qconvname,
13739 CBC 1 : convinfo->dobj.namespace->dobj.name);
13740 :
13741 GIC 36 : if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13742 CBC 36 : ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13743 GIC 36 : ARCHIVE_OPTS(.tag = convinfo->dobj.name,
13744 : .namespace = convinfo->dobj.namespace->dobj.name,
13745 ECB : .owner = convinfo->rolname,
13746 : .description = "CONVERSION",
13747 : .section = SECTION_PRE_DATA,
13748 : .createStmt = q->data,
13749 : .dropStmt = delq->data));
13750 :
13751 : /* Dump Conversion Comments */
13752 CBC 36 : if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13753 GIC 36 : dumpComment(fout, "CONVERSION", qconvname,
13754 CBC 36 : convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13755 36 : convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13756 ECB :
13757 GIC 36 : PQclear(res);
13758 :
13759 36 : destroyPQExpBuffer(query);
13760 36 : destroyPQExpBuffer(q);
13761 36 : destroyPQExpBuffer(delq);
13762 36 : free(qconvname);
13763 : }
13764 :
13765 ECB : /*
13766 EUB : * format_aggregate_signature: generate aggregate name and argument list
13767 : *
13768 : * The argument type names are qualified if needed. The aggregate name
13769 : * is never qualified.
13770 ECB : */
13771 : static char *
13772 CBC 288 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
13773 ECB : {
13774 : PQExpBufferData buf;
13775 : int j;
13776 :
13777 GIC 288 : initPQExpBuffer(&buf);
13778 288 : if (honor_quotes)
13779 UIC 0 : appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13780 : else
13781 GIC 288 : appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13782 :
13783 288 : if (agginfo->aggfn.nargs == 0)
13784 CBC 40 : appendPQExpBufferStr(&buf, "(*)");
13785 : else
13786 ECB : {
13787 GIC 248 : appendPQExpBufferChar(&buf, '(');
13788 541 : for (j = 0; j < agginfo->aggfn.nargs; j++)
13789 293 : appendPQExpBuffer(&buf, "%s%s",
13790 : (j > 0) ? ", " : "",
13791 : getFormattedTypeName(fout,
13792 293 : agginfo->aggfn.argtypes[j],
13793 : zeroIsError));
13794 248 : appendPQExpBufferChar(&buf, ')');
13795 : }
13796 288 : return buf.data;
13797 : }
13798 :
13799 : /*
13800 : * dumpAgg
13801 : * write out a single aggregate definition
13802 : */
13803 : static void
13804 292 : dumpAgg(Archive *fout, const AggInfo *agginfo)
13805 ECB : {
13806 CBC 292 : DumpOptions *dopt = fout->dopt;
13807 : PQExpBuffer query;
13808 ECB : PQExpBuffer q;
13809 : PQExpBuffer delq;
13810 : PQExpBuffer details;
13811 : char *aggsig; /* identity signature */
13812 CBC 292 : char *aggfullsig = NULL; /* full signature */
13813 : char *aggsig_tag;
13814 : PGresult *res;
13815 ECB : int i_agginitval;
13816 : int i_aggminitval;
13817 : const char *aggtransfn;
13818 : const char *aggfinalfn;
13819 : const char *aggcombinefn;
13820 : const char *aggserialfn;
13821 : const char *aggdeserialfn;
13822 EUB : const char *aggmtransfn;
13823 : const char *aggminvtransfn;
13824 : const char *aggmfinalfn;
13825 : bool aggfinalextra;
13826 ECB : bool aggmfinalextra;
13827 : char aggfinalmodify;
13828 : char aggmfinalmodify;
13829 : const char *aggsortop;
13830 EUB : char *aggsortconvop;
13831 : char aggkind;
13832 : const char *aggtranstype;
13833 ECB : const char *aggtransspace;
13834 : const char *aggmtranstype;
13835 : const char *aggmtransspace;
13836 : const char *agginitval;
13837 EUB : const char *aggminitval;
13838 : const char *proparallel;
13839 : char defaultfinalmodify;
13840 ECB :
13841 : /* Do nothing in data-only dump */
13842 GIC 292 : if (dopt->dataOnly)
13843 4 : return;
13844 EUB :
13845 GIC 288 : query = createPQExpBuffer();
13846 288 : q = createPQExpBuffer();
13847 CBC 288 : delq = createPQExpBuffer();
13848 GIC 288 : details = createPQExpBuffer();
13849 :
13850 288 : if (!fout->is_prepared[PREPQUERY_DUMPAGG])
13851 : {
13852 ECB : /* Set up query for aggregate-specific details */
13853 GIC 58 : appendPQExpBufferStr(query,
13854 ECB : "PREPARE dumpAgg(pg_catalog.oid) AS\n");
13855 :
13856 CBC 58 : appendPQExpBufferStr(query,
13857 ECB : "SELECT "
13858 : "aggtransfn,\n"
13859 : "aggfinalfn,\n"
13860 : "aggtranstype::pg_catalog.regtype,\n"
13861 : "agginitval,\n"
13862 : "aggsortop,\n"
13863 : "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
13864 : "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
13865 :
13866 CBC 58 : if (fout->remoteVersion >= 90400)
13867 GIC 58 : appendPQExpBufferStr(query,
13868 ECB : "aggkind,\n"
13869 : "aggmtransfn,\n"
13870 : "aggminvtransfn,\n"
13871 : "aggmfinalfn,\n"
13872 : "aggmtranstype::pg_catalog.regtype,\n"
13873 : "aggfinalextra,\n"
13874 : "aggmfinalextra,\n"
13875 : "aggtransspace,\n"
13876 : "aggmtransspace,\n"
13877 : "aggminitval,\n");
13878 : else
13879 UIC 0 : appendPQExpBufferStr(query,
13880 ECB : "'n' AS aggkind,\n"
13881 EUB : "'-' AS aggmtransfn,\n"
13882 : "'-' AS aggminvtransfn,\n"
13883 ECB : "'-' AS aggmfinalfn,\n"
13884 : "0 AS aggmtranstype,\n"
13885 : "false AS aggfinalextra,\n"
13886 : "false AS aggmfinalextra,\n"
13887 : "0 AS aggtransspace,\n"
13888 : "0 AS aggmtransspace,\n"
13889 : "NULL AS aggminitval,\n");
13890 :
13891 CBC 58 : if (fout->remoteVersion >= 90600)
13892 58 : appendPQExpBufferStr(query,
13893 ECB : "aggcombinefn,\n"
13894 : "aggserialfn,\n"
13895 : "aggdeserialfn,\n"
13896 EUB : "proparallel,\n");
13897 : else
13898 UBC 0 : appendPQExpBufferStr(query,
13899 : "'-' AS aggcombinefn,\n"
13900 EUB : "'-' AS aggserialfn,\n"
13901 : "'-' AS aggdeserialfn,\n"
13902 : "'u' AS proparallel,\n");
13903 ECB :
13904 GBC 58 : if (fout->remoteVersion >= 110000)
13905 GIC 58 : appendPQExpBufferStr(query,
13906 ECB : "aggfinalmodify,\n"
13907 : "aggmfinalmodify\n");
13908 : else
13909 LBC 0 : appendPQExpBufferStr(query,
13910 : "'0' AS aggfinalmodify,\n"
13911 : "'0' AS aggmfinalmodify\n");
13912 :
13913 CBC 58 : appendPQExpBufferStr(query,
13914 ECB : "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13915 : "WHERE a.aggfnoid = p.oid "
13916 : "AND p.oid = $1");
13917 :
13918 CBC 58 : ExecuteSqlStatement(fout, query->data);
13919 ECB :
13920 GIC 58 : fout->is_prepared[PREPQUERY_DUMPAGG] = true;
13921 : }
13922 :
13923 GBC 288 : printfPQExpBuffer(query,
13924 EUB : "EXECUTE dumpAgg('%u')",
13925 GBC 288 : agginfo->aggfn.dobj.catId.oid);
13926 EUB :
13927 GIC 288 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13928 :
13929 288 : i_agginitval = PQfnumber(res, "agginitval");
13930 CBC 288 : i_aggminitval = PQfnumber(res, "aggminitval");
13931 :
13932 GBC 288 : aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
13933 288 : aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
13934 GIC 288 : aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
13935 288 : aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
13936 288 : aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
13937 288 : aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
13938 288 : aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
13939 288 : aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
13940 CBC 288 : aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
13941 GIC 288 : aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
13942 288 : aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
13943 288 : aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
13944 CBC 288 : aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
13945 288 : aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
13946 GIC 288 : aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
13947 CBC 288 : aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
13948 288 : aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
13949 GIC 288 : aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
13950 288 : agginitval = PQgetvalue(res, 0, i_agginitval);
13951 288 : aggminitval = PQgetvalue(res, 0, i_aggminitval);
13952 288 : proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13953 :
13954 ECB : {
13955 : char *funcargs;
13956 : char *funciargs;
13957 :
13958 GIC 288 : funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13959 CBC 288 : funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13960 GIC 288 : aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13961 CBC 288 : aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13962 ECB : }
13963 :
13964 GIC 288 : aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13965 :
13966 : /* identify default modify flag for aggkind (must match DefineAggregate) */
13967 288 : defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
13968 : /* replace omitted flags for old versions */
13969 288 : if (aggfinalmodify == '0')
13970 UIC 0 : aggfinalmodify = defaultfinalmodify;
13971 GIC 288 : if (aggmfinalmodify == '0')
13972 LBC 0 : aggmfinalmodify = defaultfinalmodify;
13973 ECB :
13974 : /* regproc and regtype output is already sufficiently quoted */
13975 CBC 288 : appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
13976 : aggtransfn, aggtranstype);
13977 ECB :
13978 GIC 288 : if (strcmp(aggtransspace, "0") != 0)
13979 ECB : {
13980 CBC 5 : appendPQExpBuffer(details, ",\n SSPACE = %s",
13981 ECB : aggtransspace);
13982 : }
13983 :
13984 GIC 288 : if (!PQgetisnull(res, 0, i_agginitval))
13985 : {
13986 211 : appendPQExpBufferStr(details, ",\n INITCOND = ");
13987 211 : appendStringLiteralAH(details, agginitval, fout);
13988 : }
13989 :
13990 CBC 288 : if (strcmp(aggfinalfn, "-") != 0)
13991 : {
13992 136 : appendPQExpBuffer(details, ",\n FINALFUNC = %s",
13993 : aggfinalfn);
13994 GIC 136 : if (aggfinalextra)
13995 10 : appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
13996 136 : if (aggfinalmodify != defaultfinalmodify)
13997 : {
13998 36 : switch (aggfinalmodify)
13999 : {
14000 UIC 0 : case AGGMODIFY_READ_ONLY:
14001 0 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_ONLY");
14002 0 : break;
14003 GIC 36 : case AGGMODIFY_SHAREABLE:
14004 36 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = SHAREABLE");
14005 36 : break;
14006 UIC 0 : case AGGMODIFY_READ_WRITE:
14007 0 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_WRITE");
14008 LBC 0 : break;
14009 0 : default:
14010 UIC 0 : pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
14011 ECB : agginfo->aggfn.dobj.name);
14012 : break;
14013 : }
14014 : }
14015 : }
14016 :
14017 GIC 288 : if (strcmp(aggcombinefn, "-") != 0)
14018 LBC 0 : appendPQExpBuffer(details, ",\n COMBINEFUNC = %s", aggcombinefn);
14019 :
14020 GIC 288 : if (strcmp(aggserialfn, "-") != 0)
14021 UIC 0 : appendPQExpBuffer(details, ",\n SERIALFUNC = %s", aggserialfn);
14022 :
14023 GIC 288 : if (strcmp(aggdeserialfn, "-") != 0)
14024 LBC 0 : appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
14025 :
14026 CBC 288 : if (strcmp(aggmtransfn, "-") != 0)
14027 : {
14028 30 : appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
14029 ECB : aggmtransfn,
14030 : aggminvtransfn,
14031 : aggmtranstype);
14032 : }
14033 :
14034 CBC 288 : if (strcmp(aggmtransspace, "0") != 0)
14035 ECB : {
14036 LBC 0 : appendPQExpBuffer(details, ",\n MSSPACE = %s",
14037 : aggmtransspace);
14038 ECB : }
14039 :
14040 GIC 288 : if (!PQgetisnull(res, 0, i_aggminitval))
14041 ECB : {
14042 GIC 10 : appendPQExpBufferStr(details, ",\n MINITCOND = ");
14043 CBC 10 : appendStringLiteralAH(details, aggminitval, fout);
14044 ECB : }
14045 :
14046 CBC 288 : if (strcmp(aggmfinalfn, "-") != 0)
14047 : {
14048 LBC 0 : appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
14049 : aggmfinalfn);
14050 0 : if (aggmfinalextra)
14051 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
14052 UIC 0 : if (aggmfinalmodify != defaultfinalmodify)
14053 ECB : {
14054 UIC 0 : switch (aggmfinalmodify)
14055 ECB : {
14056 LBC 0 : case AGGMODIFY_READ_ONLY:
14057 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_ONLY");
14058 UIC 0 : break;
14059 0 : case AGGMODIFY_SHAREABLE:
14060 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = SHAREABLE");
14061 0 : break;
14062 0 : case AGGMODIFY_READ_WRITE:
14063 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_WRITE");
14064 0 : break;
14065 0 : default:
14066 LBC 0 : pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
14067 ECB : agginfo->aggfn.dobj.name);
14068 : break;
14069 : }
14070 : }
14071 : }
14072 :
14073 CBC 288 : aggsortconvop = getFormattedOperatorName(aggsortop);
14074 288 : if (aggsortconvop)
14075 ECB : {
14076 LBC 0 : appendPQExpBuffer(details, ",\n SORTOP = %s",
14077 : aggsortconvop);
14078 UIC 0 : free(aggsortconvop);
14079 : }
14080 :
14081 GIC 288 : if (aggkind == AGGKIND_HYPOTHETICAL)
14082 5 : appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
14083 :
14084 288 : if (proparallel[0] != PROPARALLEL_UNSAFE)
14085 : {
14086 CBC 5 : if (proparallel[0] == PROPARALLEL_SAFE)
14087 GIC 5 : appendPQExpBufferStr(details, ",\n PARALLEL = safe");
14088 UIC 0 : else if (proparallel[0] == PROPARALLEL_RESTRICTED)
14089 0 : appendPQExpBufferStr(details, ",\n PARALLEL = restricted");
14090 0 : else if (proparallel[0] != PROPARALLEL_UNSAFE)
14091 LBC 0 : pg_fatal("unrecognized proparallel value for function \"%s\"",
14092 ECB : agginfo->aggfn.dobj.name);
14093 EUB : }
14094 :
14095 CBC 288 : appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
14096 GIC 288 : fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14097 ECB : aggsig);
14098 :
14099 GIC 576 : appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
14100 288 : fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14101 ECB : aggfullsig ? aggfullsig : aggsig, details->data);
14102 :
14103 CBC 288 : if (dopt->binary_upgrade)
14104 GIC 49 : binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
14105 : "AGGREGATE", aggsig,
14106 CBC 49 : agginfo->aggfn.dobj.namespace->dobj.name);
14107 :
14108 288 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
14109 GIC 272 : ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
14110 CBC 272 : agginfo->aggfn.dobj.dumpId,
14111 GIC 272 : ARCHIVE_OPTS(.tag = aggsig_tag,
14112 : .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
14113 : .owner = agginfo->aggfn.rolname,
14114 : .description = "AGGREGATE",
14115 : .section = SECTION_PRE_DATA,
14116 : .createStmt = q->data,
14117 : .dropStmt = delq->data));
14118 ECB :
14119 : /* Dump Aggregate Comments */
14120 CBC 288 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
14121 GIC 10 : dumpComment(fout, "AGGREGATE", aggsig,
14122 10 : agginfo->aggfn.dobj.namespace->dobj.name,
14123 10 : agginfo->aggfn.rolname,
14124 10 : agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14125 :
14126 CBC 288 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
14127 UIC 0 : dumpSecLabel(fout, "AGGREGATE", aggsig,
14128 0 : agginfo->aggfn.dobj.namespace->dobj.name,
14129 0 : agginfo->aggfn.rolname,
14130 0 : agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14131 :
14132 : /*
14133 : * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
14134 : * command look like a function's GRANT; in particular this affects the
14135 : * syntax for zero-argument aggregates and ordered-set aggregates.
14136 : */
14137 GIC 288 : free(aggsig);
14138 :
14139 288 : aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14140 :
14141 288 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
14142 17 : dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
14143 : "FUNCTION", aggsig, NULL,
14144 17 : agginfo->aggfn.dobj.namespace->dobj.name,
14145 17 : agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
14146 :
14147 288 : free(aggsig);
14148 GNC 288 : free(aggfullsig);
14149 GIC 288 : free(aggsig_tag);
14150 :
14151 288 : PQclear(res);
14152 :
14153 288 : destroyPQExpBuffer(query);
14154 288 : destroyPQExpBuffer(q);
14155 CBC 288 : destroyPQExpBuffer(delq);
14156 288 : destroyPQExpBuffer(details);
14157 : }
14158 ECB :
14159 : /*
14160 : * dumpTSParser
14161 : * write out a single text search parser
14162 : */
14163 : static void
14164 GIC 39 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
14165 : {
14166 CBC 39 : DumpOptions *dopt = fout->dopt;
14167 : PQExpBuffer q;
14168 : PQExpBuffer delq;
14169 ECB : char *qprsname;
14170 :
14171 : /* Do nothing in data-only dump */
14172 GIC 39 : if (dopt->dataOnly)
14173 3 : return;
14174 :
14175 36 : q = createPQExpBuffer();
14176 36 : delq = createPQExpBuffer();
14177 :
14178 36 : qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14179 ECB :
14180 CBC 36 : appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14181 GIC 36 : fmtQualifiedDumpable(prsinfo));
14182 :
14183 36 : appendPQExpBuffer(q, " START = %s,\n",
14184 36 : convertTSFunction(fout, prsinfo->prsstart));
14185 36 : appendPQExpBuffer(q, " GETTOKEN = %s,\n",
14186 36 : convertTSFunction(fout, prsinfo->prstoken));
14187 36 : appendPQExpBuffer(q, " END = %s,\n",
14188 36 : convertTSFunction(fout, prsinfo->prsend));
14189 36 : if (prsinfo->prsheadline != InvalidOid)
14190 UIC 0 : appendPQExpBuffer(q, " HEADLINE = %s,\n",
14191 0 : convertTSFunction(fout, prsinfo->prsheadline));
14192 GBC 36 : appendPQExpBuffer(q, " LEXTYPES = %s );\n",
14193 GIC 36 : convertTSFunction(fout, prsinfo->prslextype));
14194 :
14195 36 : appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14196 36 : fmtQualifiedDumpable(prsinfo));
14197 :
14198 36 : if (dopt->binary_upgrade)
14199 1 : binary_upgrade_extension_member(q, &prsinfo->dobj,
14200 : "TEXT SEARCH PARSER", qprsname,
14201 1 : prsinfo->dobj.namespace->dobj.name);
14202 :
14203 36 : if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14204 CBC 36 : ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14205 36 : ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
14206 : .namespace = prsinfo->dobj.namespace->dobj.name,
14207 : .description = "TEXT SEARCH PARSER",
14208 : .section = SECTION_PRE_DATA,
14209 : .createStmt = q->data,
14210 : .dropStmt = delq->data));
14211 EUB :
14212 : /* Dump Parser Comments */
14213 GIC 36 : if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14214 36 : dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14215 36 : prsinfo->dobj.namespace->dobj.name, "",
14216 36 : prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14217 ECB :
14218 CBC 36 : destroyPQExpBuffer(q);
14219 GIC 36 : destroyPQExpBuffer(delq);
14220 36 : free(qprsname);
14221 : }
14222 EUB :
14223 : /*
14224 : * dumpTSDictionary
14225 : * write out a single text search dictionary
14226 ECB : */
14227 : static void
14228 GIC 84 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
14229 : {
14230 84 : DumpOptions *dopt = fout->dopt;
14231 ECB : PQExpBuffer q;
14232 : PQExpBuffer delq;
14233 : PQExpBuffer query;
14234 : char *qdictname;
14235 : PGresult *res;
14236 : char *nspname;
14237 : char *tmplname;
14238 :
14239 : /* Do nothing in data-only dump */
14240 CBC 84 : if (dopt->dataOnly)
14241 GIC 3 : return;
14242 ECB :
14243 CBC 81 : q = createPQExpBuffer();
14244 GIC 81 : delq = createPQExpBuffer();
14245 CBC 81 : query = createPQExpBuffer();
14246 ECB :
14247 CBC 81 : qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14248 ECB :
14249 : /* Fetch name and namespace of the dictionary's template */
14250 CBC 81 : appendPQExpBuffer(query, "SELECT nspname, tmplname "
14251 ECB : "FROM pg_ts_template p, pg_namespace n "
14252 : "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14253 CBC 81 : dictinfo->dicttemplate);
14254 81 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
14255 81 : nspname = PQgetvalue(res, 0, 0);
14256 81 : tmplname = PQgetvalue(res, 0, 1);
14257 ECB :
14258 CBC 81 : appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14259 81 : fmtQualifiedDumpable(dictinfo));
14260 ECB :
14261 CBC 81 : appendPQExpBufferStr(q, " TEMPLATE = ");
14262 81 : appendPQExpBuffer(q, "%s.", fmtId(nspname));
14263 81 : appendPQExpBufferStr(q, fmtId(tmplname));
14264 ECB :
14265 CBC 81 : PQclear(res);
14266 :
14267 : /* the dictinitoption can be dumped straight into the command */
14268 GIC 81 : if (dictinfo->dictinitoption)
14269 45 : appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
14270 :
14271 CBC 81 : appendPQExpBufferStr(q, " );\n");
14272 ECB :
14273 CBC 81 : appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14274 81 : fmtQualifiedDumpable(dictinfo));
14275 :
14276 GIC 81 : if (dopt->binary_upgrade)
14277 CBC 10 : binary_upgrade_extension_member(q, &dictinfo->dobj,
14278 : "TEXT SEARCH DICTIONARY", qdictname,
14279 GIC 10 : dictinfo->dobj.namespace->dobj.name);
14280 ECB :
14281 GIC 81 : if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14282 CBC 81 : ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14283 GBC 81 : ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
14284 ECB : .namespace = dictinfo->dobj.namespace->dobj.name,
14285 EUB : .owner = dictinfo->rolname,
14286 : .description = "TEXT SEARCH DICTIONARY",
14287 : .section = SECTION_PRE_DATA,
14288 ECB : .createStmt = q->data,
14289 : .dropStmt = delq->data));
14290 :
14291 : /* Dump Dictionary Comments */
14292 GIC 81 : if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14293 CBC 36 : dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14294 GIC 36 : dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14295 36 : dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14296 :
14297 CBC 81 : destroyPQExpBuffer(q);
14298 GIC 81 : destroyPQExpBuffer(delq);
14299 CBC 81 : destroyPQExpBuffer(query);
14300 81 : free(qdictname);
14301 : }
14302 :
14303 ECB : /*
14304 : * dumpTSTemplate
14305 : * write out a single text search template
14306 : */
14307 : static void
14308 CBC 39 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
14309 ECB : {
14310 GIC 39 : DumpOptions *dopt = fout->dopt;
14311 ECB : PQExpBuffer q;
14312 : PQExpBuffer delq;
14313 EUB : char *qtmplname;
14314 :
14315 : /* Do nothing in data-only dump */
14316 CBC 39 : if (dopt->dataOnly)
14317 3 : return;
14318 ECB :
14319 GBC 36 : q = createPQExpBuffer();
14320 36 : delq = createPQExpBuffer();
14321 EUB :
14322 GBC 36 : qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14323 EUB :
14324 GIC 36 : appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14325 36 : fmtQualifiedDumpable(tmplinfo));
14326 :
14327 36 : if (tmplinfo->tmplinit != InvalidOid)
14328 UIC 0 : appendPQExpBuffer(q, " INIT = %s,\n",
14329 0 : convertTSFunction(fout, tmplinfo->tmplinit));
14330 CBC 36 : appendPQExpBuffer(q, " LEXIZE = %s );\n",
14331 GBC 36 : convertTSFunction(fout, tmplinfo->tmpllexize));
14332 :
14333 CBC 36 : appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14334 GBC 36 : fmtQualifiedDumpable(tmplinfo));
14335 :
14336 CBC 36 : if (dopt->binary_upgrade)
14337 GBC 1 : binary_upgrade_extension_member(q, &tmplinfo->dobj,
14338 : "TEXT SEARCH TEMPLATE", qtmplname,
14339 CBC 1 : tmplinfo->dobj.namespace->dobj.name);
14340 :
14341 36 : if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14342 GIC 36 : ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14343 36 : ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
14344 : .namespace = tmplinfo->dobj.namespace->dobj.name,
14345 : .description = "TEXT SEARCH TEMPLATE",
14346 : .section = SECTION_PRE_DATA,
14347 ECB : .createStmt = q->data,
14348 : .dropStmt = delq->data));
14349 EUB :
14350 : /* Dump Template Comments */
14351 GIC 36 : if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14352 36 : dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14353 CBC 36 : tmplinfo->dobj.namespace->dobj.name, "",
14354 GIC 36 : tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14355 ECB :
14356 CBC 36 : destroyPQExpBuffer(q);
14357 GIC 36 : destroyPQExpBuffer(delq);
14358 36 : free(qtmplname);
14359 ECB : }
14360 :
14361 EUB : /*
14362 : * dumpTSConfig
14363 : * write out a single text search configuration
14364 : */
14365 : static void
14366 GIC 59 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
14367 EUB : {
14368 GIC 59 : DumpOptions *dopt = fout->dopt;
14369 EUB : PQExpBuffer q;
14370 : PQExpBuffer delq;
14371 : PQExpBuffer query;
14372 : char *qcfgname;
14373 : PGresult *res;
14374 : char *nspname;
14375 : char *prsname;
14376 : int ntups,
14377 : i;
14378 : int i_tokenname;
14379 : int i_dictname;
14380 :
14381 : /* Do nothing in data-only dump */
14382 GIC 59 : if (dopt->dataOnly)
14383 3 : return;
14384 :
14385 56 : q = createPQExpBuffer();
14386 CBC 56 : delq = createPQExpBuffer();
14387 56 : query = createPQExpBuffer();
14388 :
14389 GBC 56 : qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14390 :
14391 EUB : /* Fetch name and namespace of the config's parser */
14392 GIC 56 : appendPQExpBuffer(query, "SELECT nspname, prsname "
14393 : "FROM pg_ts_parser p, pg_namespace n "
14394 ECB : "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14395 CBC 56 : cfginfo->cfgparser);
14396 GIC 56 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
14397 CBC 56 : nspname = PQgetvalue(res, 0, 0);
14398 GIC 56 : prsname = PQgetvalue(res, 0, 1);
14399 ECB :
14400 CBC 56 : appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14401 GBC 56 : fmtQualifiedDumpable(cfginfo));
14402 EUB :
14403 GBC 56 : appendPQExpBuffer(q, " PARSER = %s.", fmtId(nspname));
14404 56 : appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14405 :
14406 GIC 56 : PQclear(res);
14407 :
14408 CBC 56 : resetPQExpBuffer(query);
14409 56 : appendPQExpBuffer(query,
14410 : "SELECT\n"
14411 : " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14412 ECB : " WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14413 : " m.mapdict::pg_catalog.regdictionary AS dictname\n"
14414 : "FROM pg_catalog.pg_ts_config_map AS m\n"
14415 : "WHERE m.mapcfg = '%u'\n"
14416 : "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14417 CBC 56 : cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14418 :
14419 56 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14420 GIC 56 : ntups = PQntuples(res);
14421 ECB :
14422 CBC 56 : i_tokenname = PQfnumber(res, "tokenname");
14423 56 : i_dictname = PQfnumber(res, "dictname");
14424 ECB :
14425 GIC 1255 : for (i = 0; i < ntups; i++)
14426 : {
14427 1199 : char *tokenname = PQgetvalue(res, i, i_tokenname);
14428 1199 : char *dictname = PQgetvalue(res, i, i_dictname);
14429 :
14430 1199 : if (i == 0 ||
14431 1143 : strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14432 : {
14433 ECB : /* starting a new token type, so start a new command */
14434 CBC 1064 : if (i > 0)
14435 1008 : appendPQExpBufferStr(q, ";\n");
14436 1064 : appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14437 1064 : fmtQualifiedDumpable(cfginfo));
14438 : /* tokenname needs quoting, dictname does NOT */
14439 1064 : appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
14440 EUB : fmtId(tokenname), dictname);
14441 : }
14442 : else
14443 GBC 135 : appendPQExpBuffer(q, ", %s", dictname);
14444 : }
14445 :
14446 GIC 56 : if (ntups > 0)
14447 56 : appendPQExpBufferStr(q, ";\n");
14448 :
14449 56 : PQclear(res);
14450 ECB :
14451 GIC 56 : appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14452 CBC 56 : fmtQualifiedDumpable(cfginfo));
14453 :
14454 56 : if (dopt->binary_upgrade)
14455 5 : binary_upgrade_extension_member(q, &cfginfo->dobj,
14456 : "TEXT SEARCH CONFIGURATION", qcfgname,
14457 5 : cfginfo->dobj.namespace->dobj.name);
14458 ECB :
14459 GIC 56 : if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14460 CBC 56 : ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14461 56 : ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
14462 ECB : .namespace = cfginfo->dobj.namespace->dobj.name,
14463 : .owner = cfginfo->rolname,
14464 : .description = "TEXT SEARCH CONFIGURATION",
14465 : .section = SECTION_PRE_DATA,
14466 : .createStmt = q->data,
14467 : .dropStmt = delq->data));
14468 :
14469 : /* Dump Configuration Comments */
14470 GIC 56 : if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14471 36 : dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14472 36 : cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14473 36 : cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14474 :
14475 56 : destroyPQExpBuffer(q);
14476 56 : destroyPQExpBuffer(delq);
14477 CBC 56 : destroyPQExpBuffer(query);
14478 GIC 56 : free(qcfgname);
14479 ECB : }
14480 :
14481 : /*
14482 : * dumpForeignDataWrapper
14483 : * write out a single foreign-data wrapper definition
14484 : */
14485 : static void
14486 CBC 45 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
14487 : {
14488 45 : DumpOptions *dopt = fout->dopt;
14489 ECB : PQExpBuffer q;
14490 : PQExpBuffer delq;
14491 : char *qfdwname;
14492 :
14493 : /* Do nothing in data-only dump */
14494 CBC 45 : if (dopt->dataOnly)
14495 GIC 4 : return;
14496 ECB :
14497 CBC 41 : q = createPQExpBuffer();
14498 41 : delq = createPQExpBuffer();
14499 ECB :
14500 CBC 41 : qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14501 ECB :
14502 CBC 41 : appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14503 EUB : qfdwname);
14504 :
14505 CBC 41 : if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14506 LBC 0 : appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14507 :
14508 CBC 41 : if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14509 LBC 0 : appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14510 :
14511 CBC 41 : if (strlen(fdwinfo->fdwoptions) > 0)
14512 LBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
14513 :
14514 CBC 41 : appendPQExpBufferStr(q, ";\n");
14515 :
14516 41 : appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14517 ECB : qfdwname);
14518 :
14519 GIC 41 : if (dopt->binary_upgrade)
14520 2 : binary_upgrade_extension_member(q, &fdwinfo->dobj,
14521 : "FOREIGN DATA WRAPPER", qfdwname,
14522 : NULL);
14523 :
14524 41 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14525 41 : ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14526 CBC 41 : ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
14527 ECB : .owner = fdwinfo->rolname,
14528 : .description = "FOREIGN DATA WRAPPER",
14529 : .section = SECTION_PRE_DATA,
14530 : .createStmt = q->data,
14531 : .dropStmt = delq->data));
14532 :
14533 : /* Dump Foreign Data Wrapper Comments */
14534 GIC 41 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14535 UIC 0 : dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14536 0 : NULL, fdwinfo->rolname,
14537 0 : fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14538 :
14539 : /* Handle the ACL */
14540 GIC 41 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14541 CBC 35 : dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
14542 : "FOREIGN DATA WRAPPER", qfdwname, NULL,
14543 35 : NULL, fdwinfo->rolname, &fdwinfo->dacl);
14544 :
14545 GIC 41 : free(qfdwname);
14546 :
14547 41 : destroyPQExpBuffer(q);
14548 41 : destroyPQExpBuffer(delq);
14549 : }
14550 :
14551 : /*
14552 : * dumpForeignServer
14553 ECB : * write out a foreign server definition
14554 : */
14555 : static void
14556 CBC 49 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
14557 ECB : {
14558 CBC 49 : DumpOptions *dopt = fout->dopt;
14559 : PQExpBuffer q;
14560 ECB : PQExpBuffer delq;
14561 : PQExpBuffer query;
14562 : PGresult *res;
14563 : char *qsrvname;
14564 : char *fdwname;
14565 :
14566 : /* Do nothing in data-only dump */
14567 CBC 49 : if (dopt->dataOnly)
14568 6 : return;
14569 ECB :
14570 GIC 43 : q = createPQExpBuffer();
14571 CBC 43 : delq = createPQExpBuffer();
14572 43 : query = createPQExpBuffer();
14573 :
14574 43 : qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14575 ECB :
14576 : /* look up the foreign-data wrapper */
14577 GIC 43 : appendPQExpBuffer(query, "SELECT fdwname "
14578 ECB : "FROM pg_foreign_data_wrapper w "
14579 : "WHERE w.oid = '%u'",
14580 GIC 43 : srvinfo->srvfdw);
14581 CBC 43 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
14582 43 : fdwname = PQgetvalue(res, 0, 0);
14583 :
14584 43 : appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14585 GIC 43 : if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14586 ECB : {
14587 LBC 0 : appendPQExpBufferStr(q, " TYPE ");
14588 UIC 0 : appendStringLiteralAH(q, srvinfo->srvtype, fout);
14589 ECB : }
14590 CBC 43 : if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14591 : {
14592 LBC 0 : appendPQExpBufferStr(q, " VERSION ");
14593 UIC 0 : appendStringLiteralAH(q, srvinfo->srvversion, fout);
14594 ECB : }
14595 :
14596 CBC 43 : appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14597 GIC 43 : appendPQExpBufferStr(q, fmtId(fdwname));
14598 :
14599 43 : if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14600 UIC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
14601 :
14602 GIC 43 : appendPQExpBufferStr(q, ";\n");
14603 :
14604 43 : appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14605 ECB : qsrvname);
14606 :
14607 CBC 43 : if (dopt->binary_upgrade)
14608 2 : binary_upgrade_extension_member(q, &srvinfo->dobj,
14609 : "SERVER", qsrvname, NULL);
14610 ECB :
14611 CBC 43 : if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14612 43 : ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14613 43 : ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
14614 : .owner = srvinfo->rolname,
14615 : .description = "SERVER",
14616 : .section = SECTION_PRE_DATA,
14617 : .createStmt = q->data,
14618 : .dropStmt = delq->data));
14619 :
14620 : /* Dump Foreign Server Comments */
14621 43 : if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14622 UIC 0 : dumpComment(fout, "SERVER", qsrvname,
14623 LBC 0 : NULL, srvinfo->rolname,
14624 UIC 0 : srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14625 :
14626 : /* Handle the ACL */
14627 GIC 43 : if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14628 35 : dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
14629 ECB : "FOREIGN SERVER", qsrvname, NULL,
14630 CBC 35 : NULL, srvinfo->rolname, &srvinfo->dacl);
14631 :
14632 ECB : /* Dump user mappings */
14633 CBC 43 : if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14634 GIC 43 : dumpUserMappings(fout,
14635 CBC 43 : srvinfo->dobj.name, NULL,
14636 GIC 43 : srvinfo->rolname,
14637 CBC 43 : srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14638 ECB :
14639 GIC 43 : PQclear(res);
14640 ECB :
14641 GBC 43 : free(qsrvname);
14642 EUB :
14643 CBC 43 : destroyPQExpBuffer(q);
14644 43 : destroyPQExpBuffer(delq);
14645 GIC 43 : destroyPQExpBuffer(query);
14646 ECB : }
14647 :
14648 : /*
14649 : * dumpUserMappings
14650 : *
14651 : * This routine is used to dump any user mappings associated with the
14652 : * server handed to this routine. Should be called after ArchiveEntry()
14653 : * for the server.
14654 : */
14655 : static void
14656 CBC 43 : dumpUserMappings(Archive *fout,
14657 : const char *servername, const char *namespace,
14658 : const char *owner,
14659 : CatalogId catalogId, DumpId dumpId)
14660 : {
14661 : PQExpBuffer q;
14662 : PQExpBuffer delq;
14663 : PQExpBuffer query;
14664 ECB : PQExpBuffer tag;
14665 : PGresult *res;
14666 : int ntups;
14667 : int i_usename;
14668 : int i_umoptions;
14669 : int i;
14670 :
14671 CBC 43 : q = createPQExpBuffer();
14672 GIC 43 : tag = createPQExpBuffer();
14673 43 : delq = createPQExpBuffer();
14674 43 : query = createPQExpBuffer();
14675 :
14676 : /*
14677 : * We read from the publicly accessible view pg_user_mappings, so as not
14678 : * to fail if run by a non-superuser. Note that the view will show
14679 ECB : * umoptions as null if the user hasn't got privileges for the associated
14680 : * server; this means that pg_dump will dump such a mapping, but with no
14681 : * OPTIONS clause. A possible alternative is to skip such mappings
14682 : * altogether, but it's not clear that that's an improvement.
14683 : */
14684 GIC 43 : appendPQExpBuffer(query,
14685 : "SELECT usename, "
14686 : "array_to_string(ARRAY("
14687 : "SELECT quote_ident(option_name) || ' ' || "
14688 : "quote_literal(option_value) "
14689 : "FROM pg_options_to_table(umoptions) "
14690 : "ORDER BY option_name"
14691 : "), E',\n ') AS umoptions "
14692 : "FROM pg_user_mappings "
14693 : "WHERE srvid = '%u' "
14694 : "ORDER BY usename",
14695 ECB : catalogId.oid);
14696 :
14697 GIC 43 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14698 ECB :
14699 CBC 43 : ntups = PQntuples(res);
14700 43 : i_usename = PQfnumber(res, "usename");
14701 GIC 43 : i_umoptions = PQfnumber(res, "umoptions");
14702 ECB :
14703 GIC 78 : for (i = 0; i < ntups; i++)
14704 : {
14705 ECB : char *usename;
14706 : char *umoptions;
14707 :
14708 CBC 35 : usename = PQgetvalue(res, i, i_usename);
14709 35 : umoptions = PQgetvalue(res, i, i_umoptions);
14710 ECB :
14711 CBC 35 : resetPQExpBuffer(q);
14712 GIC 35 : appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14713 CBC 35 : appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14714 ECB :
14715 GIC 35 : if (umoptions && strlen(umoptions) > 0)
14716 LBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
14717 ECB :
14718 GIC 35 : appendPQExpBufferStr(q, ";\n");
14719 ECB :
14720 GIC 35 : resetPQExpBuffer(delq);
14721 CBC 35 : appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14722 35 : appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14723 :
14724 GIC 35 : resetPQExpBuffer(tag);
14725 35 : appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14726 : usename, servername);
14727 :
14728 35 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
14729 35 : ARCHIVE_OPTS(.tag = tag->data,
14730 ECB : .namespace = namespace,
14731 : .owner = owner,
14732 : .description = "USER MAPPING",
14733 : .section = SECTION_PRE_DATA,
14734 : .createStmt = q->data,
14735 : .dropStmt = delq->data));
14736 : }
14737 :
14738 CBC 43 : PQclear(res);
14739 :
14740 43 : destroyPQExpBuffer(query);
14741 43 : destroyPQExpBuffer(delq);
14742 GIC 43 : destroyPQExpBuffer(tag);
14743 CBC 43 : destroyPQExpBuffer(q);
14744 43 : }
14745 :
14746 : /*
14747 ECB : * Write out default privileges information
14748 : */
14749 : static void
14750 CBC 154 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
14751 : {
14752 154 : DumpOptions *dopt = fout->dopt;
14753 : PQExpBuffer q;
14754 : PQExpBuffer tag;
14755 : const char *type;
14756 ECB :
14757 : /* Do nothing in data-only dump, or if we're skipping ACLs */
14758 GIC 154 : if (dopt->dataOnly || dopt->aclsSkip)
14759 CBC 16 : return;
14760 ECB :
14761 GIC 138 : q = createPQExpBuffer();
14762 CBC 138 : tag = createPQExpBuffer();
14763 :
14764 138 : switch (daclinfo->defaclobjtype)
14765 ECB : {
14766 GIC 69 : case DEFACLOBJ_RELATION:
14767 CBC 69 : type = "TABLES";
14768 69 : break;
14769 UIC 0 : case DEFACLOBJ_SEQUENCE:
14770 LBC 0 : type = "SEQUENCES";
14771 UIC 0 : break;
14772 CBC 69 : case DEFACLOBJ_FUNCTION:
14773 69 : type = "FUNCTIONS";
14774 69 : break;
14775 UIC 0 : case DEFACLOBJ_TYPE:
14776 0 : type = "TYPES";
14777 0 : break;
14778 0 : case DEFACLOBJ_NAMESPACE:
14779 0 : type = "SCHEMAS";
14780 0 : break;
14781 0 : default:
14782 : /* shouldn't get here */
14783 LBC 0 : pg_fatal("unrecognized object type in default privileges: %d",
14784 ECB : (int) daclinfo->defaclobjtype);
14785 : type = ""; /* keep compiler quiet */
14786 : }
14787 :
14788 CBC 138 : appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14789 ECB :
14790 : /* build the actual command(s) for this tuple */
14791 CBC 138 : if (!buildDefaultACLCommands(type,
14792 GIC 138 : daclinfo->dobj.namespace != NULL ?
14793 70 : daclinfo->dobj.namespace->dobj.name : NULL,
14794 138 : daclinfo->dacl.acl,
14795 138 : daclinfo->dacl.acldefault,
14796 138 : daclinfo->defaclrole,
14797 : fout->remoteVersion,
14798 : q))
14799 LBC 0 : pg_fatal("could not parse default ACL list (%s)",
14800 : daclinfo->dacl.acl);
14801 ECB :
14802 GIC 138 : if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14803 138 : ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14804 138 : ARCHIVE_OPTS(.tag = tag->data,
14805 : .namespace = daclinfo->dobj.namespace ?
14806 : daclinfo->dobj.namespace->dobj.name : NULL,
14807 ECB : .owner = daclinfo->defaclrole,
14808 : .description = "DEFAULT ACL",
14809 : .section = SECTION_POST_DATA,
14810 : .createStmt = q->data));
14811 :
14812 GIC 138 : destroyPQExpBuffer(tag);
14813 CBC 138 : destroyPQExpBuffer(q);
14814 : }
14815 ECB :
14816 : /*----------
14817 : * Write out grant/revoke information
14818 : *
14819 EUB : * 'objDumpId' is the dump ID of the underlying object.
14820 : * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
14821 ECB : * or InvalidDumpId if there is no need for a second dependency.
14822 EUB : * 'type' must be one of
14823 : * TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14824 ECB : * FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14825 EUB : * 'name' is the formatted name of the object. Must be quoted etc. already.
14826 : * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
14827 ECB : * (Currently we assume that subname is only provided for table columns.)
14828 : * 'nspname' is the namespace the object is in (NULL if none).
14829 : * 'owner' is the owner, NULL if there is no owner (for languages).
14830 : * 'dacl' is the DumpableAcl struct fpr the object.
14831 : *
14832 : * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
14833 : * no ACL entry was created.
14834 : *----------
14835 : */
14836 : static DumpId
14837 CBC 18280 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
14838 ECB : const char *type, const char *name, const char *subname,
14839 : const char *nspname, const char *owner,
14840 : const DumpableAcl *dacl)
14841 : {
14842 GIC 18280 : DumpId aclDumpId = InvalidDumpId;
14843 18280 : DumpOptions *dopt = fout->dopt;
14844 18280 : const char *acls = dacl->acl;
14845 18280 : const char *acldefault = dacl->acldefault;
14846 18280 : char privtype = dacl->privtype;
14847 CBC 18280 : const char *initprivs = dacl->initprivs;
14848 EUB : const char *baseacls;
14849 : PQExpBuffer sql;
14850 :
14851 : /* Do nothing if ACL dump is not enabled */
14852 GIC 18280 : if (dopt->aclsSkip)
14853 CBC 312 : return InvalidDumpId;
14854 ECB :
14855 : /* --data-only skips ACLs *except* large object ACLs */
14856 CBC 17968 : if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14857 UIC 0 : return InvalidDumpId;
14858 ECB :
14859 GIC 17968 : sql = createPQExpBuffer();
14860 ECB :
14861 : /*
14862 : * In binary upgrade mode, we don't run an extension's script but instead
14863 : * dump out the objects independently and then recreate them. To preserve
14864 : * any initial privileges which were set on extension objects, we need to
14865 : * compute the set of GRANT and REVOKE commands necessary to get from the
14866 : * default privileges of an object to its initial privileges as recorded
14867 : * in pg_init_privs.
14868 : *
14869 : * At restore time, we apply these commands after having called
14870 : * binary_upgrade_set_record_init_privs(true). That tells the backend to
14871 : * copy the results into pg_init_privs. This is how we preserve the
14872 : * contents of that catalog across binary upgrades.
14873 : */
14874 GIC 17968 : if (dopt->binary_upgrade && privtype == 'e' &&
14875 11 : initprivs && *initprivs != '\0')
14876 : {
14877 11 : appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14878 11 : if (!buildACLCommands(name, subname, nspname, type,
14879 : initprivs, acldefault, owner,
14880 ECB : "", fout->remoteVersion, sql))
14881 LBC 0 : pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
14882 : initprivs, acldefault, name, type);
14883 CBC 11 : appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14884 ECB : }
14885 :
14886 : /*
14887 : * Now figure the GRANT and REVOKE commands needed to get to the object's
14888 : * actual current ACL, starting from the initprivs if given, else from the
14889 : * object-type-specific default. Also, while buildACLCommands will assume
14890 : * that a NULL/empty acls string means it needn't do anything, what that
14891 : * actually represents is the object-type-specific default; so we need to
14892 : * substitute the acldefault string to get the right results in that case.
14893 : */
14894 CBC 17968 : if (initprivs && *initprivs != '\0')
14895 ECB : {
14896 GIC 16166 : baseacls = initprivs;
14897 CBC 16166 : if (acls == NULL || *acls == '\0')
14898 16 : acls = acldefault;
14899 : }
14900 EUB : else
14901 GBC 1802 : baseacls = acldefault;
14902 :
14903 CBC 17968 : if (!buildACLCommands(name, subname, nspname, type,
14904 : acls, baseacls, owner,
14905 EUB : "", fout->remoteVersion, sql))
14906 UBC 0 : pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
14907 : acls, baseacls, name, type);
14908 :
14909 CBC 17968 : if (sql->len > 0)
14910 ECB : {
14911 GIC 1886 : PQExpBuffer tag = createPQExpBuffer();
14912 ECB : DumpId aclDeps[2];
14913 GBC 1886 : int nDeps = 0;
14914 :
14915 CBC 1886 : if (subname)
14916 GIC 1102 : appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
14917 ECB : else
14918 GIC 784 : appendPQExpBuffer(tag, "%s %s", type, name);
14919 :
14920 CBC 1886 : aclDeps[nDeps++] = objDumpId;
14921 1886 : if (altDumpId != InvalidDumpId)
14922 GIC 1022 : aclDeps[nDeps++] = altDumpId;
14923 :
14924 CBC 1886 : aclDumpId = createDumpId();
14925 ECB :
14926 CBC 1886 : ArchiveEntry(fout, nilCatalogId, aclDumpId,
14927 GIC 1886 : ARCHIVE_OPTS(.tag = tag->data,
14928 : .namespace = nspname,
14929 : .owner = owner,
14930 : .description = "ACL",
14931 : .section = SECTION_NONE,
14932 : .createStmt = sql->data,
14933 : .deps = aclDeps,
14934 ECB : .nDeps = nDeps));
14935 EUB :
14936 GBC 1886 : destroyPQExpBuffer(tag);
14937 EUB : }
14938 :
14939 GIC 17968 : destroyPQExpBuffer(sql);
14940 ECB :
14941 CBC 17968 : return aclDumpId;
14942 : }
14943 ECB :
14944 : /*
14945 : * dumpSecLabel
14946 : *
14947 : * This routine is used to dump any security labels associated with the
14948 : * object handed to this routine. The routine takes the object type
14949 : * and object name (ready to print, except for schema decoration), plus
14950 : * the namespace and owner of the object (for labeling the ArchiveEntry),
14951 : * plus catalog ID and subid which are the lookup key for pg_seclabel,
14952 : * plus the dump ID for the object (for setting a dependency).
14953 : * If a matching pg_seclabel entry is found, it is dumped.
14954 : *
14955 : * Note: although this routine takes a dumpId for dependency purposes,
14956 : * that purpose is just to mark the dependency in the emitted dump file
14957 : * for possible future use by pg_restore. We do NOT use it for determining
14958 : * ordering of the label in the dump file, because this routine is called
14959 : * after dependency sorting occurs. This routine should be called just after
14960 : * calling ArchiveEntry() for the specified object.
14961 : */
14962 : static void
14963 UIC 0 : dumpSecLabel(Archive *fout, const char *type, const char *name,
14964 : const char *namespace, const char *owner,
14965 : CatalogId catalogId, int subid, DumpId dumpId)
14966 : {
14967 0 : DumpOptions *dopt = fout->dopt;
14968 : SecLabelItem *labels;
14969 ECB : int nlabels;
14970 : int i;
14971 : PQExpBuffer query;
14972 :
14973 : /* do nothing, if --no-security-labels is supplied */
14974 UIC 0 : if (dopt->no_security_labels)
14975 0 : return;
14976 :
14977 : /* Security labels are schema not data ... except large object labels are data */
14978 0 : if (strcmp(type, "LARGE OBJECT") != 0)
14979 : {
14980 0 : if (dopt->dataOnly)
14981 0 : return;
14982 : }
14983 : else
14984 ECB : {
14985 : /* We do dump large object security labels in binary-upgrade mode */
14986 LBC 0 : if (dopt->schemaOnly && !dopt->binary_upgrade)
14987 0 : return;
14988 : }
14989 :
14990 : /* Search for security labels associated with catalogId, using table */
14991 UIC 0 : nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
14992 :
14993 0 : query = createPQExpBuffer();
14994 :
14995 0 : for (i = 0; i < nlabels; i++)
14996 : {
14997 ECB : /*
14998 : * Ignore label entries for which the subid doesn't match.
14999 : */
15000 UIC 0 : if (labels[i].objsubid != subid)
15001 0 : continue;
15002 :
15003 0 : appendPQExpBuffer(query,
15004 : "SECURITY LABEL FOR %s ON %s ",
15005 0 : fmtId(labels[i].provider), type);
15006 0 : if (namespace && *namespace)
15007 0 : appendPQExpBuffer(query, "%s.", fmtId(namespace));
15008 0 : appendPQExpBuffer(query, "%s IS ", name);
15009 0 : appendStringLiteralAH(query, labels[i].label, fout);
15010 LBC 0 : appendPQExpBufferStr(query, ";\n");
15011 : }
15012 ECB :
15013 LBC 0 : if (query->len > 0)
15014 ECB : {
15015 UIC 0 : PQExpBuffer tag = createPQExpBuffer();
15016 ECB :
15017 UIC 0 : appendPQExpBuffer(tag, "%s %s", type, name);
15018 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
15019 0 : ARCHIVE_OPTS(.tag = tag->data,
15020 : .namespace = namespace,
15021 ECB : .owner = owner,
15022 : .description = "SECURITY LABEL",
15023 : .section = SECTION_NONE,
15024 : .createStmt = query->data,
15025 : .deps = &dumpId,
15026 : .nDeps = 1));
15027 UIC 0 : destroyPQExpBuffer(tag);
15028 ECB : }
15029 EUB :
15030 UIC 0 : destroyPQExpBuffer(query);
15031 ECB : }
15032 :
15033 : /*
15034 : * dumpTableSecLabel
15035 : *
15036 : * As above, but dump security label for both the specified table (or view)
15037 : * and its columns.
15038 : */
15039 : static void
15040 UIC 0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
15041 ECB : {
15042 LBC 0 : DumpOptions *dopt = fout->dopt;
15043 : SecLabelItem *labels;
15044 : int nlabels;
15045 : int i;
15046 : PQExpBuffer query;
15047 : PQExpBuffer target;
15048 :
15049 : /* do nothing, if --no-security-labels is supplied */
15050 UIC 0 : if (dopt->no_security_labels)
15051 LBC 0 : return;
15052 :
15053 ECB : /* SecLabel are SCHEMA not data */
15054 LBC 0 : if (dopt->dataOnly)
15055 0 : return;
15056 ECB :
15057 : /* Search for comments associated with relation, using table */
15058 UIC 0 : nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
15059 0 : tbinfo->dobj.catId.oid,
15060 : &labels);
15061 :
15062 : /* If security labels exist, build SECURITY LABEL statements */
15063 LBC 0 : if (nlabels <= 0)
15064 UIC 0 : return;
15065 ECB :
15066 UIC 0 : query = createPQExpBuffer();
15067 0 : target = createPQExpBuffer();
15068 :
15069 0 : for (i = 0; i < nlabels; i++)
15070 : {
15071 ECB : const char *colname;
15072 LBC 0 : const char *provider = labels[i].provider;
15073 UIC 0 : const char *label = labels[i].label;
15074 LBC 0 : int objsubid = labels[i].objsubid;
15075 ECB :
15076 UIC 0 : resetPQExpBuffer(target);
15077 LBC 0 : if (objsubid == 0)
15078 : {
15079 0 : appendPQExpBuffer(target, "%s %s", reltypename,
15080 0 : fmtQualifiedDumpable(tbinfo));
15081 ECB : }
15082 EUB : else
15083 : {
15084 UBC 0 : colname = getAttrName(objsubid, tbinfo);
15085 ECB : /* first fmtXXX result must be consumed before calling again */
15086 LBC 0 : appendPQExpBuffer(target, "COLUMN %s",
15087 0 : fmtQualifiedDumpable(tbinfo));
15088 UBC 0 : appendPQExpBuffer(target, ".%s", fmtId(colname));
15089 EUB : }
15090 UBC 0 : appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
15091 EUB : fmtId(provider), target->data);
15092 UBC 0 : appendStringLiteralAH(query, label, fout);
15093 0 : appendPQExpBufferStr(query, ";\n");
15094 EUB : }
15095 UIC 0 : if (query->len > 0)
15096 EUB : {
15097 UIC 0 : resetPQExpBuffer(target);
15098 0 : appendPQExpBuffer(target, "%s %s", reltypename,
15099 0 : fmtId(tbinfo->dobj.name));
15100 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
15101 LBC 0 : ARCHIVE_OPTS(.tag = target->data,
15102 : .namespace = tbinfo->dobj.namespace->dobj.name,
15103 : .owner = tbinfo->rolname,
15104 ECB : .description = "SECURITY LABEL",
15105 : .section = SECTION_NONE,
15106 : .createStmt = query->data,
15107 : .deps = &(tbinfo->dobj.dumpId),
15108 : .nDeps = 1));
15109 : }
15110 UIC 0 : destroyPQExpBuffer(query);
15111 0 : destroyPQExpBuffer(target);
15112 EUB : }
15113 :
15114 : /*
15115 ECB : * findSecLabels
15116 : *
15117 : * Find the security label(s), if any, associated with the given object.
15118 : * All the objsubid values associated with the given classoid/objoid are
15119 : * found with one search.
15120 : */
15121 : static int
15122 UIC 0 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
15123 : {
15124 0 : SecLabelItem *middle = NULL;
15125 ECB : SecLabelItem *low;
15126 : SecLabelItem *high;
15127 : int nmatch;
15128 :
15129 UIC 0 : if (nseclabels <= 0) /* no labels, so no match is possible */
15130 : {
15131 0 : *items = NULL;
15132 0 : return 0;
15133 : }
15134 :
15135 : /*
15136 : * Do binary search to find some item matching the object.
15137 : */
15138 0 : low = &seclabels[0];
15139 0 : high = &seclabels[nseclabels - 1];
15140 0 : while (low <= high)
15141 : {
15142 0 : middle = low + (high - low) / 2;
15143 :
15144 0 : if (classoid < middle->classoid)
15145 0 : high = middle - 1;
15146 0 : else if (classoid > middle->classoid)
15147 0 : low = middle + 1;
15148 0 : else if (objoid < middle->objoid)
15149 0 : high = middle - 1;
15150 LBC 0 : else if (objoid > middle->objoid)
15151 UIC 0 : low = middle + 1;
15152 : else
15153 0 : break; /* found a match */
15154 : }
15155 ECB :
15156 LBC 0 : if (low > high) /* no matches */
15157 ECB : {
15158 LBC 0 : *items = NULL;
15159 0 : return 0;
15160 ECB : }
15161 :
15162 : /*
15163 : * Now determine how many items match the object. The search loop
15164 : * invariant still holds: only items between low and high inclusive could
15165 : * match.
15166 : */
15167 UIC 0 : nmatch = 1;
15168 0 : while (middle > low)
15169 ECB : {
15170 UBC 0 : if (classoid != middle[-1].classoid ||
15171 UIC 0 : objoid != middle[-1].objoid)
15172 ECB : break;
15173 UIC 0 : middle--;
15174 0 : nmatch++;
15175 : }
15176 :
15177 0 : *items = middle;
15178 :
15179 0 : middle += nmatch;
15180 0 : while (middle <= high)
15181 : {
15182 0 : if (classoid != middle->classoid ||
15183 0 : objoid != middle->objoid)
15184 : break;
15185 0 : middle++;
15186 0 : nmatch++;
15187 ECB : }
15188 :
15189 UIC 0 : return nmatch;
15190 ECB : }
15191 :
15192 : /*
15193 : * collectSecLabels
15194 EUB : *
15195 : * Construct a table of all security labels available for database objects;
15196 ECB : * also set the has-seclabel component flag for each relevant object.
15197 : *
15198 : * The table is sorted by classoid/objid/objsubid for speed in lookup.
15199 : */
15200 : static void
15201 GIC 118 : collectSecLabels(Archive *fout)
15202 : {
15203 : PGresult *res;
15204 : PQExpBuffer query;
15205 : int i_label;
15206 : int i_provider;
15207 ECB : int i_classoid;
15208 : int i_objoid;
15209 : int i_objsubid;
15210 : int ntups;
15211 : int i;
15212 : DumpableObject *dobj;
15213 :
15214 CBC 118 : query = createPQExpBuffer();
15215 :
15216 118 : appendPQExpBufferStr(query,
15217 : "SELECT label, provider, classoid, objoid, objsubid "
15218 : "FROM pg_catalog.pg_seclabel "
15219 EUB : "ORDER BY classoid, objoid, objsubid");
15220 :
15221 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15222 ECB :
15223 : /* Construct lookup table containing OIDs in numeric form */
15224 CBC 118 : i_label = PQfnumber(res, "label");
15225 GIC 118 : i_provider = PQfnumber(res, "provider");
15226 CBC 118 : i_classoid = PQfnumber(res, "classoid");
15227 GIC 118 : i_objoid = PQfnumber(res, "objoid");
15228 CBC 118 : i_objsubid = PQfnumber(res, "objsubid");
15229 ECB :
15230 GIC 118 : ntups = PQntuples(res);
15231 ECB :
15232 GIC 118 : seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15233 CBC 118 : nseclabels = 0;
15234 118 : dobj = NULL;
15235 ECB :
15236 GIC 118 : for (i = 0; i < ntups; i++)
15237 ECB : {
15238 : CatalogId objId;
15239 : int subid;
15240 :
15241 UIC 0 : objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
15242 0 : objId.oid = atooid(PQgetvalue(res, i, i_objoid));
15243 0 : subid = atoi(PQgetvalue(res, i, i_objsubid));
15244 :
15245 : /* We needn't remember labels that don't match any dumpable object */
15246 0 : if (dobj == NULL ||
15247 0 : dobj->catId.tableoid != objId.tableoid ||
15248 0 : dobj->catId.oid != objId.oid)
15249 LBC 0 : dobj = findObjectByCatalogId(objId);
15250 UIC 0 : if (dobj == NULL)
15251 0 : continue;
15252 ECB :
15253 : /*
15254 : * Labels on columns of composite types are linked to the type's
15255 : * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
15256 : * in the type's own DumpableObject.
15257 : */
15258 UIC 0 : if (subid != 0 && dobj->objType == DO_TABLE &&
15259 0 : ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
15260 0 : {
15261 : TypeInfo *cTypeInfo;
15262 :
15263 0 : cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
15264 0 : if (cTypeInfo)
15265 0 : cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
15266 : }
15267 : else
15268 0 : dobj->components |= DUMP_COMPONENT_SECLABEL;
15269 :
15270 0 : seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
15271 0 : seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
15272 0 : seclabels[nseclabels].classoid = objId.tableoid;
15273 0 : seclabels[nseclabels].objoid = objId.oid;
15274 0 : seclabels[nseclabels].objsubid = subid;
15275 0 : nseclabels++;
15276 EUB : }
15277 :
15278 GIC 118 : PQclear(res);
15279 118 : destroyPQExpBuffer(query);
15280 GBC 118 : }
15281 :
15282 : /*
15283 : * dumpTable
15284 : * write out to fout the declarations (not data) of a user-defined table
15285 : */
15286 : static void
15287 20378 : dumpTable(Archive *fout, const TableInfo *tbinfo)
15288 EUB : {
15289 GIC 20378 : DumpOptions *dopt = fout->dopt;
15290 20378 : DumpId tableAclDumpId = InvalidDumpId;
15291 EUB : char *namecopy;
15292 :
15293 : /* Do nothing in data-only dump */
15294 GBC 20378 : if (dopt->dataOnly)
15295 GIC 831 : return;
15296 :
15297 19547 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15298 : {
15299 GBC 5015 : if (tbinfo->relkind == RELKIND_SEQUENCE)
15300 315 : dumpSequence(fout, tbinfo);
15301 : else
15302 GIC 4700 : dumpTableSchema(fout, tbinfo);
15303 : }
15304 EUB :
15305 : /* Handle the ACL here */
15306 GBC 19547 : namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15307 GIC 19547 : if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15308 EUB : {
15309 GIC 14841 : const char *objtype =
15310 14841 : (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15311 :
15312 : tableAclDumpId =
15313 GBC 14841 : dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
15314 EUB : objtype, namecopy, NULL,
15315 GIC 14841 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15316 EUB : &tbinfo->dacl);
15317 : }
15318 :
15319 : /*
15320 : * Handle column ACLs, if any. Note: we pull these with a separate query
15321 : * rather than trying to fetch them during getTableAttrs, so that we won't
15322 : * miss ACLs on system columns. Doing it this way also allows us to dump
15323 : * ACLs for catalogs that we didn't mark "interesting" back in getTables.
15324 : */
15325 GIC 19547 : if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
15326 EUB : {
15327 GIC 196 : PQExpBuffer query = createPQExpBuffer();
15328 EUB : PGresult *res;
15329 : int i;
15330 :
15331 GBC 196 : if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
15332 EUB : {
15333 : /* Set up query for column ACLs */
15334 GIC 103 : appendPQExpBufferStr(query,
15335 : "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
15336 :
15337 103 : if (fout->remoteVersion >= 90600)
15338 : {
15339 : /*
15340 EUB : * In principle we should call acldefault('c', relowner) to
15341 : * get the default ACL for a column. However, we don't
15342 : * currently store the numeric OID of the relowner in
15343 : * TableInfo. We could convert the owner name using regrole,
15344 : * but that creates a risk of failure due to concurrent role
15345 : * renames. Given that the default ACL for columns is empty
15346 : * and is likely to stay that way, it's not worth extra cycles
15347 : * and risk to avoid hard-wiring that knowledge here.
15348 : */
15349 GIC 103 : appendPQExpBufferStr(query,
15350 : "SELECT at.attname, "
15351 : "at.attacl, "
15352 : "'{}' AS acldefault, "
15353 EUB : "pip.privtype, pip.initprivs "
15354 : "FROM pg_catalog.pg_attribute at "
15355 : "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15356 : "(at.attrelid = pip.objoid "
15357 : "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15358 : "AND at.attnum = pip.objsubid) "
15359 : "WHERE at.attrelid = $1 AND "
15360 : "NOT at.attisdropped "
15361 : "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
15362 : "ORDER BY at.attnum");
15363 : }
15364 : else
15365 : {
15366 UIC 0 : appendPQExpBufferStr(query,
15367 EUB : "SELECT attname, attacl, '{}' AS acldefault, "
15368 : "NULL AS privtype, NULL AS initprivs "
15369 : "FROM pg_catalog.pg_attribute "
15370 : "WHERE attrelid = $1 AND NOT attisdropped "
15371 : "AND attacl IS NOT NULL "
15372 : "ORDER BY attnum");
15373 : }
15374 :
15375 GIC 103 : ExecuteSqlStatement(fout, query->data);
15376 EUB :
15377 GBC 103 : fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
15378 : }
15379 EUB :
15380 GBC 196 : printfPQExpBuffer(query,
15381 : "EXECUTE getColumnACLs('%u')",
15382 196 : tbinfo->dobj.catId.oid);
15383 :
15384 GIC 196 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15385 EUB :
15386 GBC 2914 : for (i = 0; i < PQntuples(res); i++)
15387 EUB : {
15388 GIC 2718 : char *attname = PQgetvalue(res, i, 0);
15389 GBC 2718 : char *attacl = PQgetvalue(res, i, 1);
15390 2718 : char *acldefault = PQgetvalue(res, i, 2);
15391 GIC 2718 : char privtype = *(PQgetvalue(res, i, 3));
15392 GBC 2718 : char *initprivs = PQgetvalue(res, i, 4);
15393 EUB : DumpableAcl coldacl;
15394 : char *attnamecopy;
15395 :
15396 GIC 2718 : coldacl.acl = attacl;
15397 GBC 2718 : coldacl.acldefault = acldefault;
15398 GIC 2718 : coldacl.privtype = privtype;
15399 GBC 2718 : coldacl.initprivs = initprivs;
15400 2718 : attnamecopy = pg_strdup(fmtId(attname));
15401 EUB :
15402 : /*
15403 : * Column's GRANT type is always TABLE. Each column ACL depends
15404 : * on the table-level ACL, since we can restore column ACLs in
15405 : * parallel but the table-level ACL has to be done first.
15406 : */
15407 GIC 2718 : dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
15408 EUB : "TABLE", namecopy, attnamecopy,
15409 GIC 2718 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15410 EUB : &coldacl);
15411 GBC 2718 : free(attnamecopy);
15412 EUB : }
15413 GBC 196 : PQclear(res);
15414 196 : destroyPQExpBuffer(query);
15415 : }
15416 :
15417 GIC 19547 : free(namecopy);
15418 : }
15419 :
15420 : /*
15421 : * Create the AS clause for a view or materialized view. The semicolon is
15422 : * stripped because a materialized view must add a WITH NO DATA clause.
15423 EUB : *
15424 : * This returns a new buffer which must be freed by the caller.
15425 : */
15426 : static PQExpBuffer
15427 GIC 599 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
15428 : {
15429 599 : PQExpBuffer query = createPQExpBuffer();
15430 599 : PQExpBuffer result = createPQExpBuffer();
15431 : PGresult *res;
15432 : int len;
15433 :
15434 : /* Fetch the view definition */
15435 GBC 599 : appendPQExpBuffer(query,
15436 : "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15437 599 : tbinfo->dobj.catId.oid);
15438 :
15439 GIC 599 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15440 :
15441 599 : if (PQntuples(res) != 1)
15442 EUB : {
15443 UIC 0 : if (PQntuples(res) < 1)
15444 UBC 0 : pg_fatal("query to obtain definition of view \"%s\" returned no data",
15445 EUB : tbinfo->dobj.name);
15446 : else
15447 UIC 0 : pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
15448 : tbinfo->dobj.name);
15449 : }
15450 :
15451 GBC 599 : len = PQgetlength(res, 0, 0);
15452 EUB :
15453 GBC 599 : if (len == 0)
15454 UIC 0 : pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
15455 EUB : tbinfo->dobj.name);
15456 :
15457 : /* Strip off the trailing semicolon so that other things may follow. */
15458 GBC 599 : Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15459 599 : appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15460 EUB :
15461 GBC 599 : PQclear(res);
15462 599 : destroyPQExpBuffer(query);
15463 EUB :
15464 GBC 599 : return result;
15465 : }
15466 EUB :
15467 : /*
15468 : * Create a dummy AS clause for a view. This is used when the real view
15469 : * definition has to be postponed because of circular dependencies.
15470 : * We must duplicate the view's external properties -- column names and types
15471 : * (including collation) -- so that it works for subsequent references.
15472 : *
15473 : * This returns a new buffer which must be freed by the caller.
15474 : */
15475 : static PQExpBuffer
15476 GIC 20 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
15477 : {
15478 20 : PQExpBuffer result = createPQExpBuffer();
15479 : int j;
15480 EUB :
15481 GBC 20 : appendPQExpBufferStr(result, "SELECT");
15482 :
15483 40 : for (j = 0; j < tbinfo->numatts; j++)
15484 EUB : {
15485 GIC 20 : if (j > 0)
15486 GBC 10 : appendPQExpBufferChar(result, ',');
15487 20 : appendPQExpBufferStr(result, "\n ");
15488 :
15489 GIC 20 : appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15490 EUB :
15491 : /*
15492 : * Must add collation if not default for the type, because CREATE OR
15493 : * REPLACE VIEW won't change it
15494 : */
15495 GBC 20 : if (OidIsValid(tbinfo->attcollation[j]))
15496 EUB : {
15497 : CollInfo *coll;
15498 :
15499 UBC 0 : coll = findCollationByOid(tbinfo->attcollation[j]);
15500 UIC 0 : if (coll)
15501 0 : appendPQExpBuffer(result, " COLLATE %s",
15502 UBC 0 : fmtQualifiedDumpable(coll));
15503 : }
15504 :
15505 GIC 20 : appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15506 : }
15507 :
15508 20 : return result;
15509 : }
15510 :
15511 : /*
15512 : * dumpTableSchema
15513 : * write the declaration (not data) of one user-defined table or view
15514 ECB : */
15515 : static void
15516 GIC 4700 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
15517 : {
15518 4700 : DumpOptions *dopt = fout->dopt;
15519 4700 : PQExpBuffer q = createPQExpBuffer();
15520 4700 : PQExpBuffer delq = createPQExpBuffer();
15521 : char *qrelname;
15522 : char *qualrelname;
15523 : int numParents;
15524 : TableInfo **parents;
15525 : int actual_atts; /* number of attrs in this CREATE statement */
15526 : const char *reltypename;
15527 ECB : char *storage;
15528 : int j,
15529 : k;
15530 :
15531 : /* We had better have loaded per-column details about this table */
15532 GIC 4700 : Assert(tbinfo->interesting);
15533 :
15534 CBC 4700 : qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15535 GIC 4700 : qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15536 :
15537 CBC 4700 : if (tbinfo->hasoids)
15538 LBC 0 : pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
15539 ECB : qrelname);
15540 :
15541 CBC 4700 : if (dopt->binary_upgrade)
15542 GIC 709 : binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
15543 ECB :
15544 : /* Is it a table or a view? */
15545 CBC 4700 : if (tbinfo->relkind == RELKIND_VIEW)
15546 ECB : {
15547 : PQExpBuffer result;
15548 :
15549 : /*
15550 : * Note: keep this code in sync with the is_view case in dumpRule()
15551 : */
15552 :
15553 GIC 271 : reltypename = "VIEW";
15554 EUB :
15555 GBC 271 : appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15556 EUB :
15557 GIC 271 : if (dopt->binary_upgrade)
15558 48 : binary_upgrade_set_pg_class_oids(fout, q,
15559 GBC 48 : tbinfo->dobj.catId.oid, false);
15560 EUB :
15561 GBC 271 : appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15562 EUB :
15563 GBC 271 : if (tbinfo->dummy_view)
15564 10 : result = createDummyViewAsClause(fout, tbinfo);
15565 : else
15566 : {
15567 GIC 261 : if (nonemptyReloptions(tbinfo->reloptions))
15568 : {
15569 56 : appendPQExpBufferStr(q, " WITH (");
15570 56 : appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15571 GBC 56 : appendPQExpBufferChar(q, ')');
15572 EUB : }
15573 GBC 261 : result = createViewAsClause(fout, tbinfo);
15574 : }
15575 GIC 271 : appendPQExpBuffer(q, " AS\n%s", result->data);
15576 GBC 271 : destroyPQExpBuffer(result);
15577 EUB :
15578 GBC 271 : if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15579 GIC 36 : appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
15580 271 : appendPQExpBufferStr(q, ";\n");
15581 EUB : }
15582 : else
15583 : {
15584 GBC 4429 : char *partkeydef = NULL;
15585 4429 : char *ftoptions = NULL;
15586 4429 : char *srvname = NULL;
15587 4429 : char *foreign = "";
15588 EUB :
15589 : /*
15590 : * Set reltypename, and collect any relkind-specific data that we
15591 ECB : * didn't fetch during getTables().
15592 : */
15593 CBC 4429 : switch (tbinfo->relkind)
15594 : {
15595 GIC 466 : case RELKIND_PARTITIONED_TABLE:
15596 : {
15597 466 : PQExpBuffer query = createPQExpBuffer();
15598 : PGresult *res;
15599 :
15600 CBC 466 : reltypename = "TABLE";
15601 :
15602 ECB : /* retrieve partition key definition */
15603 CBC 466 : appendPQExpBuffer(query,
15604 : "SELECT pg_get_partkeydef('%u')",
15605 GIC 466 : tbinfo->dobj.catId.oid);
15606 466 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
15607 CBC 466 : partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
15608 466 : PQclear(res);
15609 GIC 466 : destroyPQExpBuffer(query);
15610 CBC 466 : break;
15611 : }
15612 38 : case RELKIND_FOREIGN_TABLE:
15613 ECB : {
15614 GIC 38 : PQExpBuffer query = createPQExpBuffer();
15615 ECB : PGresult *res;
15616 : int i_srvname;
15617 : int i_ftoptions;
15618 :
15619 CBC 38 : reltypename = "FOREIGN TABLE";
15620 ECB :
15621 : /* retrieve name of foreign server and generic options */
15622 CBC 38 : appendPQExpBuffer(query,
15623 ECB : "SELECT fs.srvname, "
15624 : "pg_catalog.array_to_string(ARRAY("
15625 : "SELECT pg_catalog.quote_ident(option_name) || "
15626 : "' ' || pg_catalog.quote_literal(option_value) "
15627 : "FROM pg_catalog.pg_options_to_table(ftoptions) "
15628 : "ORDER BY option_name"
15629 : "), E',\n ') AS ftoptions "
15630 : "FROM pg_catalog.pg_foreign_table ft "
15631 : "JOIN pg_catalog.pg_foreign_server fs "
15632 : "ON (fs.oid = ft.ftserver) "
15633 : "WHERE ft.ftrelid = '%u'",
15634 GIC 38 : tbinfo->dobj.catId.oid);
15635 38 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
15636 38 : i_srvname = PQfnumber(res, "srvname");
15637 38 : i_ftoptions = PQfnumber(res, "ftoptions");
15638 CBC 38 : srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15639 GIC 38 : ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15640 CBC 38 : PQclear(res);
15641 GIC 38 : destroyPQExpBuffer(query);
15642 :
15643 38 : foreign = "FOREIGN ";
15644 CBC 38 : break;
15645 : }
15646 GIC 328 : case RELKIND_MATVIEW:
15647 CBC 328 : reltypename = "MATERIALIZED VIEW";
15648 GIC 328 : break;
15649 3597 : default:
15650 CBC 3597 : reltypename = "TABLE";
15651 GIC 3597 : break;
15652 : }
15653 :
15654 4429 : numParents = tbinfo->numParents;
15655 4429 : parents = tbinfo->parents;
15656 :
15657 4429 : appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15658 :
15659 4429 : if (dopt->binary_upgrade)
15660 661 : binary_upgrade_set_pg_class_oids(fout, q,
15661 661 : tbinfo->dobj.catId.oid, false);
15662 ECB :
15663 GIC 4429 : appendPQExpBuffer(q, "CREATE %s%s %s",
15664 4429 : tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15665 : "UNLOGGED " : "",
15666 : reltypename,
15667 : qualrelname);
15668 :
15669 : /*
15670 : * Attach to type, if reloftype; except in case of a binary upgrade,
15671 : * we dump the table normally and attach it to the type afterward.
15672 : */
15673 4429 : if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
15674 24 : appendPQExpBuffer(q, " OF %s",
15675 24 : getFormattedTypeName(fout, tbinfo->reloftype,
15676 : zeroIsError));
15677 :
15678 4429 : if (tbinfo->relkind != RELKIND_MATVIEW)
15679 EUB : {
15680 : /* Dump the attributes */
15681 GIC 4101 : actual_atts = 0;
15682 20258 : for (j = 0; j < tbinfo->numatts; j++)
15683 : {
15684 : /*
15685 : * Normally, dump if it's locally defined in this table, and
15686 : * not dropped. But for binary upgrade, we'll dump all the
15687 : * columns, and then fix up the dropped and nonlocal cases
15688 ECB : * below.
15689 : */
15690 CBC 16157 : if (shouldPrintColumn(dopt, tbinfo, j))
15691 : {
15692 : bool print_default;
15693 ECB : bool print_notnull;
15694 :
15695 : /*
15696 : * Default value --- suppress if to be printed separately
15697 : * or not at all.
15698 : */
15699 GIC 31614 : print_default = (tbinfo->attrdefs[j] != NULL &&
15700 GNC 16162 : tbinfo->attrdefs[j]->dobj.dump &&
15701 CBC 753 : !tbinfo->attrdefs[j]->separate);
15702 :
15703 ECB : /*
15704 : * Not Null constraint --- suppress unless it is locally
15705 : * defined, except if partition, or in binary-upgrade case
15706 : * where that won't work.
15707 : */
15708 GIC 16327 : print_notnull = (tbinfo->notnull[j] &&
15709 GNC 918 : (tbinfo->localNotNull[j] ||
15710 GIC 425 : tbinfo->ispartition || dopt->binary_upgrade));
15711 ECB :
15712 : /*
15713 : * Skip column if fully defined by reloftype, except in
15714 : * binary upgrade
15715 : */
15716 GIC 15409 : if (OidIsValid(tbinfo->reloftype) &&
15717 50 : !print_default && !print_notnull &&
15718 40 : !dopt->binary_upgrade)
15719 32 : continue;
15720 :
15721 : /* Format properly if not first attr */
15722 CBC 15377 : if (actual_atts == 0)
15723 GIC 3877 : appendPQExpBufferStr(q, " (");
15724 ECB : else
15725 GIC 11500 : appendPQExpBufferChar(q, ',');
15726 CBC 15377 : appendPQExpBufferStr(q, "\n ");
15727 GIC 15377 : actual_atts++;
15728 ECB :
15729 : /* Attribute name */
15730 GIC 15377 : appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15731 :
15732 CBC 15377 : if (tbinfo->attisdropped[j])
15733 : {
15734 : /*
15735 : * ALTER TABLE DROP COLUMN clears
15736 : * pg_attribute.atttypid, so we will not have gotten a
15737 : * valid type name; insert INTEGER as a stopgap. We'll
15738 : * clean things up later.
15739 : */
15740 GIC 79 : appendPQExpBufferStr(q, " INTEGER /* dummy */");
15741 : /* and skip to the next column */
15742 CBC 79 : continue;
15743 : }
15744 ECB :
15745 : /*
15746 : * Attribute type; print it except when creating a typed
15747 : * table ('OF type_name'), but in binary-upgrade mode,
15748 : * print it in that case too.
15749 : */
15750 CBC 15298 : if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
15751 : {
15752 15290 : appendPQExpBuffer(q, " %s",
15753 GIC 15290 : tbinfo->atttypnames[j]);
15754 ECB : }
15755 :
15756 CBC 15298 : if (print_default)
15757 : {
15758 GBC 640 : if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
15759 274 : appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
15760 GIC 274 : tbinfo->attrdefs[j]->adef_expr);
15761 : else
15762 GBC 366 : appendPQExpBuffer(q, " DEFAULT %s",
15763 GIC 366 : tbinfo->attrdefs[j]->adef_expr);
15764 : }
15765 :
15766 ECB :
15767 GIC 15298 : if (print_notnull)
15768 CBC 883 : appendPQExpBufferStr(q, " NOT NULL");
15769 EUB :
15770 : /* Add collation if not default for the type */
15771 GIC 15298 : if (OidIsValid(tbinfo->attcollation[j]))
15772 : {
15773 ECB : CollInfo *coll;
15774 :
15775 GIC 5 : coll = findCollationByOid(tbinfo->attcollation[j]);
15776 CBC 5 : if (coll)
15777 5 : appendPQExpBuffer(q, " COLLATE %s",
15778 GIC 5 : fmtQualifiedDumpable(coll));
15779 ECB : }
15780 : }
15781 : }
15782 :
15783 : /*
15784 : * Add non-inherited CHECK constraints, if any.
15785 : *
15786 : * For partitions, we need to include check constraints even if
15787 : * they're not defined locally, because the ALTER TABLE ATTACH
15788 : * PARTITION that we'll emit later expects the constraint to be
15789 : * there. (No need to fix conislocal: ATTACH PARTITION does that)
15790 : */
15791 CBC 4659 : for (j = 0; j < tbinfo->ncheck; j++)
15792 : {
15793 558 : ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15794 :
15795 GIC 558 : if (constr->separate ||
15796 CBC 518 : (!constr->conislocal && !tbinfo->ispartition))
15797 GIC 81 : continue;
15798 ECB :
15799 GIC 477 : if (actual_atts == 0)
15800 CBC 16 : appendPQExpBufferStr(q, " (\n ");
15801 ECB : else
15802 CBC 461 : appendPQExpBufferStr(q, ",\n ");
15803 :
15804 477 : appendPQExpBuffer(q, "CONSTRAINT %s ",
15805 GIC 477 : fmtId(constr->dobj.name));
15806 477 : appendPQExpBufferStr(q, constr->condef);
15807 :
15808 477 : actual_atts++;
15809 : }
15810 ECB :
15811 GIC 4101 : if (actual_atts)
15812 3893 : appendPQExpBufferStr(q, "\n)");
15813 208 : else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
15814 EUB : {
15815 : /*
15816 : * No attributes? we must have a parenthesized attribute list,
15817 : * even though empty, when not using the OF TYPE syntax.
15818 : */
15819 GIC 192 : appendPQExpBufferStr(q, " (\n)");
15820 ECB : }
15821 :
15822 : /*
15823 : * Emit the INHERITS clause (not for partitions), except in
15824 : * binary-upgrade mode.
15825 : */
15826 GIC 4101 : if (numParents > 0 && !tbinfo->ispartition &&
15827 303 : !dopt->binary_upgrade)
15828 : {
15829 261 : appendPQExpBufferStr(q, "\nINHERITS (");
15830 542 : for (k = 0; k < numParents; k++)
15831 ECB : {
15832 GIC 281 : TableInfo *parentRel = parents[k];
15833 ECB :
15834 CBC 281 : if (k > 0)
15835 20 : appendPQExpBufferStr(q, ", ");
15836 GIC 281 : appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15837 : }
15838 261 : appendPQExpBufferChar(q, ')');
15839 : }
15840 :
15841 4101 : if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15842 466 : appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
15843 :
15844 4101 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15845 38 : appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15846 : }
15847 ECB :
15848 GIC 8712 : if (nonemptyReloptions(tbinfo->reloptions) ||
15849 CBC 4283 : nonemptyReloptions(tbinfo->toast_reloptions))
15850 ECB : {
15851 GIC 146 : bool addcomma = false;
15852 ECB :
15853 GBC 146 : appendPQExpBufferStr(q, "\nWITH (");
15854 GIC 146 : if (nonemptyReloptions(tbinfo->reloptions))
15855 : {
15856 CBC 146 : addcomma = true;
15857 146 : appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15858 : }
15859 GIC 146 : if (nonemptyReloptions(tbinfo->toast_reloptions))
15860 ECB : {
15861 GIC 5 : if (addcomma)
15862 5 : appendPQExpBufferStr(q, ", ");
15863 5 : appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15864 : fout);
15865 : }
15866 146 : appendPQExpBufferChar(q, ')');
15867 : }
15868 ECB :
15869 : /* Dump generic options if any */
15870 CBC 4429 : if (ftoptions && ftoptions[0])
15871 GIC 36 : appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
15872 ECB :
15873 : /*
15874 : * For materialized views, create the AS clause just like a view. At
15875 : * this point, we always mark the view as not populated.
15876 : */
15877 GIC 4429 : if (tbinfo->relkind == RELKIND_MATVIEW)
15878 ECB : {
15879 : PQExpBuffer result;
15880 :
15881 GIC 328 : result = createViewAsClause(fout, tbinfo);
15882 CBC 328 : appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
15883 : result->data);
15884 328 : destroyPQExpBuffer(result);
15885 ECB : }
15886 : else
15887 GIC 4101 : appendPQExpBufferStr(q, ";\n");
15888 ECB :
15889 : /* Materialized views can depend on extensions */
15890 CBC 4429 : if (tbinfo->relkind == RELKIND_MATVIEW)
15891 328 : append_depends_on_extension(fout, q, &tbinfo->dobj,
15892 : "pg_catalog.pg_class",
15893 : "MATERIALIZED VIEW",
15894 ECB : qualrelname);
15895 :
15896 : /*
15897 : * in binary upgrade mode, update the catalog with any missing values
15898 : * that might be present.
15899 : */
15900 CBC 4429 : if (dopt->binary_upgrade)
15901 ECB : {
15902 GIC 3500 : for (j = 0; j < tbinfo->numatts; j++)
15903 : {
15904 2839 : if (tbinfo->attmissingval[j][0] != '\0')
15905 : {
15906 2 : appendPQExpBufferStr(q, "\n-- set missing value.\n");
15907 CBC 2 : appendPQExpBufferStr(q,
15908 : "SELECT pg_catalog.binary_upgrade_set_missing_value(");
15909 2 : appendStringLiteralAH(q, qualrelname, fout);
15910 GIC 2 : appendPQExpBufferStr(q, "::pg_catalog.regclass,");
15911 CBC 2 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15912 GNC 2 : appendPQExpBufferChar(q, ',');
15913 GIC 2 : appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
15914 CBC 2 : appendPQExpBufferStr(q, ");\n\n");
15915 : }
15916 : }
15917 ECB : }
15918 :
15919 : /*
15920 : * To create binary-compatible heap files, we have to ensure the same
15921 : * physical column order, including dropped columns, as in the
15922 : * original. Therefore, we create dropped columns above and drop them
15923 : * here, also updating their attlen/attalign values so that the
15924 : * dropped column can be skipped properly. (We do not bother with
15925 : * restoring the original attbyval setting.) Also, inheritance
15926 : * relationships are set up by doing ALTER TABLE INHERIT rather than
15927 : * using an INHERITS clause --- the latter would possibly mess up the
15928 : * column order. That also means we have to take care about setting
15929 : * attislocal correctly, plus fix up any inherited CHECK constraints.
15930 : * Analogously, we set up typed tables using ALTER TABLE / OF here.
15931 : *
15932 : * We process foreign and partitioned tables here, even though they
15933 : * lack heap storage, because they can participate in inheritance
15934 : * relationships and we want this stuff to be consistent across the
15935 : * inheritance tree. We can exclude indexes, toast tables, sequences
15936 : * and matviews, even though they have storage, because we don't
15937 : * support altering or dropping columns in them, nor can they be part
15938 : * of inheritance trees.
15939 : */
15940 GIC 4429 : if (dopt->binary_upgrade &&
15941 661 : (tbinfo->relkind == RELKIND_RELATION ||
15942 97 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15943 96 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15944 : {
15945 3466 : for (j = 0; j < tbinfo->numatts; j++)
15946 : {
15947 2821 : if (tbinfo->attisdropped[j])
15948 ECB : {
15949 CBC 79 : appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15950 79 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15951 ECB : "SET attlen = %d, "
15952 : "attalign = '%c', attbyval = false\n"
15953 : "WHERE attname = ",
15954 CBC 79 : tbinfo->attlen[j],
15955 79 : tbinfo->attalign[j]);
15956 GIC 79 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15957 CBC 79 : appendPQExpBufferStr(q, "\n AND attrelid = ");
15958 79 : appendStringLiteralAH(q, qualrelname, fout);
15959 GIC 79 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15960 ECB :
15961 CBC 79 : if (tbinfo->relkind == RELKIND_RELATION ||
15962 16 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15963 79 : appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15964 ECB : qualrelname);
15965 : else
15966 UIC 0 : appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15967 : qualrelname);
15968 CBC 79 : appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15969 79 : fmtId(tbinfo->attnames[j]));
15970 : }
15971 2742 : else if (!tbinfo->attislocal[j])
15972 : {
15973 534 : appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15974 534 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15975 ECB : "SET attislocal = false\n"
15976 : "WHERE attname = ");
15977 CBC 534 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15978 534 : appendPQExpBufferStr(q, "\n AND attrelid = ");
15979 GIC 534 : appendStringLiteralAH(q, qualrelname, fout);
15980 534 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15981 : }
15982 : }
15983 :
15984 : /*
15985 : * Add inherited CHECK constraints, if any.
15986 : *
15987 ECB : * For partitions, they were already dumped, and conislocal
15988 : * doesn't need fixing.
15989 : */
15990 GIC 696 : for (k = 0; k < tbinfo->ncheck; k++)
15991 : {
15992 CBC 51 : ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15993 :
15994 GIC 51 : if (constr->separate || constr->conislocal || tbinfo->ispartition)
15995 CBC 49 : continue;
15996 ECB :
15997 GIC 2 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15998 2 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
15999 : foreign, qualrelname,
16000 2 : fmtId(constr->dobj.name),
16001 : constr->condef);
16002 2 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
16003 : "SET conislocal = false\n"
16004 ECB : "WHERE contype = 'c' AND conname = ");
16005 GIC 2 : appendStringLiteralAH(q, constr->dobj.name, fout);
16006 2 : appendPQExpBufferStr(q, "\n AND conrelid = ");
16007 2 : appendStringLiteralAH(q, qualrelname, fout);
16008 2 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16009 : }
16010 :
16011 645 : if (numParents > 0 && !tbinfo->ispartition)
16012 : {
16013 CBC 42 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
16014 89 : for (k = 0; k < numParents; k++)
16015 ECB : {
16016 GIC 47 : TableInfo *parentRel = parents[k];
16017 :
16018 47 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
16019 : qualrelname,
16020 47 : fmtQualifiedDumpable(parentRel));
16021 : }
16022 ECB : }
16023 :
16024 CBC 645 : if (OidIsValid(tbinfo->reloftype))
16025 : {
16026 GIC 6 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
16027 6 : appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
16028 : qualrelname,
16029 6 : getFormattedTypeName(fout, tbinfo->reloftype,
16030 ECB : zeroIsError));
16031 : }
16032 : }
16033 :
16034 : /*
16035 : * In binary_upgrade mode, arrange to restore the old relfrozenxid and
16036 : * relminmxid of all vacuumable relations. (While vacuum.c processes
16037 : * TOAST tables semi-independently, here we see them only as children
16038 : * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
16039 : * child toast table is handled below.)
16040 : */
16041 CBC 4429 : if (dopt->binary_upgrade &&
16042 GIC 661 : (tbinfo->relkind == RELKIND_RELATION ||
16043 97 : tbinfo->relkind == RELKIND_MATVIEW))
16044 ECB : {
16045 GIC 580 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
16046 CBC 580 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16047 : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16048 : "WHERE oid = ",
16049 GIC 580 : tbinfo->frozenxid, tbinfo->minmxid);
16050 580 : appendStringLiteralAH(q, qualrelname, fout);
16051 580 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16052 :
16053 580 : if (tbinfo->toast_oid)
16054 ECB : {
16055 : /*
16056 : * The toast table will have the same OID at restore, so we
16057 : * can safely target it by OID.
16058 : */
16059 GIC 251 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
16060 251 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16061 : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16062 : "WHERE oid = '%u';\n",
16063 251 : tbinfo->toast_frozenxid,
16064 CBC 251 : tbinfo->toast_minmxid, tbinfo->toast_oid);
16065 : }
16066 ECB : }
16067 :
16068 : /*
16069 : * In binary_upgrade mode, restore matviews' populated status by
16070 : * poking pg_class directly. This is pretty ugly, but we can't use
16071 : * REFRESH MATERIALIZED VIEW since it's possible that some underlying
16072 : * matview is not populated even though this matview is; in any case,
16073 : * we want to transfer the matview's heap storage, not run REFRESH.
16074 : */
16075 GIC 4429 : if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
16076 CBC 16 : tbinfo->relispopulated)
16077 ECB : {
16078 GIC 14 : appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
16079 14 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
16080 : "SET relispopulated = 't'\n"
16081 ECB : "WHERE oid = ");
16082 CBC 14 : appendStringLiteralAH(q, qualrelname, fout);
16083 GIC 14 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16084 : }
16085 ECB :
16086 : /*
16087 : * Dump additional per-column properties that we can't handle in the
16088 : * main CREATE TABLE command.
16089 : */
16090 CBC 20924 : for (j = 0; j < tbinfo->numatts; j++)
16091 ECB : {
16092 : /* None of this applies to dropped columns */
16093 GIC 16495 : if (tbinfo->attisdropped[j])
16094 426 : continue;
16095 :
16096 : /*
16097 : * If we didn't dump the column definition explicitly above, and
16098 : * it is NOT NULL and did not inherit that property from a parent,
16099 : * we have to mark it separately.
16100 : */
16101 16069 : if (!shouldPrintColumn(dopt, tbinfo, j) &&
16102 GNC 401 : tbinfo->notnull[j] && tbinfo->localNotNull[j] &&
16103 7 : tbinfo->ispartition)
16104 UIC 0 : appendPQExpBuffer(q,
16105 : "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET NOT NULL;\n",
16106 ECB : foreign, qualrelname,
16107 UIC 0 : fmtId(tbinfo->attnames[j]));
16108 ECB :
16109 : /*
16110 : * Dump per-column statistics information. We only issue an ALTER
16111 : * TABLE statement if the attstattarget entry for this column is
16112 : * non-negative (i.e. it's not the default value)
16113 : */
16114 CBC 16069 : if (tbinfo->attstattarget[j] >= 0)
16115 36 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
16116 : foreign, qualrelname,
16117 36 : fmtId(tbinfo->attnames[j]),
16118 GIC 36 : tbinfo->attstattarget[j]);
16119 ECB :
16120 : /*
16121 : * Dump per-column storage information. The statement is only
16122 : * dumped if the storage has been changed from the type's default.
16123 : */
16124 GIC 16069 : if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
16125 : {
16126 CBC 87 : switch (tbinfo->attstorage[j])
16127 ECB : {
16128 CBC 10 : case TYPSTORAGE_PLAIN:
16129 GIC 10 : storage = "PLAIN";
16130 10 : break;
16131 41 : case TYPSTORAGE_EXTERNAL:
16132 41 : storage = "EXTERNAL";
16133 41 : break;
16134 LBC 0 : case TYPSTORAGE_EXTENDED:
16135 UIC 0 : storage = "EXTENDED";
16136 0 : break;
16137 GIC 36 : case TYPSTORAGE_MAIN:
16138 36 : storage = "MAIN";
16139 36 : break;
16140 UIC 0 : default:
16141 LBC 0 : storage = NULL;
16142 ECB : }
16143 :
16144 : /*
16145 : * Only dump the statement if it's a storage type we recognize
16146 : */
16147 CBC 87 : if (storage != NULL)
16148 GIC 87 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
16149 ECB : foreign, qualrelname,
16150 CBC 87 : fmtId(tbinfo->attnames[j]),
16151 ECB : storage);
16152 : }
16153 :
16154 : /*
16155 : * Dump per-column compression, if it's been set.
16156 : */
16157 CBC 16069 : if (!dopt->no_toast_compression)
16158 : {
16159 ECB : const char *cmname;
16160 :
16161 GIC 15998 : switch (tbinfo->attcompression[j])
16162 : {
16163 CBC 55 : case 'p':
16164 55 : cmname = "pglz";
16165 GIC 55 : break;
16166 CBC 100 : case 'l':
16167 GIC 100 : cmname = "lz4";
16168 CBC 100 : break;
16169 15843 : default:
16170 GIC 15843 : cmname = NULL;
16171 CBC 15843 : break;
16172 ECB : }
16173 :
16174 CBC 15998 : if (cmname != NULL)
16175 GIC 155 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
16176 ECB : foreign, qualrelname,
16177 CBC 155 : fmtId(tbinfo->attnames[j]),
16178 ECB : cmname);
16179 : }
16180 :
16181 : /*
16182 : * Dump per-column attributes.
16183 : */
16184 GIC 16069 : if (tbinfo->attoptions[j][0] != '\0')
16185 CBC 36 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
16186 ECB : foreign, qualrelname,
16187 GIC 36 : fmtId(tbinfo->attnames[j]),
16188 36 : tbinfo->attoptions[j]);
16189 :
16190 : /*
16191 : * Dump per-column fdw options.
16192 ECB : */
16193 GIC 16069 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16194 38 : tbinfo->attfdwoptions[j][0] != '\0')
16195 36 : appendPQExpBuffer(q,
16196 ECB : "ALTER FOREIGN TABLE %s ALTER COLUMN %s OPTIONS (\n"
16197 : " %s\n"
16198 : ");\n",
16199 : qualrelname,
16200 GIC 36 : fmtId(tbinfo->attnames[j]),
16201 36 : tbinfo->attfdwoptions[j]);
16202 ECB : } /* end loop over columns */
16203 :
16204 GNC 4429 : free(partkeydef);
16205 4429 : free(ftoptions);
16206 4429 : free(srvname);
16207 : }
16208 :
16209 : /*
16210 : * dump properties we only have ALTER TABLE syntax for
16211 : */
16212 CBC 4700 : if ((tbinfo->relkind == RELKIND_RELATION ||
16213 GIC 1103 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
16214 CBC 637 : tbinfo->relkind == RELKIND_MATVIEW) &&
16215 GIC 4391 : tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
16216 ECB : {
16217 UIC 0 : if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
16218 ECB : {
16219 : /* nothing to do, will be set when the index is dumped */
16220 : }
16221 LBC 0 : else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
16222 ECB : {
16223 LBC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
16224 ECB : qualrelname);
16225 : }
16226 LBC 0 : else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16227 : {
16228 UIC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16229 : qualrelname);
16230 : }
16231 : }
16232 :
16233 GIC 4700 : if (tbinfo->forcerowsec)
16234 5 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16235 : qualrelname);
16236 :
16237 4700 : if (dopt->binary_upgrade)
16238 709 : binary_upgrade_extension_member(q, &tbinfo->dobj,
16239 : reltypename, qrelname,
16240 709 : tbinfo->dobj.namespace->dobj.name);
16241 :
16242 4700 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16243 : {
16244 4700 : char *tablespace = NULL;
16245 4700 : char *tableam = NULL;
16246 :
16247 : /*
16248 : * _selectTablespace() relies on tablespace-enabled objects in the
16249 : * default tablespace to have a tablespace of "" (empty string) versus
16250 : * non-tablespace-enabled objects to have a tablespace of NULL.
16251 : * getTables() sets tbinfo->reltablespace to "" for the default
16252 ECB : * tablespace (not NULL).
16253 : */
16254 CBC 4700 : if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
16255 4391 : tablespace = tbinfo->reltablespace;
16256 :
16257 4700 : if (RELKIND_HAS_TABLE_AM(tbinfo->relkind))
16258 GIC 3925 : tableam = tbinfo->amname;
16259 ECB :
16260 GIC 4700 : ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16261 CBC 4700 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16262 ECB : .namespace = tbinfo->dobj.namespace->dobj.name,
16263 : .tablespace = tablespace,
16264 : .tableam = tableam,
16265 : .owner = tbinfo->rolname,
16266 : .description = reltypename,
16267 : .section = tbinfo->postponed_def ?
16268 : SECTION_POST_DATA : SECTION_PRE_DATA,
16269 : .createStmt = q->data,
16270 : .dropStmt = delq->data));
16271 : }
16272 :
16273 : /* Dump Table Comments */
16274 CBC 4700 : if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16275 82 : dumpTableComment(fout, tbinfo, reltypename);
16276 :
16277 : /* Dump Table Security Labels */
16278 GBC 4700 : if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16279 UIC 0 : dumpTableSecLabel(fout, tbinfo, reltypename);
16280 ECB :
16281 : /* Dump comments on inlined table constraints */
16282 GIC 5258 : for (j = 0; j < tbinfo->ncheck; j++)
16283 ECB : {
16284 GIC 558 : ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16285 ECB :
16286 CBC 558 : if (constr->separate || !constr->conislocal)
16287 GIC 229 : continue;
16288 :
16289 CBC 329 : if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
16290 41 : dumpTableConstraintComment(fout, constr);
16291 ECB : }
16292 :
16293 GIC 4700 : destroyPQExpBuffer(q);
16294 4700 : destroyPQExpBuffer(delq);
16295 4700 : free(qrelname);
16296 4700 : free(qualrelname);
16297 4700 : }
16298 :
16299 : /*
16300 : * dumpTableAttach
16301 : * write to fout the commands to attach a child partition
16302 ECB : *
16303 : * Child partitions are always made by creating them separately
16304 : * and then using ATTACH PARTITION, rather than using
16305 : * CREATE TABLE ... PARTITION OF. This is important for preserving
16306 : * any possible discrepancy in column layout, to allow assigning the
16307 : * correct tablespace if different, and so that it's possible to restore
16308 : * a partition without restoring its parent. (You'll get an error from
16309 : * the ATTACH PARTITION command, but that can be ignored, or skipped
16310 : * using "pg_restore -L" if you prefer.) The last point motivates
16311 : * treating ATTACH PARTITION as a completely separate ArchiveEntry
16312 : * rather than emitting it within the child partition's ArchiveEntry.
16313 : */
16314 : static void
16315 GIC 1166 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
16316 : {
16317 CBC 1166 : DumpOptions *dopt = fout->dopt;
16318 ECB : PQExpBuffer q;
16319 : PGresult *res;
16320 : char *partbound;
16321 :
16322 : /* Do nothing in data-only dump */
16323 CBC 1166 : if (dopt->dataOnly)
16324 GIC 15 : return;
16325 ECB :
16326 GIC 1151 : q = createPQExpBuffer();
16327 ECB :
16328 GIC 1151 : if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
16329 ECB : {
16330 : /* Set up query for partbound details */
16331 GIC 47 : appendPQExpBufferStr(q,
16332 : "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
16333 ECB :
16334 GIC 47 : appendPQExpBufferStr(q,
16335 ECB : "SELECT pg_get_expr(c.relpartbound, c.oid) "
16336 : "FROM pg_class c "
16337 : "WHERE c.oid = $1");
16338 :
16339 GIC 47 : ExecuteSqlStatement(fout, q->data);
16340 :
16341 47 : fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
16342 : }
16343 :
16344 1151 : printfPQExpBuffer(q,
16345 : "EXECUTE dumpTableAttach('%u')",
16346 1151 : attachinfo->partitionTbl->dobj.catId.oid);
16347 :
16348 1151 : res = ExecuteSqlQueryForSingleRow(fout, q->data);
16349 1151 : partbound = PQgetvalue(res, 0, 0);
16350 ECB :
16351 : /* Perform ALTER TABLE on the parent */
16352 CBC 1151 : printfPQExpBuffer(q,
16353 : "ALTER TABLE ONLY %s ",
16354 1151 : fmtQualifiedDumpable(attachinfo->parentTbl));
16355 1151 : appendPQExpBuffer(q,
16356 : "ATTACH PARTITION %s %s;\n",
16357 GIC 1151 : fmtQualifiedDumpable(attachinfo->partitionTbl),
16358 ECB : partbound);
16359 :
16360 : /*
16361 : * There is no point in creating a drop query as the drop is done by table
16362 : * drop. (If you think to change this, see also _printTocEntry().)
16363 : * Although this object doesn't really have ownership as such, set the
16364 : * owner field anyway to ensure that the command is run by the correct
16365 : * role at restore time.
16366 : */
16367 GIC 1151 : ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16368 CBC 1151 : ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16369 ECB : .namespace = attachinfo->dobj.namespace->dobj.name,
16370 : .owner = attachinfo->partitionTbl->rolname,
16371 : .description = "TABLE ATTACH",
16372 : .section = SECTION_PRE_DATA,
16373 : .createStmt = q->data));
16374 :
16375 GIC 1151 : PQclear(res);
16376 1151 : destroyPQExpBuffer(q);
16377 : }
16378 :
16379 : /*
16380 : * dumpAttrDef --- dump an attribute's default-value declaration
16381 : */
16382 : static void
16383 793 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
16384 ECB : {
16385 CBC 793 : DumpOptions *dopt = fout->dopt;
16386 GIC 793 : TableInfo *tbinfo = adinfo->adtable;
16387 CBC 793 : int adnum = adinfo->adnum;
16388 ECB : PQExpBuffer q;
16389 : PQExpBuffer delq;
16390 : char *qualrelname;
16391 : char *tag;
16392 : char *foreign;
16393 :
16394 : /* Do nothing in data-only dump */
16395 GIC 793 : if (dopt->dataOnly)
16396 UIC 0 : return;
16397 :
16398 : /* Skip if not "separate"; it was dumped in the table's definition */
16399 CBC 793 : if (!adinfo->separate)
16400 GIC 640 : return;
16401 :
16402 CBC 153 : q = createPQExpBuffer();
16403 153 : delq = createPQExpBuffer();
16404 :
16405 GIC 153 : qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16406 :
16407 153 : foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
16408 :
16409 153 : appendPQExpBuffer(q,
16410 ECB : "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
16411 CBC 153 : foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
16412 153 : adinfo->adef_expr);
16413 EUB :
16414 GIC 153 : appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
16415 : foreign, qualrelname,
16416 GBC 153 : fmtId(tbinfo->attnames[adnum - 1]));
16417 :
16418 GIC 153 : tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16419 :
16420 153 : if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16421 153 : ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16422 153 : ARCHIVE_OPTS(.tag = tag,
16423 ECB : .namespace = tbinfo->dobj.namespace->dobj.name,
16424 : .owner = tbinfo->rolname,
16425 : .description = "DEFAULT",
16426 : .section = SECTION_PRE_DATA,
16427 : .createStmt = q->data,
16428 : .dropStmt = delq->data));
16429 :
16430 GIC 153 : free(tag);
16431 153 : destroyPQExpBuffer(q);
16432 153 : destroyPQExpBuffer(delq);
16433 CBC 153 : free(qualrelname);
16434 : }
16435 ECB :
16436 : /*
16437 : * getAttrName: extract the correct name for an attribute
16438 : *
16439 : * The array tblInfo->attnames[] only provides names of user attributes;
16440 : * if a system attribute number is supplied, we have to fake it.
16441 : * We also do a little bit of bounds checking for safety's sake.
16442 : */
16443 EUB : static const char *
16444 GBC 1165 : getAttrName(int attrnum, const TableInfo *tblInfo)
16445 EUB : {
16446 CBC 1165 : if (attrnum > 0 && attrnum <= tblInfo->numatts)
16447 1165 : return tblInfo->attnames[attrnum - 1];
16448 LBC 0 : switch (attrnum)
16449 EUB : {
16450 UBC 0 : case SelfItemPointerAttributeNumber:
16451 UIC 0 : return "ctid";
16452 0 : case MinTransactionIdAttributeNumber:
16453 0 : return "xmin";
16454 0 : case MinCommandIdAttributeNumber:
16455 0 : return "cmin";
16456 LBC 0 : case MaxTransactionIdAttributeNumber:
16457 0 : return "xmax";
16458 UIC 0 : case MaxCommandIdAttributeNumber:
16459 LBC 0 : return "cmax";
16460 UIC 0 : case TableOidAttributeNumber:
16461 0 : return "tableoid";
16462 : }
16463 0 : pg_fatal("invalid column number %d for table \"%s\"",
16464 : attrnum, tblInfo->dobj.name);
16465 : return NULL; /* keep compiler quiet */
16466 ECB : }
16467 :
16468 : /*
16469 : * dumpIndex
16470 : * write out to fout a user-defined index
16471 : */
16472 : static void
16473 CBC 1842 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
16474 ECB : {
16475 CBC 1842 : DumpOptions *dopt = fout->dopt;
16476 1842 : TableInfo *tbinfo = indxinfo->indextable;
16477 1842 : bool is_constraint = (indxinfo->indexconstraint != 0);
16478 ECB : PQExpBuffer q;
16479 : PQExpBuffer delq;
16480 : char *qindxname;
16481 : char *qqindxname;
16482 :
16483 : /* Do nothing in data-only dump */
16484 CBC 1842 : if (dopt->dataOnly)
16485 GIC 48 : return;
16486 ECB :
16487 GIC 1794 : q = createPQExpBuffer();
16488 1794 : delq = createPQExpBuffer();
16489 :
16490 1794 : qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16491 1794 : qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
16492 :
16493 ECB : /*
16494 : * If there's an associated constraint, don't dump the index per se, but
16495 : * do dump any comment for it. (This is safe because dependency ordering
16496 : * will have ensured the constraint is emitted first.) Note that the
16497 : * emitted comment has to be shown as depending on the constraint, not the
16498 : * index, in such cases.
16499 : */
16500 GIC 1794 : if (!is_constraint)
16501 : {
16502 CBC 939 : char *indstatcols = indxinfo->indstatcols;
16503 939 : char *indstatvals = indxinfo->indstatvals;
16504 939 : char **indstatcolsarray = NULL;
16505 GIC 939 : char **indstatvalsarray = NULL;
16506 939 : int nstatcols = 0;
16507 939 : int nstatvals = 0;
16508 :
16509 CBC 939 : if (dopt->binary_upgrade)
16510 147 : binary_upgrade_set_pg_class_oids(fout, q,
16511 GIC 147 : indxinfo->dobj.catId.oid, true);
16512 :
16513 ECB : /* Plain secondary index */
16514 CBC 939 : appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16515 ECB :
16516 : /*
16517 : * Append ALTER TABLE commands as needed to set properties that we
16518 : * only have ALTER TABLE syntax for. Keep this in sync with the
16519 : * similar code in dumpConstraint!
16520 : */
16521 :
16522 : /* If the index is clustered, we need to record that. */
16523 CBC 939 : if (indxinfo->indisclustered)
16524 ECB : {
16525 UIC 0 : appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16526 UBC 0 : fmtQualifiedDumpable(tbinfo));
16527 : /* index name is not qualified in this syntax */
16528 UIC 0 : appendPQExpBuffer(q, " ON %s;\n",
16529 : qindxname);
16530 EUB : }
16531 :
16532 : /*
16533 : * If the index has any statistics on some of its columns, generate
16534 : * the associated ALTER INDEX queries.
16535 : */
16536 GIC 939 : if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
16537 EUB : {
16538 : int j;
16539 :
16540 GIC 36 : if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
16541 UIC 0 : pg_fatal("could not parse index statistic columns");
16542 CBC 36 : if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
16543 LBC 0 : pg_fatal("could not parse index statistic values");
16544 GIC 36 : if (nstatcols != nstatvals)
16545 UIC 0 : pg_fatal("mismatched number of columns and values for index statistics");
16546 ECB :
16547 CBC 108 : for (j = 0; j < nstatcols; j++)
16548 : {
16549 72 : appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
16550 :
16551 ECB : /*
16552 : * Note that this is a column number, so no quotes should be
16553 : * used.
16554 : */
16555 GIC 72 : appendPQExpBuffer(q, "ALTER COLUMN %s ",
16556 72 : indstatcolsarray[j]);
16557 72 : appendPQExpBuffer(q, "SET STATISTICS %s;\n",
16558 72 : indstatvalsarray[j]);
16559 : }
16560 : }
16561 :
16562 : /* Indexes can depend on extensions */
16563 CBC 939 : append_depends_on_extension(fout, q, &indxinfo->dobj,
16564 ECB : "pg_catalog.pg_class",
16565 : "INDEX", qqindxname);
16566 :
16567 : /* If the index defines identity, we need to record that. */
16568 GIC 939 : if (indxinfo->indisreplident)
16569 ECB : {
16570 LBC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16571 UIC 0 : fmtQualifiedDumpable(tbinfo));
16572 : /* index name is not qualified in this syntax */
16573 0 : appendPQExpBuffer(q, " INDEX %s;\n",
16574 : qindxname);
16575 : }
16576 :
16577 GIC 939 : appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
16578 :
16579 939 : if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16580 939 : ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16581 939 : ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
16582 : .namespace = tbinfo->dobj.namespace->dobj.name,
16583 ECB : .tablespace = indxinfo->tablespace,
16584 : .owner = tbinfo->rolname,
16585 : .description = "INDEX",
16586 : .section = SECTION_POST_DATA,
16587 : .createStmt = q->data,
16588 EUB : .dropStmt = delq->data));
16589 :
16590 GNC 939 : free(indstatcolsarray);
16591 939 : free(indstatvalsarray);
16592 : }
16593 ECB :
16594 : /* Dump Index Comments */
16595 GIC 1794 : if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16596 CBC 15 : dumpComment(fout, "INDEX", qindxname,
16597 15 : tbinfo->dobj.namespace->dobj.name,
16598 : tbinfo->rolname,
16599 : indxinfo->dobj.catId, 0,
16600 ECB : is_constraint ? indxinfo->indexconstraint :
16601 : indxinfo->dobj.dumpId);
16602 :
16603 CBC 1794 : destroyPQExpBuffer(q);
16604 1794 : destroyPQExpBuffer(delq);
16605 GIC 1794 : free(qindxname);
16606 1794 : free(qqindxname);
16607 : }
16608 :
16609 : /*
16610 : * dumpIndexAttach
16611 : * write out to fout a partitioned-index attachment clause
16612 : */
16613 : static void
16614 567 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
16615 : {
16616 : /* Do nothing in data-only dump */
16617 567 : if (fout->dopt->dataOnly)
16618 24 : return;
16619 :
16620 543 : if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16621 : {
16622 CBC 543 : PQExpBuffer q = createPQExpBuffer();
16623 :
16624 543 : appendPQExpBuffer(q, "ALTER INDEX %s ",
16625 GIC 543 : fmtQualifiedDumpable(attachinfo->parentIdx));
16626 543 : appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16627 543 : fmtQualifiedDumpable(attachinfo->partitionIdx));
16628 :
16629 : /*
16630 ECB : * There is no point in creating a drop query as the drop is done by
16631 : * index drop. (If you think to change this, see also
16632 : * _printTocEntry().) Although this object doesn't really have
16633 : * ownership as such, set the owner field anyway to ensure that the
16634 : * command is run by the correct role at restore time.
16635 : */
16636 GIC 543 : ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16637 543 : ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16638 ECB : .namespace = attachinfo->dobj.namespace->dobj.name,
16639 : .owner = attachinfo->parentIdx->indextable->rolname,
16640 : .description = "INDEX ATTACH",
16641 : .section = SECTION_POST_DATA,
16642 : .createStmt = q->data));
16643 :
16644 GIC 543 : destroyPQExpBuffer(q);
16645 : }
16646 ECB : }
16647 :
16648 : /*
16649 : * dumpStatisticsExt
16650 : * write out to fout an extended statistics object
16651 : */
16652 : static void
16653 CBC 137 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
16654 : {
16655 137 : DumpOptions *dopt = fout->dopt;
16656 ECB : PQExpBuffer q;
16657 : PQExpBuffer delq;
16658 : PQExpBuffer query;
16659 : char *qstatsextname;
16660 : PGresult *res;
16661 : char *stxdef;
16662 :
16663 : /* Do nothing in data-only dump */
16664 CBC 137 : if (dopt->dataOnly)
16665 GIC 9 : return;
16666 :
16667 128 : q = createPQExpBuffer();
16668 128 : delq = createPQExpBuffer();
16669 128 : query = createPQExpBuffer();
16670 :
16671 128 : qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16672 :
16673 128 : appendPQExpBuffer(query, "SELECT "
16674 ECB : "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16675 CBC 128 : statsextinfo->dobj.catId.oid);
16676 :
16677 GIC 128 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
16678 :
16679 128 : stxdef = PQgetvalue(res, 0, 0);
16680 :
16681 : /* Result of pg_get_statisticsobjdef is complete except for semicolon */
16682 CBC 128 : appendPQExpBuffer(q, "%s;\n", stxdef);
16683 ECB :
16684 : /*
16685 : * We only issue an ALTER STATISTICS statement if the stxstattarget entry
16686 : * for this statistics object is non-negative (i.e. it's not the default
16687 : * value).
16688 : */
16689 GIC 128 : if (statsextinfo->stattarget >= 0)
16690 ECB : {
16691 GIC 36 : appendPQExpBuffer(q, "ALTER STATISTICS %s ",
16692 CBC 36 : fmtQualifiedDumpable(statsextinfo));
16693 36 : appendPQExpBuffer(q, "SET STATISTICS %d;\n",
16694 36 : statsextinfo->stattarget);
16695 : }
16696 :
16697 GIC 128 : appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16698 128 : fmtQualifiedDumpable(statsextinfo));
16699 :
16700 128 : if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16701 128 : ArchiveEntry(fout, statsextinfo->dobj.catId,
16702 CBC 128 : statsextinfo->dobj.dumpId,
16703 GBC 128 : ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
16704 : .namespace = statsextinfo->dobj.namespace->dobj.name,
16705 : .owner = statsextinfo->rolname,
16706 ECB : .description = "STATISTICS",
16707 : .section = SECTION_POST_DATA,
16708 : .createStmt = q->data,
16709 : .dropStmt = delq->data));
16710 :
16711 : /* Dump Statistics Comments */
16712 CBC 128 : if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16713 UIC 0 : dumpComment(fout, "STATISTICS", qstatsextname,
16714 LBC 0 : statsextinfo->dobj.namespace->dobj.name,
16715 UIC 0 : statsextinfo->rolname,
16716 ECB : statsextinfo->dobj.catId, 0,
16717 UIC 0 : statsextinfo->dobj.dumpId);
16718 ECB :
16719 CBC 128 : PQclear(res);
16720 GIC 128 : destroyPQExpBuffer(q);
16721 CBC 128 : destroyPQExpBuffer(delq);
16722 GIC 128 : destroyPQExpBuffer(query);
16723 CBC 128 : free(qstatsextname);
16724 : }
16725 ECB :
16726 : /*
16727 : * dumpConstraint
16728 : * write out to fout a user-defined constraint
16729 : */
16730 : static void
16731 GIC 1684 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
16732 : {
16733 1684 : DumpOptions *dopt = fout->dopt;
16734 1684 : TableInfo *tbinfo = coninfo->contable;
16735 : PQExpBuffer q;
16736 : PQExpBuffer delq;
16737 CBC 1684 : char *tag = NULL;
16738 ECB : char *foreign;
16739 :
16740 : /* Do nothing in data-only dump */
16741 GIC 1684 : if (dopt->dataOnly)
16742 38 : return;
16743 :
16744 1646 : q = createPQExpBuffer();
16745 1646 : delq = createPQExpBuffer();
16746 :
16747 3211 : foreign = tbinfo &&
16748 1646 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
16749 :
16750 1646 : if (coninfo->contype == 'p' ||
16751 CBC 839 : coninfo->contype == 'u' ||
16752 GIC 801 : coninfo->contype == 'x')
16753 CBC 855 : {
16754 ECB : /* Index-related constraint */
16755 EUB : IndxInfo *indxinfo;
16756 : int k;
16757 :
16758 GBC 855 : indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16759 EUB :
16760 GBC 855 : if (indxinfo == NULL)
16761 UBC 0 : pg_fatal("missing index for constraint \"%s\"",
16762 EUB : coninfo->dobj.name);
16763 :
16764 GBC 855 : if (dopt->binary_upgrade)
16765 108 : binary_upgrade_set_pg_class_oids(fout, q,
16766 EUB : indxinfo->dobj.catId.oid, true);
16767 :
16768 GBC 855 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
16769 GIC 855 : fmtQualifiedDumpable(tbinfo));
16770 GBC 855 : appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
16771 GIC 855 : fmtId(coninfo->dobj.name));
16772 :
16773 855 : if (coninfo->condef)
16774 : {
16775 : /* pg_get_constraintdef should have provided everything */
16776 10 : appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16777 : }
16778 : else
16779 : {
16780 GNC 845 : appendPQExpBufferStr(q,
16781 845 : coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16782 : /*
16783 : * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
16784 : * indexes. Being able to create this was fixed, but we need to
16785 : * make the index distinct in order to be able to restore the dump.
16786 : */
16787 845 : if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
16788 UNC 0 : appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
16789 GNC 845 : appendPQExpBufferStr(q, " (");
16790 GIC 1970 : for (k = 0; k < indxinfo->indnkeyattrs; k++)
16791 : {
16792 1125 : int indkey = (int) indxinfo->indkeys[k];
16793 : const char *attname;
16794 :
16795 1125 : if (indkey == InvalidAttrNumber)
16796 LBC 0 : break;
16797 CBC 1125 : attname = getAttrName(indkey, tbinfo);
16798 :
16799 1125 : appendPQExpBuffer(q, "%s%s",
16800 ECB : (k == 0) ? "" : ", ",
16801 : fmtId(attname));
16802 : }
16803 :
16804 GIC 845 : if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
16805 20 : appendPQExpBufferStr(q, ") INCLUDE (");
16806 :
16807 885 : for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16808 : {
16809 40 : int indkey = (int) indxinfo->indkeys[k];
16810 : const char *attname;
16811 :
16812 CBC 40 : if (indkey == InvalidAttrNumber)
16813 UIC 0 : break;
16814 CBC 40 : attname = getAttrName(indkey, tbinfo);
16815 ECB :
16816 CBC 80 : appendPQExpBuffer(q, "%s%s",
16817 40 : (k == indxinfo->indnkeyattrs) ? "" : ", ",
16818 ECB : fmtId(attname));
16819 : }
16820 :
16821 CBC 845 : appendPQExpBufferChar(q, ')');
16822 ECB :
16823 CBC 845 : if (nonemptyReloptions(indxinfo->indreloptions))
16824 : {
16825 UIC 0 : appendPQExpBufferStr(q, " WITH (");
16826 LBC 0 : appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16827 UIC 0 : appendPQExpBufferChar(q, ')');
16828 : }
16829 :
16830 GIC 845 : if (coninfo->condeferrable)
16831 : {
16832 UIC 0 : appendPQExpBufferStr(q, " DEFERRABLE");
16833 0 : if (coninfo->condeferred)
16834 0 : appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16835 ECB : }
16836 :
16837 GBC 845 : appendPQExpBufferStr(q, ";\n");
16838 EUB : }
16839 :
16840 : /*
16841 : * Append ALTER TABLE commands as needed to set properties that we
16842 : * only have ALTER TABLE syntax for. Keep this in sync with the
16843 : * similar code in dumpIndex!
16844 : */
16845 :
16846 : /* If the index is clustered, we need to record that. */
16847 GIC 855 : if (indxinfo->indisclustered)
16848 ECB : {
16849 GIC 36 : appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16850 36 : fmtQualifiedDumpable(tbinfo));
16851 : /* index name is not qualified in this syntax */
16852 CBC 36 : appendPQExpBuffer(q, " ON %s;\n",
16853 GBC 36 : fmtId(indxinfo->dobj.name));
16854 ECB : }
16855 EUB :
16856 ECB : /* If the index defines identity, we need to record that. */
16857 GBC 855 : if (indxinfo->indisreplident)
16858 : {
16859 LBC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16860 UIC 0 : fmtQualifiedDumpable(tbinfo));
16861 ECB : /* index name is not qualified in this syntax */
16862 UIC 0 : appendPQExpBuffer(q, " INDEX %s;\n",
16863 0 : fmtId(indxinfo->dobj.name));
16864 : }
16865 :
16866 : /* Indexes can depend on extensions */
16867 CBC 855 : append_depends_on_extension(fout, q, &indxinfo->dobj,
16868 ECB : "pg_catalog.pg_class", "INDEX",
16869 CBC 855 : fmtQualifiedDumpable(indxinfo));
16870 ECB :
16871 GIC 855 : appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
16872 855 : fmtQualifiedDumpable(tbinfo));
16873 855 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16874 855 : fmtId(coninfo->dobj.name));
16875 ECB :
16876 GIC 855 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16877 :
16878 855 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16879 855 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16880 CBC 855 : ARCHIVE_OPTS(.tag = tag,
16881 : .namespace = tbinfo->dobj.namespace->dobj.name,
16882 EUB : .tablespace = indxinfo->tablespace,
16883 : .owner = tbinfo->rolname,
16884 : .description = "CONSTRAINT",
16885 : .section = SECTION_POST_DATA,
16886 : .createStmt = q->data,
16887 : .dropStmt = delq->data));
16888 : }
16889 CBC 791 : else if (coninfo->contype == 'f')
16890 : {
16891 ECB : char *only;
16892 :
16893 : /*
16894 : * Foreign keys on partitioned tables are always declared as
16895 : * inheriting to partitions; for all other cases, emit them as
16896 : * applying ONLY directly to the named table, because that's how they
16897 : * work for regular inherited tables.
16898 : */
16899 GIC 152 : only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
16900 :
16901 : /*
16902 ECB : * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16903 : * current table data is not processed
16904 : */
16905 GIC 152 : appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
16906 152 : only, fmtQualifiedDumpable(tbinfo));
16907 CBC 152 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
16908 152 : fmtId(coninfo->dobj.name),
16909 152 : coninfo->condef);
16910 :
16911 GIC 152 : appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
16912 152 : only, fmtQualifiedDumpable(tbinfo));
16913 152 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16914 152 : fmtId(coninfo->dobj.name));
16915 ECB :
16916 CBC 152 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16917 ECB :
16918 CBC 152 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16919 GIC 152 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16920 152 : ARCHIVE_OPTS(.tag = tag,
16921 : .namespace = tbinfo->dobj.namespace->dobj.name,
16922 : .owner = tbinfo->rolname,
16923 : .description = "FK CONSTRAINT",
16924 : .section = SECTION_POST_DATA,
16925 : .createStmt = q->data,
16926 ECB : .dropStmt = delq->data));
16927 : }
16928 GNC 639 : else if (coninfo->contype == 'n')
16929 : {
16930 UNC 0 : appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
16931 0 : fmtQualifiedDumpable(tbinfo));
16932 0 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
16933 0 : fmtId(coninfo->dobj.name),
16934 0 : coninfo->condef);
16935 :
16936 0 : appendPQExpBuffer(delq, "ALTER %sTABLE %s\n", foreign,
16937 0 : fmtQualifiedDumpable(tbinfo));
16938 0 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16939 0 : fmtId(coninfo->dobj.name));
16940 :
16941 0 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16942 :
16943 0 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16944 0 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16945 0 : ARCHIVE_OPTS(.tag = tag,
16946 : .namespace = tbinfo->dobj.namespace->dobj.name,
16947 : .owner = tbinfo->rolname,
16948 : .description = "NOT NULL CONSTRAINT",
16949 : .section = SECTION_POST_DATA,
16950 : .createStmt = q->data,
16951 : .dropStmt = delq->data));
16952 : }
16953 GIC 639 : else if (coninfo->contype == 'c' && tbinfo)
16954 ECB : {
16955 : /* CHECK constraint on a table */
16956 :
16957 : /* Ignore if not to be dumped separately, or if it was inherited */
16958 GIC 558 : if (coninfo->separate && coninfo->conislocal)
16959 ECB : {
16960 : /* not ONLY since we want it to propagate to children */
16961 CBC 25 : appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
16962 25 : fmtQualifiedDumpable(tbinfo));
16963 25 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
16964 25 : fmtId(coninfo->dobj.name),
16965 GIC 25 : coninfo->condef);
16966 :
16967 25 : appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
16968 25 : fmtQualifiedDumpable(tbinfo));
16969 25 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16970 25 : fmtId(coninfo->dobj.name));
16971 :
16972 25 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16973 ECB :
16974 CBC 25 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16975 GIC 25 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16976 25 : ARCHIVE_OPTS(.tag = tag,
16977 : .namespace = tbinfo->dobj.namespace->dobj.name,
16978 : .owner = tbinfo->rolname,
16979 : .description = "CHECK CONSTRAINT",
16980 : .section = SECTION_POST_DATA,
16981 ECB : .createStmt = q->data,
16982 : .dropStmt = delq->data));
16983 : }
16984 : }
16985 GIC 81 : else if (coninfo->contype == 'c' && tbinfo == NULL)
16986 81 : {
16987 : /* CHECK constraint on a domain */
16988 81 : TypeInfo *tyinfo = coninfo->condomain;
16989 :
16990 ECB : /* Ignore if not to be dumped separately */
16991 GIC 81 : if (coninfo->separate)
16992 ECB : {
16993 UIC 0 : appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16994 0 : fmtQualifiedDumpable(tyinfo));
16995 0 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
16996 0 : fmtId(coninfo->dobj.name),
16997 0 : coninfo->condef);
16998 :
16999 0 : appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
17000 0 : fmtQualifiedDumpable(tyinfo));
17001 LBC 0 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
17002 0 : fmtId(coninfo->dobj.name));
17003 :
17004 0 : tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
17005 ECB :
17006 LBC 0 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17007 UIC 0 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
17008 LBC 0 : ARCHIVE_OPTS(.tag = tag,
17009 : .namespace = tyinfo->dobj.namespace->dobj.name,
17010 ECB : .owner = tyinfo->rolname,
17011 : .description = "CHECK CONSTRAINT",
17012 : .section = SECTION_POST_DATA,
17013 : .createStmt = q->data,
17014 : .dropStmt = delq->data));
17015 : }
17016 : }
17017 : else
17018 : {
17019 LBC 0 : pg_fatal("unrecognized constraint type: %c",
17020 : coninfo->contype);
17021 : }
17022 :
17023 : /* Dump Constraint Comments --- only works for table constraints */
17024 GIC 1646 : if (tbinfo && coninfo->separate &&
17025 1047 : coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17026 CBC 10 : dumpTableConstraintComment(fout, coninfo);
17027 :
17028 1646 : free(tag);
17029 1646 : destroyPQExpBuffer(q);
17030 1646 : destroyPQExpBuffer(delq);
17031 ECB : }
17032 :
17033 : /*
17034 : * dumpTableConstraintComment --- dump a constraint's comment if any
17035 : *
17036 : * This is split out because we need the function in two different places
17037 : * depending on whether the constraint is dumped as part of CREATE TABLE
17038 : * or as a separate ALTER command.
17039 : */
17040 : static void
17041 GIC 51 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
17042 : {
17043 51 : TableInfo *tbinfo = coninfo->contable;
17044 51 : PQExpBuffer conprefix = createPQExpBuffer();
17045 : char *qtabname;
17046 :
17047 51 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17048 :
17049 CBC 51 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
17050 GBC 51 : fmtId(coninfo->dobj.name));
17051 EUB :
17052 GBC 51 : if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17053 GIC 51 : dumpComment(fout, conprefix->data, qtabname,
17054 GBC 51 : tbinfo->dobj.namespace->dobj.name,
17055 : tbinfo->rolname,
17056 ECB : coninfo->dobj.catId, 0,
17057 CBC 51 : coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
17058 ECB :
17059 CBC 51 : destroyPQExpBuffer(conprefix);
17060 51 : free(qtabname);
17061 GIC 51 : }
17062 :
17063 : /*
17064 : * dumpSequence
17065 : * write the declaration (not data) of one user-defined sequence
17066 : */
17067 : static void
17068 CBC 315 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
17069 : {
17070 315 : DumpOptions *dopt = fout->dopt;
17071 ECB : PGresult *res;
17072 : char *startv,
17073 : *incby,
17074 : *maxv,
17075 : *minv,
17076 : *cache,
17077 : *seqtype;
17078 : bool cycled;
17079 : bool is_ascending;
17080 : int64 default_minv,
17081 : default_maxv;
17082 : char bufm[32],
17083 : bufx[32];
17084 CBC 315 : PQExpBuffer query = createPQExpBuffer();
17085 315 : PQExpBuffer delqry = createPQExpBuffer();
17086 : char *qseqname;
17087 315 : TableInfo *owning_tab = NULL;
17088 ECB :
17089 CBC 315 : qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
17090 ECB :
17091 GIC 315 : if (fout->remoteVersion >= 100000)
17092 : {
17093 315 : appendPQExpBuffer(query,
17094 : "SELECT format_type(seqtypid, NULL), "
17095 ECB : "seqstart, seqincrement, "
17096 : "seqmax, seqmin, "
17097 : "seqcache, seqcycle "
17098 EUB : "FROM pg_catalog.pg_sequence "
17099 : "WHERE seqrelid = '%u'::oid",
17100 GIC 315 : tbinfo->dobj.catId.oid);
17101 ECB : }
17102 : else
17103 : {
17104 : /*
17105 : * Before PostgreSQL 10, sequence metadata is in the sequence itself.
17106 : *
17107 : * Note: it might seem that 'bigint' potentially needs to be
17108 : * schema-qualified, but actually that's a keyword.
17109 : */
17110 LBC 0 : appendPQExpBuffer(query,
17111 : "SELECT 'bigint' AS sequence_type, "
17112 : "start_value, increment_by, max_value, min_value, "
17113 ECB : "cache_value, is_cycled FROM %s",
17114 UIC 0 : fmtQualifiedDumpable(tbinfo));
17115 : }
17116 :
17117 CBC 315 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17118 ECB :
17119 GIC 315 : if (PQntuples(res) != 1)
17120 UIC 0 : pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
17121 : "query to get data of sequence \"%s\" returned %d rows (expected 1)",
17122 : PQntuples(res)),
17123 : tbinfo->dobj.name, PQntuples(res));
17124 ECB :
17125 GBC 315 : seqtype = PQgetvalue(res, 0, 0);
17126 CBC 315 : startv = PQgetvalue(res, 0, 1);
17127 315 : incby = PQgetvalue(res, 0, 2);
17128 GIC 315 : maxv = PQgetvalue(res, 0, 3);
17129 CBC 315 : minv = PQgetvalue(res, 0, 4);
17130 GIC 315 : cache = PQgetvalue(res, 0, 5);
17131 315 : cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
17132 ECB :
17133 EUB : /* Calculate default limits for a sequence of this type */
17134 CBC 315 : is_ascending = (incby[0] != '-');
17135 GIC 315 : if (strcmp(seqtype, "smallint") == 0)
17136 ECB : {
17137 GIC 25 : default_minv = is_ascending ? 1 : PG_INT16_MIN;
17138 25 : default_maxv = is_ascending ? PG_INT16_MAX : -1;
17139 : }
17140 290 : else if (strcmp(seqtype, "integer") == 0)
17141 ECB : {
17142 CBC 241 : default_minv = is_ascending ? 1 : PG_INT32_MIN;
17143 GIC 241 : default_maxv = is_ascending ? PG_INT32_MAX : -1;
17144 ECB : }
17145 GIC 49 : else if (strcmp(seqtype, "bigint") == 0)
17146 ECB : {
17147 GIC 49 : default_minv = is_ascending ? 1 : PG_INT64_MIN;
17148 49 : default_maxv = is_ascending ? PG_INT64_MAX : -1;
17149 ECB : }
17150 EUB : else
17151 ECB : {
17152 UIC 0 : pg_fatal("unrecognized sequence type: %s", seqtype);
17153 ECB : default_minv = default_maxv = 0; /* keep compiler quiet */
17154 : }
17155 :
17156 : /*
17157 : * 64-bit strtol() isn't very portable, so convert the limits to strings
17158 : * and compare that way.
17159 : */
17160 CBC 315 : snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
17161 GIC 315 : snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
17162 EUB :
17163 : /* Don't print minv/maxv if they match the respective default limit */
17164 GBC 315 : if (strcmp(minv, bufm) == 0)
17165 GIC 300 : minv = NULL;
17166 315 : if (strcmp(maxv, bufx) == 0)
17167 CBC 300 : maxv = NULL;
17168 :
17169 EUB : /*
17170 : * Identity sequences are not to be dropped separately.
17171 : */
17172 GIC 315 : if (!tbinfo->is_identity_sequence)
17173 : {
17174 CBC 209 : appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
17175 GIC 209 : fmtQualifiedDumpable(tbinfo));
17176 : }
17177 :
17178 315 : resetPQExpBuffer(query);
17179 :
17180 315 : if (dopt->binary_upgrade)
17181 : {
17182 48 : binary_upgrade_set_pg_class_oids(fout, query,
17183 48 : tbinfo->dobj.catId.oid, false);
17184 ECB :
17185 : /*
17186 : * In older PG versions a sequence will have a pg_type entry, but v14
17187 : * and up don't use that, so don't attempt to preserve the type OID.
17188 : */
17189 : }
17190 :
17191 GIC 315 : if (tbinfo->is_identity_sequence)
17192 : {
17193 106 : owning_tab = findTableByOid(tbinfo->owning_tab);
17194 ECB :
17195 GIC 106 : appendPQExpBuffer(query,
17196 EUB : "ALTER TABLE %s ",
17197 GBC 106 : fmtQualifiedDumpable(owning_tab));
17198 GIC 106 : appendPQExpBuffer(query,
17199 EUB : "ALTER COLUMN %s ADD GENERATED ",
17200 GBC 106 : fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17201 GIC 106 : if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
17202 71 : appendPQExpBufferStr(query, "ALWAYS");
17203 35 : else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
17204 CBC 35 : appendPQExpBufferStr(query, "BY DEFAULT");
17205 GIC 106 : appendPQExpBuffer(query, " AS IDENTITY (\n SEQUENCE NAME %s\n",
17206 CBC 106 : fmtQualifiedDumpable(tbinfo));
17207 : }
17208 ECB : else
17209 : {
17210 CBC 209 : appendPQExpBuffer(query,
17211 ECB : "CREATE %sSEQUENCE %s\n",
17212 GIC 209 : tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
17213 ECB : "UNLOGGED " : "",
17214 GIC 209 : fmtQualifiedDumpable(tbinfo));
17215 ECB :
17216 CBC 209 : if (strcmp(seqtype, "bigint") != 0)
17217 165 : appendPQExpBuffer(query, " AS %s\n", seqtype);
17218 : }
17219 :
17220 GIC 315 : appendPQExpBuffer(query, " START WITH %s\n", startv);
17221 :
17222 315 : appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
17223 :
17224 315 : if (minv)
17225 15 : appendPQExpBuffer(query, " MINVALUE %s\n", minv);
17226 ECB : else
17227 GIC 300 : appendPQExpBufferStr(query, " NO MINVALUE\n");
17228 :
17229 315 : if (maxv)
17230 15 : appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
17231 : else
17232 300 : appendPQExpBufferStr(query, " NO MAXVALUE\n");
17233 :
17234 315 : appendPQExpBuffer(query,
17235 : " CACHE %s%s",
17236 ECB : cache, (cycled ? "\n CYCLE" : ""));
17237 :
17238 GIC 315 : if (tbinfo->is_identity_sequence)
17239 : {
17240 106 : appendPQExpBufferStr(query, "\n);\n");
17241 106 : if (tbinfo->relpersistence != owning_tab->relpersistence)
17242 LBC 0 : appendPQExpBuffer(query,
17243 ECB : "ALTER SEQUENCE %s SET %s;\n",
17244 LBC 0 : fmtQualifiedDumpable(tbinfo),
17245 0 : tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
17246 ECB : "UNLOGGED" : "LOGGED");
17247 : }
17248 : else
17249 CBC 209 : appendPQExpBufferStr(query, ";\n");
17250 ECB :
17251 : /* binary_upgrade: no need to clear TOAST table oid */
17252 :
17253 CBC 315 : if (dopt->binary_upgrade)
17254 GIC 48 : binary_upgrade_extension_member(query, &tbinfo->dobj,
17255 ECB : "SEQUENCE", qseqname,
17256 CBC 48 : tbinfo->dobj.namespace->dobj.name);
17257 ECB :
17258 GIC 315 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17259 315 : ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
17260 315 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17261 : .namespace = tbinfo->dobj.namespace->dobj.name,
17262 : .owner = tbinfo->rolname,
17263 : .description = "SEQUENCE",
17264 : .section = SECTION_PRE_DATA,
17265 ECB : .createStmt = query->data,
17266 : .dropStmt = delqry->data));
17267 EUB :
17268 : /*
17269 : * If the sequence is owned by a table column, emit the ALTER for it as a
17270 : * separate TOC entry immediately following the sequence's own entry. It's
17271 : * OK to do this rather than using full sorting logic, because the
17272 : * dependency that tells us it's owned will have forced the table to be
17273 : * created first. We can't just include the ALTER in the TOC entry
17274 : * because it will fail if we haven't reassigned the sequence owner to
17275 : * match the table's owner.
17276 : *
17277 : * We need not schema-qualify the table reference because both sequence
17278 : * and table must be in the same schema.
17279 : */
17280 GBC 315 : if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
17281 EUB : {
17282 GBC 120 : owning_tab = findTableByOid(tbinfo->owning_tab);
17283 :
17284 GIC 120 : if (owning_tab == NULL)
17285 UIC 0 : pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
17286 : tbinfo->owning_tab, tbinfo->dobj.catId.oid);
17287 :
17288 GIC 120 : if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
17289 : {
17290 CBC 118 : resetPQExpBuffer(query);
17291 GIC 118 : appendPQExpBuffer(query, "ALTER SEQUENCE %s",
17292 118 : fmtQualifiedDumpable(tbinfo));
17293 118 : appendPQExpBuffer(query, " OWNED BY %s",
17294 118 : fmtQualifiedDumpable(owning_tab));
17295 CBC 118 : appendPQExpBuffer(query, ".%s;\n",
17296 GIC 118 : fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17297 :
17298 CBC 118 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17299 118 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
17300 118 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17301 ECB : .namespace = tbinfo->dobj.namespace->dobj.name,
17302 : .owner = tbinfo->rolname,
17303 : .description = "SEQUENCE OWNED BY",
17304 : .section = SECTION_PRE_DATA,
17305 : .createStmt = query->data,
17306 : .deps = &(tbinfo->dobj.dumpId),
17307 : .nDeps = 1));
17308 : }
17309 : }
17310 :
17311 : /* Dump Sequence Comments and Security Labels */
17312 CBC 315 : if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17313 LBC 0 : dumpComment(fout, "SEQUENCE", qseqname,
17314 UIC 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17315 0 : tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17316 :
17317 GIC 315 : if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
17318 UIC 0 : dumpSecLabel(fout, "SEQUENCE", qseqname,
17319 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17320 0 : tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17321 :
17322 CBC 315 : PQclear(res);
17323 ECB :
17324 GIC 315 : destroyPQExpBuffer(query);
17325 CBC 315 : destroyPQExpBuffer(delqry);
17326 GIC 315 : free(qseqname);
17327 315 : }
17328 ECB :
17329 : /*
17330 EUB : * dumpSequenceData
17331 : * write the data of one user-defined sequence
17332 : */
17333 : static void
17334 GBC 338 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
17335 : {
17336 338 : TableInfo *tbinfo = tdinfo->tdtable;
17337 EUB : PGresult *res;
17338 : char *last;
17339 : bool called;
17340 GIC 338 : PQExpBuffer query = createPQExpBuffer();
17341 EUB :
17342 GIC 338 : appendPQExpBuffer(query,
17343 EUB : "SELECT last_value, is_called FROM %s",
17344 GBC 338 : fmtQualifiedDumpable(tbinfo));
17345 EUB :
17346 GIC 338 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17347 :
17348 338 : if (PQntuples(res) != 1)
17349 UIC 0 : pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
17350 : "query to get data of sequence \"%s\" returned %d rows (expected 1)",
17351 : PQntuples(res)),
17352 : tbinfo->dobj.name, PQntuples(res));
17353 :
17354 GIC 338 : last = PQgetvalue(res, 0, 0);
17355 338 : called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
17356 EUB :
17357 GIC 338 : resetPQExpBuffer(query);
17358 338 : appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
17359 338 : appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
17360 338 : appendPQExpBuffer(query, ", %s, %s);\n",
17361 ECB : last, (called ? "true" : "false"));
17362 :
17363 CBC 338 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
17364 GIC 338 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
17365 CBC 338 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17366 ECB : .namespace = tbinfo->dobj.namespace->dobj.name,
17367 : .owner = tbinfo->rolname,
17368 : .description = "SEQUENCE SET",
17369 : .section = SECTION_DATA,
17370 : .createStmt = query->data,
17371 : .deps = &(tbinfo->dobj.dumpId),
17372 : .nDeps = 1));
17373 :
17374 GIC 338 : PQclear(res);
17375 :
17376 338 : destroyPQExpBuffer(query);
17377 338 : }
17378 ECB :
17379 : /*
17380 : * dumpTrigger
17381 : * write the declaration of one user-defined table trigger
17382 : */
17383 : static void
17384 CBC 504 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
17385 : {
17386 504 : DumpOptions *dopt = fout->dopt;
17387 504 : TableInfo *tbinfo = tginfo->tgtable;
17388 : PQExpBuffer query;
17389 ECB : PQExpBuffer delqry;
17390 : PQExpBuffer trigprefix;
17391 : PQExpBuffer trigidentity;
17392 : char *qtabname;
17393 : char *tgargs;
17394 : size_t lentgargs;
17395 : const char *p;
17396 : int findx;
17397 : char *tag;
17398 :
17399 : /* Do nothing in data-only dump */
17400 GIC 504 : if (dopt->dataOnly)
17401 16 : return;
17402 :
17403 488 : query = createPQExpBuffer();
17404 488 : delqry = createPQExpBuffer();
17405 CBC 488 : trigprefix = createPQExpBuffer();
17406 GIC 488 : trigidentity = createPQExpBuffer();
17407 ECB :
17408 GIC 488 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17409 :
17410 488 : appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
17411 488 : appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
17412 :
17413 488 : appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
17414 :
17415 488 : if (tginfo->tgdef)
17416 : {
17417 488 : appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17418 : }
17419 : else
17420 : {
17421 LBC 0 : if (tginfo->tgisconstraint)
17422 ECB : {
17423 UIC 0 : appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
17424 LBC 0 : appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
17425 : }
17426 ECB : else
17427 : {
17428 LBC 0 : appendPQExpBufferStr(query, "CREATE TRIGGER ");
17429 UIC 0 : appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
17430 ECB : }
17431 UIC 0 : appendPQExpBufferStr(query, "\n ");
17432 :
17433 : /* Trigger type */
17434 0 : if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
17435 0 : appendPQExpBufferStr(query, "BEFORE");
17436 0 : else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
17437 LBC 0 : appendPQExpBufferStr(query, "AFTER");
17438 UIC 0 : else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
17439 0 : appendPQExpBufferStr(query, "INSTEAD OF");
17440 : else
17441 0 : pg_fatal("unexpected tgtype value: %d", tginfo->tgtype);
17442 :
17443 0 : findx = 0;
17444 0 : if (TRIGGER_FOR_INSERT(tginfo->tgtype))
17445 : {
17446 0 : appendPQExpBufferStr(query, " INSERT");
17447 UBC 0 : findx++;
17448 : }
17449 UIC 0 : if (TRIGGER_FOR_DELETE(tginfo->tgtype))
17450 : {
17451 UBC 0 : if (findx > 0)
17452 UIC 0 : appendPQExpBufferStr(query, " OR DELETE");
17453 : else
17454 LBC 0 : appendPQExpBufferStr(query, " DELETE");
17455 UIC 0 : findx++;
17456 ECB : }
17457 UBC 0 : if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
17458 : {
17459 UIC 0 : if (findx > 0)
17460 0 : appendPQExpBufferStr(query, " OR UPDATE");
17461 : else
17462 LBC 0 : appendPQExpBufferStr(query, " UPDATE");
17463 0 : findx++;
17464 ECB : }
17465 LBC 0 : if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
17466 ECB : {
17467 LBC 0 : if (findx > 0)
17468 0 : appendPQExpBufferStr(query, " OR TRUNCATE");
17469 : else
17470 UIC 0 : appendPQExpBufferStr(query, " TRUNCATE");
17471 LBC 0 : findx++;
17472 ECB : }
17473 UIC 0 : appendPQExpBuffer(query, " ON %s\n",
17474 LBC 0 : fmtQualifiedDumpable(tbinfo));
17475 ECB :
17476 UIC 0 : if (tginfo->tgisconstraint)
17477 ECB : {
17478 UIC 0 : if (OidIsValid(tginfo->tgconstrrelid))
17479 ECB : {
17480 : /* regclass output is already quoted */
17481 UIC 0 : appendPQExpBuffer(query, " FROM %s\n ",
17482 LBC 0 : tginfo->tgconstrrelname);
17483 : }
17484 0 : if (!tginfo->tgdeferrable)
17485 0 : appendPQExpBufferStr(query, "NOT ");
17486 UIC 0 : appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
17487 0 : if (tginfo->tginitdeferred)
17488 0 : appendPQExpBufferStr(query, "DEFERRED\n");
17489 EUB : else
17490 UIC 0 : appendPQExpBufferStr(query, "IMMEDIATE\n");
17491 : }
17492 :
17493 0 : if (TRIGGER_FOR_ROW(tginfo->tgtype))
17494 0 : appendPQExpBufferStr(query, " FOR EACH ROW\n ");
17495 : else
17496 0 : appendPQExpBufferStr(query, " FOR EACH STATEMENT\n ");
17497 ECB :
17498 : /* regproc output is already sufficiently quoted */
17499 UIC 0 : appendPQExpBuffer(query, "EXECUTE FUNCTION %s(",
17500 0 : tginfo->tgfname);
17501 ECB :
17502 LBC 0 : tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
17503 ECB : &lentgargs);
17504 LBC 0 : p = tgargs;
17505 UIC 0 : for (findx = 0; findx < tginfo->tgnargs; findx++)
17506 : {
17507 : /* find the embedded null that terminates this trigger argument */
17508 0 : size_t tlen = strlen(p);
17509 ECB :
17510 UIC 0 : if (p + tlen >= tgargs + lentgargs)
17511 ECB : {
17512 : /* hm, not found before end of bytea value... */
17513 UIC 0 : pg_fatal("invalid argument string (%s) for trigger \"%s\" on table \"%s\"",
17514 : tginfo->tgargs,
17515 ECB : tginfo->dobj.name,
17516 : tbinfo->dobj.name);
17517 : }
17518 :
17519 LBC 0 : if (findx > 0)
17520 0 : appendPQExpBufferStr(query, ", ");
17521 UIC 0 : appendStringLiteralAH(query, p, fout);
17522 0 : p += tlen + 1;
17523 : }
17524 0 : free(tgargs);
17525 0 : appendPQExpBufferStr(query, ");\n");
17526 : }
17527 :
17528 ECB : /* Triggers can depend on extensions */
17529 GIC 488 : append_depends_on_extension(fout, query, &tginfo->dobj,
17530 ECB : "pg_catalog.pg_trigger", "TRIGGER",
17531 GIC 488 : trigidentity->data);
17532 ECB :
17533 GIC 488 : if (tginfo->tgispartition)
17534 ECB : {
17535 CBC 121 : Assert(tbinfo->ispartition);
17536 :
17537 ECB : /*
17538 : * Partition triggers only appear here because their 'tgenabled' flag
17539 : * differs from its parent's. The trigger is created already, so
17540 : * remove the CREATE and replace it with an ALTER. (Clear out the
17541 : * DROP query too, so that pg_dump --create does not cause errors.)
17542 : */
17543 CBC 121 : resetPQExpBuffer(query);
17544 GIC 121 : resetPQExpBuffer(delqry);
17545 121 : appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
17546 121 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
17547 CBC 121 : fmtQualifiedDumpable(tbinfo));
17548 GIC 121 : switch (tginfo->tgenabled)
17549 ECB : {
17550 GIC 42 : case 'f':
17551 ECB : case 'D':
17552 GIC 42 : appendPQExpBufferStr(query, "DISABLE");
17553 CBC 42 : break;
17554 LBC 0 : case 't':
17555 : case 'O':
17556 UIC 0 : appendPQExpBufferStr(query, "ENABLE");
17557 LBC 0 : break;
17558 GIC 37 : case 'R':
17559 CBC 37 : appendPQExpBufferStr(query, "ENABLE REPLICA");
17560 GIC 37 : break;
17561 CBC 42 : case 'A':
17562 42 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
17563 GIC 42 : break;
17564 ECB : }
17565 GIC 121 : appendPQExpBuffer(query, " TRIGGER %s;\n",
17566 CBC 121 : fmtId(tginfo->dobj.name));
17567 ECB : }
17568 GIC 367 : else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17569 ECB : {
17570 UIC 0 : appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
17571 LBC 0 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
17572 UIC 0 : fmtQualifiedDumpable(tbinfo));
17573 0 : switch (tginfo->tgenabled)
17574 : {
17575 LBC 0 : case 'D':
17576 : case 'f':
17577 0 : appendPQExpBufferStr(query, "DISABLE");
17578 0 : break;
17579 UBC 0 : case 'A':
17580 UIC 0 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
17581 UBC 0 : break;
17582 0 : case 'R':
17583 UIC 0 : appendPQExpBufferStr(query, "ENABLE REPLICA");
17584 0 : break;
17585 0 : default:
17586 LBC 0 : appendPQExpBufferStr(query, "ENABLE");
17587 UIC 0 : break;
17588 : }
17589 0 : appendPQExpBuffer(query, " TRIGGER %s;\n",
17590 LBC 0 : fmtId(tginfo->dobj.name));
17591 ECB : }
17592 :
17593 CBC 488 : appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17594 GIC 488 : fmtId(tginfo->dobj.name));
17595 ECB :
17596 CBC 488 : tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17597 ECB :
17598 GIC 488 : if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17599 488 : ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17600 488 : ARCHIVE_OPTS(.tag = tag,
17601 : .namespace = tbinfo->dobj.namespace->dobj.name,
17602 : .owner = tbinfo->rolname,
17603 : .description = "TRIGGER",
17604 : .section = SECTION_POST_DATA,
17605 : .createStmt = query->data,
17606 : .dropStmt = delqry->data));
17607 :
17608 488 : if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17609 UIC 0 : dumpComment(fout, trigprefix->data, qtabname,
17610 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17611 0 : tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17612 :
17613 GIC 488 : free(tag);
17614 488 : destroyPQExpBuffer(query);
17615 488 : destroyPQExpBuffer(delqry);
17616 488 : destroyPQExpBuffer(trigprefix);
17617 CBC 488 : destroyPQExpBuffer(trigidentity);
17618 GIC 488 : free(qtabname);
17619 ECB : }
17620 :
17621 : /*
17622 EUB : * dumpEventTrigger
17623 : * write the declaration of one user-defined event trigger
17624 : */
17625 ECB : static void
17626 GIC 38 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
17627 ECB : {
17628 CBC 38 : DumpOptions *dopt = fout->dopt;
17629 ECB : PQExpBuffer query;
17630 : PQExpBuffer delqry;
17631 : char *qevtname;
17632 :
17633 : /* Do nothing in data-only dump */
17634 GIC 38 : if (dopt->dataOnly)
17635 CBC 3 : return;
17636 ECB :
17637 CBC 35 : query = createPQExpBuffer();
17638 GIC 35 : delqry = createPQExpBuffer();
17639 :
17640 35 : qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17641 :
17642 35 : appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17643 35 : appendPQExpBufferStr(query, qevtname);
17644 35 : appendPQExpBufferStr(query, " ON ");
17645 35 : appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17646 :
17647 35 : if (strcmp("", evtinfo->evttags) != 0)
17648 : {
17649 LBC 0 : appendPQExpBufferStr(query, "\n WHEN TAG IN (");
17650 UBC 0 : appendPQExpBufferStr(query, evtinfo->evttags);
17651 0 : appendPQExpBufferChar(query, ')');
17652 EUB : }
17653 :
17654 CBC 35 : appendPQExpBufferStr(query, "\n EXECUTE FUNCTION ");
17655 GBC 35 : appendPQExpBufferStr(query, evtinfo->evtfname);
17656 35 : appendPQExpBufferStr(query, "();\n");
17657 EUB :
17658 GIC 35 : if (evtinfo->evtenabled != 'O')
17659 ECB : {
17660 UIC 0 : appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17661 ECB : qevtname);
17662 LBC 0 : switch (evtinfo->evtenabled)
17663 ECB : {
17664 LBC 0 : case 'D':
17665 UIC 0 : appendPQExpBufferStr(query, "DISABLE");
17666 0 : break;
17667 0 : case 'A':
17668 0 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
17669 0 : break;
17670 0 : case 'R':
17671 LBC 0 : appendPQExpBufferStr(query, "ENABLE REPLICA");
17672 UIC 0 : break;
17673 LBC 0 : default:
17674 UIC 0 : appendPQExpBufferStr(query, "ENABLE");
17675 0 : break;
17676 : }
17677 LBC 0 : appendPQExpBufferStr(query, ";\n");
17678 : }
17679 ECB :
17680 GIC 35 : appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17681 ECB : qevtname);
17682 :
17683 CBC 35 : if (dopt->binary_upgrade)
17684 GIC 1 : binary_upgrade_extension_member(query, &evtinfo->dobj,
17685 ECB : "EVENT TRIGGER", qevtname, NULL);
17686 EUB :
17687 GIC 35 : if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17688 35 : ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17689 35 : ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
17690 : .owner = evtinfo->evtowner,
17691 ECB : .description = "EVENT TRIGGER",
17692 : .section = SECTION_POST_DATA,
17693 : .createStmt = query->data,
17694 : .dropStmt = delqry->data));
17695 :
17696 CBC 35 : if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17697 LBC 0 : dumpComment(fout, "EVENT TRIGGER", qevtname,
17698 UIC 0 : NULL, evtinfo->evtowner,
17699 0 : evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17700 ECB :
17701 CBC 35 : destroyPQExpBuffer(query);
17702 35 : destroyPQExpBuffer(delqry);
17703 GIC 35 : free(qevtname);
17704 : }
17705 :
17706 : /*
17707 : * dumpRule
17708 : * Dump a rule
17709 : */
17710 : static void
17711 CBC 821 : dumpRule(Archive *fout, const RuleInfo *rinfo)
17712 : {
17713 821 : DumpOptions *dopt = fout->dopt;
17714 821 : TableInfo *tbinfo = rinfo->ruletable;
17715 : bool is_view;
17716 : PQExpBuffer query;
17717 : PQExpBuffer cmd;
17718 : PQExpBuffer delcmd;
17719 : PQExpBuffer ruleprefix;
17720 : char *qtabname;
17721 ECB : PGresult *res;
17722 : char *tag;
17723 :
17724 : /* Do nothing in data-only dump */
17725 GIC 821 : if (dopt->dataOnly)
17726 27 : return;
17727 :
17728 : /*
17729 : * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17730 : * we do not want to dump it as a separate object.
17731 : */
17732 794 : if (!rinfo->separate)
17733 589 : return;
17734 :
17735 : /*
17736 : * If it's an ON SELECT rule, we want to print it as a view definition,
17737 ECB : * instead of a rule.
17738 : */
17739 GIC 205 : is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17740 ECB :
17741 CBC 205 : query = createPQExpBuffer();
17742 205 : cmd = createPQExpBuffer();
17743 205 : delcmd = createPQExpBuffer();
17744 GIC 205 : ruleprefix = createPQExpBuffer();
17745 ECB :
17746 GIC 205 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17747 ECB :
17748 CBC 205 : if (is_view)
17749 : {
17750 ECB : PQExpBuffer result;
17751 :
17752 : /*
17753 : * We need OR REPLACE here because we'll be replacing a dummy view.
17754 : * Otherwise this should look largely like the regular view dump code.
17755 : */
17756 GIC 10 : appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17757 10 : fmtQualifiedDumpable(tbinfo));
17758 GBC 10 : if (nonemptyReloptions(tbinfo->reloptions))
17759 : {
17760 UBC 0 : appendPQExpBufferStr(cmd, " WITH (");
17761 0 : appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17762 UIC 0 : appendPQExpBufferChar(cmd, ')');
17763 : }
17764 GIC 10 : result = createViewAsClause(fout, tbinfo);
17765 GBC 10 : appendPQExpBuffer(cmd, " AS\n%s", result->data);
17766 10 : destroyPQExpBuffer(result);
17767 GIC 10 : if (tbinfo->checkoption != NULL)
17768 UBC 0 : appendPQExpBuffer(cmd, "\n WITH %s CHECK OPTION",
17769 : tbinfo->checkoption);
17770 GIC 10 : appendPQExpBufferStr(cmd, ";\n");
17771 EUB : }
17772 : else
17773 : {
17774 : /* In the rule case, just print pg_get_ruledef's result verbatim */
17775 GBC 195 : appendPQExpBuffer(query,
17776 EUB : "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17777 GIC 195 : rinfo->dobj.catId.oid);
17778 EUB :
17779 GIC 195 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17780 EUB :
17781 GBC 195 : if (PQntuples(res) != 1)
17782 UIC 0 : pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
17783 EUB : rinfo->dobj.name, tbinfo->dobj.name);
17784 :
17785 GIC 195 : printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17786 EUB :
17787 GIC 195 : PQclear(res);
17788 EUB : }
17789 :
17790 : /*
17791 : * Add the command to alter the rules replication firing semantics if it
17792 : * differs from the default.
17793 : */
17794 GBC 205 : if (rinfo->ev_enabled != 'O')
17795 : {
17796 UBC 0 : appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17797 0 : switch (rinfo->ev_enabled)
17798 : {
17799 0 : case 'A':
17800 0 : appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17801 UIC 0 : fmtId(rinfo->dobj.name));
17802 UBC 0 : break;
17803 UIC 0 : case 'R':
17804 UBC 0 : appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17805 0 : fmtId(rinfo->dobj.name));
17806 UIC 0 : break;
17807 UBC 0 : case 'D':
17808 0 : appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17809 UIC 0 : fmtId(rinfo->dobj.name));
17810 UBC 0 : break;
17811 EUB : }
17812 : }
17813 :
17814 GIC 205 : if (is_view)
17815 EUB : {
17816 : /*
17817 : * We can't DROP a view's ON SELECT rule. Instead, use CREATE OR
17818 : * REPLACE VIEW to replace the rule with something with minimal
17819 : * dependencies.
17820 : */
17821 : PQExpBuffer result;
17822 :
17823 GBC 10 : appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17824 10 : fmtQualifiedDumpable(tbinfo));
17825 10 : result = createDummyViewAsClause(fout, tbinfo);
17826 GIC 10 : appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17827 GBC 10 : destroyPQExpBuffer(result);
17828 : }
17829 : else
17830 EUB : {
17831 GBC 195 : appendPQExpBuffer(delcmd, "DROP RULE %s ",
17832 GIC 195 : fmtId(rinfo->dobj.name));
17833 GBC 195 : appendPQExpBuffer(delcmd, "ON %s;\n",
17834 GIC 195 : fmtQualifiedDumpable(tbinfo));
17835 : }
17836 EUB :
17837 GBC 205 : appendPQExpBuffer(ruleprefix, "RULE %s ON",
17838 GIC 205 : fmtId(rinfo->dobj.name));
17839 EUB :
17840 GIC 205 : tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17841 EUB :
17842 GBC 205 : if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17843 GIC 205 : ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17844 205 : ARCHIVE_OPTS(.tag = tag,
17845 EUB : .namespace = tbinfo->dobj.namespace->dobj.name,
17846 : .owner = tbinfo->rolname,
17847 : .description = "RULE",
17848 : .section = SECTION_POST_DATA,
17849 : .createStmt = cmd->data,
17850 : .dropStmt = delcmd->data));
17851 :
17852 : /* Dump rule comments */
17853 GIC 205 : if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17854 UIC 0 : dumpComment(fout, ruleprefix->data, qtabname,
17855 0 : tbinfo->dobj.namespace->dobj.name,
17856 EUB : tbinfo->rolname,
17857 UBC 0 : rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17858 EUB :
17859 GBC 205 : free(tag);
17860 GIC 205 : destroyPQExpBuffer(query);
17861 GBC 205 : destroyPQExpBuffer(cmd);
17862 205 : destroyPQExpBuffer(delcmd);
17863 GIC 205 : destroyPQExpBuffer(ruleprefix);
17864 205 : free(qtabname);
17865 : }
17866 ECB :
17867 : /*
17868 : * getExtensionMembership --- obtain extension membership data
17869 : *
17870 : * We need to identify objects that are extension members as soon as they're
17871 : * loaded, so that we can correctly determine whether they need to be dumped.
17872 : * Generally speaking, extension member objects will get marked as *not* to
17873 : * be dumped, as they will be recreated by the single CREATE EXTENSION
17874 : * command. However, in binary upgrade mode we still need to dump the members
17875 : * individually.
17876 : */
17877 : void
17878 GIC 119 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17879 : int numExtensions)
17880 ECB : {
17881 : PQExpBuffer query;
17882 : PGresult *res;
17883 : int ntups,
17884 : i;
17885 : int i_classid,
17886 : i_objid,
17887 : i_refobjid;
17888 : ExtensionInfo *ext;
17889 :
17890 : /* Nothing to do if no extensions */
17891 GBC 119 : if (numExtensions == 0)
17892 UIC 0 : return;
17893 EUB :
17894 GBC 119 : query = createPQExpBuffer();
17895 ECB :
17896 : /* refclassid constraint is redundant but may speed the search */
17897 CBC 119 : appendPQExpBufferStr(query, "SELECT "
17898 ECB : "classid, objid, refobjid "
17899 : "FROM pg_depend "
17900 : "WHERE refclassid = 'pg_extension'::regclass "
17901 : "AND deptype = 'e' "
17902 : "ORDER BY 3");
17903 :
17904 GIC 119 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17905 ECB :
17906 GIC 119 : ntups = PQntuples(res);
17907 EUB :
17908 GBC 119 : i_classid = PQfnumber(res, "classid");
17909 119 : i_objid = PQfnumber(res, "objid");
17910 119 : i_refobjid = PQfnumber(res, "refobjid");
17911 :
17912 EUB : /*
17913 : * Since we ordered the SELECT by referenced ID, we can expect that
17914 : * multiple entries for the same extension will appear together; this
17915 : * saves on searches.
17916 : */
17917 GBC 119 : ext = NULL;
17918 EUB :
17919 GBC 925 : for (i = 0; i < ntups; i++)
17920 EUB : {
17921 : CatalogId objId;
17922 : Oid extId;
17923 :
17924 GBC 806 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17925 GIC 806 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
17926 GBC 806 : extId = atooid(PQgetvalue(res, i, i_refobjid));
17927 EUB :
17928 GIC 806 : if (ext == NULL ||
17929 687 : ext->dobj.catId.oid != extId)
17930 CBC 141 : ext = findExtensionByOid(extId);
17931 ECB :
17932 GIC 806 : if (ext == NULL)
17933 ECB : {
17934 : /* shouldn't happen */
17935 LBC 0 : pg_log_warning("could not find referenced extension %u", extId);
17936 0 : continue;
17937 ECB : }
17938 :
17939 GIC 806 : recordExtensionMembership(objId, ext);
17940 : }
17941 :
17942 119 : PQclear(res);
17943 :
17944 119 : destroyPQExpBuffer(query);
17945 ECB : }
17946 EUB :
17947 : /*
17948 : * processExtensionTables --- deal with extension configuration tables
17949 : *
17950 ECB : * There are two parts to this process:
17951 : *
17952 : * 1. Identify and create dump records for extension configuration tables.
17953 : *
17954 : * Extensions can mark tables as "configuration", which means that the user
17955 : * is able and expected to modify those tables after the extension has been
17956 : * loaded. For these tables, we dump out only the data- the structure is
17957 : * expected to be handled at CREATE EXTENSION time, including any indexes or
17958 : * foreign keys, which brings us to-
17959 : *
17960 : * 2. Record FK dependencies between configuration tables.
17961 : *
17962 : * Due to the FKs being created at CREATE EXTENSION time and therefore before
17963 : * the data is loaded, we have to work out what the best order for reloading
17964 : * the data is, to avoid FK violations when the tables are restored. This is
17965 : * not perfect- we can't handle circular dependencies and if any exist they
17966 : * will cause an invalid dump to be produced (though at least all of the data
17967 : * is included for a user to manually restore). This is currently documented
17968 : * but perhaps we can provide a better solution in the future.
17969 : */
17970 : void
17971 CBC 118 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17972 ECB : int numExtensions)
17973 : {
17974 CBC 118 : DumpOptions *dopt = fout->dopt;
17975 ECB : PQExpBuffer query;
17976 : PGresult *res;
17977 : int ntups,
17978 : i;
17979 : int i_conrelid,
17980 : i_confrelid;
17981 :
17982 : /* Nothing to do if no extensions */
17983 GIC 118 : if (numExtensions == 0)
17984 LBC 0 : return;
17985 :
17986 EUB : /*
17987 : * Identify extension configuration tables and create TableDataInfo
17988 : * objects for them, ensuring their data will be dumped even though the
17989 : * tables themselves won't be.
17990 : *
17991 ECB : * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17992 : * user data in a configuration table is treated like schema data. This
17993 : * seems appropriate since system data in a config table would get
17994 : * reloaded by CREATE EXTENSION. If the extension is not listed in the
17995 : * list of extensions to be included, none of its data is dumped.
17996 : */
17997 GBC 258 : for (i = 0; i < numExtensions; i++)
17998 : {
17999 140 : ExtensionInfo *curext = &(extinfo[i]);
18000 GIC 140 : char *extconfig = curext->extconfig;
18001 GBC 140 : char *extcondition = curext->extcondition;
18002 140 : char **extconfigarray = NULL;
18003 140 : char **extconditionarray = NULL;
18004 140 : int nconfigitems = 0;
18005 140 : int nconditionitems = 0;
18006 EUB :
18007 : /*
18008 : * Check if this extension is listed as to include in the dump. If
18009 : * not, any table data associated with it is discarded.
18010 : */
18011 GBC 140 : if (extension_include_oids.head != NULL &&
18012 8 : !simple_oid_list_member(&extension_include_oids,
18013 : curext->dobj.catId.oid))
18014 4 : continue;
18015 :
18016 GIC 136 : if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
18017 ECB : {
18018 : int j;
18019 :
18020 CBC 19 : if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
18021 LBC 0 : pg_fatal("could not parse %s array", "extconfig");
18022 GIC 19 : if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
18023 UIC 0 : pg_fatal("could not parse %s array", "extcondition");
18024 CBC 19 : if (nconfigitems != nconditionitems)
18025 LBC 0 : pg_fatal("mismatched number of configurations and conditions for extension");
18026 ECB :
18027 GIC 57 : for (j = 0; j < nconfigitems; j++)
18028 : {
18029 : TableInfo *configtbl;
18030 38 : Oid configtbloid = atooid(extconfigarray[j]);
18031 38 : bool dumpobj =
18032 38 : curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
18033 ECB :
18034 GBC 38 : configtbl = findTableByOid(configtbloid);
18035 38 : if (configtbl == NULL)
18036 UBC 0 : continue;
18037 :
18038 ECB : /*
18039 : * Tables of not-to-be-dumped extensions shouldn't be dumped
18040 : * unless the table or its schema is explicitly included
18041 : */
18042 GIC 38 : if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
18043 : {
18044 : /* check table explicitly requested */
18045 2 : if (table_include_oids.head != NULL &&
18046 UIC 0 : simple_oid_list_member(&table_include_oids,
18047 : configtbloid))
18048 LBC 0 : dumpobj = true;
18049 :
18050 ECB : /* check table's schema explicitly requested */
18051 CBC 2 : if (configtbl->dobj.namespace->dobj.dump &
18052 : DUMP_COMPONENT_DATA)
18053 GIC 2 : dumpobj = true;
18054 : }
18055 :
18056 : /* check table excluded by an exclusion switch */
18057 40 : if (table_exclude_oids.head != NULL &&
18058 2 : simple_oid_list_member(&table_exclude_oids,
18059 : configtbloid))
18060 1 : dumpobj = false;
18061 :
18062 ECB : /* check schema excluded by an exclusion switch */
18063 CBC 38 : if (simple_oid_list_member(&schema_exclude_oids,
18064 GIC 38 : configtbl->dobj.namespace->dobj.catId.oid))
18065 UIC 0 : dumpobj = false;
18066 :
18067 GIC 38 : if (dumpobj)
18068 : {
18069 CBC 37 : makeTableDataInfo(dopt, configtbl);
18070 37 : if (configtbl->dataObj != NULL)
18071 : {
18072 GIC 37 : if (strlen(extconditionarray[j]) > 0)
18073 UIC 0 : configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
18074 : }
18075 : }
18076 ECB : }
18077 : }
18078 CBC 136 : if (extconfigarray)
18079 19 : free(extconfigarray);
18080 136 : if (extconditionarray)
18081 19 : free(extconditionarray);
18082 : }
18083 ECB :
18084 : /*
18085 : * Now that all the TableDataInfo objects have been created for all the
18086 : * extensions, check their FK dependencies and register them to try and
18087 : * dump the data out in an order that they can be restored in.
18088 : *
18089 : * Note that this is not a problem for user tables as their FKs are
18090 : * recreated after the data has been loaded.
18091 : */
18092 :
18093 CBC 118 : query = createPQExpBuffer();
18094 ECB :
18095 CBC 118 : printfPQExpBuffer(query,
18096 : "SELECT conrelid, confrelid "
18097 EUB : "FROM pg_constraint "
18098 : "JOIN pg_depend ON (objid = confrelid) "
18099 : "WHERE contype = 'f' "
18100 : "AND refclassid = 'pg_extension'::regclass "
18101 ECB : "AND classid = 'pg_class'::regclass;");
18102 :
18103 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18104 118 : ntups = PQntuples(res);
18105 EUB :
18106 GIC 118 : i_conrelid = PQfnumber(res, "conrelid");
18107 CBC 118 : i_confrelid = PQfnumber(res, "confrelid");
18108 :
18109 : /* Now get the dependencies and register them */
18110 GIC 118 : for (i = 0; i < ntups; i++)
18111 : {
18112 ECB : Oid conrelid,
18113 : confrelid;
18114 : TableInfo *reftable,
18115 : *contable;
18116 :
18117 UIC 0 : conrelid = atooid(PQgetvalue(res, i, i_conrelid));
18118 LBC 0 : confrelid = atooid(PQgetvalue(res, i, i_confrelid));
18119 UBC 0 : contable = findTableByOid(conrelid);
18120 UIC 0 : reftable = findTableByOid(confrelid);
18121 :
18122 LBC 0 : if (reftable == NULL ||
18123 UIC 0 : reftable->dataObj == NULL ||
18124 LBC 0 : contable == NULL ||
18125 UIC 0 : contable->dataObj == NULL)
18126 0 : continue;
18127 :
18128 : /*
18129 : * Make referencing TABLE_DATA object depend on the referenced table's
18130 : * TABLE_DATA object.
18131 ECB : */
18132 UIC 0 : addObjectDependency(&contable->dataObj->dobj,
18133 UBC 0 : reftable->dataObj->dobj.dumpId);
18134 EUB : }
18135 GIC 118 : PQclear(res);
18136 GBC 118 : destroyPQExpBuffer(query);
18137 EUB : }
18138 :
18139 : /*
18140 : * getDependencies --- obtain available dependency data
18141 : */
18142 : static void
18143 GBC 118 : getDependencies(Archive *fout)
18144 EUB : {
18145 : PQExpBuffer query;
18146 : PGresult *res;
18147 : int ntups,
18148 : i;
18149 : int i_classid,
18150 : i_objid,
18151 ECB : i_refclassid,
18152 : i_refobjid,
18153 : i_deptype;
18154 : DumpableObject *dobj,
18155 : *refdobj;
18156 :
18157 GIC 118 : pg_log_info("reading dependency data");
18158 :
18159 118 : query = createPQExpBuffer();
18160 ECB :
18161 : /*
18162 : * Messy query to collect the dependency data we need. Note that we
18163 : * ignore the sub-object column, so that dependencies of or on a column
18164 : * look the same as dependencies of or on a whole table.
18165 : *
18166 : * PIN dependencies aren't interesting, and EXTENSION dependencies were
18167 : * already processed by getExtensionMembership.
18168 : */
18169 CBC 118 : appendPQExpBufferStr(query, "SELECT "
18170 ECB : "classid, objid, refclassid, refobjid, deptype "
18171 : "FROM pg_depend "
18172 : "WHERE deptype != 'p' AND deptype != 'e'\n");
18173 :
18174 : /*
18175 : * Since we don't treat pg_amop entries as separate DumpableObjects, we
18176 : * have to translate their dependencies into dependencies of their parent
18177 : * opfamily. Ignore internal dependencies though, as those will point to
18178 : * their parent opclass, which we needn't consider here (and if we did,
18179 : * it'd just result in circular dependencies). Also, "loose" opfamily
18180 : * entries will have dependencies on their parent opfamily, which we
18181 : * should drop since they'd likewise become useless self-dependencies.
18182 : * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
18183 : */
18184 GIC 118 : appendPQExpBufferStr(query, "UNION ALL\n"
18185 : "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
18186 : "FROM pg_depend d, pg_amop o "
18187 : "WHERE deptype NOT IN ('p', 'e', 'i') AND "
18188 : "classid = 'pg_amop'::regclass AND objid = o.oid "
18189 : "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
18190 ECB :
18191 EUB : /* Likewise for pg_amproc entries */
18192 GBC 118 : appendPQExpBufferStr(query, "UNION ALL\n"
18193 : "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
18194 EUB : "FROM pg_depend d, pg_amproc p "
18195 : "WHERE deptype NOT IN ('p', 'e', 'i') AND "
18196 ECB : "classid = 'pg_amproc'::regclass AND objid = p.oid "
18197 : "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
18198 :
18199 : /* Sort the output for efficiency below */
18200 CBC 118 : appendPQExpBufferStr(query, "ORDER BY 1,2");
18201 ECB :
18202 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18203 :
18204 118 : ntups = PQntuples(res);
18205 :
18206 118 : i_classid = PQfnumber(res, "classid");
18207 118 : i_objid = PQfnumber(res, "objid");
18208 118 : i_refclassid = PQfnumber(res, "refclassid");
18209 118 : i_refobjid = PQfnumber(res, "refobjid");
18210 118 : i_deptype = PQfnumber(res, "deptype");
18211 :
18212 : /*
18213 : * Since we ordered the SELECT by referencing ID, we can expect that
18214 : * multiple entries for the same object will appear together; this saves
18215 ECB : * on searches.
18216 : */
18217 GIC 118 : dobj = NULL;
18218 :
18219 253999 : for (i = 0; i < ntups; i++)
18220 : {
18221 : CatalogId objId;
18222 : CatalogId refobjId;
18223 : char deptype;
18224 :
18225 253881 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
18226 253881 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
18227 253881 : refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
18228 CBC 253881 : refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
18229 GBC 253881 : deptype = *(PQgetvalue(res, i, i_deptype));
18230 :
18231 CBC 253881 : if (dobj == NULL ||
18232 GIC 239304 : dobj->catId.tableoid != objId.tableoid ||
18233 237783 : dobj->catId.oid != objId.oid)
18234 CBC 109875 : dobj = findObjectByCatalogId(objId);
18235 :
18236 : /*
18237 : * Failure to find objects mentioned in pg_depend is not unexpected,
18238 : * since for example we don't collect info about TOAST tables.
18239 : */
18240 GIC 253881 : if (dobj == NULL)
18241 ECB : {
18242 : #ifdef NOT_USED
18243 : pg_log_warning("no referencing object %u %u",
18244 : objId.tableoid, objId.oid);
18245 : #endif
18246 CBC 15043 : continue;
18247 ECB : }
18248 :
18249 GIC 239415 : refdobj = findObjectByCatalogId(refobjId);
18250 :
18251 239415 : if (refdobj == NULL)
18252 : {
18253 : #ifdef NOT_USED
18254 ECB : pg_log_warning("no referenced object %u %u",
18255 : refobjId.tableoid, refobjId.oid);
18256 : #endif
18257 GIC 577 : continue;
18258 : }
18259 :
18260 : /*
18261 ECB : * For 'x' dependencies, mark the object for later; we still add the
18262 : * normal dependency, for possible ordering purposes. Currently
18263 : * pg_dump_sort.c knows to put extensions ahead of all object types
18264 : * that could possibly depend on them, but this is safer.
18265 : */
18266 CBC 238838 : if (deptype == 'x')
18267 40 : dobj->depends_on_ext = true;
18268 :
18269 ECB : /*
18270 : * Ordinarily, table rowtypes have implicit dependencies on their
18271 : * tables. However, for a composite type the implicit dependency goes
18272 EUB : * the other way in pg_depend; which is the right thing for DROP but
18273 : * it doesn't produce the dependency ordering we need. So in that one
18274 : * case, we reverse the direction of the dependency.
18275 : */
18276 CBC 238838 : if (deptype == 'i' &&
18277 GIC 65124 : dobj->objType == DO_TABLE &&
18278 786 : refdobj->objType == DO_TYPE)
18279 CBC 137 : addObjectDependency(refdobj, dobj->dumpId);
18280 : else
18281 ECB : /* normal case */
18282 GIC 238701 : addObjectDependency(dobj, refdobj->dumpId);
18283 : }
18284 :
18285 118 : PQclear(res);
18286 :
18287 118 : destroyPQExpBuffer(query);
18288 118 : }
18289 :
18290 :
18291 : /*
18292 : * createBoundaryObjects - create dummy DumpableObjects to represent
18293 : * dump section boundaries.
18294 : */
18295 : static DumpableObject *
18296 118 : createBoundaryObjects(void)
18297 : {
18298 : DumpableObject *dobjs;
18299 :
18300 118 : dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
18301 :
18302 118 : dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
18303 118 : dobjs[0].catId = nilCatalogId;
18304 118 : AssignDumpId(dobjs + 0);
18305 118 : dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
18306 :
18307 118 : dobjs[1].objType = DO_POST_DATA_BOUNDARY;
18308 CBC 118 : dobjs[1].catId = nilCatalogId;
18309 GIC 118 : AssignDumpId(dobjs + 1);
18310 118 : dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
18311 ECB :
18312 GIC 118 : return dobjs;
18313 : }
18314 :
18315 : /*
18316 : * addBoundaryDependencies - add dependencies as needed to enforce the dump
18317 : * section boundaries.
18318 : */
18319 : static void
18320 CBC 118 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
18321 EUB : DumpableObject *boundaryObjs)
18322 : {
18323 GIC 118 : DumpableObject *preDataBound = boundaryObjs + 0;
18324 118 : DumpableObject *postDataBound = boundaryObjs + 1;
18325 : int i;
18326 :
18327 510138 : for (i = 0; i < numObjs; i++)
18328 : {
18329 510020 : DumpableObject *dobj = dobjs[i];
18330 :
18331 : /*
18332 : * The classification of object types here must match the SECTION_xxx
18333 : * values assigned during subsequent ArchiveEntry calls!
18334 ECB : */
18335 GIC 510020 : switch (dobj->objType)
18336 ECB : {
18337 CBC 482225 : case DO_NAMESPACE:
18338 ECB : case DO_EXTENSION:
18339 : case DO_TYPE:
18340 : case DO_SHELL_TYPE:
18341 : case DO_FUNC:
18342 : case DO_AGG:
18343 : case DO_OPERATOR:
18344 : case DO_ACCESS_METHOD:
18345 : case DO_OPCLASS:
18346 : case DO_OPFAMILY:
18347 : case DO_COLLATION:
18348 : case DO_CONVERSION:
18349 : case DO_TABLE:
18350 : case DO_TABLE_ATTACH:
18351 : case DO_ATTRDEF:
18352 : case DO_PROCLANG:
18353 : case DO_CAST:
18354 : case DO_DUMMY_TYPE:
18355 : case DO_TSPARSER:
18356 : case DO_TSDICT:
18357 : case DO_TSTEMPLATE:
18358 EUB : case DO_TSCONFIG:
18359 ECB : case DO_FDW:
18360 EUB : case DO_FOREIGN_SERVER:
18361 ECB : case DO_TRANSFORM:
18362 : case DO_LARGE_OBJECT:
18363 : /* Pre-data objects: must come before the pre-data boundary */
18364 CBC 482225 : addObjectDependency(preDataBound, dobj->dumpId);
18365 GIC 482225 : break;
18366 3475 : case DO_TABLE_DATA:
18367 ECB : case DO_SEQUENCE_SET:
18368 : case DO_LARGE_OBJECT_DATA:
18369 : /* Data objects: must come between the boundaries */
18370 GIC 3475 : addObjectDependency(dobj, preDataBound->dumpId);
18371 CBC 3475 : addObjectDependency(postDataBound, dobj->dumpId);
18372 3475 : break;
18373 GBC 4629 : case DO_INDEX:
18374 : case DO_INDEX_ATTACH:
18375 : case DO_STATSEXT:
18376 : case DO_REFRESH_MATVIEW:
18377 : case DO_TRIGGER:
18378 : case DO_EVENT_TRIGGER:
18379 ECB : case DO_DEFAULT_ACL:
18380 : case DO_POLICY:
18381 : case DO_PUBLICATION:
18382 : case DO_PUBLICATION_REL:
18383 EUB : case DO_PUBLICATION_TABLE_IN_SCHEMA:
18384 : case DO_SUBSCRIPTION:
18385 : /* Post-data objects: must come after the post-data boundary */
18386 GIC 4629 : addObjectDependency(dobj, postDataBound->dumpId);
18387 4629 : break;
18388 CBC 17749 : case DO_RULE:
18389 : /* Rules are post-data, but only if dumped separately */
18390 17749 : if (((RuleInfo *) dobj)->separate)
18391 GIC 431 : addObjectDependency(dobj, postDataBound->dumpId);
18392 17749 : break;
18393 1706 : case DO_CONSTRAINT:
18394 ECB : case DO_FK_CONSTRAINT:
18395 : /* Constraints are post-data, but only if dumped separately */
18396 GIC 1706 : if (((ConstraintInfo *) dobj)->separate)
18397 CBC 1080 : addObjectDependency(dobj, postDataBound->dumpId);
18398 GIC 1706 : break;
18399 118 : case DO_PRE_DATA_BOUNDARY:
18400 ECB : /* nothing to do */
18401 CBC 118 : break;
18402 GBC 118 : case DO_POST_DATA_BOUNDARY:
18403 : /* must come after the pre-data boundary */
18404 CBC 118 : addObjectDependency(dobj, preDataBound->dumpId);
18405 GIC 118 : break;
18406 ECB : }
18407 : }
18408 GIC 118 : }
18409 ECB :
18410 EUB :
18411 : /*
18412 : * BuildArchiveDependencies - create dependency data for archive TOC entries
18413 : *
18414 : * The raw dependency data obtained by getDependencies() is not terribly
18415 ECB : * useful in an archive dump, because in many cases there are dependency
18416 : * chains linking through objects that don't appear explicitly in the dump.
18417 : * For example, a view will depend on its _RETURN rule while the _RETURN rule
18418 : * will depend on other objects --- but the rule will not appear as a separate
18419 : * object in the dump. We need to adjust the view's dependencies to include
18420 : * whatever the rule depends on that is included in the dump.
18421 : *
18422 : * Just to make things more complicated, there are also "special" dependencies
18423 : * such as the dependency of a TABLE DATA item on its TABLE, which we must
18424 : * not rearrange because pg_restore knows that TABLE DATA only depends on
18425 : * its table. In these cases we must leave the dependencies strictly as-is
18426 : * even if they refer to not-to-be-dumped objects.
18427 : *
18428 : * To handle this, the convention is that "special" dependencies are created
18429 : * during ArchiveEntry calls, and an archive TOC item that has any such
18430 : * entries will not be touched here. Otherwise, we recursively search the
18431 : * DumpableObject data structures to build the correct dependencies for each
18432 : * archive TOC item.
18433 : */
18434 : static void
18435 GIC 25 : BuildArchiveDependencies(Archive *fout)
18436 : {
18437 25 : ArchiveHandle *AH = (ArchiveHandle *) fout;
18438 : TocEntry *te;
18439 :
18440 ECB : /* Scan all TOC entries in the archive */
18441 CBC 4956 : for (te = AH->toc->next; te != AH->toc; te = te->next)
18442 : {
18443 ECB : DumpableObject *dobj;
18444 : DumpId *dependencies;
18445 : int nDeps;
18446 : int allocDeps;
18447 :
18448 : /* No need to process entries that will not be dumped */
18449 GIC 4931 : if (te->reqs == 0)
18450 1576 : continue;
18451 : /* Ignore entries that already have "special" dependencies */
18452 4929 : if (te->nDeps > 0)
18453 1305 : continue;
18454 EUB : /* Otherwise, look up the item's original DumpableObject, if any */
18455 GBC 3624 : dobj = findObjectByDumpId(te->dumpId);
18456 3624 : if (dobj == NULL)
18457 125 : continue;
18458 : /* No work if it has no dependencies */
18459 3499 : if (dobj->nDeps <= 0)
18460 144 : continue;
18461 EUB : /* Set up work array */
18462 GBC 3355 : allocDeps = 64;
18463 3355 : dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18464 GIC 3355 : nDeps = 0;
18465 : /* Recursively find all dumpable dependencies */
18466 3355 : findDumpableDependencies(AH, dobj,
18467 : &dependencies, &nDeps, &allocDeps);
18468 : /* And save 'em ... */
18469 GBC 3355 : if (nDeps > 0)
18470 EUB : {
18471 GIC 2586 : dependencies = (DumpId *) pg_realloc(dependencies,
18472 ECB : nDeps * sizeof(DumpId));
18473 CBC 2586 : te->dependencies = dependencies;
18474 GIC 2586 : te->nDeps = nDeps;
18475 : }
18476 : else
18477 769 : free(dependencies);
18478 : }
18479 25 : }
18480 ECB :
18481 : /* Recursive search subroutine for BuildArchiveDependencies */
18482 : static void
18483 GIC 8271 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
18484 : DumpId **dependencies, int *nDeps, int *allocDeps)
18485 : {
18486 : int i;
18487 :
18488 : /*
18489 : * Ignore section boundary objects: if we search through them, we'll
18490 : * report lots of bogus dependencies.
18491 : */
18492 8271 : if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18493 8261 : dobj->objType == DO_POST_DATA_BOUNDARY)
18494 CBC 1525 : return;
18495 :
18496 17284 : for (i = 0; i < dobj->nDeps; i++)
18497 : {
18498 GIC 10538 : DumpId depid = dobj->dependencies[i];
18499 :
18500 10538 : if (TocIDRequired(AH, depid) != 0)
18501 : {
18502 : /* Object will be dumped, so just reference it as a dependency */
18503 5622 : if (*nDeps >= *allocDeps)
18504 : {
18505 UIC 0 : *allocDeps *= 2;
18506 LBC 0 : *dependencies = (DumpId *) pg_realloc(*dependencies,
18507 UIC 0 : *allocDeps * sizeof(DumpId));
18508 : }
18509 GIC 5622 : (*dependencies)[*nDeps] = depid;
18510 5622 : (*nDeps)++;
18511 : }
18512 : else
18513 : {
18514 : /*
18515 : * Object will not be dumped, so recursively consider its deps. We
18516 : * rely on the assumption that sortDumpableObjects already broke
18517 : * any dependency loops, else we might recurse infinitely.
18518 : */
18519 4916 : DumpableObject *otherdobj = findObjectByDumpId(depid);
18520 :
18521 CBC 4916 : if (otherdobj)
18522 GIC 4916 : findDumpableDependencies(AH, otherdobj,
18523 : dependencies, nDeps, allocDeps);
18524 : }
18525 : }
18526 : }
18527 :
18528 :
18529 ECB : /*
18530 : * getFormattedTypeName - retrieve a nicely-formatted type name for the
18531 : * given type OID.
18532 : *
18533 : * This does not guarantee to schema-qualify the output, so it should not
18534 : * be used to create the target object name for CREATE or ALTER commands.
18535 : *
18536 : * Note that the result is cached and must not be freed by the caller.
18537 : */
18538 : static const char *
18539 CBC 2294 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18540 : {
18541 ECB : TypeInfo *typeInfo;
18542 : char *result;
18543 : PQExpBuffer query;
18544 : PGresult *res;
18545 :
18546 CBC 2294 : if (oid == 0)
18547 ECB : {
18548 UIC 0 : if ((opts & zeroAsStar) != 0)
18549 0 : return "*";
18550 0 : else if ((opts & zeroAsNone) != 0)
18551 0 : return "NONE";
18552 : }
18553 :
18554 ECB : /* see if we have the result cached in the type's TypeInfo record */
18555 GIC 2294 : typeInfo = findTypeByOid(oid);
18556 CBC 2294 : if (typeInfo && typeInfo->ftypname)
18557 GIC 1818 : return typeInfo->ftypname;
18558 :
18559 476 : query = createPQExpBuffer();
18560 476 : appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18561 : oid);
18562 ECB :
18563 CBC 476 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
18564 ECB :
18565 : /* result of format_type is already quoted */
18566 CBC 476 : result = pg_strdup(PQgetvalue(res, 0, 0));
18567 :
18568 476 : PQclear(res);
18569 476 : destroyPQExpBuffer(query);
18570 ECB :
18571 : /*
18572 : * Cache the result for re-use in later requests, if possible. If we
18573 : * don't have a TypeInfo for the type, the string will be leaked once the
18574 : * caller is done with it ... but that case really should not happen, so
18575 : * leaking if it does seems acceptable.
18576 : */
18577 CBC 476 : if (typeInfo)
18578 GIC 476 : typeInfo->ftypname = result;
18579 :
18580 476 : return result;
18581 : }
18582 :
18583 ECB : /*
18584 : * Return a column list clause for the given relation.
18585 : *
18586 : * Special case: if there are no undropped columns in the relation, return
18587 : * "", not an invalid "()" column list.
18588 : */
18589 : static const char *
18590 GIC 6020 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18591 : {
18592 6020 : int numatts = ti->numatts;
18593 6020 : char **attnames = ti->attnames;
18594 CBC 6020 : bool *attisdropped = ti->attisdropped;
18595 GIC 6020 : char *attgenerated = ti->attgenerated;
18596 : bool needComma;
18597 : int i;
18598 :
18599 6020 : appendPQExpBufferChar(buffer, '(');
18600 6020 : needComma = false;
18601 30584 : for (i = 0; i < numatts; i++)
18602 : {
18603 CBC 24564 : if (attisdropped[i])
18604 564 : continue;
18605 GIC 24000 : if (attgenerated[i])
18606 620 : continue;
18607 23380 : if (needComma)
18608 17594 : appendPQExpBufferStr(buffer, ", ");
18609 23380 : appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18610 23380 : needComma = true;
18611 : }
18612 :
18613 CBC 6020 : if (!needComma)
18614 234 : return ""; /* no undropped columns */
18615 ECB :
18616 CBC 5786 : appendPQExpBufferChar(buffer, ')');
18617 GIC 5786 : return buffer->data;
18618 : }
18619 ECB :
18620 : /*
18621 : * Check if a reloptions array is nonempty.
18622 : */
18623 : static bool
18624 CBC 10120 : nonemptyReloptions(const char *reloptions)
18625 ECB : {
18626 : /* Don't want to print it if it's just "{}" */
18627 GIC 10120 : return (reloptions != NULL && strlen(reloptions) > 2);
18628 : }
18629 :
18630 : /*
18631 : * Format a reloptions array and append it to the given buffer.
18632 : *
18633 ECB : * "prefix" is prepended to the option names; typically it's "" or "toast.".
18634 : */
18635 : static void
18636 GIC 207 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18637 ECB : const char *prefix, Archive *fout)
18638 : {
18639 : bool res;
18640 :
18641 CBC 207 : res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18642 207 : fout->std_strings);
18643 GIC 207 : if (!res)
18644 LBC 0 : pg_log_warning("could not parse %s array", "reloptions");
18645 CBC 207 : }
|