Age Owner 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
7639 tgl 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;
3940 tgl 342 ECB : DumpableObject *boundaryObjs;
343 : int i;
344 : int optindex;
3099 alvherre 345 : RestoreOptions *ropt;
346 : Archive *fout; /* the script file */
1469 peter 347 GIC 181 : bool g_verbose = false;
3099 alvherre 348 181 : const char *dumpencoding = NULL;
3065 simon 349 181 : const char *dumpsnapshot = NULL;
3099 alvherre 350 181 : char *use_role = NULL;
3668 andrew 351 181 : int numWorkers = 1;
7639 tgl 352 181 : int plainText = 0;
4459 heikki.linnakangas 353 181 : ArchiveFormat archiveFormat = archUnknown;
354 : ArchiveMode archiveMode;
128 michael 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;
5474 tgl 360 ECB :
3010 361 : static DumpOptions dopt;
8314 bruce 362 :
3010 tgl 363 : static struct option long_options[] = {
7639 364 : {"data-only", no_argument, NULL, 'a'},
365 : {"blobs", no_argument, NULL, 'b'},
366 : {"large-objects", no_argument, NULL, 'b'},
2322 sfrost 367 : {"no-blobs", no_argument, NULL, 'B'},
368 : {"no-large-objects", no_argument, NULL, 'B'},
369 : {"clean", no_argument, NULL, 'c'},
7639 tgl 370 : {"create", no_argument, NULL, 'C'},
3695 heikki.linnakangas 371 : {"dbname", required_argument, NULL, 'd'},
739 michael 372 : {"extension", required_argument, NULL, 'e'},
7639 tgl 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 :
1469 peter 438 GIC 181 : pg_logging_init(argv[0]);
439 181 : pg_logging_set_level(PG_LOG_WARNING);
5232 peter_e 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 : */
3668 andrew 446 181 : init_parallel_dump_utils();
447 :
7310 bruce 448 181 : progname = get_progname(argv[0]);
449 :
7639 tgl 450 181 : if (argc > 1)
451 : {
452 181 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
453 : {
454 1 : help(progname);
4070 rhaas 455 1 : exit_nicely(0);
9345 bruce 456 ECB : }
7639 tgl 457 CBC 180 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
9345 bruce 458 ECB : {
7639 tgl 459 GIC 30 : puts("pg_dump (PostgreSQL) " PG_VERSION);
4070 rhaas 460 30 : exit_nicely(0);
461 : }
462 : }
463 :
3010 tgl 464 CBC 150 : InitDumpOptions(&dopt);
465 :
739 michael 466 627 : while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
7398 peter_e 467 GIC 627 : long_options, &optindex)) != -1)
7639 tgl 468 ECB : {
7639 tgl 469 GIC 481 : switch (c)
7639 tgl 470 ECB : {
7639 tgl 471 GIC 8 : case 'a': /* Dump data only */
3010 tgl 472 CBC 8 : dopt.dataOnly = true;
7639 473 8 : break;
474 :
125 peter 475 GNC 1 : case 'b': /* Dump LOs */
476 1 : dopt.outputLOs = true;
7639 tgl 477 CBC 1 : break;
9345 bruce 478 ECB :
125 peter 479 GNC 2 : case 'B': /* Don't dump LOs */
480 2 : dopt.dontOutputLOs = true;
2322 sfrost 481 GIC 2 : break;
2322 sfrost 482 ECB :
6385 bruce 483 GIC 6 : case 'c': /* clean (i.e., drop) schema prior to create */
3010 tgl 484 CBC 6 : dopt.outputClean = 1;
7639 485 6 : break;
486 :
487 25 : case 'C': /* Create DB */
3010 tgl 488 GIC 25 : dopt.outputCreateDB = 1;
7639 tgl 489 CBC 25 : break;
7895 tgl 490 ECB :
3695 heikki.linnakangas 491 CBC 4 : case 'd': /* database name */
927 tgl 492 GIC 4 : dopt.cparams.dbname = pg_strdup(optarg);
3695 heikki.linnakangas 493 CBC 4 : break;
3695 heikki.linnakangas 494 ECB :
739 michael 495 CBC 4 : case 'e': /* include extension(s) */
739 michael 496 GIC 4 : simple_string_list_append(&extension_include_patterns, optarg);
739 michael 497 CBC 4 : dopt.include_everything = false;
498 4 : break;
739 michael 499 ECB :
6482 bruce 500 GIC 2 : case 'E': /* Dump encoding */
3831 bruce 501 CBC 2 : dumpencoding = pg_strdup(optarg);
6482 502 2 : break;
6482 bruce 503 ECB :
7639 tgl 504 GIC 110 : case 'f':
3831 bruce 505 CBC 110 : filename = pg_strdup(optarg);
7639 tgl 506 110 : break;
7895 tgl 507 ECB :
7639 tgl 508 GIC 71 : case 'F':
3831 bruce 509 CBC 71 : format = pg_strdup(optarg);
7639 tgl 510 71 : break;
7895 tgl 511 ECB :
7639 tgl 512 GIC 6 : case 'h': /* server host */
927 tgl 513 CBC 6 : dopt.cparams.pghost = pg_strdup(optarg);
7639 514 6 : break;
7895 tgl 515 ECB :
3668 andrew 516 CBC 12 : case 'j': /* number of dump jobs */
624 michael 517 GIC 12 : if (!option_parse_int(optarg, "-j/--jobs", 1,
624 michael 518 ECB : PG_MAX_JOBS,
519 : &numWorkers))
624 michael 520 CBC 1 : exit_nicely(1);
3668 andrew 521 GIC 11 : break;
3668 andrew 522 ECB :
6026 tgl 523 CBC 14 : case 'n': /* include schema(s) */
524 14 : simple_string_list_append(&schema_include_patterns, optarg);
3010 tgl 525 GIC 14 : dopt.include_everything = false;
6026 tgl 526 CBC 14 : break;
6095 bruce 527 ECB :
6026 tgl 528 CBC 1 : case 'N': /* exclude schema(s) */
6026 tgl 529 GIC 1 : simple_string_list_append(&schema_exclude_patterns, optarg);
7360 bruce 530 CBC 1 : break;
7360 bruce 531 ECB :
7639 tgl 532 CBC 2 : case 'O': /* Don't reconnect to match owner */
3010 tgl 533 GIC 2 : dopt.outputNoOwner = 1;
7639 tgl 534 CBC 2 : break;
9345 bruce 535 ECB :
7639 tgl 536 GIC 15 : case 'p': /* server port */
927 537 15 : dopt.cparams.pgport = pg_strdup(optarg);
7639 tgl 538 CBC 15 : break;
9173 bruce 539 ECB :
7138 tgl 540 GIC 2 : case 'R':
7138 tgl 541 ECB : /* no-op, still accepted for backwards compatibility */
7639 tgl 542 CBC 2 : break;
9345 bruce 543 ECB :
7639 tgl 544 CBC 12 : case 's': /* dump schema only */
3010 tgl 545 GIC 12 : dopt.schemaOnly = true;
7639 tgl 546 CBC 12 : break;
9345 bruce 547 ECB :
6385 bruce 548 CBC 1 : case 'S': /* Username for superuser in plain text output */
3010 tgl 549 GIC 1 : dopt.outputSuperuser = pg_strdup(optarg);
7639 tgl 550 CBC 1 : break;
8314 bruce 551 ECB :
6026 tgl 552 CBC 8 : case 't': /* include table(s) */
6026 tgl 553 GIC 8 : simple_string_list_append(&table_include_patterns, optarg);
3010 tgl 554 CBC 8 : dopt.include_everything = false;
6026 555 8 : break;
6026 tgl 556 ECB :
6026 tgl 557 GIC 2 : case 'T': /* exclude table(s) */
6026 tgl 558 CBC 2 : simple_string_list_append(&table_exclude_patterns, optarg);
6026 tgl 559 GIC 2 : break;
6026 tgl 560 ECB :
7639 tgl 561 GIC 7 : case 'U':
927 tgl 562 CBC 7 : dopt.cparams.username = pg_strdup(optarg);
7639 563 7 : break;
7639 tgl 564 ECB :
7639 tgl 565 GIC 6 : case 'v': /* verbose */
7639 tgl 566 CBC 6 : g_verbose = true;
934 567 6 : pg_logging_increase_verbosity();
7639 568 6 : break;
569 :
5155 peter_e 570 1 : case 'w':
927 tgl 571 1 : dopt.cparams.promptPassword = TRI_NO;
5155 peter_e 572 1 : break;
5155 peter_e 573 ECB :
7639 tgl 574 UIC 0 : case 'W':
927 tgl 575 LBC 0 : dopt.cparams.promptPassword = TRI_YES;
7639 576 0 : break;
7639 tgl 577 ECB :
7639 tgl 578 GIC 2 : case 'x': /* skip ACL dump */
3010 tgl 579 CBC 2 : dopt.aclsSkip = true;
7639 580 2 : break;
7639 tgl 581 ECB :
128 michael 582 GNC 15 : case 'Z': /* Compression */
583 15 : parse_compress_options(optarg, &compression_algorithm_str,
584 : &compression_detail);
585 15 : user_compression_defined = true;
7639 tgl 586 CBC 15 : break;
587 :
588 29 : case 0:
4405 rhaas 589 ECB : /* This covers the long options. */
7639 tgl 590 CBC 29 : break;
591 :
5207 tgl 592 GBC 2 : case 2: /* lock-wait-timeout */
3010 593 2 : dopt.lockWaitTimeout = pg_strdup(optarg);
5376 594 2 : break;
595 :
5207 tgl 596 CBC 3 : case 3: /* SET ROLE */
3831 bruce 597 3 : use_role = pg_strdup(optarg);
5207 tgl 598 3 : break;
599 :
3955 bruce 600 1 : case 4: /* exclude table(s) data */
4134 andrew 601 1 : simple_string_list_append(&tabledata_exclude_patterns, optarg);
4134 andrew 602 GIC 1 : break;
4134 andrew 603 ECB :
4132 andrew 604 CBC 6 : case 5: /* section */
3010 tgl 605 GIC 6 : set_dump_section(optarg, &dopt.dumpSections);
4132 andrew 606 CBC 6 : break;
607 :
3065 simon 608 LBC 0 : case 6: /* snapshot */
3065 simon 609 UIC 0 : dumpsnapshot = pg_strdup(optarg);
3065 simon 610 LBC 0 : break;
3065 simon 611 ECB :
2209 andrew 612 CBC 88 : case 7: /* no-sync */
2209 andrew 613 GIC 88 : dosync = false;
2209 andrew 614 CBC 88 : break;
2209 andrew 615 ECB :
1511 andrew 616 CBC 1 : case 8:
1511 andrew 617 GIC 1 : have_extra_float_digits = true;
624 michael 618 CBC 1 : if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
624 michael 619 ECB : &extra_float_digits))
1511 andrew 620 CBC 1 : exit_nicely(1);
1511 andrew 621 UIC 0 : break;
1511 andrew 622 ECB :
1494 alvherre 623 CBC 2 : case 9: /* inserts */
1494 alvherre 624 ECB :
625 : /*
1494 alvherre 626 EUB : * dump_inserts also stores --rows-per-insert, careful not to
627 : * overwrite that.
628 : */
1494 alvherre 629 GIC 2 : if (dopt.dump_inserts == 0)
1494 alvherre 630 CBC 2 : dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
631 2 : break;
1494 alvherre 632 ECB :
1494 alvherre 633 GIC 2 : case 10: /* rows per insert */
624 michael 634 CBC 2 : if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
624 michael 635 ECB : &dopt.dump_inserts))
1494 alvherre 636 CBC 1 : exit_nicely(1);
1494 alvherre 637 GIC 1 : break;
1494 alvherre 638 ECB :
1110 alvherre 639 GBC 4 : case 11: /* include foreign data */
1110 alvherre 640 GIC 4 : simple_string_list_append(&foreign_servers_include_patterns,
1110 alvherre 641 ECB : optarg);
1110 alvherre 642 GIC 4 : break;
643 :
26 tgl 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 :
7639 tgl 660 GIC 1 : default:
661 : /* getopt_long already emitted a complaint */
366 662 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4070 rhaas 663 CBC 1 : exit_nicely(1);
9503 vadim4o 664 ECB : }
9345 bruce 665 : }
666 :
3695 heikki.linnakangas 667 : /*
668 : * Non-option argument specifies database name as long as it wasn't
669 : * already specified with -d / --dbname
670 : */
927 tgl 671 CBC 146 : if (optind < argc && dopt.cparams.dbname == NULL)
927 tgl 672 GIC 116 : dopt.cparams.dbname = argv[optind++];
4622 tgl 673 ECB :
674 : /* Complain if any arguments remain */
4622 tgl 675 GIC 146 : if (optind < argc)
7639 tgl 676 ECB : {
1469 peter 677 GIC 1 : pg_log_error("too many command-line arguments (first is \"%s\")",
1469 peter 678 ECB : argv[optind]);
366 tgl 679 CBC 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4070 rhaas 680 GIC 1 : exit_nicely(1);
7639 tgl 681 ECB : }
7910 peter_e 682 :
683 : /* --column-inserts implies --inserts */
1494 alvherre 684 CBC 145 : if (dopt.column_inserts && dopt.dump_inserts == 0)
685 1 : dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
686 :
2334 tgl 687 ECB : /*
688 : * Binary upgrade mode implies dumping sequence data even in schema-only
2420 peter_e 689 : * mode. This is not exposed as a separate option, but kept separate
2334 tgl 690 : * internally for clarity.
691 : */
2420 peter_e 692 CBC 145 : if (dopt.binary_upgrade)
2420 peter_e 693 GIC 8 : dopt.sequence_data = 1;
2420 peter_e 694 ECB :
3010 tgl 695 GIC 145 : if (dopt.dataOnly && dopt.schemaOnly)
366 tgl 696 CBC 1 : pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
7910 peter_e 697 ECB :
1110 alvherre 698 GIC 144 : if (dopt.schemaOnly && foreign_servers_include_patterns.head != NULL)
366 tgl 699 1 : pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
700 :
1110 alvherre 701 143 : if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
366 tgl 702 1 : pg_fatal("option --include-foreign-data is not supported with parallel backup");
703 :
3010 704 142 : if (dopt.dataOnly && dopt.outputClean)
366 tgl 705 CBC 1 : pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
7530 bruce 706 ECB :
3010 tgl 707 GIC 141 : if (dopt.if_exists && !dopt.outputClean)
366 708 1 : pg_fatal("option --if-exists requires option -c/--clean");
3324 alvherre 709 ECB :
710 : /*
1494 711 : * --inserts are already implied above if --column-inserts or
712 : * --rows-per-insert were specified.
713 : */
1494 alvherre 714 CBC 140 : if (dopt.do_nothing && dopt.dump_inserts == 0)
366 tgl 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 */
4459 heikki.linnakangas 718 CBC 139 : archiveFormat = parseArchiveFormat(format, &archiveMode);
4459 heikki.linnakangas 719 ECB :
720 : /* archiveFormat specific setup */
4459 heikki.linnakangas 721 GIC 138 : if (archiveFormat == archNull)
5862 bruce 722 112 : plainText = 1;
723 :
724 : /*
725 : * Compression options
726 : */
128 michael 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 :
4 tomas.vondra 739 134 : error_detail = supports_compression(compression_spec);
740 134 : if (error_detail != NULL)
4 tomas.vondra 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 : */
4 tomas.vondra 748 GNC 134 : if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
4 tomas.vondra 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 : */
128 michael 756 GNC 134 : if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
757 23 : !user_compression_defined)
128 michael 758 ECB : {
759 : #ifdef HAVE_LIBZ
128 michael 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
128 michael 765 ECB : }
766 :
1900 tgl 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 : */
1900 tgl 771 GIC 134 : if (!plainText)
772 26 : dopt.outputCreateDB = 1;
773 :
3668 andrew 774 ECB : /* Parallel backup only in the directory archive format so far */
3668 andrew 775 CBC 134 : if (archiveFormat != archDirectory && numWorkers > 1)
366 tgl 776 GIC 1 : pg_fatal("parallel backup only supported by the directory format");
777 :
4214 tgl 778 ECB : /* Open the output file */
128 michael 779 GNC 133 : fout = CreateArchive(filename, archiveFormat, compression_spec,
780 : dosync, archiveMode, setupDumpWorker);
4037 alvherre 781 ECB :
2643 tgl 782 : /* Make dump options accessible right away */
2643 tgl 783 GIC 132 : SetArchiveOptions(fout, &dopt, NULL);
784 :
785 : /* Register the cleanup hook */
4037 alvherre 786 132 : on_exit_close_archive(fout);
4459 heikki.linnakangas 787 ECB :
788 : /* Let the archiver know how noisy to be */
4080 rhaas 789 CBC 132 : fout->verbose = g_verbose;
790 :
791 :
5474 tgl 792 ECB : /*
793 : * We allow the server to be back to 9.2, and up to any minor release of
5050 bruce 794 : * our own major version. (See also version check in pg_dumpall.c.)
5474 tgl 795 : */
481 tgl 796 CBC 132 : fout->minRemoteVersion = 90200;
3666 heikki.linnakangas 797 GIC 132 : fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
798 :
3668 andrew 799 CBC 132 : fout->numWorkers = numWorkers;
3668 andrew 800 ECB :
7639 tgl 801 EUB : /*
802 : * Open the database using the Archiver, so it knows about it. Errors mean
803 : * death.
804 : */
927 tgl 805 GIC 132 : ConnectDatabase(fout, &dopt.cparams, false);
2643 806 131 : setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
807 :
3726 magnus 808 ECB : /*
2064 tgl 809 EUB : * On hot standbys, never try to dump unlogged table data, since it will
810 : * just throw an error.
811 : */
2509 magnus 812 GIC 131 : if (fout->isStandby)
813 3 : dopt.no_unlogged_table_data = true;
814 :
815 : /*
2300 sfrost 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 : */
481 tgl 820 CBC 131 : g_last_builtin_oid = FirstNormalObjectId - 1;
821 :
1469 peter 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 */
6026 tgl 825 131 : if (schema_include_patterns.head != NULL)
826 : {
4080 rhaas 827 14 : expand_schema_name_patterns(fout, &schema_include_patterns,
828 : &schema_include_oids,
829 : strict_names);
6026 tgl 830 8 : if (schema_include_oids.head == NULL)
366 tgl 831 CBC 1 : pg_fatal("no matching schemas were found");
6095 bruce 832 ECB : }
4080 rhaas 833 GIC 124 : expand_schema_name_patterns(fout, &schema_exclude_patterns,
834 : &schema_exclude_oids,
2764 teodor 835 ECB : false);
6026 tgl 836 : /* non-matching exclusion patterns aren't an error */
837 :
838 : /* Expand table selection patterns into OID lists */
26 tgl 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 :
4079 rhaas 850 GIC 119 : expand_table_name_patterns(fout, &table_exclude_patterns,
851 : &table_exclude_oids,
852 : false, false);
26 tgl 853 GNC 119 : expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
854 : &table_exclude_oids,
855 : false, true);
856 :
4079 rhaas 857 GIC 119 : expand_table_name_patterns(fout, &tabledata_exclude_patterns,
858 : &tabledata_exclude_oids,
859 : false, false);
26 tgl 860 GNC 119 : expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
861 : &tabledata_exclude_oids,
862 : false, true);
863 :
1110 alvherre 864 GIC 119 : expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
1110 alvherre 865 ECB : &foreign_servers_include_oids);
866 :
867 : /* non-matching exclusion patterns aren't an error */
6095 bruce 868 :
869 : /* Expand extension selection patterns into OID lists */
739 michael 870 GIC 119 : if (extension_include_patterns.head != NULL)
871 : {
872 4 : expand_extension_name_patterns(fout, &extension_include_patterns,
873 : &extension_include_oids,
739 michael 874 ECB : strict_names);
739 michael 875 CBC 4 : if (extension_include_oids.head == NULL)
366 tgl 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 : */
125 peter 888 GNC 119 : if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputLOs)
889 96 : dopt.outputLOs = true;
890 :
464 tgl 891 ECB : /*
892 : * Collect role names so we can map object owner OIDs to names.
893 : */
464 tgl 894 CBC 119 : collectRoleNames(fout);
895 :
7064 tgl 896 ECB : /*
897 : * Now scan the database and create DumpableObject structs for all the
898 : * objects we intend to dump.
899 : */
2643 tgl 900 CBC 119 : tblinfo = getSchemaData(fout, &numTables);
901 :
3010 902 118 : if (!dopt.schemaOnly)
903 : {
1601 andres 904 GIC 108 : getTableData(&dopt, tblinfo, numTables, 0);
3689 kgrittn 905 108 : buildMatViewRefreshDependencies(fout);
3010 tgl 906 108 : if (dopt.dataOnly)
5326 907 6 : getTableDataFKConstraints();
5326 tgl 908 ECB : }
909 :
2420 peter_e 910 GIC 118 : if (dopt.schemaOnly && dopt.sequence_data)
1601 andres 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
2225 sfrost 915 ECB : * data or the associated metadata that resides in the pg_largeobject and
1834 tgl 916 : * pg_largeobject_metadata tables, respectively.
2225 sfrost 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 : */
125 peter 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.
7064 tgl 926 ECB : */
4080 rhaas 927 GIC 118 : getDependencies(fout);
928 :
489 tgl 929 ECB : /*
930 : * Collect ACLs, comments, and security labels, if wanted.
931 : */
489 tgl 932 GIC 118 : if (!dopt.aclsSkip)
489 tgl 933 CBC 116 : getAdditionalACLs(fout);
489 tgl 934 GIC 118 : if (!dopt.no_comments)
935 118 : collectComments(fout);
936 118 : if (!dopt.no_security_labels)
937 118 : collectSecLabels(fout);
938 :
3940 tgl 939 ECB : /* Lastly, create dummy objects to represent the section boundaries */
3940 tgl 940 GIC 118 : boundaryObjs = createBoundaryObjects();
3940 tgl 941 ECB :
942 : /* Get pointers to all the known DumpableObjects */
3940 tgl 943 GIC 118 : getDumpableObjects(&dobjs, &numObjs);
3940 tgl 944 ECB :
3940 tgl 945 EUB : /*
946 : * Add dummy dependencies to enforce the dump section ordering.
947 : */
3940 tgl 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 : */
2370 tgl 957 CBC 118 : sortDumpableObjectsByTypeName(dobjs, numObjs);
6976 tgl 958 ECB :
3940 tgl 959 GIC 118 : sortDumpableObjects(dobjs, numObjs,
960 118 : boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
961 :
962 : /*
6385 bruce 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.
750 tgl 969 : */
4080 rhaas 970 GIC 118 : dumpEncoding(fout);
4080 rhaas 971 CBC 118 : dumpStdStrings(fout);
1868 tgl 972 GIC 118 : dumpSearchPath(fout);
6162 bruce 973 ECB :
1903 tgl 974 : /* The database items are always next, unless we don't want them at all */
1900 tgl 975 CBC 118 : if (dopt.outputCreateDB)
2643 976 50 : dumpDatabase(fout);
977 :
978 : /* Now the rearrangeable objects. */
7064 979 510138 : for (i = 0; i < numObjs; i++)
2643 980 510020 : dumpDumpableObject(fout, dobjs[i]);
981 :
982 : /*
983 : * Set up options info to ensure we dump what we want.
984 : */
3967 tgl 985 GIC 118 : ropt = NewRestoreOptions();
986 118 : ropt->filename = filename;
987 :
988 : /* if you change this list, see dumpOptionsFromRestoreOptions */
927 989 118 : ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
927 tgl 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;
927 tgl 992 GIC 118 : ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
993 118 : ropt->cparams.promptPassword = dopt.cparams.promptPassword;
3010 994 118 : ropt->dropSchema = dopt.outputClean;
995 118 : ropt->dataOnly = dopt.dataOnly;
3010 tgl 996 CBC 118 : ropt->schemaOnly = dopt.schemaOnly;
3010 tgl 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;
3010 tgl 1001 CBC 118 : ropt->superuser = dopt.outputSuperuser;
1002 118 : ropt->createDB = dopt.outputCreateDB;
1003 118 : ropt->noOwner = dopt.outputNoOwner;
447 michael 1004 118 : ropt->noTableAm = dopt.outputNoTableAm;
3010 tgl 1005 118 : ropt->noTablespace = dopt.outputNoTablespaces;
1006 118 : ropt->disable_triggers = dopt.disable_triggers;
3010 tgl 1007 GIC 118 : ropt->use_setsessauth = dopt.use_setsessauth;
1008 118 : ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
3010 tgl 1009 CBC 118 : ropt->dump_inserts = dopt.dump_inserts;
1900 tgl 1010 GIC 118 : ropt->no_comments = dopt.no_comments;
2158 peter_e 1011 118 : ropt->no_publications = dopt.no_publications;
3010 tgl 1012 CBC 118 : ropt->no_security_labels = dopt.no_security_labels;
2161 peter_e 1013 GIC 118 : ropt->no_subscriptions = dopt.no_subscriptions;
3010 tgl 1014 118 : ropt->lockWaitTimeout = dopt.lockWaitTimeout;
1015 118 : ropt->include_everything = dopt.include_everything;
1016 118 : ropt->enable_row_security = dopt.enable_row_security;
2420 peter_e 1017 CBC 118 : ropt->sequence_data = dopt.sequence_data;
2225 sfrost 1018 GIC 118 : ropt->binary_upgrade = dopt.binary_upgrade;
1019 :
128 michael 1020 GNC 118 : ropt->compression_spec = compression_spec;
1021 :
3955 bruce 1022 GIC 118 : ropt->suppressDumpWarnings = true; /* We've already shown them */
3967 tgl 1023 ECB :
2643 tgl 1024 GIC 118 : SetArchiveOptions(fout, &dopt, ropt);
2643 tgl 1025 ECB :
1026 : /* Mark which entries should be output */
2643 tgl 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 : */
3940 1034 118 : if (!plainText)
1035 25 : BuildArchiveDependencies(fout);
3940 tgl 1036 ECB :
3967 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 : */
3967 tgl 1044 GIC 118 : if (plainText)
3967 tgl 1045 CBC 93 : RestoreArchive(fout);
8216 pjw 1046 ECB :
2643 tgl 1047 GIC 117 : CloseArchive(fout);
1048 :
4070 rhaas 1049 117 : exit_nicely(0);
1050 : }
8216 pjw 1051 ECB :
1052 :
1053 : static void
7639 tgl 1054 GIC 1 : help(const char *progname)
7639 tgl 1055 ECB : {
7529 peter_e 1056 CBC 1 : printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
1057 1 : printf(_("Usage:\n"));
7478 1058 1 : printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
8216 pjw 1059 ECB :
7478 peter_e 1060 CBC 1 : printf(_("\nGeneral options:\n"));
3978 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"
3978 peter_e 1063 ECB : " plain text (default))\n"));
3668 andrew 1064 CBC 1 : printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
3978 peter_e 1065 1 : printf(_(" -v, --verbose verbose mode\n"));
3947 1066 1 : printf(_(" -V, --version output version information, then exit\n"));
128 michael 1067 GNC 1 : printf(_(" -Z, --compress=METHOD[:LEVEL]\n"
1068 : " compress as specified\n"));
3978 peter_e 1069 CBC 1 : printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
2209 andrew 1070 1 : printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
3947 peter_e 1071 1 : printf(_(" -?, --help show this help, then exit\n"));
7478 peter_e 1072 ECB :
7478 peter_e 1073 CBC 1 : printf(_("\nOptions controlling the output content:\n"));
3978 1074 1 : printf(_(" -a, --data-only dump only the data, not the schema\n"));
38 dgustafsson 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"));
3978 peter_e 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"));
739 michael 1081 1 : printf(_(" -e, --extension=PATTERN dump the specified extension(s) only\n"));
3978 peter_e 1082 1 : printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
1314 peter 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"));
3978 peter_e 1085 1 : printf(_(" -O, --no-owner skip restoration of object ownership in\n"
3978 peter_e 1086 ECB : " plain-text format\n"));
3978 peter_e 1087 CBC 1 : printf(_(" -s, --schema-only dump only the schema, no data\n"));
3978 peter_e 1088 GIC 1 : printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
26 tgl 1089 GNC 1 : printf(_(" -t, --table=PATTERN dump only the specified table(s)\n"));
1314 peter 1090 GIC 1 : printf(_(" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n"));
3978 peter_e 1091 CBC 1 : printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
3978 peter_e 1092 GIC 1 : printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
3978 peter_e 1093 CBC 1 : printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
3978 peter_e 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"));
2762 peter_e 1096 CBC 1 : printf(_(" --enable-row-security enable row security (dump only content user has\n"
1097 : " access to)\n"));
26 tgl 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"));
1314 peter 1101 GIC 1 : printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
26 tgl 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"));
1511 andrew 1105 GIC 1 : printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
3324 alvherre 1106 1 : printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
1110 1107 1 : printf(_(" --include-foreign-data=PATTERN\n"
1108 : " include data of foreign tables on foreign\n"
1066 peter 1109 ECB : " servers matching PATTERN\n"));
3978 peter_e 1110 CBC 1 : printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
1770 peter_e 1111 GIC 1 : printf(_(" --load-via-partition-root load partitions via the root table\n"));
1900 tgl 1112 1 : printf(_(" --no-comments do not dump comments\n"));
2158 peter_e 1113 1 : printf(_(" --no-publications do not dump publications\n"));
3978 1114 1 : printf(_(" --no-security-labels do not dump security label assignments\n"));
2161 1115 1 : printf(_(" --no-subscriptions do not dump subscriptions\n"));
447 michael 1116 1 : printf(_(" --no-table-access-method do not dump table access methods\n"));
3978 peter_e 1117 1 : printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
695 peter 1118 1 : printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
3978 peter_e 1119 CBC 1 : printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
1731 tmunro 1120 1 : printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
3978 peter_e 1121 GIC 1 : printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
1494 alvherre 1122 CBC 1 : printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
3978 peter_e 1123 GIC 1 : printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
3978 peter_e 1124 CBC 1 : printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
2751 peter_e 1125 GIC 1 : printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
2764 teodor 1126 1 : printf(_(" --strict-names require table and/or schema include patterns to\n"
1127 : " match at least one entity each\n"));
26 tgl 1128 GNC 1 : printf(_(" --table-and-children=PATTERN dump only the specified table(s),\n"
1129 : " including child and partition tables\n"));
6028 peter_e 1130 GIC 1 : printf(_(" --use-set-session-authorization\n"
3978 peter_e 1131 ECB : " use SET SESSION AUTHORIZATION commands instead of\n"
1132 : " ALTER OWNER commands to set ownership\n"));
7478 1133 :
7478 peter_e 1134 CBC 1 : printf(_("\nConnection options:\n"));
3695 heikki.linnakangas 1135 1 : printf(_(" -d, --dbname=DBNAME database to dump\n"));
7242 bruce 1136 GIC 1 : printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
7478 peter_e 1137 CBC 1 : printf(_(" -p, --port=PORT database server port number\n"));
1138 1 : printf(_(" -U, --username=NAME connect as specified database user\n"));
5136 1139 1 : printf(_(" -w, --no-password never prompt for password\n"));
7478 peter_e 1140 GIC 1 : printf(_(" -W, --password force password prompt (should happen automatically)\n"));
4337 peter_e 1141 CBC 1 : printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
7529 peter_e 1142 ECB :
7200 peter_e 1143 CBC 1 : printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
7529 peter_e 1144 ECB : "variable value is used.\n\n"));
1136 peter 1145 GIC 1 : printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1136 peter 1146 CBC 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
7639 tgl 1147 1 : }
8216 pjw 1148 ECB :
1149 : static void
2643 tgl 1150 CBC 149 : setup_connection(Archive *AH, const char *dumpencoding,
3065 simon 1151 ECB : const char *dumpsnapshot, char *use_role)
4090 rhaas 1152 : {
2643 tgl 1153 GIC 149 : DumpOptions *dopt = AH->dopt;
4070 rhaas 1154 CBC 149 : PGconn *conn = GetConnection(AH);
1155 : const char *std_strings;
4090 rhaas 1156 ECB :
1868 noah 1157 CBC 149 : PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1868 noah 1158 ECB :
3668 andrew 1159 : /*
2503 tgl 1160 : * Set the client encoding if requested.
3668 andrew 1161 : */
4090 rhaas 1162 CBC 149 : if (dumpencoding)
1163 : {
4070 1164 20 : if (PQsetClientEncoding(conn, dumpencoding) < 0)
366 tgl 1165 LBC 0 : pg_fatal("invalid client encoding \"%s\" specified",
366 tgl 1166 ECB : dumpencoding);
4090 rhaas 1167 : }
1168 :
1169 : /*
1170 : * Get the active encoding and the standard_conforming_strings setting, so
1171 : * we know how to escape strings.
1172 : */
4070 rhaas 1173 CBC 149 : AH->encoding = PQclientEncoding(conn);
1174 :
1175 149 : std_strings = PQparameterStatus(conn, "standard_conforming_strings");
4090 rhaas 1176 GIC 149 : AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1177 :
2503 tgl 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 : */
3668 andrew 1183 CBC 149 : if (!use_role && AH->use_role)
1184 2 : use_role = AH->use_role;
1185 :
1186 : /* Set the role if requested */
481 tgl 1187 149 : if (use_role)
4090 rhaas 1188 ECB : {
4090 rhaas 1189 CBC 5 : PQExpBuffer query = createPQExpBuffer();
4090 rhaas 1190 ECB :
4090 rhaas 1191 CBC 5 : appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
4079 1192 5 : ExecuteSqlStatement(AH, query->data);
4090 1193 5 : destroyPQExpBuffer(query);
3668 andrew 1194 ECB :
2503 tgl 1195 : /* save it for possible later use by parallel workers */
3668 andrew 1196 CBC 5 : if (!AH->use_role)
2503 tgl 1197 3 : AH->use_role = pg_strdup(use_role);
4090 rhaas 1198 ECB : }
1199 :
1200 : /* Set the datestyle to ISO to ensure the dump's portability */
4079 rhaas 1201 CBC 149 : ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
4090 rhaas 1202 ECB :
1203 : /* Likewise, avoid using sql_standard intervalstyle */
481 tgl 1204 GIC 149 : ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
4090 rhaas 1205 ECB :
1206 : /*
1418 tgl 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 : */
1511 andrew 1211 CBC 149 : if (have_extra_float_digits)
1511 andrew 1212 ECB : {
1511 andrew 1213 LBC 0 : PQExpBuffer q = createPQExpBuffer();
1418 tgl 1214 ECB :
1511 andrew 1215 LBC 0 : appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1511 andrew 1216 ECB : extra_float_digits);
1511 andrew 1217 LBC 0 : ExecuteSqlStatement(AH, q->data);
1218 0 : destroyPQExpBuffer(q);
1219 : }
2370 tgl 1220 ECB : else
481 tgl 1221 GIC 149 : ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
4090 rhaas 1222 ECB :
1223 : /*
481 tgl 1224 : * Disable synchronized scanning, to prevent unpredictable changes in row
1225 : * ordering across a dump and reload.
1226 : */
481 tgl 1227 CBC 149 : ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1228 :
1229 : /*
4090 rhaas 1230 ECB : * Disable timeouts if supported.
1231 : */
2370 tgl 1232 GIC 149 : ExecuteSqlStatement(AH, "SET statement_timeout = 0");
3676 1233 149 : if (AH->remoteVersion >= 90300)
3676 tgl 1234 CBC 149 : ExecuteSqlStatement(AH, "SET lock_timeout = 0");
2489 tgl 1235 GIC 149 : if (AH->remoteVersion >= 90600)
1236 149 : ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1237 :
1238 : /*
4090 rhaas 1239 ECB : * Quote all identifiers, if requested.
1240 : */
481 tgl 1241 CBC 149 : if (quote_all_identifiers)
4079 rhaas 1242 GBC 6 : ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1243 :
1244 : /*
1245 : * Adjust row-security mode, if supported.
1246 : */
2972 tgl 1247 GIC 149 : if (AH->remoteVersion >= 90500)
1248 : {
1249 149 : if (dopt->enable_row_security)
2972 tgl 1250 LBC 0 : ExecuteSqlStatement(AH, "SET row_security = on");
1251 : else
2972 tgl 1252 CBC 149 : ExecuteSqlStatement(AH, "SET row_security = off");
2972 tgl 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 : */
489 tgl 1259 GIC 149 : AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
489 tgl 1260 ECB :
3668 andrew 1261 : /*
1262 : * Start transaction-snapshot mode transaction to dump consistent data.
1263 : */
3668 andrew 1264 CBC 149 : ExecuteSqlStatement(AH, "BEGIN");
1265 :
481 tgl 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 : */
481 tgl 1274 CBC 149 : if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
481 tgl 1275 UIC 0 : ExecuteSqlStatement(AH,
1276 : "SET TRANSACTION ISOLATION LEVEL "
1277 : "SERIALIZABLE, READ ONLY, DEFERRABLE");
2370 tgl 1278 ECB : else
3668 andrew 1279 GIC 149 : ExecuteSqlStatement(AH,
1280 : "SET TRANSACTION ISOLATION LEVEL "
481 tgl 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 : */
3065 simon 1288 CBC 149 : if (dumpsnapshot)
2503 tgl 1289 UIC 0 : AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
3668 andrew 1290 EUB :
3065 simon 1291 GIC 149 : if (AH->sync_snapshot_id)
3668 andrew 1292 EUB : {
3065 simon 1293 GIC 18 : PQExpBuffer query = createPQExpBuffer();
2878 bruce 1294 EUB :
1375 drowley 1295 GBC 18 : appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
3065 simon 1296 GIC 18 : appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1297 18 : ExecuteSqlStatement(AH, query->data);
3065 simon 1298 CBC 18 : destroyPQExpBuffer(query);
1299 : }
480 tgl 1300 GIC 131 : else if (AH->numWorkers > 1)
1301 : {
2062 peter_e 1302 9 : if (AH->isStandby && AH->remoteVersion < 100000)
366 tgl 1303 UIC 0 : pg_fatal("parallel dumps from standby servers are not supported by this server version");
3065 simon 1304 CBC 9 : AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1305 : }
3668 andrew 1306 GIC 149 : }
1307 :
1308 : /* Set up connection for a parallel worker process */
3668 andrew 1309 ECB : static void
2503 tgl 1310 CBC 18 : setupDumpWorker(Archive *AH)
3668 andrew 1311 ECB : {
2503 tgl 1312 : /*
1029 andres 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 : */
2503 tgl 1318 CBC 18 : setup_connection(AH,
2503 tgl 1319 ECB : pg_encoding_to_char(AH->encoding),
1320 : NULL,
1321 : NULL);
3668 andrew 1322 GIC 18 : }
1323 :
3668 andrew 1324 ECB : static char *
3668 andrew 1325 GIC 9 : get_synchronized_snapshot(Archive *fout)
3668 andrew 1326 ECB : {
2503 tgl 1327 GBC 9 : char *query = "SELECT pg_catalog.pg_export_snapshot()";
1328 : char *result;
3668 andrew 1329 ECB : PGresult *res;
1330 :
3668 andrew 1331 GIC 9 : res = ExecuteSqlQueryForSingleRow(fout, query);
2503 tgl 1332 9 : result = pg_strdup(PQgetvalue(res, 0, 0));
3668 andrew 1333 9 : PQclear(res);
1334 :
1335 9 : return result;
4090 rhaas 1336 ECB : }
1337 :
1338 : static ArchiveFormat
4459 heikki.linnakangas 1339 GIC 139 : parseArchiveFormat(const char *format, ArchiveMode *mode)
1340 : {
4459 heikki.linnakangas 1341 ECB : ArchiveFormat archiveFormat;
1342 :
4459 heikki.linnakangas 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 : }
4459 heikki.linnakangas 1351 CBC 105 : else if (pg_strcasecmp(format, "c") == 0)
4459 heikki.linnakangas 1352 GBC 2 : archiveFormat = archCustom;
4459 heikki.linnakangas 1353 GIC 103 : else if (pg_strcasecmp(format, "custom") == 0)
1354 10 : archiveFormat = archCustom;
1355 93 : else if (pg_strcasecmp(format, "d") == 0)
4459 heikki.linnakangas 1356 CBC 7 : archiveFormat = archDirectory;
4459 heikki.linnakangas 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;
4459 heikki.linnakangas 1365 CBC 2 : else if (pg_strcasecmp(format, "tar") == 0)
4459 heikki.linnakangas 1366 GBC 1 : archiveFormat = archTar;
1367 : else
366 tgl 1368 CBC 1 : pg_fatal("invalid output format \"%s\" specified", format);
4459 heikki.linnakangas 1369 GIC 138 : return archiveFormat;
4459 heikki.linnakangas 1370 ECB : }
1371 :
7639 tgl 1372 : /*
6026 1373 : * Find the OIDs of all schemas matching the given list of patterns,
1374 : * and append them to the given OID list.
7639 1375 : */
1376 : static void
4080 rhaas 1377 CBC 138 : expand_schema_name_patterns(Archive *fout,
1378 : SimpleStringList *patterns,
2764 teodor 1379 ECB : SimpleOidList *oids,
2764 teodor 1380 EUB : bool strict_names)
7639 tgl 1381 ECB : {
1382 : PQExpBuffer query;
6026 1383 : PGresult *res;
1384 : SimpleStringListCell *cell;
1385 : int i;
1386 :
6026 tgl 1387 CBC 138 : if (patterns->head == NULL)
6026 tgl 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.
7639 tgl 1395 ECB : */
1396 :
6026 tgl 1397 GIC 24 : for (cell = patterns->head; cell; cell = cell->next)
1398 : {
332 tgl 1399 ECB : PQExpBufferData dbbuf;
1400 : int dotcnt;
1401 :
1375 drowley 1402 CBC 15 : appendPQExpBufferStr(query,
1403 : "SELECT oid FROM pg_catalog.pg_namespace n\n");
354 rhaas 1404 15 : initPQExpBuffer(&dbbuf);
4070 rhaas 1405 GIC 15 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1406 : false, NULL, "n.nspname", NULL, NULL, &dbbuf,
1407 : &dotcnt);
354 rhaas 1408 CBC 15 : if (dotcnt > 1)
1409 2 : pg_fatal("improper qualified name (too many dotted names): %s",
354 rhaas 1410 ECB : cell->val);
354 rhaas 1411 GIC 13 : else if (dotcnt == 1)
354 rhaas 1412 CBC 3 : prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
354 rhaas 1413 GIC 10 : termPQExpBuffer(&dbbuf);
1414 :
2764 teodor 1415 10 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2764 teodor 1416 CBC 10 : if (strict_names && PQntuples(res) == 0)
366 tgl 1417 GIC 1 : pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
1418 :
2764 teodor 1419 17 : for (i = 0; i < PQntuples(res); i++)
2764 teodor 1420 ECB : {
2764 teodor 1421 GIC 8 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
2764 teodor 1422 ECB : }
1423 :
2764 teodor 1424 GIC 9 : PQclear(res);
2764 teodor 1425 CBC 9 : resetPQExpBuffer(query);
7360 bruce 1426 ECB : }
1427 :
6026 tgl 1428 CBC 9 : destroyPQExpBuffer(query);
7639 tgl 1429 ECB : }
7997 peter_e 1430 :
739 michael 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
739 michael 1436 CBC 4 : expand_extension_name_patterns(Archive *fout,
739 michael 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 :
739 michael 1446 CBC 4 : if (patterns->head == NULL)
739 michael 1447 UIC 0 : return; /* nothing to do */
1448 :
739 michael 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.
739 michael 1454 ECB : */
739 michael 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);
354 rhaas 1464 CBC 4 : if (dotcnt > 0)
354 rhaas 1465 LBC 0 : pg_fatal("improper qualified name (too many dotted names): %s",
1466 : cell->val);
739 michael 1467 ECB :
739 michael 1468 GIC 4 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1469 4 : if (strict_names && PQntuples(res) == 0)
366 tgl 1470 UIC 0 : pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
1471 :
739 michael 1472 GIC 8 : for (i = 0; i < PQntuples(res); i++)
1473 : {
739 michael 1474 CBC 4 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1475 : }
1476 :
739 michael 1477 GIC 4 : PQclear(res);
1478 4 : resetPQExpBuffer(query);
739 michael 1479 ECB : }
1480 :
739 michael 1481 CBC 4 : destroyPQExpBuffer(query);
739 michael 1482 ECB : }
1483 :
1484 : /*
1110 alvherre 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
1110 alvherre 1489 CBC 119 : expand_foreign_server_name_patterns(Archive *fout,
1110 alvherre 1490 ECB : SimpleStringList *patterns,
1491 : SimpleOidList *oids)
1492 : {
1493 : PQExpBuffer query;
1494 : PGresult *res;
1495 : SimpleStringListCell *cell;
1496 : int i;
1497 :
1110 alvherre 1498 CBC 119 : if (patterns->head == NULL)
1110 alvherre 1499 GIC 117 : return; /* nothing to do */
1500 :
1110 alvherre 1501 CBC 2 : query = createPQExpBuffer();
1110 alvherre 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 :
1110 alvherre 1508 GIC 4 : for (cell = patterns->head; cell; cell = cell->next)
1509 : {
1510 : int dotcnt;
1511 :
906 drowley 1512 2 : appendPQExpBufferStr(query,
906 drowley 1513 ECB : "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
1110 alvherre 1514 GIC 2 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1515 : false, NULL, "s.srvname", NULL, NULL, NULL,
1516 : &dotcnt);
354 rhaas 1517 2 : if (dotcnt > 0)
354 rhaas 1518 UIC 0 : pg_fatal("improper qualified name (too many dotted names): %s",
1519 : cell->val);
1520 :
1110 alvherre 1521 GIC 2 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1522 2 : if (PQntuples(res) == 0)
366 tgl 1523 LBC 0 : pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
1110 alvherre 1524 EUB :
1110 alvherre 1525 GIC 4 : for (i = 0; i < PQntuples(res); i++)
1110 alvherre 1526 CBC 2 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1527 :
1110 alvherre 1528 GIC 2 : PQclear(res);
1529 2 : resetPQExpBuffer(query);
1530 : }
1531 :
1110 alvherre 1532 CBC 2 : destroyPQExpBuffer(query);
1533 : }
1534 :
1535 : /*
6026 tgl 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()
1500 andrew 1538 : * in pg_dumpall.c
1539 : */
1540 : static void
4079 rhaas 1541 CBC 720 : expand_table_name_patterns(Archive *fout,
2764 teodor 1542 EUB : SimpleStringList *patterns, SimpleOidList *oids,
1543 : bool strict_names, bool with_child_tables)
1544 : {
6026 tgl 1545 ECB : PQExpBuffer query;
1546 : PGresult *res;
6026 tgl 1547 EUB : SimpleStringListCell *cell;
1548 : int i;
6026 tgl 1549 ECB :
6026 tgl 1550 GIC 720 : if (patterns->head == NULL)
6026 tgl 1551 CBC 707 : return; /* nothing to do */
1552 :
6026 tgl 1553 GIC 13 : query = createPQExpBuffer();
6026 tgl 1554 ECB :
7639 1555 : /*
1556 : * this might sometimes result in duplicate entries in the OID list, but
1557 : * we don't care.
1558 : */
1559 :
6026 tgl 1560 GIC 23 : for (cell = patterns->head; cell; cell = cell->next)
1561 : {
1562 : PQExpBufferData dbbuf;
1563 : int dotcnt;
1564 :
1565 : /*
1868 noah 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 : */
26 tgl 1573 GNC 14 : if (with_child_tables)
1574 : {
1575 3 : appendPQExpBuffer(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
1576 : }
1577 :
6026 tgl 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"
1868 noah 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,
2314 rhaas 1586 : RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1587 : RELKIND_PARTITIONED_TABLE);
354 rhaas 1588 GIC 14 : initPQExpBuffer(&dbbuf);
4070 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);
354 rhaas 1593 CBC 14 : if (dotcnt > 2)
354 rhaas 1594 GIC 1 : pg_fatal("improper relation name (too many dotted names): %s",
1595 : cell->val);
1596 13 : else if (dotcnt == 2)
354 rhaas 1597 CBC 2 : prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
354 rhaas 1598 GIC 11 : termPQExpBuffer(&dbbuf);
6094 bruce 1599 ECB :
26 tgl 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 :
1868 noah 1611 GIC 11 : ExecuteSqlStatement(fout, "RESET search_path");
2764 teodor 1612 11 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1868 noah 1613 CBC 11 : PQclear(ExecuteSqlQueryForSingleRow(fout,
1868 noah 1614 EUB : ALWAYS_SECURE_SEARCH_PATH_SQL));
2764 teodor 1615 GIC 11 : if (strict_names && PQntuples(res) == 0)
366 tgl 1616 1 : pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
6094 bruce 1617 ECB :
2764 teodor 1618 CBC 31 : for (i = 0; i < PQntuples(res); i++)
2764 teodor 1619 EUB : {
2764 teodor 1620 GIC 21 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
2764 teodor 1621 ECB : }
1622 :
2764 teodor 1623 GIC 10 : PQclear(res);
2764 teodor 1624 CBC 10 : resetPQExpBuffer(query);
7242 tgl 1625 ECB : }
1626 :
6026 tgl 1627 GIC 9 : destroyPQExpBuffer(query);
6026 tgl 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
354 rhaas 1637 CBC 5 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
1638 : {
1639 : const char *db;
1640 :
354 rhaas 1641 GIC 5 : db = PQdb(conn);
1642 5 : if (db == NULL)
354 rhaas 1643 UIC 0 : pg_fatal("You are currently not connected to a database.");
1644 :
354 rhaas 1645 GIC 5 : if (strcmp(db, dbname) != 0)
354 rhaas 1646 CBC 5 : pg_fatal("cross-database references are not implemented: %s",
354 rhaas 1647 ECB : pattern);
354 rhaas 1648 UIC 0 : }
354 rhaas 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
2643 tgl 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
2559 sfrost 1662 GIC 445511 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1663 : {
2643 tgl 1664 445511 : ExtensionInfo *ext = findOwningExtension(dobj->catId);
1665 :
1666 445511 : if (ext == NULL)
1667 445039 : return false;
1668 :
2643 tgl 1669 CBC 472 : dobj->ext_member = true;
1670 :
2643 tgl 1671 ECB : /* Record dependency so that getDependencies needn't deal with that */
2643 tgl 1672 GIC 472 : addObjectDependency(dobj, ext->dobj.dumpId);
1673 :
2643 tgl 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.
2559 sfrost 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.
2643 tgl 1689 : */
2529 sfrost 1690 CBC 472 : if (fout->dopt->binary_upgrade)
2643 tgl 1691 GIC 47 : dobj->dump = ext->dobj.dump;
2529 sfrost 1692 ECB : else
1693 : {
2529 sfrost 1694 CBC 425 : if (fout->remoteVersion < 90600)
2529 sfrost 1695 UIC 0 : dobj->dump = DUMP_COMPONENT_NONE;
2529 sfrost 1696 ECB : else
2529 sfrost 1697 GIC 425 : dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
2404 tgl 1698 ECB : DUMP_COMPONENT_SECLABEL |
1699 : DUMP_COMPONENT_POLICY);
1700 : }
1701 :
2643 tgl 1702 GIC 472 : return true;
1703 : }
1704 :
1705 : /*
1706 : * selectDumpableNamespace: policy-setting subroutine
6026 tgl 1707 ECB : * Mark a namespace as to be dumped or not
1708 : */
1709 : static void
2559 sfrost 1710 GIC 783 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
6026 tgl 1711 ECB : {
650 noah 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 : */
650 noah 1717 GIC 783 : nsinfo->create = true;
1718 :
6026 tgl 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 : */
6026 tgl 1724 GIC 783 : if (table_include_oids.head != NULL)
2559 sfrost 1725 18 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
6026 tgl 1726 765 : else if (schema_include_oids.head != NULL)
2559 sfrost 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 &&
2404 tgl 1732 726 : strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
2404 tgl 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
2559 sfrost 1737 : * initdb time, see pg_init_privs).
1738 : */
2559 sfrost 1739 GBC 109 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1740 : }
6026 tgl 1741 CBC 617 : else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1742 356 : strcmp(nsinfo->dobj.name, "information_schema") == 0)
1743 : {
2404 tgl 1744 EUB : /* Other system schemas don't get dumped */
2559 sfrost 1745 GIC 370 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1746 : }
1900 tgl 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 : */
650 noah 1757 105 : nsinfo->create = false;
650 noah 1758 CBC 105 : nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
577 noah 1759 GIC 105 : if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
650 noah 1760 CBC 62 : nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
1900 tgl 1761 GIC 105 : nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
489 tgl 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 : */
489 tgl 1768 CBC 105 : nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
1769 : }
1770 : else
2559 sfrost 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 &&
6026 tgl 1777 363 : simple_oid_list_member(&schema_exclude_oids,
1778 : nsinfo->dobj.catId.oid))
2559 sfrost 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
2404 tgl 1786 ECB : * suppressed by it, otherwise not.)
1787 : */
2404 tgl 1788 GIC 783 : (void) checkExtensionMembership(&nsinfo->dobj, fout);
6026 1789 783 : }
6026 tgl 1790 ECB :
6026 tgl 1791 EUB : /*
1792 : * selectDumpableTable: policy-setting subroutine
6026 tgl 1793 ECB : * Mark a table as to be dumped or not
1794 : */
1795 : static void
2559 sfrost 1796 GIC 30467 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1797 : {
2559 sfrost 1798 CBC 30467 : if (checkExtensionMembership(&tbinfo->dobj, fout))
2643 tgl 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 : */
6026 1805 30269 : if (table_include_oids.head != NULL)
6026 tgl 1806 CBC 1488 : tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1807 : tbinfo->dobj.catId.oid) ?
2559 sfrost 1808 GIC 744 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1809 : else
1810 29525 : tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1811 :
1812 : /*
6026 tgl 1813 ECB : * In any case, a table can be excluded by an exclusion switch
1814 : */
6026 tgl 1815 GIC 50701 : if (tbinfo->dobj.dump &&
1816 20432 : simple_oid_list_member(&table_exclude_oids,
1817 : tbinfo->dobj.catId.oid))
2559 sfrost 1818 6 : tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1819 : }
8216 pjw 1820 ECB :
6247 tgl 1821 : /*
1822 : * selectDumpableType: policy-setting subroutine
1823 : * Mark a type as to be dumped or not
5194 1824 : *
1825 : * If it's a table's rowtype or an autogenerated array type, we also apply a
3260 bruce 1826 : * special type code to facilitate sorting into the desired order. (We don't
5194 tgl 1827 : * want to consider those to be ordinary types because that would bring tables
4191 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
2559 sfrost 1835 CBC 83866 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1836 : {
5194 tgl 1837 ECB : /* skip complex types, except for standalone composite types */
4855 bruce 1838 CBC 83866 : if (OidIsValid(tyinfo->typrelid) &&
4855 bruce 1839 GIC 29911 : tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1840 : {
4191 tgl 1841 CBC 29774 : TableInfo *tytable = findTableByOid(tyinfo->typrelid);
1842 :
4855 bruce 1843 29774 : tyinfo->dobj.objType = DO_DUMMY_TYPE;
4191 tgl 1844 GIC 29774 : if (tytable != NULL)
1845 29774 : tyinfo->dobj.dump = tytable->dobj.dump;
1846 : else
2559 sfrost 1847 UIC 0 : tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
4191 tgl 1848 GIC 29774 : return;
1849 : }
1850 :
1851 : /* skip auto-generated array types */
840 akorotkov 1852 54092 : if (tyinfo->isArray || tyinfo->isMultirange)
5194 tgl 1853 ECB : {
4855 bruce 1854 CBC 41015 : tyinfo->dobj.objType = DO_DUMMY_TYPE;
3955 bruce 1855 ECB :
4191 tgl 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 :
2559 sfrost 1864 CBC 54092 : if (checkExtensionMembership(&tyinfo->dobj, fout))
2643 tgl 1865 GIC 22 : return; /* extension membership overrides all else */
1866 :
2559 sfrost 1867 ECB : /* Dump based on if the contents of the namespace are being dumped */
2559 sfrost 1868 GIC 54070 : tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1869 : }
1870 :
1871 : /*
4934 tgl 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
2643 tgl 1880 GIC 180 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1881 : {
1882 : /* Default ACLs can't be extension members */
1883 :
4934 tgl 1884 CBC 180 : if (dinfo->dobj.namespace)
2559 sfrost 1885 ECB : /* default ACLs are considered part of the namespace */
2529 sfrost 1886 GIC 90 : dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1887 : else
2559 1888 90 : dinfo->dobj.dump = dopt->include_everything ?
1889 90 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
4934 tgl 1890 180 : }
1891 :
2980 tgl 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
2559 sfrost 1902 CBC 26389 : selectDumpableCast(CastInfo *cast, Archive *fout)
1903 : {
1904 26389 : if (checkExtensionMembership(&cast->dobj, fout))
2643 tgl 1905 UIC 0 : return; /* extension membership overrides all else */
2643 tgl 1906 ECB :
1907 : /*
1908 : * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1909 : * support ACLs currently.
1910 : */
2300 sfrost 1911 CBC 26389 : if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2559 1912 26314 : cast->dobj.dump = DUMP_COMPONENT_NONE;
1913 : else
1914 75 : cast->dobj.dump = fout->dopt->include_everything ?
2559 sfrost 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))
2643 tgl 1930 118 : return; /* extension membership overrides all else */
2643 tgl 1931 ECB :
1932 : /*
1933 : * Only include procedural languages when we are dumping everything.
2529 sfrost 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 : */
2529 sfrost 1939 CBC 45 : if (!fout->dopt->include_everything)
2559 1940 7 : plang->dobj.dump = DUMP_COMPONENT_NONE;
2643 tgl 1941 ECB : else
1942 : {
2300 sfrost 1943 GBC 38 : if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2529 sfrost 1944 LBC 0 : plang->dobj.dump = fout->remoteVersion < 90600 ?
2529 sfrost 1945 UIC 0 : DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1946 : else
2529 sfrost 1947 GIC 38 : plang->dobj.dump = DUMP_COMPONENT_ALL;
2529 sfrost 1948 ECB : }
1949 : }
2643 tgl 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
2559 sfrost 1960 CBC 943 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
2573 alvherre 1961 ECB : {
2559 sfrost 1962 GIC 943 : if (checkExtensionMembership(&method->dobj, fout))
2573 alvherre 1963 22 : return; /* extension membership overrides all else */
2573 alvherre 1964 ECB :
1965 : /*
1966 : * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1967 : * they do not support ACLs currently.
1968 : */
2300 sfrost 1969 GIC 921 : if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2559 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 :
4419 tgl 1976 ECB : /*
1977 : * selectDumpableExtension: policy-setting subroutine
1978 : * Mark an extension as to be dumped or not
1979 : *
1900 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
4337 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
739 michael 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.
4419 tgl 1986 : */
1987 : static void
2643 tgl 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 : */
1900 1995 141 : if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2529 sfrost 1996 119 : extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1997 : else
739 michael 1998 ECB : {
1999 : /* check if there is a list of extensions to dump */
739 michael 2000 CBC 22 : if (extension_include_oids.head != NULL)
739 michael 2001 GBC 4 : extinfo->dobj.dump = extinfo->dobj.dump_contains =
739 michael 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 =
739 michael 2007 CBC 18 : dopt->include_everything ?
2008 18 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2009 : }
4419 tgl 2010 141 : }
4419 tgl 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
529 akapila 2021 GIC 353 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
2022 : {
2210 peter_e 2023 CBC 353 : if (checkExtensionMembership(dobj, fout))
2210 peter_e 2024 UIC 0 : return; /* extension membership overrides all else */
2210 peter_e 2025 ECB :
2210 peter_e 2026 CBC 353 : dobj->dump = fout->dopt->include_everything ?
2210 peter_e 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.
6247 tgl 2035 ECB : */
2036 : static void
2559 sfrost 2037 GIC 332321 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
2038 : {
2559 sfrost 2039 CBC 332321 : if (checkExtensionMembership(dobj, fout))
2643 tgl 2040 GBC 90 : return; /* extension membership overrides all else */
2643 tgl 2041 EUB :
2042 : /*
2643 tgl 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 : */
6247 tgl 2046 GIC 332231 : if (dobj->namespace)
2559 sfrost 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
7639 tgl 2056 ECB : * to be dumped.
2057 : */
2058 : static int
788 peter 2059 CBC 2982 : dumpTableData_copy(Archive *fout, const void *dcontext)
2060 : {
7064 tgl 2061 GIC 2982 : TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2062 2982 : TableInfo *tbinfo = tdinfo->tdtable;
6976 2063 2982 : const char *classname = tbinfo->dobj.name;
7639 2064 2982 : PQExpBuffer q = createPQExpBuffer();
3668 andrew 2065 ECB :
2066 : /*
2067 : * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
2068 : * which uses it already.
2069 : */
3668 andrew 2070 GIC 2982 : PQExpBuffer clistBuf = createPQExpBuffer();
4070 rhaas 2071 2982 : PGconn *conn = GetConnection(fout);
2072 : PGresult *res;
2073 : int ret;
2074 : char *copybuf;
2075 : const char *column_list;
2076 :
1469 peter 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
2370 tgl 2084 ECB : * involving ADD COLUMN and inheritance.)
2085 : */
2370 tgl 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
1110 alvherre 2091 ECB : * suffices.
2092 : */
1110 alvherre 2093 GIC 2982 : if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2094 : {
4443 tgl 2095 1 : appendPQExpBufferStr(q, "COPY (SELECT ");
4443 tgl 2096 ECB : /* klugery to get rid of parens in column list */
4443 tgl 2097 CBC 1 : if (strlen(column_list) > 2)
4443 tgl 2098 ECB : {
4443 tgl 2099 GIC 1 : appendPQExpBufferStr(q, column_list + 1);
4443 tgl 2100 CBC 1 : q->data[q->len - 1] = ' ';
2101 : }
4443 tgl 2102 ECB : else
4443 tgl 2103 LBC 0 : appendPQExpBufferStr(q, "* ");
1110 alvherre 2104 ECB :
4443 tgl 2105 GIC 2 : appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1868 tgl 2106 CBC 1 : fmtQualifiedDumpable(tbinfo),
1110 alvherre 2107 GIC 1 : tdinfo->filtercond ? tdinfo->filtercond : "");
2108 : }
2109 : else
2110 : {
7570 bruce 2111 2981 : appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1868 tgl 2112 2981 : fmtQualifiedDumpable(tbinfo),
2113 : column_list);
2114 : }
4079 rhaas 2115 2982 : res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
6246 tgl 2116 2981 : PQclear(res);
3668 andrew 2117 CBC 2981 : destroyPQExpBuffer(clistBuf);
2118 :
6246 tgl 2119 ECB : for (;;)
8053 bruce 2120 EUB : {
4070 rhaas 2121 GIC 1694713 : ret = PQgetCopyData(conn, ©buf, 0);
8314 bruce 2122 ECB :
6246 tgl 2123 CBC 1694713 : if (ret < 0)
6246 tgl 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 : /* ----------
7639 tgl 2133 ECB : * THROTTLE:
2134 : *
6347 bruce 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'
6385 2142 : * implementation was suggested. The latter failed because the loop
2143 : * was too tight. Finally, the following was implemented:
2144 : *
5750 neilc 2145 : * If throttle is non-zero, then
5624 bruce 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
6347 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
6385 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 : }
7539 peter_e 2178 GIC 2981 : archprintf(fout, "\\.\n\n\n");
2179 :
6246 tgl 2180 2981 : if (ret == -2)
2181 : {
6246 tgl 2182 ECB : /* copy data transfer failed */
1469 peter 2183 UIC 0 : pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
366 tgl 2184 0 : pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2185 0 : pg_log_error_detail("Command was: %s", q->data);
4070 rhaas 2186 0 : exit_nicely(1);
2187 : }
2188 :
6246 tgl 2189 ECB : /* Check command status and return to normal libpq state */
4070 rhaas 2190 GIC 2981 : res = PQgetResult(conn);
4079 rhaas 2191 CBC 2981 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
2192 : {
1469 peter 2193 LBC 0 : pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
366 tgl 2194 UIC 0 : pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
366 tgl 2195 LBC 0 : pg_log_error_detail("Command was: %s", q->data);
4070 rhaas 2196 0 : exit_nicely(1);
2197 : }
7586 bruce 2198 GIC 2981 : PQclear(res);
6246 tgl 2199 EUB :
2200 : /* Do this to ensure we've pumped libpq back to idle state */
2502 tgl 2201 CBC 2981 : if (PQgetResult(conn) != NULL)
1469 peter 2202 LBC 0 : pg_log_warning("unexpected extra results during COPY of table \"%s\"",
1418 tgl 2203 ECB : classname);
2204 :
7639 tgl 2205 GIC 2981 : destroyPQExpBuffer(q);
2206 2981 : return 1;
7639 tgl 2207 ECB : }
9345 bruce 2208 :
2209 : /*
2210 : * Dump table data using INSERT commands.
4111 tgl 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 : */
7639 2217 : static int
788 peter 2218 GIC 57 : dumpTableData_insert(Archive *fout, const void *dcontext)
7639 tgl 2219 ECB : {
7064 tgl 2220 CBC 57 : TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
7064 tgl 2221 GIC 57 : TableInfo *tbinfo = tdinfo->tdtable;
2643 tgl 2222 CBC 57 : DumpOptions *dopt = fout->dopt;
7639 tgl 2223 GIC 57 : PQExpBuffer q = createPQExpBuffer();
3432 tgl 2224 CBC 57 : PQExpBuffer insertStmt = NULL;
503 tgl 2225 ECB : char *attgenerated;
2226 : PGresult *res;
2227 : int nfields,
2228 : i;
1494 alvherre 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 : */
503 tgl 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",
1868 2261 57 : fmtQualifiedDumpable(tbinfo));
4443 2262 57 : if (tdinfo->filtercond)
4443 tgl 2263 UIC 0 : appendPQExpBuffer(q, " %s", tdinfo->filtercond);
2264 :
4079 rhaas 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 */
503 tgl 2273 105 : if (nfields != PQnfields(res) &&
503 tgl 2274 CBC 10 : !(nfields == 0 && PQnfields(res) == 1))
366 tgl 2275 UIC 0 : pg_fatal("wrong number of fields retrieved from table \"%s\"",
366 tgl 2276 ECB : tbinfo->dobj.name);
2277 :
2278 : /*
1494 alvherre 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
503 tgl 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 : */
1494 alvherre 2285 GIC 105 : if (insertStmt == NULL)
7639 tgl 2286 ECB : {
1494 alvherre 2287 : TableInfo *targettab;
2288 :
1494 alvherre 2289 GBC 57 : insertStmt = createPQExpBuffer();
2064 rhaas 2290 EUB :
1494 alvherre 2291 : /*
23 tgl 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
23 tgl 2294 ECB : * through the root table.
2295 : */
23 tgl 2296 GIC 57 : if (tbinfo->ispartition &&
23 tgl 2297 CBC 32 : (dopt->load_via_partition_root ||
23 tgl 2298 GBC 16 : forcePartitionRootLoad(tbinfo)))
1494 alvherre 2299 GIC 3 : targettab = getRootTableInfo(tbinfo);
2300 : else
1494 alvherre 2301 CBC 54 : targettab = tbinfo;
2064 rhaas 2302 ECB :
1494 alvherre 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 */
1494 alvherre 2314 CBC 50 : if (dopt->column_inserts)
2315 : {
2316 21 : appendPQExpBufferChar(insertStmt, '(');
2317 73 : for (int field = 0; field < nfields; field++)
3432 tgl 2318 ECB : {
1494 alvherre 2319 CBC 52 : if (field > 0)
2320 31 : appendPQExpBufferStr(insertStmt, ", ");
1494 alvherre 2321 GIC 52 : appendPQExpBufferStr(insertStmt,
2322 52 : fmtId(PQfname(res, field)));
2323 : }
2324 21 : appendPQExpBufferStr(insertStmt, ") ");
1494 alvherre 2325 ECB : }
3432 tgl 2326 :
1494 alvherre 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++)
1494 alvherre 2335 ECB : {
2336 : /* Write the INSERT if not in the middle of a multi-row INSERT. */
1494 alvherre 2337 CBC 3069 : if (rows_this_statement == 0)
2338 3063 : archputs(insertStmt->data, fout);
2339 :
1494 alvherre 2340 ECB : /*
1441 michael 2341 : * If it is zero-column table then we've already written the
1494 alvherre 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 : */
3432 tgl 2349 CBC 3069 : if (nfields == 0)
2350 6 : continue;
3432 tgl 2351 ECB :
2352 : /* Emit a row heading */
1494 alvherre 2353 GIC 3063 : if (rows_per_statement == 1)
1494 alvherre 2354 CBC 3054 : archputs(" (", fout);
2355 9 : else if (rows_this_statement > 0)
2356 6 : archputs(",\n\t(", fout);
1494 alvherre 2357 ECB : else
1494 alvherre 2358 CBC 3 : archputs("\n\t(", fout);
1494 alvherre 2359 EUB :
1494 alvherre 2360 GIC 9245 : for (int field = 0; field < nfields; field++)
7639 tgl 2361 ECB : {
7639 tgl 2362 GIC 6182 : if (field > 0)
3432 2363 3119 : archputs(", ", fout);
503 2364 6182 : if (attgenerated[field])
1471 peter 2365 ECB : {
1471 peter 2366 GIC 2 : archputs("DEFAULT", fout);
2367 2 : continue;
2368 : }
7639 tgl 2369 CBC 6180 : if (PQgetisnull(res, tuple, field))
7639 tgl 2370 ECB : {
3432 tgl 2371 GBC 83 : archputs("NULL", fout);
7639 tgl 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:
7539 peter_e 2381 ECB : case OIDOID:
2382 : case FLOAT4OID:
2383 : case FLOAT8OID:
2384 : case NUMERICOID:
7522 bruce 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 : *
6347 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 : */
7522 bruce 2397 CBC 4069 : const char *s = PQgetvalue(res, tuple, field);
2398 :
2399 4069 : if (strspn(s, "0123456789 +-eE.") == strlen(s))
3432 tgl 2400 4067 : archputs(s, fout);
2401 : else
7522 bruce 2402 GIC 2 : archprintf(fout, "'%s'", s);
7522 bruce 2403 ECB : }
7522 bruce 2404 GIC 4069 : break;
7539 peter_e 2405 ECB :
7639 tgl 2406 GIC 2 : case BITOID:
2407 : case VARBITOID:
2408 2 : archprintf(fout, "B'%s'",
2409 : PQgetvalue(res, tuple, field));
7639 tgl 2410 CBC 2 : break;
2411 :
7539 peter_e 2412 4 : case BOOLOID:
7522 bruce 2413 4 : if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
3432 tgl 2414 GIC 2 : archputs("true", fout);
7539 peter_e 2415 ECB : else
3432 tgl 2416 CBC 2 : archputs("false", fout);
7539 peter_e 2417 4 : break;
7539 peter_e 2418 ECB :
7539 peter_e 2419 GIC 2022 : default:
7539 peter_e 2420 ECB : /* All other types are printed as string literals. */
7639 tgl 2421 GIC 2022 : resetPQExpBuffer(q);
6160 2422 2022 : appendStringLiteralAH(q,
6160 tgl 2423 ECB : PQgetvalue(res, tuple, field),
2424 : fout);
6647 tgl 2425 GIC 2022 : archputs(q->data, fout);
7639 tgl 2426 CBC 2022 : break;
2427 : }
2428 : }
2429 :
1494 alvherre 2430 ECB : /* Terminate the row ... */
1494 alvherre 2431 GIC 3063 : archputs(")", fout);
2432 :
1494 alvherre 2433 ECB : /* ... and the statement, if the target no. of rows is reached */
1494 alvherre 2434 CBC 3063 : if (++rows_this_statement >= rows_per_statement)
2435 : {
1494 alvherre 2436 GIC 3056 : if (dopt->do_nothing)
1494 alvherre 2437 UIC 0 : archputs(" ON CONFLICT DO NOTHING;\n", fout);
2438 : else
1494 alvherre 2439 GIC 3056 : archputs(";\n", fout);
2440 : /* Reset the row counter */
2441 3056 : rows_this_statement = 0;
2442 : }
2443 : }
2444 :
4079 rhaas 2445 CBC 105 : if (PQntuples(res) <= 0)
4079 rhaas 2446 ECB : {
4079 rhaas 2447 GIC 57 : PQclear(res);
2448 57 : break;
4079 rhaas 2449 ECB : }
4079 rhaas 2450 CBC 48 : PQclear(res);
4079 rhaas 2451 ECB : }
8462 JanWieck 2452 :
2453 : /* Terminate any statements that didn't make the row count. */
1494 alvherre 2454 CBC 57 : if (rows_this_statement > 0)
2455 : {
2456 1 : if (dopt->do_nothing)
1494 alvherre 2457 UIC 0 : archputs(" ON CONFLICT DO NOTHING;\n", fout);
1494 alvherre 2458 ECB : else
1494 alvherre 2459 CBC 1 : archputs(";\n", fout);
1494 alvherre 2460 ECB : }
2461 :
3432 tgl 2462 CBC 57 : archputs("\n\n", fout);
7064 tgl 2463 ECB :
4079 rhaas 2464 GIC 57 : ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
9345 bruce 2465 ECB :
7639 tgl 2466 GIC 57 : destroyPQExpBuffer(q);
3432 tgl 2467 CBC 57 : if (insertStmt != NULL)
2468 57 : destroyPQExpBuffer(insertStmt);
503 tgl 2469 GIC 57 : free(attgenerated);
2470 :
7639 2471 57 : return 1;
7639 tgl 2472 ECB : }
2473 :
2064 rhaas 2474 : /*
2475 : * getRootTableInfo:
2476 : * get the root TableInfo for the given partition table.
2477 : */
2478 : static TableInfo *
788 peter 2479 GIC 9 : getRootTableInfo(const TableInfo *tbinfo)
2480 : {
2481 : TableInfo *parentTbinfo;
2482 :
2064 rhaas 2483 9 : Assert(tbinfo->ispartition);
2484 9 : Assert(tbinfo->numParents == 1);
2485 :
2486 9 : parentTbinfo = tbinfo->parents[0];
2487 9 : while (parentTbinfo->ispartition)
2488 : {
2064 rhaas 2489 UIC 0 : Assert(parentTbinfo->numParents == 1);
2490 0 : parentTbinfo = parentTbinfo->parents[0];
2491 : }
2492 :
2064 rhaas 2493 CBC 9 : return parentTbinfo;
2494 : }
8314 bruce 2495 ECB :
23 tgl 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
23 tgl 2504 CBC 865 : forcePartitionRootLoad(const TableInfo *tbinfo)
2505 : {
23 tgl 2506 ECB : TableInfo *parentTbinfo;
2507 :
23 tgl 2508 CBC 865 : Assert(tbinfo->ispartition);
2509 865 : Assert(tbinfo->numParents == 1);
23 tgl 2510 ECB :
23 tgl 2511 GIC 865 : parentTbinfo = tbinfo->parents[0];
23 tgl 2512 CBC 865 : if (parentTbinfo->unsafe_partitions)
2513 9 : return true;
23 tgl 2514 GIC 1072 : while (parentTbinfo->ispartition)
23 tgl 2515 ECB : {
23 tgl 2516 GIC 216 : Assert(parentTbinfo->numParents == 1);
23 tgl 2517 CBC 216 : parentTbinfo = parentTbinfo->parents[0];
2518 216 : if (parentTbinfo->unsafe_partitions)
23 tgl 2519 UIC 0 : return true;
2520 : }
23 tgl 2521 ECB :
23 tgl 2522 CBC 856 : return false;
2523 : }
2524 :
2525 : /*
2526 : * dumpTableData -
7064 tgl 2527 ECB : * dump the contents of a single table
2528 : *
2529 : * Actually, this just makes an ArchiveEntry for the table contents.
7639 2530 : */
2531 : static void
788 peter 2532 CBC 3095 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
7639 tgl 2533 EUB : {
2643 tgl 2534 GIC 3095 : DumpOptions *dopt = fout->dopt;
7064 tgl 2535 CBC 3095 : TableInfo *tbinfo = tdinfo->tdtable;
4442 tgl 2536 GIC 3095 : PQExpBuffer copyBuf = createPQExpBuffer();
3668 andrew 2537 CBC 3095 : PQExpBuffer clistBuf = createPQExpBuffer();
2538 : DataDumperPtr dumpFn;
23 tgl 2539 GIC 3095 : char *tdDefn = NULL;
2540 : char *copyStmt;
2064 rhaas 2541 ECB : const char *copyFrom;
2542 :
914 tgl 2543 : /* We had better have loaded per-column details about this table */
914 tgl 2544 CBC 3095 : Assert(tbinfo->interesting);
2545 :
23 tgl 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 : */
23 tgl 2552 CBC 3095 : if (tbinfo->ispartition &&
23 tgl 2553 GBC 1698 : (dopt->load_via_partition_root ||
23 tgl 2554 GIC 849 : forcePartitionRootLoad(tbinfo)))
23 tgl 2555 CBC 6 : {
2556 : TableInfo *parentTbinfo;
2557 :
2558 6 : parentTbinfo = getRootTableInfo(tbinfo);
23 tgl 2559 GIC 6 : copyFrom = fmtQualifiedDumpable(parentTbinfo);
23 tgl 2560 CBC 6 : printfPQExpBuffer(copyBuf, "-- load via partition root %s",
2561 : copyFrom);
2562 6 : tdDefn = pg_strdup(copyBuf->data);
23 tgl 2563 ECB : }
2564 : else
23 tgl 2565 CBC 3089 : copyFrom = fmtQualifiedDumpable(tbinfo);
2566 :
1005 alvherre 2567 3095 : if (dopt->dump_inserts == 0)
2568 : {
2569 : /* Dump/restore using COPY */
7064 tgl 2570 GIC 3038 : dumpFn = dumpTableData_copy;
2571 : /* must use 2 steps here 'cause fmtId is nonreentrant */
23 2572 3038 : printfPQExpBuffer(copyBuf, "COPY %s ",
2573 : copyFrom);
1601 andres 2574 3038 : appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
1601 andres 2575 ECB : fmtCopyColumnList(tbinfo, clistBuf));
7064 tgl 2576 GIC 3038 : copyStmt = copyBuf->data;
2577 : }
2578 : else
7064 tgl 2579 ECB : {
2580 : /* Restore using INSERT */
7064 tgl 2581 GIC 57 : dumpFn = dumpTableData_insert;
7064 tgl 2582 CBC 57 : copyStmt = NULL;
7064 tgl 2583 ECB : }
2584 :
3940 tgl 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.
3940 tgl 2589 ECB : */
2559 sfrost 2590 GIC 3095 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2591 : {
2592 : TocEntry *te;
2593 :
1668 tgl 2594 3095 : te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1528 alvherre 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,
23 tgl 2600 ECB : .createStmt = tdDefn,
2601 : .copyStmt = copyStmt,
2602 : .deps = &(tbinfo->dobj.dumpId),
2603 : .nDeps = 1,
1528 alvherre 2604 : .dumpFn = dumpFn,
2605 : .dumpArg = tdinfo));
2606 :
1668 tgl 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
489 2610 : * dataLength in table pages (including TOAST pages) during dump, so
2611 : * no scaling is needed.
2612 : *
1668 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.
1668 tgl 2615 EUB : * Cast so that we get the right interpretation of table sizes
2616 : * exceeding INT_MAX pages.
2617 : */
1668 tgl 2618 CBC 3095 : te->dataLength = (BlockNumber) tbinfo->relpages;
489 tgl 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 ||
489 tgl 2628 ECB : te->dataLength < 0))
2629 : te->dataLength = INT_MAX;
1668 2630 : }
7064 2631 :
7064 tgl 2632 CBC 3095 : destroyPQExpBuffer(copyBuf);
3668 andrew 2633 3095 : destroyPQExpBuffer(clistBuf);
7064 tgl 2634 GIC 3095 : }
7064 tgl 2635 ECB :
2636 : /*
2637 : * refreshMatViewData -
2638 : * load or refresh the contents of a single materialized view
2639 : *
3689 kgrittn 2640 : * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2641 : * statement.
2642 : */
2643 : static void
788 peter 2644 GIC 328 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
2645 : {
3689 kgrittn 2646 328 : TableInfo *tbinfo = tdinfo->tdtable;
2647 : PQExpBuffer q;
3689 kgrittn 2648 ECB :
3625 tgl 2649 : /* If the materialized view is not flagged as populated, skip this. */
3625 tgl 2650 CBC 328 : if (!tbinfo->relispopulated)
3689 kgrittn 2651 74 : return;
2652 :
3689 kgrittn 2653 GIC 254 : q = createPQExpBuffer();
3689 kgrittn 2654 ECB :
3689 kgrittn 2655 CBC 254 : appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
1868 tgl 2656 254 : fmtQualifiedDumpable(tbinfo));
2657 :
2559 sfrost 2658 254 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2559 sfrost 2659 GIC 254 : ArchiveEntry(fout,
2660 : tdinfo->dobj.catId, /* catalog ID */
2118 tgl 2661 CBC 254 : tdinfo->dobj.dumpId, /* dump ID */
1528 alvherre 2662 GIC 254 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
1528 alvherre 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));
3689 kgrittn 2670 :
3689 kgrittn 2671 GIC 254 : destroyPQExpBuffer(q);
3689 kgrittn 2672 ECB : }
2673 :
2674 : /*
2675 : * getTableData -
2676 : * set up dumpable objects representing the contents of tables
7064 tgl 2677 : */
2678 : static void
1601 andres 2679 GIC 116 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2680 : {
2681 : int i;
2682 :
7639 tgl 2683 30002 : for (i = 0; i < numTables; i++)
2684 : {
2420 peter_e 2685 29886 : if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2420 peter_e 2686 CBC 757 : (!relkind || tblinfo[i].relkind == relkind))
1601 andres 2687 GIC 4389 : makeTableDataInfo(dopt, &(tblinfo[i]));
2688 : }
4443 tgl 2689 116 : }
7423 tgl 2690 ECB :
4443 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
1601 andres 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 : */
4078 tgl 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 */
1110 alvherre 2713 4200 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
1110 alvherre 2714 CBC 41 : (foreign_servers_include_oids.head == NULL ||
1060 tgl 2715 4 : !simple_oid_list_member(&foreign_servers_include_oids,
2716 : tbinfo->foreign_server)))
4078 tgl 2717 GIC 40 : return;
2718 : /* Skip partitioned tables (data in partitions) */
2314 rhaas 2719 4160 : if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2720 390 : return;
2721 :
2722 : /* Don't dump data in unlogged tables, if so requested */
4078 tgl 2723 3770 : if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
3099 alvherre 2724 9 : dopt->no_unlogged_table_data)
4078 tgl 2725 4 : return;
2726 :
2727 : /* Check that the data is not explicitly excluded */
4078 tgl 2728 CBC 3766 : if (simple_oid_list_member(&tabledata_exclude_oids,
4078 tgl 2729 ECB : tbinfo->dobj.catId.oid))
4078 tgl 2730 CBC 5 : return;
2731 :
2732 : /* OK, let's dump it */
4153 bruce 2733 GIC 3761 : tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2734 :
3689 kgrittn 2735 3761 : if (tbinfo->relkind == RELKIND_MATVIEW)
2736 328 : tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2420 peter_e 2737 3433 : else if (tbinfo->relkind == RELKIND_SEQUENCE)
2738 338 : tdinfo->dobj.objType = DO_SEQUENCE_SET;
2739 : else
3689 kgrittn 2740 CBC 3095 : tdinfo->dobj.objType = DO_TABLE_DATA;
2741 :
4443 tgl 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 : */
4443 tgl 2746 CBC 3761 : tdinfo->dobj.catId.tableoid = 0;
2747 3761 : tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
4443 tgl 2748 GIC 3761 : AssignDumpId(&tdinfo->dobj);
4443 tgl 2749 CBC 3761 : tdinfo->dobj.name = tbinfo->dobj.name;
4443 tgl 2750 GIC 3761 : tdinfo->dobj.namespace = tbinfo->dobj.namespace;
4443 tgl 2751 CBC 3761 : tdinfo->tdtable = tbinfo;
4382 bruce 2752 3761 : tdinfo->filtercond = NULL; /* might get set later */
4443 tgl 2753 GIC 3761 : addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
4443 tgl 2754 ECB :
489 2755 : /* A TableDataInfo contains data, of course */
489 tgl 2756 GIC 3761 : tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
489 tgl 2757 ECB :
4443 tgl 2758 CBC 3761 : tbinfo->dataObj = tdinfo;
2759 :
2760 : /* Make sure that we'll collect per-column info for this table. */
914 tgl 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.
3689 kgrittn 2767 ECB : *
2768 : * This must be called after all the objects are created, but before they are
2769 : * sorted.
2770 : */
2771 : static void
3689 kgrittn 2772 GIC 108 : buildMatViewRefreshDependencies(Archive *fout)
2773 : {
2774 : PQExpBuffer query;
3689 kgrittn 2775 ECB : PGresult *res;
2776 : int ntups,
2777 : i;
2778 : int i_classid,
2779 : i_objid,
2780 : i_refobjid;
2781 :
3679 2782 : /* No Mat Views before 9.3. */
3679 kgrittn 2783 CBC 108 : if (fout->remoteVersion < 90300)
3679 kgrittn 2784 UIC 0 : return;
3679 kgrittn 2785 ECB :
3679 kgrittn 2786 GIC 108 : query = createPQExpBuffer();
2787 :
3429 heikki.linnakangas 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)
2222 tgl 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 "
3260 bruce 2802 : "UNION "
2803 : "SELECT w.objid, d3.refobjid, c3.relkind "
2804 : "FROM w "
2805 : "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2118 tgl 2806 : "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
3260 bruce 2807 : "AND d3.objid = r3.oid "
2808 : "AND d3.refobjid <> w.refobjid "
2809 : "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2118 tgl 2810 : "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2222 2811 : CppAsString2(RELKIND_VIEW) ") "
2812 : ") "
2118 2813 : "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2814 : "FROM w "
2222 2815 : "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
3689 kgrittn 2816 :
3689 kgrittn 2817 GIC 108 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2818 :
3689 kgrittn 2819 CBC 108 : ntups = PQntuples(res);
3689 kgrittn 2820 ECB :
3689 kgrittn 2821 CBC 108 : i_classid = PQfnumber(res, "classid");
3689 kgrittn 2822 GIC 108 : i_objid = PQfnumber(res, "objid");
2823 108 : i_refobjid = PQfnumber(res, "refobjid");
3689 kgrittn 2824 ECB :
3689 kgrittn 2825 GIC 378 : for (i = 0; i < ntups; i++)
3689 kgrittn 2826 ECB : {
2827 : CatalogId objId;
2828 : CatalogId refobjId;
3668 andrew 2829 : DumpableObject *dobj;
2830 : DumpableObject *refdobj;
2831 : TableInfo *tbinfo;
2832 : TableInfo *reftbinfo;
3689 kgrittn 2833 :
3689 kgrittn 2834 CBC 270 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
3689 kgrittn 2835 GIC 270 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
3689 kgrittn 2836 CBC 270 : refobjId.tableoid = objId.tableoid;
3689 kgrittn 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;
3689 kgrittn 2842 ECB :
3689 kgrittn 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 :
3689 kgrittn 2851 GIC 234 : refdobj = findObjectByCatalogId(refobjId);
3689 kgrittn 2852 CBC 234 : if (refdobj == NULL)
3689 kgrittn 2853 UIC 0 : continue;
3689 kgrittn 2854 ECB :
3689 kgrittn 2855 GIC 234 : Assert(refdobj->objType == DO_TABLE);
2856 234 : reftbinfo = (TableInfo *) refdobj;
3689 kgrittn 2857 CBC 234 : Assert(reftbinfo->relkind == RELKIND_MATVIEW);
3689 kgrittn 2858 GIC 234 : refdobj = (DumpableObject *) reftbinfo->dataObj;
2859 234 : if (refdobj == NULL)
3689 kgrittn 2860 UIC 0 : continue;
3689 kgrittn 2861 GIC 234 : Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2862 :
2863 234 : addObjectDependency(dobj, refdobj->dumpId);
2864 :
3625 tgl 2865 234 : if (!reftbinfo->relispopulated)
2866 37 : tbinfo->relispopulated = false;
2867 : }
3689 kgrittn 2868 ECB :
3689 kgrittn 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
5326 tgl 2879 ECB : * we handle foreign key issues by not creating the FK constraints until
5326 tgl 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
5326 tgl 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
5326 tgl 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)
5326 tgl 2909 UIC 0 : continue;
2910 :
2911 : /*
2912 : * Okay, make referencing table's TABLE_DATA object depend on the
5050 bruce 2913 ECB : * referenced table's TABLE_DATA object.
2914 : */
5326 tgl 2915 CBC 3 : addObjectDependency(&cinfo->contable->dataObj->dobj,
5326 tgl 2916 GIC 3 : ftable->dataObj->dobj.dumpId);
5326 tgl 2917 ECB : }
2918 : }
5326 tgl 2919 CBC 6 : free(dobjs);
5326 tgl 2920 GIC 6 : }
5326 tgl 2921 ECB :
2922 :
2923 : /*
2924 : * dumpDatabase:
2925 : * dump the database definition
2926 : */
2927 : static void
2643 tgl 2928 GIC 50 : dumpDatabase(Archive *fout)
2929 : {
2643 tgl 2930 CBC 50 : DumpOptions *dopt = fout->dopt;
8053 bruce 2931 50 : PQExpBuffer dbQry = createPQExpBuffer();
2932 50 : PQExpBuffer delQry = createPQExpBuffer();
2933 50 : PQExpBuffer creaQry = createPQExpBuffer();
1903 tgl 2934 GIC 50 : PQExpBuffer labelq = createPQExpBuffer();
4070 rhaas 2935 CBC 50 : PGconn *conn = GetConnection(fout);
8053 bruce 2936 ECB : PGresult *res;
7064 tgl 2937 : int i_tableoid,
2938 : i_oid,
1825 peter_e 2939 : i_datname,
464 tgl 2940 : i_datdba,
7727 2941 : i_encoding,
388 peter 2942 : i_datlocprovider,
5311 heikki.linnakangas 2943 : i_collate,
2944 : i_ctype,
388 peter 2945 : i_daticulocale,
2946 : i_daticurules,
2947 : i_frozenxid,
3203 bruce 2948 : i_minmxid,
1903 tgl 2949 : i_datacl,
489 tgl 2950 EUB : i_acldefault,
2951 : i_datistemplate,
1903 tgl 2952 ECB : i_datconnlimit,
419 peter 2953 : i_datcollversion,
6869 tgl 2954 : i_tablespace;
7064 2955 : CatalogId dbCatId;
2956 : DumpId dbDumpId;
489 tgl 2957 EUB : DumpableAcl dbdacl;
7727 tgl 2958 ECB : const char *datname,
2959 : *dba,
2960 : *encoding,
2961 : *datlocprovider,
5311 heikki.linnakangas 2962 : *collate,
2963 : *ctype,
2964 : *iculocale,
2965 : *icurules,
2966 : *datistemplate,
1903 tgl 2967 : *datconnlimit,
2968 : *tablespace;
3096 2969 : uint32 frozenxid,
2970 : minmxid;
2971 : char *qdatname;
2972 :
1469 peter 2973 GIC 50 : pg_log_info("saving database definition");
2974 :
2975 : /*
2976 : * Fetch the database-level properties for this database.
2977 : */
215 drowley 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, ");
489 tgl 2984 GIC 50 : if (fout->remoteVersion >= 90300)
215 drowley 2985 GNC 50 : appendPQExpBufferStr(dbQry, "datminmxid, ");
2986 : else
215 drowley 2987 UNC 0 : appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
419 peter 2988 GIC 50 : if (fout->remoteVersion >= 150000)
215 drowley 2989 GNC 50 : appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale, datcollversion, ");
2990 : else
215 drowley 2991 UNC 0 : appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS daticulocale, NULL AS datcollversion, ");
32 peter 2992 GNC 50 : if (fout->remoteVersion >= 160000)
2993 50 : appendPQExpBufferStr(dbQry, "daticurules, ");
2994 : else
32 peter 2995 UNC 0 : appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
215 drowley 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()");
7064 tgl 3001 ECB :
4070 rhaas 3002 GIC 50 : res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
3003 :
7064 tgl 3004 50 : i_tableoid = PQfnumber(res, "tableoid");
7064 tgl 3005 CBC 50 : i_oid = PQfnumber(res, "oid");
1825 peter_e 3006 50 : i_datname = PQfnumber(res, "datname");
464 tgl 3007 50 : i_datdba = PQfnumber(res, "datdba");
7727 3008 50 : i_encoding = PQfnumber(res, "encoding");
388 peter 3009 50 : i_datlocprovider = PQfnumber(res, "datlocprovider");
5310 heikki.linnakangas 3010 50 : i_collate = PQfnumber(res, "datcollate");
5310 heikki.linnakangas 3011 GBC 50 : i_ctype = PQfnumber(res, "datctype");
388 peter 3012 GIC 50 : i_daticulocale = PQfnumber(res, "daticulocale");
32 peter 3013 GNC 50 : i_daticurules = PQfnumber(res, "daticurules");
5163 bruce 3014 GIC 50 : i_frozenxid = PQfnumber(res, "datfrozenxid");
3203 3015 50 : i_minmxid = PQfnumber(res, "datminmxid");
1903 tgl 3016 50 : i_datacl = PQfnumber(res, "datacl");
489 3017 50 : i_acldefault = PQfnumber(res, "acldefault");
1903 tgl 3018 CBC 50 : i_datistemplate = PQfnumber(res, "datistemplate");
3019 50 : i_datconnlimit = PQfnumber(res, "datconnlimit");
419 peter 3020 GIC 50 : i_datcollversion = PQfnumber(res, "datcollversion");
6869 tgl 3021 50 : i_tablespace = PQfnumber(res, "tablespace");
7064 tgl 3022 ECB :
7064 tgl 3023 CBC 50 : dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
7064 tgl 3024 GIC 50 : dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
1825 peter_e 3025 50 : datname = PQgetvalue(res, 0, i_datname);
464 tgl 3026 50 : dba = getRoleName(PQgetvalue(res, 0, i_datdba));
7727 3027 50 : encoding = PQgetvalue(res, 0, i_encoding);
388 peter 3028 50 : datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
5311 heikki.linnakangas 3029 50 : collate = PQgetvalue(res, 0, i_collate);
3030 50 : ctype = PQgetvalue(res, 0, i_ctype);
388 peter 3031 CBC 50 : if (!PQgetisnull(res, 0, i_daticulocale))
388 peter 3032 GIC 50 : iculocale = PQgetvalue(res, 0, i_daticulocale);
388 peter 3033 ECB : else
388 peter 3034 LBC 0 : iculocale = NULL;
32 peter 3035 GNC 50 : if (!PQgetisnull(res, 0, i_daticurules))
32 peter 3036 UNC 0 : icurules = PQgetvalue(res, 0, i_daticurules);
3037 : else
32 peter 3038 GNC 50 : icurules = NULL;
5163 bruce 3039 CBC 50 : frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
3203 3040 50 : minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
489 tgl 3041 50 : dbdacl.acl = PQgetvalue(res, 0, i_datacl);
3042 50 : dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
1903 tgl 3043 GIC 50 : datistemplate = PQgetvalue(res, 0, i_datistemplate);
3044 50 : datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
6869 3045 50 : tablespace = PQgetvalue(res, 0, i_tablespace);
3046 :
1825 peter_e 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 : */
440 rhaas 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 : }
7414 tgl 3066 50 : if (strlen(encoding) > 0)
3067 : {
3429 heikki.linnakangas 3068 50 : appendPQExpBufferStr(creaQry, " ENCODING = ");
4080 rhaas 3069 50 : appendStringLiteralAH(creaQry, encoding, fout);
3070 : }
3071 :
388 peter 3072 50 : appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
3073 50 : if (datlocprovider[0] == 'c')
388 peter 3074 UIC 0 : appendPQExpBufferStr(creaQry, "libc");
388 peter 3075 GIC 50 : else if (datlocprovider[0] == 'i')
3076 50 : appendPQExpBufferStr(creaQry, "icu");
3077 : else
366 tgl 3078 UIC 0 : pg_fatal("unrecognized locale provider: %s",
3079 : datlocprovider);
388 peter 3080 ECB :
1356 peter 3081 GIC 50 : if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
3082 : {
3083 50 : appendPQExpBufferStr(creaQry, " LOCALE = ");
4080 rhaas 3084 50 : appendStringLiteralAH(creaQry, collate, fout);
5311 heikki.linnakangas 3085 ECB : }
3086 : else
3087 : {
1356 peter 3088 UIC 0 : if (strlen(collate) > 0)
3089 : {
3090 0 : appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
1356 peter 3091 LBC 0 : appendStringLiteralAH(creaQry, collate, fout);
1356 peter 3092 ECB : }
1356 peter 3093 UIC 0 : if (strlen(ctype) > 0)
1356 peter 3094 EUB : {
1356 peter 3095 LBC 0 : appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
3096 0 : appendStringLiteralAH(creaQry, ctype, fout);
3097 : }
5311 heikki.linnakangas 3098 EUB : }
388 peter 3099 CBC 50 : if (iculocale)
388 peter 3100 ECB : {
388 peter 3101 GIC 50 : appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
388 peter 3102 GBC 50 : appendStringLiteralAH(creaQry, iculocale, fout);
388 peter 3103 ECB : }
32 peter 3104 GNC 50 : if (icurules)
3105 : {
32 peter 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 : */
419 peter 3114 CBC 50 : if (dopt->binary_upgrade)
3115 : {
3116 7 : if (!PQgetisnull(res, 0, i_datcollversion))
419 peter 3117 ECB : {
419 peter 3118 CBC 7 : appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
3119 7 : appendStringLiteralAH(creaQry,
419 peter 3120 ECB : PQgetvalue(res, 0, i_datcollversion),
3121 : fout);
3122 : }
3123 : }
3124 :
1903 tgl 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 : */
2404 tgl 3133 CBC 50 : if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2404 tgl 3134 UIC 0 : !dopt->outputNoTablespaces)
6747 tgl 3135 LBC 0 : appendPQExpBuffer(creaQry, " TABLESPACE = %s",
6747 tgl 3136 ECB : fmtId(tablespace));
3429 heikki.linnakangas 3137 CBC 50 : appendPQExpBufferStr(creaQry, ";\n");
7727 tgl 3138 ECB :
7727 tgl 3139 CBC 50 : appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1903 tgl 3140 ECB : qdatname);
7727 3141 :
7064 tgl 3142 CBC 50 : dbDumpId = createDumpId();
7064 tgl 3143 ECB :
4080 rhaas 3144 CBC 50 : ArchiveEntry(fout,
3145 : dbCatId, /* catalog ID */
7064 tgl 3146 EUB : dbDumpId, /* dump ID */
1528 alvherre 3147 CBC 50 : ARCHIVE_OPTS(.tag = datname,
1528 alvherre 3148 EUB : .owner = dba,
3149 : .description = "DATABASE",
1528 alvherre 3150 ECB : .section = SECTION_PRE_DATA,
3151 : .createStmt = creaQry->data,
3152 : .dropStmt = delQry->data));
8286 pjw 3153 :
1868 tgl 3154 : /* Compute correct tag for archive entry */
1903 tgl 3155 CBC 50 : appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
1903 tgl 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 : */
1903 tgl 3164 GIC 50 : char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
3165 :
1900 3166 50 : if (comment && *comment && !dopt->no_comments)
3167 : {
1903 tgl 3168 CBC 20 : resetPQExpBuffer(dbQry);
3169 :
1903 tgl 3170 ECB : /*
3171 : * Generates warning when loaded into a differently-named
3172 : * database.
3173 : */
1903 tgl 3174 GIC 20 : appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
1903 tgl 3175 CBC 20 : appendStringLiteralAH(dbQry, comment, fout);
1903 tgl 3176 GIC 20 : appendPQExpBufferStr(dbQry, ";\n");
3177 :
1903 tgl 3178 CBC 20 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 3179 GIC 20 : ARCHIVE_OPTS(.tag = labelq->data,
1528 alvherre 3180 ECB : .owner = dba,
3181 : .description = "COMMENT",
3182 : .section = SECTION_NONE,
3183 : .createStmt = dbQry->data,
3184 : .deps = &dbDumpId,
3185 : .nDeps = 1));
1903 tgl 3186 EUB : }
1903 tgl 3187 ECB : }
3188 :
3189 : /* Dump DB security label, if enabled */
481 tgl 3190 GBC 50 : if (!dopt->no_security_labels)
3191 : {
3192 : PGresult *shres;
1903 tgl 3193 ECB : PQExpBuffer seclabelQry;
3194 :
1903 tgl 3195 CBC 50 : seclabelQry = createPQExpBuffer();
1903 tgl 3196 ECB :
957 peter 3197 GIC 50 : buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
1903 tgl 3198 50 : shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
3199 50 : resetPQExpBuffer(seclabelQry);
1903 tgl 3200 GBC 50 : emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
1903 tgl 3201 GIC 50 : if (seclabelQry->len > 0)
1903 tgl 3202 UBC 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 3203 0 : ARCHIVE_OPTS(.tag = labelq->data,
3204 : .owner = dba,
1528 alvherre 3205 EUB : .description = "SECURITY LABEL",
3206 : .section = SECTION_NONE,
3207 : .createStmt = seclabelQry->data,
3208 : .deps = &dbDumpId,
3209 : .nDeps = 1));
1903 tgl 3210 GIC 50 : destroyPQExpBuffer(seclabelQry);
1903 tgl 3211 CBC 50 : PQclear(shres);
3212 : }
1903 tgl 3213 ECB :
3214 : /*
3215 : * Dump ACL if any. Note that we do not support initial privileges
3216 : * (pg_init_privs) on databases.
3217 : */
489 tgl 3218 GBC 50 : dbdacl.privtype = 0;
3219 50 : dbdacl.initprivs = NULL;
3220 :
1002 tgl 3221 GIC 50 : dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
3222 : qdatname, NULL, NULL,
3223 : dba, &dbdacl);
3224 :
3225 : /*
1903 tgl 3226 ECB : * Now construct a DATABASE PROPERTIES archive entry to restore any
3227 : * non-default database-level properties. (The reason this must be
1902 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 : */
1903 tgl 3233 GIC 50 : resetPQExpBuffer(creaQry);
3234 50 : resetPQExpBuffer(delQry);
3235 :
3236 50 : if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
1903 tgl 3237 UIC 0 : appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
3238 : qdatname, datconnlimit);
3239 :
1903 tgl 3240 GIC 50 : if (strcmp(datistemplate, "t") == 0)
3241 : {
3242 1 : appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
3243 : qdatname);
3244 :
1903 tgl 3245 ECB : /*
1903 tgl 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
1903 tgl 3249 ECB : * since no such command is currently supported, fake it with a direct
3250 : * UPDATE on pg_database.
3251 : */
1903 tgl 3252 GIC 1 : appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
3253 : "SET datistemplate = false WHERE datname = ");
1903 tgl 3254 CBC 1 : appendStringLiteralAH(delQry, datname, fout);
1903 tgl 3255 GIC 1 : appendPQExpBufferStr(delQry, ";\n");
1903 tgl 3256 ECB : }
3257 :
3258 : /* Add database-specific SET options */
1903 tgl 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 : */
1903 tgl 3265 GIC 50 : if (dopt->binary_upgrade)
3266 : {
1903 tgl 3267 CBC 7 : appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
1903 tgl 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 :
1903 tgl 3276 CBC 50 : if (creaQry->len > 0)
1903 tgl 3277 GIC 11 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 3278 CBC 11 : ARCHIVE_OPTS(.tag = datname,
3279 : .owner = dba,
1528 alvherre 3280 ECB : .description = "DATABASE PROPERTIES",
3281 : .section = SECTION_PRE_DATA,
3282 : .createStmt = creaQry->data,
3283 : .dropStmt = delQry->data,
3284 : .deps = &dbDumpId));
3285 :
5011 bruce 3286 : /*
1595 andres 3287 : * pg_largeobject comes from the old system intact, so set its
275 rhaas 3288 : * relfrozenxids, relminmxids and relfilenode.
3289 : */
3099 alvherre 3290 CBC 50 : if (dopt->binary_upgrade)
5011 bruce 3291 ECB : {
3292 : PGresult *lo_res;
5011 bruce 3293 GIC 7 : PQExpBuffer loFrozenQry = createPQExpBuffer();
3294 7 : PQExpBuffer loOutQry = createPQExpBuffer();
254 rhaas 3295 7 : PQExpBuffer loHorizonQry = createPQExpBuffer();
3296 : int ii_relfrozenxid,
3297 : ii_relfilenode,
3298 : ii_oid,
3299 : ii_relminmxid;
3300 :
3301 : /*
4382 bruce 3302 ECB : * pg_largeobject
3303 : */
3203 bruce 3304 GIC 7 : if (fout->remoteVersion >= 90300)
275 rhaas 3305 7 : appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
3306 : "FROM pg_catalog.pg_class\n"
275 rhaas 3307 ECB : "WHERE oid IN (%u, %u);\n",
3308 : LargeObjectRelationId, LargeObjectLOidPNIndexId);
3203 bruce 3309 : else
275 rhaas 3310 LBC 0 : appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
3203 bruce 3311 ECB : "FROM pg_catalog.pg_class\n"
275 rhaas 3312 : "WHERE oid IN (%u, %u);\n",
3313 : LargeObjectRelationId, LargeObjectLOidPNIndexId);
5011 bruce 3314 EUB :
275 rhaas 3315 GBC 7 : lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
3316 :
232 drowley 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 :
254 rhaas 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");
275 rhaas 3324 GIC 21 : for (int i = 0; i < PQntuples(lo_res); ++i)
3325 : {
3326 : Oid oid;
3327 : RelFileNumber relfilenumber;
3328 :
254 3329 14 : appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
255 rhaas 3330 ECB : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
275 3331 : "WHERE oid = %u;\n",
232 drowley 3332 GIC 14 : atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
232 drowley 3333 CBC 14 : atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
232 drowley 3334 GIC 14 : atooid(PQgetvalue(lo_res, i, ii_oid)));
3335 :
3336 14 : oid = atooid(PQgetvalue(lo_res, i, ii_oid));
193 rhaas 3337 GNC 14 : relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
3338 :
255 rhaas 3339 GIC 14 : if (oid == LargeObjectRelationId)
254 3340 7 : appendPQExpBuffer(loOutQry,
3341 : "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
3342 : relfilenumber);
255 3343 7 : else if (oid == LargeObjectLOidPNIndexId)
254 3344 7 : appendPQExpBuffer(loOutQry,
193 rhaas 3345 ECB : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
3346 : relfilenumber);
3347 : }
255 3348 :
254 rhaas 3349 GBC 7 : appendPQExpBufferStr(loOutQry,
3350 : "TRUNCATE pg_catalog.pg_largeobject;\n");
254 rhaas 3351 GIC 7 : appendPQExpBufferStr(loOutQry, loHorizonQry->data);
5011 bruce 3352 ECB :
4080 rhaas 3353 GIC 7 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 3354 CBC 7 : ARCHIVE_OPTS(.tag = "pg_largeobject",
3355 : .description = "pg_largeobject",
3356 : .section = SECTION_PRE_DATA,
3357 : .createStmt = loOutQry->data));
3358 :
5011 bruce 3359 GIC 7 : PQclear(lo_res);
3360 :
3361 7 : destroyPQExpBuffer(loFrozenQry);
254 rhaas 3362 7 : destroyPQExpBuffer(loHorizonQry);
5011 bruce 3363 7 : destroyPQExpBuffer(loOutQry);
5011 bruce 3364 ECB : }
3365 :
3003 andres 3366 CBC 50 : PQclear(res);
3003 andres 3367 ECB :
1903 tgl 3368 GIC 50 : free(qdatname);
7919 3369 50 : destroyPQExpBuffer(dbQry);
3370 50 : destroyPQExpBuffer(delQry);
7919 tgl 3371 CBC 50 : destroyPQExpBuffer(creaQry);
1903 tgl 3372 GIC 50 : destroyPQExpBuffer(labelq);
8286 pjw 3373 50 : }
3374 :
3375 : /*
3376 : * Collect any database-specific or role-and-database-specific SET options
1903 tgl 3377 ECB : * for this database, and append them to outbuf.
3378 : */
3379 : static void
1903 tgl 3380 CBC 50 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
3381 : const char *dbname, Oid dboid)
3382 : {
1903 tgl 3383 GIC 50 : PGconn *conn = GetConnection(AH);
1903 tgl 3384 CBC 50 : PQExpBuffer buf = createPQExpBuffer();
1903 tgl 3385 ECB : PGresult *res;
3386 :
3387 : /* First collect database-specific options */
121 akorotkov 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 "
481 tgl 3392 ECB : "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3393 : dboid);
3394 :
481 tgl 3395 GIC 50 : res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3396 :
3397 80 : for (int i = 0; i < PQntuples(res); i++)
3398 : {
121 akorotkov 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 :
481 tgl 3408 GIC 50 : PQclear(res);
3409 :
3410 : /* Now look for role-and-database-specific options */
121 akorotkov 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",
481 tgl 3416 ECB : dboid);
1903 3417 :
481 tgl 3418 CBC 50 : res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3419 :
481 tgl 3420 GIC 50 : for (int i = 0; i < PQntuples(res); i++)
3421 : {
121 akorotkov 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,
481 tgl 3427 UIC 0 : "ROLE", PQgetvalue(res, i, 0),
3428 : "DATABASE", dbname,
3429 : outbuf);
3430 : }
3431 :
481 tgl 3432 GIC 50 : PQclear(res);
1903 tgl 3433 ECB :
1903 tgl 3434 CBC 50 : destroyPQExpBuffer(buf);
1903 tgl 3435 GIC 50 : }
3436 :
3437 : /*
3438 : * dumpEncoding: put the correct encoding into the archive
6984 tgl 3439 EUB : */
3440 : static void
6984 tgl 3441 GIC 118 : dumpEncoding(Archive *AH)
3442 : {
6160 3443 118 : const char *encname = pg_encoding_to_char(AH->encoding);
6160 tgl 3444 CBC 118 : PQExpBuffer qry = createPQExpBuffer();
3445 :
1469 peter 3446 118 : pg_log_info("saving encoding = %s", encname);
6984 tgl 3447 ECB :
3429 heikki.linnakangas 3448 CBC 118 : appendPQExpBufferStr(qry, "SET client_encoding = ");
6160 tgl 3449 118 : appendStringLiteralAH(qry, encname, AH);
3429 heikki.linnakangas 3450 GIC 118 : appendPQExpBufferStr(qry, ";\n");
6984 tgl 3451 ECB :
6984 tgl 3452 CBC 118 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
1528 alvherre 3453 118 : ARCHIVE_OPTS(.tag = "ENCODING",
3454 : .description = "ENCODING",
3455 : .section = SECTION_PRE_DATA,
3456 : .createStmt = qry->data));
3457 :
6984 tgl 3458 118 : destroyPQExpBuffer(qry);
6984 tgl 3459 GIC 118 : }
3460 :
6984 tgl 3461 ECB :
6162 bruce 3462 : /*
3463 : * dumpStdStrings: put the correct escape string behavior into the archive
3464 : */
3465 : static void
6162 bruce 3466 CBC 118 : dumpStdStrings(Archive *AH)
3467 : {
6160 tgl 3468 118 : const char *stdstrings = AH->std_strings ? "on" : "off";
3469 118 : PQExpBuffer qry = createPQExpBuffer();
3470 :
1469 peter 3471 GIC 118 : pg_log_info("saving standard_conforming_strings = %s",
1469 peter 3472 ECB : stdstrings);
6162 bruce 3473 :
6160 tgl 3474 GIC 118 : appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3475 : stdstrings);
3476 :
6162 bruce 3477 118 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
1528 alvherre 3478 CBC 118 : ARCHIVE_OPTS(.tag = "STDSTRINGS",
3479 : .description = "STDSTRINGS",
1528 alvherre 3480 ECB : .section = SECTION_PRE_DATA,
3481 : .createStmt = qry->data));
6162 bruce 3482 :
6162 bruce 3483 CBC 118 : destroyPQExpBuffer(qry);
6162 bruce 3484 GIC 118 : }
3485 :
3486 : /*
3487 : * dumpSearchPath: record the active search_path in the archive
1868 tgl 3488 ECB : */
3489 : static void
1868 tgl 3490 CBC 118 : dumpSearchPath(Archive *AH)
1868 tgl 3491 ECB : {
1868 tgl 3492 CBC 118 : PQExpBuffer qry = createPQExpBuffer();
1868 tgl 3493 GIC 118 : PQExpBuffer path = createPQExpBuffer();
3494 : PGresult *res;
1868 tgl 3495 CBC 118 : char **schemanames = NULL;
1868 tgl 3496 GIC 118 : int nschemanames = 0;
1868 tgl 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 : */
1868 tgl 3506 GIC 118 : res = ExecuteSqlQueryForSingleRow(AH,
3507 : "SELECT pg_catalog.current_schemas(false)");
3508 :
1868 tgl 3509 CBC 118 : if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
366 tgl 3510 UIC 0 : pg_fatal("could not parse result of current_schemas()");
3511 :
1868 tgl 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 : */
1868 tgl 3518 CBC 118 : for (i = 0; i < nschemanames; i++)
1868 tgl 3519 ECB : {
1868 tgl 3520 LBC 0 : if (i > 0)
1868 tgl 3521 UIC 0 : appendPQExpBufferStr(path, ", ");
3522 0 : appendPQExpBufferStr(path, fmtId(schemanames[i]));
3523 : }
1868 tgl 3524 ECB :
1868 tgl 3525 GIC 118 : appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
1868 tgl 3526 CBC 118 : appendStringLiteralAH(qry, path->data, AH);
1868 tgl 3527 GIC 118 : appendPQExpBufferStr(qry, ", false);\n");
1868 tgl 3528 ECB :
1469 peter 3529 GIC 118 : pg_log_info("saving search_path = %s", path->data);
1868 tgl 3530 ECB :
1868 tgl 3531 CBC 118 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
1528 alvherre 3532 118 : ARCHIVE_OPTS(.tag = "SEARCHPATH",
3533 : .description = "SEARCHPATH",
3534 : .section = SECTION_PRE_DATA,
3535 : .createStmt = qry->data));
3536 :
1868 tgl 3537 ECB : /* Also save it in AH->searchpath, in case we're doing plain text dump */
1868 tgl 3538 GIC 118 : AH->searchpath = pg_strdup(qry->data);
3539 :
297 peter 3540 GNC 118 : free(schemanames);
1868 tgl 3541 CBC 118 : PQclear(res);
3542 118 : destroyPQExpBuffer(qry);
1868 tgl 3543 GIC 118 : destroyPQExpBuffer(path);
3544 118 : }
3545 :
6162 bruce 3546 ECB :
3547 : /*
3548 : * getLOs:
3549 : * Collect schema-level data about large objects
6492 tgl 3550 EUB : */
3551 : static void
125 peter 3552 GNC 104 : getLOs(Archive *fout)
6492 tgl 3553 EUB : {
2559 sfrost 3554 GBC 104 : DumpOptions *dopt = fout->dopt;
125 peter 3555 GNC 104 : PQExpBuffer loQry = createPQExpBuffer();
3556 : LoInfo *loinfo;
3557 : DumpableObject *lodata;
3558 : PGresult *res;
3559 : int ntups;
4798 tgl 3560 ECB : int i;
3561 : int i_oid;
2559 sfrost 3562 : int i_lomowner;
3563 : int i_lomacl;
3564 : int i_acldefault;
3565 :
1469 peter 3566 GIC 104 : pg_log_info("reading large objects");
3567 :
3568 : /* Fetch LO OIDs, and owner/ACL data */
125 peter 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 :
2559 sfrost 3576 CBC 104 : i_oid = PQfnumber(res, "oid");
464 tgl 3577 104 : i_lomowner = PQfnumber(res, "lomowner");
2559 sfrost 3578 104 : i_lomacl = PQfnumber(res, "lomacl");
489 tgl 3579 GIC 104 : i_acldefault = PQfnumber(res, "acldefault");
2559 sfrost 3580 ECB :
4798 tgl 3581 CBC 104 : ntups = PQntuples(res);
3582 :
3583 : /*
3584 : * Each large object has its own "BLOB" archive entry.
3585 : */
125 peter 3586 GNC 104 : loinfo = (LoInfo *) pg_malloc(ntups * sizeof(LoInfo));
2559 sfrost 3587 ECB :
2559 sfrost 3588 GIC 193 : for (i = 0; i < ntups; i++)
3589 : {
125 peter 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);
6492 tgl 3594 ECB :
125 peter 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 */
489 tgl 3606 CBC 89 : if (!PQgetisnull(res, i, i_lomacl))
125 peter 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
1595 andres 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 : */
2225 sfrost 3616 GIC 89 : if (dopt->binary_upgrade)
125 peter 3617 GNC 5 : loinfo[i].dobj.dump &= ~DUMP_COMPONENT_DATA;
2559 sfrost 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 : */
2559 sfrost 3624 CBC 104 : if (ntups > 0)
3625 : {
125 peter 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 :
6492 tgl 3634 CBC 104 : PQclear(res);
125 peter 3635 GNC 104 : destroyPQExpBuffer(loQry);
4798 tgl 3636 GIC 104 : }
6492 tgl 3637 ECB :
4798 tgl 3638 EUB : /*
3639 : * dumpLO
3640 : *
3641 : * dump the definition (metadata) of the given large object
3642 : */
3643 : static void
125 peter 3644 GNC 89 : dumpLO(Archive *fout, const LoInfo *loinfo)
3645 : {
4790 bruce 3646 CBC 89 : PQExpBuffer cquery = createPQExpBuffer();
4790 bruce 3647 GIC 89 : PQExpBuffer dquery = createPQExpBuffer();
4798 tgl 3648 EUB :
4798 tgl 3649 GBC 89 : appendPQExpBuffer(cquery,
4798 tgl 3650 EUB : "SELECT pg_catalog.lo_create('%s');\n",
125 peter 3651 GNC 89 : loinfo->dobj.name);
3652 :
4798 tgl 3653 CBC 89 : appendPQExpBuffer(dquery,
4798 tgl 3654 ECB : "SELECT pg_catalog.lo_unlink('%s');\n",
125 peter 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 :
4798 tgl 3666 ECB : /* Dump comment if any */
125 peter 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);
4798 tgl 3671 ECB :
4577 rhaas 3672 : /* Dump security label if any */
125 peter 3673 GNC 89 : if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
125 peter 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 */
125 peter 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);
4798 tgl 3683 ECB :
4798 tgl 3684 GIC 89 : destroyPQExpBuffer(cquery);
3685 89 : destroyPQExpBuffer(dquery);
6492 3686 89 : }
3687 :
3688 : /*
3689 : * dumpLOs:
3690 : * dump the data contents of all large objects
3691 : */
3692 : static int
125 peter 3693 GNC 38 : dumpLOs(Archive *fout, const void *arg)
8297 pjw 3694 ECB : {
3695 : const char *loQry;
3696 : const char *loFetchQry;
4070 rhaas 3697 CBC 38 : PGconn *conn = GetConnection(fout);
3698 : PGresult *res;
3699 : char buf[LOBBUFSIZE];
3700 : int ntups;
3701 : int i;
7360 tgl 3702 ECB : int cnt;
3703 :
1469 peter 3704 CBC 38 : pg_log_info("saving large objects");
8297 pjw 3705 ECB :
4798 tgl 3706 : /*
3707 : * Currently, we re-fetch all LO OIDs using a cursor. Consider scanning
3708 : * the already-in-memory dumpable objects instead...
3709 : */
125 peter 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 :
6492 tgl 3716 ECB : /* Command to fetch from cursor */
125 peter 3717 GNC 38 : loFetchQry = "FETCH 1000 IN looid";
8297 pjw 3718 ECB :
8053 bruce 3719 : do
3720 : {
6501 tgl 3721 : /* Do a fetch */
125 peter 3722 GNC 76 : res = ExecuteSqlQuery(fout, loFetchQry, PGRES_TUPLES_OK);
8297 pjw 3723 ECB :
3724 : /* Process the tuples, if any */
4798 tgl 3725 CBC 76 : ntups = PQntuples(res);
3726 156 : for (i = 0; i < ntups; i++)
8297 pjw 3727 ECB : {
3728 : Oid loOid;
3729 : int loFd;
3730 :
125 peter 3731 GNC 80 : loOid = atooid(PQgetvalue(res, i, 0));
3732 : /* Open the LO */
3733 80 : loFd = lo_open(conn, loOid, INV_READ);
8297 pjw 3734 CBC 80 : if (loFd == -1)
366 tgl 3735 LBC 0 : pg_fatal("could not open large object %u: %s",
3736 : loOid, PQerrorMessage(conn));
3737 :
125 peter 3738 GNC 80 : StartLO(fout, loOid);
3739 :
3740 : /* Now read it in chunks, sending data to archive */
3741 : do
3742 : {
4070 rhaas 3743 GIC 122 : cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
7639 tgl 3744 CBC 122 : if (cnt < 0)
366 tgl 3745 LBC 0 : pg_fatal("error reading large object %u: %s",
3746 : loOid, PQerrorMessage(conn));
3747 :
4080 rhaas 3748 GIC 122 : WriteData(fout, buf, cnt);
7639 tgl 3749 122 : } while (cnt > 0);
3750 :
4070 rhaas 3751 80 : lo_close(conn, loFd);
9345 bruce 3752 ECB :
125 peter 3753 GNC 80 : EndLO(fout, loOid);
7639 tgl 3754 ECB : }
4079 rhaas 3755 :
4079 rhaas 3756 CBC 76 : PQclear(res);
4798 tgl 3757 76 : } while (ntups > 0);
9345 bruce 3758 ECB :
6492 tgl 3759 CBC 38 : return 1;
3760 : }
3761 :
3124 sfrost 3762 ECB : /*
3055 3763 : * getPolicies
586 tgl 3764 : * get information about all RLS policies on dumpable tables.
3765 : */
3766 : void
3055 sfrost 3767 GIC 118 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3768 : {
3769 : PQExpBuffer query;
3770 : PQExpBuffer tbloids;
3771 : PGresult *res;
3055 sfrost 3772 ECB : PolicyInfo *polinfo;
3773 : int i_oid;
3096 tgl 3774 : int i_tableoid;
586 3775 : int i_polrelid;
3776 : int i_polname;
3055 sfrost 3777 : int i_polcmd;
3778 : int i_polpermissive;
3779 : int i_polroles;
3780 : int i_polqual;
3781 : int i_polwithcheck;
3782 : int i,
3096 tgl 3783 : j,
3784 : ntups;
3124 sfrost 3785 :
464 tgl 3786 : /* No policies before 9.5 */
3124 sfrost 3787 CBC 118 : if (fout->remoteVersion < 90500)
3124 sfrost 3788 UIC 0 : return;
3789 :
3119 sfrost 3790 GIC 118 : query = createPQExpBuffer();
464 tgl 3791 118 : tbloids = createPQExpBuffer();
3792 :
3793 : /*
3794 : * Identify tables of interest, and check which ones have RLS enabled.
586 tgl 3795 ECB : */
464 tgl 3796 CBC 118 : appendPQExpBufferChar(tbloids, '{');
3124 sfrost 3797 30474 : for (i = 0; i < numTables; i++)
3124 sfrost 3798 ECB : {
3096 tgl 3799 GIC 30356 : TableInfo *tbinfo = &tblinfo[i];
3800 :
3055 sfrost 3801 ECB : /* Ignore row security on tables not to be dumped */
2559 sfrost 3802 GBC 30356 : if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3124 3803 25064 : continue;
3124 sfrost 3804 EUB :
3805 : /* It can't have RLS or policies if it's not a table */
464 tgl 3806 GIC 5292 : if (tbinfo->relkind != RELKIND_RELATION &&
464 tgl 3807 CBC 1551 : tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
3808 1079 : continue;
464 tgl 3809 ECB :
3810 : /* Add it to the list of table OIDs to be probed below */
464 tgl 3811 GIC 4213 : if (tbloids->len > 1) /* do we have more than the '{'? */
464 tgl 3812 CBC 4138 : appendPQExpBufferChar(tbloids, ',');
3813 4213 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
464 tgl 3814 ECB :
3815 : /* Is RLS enabled? (That's separate from whether it has policies) */
3119 sfrost 3816 GIC 4213 : if (tbinfo->rowsec)
3817 : {
489 tgl 3818 55 : tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
3819 :
3820 : /*
464 tgl 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
3124 sfrost 3825 : * something that pg_depend entries apply to.
3826 : */
3055 sfrost 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);
3055 sfrost 3832 CBC 55 : polinfo->dobj.namespace = tbinfo->dobj.namespace;
3055 sfrost 3833 GIC 55 : polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3834 55 : polinfo->poltable = tbinfo;
3835 55 : polinfo->polname = NULL;
2316 3836 55 : polinfo->polcmd = '\0';
3837 55 : polinfo->polpermissive = 0;
3055 sfrost 3838 CBC 55 : polinfo->polroles = NULL;
3055 sfrost 3839 GIC 55 : polinfo->polqual = NULL;
3840 55 : polinfo->polwithcheck = NULL;
3841 : }
586 tgl 3842 ECB : }
464 tgl 3843 GIC 118 : appendPQExpBufferChar(tbloids, '}');
3844 :
586 tgl 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 : */
586 tgl 3851 GIC 118 : pg_log_info("reading row-level security policies");
3852 :
586 tgl 3853 CBC 118 : printfPQExpBuffer(query,
464 tgl 3854 ECB : "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
586 tgl 3855 GIC 118 : if (fout->remoteVersion >= 100000)
215 drowley 3856 GNC 118 : appendPQExpBufferStr(query, "pol.polpermissive, ");
3857 : else
215 drowley 3858 UNC 0 : appendPQExpBufferStr(query, "'t' as polpermissive, ");
586 tgl 3859 CBC 118 : appendPQExpBuffer(query,
3860 : "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
586 tgl 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, "
586 tgl 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)",
464 tgl 3866 ECB : tbloids->data);
3867 :
586 tgl 3868 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3869 :
3870 118 : ntups = PQntuples(res);
586 tgl 3871 CBC 118 : if (ntups > 0)
586 tgl 3872 ECB : {
3124 sfrost 3873 GBC 45 : i_oid = PQfnumber(res, "oid");
3124 sfrost 3874 GIC 45 : i_tableoid = PQfnumber(res, "tableoid");
586 tgl 3875 45 : i_polrelid = PQfnumber(res, "polrelid");
3055 sfrost 3876 CBC 45 : i_polname = PQfnumber(res, "polname");
3877 45 : i_polcmd = PQfnumber(res, "polcmd");
2316 sfrost 3878 GIC 45 : i_polpermissive = PQfnumber(res, "polpermissive");
3055 sfrost 3879 CBC 45 : i_polroles = PQfnumber(res, "polroles");
3055 sfrost 3880 GIC 45 : i_polqual = PQfnumber(res, "polqual");
3055 sfrost 3881 CBC 45 : i_polwithcheck = PQfnumber(res, "polwithcheck");
3882 :
3055 sfrost 3883 GIC 45 : polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3124 sfrost 3884 ECB :
3124 sfrost 3885 CBC 330 : for (j = 0; j < ntups; j++)
3886 : {
586 tgl 3887 285 : Oid polrelid = atooid(PQgetvalue(res, j, i_polrelid));
586 tgl 3888 GIC 285 : TableInfo *tbinfo = findTableByOid(polrelid);
3889 :
489 3890 285 : tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
3891 :
3055 sfrost 3892 285 : polinfo[j].dobj.objType = DO_POLICY;
3893 285 : polinfo[j].dobj.catId.tableoid =
3124 3894 285 : atooid(PQgetvalue(res, j, i_tableoid));
3055 sfrost 3895 CBC 285 : polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3055 sfrost 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 :
2316 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 :
3055 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 :
3055 sfrost 3915 CBC 285 : if (PQgetisnull(res, j, i_polwithcheck))
3055 sfrost 3916 GBC 150 : polinfo[j].polwithcheck = NULL;
3917 : else
3055 sfrost 3918 CBC 135 : polinfo[j].polwithcheck
3919 135 : = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3920 : }
3921 : }
3922 :
586 tgl 3923 GIC 118 : PQclear(res);
586 tgl 3924 ECB :
3124 sfrost 3925 CBC 118 : destroyPQExpBuffer(query);
464 tgl 3926 GIC 118 : destroyPQExpBuffer(tbloids);
3124 sfrost 3927 ECB : }
3928 :
3929 : /*
3055 3930 : * dumpPolicy
3931 : * dump the definition of the given policy
3932 : */
3933 : static void
788 peter 3934 CBC 340 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
3124 sfrost 3935 ECB : {
2643 tgl 3936 CBC 340 : DumpOptions *dopt = fout->dopt;
3055 sfrost 3937 GIC 340 : TableInfo *tbinfo = polinfo->poltable;
3938 : PQExpBuffer query;
3124 sfrost 3939 ECB : PQExpBuffer delqry;
1147 tgl 3940 : PQExpBuffer polprefix;
3941 : char *qtabname;
3942 : const char *cmd;
3943 : char *tag;
3124 sfrost 3944 :
3945 : /* Do nothing in data-only dump */
3099 alvherre 3946 CBC 340 : if (dopt->dataOnly)
3124 sfrost 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 : */
3055 3954 312 : if (polinfo->polname == NULL)
3124 sfrost 3955 ECB : {
3124 sfrost 3956 CBC 51 : query = createPQExpBuffer();
3124 sfrost 3957 ECB :
3124 sfrost 3958 CBC 51 : appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
1686 tgl 3959 51 : fmtQualifiedDumpable(tbinfo));
3124 sfrost 3960 ECB :
1686 tgl 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 : */
489 tgl 3966 CBC 51 : if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 3967 51 : ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
1528 alvherre 3968 51 : ARCHIVE_OPTS(.tag = polinfo->dobj.name,
3969 : .namespace = polinfo->dobj.namespace->dobj.name,
3970 : .owner = tbinfo->rolname,
1528 alvherre 3971 ECB : .description = "ROW SECURITY",
3972 : .section = SECTION_POST_DATA,
3973 : .createStmt = query->data,
3974 : .deps = &(tbinfo->dobj.dumpId),
3975 : .nDeps = 1));
3976 :
3124 sfrost 3977 GIC 51 : destroyPQExpBuffer(query);
3978 51 : return;
3124 sfrost 3979 ECB : }
3980 :
2316 sfrost 3981 CBC 261 : if (polinfo->polcmd == '*')
2316 sfrost 3982 GIC 87 : cmd = "";
2316 sfrost 3983 CBC 174 : else if (polinfo->polcmd == 'r')
3984 46 : cmd = " FOR SELECT";
2316 sfrost 3985 GIC 128 : else if (polinfo->polcmd == 'a')
2316 sfrost 3986 GBC 36 : cmd = " FOR INSERT";
2316 sfrost 3987 CBC 92 : else if (polinfo->polcmd == 'w')
2316 sfrost 3988 GIC 46 : cmd = " FOR UPDATE";
3989 46 : else if (polinfo->polcmd == 'd')
3990 46 : cmd = " FOR DELETE";
3991 : else
366 tgl 3992 UIC 0 : pg_fatal("unexpected policy command type: %c",
3993 : polinfo->polcmd);
3994 :
3124 sfrost 3995 GIC 261 : query = createPQExpBuffer();
3124 sfrost 3996 CBC 261 : delqry = createPQExpBuffer();
1147 tgl 3997 GIC 261 : polprefix = createPQExpBuffer();
1147 tgl 3998 ECB :
1147 tgl 3999 CBC 261 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
4000 :
2997 4001 261 : appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
2316 sfrost 4002 ECB :
1868 tgl 4003 CBC 261 : appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
2316 sfrost 4004 261 : !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3124 sfrost 4005 ECB :
3055 sfrost 4006 CBC 261 : if (polinfo->polroles != NULL)
4007 144 : appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3124 sfrost 4008 ECB :
3055 sfrost 4009 CBC 261 : if (polinfo->polqual != NULL)
2813 mail 4010 GIC 225 : appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3124 sfrost 4011 ECB :
3055 sfrost 4012 GIC 261 : if (polinfo->polwithcheck != NULL)
2813 mail 4013 CBC 123 : appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
4014 :
1375 drowley 4015 261 : appendPQExpBufferStr(query, ";\n");
3124 sfrost 4016 ECB :
2997 tgl 4017 GIC 261 : appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
1868 tgl 4018 CBC 261 : appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
4019 :
1147 4020 261 : appendPQExpBuffer(polprefix, "POLICY %s ON",
4021 261 : fmtId(polinfo->polname));
1147 tgl 4022 ECB :
2600 peter_e 4023 CBC 261 : tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
2600 peter_e 4024 ECB :
489 tgl 4025 CBC 261 : if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 4026 261 : ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
1528 alvherre 4027 261 : ARCHIVE_OPTS(.tag = tag,
1528 alvherre 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));
3124 sfrost 4034 :
1147 tgl 4035 GIC 261 : if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1147 tgl 4036 LBC 0 : dumpComment(fout, polprefix->data, qtabname,
1147 tgl 4037 UIC 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
1147 tgl 4038 LBC 0 : polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
1147 tgl 4039 ECB :
2600 peter_e 4040 GIC 261 : free(tag);
3124 sfrost 4041 CBC 261 : destroyPQExpBuffer(query);
3124 sfrost 4042 GIC 261 : destroyPQExpBuffer(delqry);
1147 tgl 4043 CBC 261 : destroyPQExpBuffer(polprefix);
4044 261 : free(qtabname);
4045 : }
3124 sfrost 4046 ECB :
2271 peter_e 4047 : /*
4048 : * getPublications
4049 : * get information about publications
4050 : */
815 tgl 4051 : PublicationInfo *
815 tgl 4052 GIC 118 : getPublications(Archive *fout, int *numPublications)
2271 peter_e 4053 ECB : {
2158 peter_e 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;
2271 peter_e 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 :
2158 peter_e 4071 GIC 118 : if (dopt->no_publications || fout->remoteVersion < 100000)
4072 : {
815 tgl 4073 UIC 0 : *numPublications = 0;
815 tgl 4074 LBC 0 : return NULL;
815 tgl 4075 ECB : }
4076 :
2271 peter_e 4077 GIC 118 : query = createPQExpBuffer();
4078 :
4079 118 : resetPQExpBuffer(query);
4080 :
4081 : /* Get the publications. */
367 tomas.vondra 4082 CBC 118 : if (fout->remoteVersion >= 130000)
215 drowley 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");
1096 peter 4088 UIC 0 : else if (fout->remoteVersion >= 110000)
215 drowley 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");
1828 peter_e 4094 ECB : else
215 drowley 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 :
2271 peter_e 4101 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4102 :
4103 118 : ntups = PQntuples(res);
4104 :
2271 peter_e 4105 CBC 118 : i_tableoid = PQfnumber(res, "tableoid");
4106 118 : i_oid = PQfnumber(res, "oid");
2271 peter_e 4107 GIC 118 : i_pubname = PQfnumber(res, "pubname");
464 tgl 4108 118 : i_pubowner = PQfnumber(res, "pubowner");
2271 peter_e 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");
1828 4113 118 : i_pubtruncate = PQfnumber(res, "pubtruncate");
1096 peter 4114 118 : i_pubviaroot = PQfnumber(res, "pubviaroot");
2271 peter_e 4115 ECB :
2271 peter_e 4116 CBC 118 : pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
2271 peter_e 4117 ECB :
2271 peter_e 4118 CBC 298 : for (i = 0; i < ntups; i++)
4119 : {
2271 peter_e 4120 GBC 180 : pubinfo[i].dobj.objType = DO_PUBLICATION;
2271 peter_e 4121 GIC 180 : pubinfo[i].dobj.catId.tableoid =
4122 180 : atooid(PQgetvalue(res, i, i_tableoid));
2271 peter_e 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));
464 tgl 4126 GIC 180 : pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
2271 peter_e 4127 CBC 180 : pubinfo[i].puballtables =
2271 peter_e 4128 GIC 180 : (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
2271 peter_e 4129 CBC 180 : pubinfo[i].pubinsert =
2271 peter_e 4130 GIC 180 : (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
2271 peter_e 4131 CBC 180 : pubinfo[i].pubupdate =
4132 180 : (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
2271 peter_e 4133 GIC 180 : pubinfo[i].pubdelete =
2271 peter_e 4134 CBC 180 : (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
1828 4135 180 : pubinfo[i].pubtruncate =
1828 peter_e 4136 GIC 180 : (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
1096 peter 4137 CBC 180 : pubinfo[i].pubviaroot =
4138 180 : (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
4139 :
2210 peter_e 4140 ECB : /* Decide whether we want to dump it */
2210 peter_e 4141 CBC 180 : selectDumpableObject(&(pubinfo[i].dobj), fout);
4142 : }
2271 4143 118 : PQclear(res);
4144 :
4145 118 : destroyPQExpBuffer(query);
815 tgl 4146 ECB :
815 tgl 4147 GIC 118 : *numPublications = ntups;
815 tgl 4148 CBC 118 : return pubinfo;
2271 peter_e 4149 ECB : }
4150 :
4151 : /*
4152 : * dumpPublication
4153 : * dump the definition of the given publication
4154 : */
4155 : static void
788 peter 4156 GIC 152 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
4157 : {
465 tgl 4158 152 : DumpOptions *dopt = fout->dopt;
4159 : PQExpBuffer delq;
4160 : PQExpBuffer query;
4161 : char *qpubname;
2158 peter_e 4162 152 : bool first = true;
2271 peter_e 4163 ECB :
465 tgl 4164 EUB : /* Do nothing in data-only dump */
465 tgl 4165 GBC 152 : if (dopt->dataOnly)
4166 12 : return;
4167 :
2271 peter_e 4168 CBC 140 : delq = createPQExpBuffer();
4169 140 : query = createPQExpBuffer();
1868 tgl 4170 ECB :
1868 tgl 4171 CBC 140 : qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
2271 peter_e 4172 ECB :
2271 peter_e 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)
2271 peter_e 4180 CBC 35 : appendPQExpBufferStr(query, " FOR ALL TABLES");
4181 :
2158 4182 140 : appendPQExpBufferStr(query, " WITH (publish = '");
2271 peter_e 4183 GIC 140 : if (pubinfo->pubinsert)
4184 : {
2158 4185 105 : appendPQExpBufferStr(query, "insert");
4186 105 : first = false;
4187 : }
4188 :
2271 4189 140 : if (pubinfo->pubupdate)
4190 : {
2155 tgl 4191 105 : if (!first)
4192 105 : appendPQExpBufferStr(query, ", ");
4193 :
2158 peter_e 4194 105 : appendPQExpBufferStr(query, "update");
4195 105 : first = false;
4196 : }
4197 :
2271 4198 140 : if (pubinfo->pubdelete)
2158 peter_e 4199 ECB : {
2155 tgl 4200 GIC 105 : if (!first)
2155 tgl 4201 GBC 105 : appendPQExpBufferStr(query, ", ");
2155 tgl 4202 EUB :
2158 peter_e 4203 GIC 105 : appendPQExpBufferStr(query, "delete");
4204 105 : first = false;
2158 peter_e 4205 ECB : }
4206 :
1828 peter_e 4207 CBC 140 : if (pubinfo->pubtruncate)
4208 : {
1828 peter_e 4209 GIC 105 : if (!first)
1828 peter_e 4210 CBC 105 : appendPQExpBufferStr(query, ", ");
1828 peter_e 4211 ECB :
1828 peter_e 4212 GIC 105 : appendPQExpBufferStr(query, "truncate");
4213 105 : first = false;
4214 : }
4215 :
215 drowley 4216 GNC 140 : appendPQExpBufferChar(query, '\'');
1096 peter 4217 EUB :
1096 peter 4218 GIC 140 : if (pubinfo->pubviaroot)
1096 peter 4219 UIC 0 : appendPQExpBufferStr(query, ", publish_via_partition_root = true");
4220 :
1096 peter 4221 GIC 140 : appendPQExpBufferStr(query, ");\n");
4222 :
489 tgl 4223 GBC 140 : if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
489 tgl 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,
489 tgl 4229 ECB : .createStmt = query->data,
4230 : .dropStmt = delq->data));
2271 peter_e 4231 :
2187 peter_e 4232 GIC 140 : if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 4233 CBC 35 : dumpComment(fout, "PUBLICATION", qpubname,
2187 peter_e 4234 35 : NULL, pubinfo->rolname,
4235 35 : pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
2187 peter_e 4236 ECB :
2187 peter_e 4237 CBC 140 : if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
1868 tgl 4238 LBC 0 : dumpSecLabel(fout, "PUBLICATION", qpubname,
2187 peter_e 4239 0 : NULL, pubinfo->rolname,
4240 0 : pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
2187 peter_e 4241 ECB :
2271 peter_e 4242 CBC 140 : destroyPQExpBuffer(delq);
2271 peter_e 4243 GIC 140 : destroyPQExpBuffer(query);
1868 tgl 4244 CBC 140 : free(qpubname);
4245 : }
2271 peter_e 4246 ECB :
4247 : /*
529 akapila 4248 : * getPublicationNamespaces
4249 : * get information about publication membership for dumpable schemas.
4250 : */
4251 : void
529 akapila 4252 CBC 118 : getPublicationNamespaces(Archive *fout)
529 akapila 4253 ECB : {
4254 : PQExpBuffer query;
4255 : PGresult *res;
4256 : PublicationSchemaInfo *pubsinfo;
529 akapila 4257 CBC 118 : DumpOptions *dopt = fout->dopt;
529 akapila 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 :
529 akapila 4266 CBC 118 : if (dopt->no_publications || fout->remoteVersion < 150000)
529 akapila 4267 UIC 0 : return;
4268 :
529 akapila 4269 CBC 118 : query = createPQExpBuffer();
4270 :
529 akapila 4271 ECB : /* Collect all publication membership info. */
529 akapila 4272 GIC 118 : appendPQExpBufferStr(query,
367 tomas.vondra 4273 ECB : "SELECT tableoid, oid, pnpubid, pnnspid "
4274 : "FROM pg_catalog.pg_publication_namespace");
529 akapila 4275 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
529 akapila 4276 ECB :
529 akapila 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 :
529 akapila 4284 ECB : /* this allocation may be more than we need */
529 akapila 4285 GIC 118 : pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
529 akapila 4286 CBC 118 : j = 0;
4287 :
529 akapila 4288 GIC 208 : for (i = 0; i < ntups; i++)
4289 : {
529 akapila 4290 CBC 90 : Oid pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
529 akapila 4291 GIC 90 : Oid pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
4292 : PublicationInfo *pubinfo;
529 akapila 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 : */
529 akapila 4299 CBC 90 : pubinfo = findPublicationByOid(pnpubid);
529 akapila 4300 GIC 90 : if (pubinfo == NULL)
529 akapila 4301 LBC 0 : continue;
529 akapila 4302 GIC 90 : nspinfo = findNamespaceByOid(pnnspid);
4303 90 : if (nspinfo == NULL)
529 akapila 4304 LBC 0 : continue;
4305 :
4306 : /*
529 akapila 4307 ECB : * We always dump publication namespaces unless the corresponding
4308 : * namespace is excluded from the dump.
4309 : */
529 akapila 4310 CBC 90 : if (nspinfo->dobj.dump == DUMP_COMPONENT_NONE)
4311 13 : continue;
4312 :
529 akapila 4313 ECB : /* OK, make a DumpableObject for this relationship */
516 akapila 4314 CBC 77 : pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
529 akapila 4315 GIC 77 : pubsinfo[j].dobj.catId.tableoid =
4316 77 : atooid(PQgetvalue(res, i, i_tableoid));
529 akapila 4317 CBC 77 : pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
529 akapila 4318 GIC 77 : AssignDumpId(&pubsinfo[j].dobj);
529 akapila 4319 CBC 77 : pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
4320 77 : pubsinfo[j].dobj.name = nspinfo->dobj.name;
529 akapila 4321 GIC 77 : pubsinfo[j].publication = pubinfo;
529 akapila 4322 CBC 77 : pubsinfo[j].pubschema = nspinfo;
529 akapila 4323 ECB :
4324 : /* Decide whether we want to dump it */
529 akapila 4325 GIC 77 : selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
529 akapila 4326 ECB :
529 akapila 4327 GIC 77 : j++;
529 akapila 4328 ECB : }
4329 :
529 akapila 4330 GIC 118 : PQclear(res);
529 akapila 4331 CBC 118 : destroyPQExpBuffer(query);
529 akapila 4332 ECB : }
4333 :
4334 : /*
2271 peter_e 4335 : * getPublicationTables
4336 : * get information about publication membership for dumpable tables.
4337 : */
4338 : void
2271 peter_e 4339 GIC 118 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
2271 peter_e 4340 ECB : {
4341 : PQExpBuffer query;
4342 : PGresult *res;
4343 : PublicationRelInfo *pubrinfo;
1657 michael 4344 CBC 118 : DumpOptions *dopt = fout->dopt;
4345 : int i_tableoid;
2271 peter_e 4346 ECB : int i_oid;
815 tgl 4347 EUB : int i_prpubid;
4348 : int i_prrelid;
411 akapila 4349 ECB : int i_prrelqual;
4350 : int i_prattrs;
2271 peter_e 4351 : int i,
4352 : j,
4353 : ntups;
4354 :
1657 michael 4355 GIC 118 : if (dopt->no_publications || fout->remoteVersion < 100000)
2271 peter_e 4356 UIC 0 : return;
4357 :
2271 peter_e 4358 GIC 118 : query = createPQExpBuffer();
4359 :
815 tgl 4360 ECB : /* Collect all publication membership info. */
411 akapila 4361 CBC 118 : if (fout->remoteVersion >= 150000)
4362 118 : appendPQExpBufferStr(query,
411 akapila 4363 ECB : "SELECT tableoid, oid, prpubid, prrelid, "
4364 : "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
379 tomas.vondra 4365 : "(CASE\n"
379 tomas.vondra 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"
379 tomas.vondra 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
411 akapila 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");
815 tgl 4379 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
815 tgl 4380 ECB :
815 tgl 4381 GIC 118 : ntups = PQntuples(res);
4382 :
4383 118 : i_tableoid = PQfnumber(res, "tableoid");
4384 118 : i_oid = PQfnumber(res, "oid");
815 tgl 4385 CBC 118 : i_prpubid = PQfnumber(res, "prpubid");
815 tgl 4386 GIC 118 : i_prrelid = PQfnumber(res, "prrelid");
411 akapila 4387 118 : i_prrelqual = PQfnumber(res, "prrelqual");
379 tomas.vondra 4388 118 : i_prattrs = PQfnumber(res, "prattrs");
4389 :
4390 : /* this allocation may be more than we need */
815 tgl 4391 118 : pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
4392 118 : j = 0;
4393 :
815 tgl 4394 CBC 433 : for (i = 0; i < ntups; i++)
2271 peter_e 4395 EUB : {
815 tgl 4396 GIC 315 : Oid prpubid = atooid(PQgetvalue(res, i, i_prpubid));
815 tgl 4397 CBC 315 : Oid prrelid = atooid(PQgetvalue(res, i, i_prrelid));
4398 : PublicationInfo *pubinfo;
4399 : TableInfo *tbinfo;
2271 peter_e 4400 ECB :
4401 : /*
4402 : * Ignore any entries for which we aren't interested in either the
815 tgl 4403 : * publication or the rel.
4404 : */
815 tgl 4405 CBC 315 : pubinfo = findPublicationByOid(prpubid);
815 tgl 4406 GIC 315 : if (pubinfo == NULL)
815 tgl 4407 LBC 0 : continue;
815 tgl 4408 CBC 315 : tbinfo = findTableByOid(prrelid);
4409 315 : if (tbinfo == NULL)
2271 peter_e 4410 LBC 0 : continue;
4411 :
4412 : /*
2153 bruce 4413 ECB : * Ignore publication membership of tables whose definitions are not
4414 : * to be dumped.
4415 : */
2271 peter_e 4416 CBC 315 : if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2271 peter_e 4417 GIC 39 : continue;
2271 peter_e 4418 ECB :
815 tgl 4419 : /* OK, make a DumpableObject for this relationship */
815 tgl 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;
815 tgl 4427 CBC 276 : pubrinfo[j].publication = pubinfo;
4428 276 : pubrinfo[j].pubtable = tbinfo;
411 akapila 4429 GBC 276 : if (PQgetisnull(res, i, i_prrelqual))
411 akapila 4430 CBC 158 : pubrinfo[j].pubrelqual = NULL;
411 akapila 4431 ECB : else
411 akapila 4432 GBC 118 : pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
4433 :
379 tomas.vondra 4434 GIC 276 : if (!PQgetisnull(res, i, i_prattrs))
4435 : {
4436 : char **attnames;
4437 : int nattnames;
379 tomas.vondra 4438 ECB : PQExpBuffer attribs;
4439 :
379 tomas.vondra 4440 GIC 78 : if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
4441 : &attnames, &nattnames))
366 tgl 4442 LBC 0 : pg_fatal("could not parse %s array", "prattrs");
379 tomas.vondra 4443 CBC 78 : attribs = createPQExpBuffer();
4444 234 : for (int k = 0; k < nattnames; k++)
379 tomas.vondra 4445 ECB : {
379 tomas.vondra 4446 CBC 156 : if (k > 0)
4447 78 : appendPQExpBufferStr(attribs, ", ");
379 tomas.vondra 4448 ECB :
379 tomas.vondra 4449 CBC 156 : appendPQExpBufferStr(attribs, fmtId(attnames[k]));
379 tomas.vondra 4450 ECB : }
379 tomas.vondra 4451 GIC 78 : pubrinfo[j].pubrattrs = attribs->data;
4452 : }
379 tomas.vondra 4453 ECB : else
379 tomas.vondra 4454 GIC 198 : pubrinfo[j].pubrattrs = NULL;
379 tomas.vondra 4455 ECB :
4456 : /* Decide whether we want to dump it */
529 akapila 4457 GIC 276 : selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
2271 peter_e 4458 ECB :
815 tgl 4459 CBC 276 : j++;
4460 : }
4461 :
815 tgl 4462 GIC 118 : PQclear(res);
2271 peter_e 4463 118 : destroyPQExpBuffer(query);
4464 : }
4465 :
4466 : /*
529 akapila 4467 ECB : * dumpPublicationNamespace
4468 : * dump the definition of the given publication schema mapping.
4469 : */
4470 : static void
529 akapila 4471 GIC 75 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
529 akapila 4472 ECB : {
465 tgl 4473 GIC 75 : DumpOptions *dopt = fout->dopt;
529 akapila 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 */
465 tgl 4480 75 : if (dopt->dataOnly)
529 akapila 4481 6 : return;
4482 :
529 akapila 4483 CBC 69 : tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
529 akapila 4484 EUB :
529 akapila 4485 GIC 69 : query = createPQExpBuffer();
529 akapila 4486 ECB :
529 akapila 4487 GIC 69 : appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
199 alvherre 4488 69 : appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
529 akapila 4489 ECB :
4490 : /*
4491 : * There is no point in creating drop query as the drop is done by schema
4492 : * drop.
4493 : */
465 tgl 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 :
465 tgl 4503 EUB : /* These objects can't currently have comments or seclabels */
4504 :
529 akapila 4505 GIC 69 : free(tag);
4506 69 : destroyPQExpBuffer(query);
529 akapila 4507 ECB : }
4508 :
2271 peter_e 4509 : /*
4510 : * dumpPublicationTable
4511 : * dump the definition of the given publication table mapping
4512 : */
4513 : static void
788 peter 4514 CBC 256 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
2271 peter_e 4515 ECB : {
465 tgl 4516 CBC 256 : DumpOptions *dopt = fout->dopt;
815 tgl 4517 GIC 256 : PublicationInfo *pubinfo = pubrinfo->publication;
2271 peter_e 4518 256 : TableInfo *tbinfo = pubrinfo->pubtable;
2271 peter_e 4519 ECB : PQExpBuffer query;
4520 : char *tag;
4521 :
465 tgl 4522 : /* Do nothing in data-only dump */
465 tgl 4523 GIC 256 : if (dopt->dataOnly)
465 tgl 4524 CBC 21 : return;
465 tgl 4525 ECB :
815 tgl 4526 GIC 235 : tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
4527 :
2271 peter_e 4528 235 : query = createPQExpBuffer();
4529 :
367 tomas.vondra 4530 235 : appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4531 235 : fmtId(pubinfo->dobj.name));
411 akapila 4532 235 : appendPQExpBuffer(query, " %s",
1868 tgl 4533 CBC 235 : fmtQualifiedDumpable(tbinfo));
381 tomas.vondra 4534 ECB :
379 tomas.vondra 4535 GBC 235 : if (pubrinfo->pubrattrs)
379 tomas.vondra 4536 CBC 68 : appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
379 tomas.vondra 4537 ECB :
411 akapila 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.
411 akapila 4544 ECB : */
411 akapila 4545 CBC 101 : appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
4546 : }
411 akapila 4547 GIC 235 : appendPQExpBufferStr(query, ";\n");
2271 peter_e 4548 ECB :
4549 : /*
815 tgl 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.
2271 peter_e 4555 : */
489 tgl 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,
489 tgl 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 :
2271 peter_e 4567 GIC 235 : free(tag);
2271 peter_e 4568 CBC 235 : destroyPQExpBuffer(query);
4569 : }
2271 peter_e 4570 EUB :
2189 peter_e 4571 ECB : /*
4572 : * Is the currently connected user a superuser?
4573 : */
4574 : static bool
2189 peter_e 4575 CBC 118 : is_superuser(Archive *fout)
4576 : {
4577 118 : ArchiveHandle *AH = (ArchiveHandle *) fout;
4578 : const char *val;
2189 peter_e 4579 ECB :
2189 peter_e 4580 GIC 118 : val = PQparameterStatus(AH->connection, "is_superuser");
4581 :
2189 peter_e 4582 CBC 118 : if (val && strcmp(val, "on") == 0)
2189 peter_e 4583 GIC 116 : return true;
4584 :
2189 peter_e 4585 CBC 2 : return false;
4586 : }
2271 peter_e 4587 ECB :
4588 : /*
4589 : * getSubscriptions
4590 : * get information about subscriptions
4591 : */
4592 : void
2271 peter_e 4593 GIC 118 : getSubscriptions(Archive *fout)
4594 : {
2161 4595 118 : DumpOptions *dopt = fout->dopt;
4596 : PQExpBuffer query;
4597 : PGresult *res;
4598 : SubscriptionInfo *subinfo;
2271 peter_e 4599 ECB : int i_tableoid;
4600 : int i_oid;
4601 : int i_subname;
464 tgl 4602 : int i_subowner;
948 akapila 4603 : int i_substream;
4604 : int i_subtwophasestate;
4605 : int i_subdisableonerr;
4606 : int i_suborigin;
4607 : int i_subconninfo;
4608 : int i_subslotname;
2186 peter_e 4609 : int i_subsynccommit;
2271 4610 : int i_subpublications;
4611 : int i_subbinary;
4612 : int i_subpasswordrequired;
4613 : int i,
4614 : ntups;
4615 :
2161 peter_e 4616 GIC 118 : if (dopt->no_subscriptions || fout->remoteVersion < 100000)
2189 peter_e 4617 LBC 0 : return;
2189 peter_e 4618 ECB :
2189 peter_e 4619 GIC 118 : if (!is_superuser(fout))
4620 : {
4621 : int n;
4622 :
4623 2 : res = ExecuteSqlQuery(fout,
2189 peter_e 4624 ECB : "SELECT count(*) FROM pg_subscription "
1985 noah 4625 : "WHERE subdbid = (SELECT oid FROM pg_database"
2118 tgl 4626 : " WHERE datname = current_database())",
4627 : PGRES_TUPLES_OK);
2189 peter_e 4628 GIC 2 : n = atoi(PQgetvalue(res, 0, 0));
4629 2 : if (n > 0)
1469 peter 4630 2 : pg_log_warning("subscriptions not dumped because current user is not a superuser");
2189 peter_e 4631 2 : PQclear(res);
2271 4632 2 : return;
4633 : }
4634 :
2271 peter_e 4635 CBC 116 : query = createPQExpBuffer();
2271 peter_e 4636 ECB :
4637 : /* Get the subscriptions in current database. */
215 drowley 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 :
995 tgl 4644 CBC 116 : if (fout->remoteVersion >= 140000)
906 drowley 4645 GIC 116 : appendPQExpBufferStr(query, " s.subbinary,\n");
995 tgl 4646 ECB : else
906 drowley 4647 LBC 0 : appendPQExpBufferStr(query, " false AS subbinary,\n");
948 akapila 4648 ECB :
948 akapila 4649 GIC 116 : if (fout->remoteVersion >= 140000)
634 4650 116 : appendPQExpBufferStr(query, " s.substream,\n");
4651 : else
90 akapila 4652 UNC 0 : appendPQExpBufferStr(query, " 'f' AS substream,\n");
634 akapila 4653 ECB :
634 akapila 4654 CBC 116 : if (fout->remoteVersion >= 150000)
391 akapila 4655 GIC 116 : appendPQExpBufferStr(query,
391 akapila 4656 ECB : " s.subtwophasestate,\n"
4657 : " s.subdisableonerr,\n");
634 4658 : else
634 akapila 4659 UIC 0 : appendPQExpBuffer(query,
391 akapila 4660 ECB : " '%c' AS subtwophasestate,\n"
4661 : " false AS subdisableonerr,\n",
634 4662 : LOGICALREP_TWOPHASE_STATE_DISABLED);
995 tgl 4663 :
262 akapila 4664 GNC 116 : if (fout->remoteVersion >= 160000)
10 rhaas 4665 116 : appendPQExpBufferStr(query,
4666 : " s.suborigin,\n"
4667 : " s.subpasswordrequired\n");
4668 : else
10 rhaas 4669 UNC 0 : appendPQExpBuffer(query,
4670 : " '%s' AS suborigin,\n"
4671 : " 't' AS subpasswordrequired\n",
4672 : LOGICALREP_ORIGIN_ANY);
4673 :
906 drowley 4674 GIC 116 : appendPQExpBufferStr(query,
906 drowley 4675 ECB : "FROM pg_subscription s\n"
4676 : "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
4677 : " WHERE datname = current_database())");
995 tgl 4678 :
2271 peter_e 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
383 akapila 4685 ECB : * after restoring the dump this value may no longer be relevant.
4686 : */
2271 peter_e 4687 CBC 116 : i_tableoid = PQfnumber(res, "tableoid");
2271 peter_e 4688 GIC 116 : i_oid = PQfnumber(res, "oid");
4689 116 : i_subname = PQfnumber(res, "subname");
464 tgl 4690 116 : i_subowner = PQfnumber(res, "subowner");
2271 peter_e 4691 116 : i_subconninfo = PQfnumber(res, "subconninfo");
4692 116 : i_subslotname = PQfnumber(res, "subslotname");
2186 4693 116 : i_subsynccommit = PQfnumber(res, "subsynccommit");
2271 4694 116 : i_subpublications = PQfnumber(res, "subpublications");
995 tgl 4695 116 : i_subbinary = PQfnumber(res, "subbinary");
948 akapila 4696 CBC 116 : i_substream = PQfnumber(res, "substream");
634 4697 116 : i_subtwophasestate = PQfnumber(res, "subtwophasestate");
391 4698 116 : i_subdisableonerr = PQfnumber(res, "subdisableonerr");
262 akapila 4699 GNC 116 : i_suborigin = PQfnumber(res, "suborigin");
10 rhaas 4700 116 : i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
4701 :
2271 peter_e 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));
2271 peter_e 4709 CBC 129 : subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4710 129 : AssignDumpId(&subinfo[i].dobj);
2271 peter_e 4711 GIC 129 : subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
464 tgl 4712 129 : subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
2271 peter_e 4713 129 : subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
2153 4714 129 : if (PQgetisnull(res, i, i_subslotname))
2153 peter_e 4715 UIC 0 : subinfo[i].subslotname = NULL;
4716 : else
2153 peter_e 4717 CBC 129 : subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
2186 peter_e 4718 GIC 258 : subinfo[i].subsynccommit =
2186 peter_e 4719 CBC 129 : pg_strdup(PQgetvalue(res, i, i_subsynccommit));
2271 peter_e 4720 GIC 258 : subinfo[i].subpublications =
4721 129 : pg_strdup(PQgetvalue(res, i, i_subpublications));
995 tgl 4722 CBC 258 : subinfo[i].subbinary =
995 tgl 4723 GIC 129 : pg_strdup(PQgetvalue(res, i, i_subbinary));
948 akapila 4724 CBC 258 : subinfo[i].substream =
4725 129 : pg_strdup(PQgetvalue(res, i, i_substream));
634 akapila 4726 GIC 258 : subinfo[i].subtwophasestate =
634 akapila 4727 CBC 129 : pg_strdup(PQgetvalue(res, i, i_subtwophasestate));
391 akapila 4728 GIC 258 : subinfo[i].subdisableonerr =
4729 129 : pg_strdup(PQgetvalue(res, i, i_subdisableonerr));
262 akapila 4730 GNC 129 : subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
10 rhaas 4731 258 : subinfo[i].subpasswordrequired =
4732 129 : pg_strdup(PQgetvalue(res, i, i_subpasswordrequired));
4733 :
4734 : /* Decide whether we want to dump it */
2189 peter_e 4735 GIC 129 : selectDumpableObject(&(subinfo[i].dobj), fout);
4736 : }
2271 4737 116 : PQclear(res);
2271 peter_e 4738 ECB :
2271 peter_e 4739 GIC 116 : destroyPQExpBuffer(query);
2271 peter_e 4740 ECB : }
4741 :
4742 : /*
4743 : * dumpSubscription
4744 : * dump the definition of the given subscription
4745 : */
4746 : static void
788 peter 4747 GIC 114 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
4748 : {
465 tgl 4749 114 : DumpOptions *dopt = fout->dopt;
4750 : PQExpBuffer delq;
4751 : PQExpBuffer query;
4752 : PQExpBuffer publications;
4753 : char *qsubname;
2271 peter_e 4754 114 : char **pubnames = NULL;
4755 114 : int npubnames = 0;
4756 : int i;
634 akapila 4757 114 : char two_phase_disabled[] = {LOGICALREP_TWOPHASE_STATE_DISABLED, '\0'};
4758 :
4759 : /* Do nothing in data-only dump */
465 tgl 4760 114 : if (dopt->dataOnly)
465 tgl 4761 CBC 9 : return;
465 tgl 4762 EUB :
2271 peter_e 4763 GIC 105 : delq = createPQExpBuffer();
2271 peter_e 4764 CBC 105 : query = createPQExpBuffer();
4765 :
1868 tgl 4766 GIC 105 : qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4767 :
2271 peter_e 4768 CBC 105 : appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4769 : qsubname);
4770 :
2271 peter_e 4771 GIC 105 : appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4772 : qsubname);
2271 peter_e 4773 CBC 105 : appendStringLiteralAH(query, subinfo->subconninfo, fout);
2271 peter_e 4774 ECB :
4775 : /* Build list of quoted publications and append them to query. */
2271 peter_e 4776 CBC 105 : if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
366 tgl 4777 LBC 0 : pg_fatal("could not parse %s array", "subpublications");
4778 :
2271 peter_e 4779 GIC 105 : publications = createPQExpBuffer();
2271 peter_e 4780 CBC 210 : for (i = 0; i < npubnames; i++)
4781 : {
2271 peter_e 4782 GIC 105 : if (i > 0)
2271 peter_e 4783 LBC 0 : appendPQExpBufferStr(publications, ", ");
4784 :
2271 peter_e 4785 GIC 105 : appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4786 : }
4787 :
2158 4788 105 : appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
2153 peter_e 4789 CBC 105 : if (subinfo->subslotname)
4790 105 : appendStringLiteralAH(query, subinfo->subslotname, fout);
4791 : else
2153 peter_e 4792 UBC 0 : appendPQExpBufferStr(query, "NONE");
4793 :
995 tgl 4794 CBC 105 : if (strcmp(subinfo->subbinary, "t") == 0)
906 drowley 4795 LBC 0 : appendPQExpBufferStr(query, ", binary = true");
4796 :
90 akapila 4797 GNC 105 : if (strcmp(subinfo->substream, "t") == 0)
906 drowley 4798 UIC 0 : appendPQExpBufferStr(query, ", streaming = on");
90 akapila 4799 GNC 105 : else if (strcmp(subinfo->substream, "p") == 0)
90 akapila 4800 UNC 0 : appendPQExpBufferStr(query, ", streaming = parallel");
948 akapila 4801 ECB :
634 akapila 4802 CBC 105 : if (strcmp(subinfo->subtwophasestate, two_phase_disabled) != 0)
634 akapila 4803 UIC 0 : appendPQExpBufferStr(query, ", two_phase = on");
4804 :
391 akapila 4805 GIC 105 : if (strcmp(subinfo->subdisableonerr, "t") == 0)
391 akapila 4806 UBC 0 : appendPQExpBufferStr(query, ", disable_on_error = true");
4807 :
262 akapila 4808 GNC 105 : if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
4809 35 : appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
4810 :
2186 peter_e 4811 GIC 105 : if (strcmp(subinfo->subsynccommit, "off") != 0)
2158 peter_e 4812 UIC 0 : appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4813 :
10 rhaas 4814 GNC 105 : if (strcmp(subinfo->subpasswordrequired, "t") != 0)
10 rhaas 4815 UNC 0 : appendPQExpBuffer(query, ", password_required = false");
4816 :
2271 peter_e 4817 CBC 105 : appendPQExpBufferStr(query, ");\n");
2271 peter_e 4818 ECB :
489 tgl 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,
489 tgl 4822 EUB : .owner = subinfo->rolname,
4823 : .description = "SUBSCRIPTION",
4824 : .section = SECTION_POST_DATA,
4825 : .createStmt = query->data,
4826 : .dropStmt = delq->data));
2271 peter_e 4827 ECB :
2187 peter_e 4828 GIC 105 : if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 4829 35 : dumpComment(fout, "SUBSCRIPTION", qsubname,
2187 peter_e 4830 35 : NULL, subinfo->rolname,
4831 35 : subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
2187 peter_e 4832 ECB :
2187 peter_e 4833 GIC 105 : if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
1868 tgl 4834 LBC 0 : dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
2187 peter_e 4835 UIC 0 : NULL, subinfo->rolname,
4836 0 : subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4837 :
2271 peter_e 4838 GIC 105 : destroyPQExpBuffer(publications);
297 peter 4839 GNC 105 : free(pubnames);
2271 peter_e 4840 ECB :
2271 peter_e 4841 CBC 105 : destroyPQExpBuffer(delq);
4842 105 : destroyPQExpBuffer(query);
1868 tgl 4843 105 : free(qsubname);
2271 peter_e 4844 ECB : }
4845 :
1124 alvherre 4846 : /*
4847 : * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
4848 : * the object needs.
4849 : */
4850 : static void
1124 alvherre 4851 CBC 4296 : append_depends_on_extension(Archive *fout,
1124 alvherre 4852 ECB : PQExpBuffer create,
4853 : const DumpableObject *dobj,
4854 : const char *catalog,
4855 : const char *keyword,
4856 : const char *objname)
4857 : {
1124 alvherre 4858 CBC 4296 : if (dobj->depends_on_ext)
1124 alvherre 4859 ECB : {
1060 tgl 4860 : char *nm;
1124 alvherre 4861 : PGresult *res;
1060 tgl 4862 : PQExpBuffer query;
4863 : int ntups;
4864 : int i_extname;
4865 : int i;
1124 alvherre 4866 :
1124 alvherre 4867 EUB : /* dodge fmtId() non-reentrancy */
1124 alvherre 4868 GIC 38 : nm = pg_strdup(objname);
1124 alvherre 4869 ECB :
1124 alvherre 4870 CBC 38 : query = createPQExpBuffer();
4871 38 : appendPQExpBuffer(query,
1124 alvherre 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,
1124 alvherre 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++)
1124 alvherre 4883 ECB : {
1124 alvherre 4884 CBC 38 : appendPQExpBuffer(create, "ALTER %s %s DEPENDS ON EXTENSION %s;\n",
4885 : keyword, nm,
1124 alvherre 4886 GIC 38 : fmtId(PQgetvalue(res, i, i_extname)));
1124 alvherre 4887 ECB : }
4888 :
1124 alvherre 4889 CBC 38 : PQclear(res);
1119 alvherre 4890 GIC 38 : destroyPQExpBuffer(query);
1124 alvherre 4891 CBC 38 : pg_free(nm);
4892 : }
1124 alvherre 4893 GIC 4296 : }
4894 :
4895 : static Oid
840 akorotkov 4896 UIC 0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
4897 : {
4898 : /*
840 akorotkov 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 : {
840 akorotkov 4912 LBC 0 : ++next_possible_free_oid;
4913 0 : printfPQExpBuffer(upgrade_query,
4914 : "SELECT EXISTS(SELECT 1 "
840 akorotkov 4915 ECB : "FROM pg_catalog.pg_type "
4916 : "WHERE oid = '%u'::pg_catalog.oid);",
4917 : next_possible_free_oid);
840 akorotkov 4918 LBC 0 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
840 akorotkov 4919 UIC 0 : is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
840 akorotkov 4920 LBC 0 : PQclear(res);
840 akorotkov 4921 UIC 0 : } while (is_dup);
4922 :
840 akorotkov 4923 LBC 0 : return next_possible_free_oid;
4924 : }
1124 alvherre 4925 ECB :
4926 : static void
4079 rhaas 4927 GIC 771 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4079 rhaas 4928 ECB : PQExpBuffer upgrade_buffer,
2017 tgl 4929 EUB : Oid pg_type_oid,
4930 : bool force_array_type,
840 akorotkov 4931 ECB : bool include_multirange_type)
4854 bruce 4932 : {
4854 bruce 4933 GIC 771 : PQExpBuffer upgrade_query = createPQExpBuffer();
2017 tgl 4934 ECB : PGresult *res;
4854 bruce 4935 EUB : Oid pg_type_array_oid;
4936 : Oid pg_type_multirange_oid;
840 akorotkov 4937 ECB : Oid pg_type_multirange_array_oid;
4938 :
3429 heikki.linnakangas 4939 GIC 771 : appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4854 bruce 4940 CBC 771 : appendPQExpBuffer(upgrade_buffer,
2878 bruce 4941 ECB : "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4790 4942 : pg_type_oid);
4943 :
4854 bruce 4944 GBC 771 : appendPQExpBuffer(upgrade_query,
4945 : "SELECT typarray "
4854 bruce 4946 ECB : "FROM pg_catalog.pg_type "
2017 tgl 4947 EUB : "WHERE oid = '%u'::pg_catalog.oid;",
4948 : pg_type_oid);
4854 bruce 4949 ECB :
2017 tgl 4950 GBC 771 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2017 tgl 4951 ECB :
2017 tgl 4952 GBC 771 : pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4953 :
2017 tgl 4954 CBC 771 : PQclear(res);
2017 tgl 4955 EUB :
2017 tgl 4956 GIC 771 : if (!OidIsValid(pg_type_array_oid) && force_array_type)
840 akorotkov 4957 LBC 0 : pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
4854 bruce 4958 EUB :
4854 bruce 4959 GIC 771 : if (OidIsValid(pg_type_array_oid))
4854 bruce 4960 ECB : {
3429 heikki.linnakangas 4961 CBC 769 : appendPQExpBufferStr(upgrade_buffer,
4962 : "\n-- For binary upgrade, must preserve pg_type array oid\n");
4854 bruce 4963 769 : appendPQExpBuffer(upgrade_buffer,
2952 peter_e 4964 EUB : "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4965 : pg_type_array_oid);
4854 bruce 4966 ECB : }
4854 bruce 4967 EUB :
4968 : /*
840 akorotkov 4969 ECB : * Pre-set the multirange type oid and its own array type oid.
4970 : */
840 akorotkov 4971 CBC 771 : if (include_multirange_type)
840 akorotkov 4972 ECB : {
840 akorotkov 4973 CBC 6 : if (fout->remoteVersion >= 140000)
4974 : {
441 tgl 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 "
840 akorotkov 4980 ECB : "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
4981 : pg_type_oid);
4982 :
840 akorotkov 4983 CBC 6 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4984 :
4985 6 : pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
840 akorotkov 4986 GBC 6 : pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
840 akorotkov 4987 EUB :
840 akorotkov 4988 GBC 6 : PQclear(res);
4989 : }
840 akorotkov 4990 ECB : else
4991 : {
840 akorotkov 4992 UIC 0 : pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
840 akorotkov 4993 LBC 0 : pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
840 akorotkov 4994 ECB : }
4995 :
840 akorotkov 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");
840 akorotkov 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 :
4854 bruce 5008 GIC 771 : destroyPQExpBuffer(upgrade_query);
5009 771 : }
4854 bruce 5010 ECB :
5011 : static void
489 tgl 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 :
1006 5018 709 : if (OidIsValid(pg_type_oid))
5019 709 : binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
840 akorotkov 5020 ECB : pg_type_oid, false, false);
4854 bruce 5021 GIC 709 : }
4854 bruce 5022 ECB :
5023 : static void
4079 rhaas 5024 GIC 1028 : binary_upgrade_set_pg_class_oids(Archive *fout,
5025 : PQExpBuffer upgrade_buffer, Oid pg_class_oid,
5026 : bool is_index)
5027 : {
447 5028 1028 : PQExpBuffer upgrade_query = createPQExpBuffer();
5029 : PGresult *upgrade_res;
5030 : RelFileNumber relfilenumber;
447 rhaas 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 : */
447 rhaas 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 :
447 rhaas 5057 GIC 1028 : upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5058 :
5059 1028 : relkind = *PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "relkind"));
5060 :
193 rhaas 5061 GNC 1028 : relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
5062 : PQfnumber(upgrade_res, "relfilenode")));
447 rhaas 5063 GIC 1028 : toast_oid = atooid(PQgetvalue(upgrade_res, 0,
447 rhaas 5064 EUB : PQfnumber(upgrade_res, "reltoastrelid")));
193 rhaas 5065 GNC 1028 : toast_relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
5066 : PQfnumber(upgrade_res, "toast_relfilenode")));
447 rhaas 5067 GIC 1028 : toast_index_oid = atooid(PQgetvalue(upgrade_res, 0,
5068 : PQfnumber(upgrade_res, "indexrelid")));
193 rhaas 5069 GNC 1028 : toast_index_relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
5070 : PQfnumber(upgrade_res, "toast_index_relfilenode")));
447 rhaas 5071 EUB :
3429 heikki.linnakangas 5072 GBC 1028 : appendPQExpBufferStr(upgrade_buffer,
447 rhaas 5073 EUB : "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
5074 :
4841 bruce 5075 GBC 1028 : if (!is_index)
5076 : {
4841 bruce 5077 GIC 773 : appendPQExpBuffer(upgrade_buffer,
5078 : "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4475 bruce 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.
1006 tgl 5085 : */
277 rhaas 5086 GNC 773 : if (RelFileNumberIsValid(relfilenumber) && relkind != RELKIND_PARTITIONED_TABLE)
447 rhaas 5087 GIC 628 : appendPQExpBuffer(upgrade_buffer,
5088 : "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
5089 : relfilenumber);
5090 :
1006 tgl 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 : */
447 rhaas 5095 GIC 773 : if (OidIsValid(toast_oid) &&
447 rhaas 5096 ECB : relkind != RELKIND_PARTITIONED_TABLE)
5097 : {
4477 bruce 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);
447 rhaas 5101 251 : appendPQExpBuffer(upgrade_buffer,
193 rhaas 5102 ECB : "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
5103 : toast_relfilenumber);
4382 bruce 5104 :
5105 : /* every toast table has an index */
4477 bruce 5106 CBC 251 : appendPQExpBuffer(upgrade_buffer,
5107 : "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
447 rhaas 5108 ECB : toast_index_oid);
447 rhaas 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 : }
1006 tgl 5113 ECB :
1006 tgl 5114 GIC 773 : PQclear(upgrade_res);
4477 bruce 5115 ECB : }
5116 : else
5117 : {
5118 : /* Preserve the OID and relfilenumber of the index */
4841 bruce 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);
447 rhaas 5122 255 : appendPQExpBuffer(upgrade_buffer,
193 rhaas 5123 ECB : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5124 : relfilenumber);
447 5125 : }
5126 :
3429 heikki.linnakangas 5127 CBC 1028 : appendPQExpBufferChar(upgrade_buffer, '\n');
5128 :
441 tgl 5129 GIC 1028 : destroyPQExpBuffer(upgrade_query);
4854 bruce 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.
1868 tgl 5135 ECB : *
5136 : * For somewhat historical reasons, objname should already be quoted,
5137 : * but not objnamespace (if any).
4442 5138 : */
5139 : static void
4442 tgl 5140 CBC 1233 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
5141 : const DumpableObject *dobj,
5142 : const char *objtype,
5143 : const char *objname,
1868 tgl 5144 EUB : const char *objnamespace)
4442 5145 : {
4442 tgl 5146 GIC 1233 : DumpableObject *extobj = NULL;
5147 : int i;
4442 tgl 5148 ECB :
4442 tgl 5149 GIC 1233 : if (!dobj->ext_member)
4442 tgl 5150 CBC 1217 : return;
5151 :
5152 : /*
4382 bruce 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 : */
4442 tgl 5158 GIC 16 : for (i = 0; i < dobj->nDeps; i++)
5159 : {
4442 tgl 5160 CBC 16 : extobj = findObjectByDumpId(dobj->dependencies[i]);
5161 16 : if (extobj && extobj->objType == DO_EXTENSION)
4442 tgl 5162 GIC 16 : break;
4442 tgl 5163 UIC 0 : extobj = NULL;
4442 tgl 5164 ECB : }
4442 tgl 5165 GIC 16 : if (extobj == NULL)
366 tgl 5166 UIC 0 : pg_fatal("could not find parent extension for %s %s",
5167 : objtype, objname);
4442 tgl 5168 ECB :
3429 heikki.linnakangas 5169 GIC 16 : appendPQExpBufferStr(upgrade_buffer,
2118 tgl 5170 ECB : "\n-- For binary upgrade, handle extension membership the hard way\n");
1868 tgl 5171 CBC 16 : appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4442 tgl 5172 GIC 16 : fmtId(extobj->name),
1868 tgl 5173 ECB : objtype);
1868 tgl 5174 GIC 16 : if (objnamespace && *objnamespace)
5175 13 : appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
1868 tgl 5176 CBC 16 : appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
5177 : }
5178 :
5179 : /*
7639 tgl 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 *
4080 rhaas 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;
9345 bruce 5200 ECB :
7639 tgl 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 : */
215 drowley 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 :
4079 rhaas 5213 CBC 119 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5214 :
9345 bruce 5215 119 : ntups = PQntuples(res);
5216 :
4153 5217 119 : nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
5218 :
7064 tgl 5219 119 : i_tableoid = PQfnumber(res, "tableoid");
9345 bruce 5220 GIC 119 : i_oid = PQfnumber(res, "oid");
7639 tgl 5221 CBC 119 : i_nspname = PQfnumber(res, "nspname");
650 noah 5222 GIC 119 : i_nspowner = PQfnumber(res, "nspowner");
7639 tgl 5223 119 : i_nspacl = PQfnumber(res, "nspacl");
489 tgl 5224 CBC 119 : i_acldefault = PQfnumber(res, "acldefault");
5225 :
9345 bruce 5226 GIC 902 : for (i = 0; i < ntups; i++)
9345 bruce 5227 ECB : {
5228 : const char *nspowner;
464 tgl 5229 :
7064 tgl 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);
4153 bruce 5234 783 : nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
489 tgl 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;
489 tgl 5238 CBC 783 : nsinfo[i].dacl.initprivs = NULL;
464 5239 783 : nspowner = PQgetvalue(res, i, i_nspowner);
464 tgl 5240 GIC 783 : nsinfo[i].nspowner = atooid(nspowner);
5241 783 : nsinfo[i].rolname = getRoleName(nspowner);
5242 :
5243 : /* Decide whether to dump this namespace */
2559 sfrost 5244 783 : selectDumpableNamespace(&nsinfo[i], fout);
5245 :
5246 : /* Mark whether namespace has an ACL */
489 tgl 5247 CBC 783 : if (!PQgetisnull(res, i, i_nspacl))
489 tgl 5248 GIC 403 : nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5249 :
489 tgl 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 : */
489 tgl 5266 CBC 783 : if (strcmp(nsinfo[i].dobj.name, "public") == 0)
5267 : {
489 tgl 5268 GIC 115 : PQExpBuffer aclarray = createPQExpBuffer();
5269 115 : PQExpBuffer aclitem = createPQExpBuffer();
5270 :
489 tgl 5271 ECB : /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
489 tgl 5272 GIC 115 : appendPQExpBufferChar(aclarray, '{');
5273 115 : quoteAclUserName(aclitem, nsinfo[i].rolname);
489 tgl 5274 CBC 115 : appendPQExpBufferStr(aclitem, "=UC/");
489 tgl 5275 GIC 115 : quoteAclUserName(aclitem, nsinfo[i].rolname);
5276 115 : appendPGArray(aclarray, aclitem->data);
5277 115 : resetPQExpBuffer(aclitem);
5278 115 : appendPQExpBufferStr(aclitem, "=U/");
489 tgl 5279 CBC 115 : quoteAclUserName(aclitem, nsinfo[i].rolname);
489 tgl 5280 GIC 115 : appendPGArray(aclarray, aclitem->data);
489 tgl 5281 CBC 115 : appendPQExpBufferChar(aclarray, '}');
489 tgl 5282 ECB :
489 tgl 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 :
9345 bruce 5292 CBC 119 : PQclear(res);
7919 tgl 5293 GIC 119 : destroyPQExpBuffer(query);
5294 :
3971 5295 119 : *numNamespaces = ntups;
5296 :
7639 5297 119 : return nsinfo;
9442 scrappy 5298 ECB : }
5299 :
5300 : /*
7639 tgl 5301 : * findNamespace:
2370 5302 : * given a namespace OID, look up the info read by getNamespaces
5303 : */
5304 : static NamespaceInfo *
957 peter 5305 GIC 446370 : findNamespace(Oid nsoid)
5306 : {
5307 : NamespaceInfo *nsinfo;
5308 :
2370 tgl 5309 446370 : nsinfo = findNamespaceByOid(nsoid);
3971 tgl 5310 CBC 446370 : if (nsinfo == NULL)
366 tgl 5311 UIC 0 : pg_fatal("schema with OID %u does not exist", nsoid);
3971 tgl 5312 CBC 446370 : return nsinfo;
9442 scrappy 5313 ECB : }
9770 5314 :
4443 tgl 5315 EUB : /*
5316 : * getExtensions:
4443 tgl 5317 ECB : * read all extensions in the system catalogs and return them in the
4443 tgl 5318 EUB : * ExtensionInfo* structure
5319 : *
5320 : * numExtensions is set to the number of extensions read in
4443 tgl 5321 ECB : */
5322 : ExtensionInfo *
2643 tgl 5323 CBC 119 : getExtensions(Archive *fout, int *numExtensions)
4443 tgl 5324 ECB : {
2643 tgl 5325 GIC 119 : DumpOptions *dopt = fout->dopt;
4443 tgl 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 :
4443 tgl 5340 GIC 119 : query = createPQExpBuffer();
5341 :
3429 heikki.linnakangas 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 :
4079 rhaas 5347 119 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5348 :
4443 tgl 5349 119 : ntups = PQntuples(res);
5350 :
4153 bruce 5351 119 : extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
5352 :
4443 tgl 5353 CBC 119 : i_tableoid = PQfnumber(res, "tableoid");
4443 tgl 5354 GIC 119 : i_oid = PQfnumber(res, "oid");
5355 119 : i_extname = PQfnumber(res, "extname");
5356 119 : i_nspname = PQfnumber(res, "nspname");
4442 5357 119 : i_extrelocatable = PQfnumber(res, "extrelocatable");
5358 119 : i_extversion = PQfnumber(res, "extversion");
4443 tgl 5359 CBC 119 : i_extconfig = PQfnumber(res, "extconfig");
4443 tgl 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;
4443 tgl 5365 CBC 141 : extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4443 tgl 5366 GIC 141 : extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4443 tgl 5367 CBC 141 : AssignDumpId(&extinfo[i].dobj);
4153 bruce 5368 GIC 141 : extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4153 bruce 5369 CBC 141 : extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4442 tgl 5370 GIC 141 : extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4153 bruce 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));
4419 tgl 5374 ECB :
5375 : /* Decide whether we want to dump it */
2643 tgl 5376 CBC 141 : selectDumpableExtension(&(extinfo[i]), dopt);
5377 : }
4443 tgl 5378 ECB :
4443 tgl 5379 GIC 119 : PQclear(res);
5380 119 : destroyPQExpBuffer(query);
5381 :
4443 tgl 5382 CBC 119 : *numExtensions = ntups;
4443 tgl 5383 ECB :
4443 tgl 5384 CBC 119 : return extinfo;
4443 tgl 5385 ECB : }
5386 :
9770 scrappy 5387 : /*
7639 tgl 5388 : * getTypes:
5389 : * read all types in the system catalogs and return them in the
5390 : * TypeInfo* structure
9770 scrappy 5391 : *
7639 tgl 5392 : * numTypes is set to the number of types read in
7064 5393 : *
5394 : * NB: this must run after getFuncs() because we assume we can do
5395 : * findFuncByOid().
9770 scrappy 5396 : */
5397 : TypeInfo *
4080 rhaas 5398 GIC 118 : getTypes(Archive *fout, int *numTypes)
9770 scrappy 5399 ECB : {
8720 bruce 5400 : PGresult *res;
5401 : int ntups;
5402 : int i;
8397 bruce 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;
5812 tgl 5418 ECB : int i_isarray;
5419 :
7639 5420 : /*
6385 bruce 5421 : * we include even the built-in types because those may be used as array
5422 : * elements by user-defined types
5423 : *
7639 tgl 5424 : * we filter out the built-in types when we dump out the types
7605 5425 : *
5812 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.
5624 bruce 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
3260 5432 : * cost of the subselect probe for all standard types. This would have to
5624 5433 : * be revisited if the backend ever allows renaming of array types.
5434 : */
215 drowley 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 :
4079 rhaas 5447 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5448 :
9345 bruce 5449 118 : ntups = PQntuples(res);
5450 :
4153 bruce 5451 GIC 118 : tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
5452 :
7064 tgl 5453 118 : i_tableoid = PQfnumber(res, "tableoid");
9345 bruce 5454 118 : i_oid = PQfnumber(res, "oid");
7639 tgl 5455 118 : i_typname = PQfnumber(res, "typname");
5456 118 : i_typnamespace = PQfnumber(res, "typnamespace");
3773 tgl 5457 CBC 118 : i_typacl = PQfnumber(res, "typacl");
489 tgl 5458 GIC 118 : i_acldefault = PQfnumber(res, "acldefault");
464 5459 118 : i_typowner = PQfnumber(res, "typowner");
7639 5460 118 : i_typelem = PQfnumber(res, "typelem");
7639 tgl 5461 CBC 118 : i_typrelid = PQfnumber(res, "typrelid");
7542 bruce 5462 118 : i_typrelkind = PQfnumber(res, "typrelkind");
7639 tgl 5463 GBC 118 : i_typtype = PQfnumber(res, "typtype");
7639 tgl 5464 CBC 118 : i_typisdefined = PQfnumber(res, "typisdefined");
5812 tgl 5465 GIC 118 : i_isarray = PQfnumber(res, "isarray");
5466 :
9345 bruce 5467 83984 : for (i = 0; i < ntups; i++)
5468 : {
4855 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);
4153 5473 83866 : tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4080 rhaas 5474 167732 : tyinfo[i].dobj.namespace =
957 peter 5475 CBC 83866 : findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
489 tgl 5476 GIC 83866 : tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
489 tgl 5477 CBC 83866 : tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
489 tgl 5478 GIC 83866 : tyinfo[i].dacl.privtype = 0;
5479 83866 : tyinfo[i].dacl.initprivs = NULL;
586 5480 83866 : tyinfo[i].ftypname = NULL; /* may get filled later */
464 5481 83866 : tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
4855 bruce 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 :
7639 tgl 5488 83866 : if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4855 bruce 5489 83816 : tyinfo[i].isDefined = true;
5490 : else
5491 50 : tyinfo[i].isDefined = false;
7605 tgl 5492 ECB :
5812 tgl 5493 GIC 83866 : if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4855 bruce 5494 CBC 40197 : tyinfo[i].isArray = true;
5495 : else
4855 bruce 5496 GIC 43669 : tyinfo[i].isArray = false;
5497 :
840 akorotkov 5498 83866 : if (tyinfo[i].typtype == 'm')
840 akorotkov 5499 CBC 818 : tyinfo[i].isMultirange = true;
5500 : else
5501 83048 : tyinfo[i].isMultirange = false;
5502 :
6247 tgl 5503 ECB : /* Decide whether we want to dump it */
2559 sfrost 5504 GIC 83866 : selectDumpableType(&tyinfo[i], fout);
2559 sfrost 5505 ECB :
489 tgl 5506 : /* Mark whether type has an ACL */
489 tgl 5507 CBC 83866 : if (!PQgetisnull(res, i, i_typacl))
5508 202 : tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6247 tgl 5509 ECB :
7064 5510 : /*
5511 : * If it's a domain, fetch info about its constraints, if any
5512 : */
4855 bruce 5513 GIC 83866 : tyinfo[i].nDomChecks = 0;
4855 bruce 5514 CBC 83866 : tyinfo[i].domChecks = NULL;
2559 sfrost 5515 GIC 83866 : if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
2559 sfrost 5516 CBC 10888 : tyinfo[i].typtype == TYPTYPE_DOMAIN)
4080 rhaas 5517 124 : getDomainConstraints(fout, &(tyinfo[i]));
7064 tgl 5518 ECB :
5519 : /*
6247 5520 : * If it's a base type, make a DumpableObject representing a shell
3260 bruce 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
4160 tgl 5523 : * definition in case they have a canonicalize function.
6247 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.
7064 5528 : */
2559 sfrost 5529 GIC 83866 : if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
5530 10888 : (tyinfo[i].typtype == TYPTYPE_BASE ||
2559 sfrost 5531 CBC 5344 : tyinfo[i].typtype == TYPTYPE_RANGE))
6247 tgl 5532 ECB : {
4153 bruce 5533 GIC 5642 : stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
6247 tgl 5534 CBC 5642 : stinfo->dobj.objType = DO_SHELL_TYPE;
6247 tgl 5535 GIC 5642 : stinfo->dobj.catId = nilCatalogId;
6247 tgl 5536 CBC 5642 : AssignDumpId(&stinfo->dobj);
4153 bruce 5537 GIC 5642 : stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4855 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 : */
2559 sfrost 5547 5642 : stinfo->dobj.dump = DUMP_COMPONENT_NONE;
5548 : }
5549 : }
9345 bruce 5550 ECB :
7639 tgl 5551 GIC 118 : *numTypes = ntups;
5552 :
9345 bruce 5553 118 : PQclear(res);
5554 :
7919 tgl 5555 CBC 118 : destroyPQExpBuffer(query);
5556 :
4855 bruce 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 *
4080 rhaas 5568 118 : getOperators(Archive *fout, int *numOprs)
5569 : {
5570 : PGresult *res;
5571 : int ntups;
5572 : int i;
8397 bruce 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 : */
9345 bruce 5587 ECB :
215 drowley 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 :
4079 rhaas 5595 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5596 :
9345 bruce 5597 118 : ntups = PQntuples(res);
7639 tgl 5598 118 : *numOprs = ntups;
9345 bruce 5599 ECB :
4153 bruce 5600 GIC 118 : oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
8484 tgl 5601 ECB :
7064 tgl 5602 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
9345 bruce 5603 CBC 118 : i_oid = PQfnumber(res, "oid");
7639 tgl 5604 GIC 118 : i_oprname = PQfnumber(res, "oprname");
7639 tgl 5605 CBC 118 : i_oprnamespace = PQfnumber(res, "oprnamespace");
464 5606 118 : i_oprowner = PQfnumber(res, "oprowner");
4112 peter_e 5607 118 : i_oprkind = PQfnumber(res, "oprkind");
7639 tgl 5608 118 : i_oprcode = PQfnumber(res, "oprcode");
9345 bruce 5609 ECB :
9345 bruce 5610 CBC 94514 : for (i = 0; i < ntups; i++)
9345 bruce 5611 ECB : {
7064 tgl 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);
4153 bruce 5616 94396 : oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
4080 rhaas 5617 188792 : oprinfo[i].dobj.namespace =
957 peter 5618 GIC 94396 : findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
464 tgl 5619 CBC 94396 : oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
4112 peter_e 5620 GIC 94396 : oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
7064 tgl 5621 CBC 94396 : oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
8238 pjw 5622 ECB :
6247 tgl 5623 : /* Decide whether we want to dump it */
2559 sfrost 5624 CBC 94396 : selectDumpableObject(&(oprinfo[i].dobj), fout);
9345 bruce 5625 ECB : }
5626 :
9345 bruce 5627 CBC 118 : PQclear(res);
9345 bruce 5628 ECB :
7919 tgl 5629 CBC 118 : destroyPQExpBuffer(query);
9770 scrappy 5630 ECB :
7639 tgl 5631 CBC 118 : return oprinfo;
9770 scrappy 5632 ECB : }
5633 :
4439 peter_e 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 *
4080 rhaas 5642 GIC 118 : getCollations(Archive *fout, int *numCollations)
4439 peter_e 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;
464 tgl 5653 : int i_collowner;
5654 :
4044 peter_e 5655 GIC 118 : query = createPQExpBuffer();
4044 peter_e 5656 ECB :
5657 : /*
5658 : * find all collations, including builtin collations; we filter out
4439 5659 : * system-defined collations at dump-out time.
5660 : */
5661 :
215 drowley 5662 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
5663 : "collnamespace, "
5664 : "collowner "
5665 : "FROM pg_collation");
4439 peter_e 5666 ECB :
4079 rhaas 5667 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4439 peter_e 5668 ECB :
4439 peter_e 5669 CBC 118 : ntups = PQntuples(res);
4439 peter_e 5670 GIC 118 : *numCollations = ntups;
5671 :
4153 bruce 5672 118 : collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5673 :
4439 peter_e 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");
464 tgl 5678 118 : i_collowner = PQfnumber(res, "collowner");
5679 :
4439 peter_e 5680 172493 : for (i = 0; i < ntups; i++)
4439 peter_e 5681 ECB : {
4439 peter_e 5682 CBC 172375 : collinfo[i].dobj.objType = DO_COLLATION;
5683 172375 : collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4439 peter_e 5684 GIC 172375 : collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4439 peter_e 5685 CBC 172375 : AssignDumpId(&collinfo[i].dobj);
4153 bruce 5686 172375 : collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
4080 rhaas 5687 344750 : collinfo[i].dobj.namespace =
957 peter 5688 172375 : findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
464 tgl 5689 172375 : collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
4439 peter_e 5690 ECB :
5691 : /* Decide whether we want to dump it */
2559 sfrost 5692 CBC 172375 : selectDumpableObject(&(collinfo[i].dobj), fout);
5693 : }
5694 :
4439 peter_e 5695 GIC 118 : PQclear(res);
5696 :
5697 118 : destroyPQExpBuffer(query);
5698 :
4439 peter_e 5699 CBC 118 : return collinfo;
5700 : }
5701 :
5702 : /*
7079 tgl 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 *
4080 rhaas 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;
7079 tgl 5720 ECB : int i_connamespace;
5721 : int i_conowner;
5722 :
3360 sfrost 5723 GIC 118 : query = createPQExpBuffer();
5724 :
7079 tgl 5725 ECB : /*
5726 : * find all conversions, including builtin conversions; we filter out
5727 : * system-defined conversions at dump-out time.
5728 : */
5729 :
215 drowley 5730 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
5731 : "connamespace, "
5732 : "conowner "
5733 : "FROM pg_conversion");
5734 :
4079 rhaas 5735 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5736 :
7079 tgl 5737 118 : ntups = PQntuples(res);
5738 118 : *numConversions = ntups;
5739 :
4153 bruce 5740 CBC 118 : convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5741 :
7064 tgl 5742 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
7079 5743 118 : i_oid = PQfnumber(res, "oid");
5744 118 : i_conname = PQfnumber(res, "conname");
5745 118 : i_connamespace = PQfnumber(res, "connamespace");
464 5746 118 : i_conowner = PQfnumber(res, "conowner");
7079 tgl 5747 ECB :
7079 tgl 5748 GIC 15267 : for (i = 0; i < ntups; i++)
7079 tgl 5749 ECB : {
7064 tgl 5750 CBC 15149 : convinfo[i].dobj.objType = DO_CONVERSION;
7064 tgl 5751 GIC 15149 : convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7064 tgl 5752 CBC 15149 : convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7064 tgl 5753 GIC 15149 : AssignDumpId(&convinfo[i].dobj);
4153 bruce 5754 CBC 15149 : convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
4080 rhaas 5755 30298 : convinfo[i].dobj.namespace =
957 peter 5756 15149 : findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
464 tgl 5757 15149 : convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
6247 tgl 5758 ECB :
5759 : /* Decide whether we want to dump it */
2559 sfrost 5760 CBC 15149 : selectDumpableObject(&(convinfo[i].dobj), fout);
5761 : }
7079 tgl 5762 ECB :
7079 tgl 5763 GIC 118 : PQclear(res);
7079 tgl 5764 ECB :
7079 tgl 5765 CBC 118 : destroyPQExpBuffer(query);
7079 tgl 5766 ECB :
7079 tgl 5767 CBC 118 : return convinfo;
7079 tgl 5768 ECB : }
5769 :
2573 alvherre 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 *
2573 alvherre 5778 GIC 118 : getAccessMethods(Archive *fout, int *numAccessMethods)
2573 alvherre 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 */
2573 alvherre 5792 GIC 118 : if (fout->remoteVersion < 90600)
5793 : {
2573 alvherre 5794 LBC 0 : *numAccessMethods = 0;
2573 alvherre 5795 UIC 0 : return NULL;
5796 : }
5797 :
2573 alvherre 5798 GIC 118 : query = createPQExpBuffer();
5799 :
5800 : /* Select all access methods from pg_am table */
1375 drowley 5801 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
5802 : "amhandler::pg_catalog.regproc AS amhandler "
5803 : "FROM pg_am");
5804 :
2573 alvherre 5805 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5806 :
2573 alvherre 5807 CBC 118 : ntups = PQntuples(res);
2573 alvherre 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");
2573 alvherre 5814 CBC 118 : i_amname = PQfnumber(res, "amname");
2573 alvherre 5815 GIC 118 : i_amhandler = PQfnumber(res, "amhandler");
5816 118 : i_amtype = PQfnumber(res, "amtype");
5817 :
5818 1061 : for (i = 0; i < ntups; i++)
2573 alvherre 5819 ECB : {
2573 alvherre 5820 GIC 943 : aminfo[i].dobj.objType = DO_ACCESS_METHOD;
2573 alvherre 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));
2573 alvherre 5823 GIC 943 : AssignDumpId(&aminfo[i].dobj);
2573 alvherre 5824 CBC 943 : aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
2573 alvherre 5825 GIC 943 : aminfo[i].dobj.namespace = NULL;
2573 alvherre 5826 CBC 943 : aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5827 943 : aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
2573 alvherre 5828 ECB :
5829 : /* Decide whether we want to dump it */
2559 sfrost 5830 CBC 943 : selectDumpableAccessMethod(&(aminfo[i]), fout);
5831 : }
2573 alvherre 5832 ECB :
2573 alvherre 5833 GIC 118 : PQclear(res);
2573 alvherre 5834 ECB :
2573 alvherre 5835 CBC 118 : destroyPQExpBuffer(query);
2573 alvherre 5836 ECB :
2573 alvherre 5837 CBC 118 : return aminfo;
2573 alvherre 5838 ECB : }
5839 :
5840 :
7558 tgl 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 *
4080 rhaas 5849 CBC 118 : getOpclasses(Archive *fout, int *numOpclasses)
5850 : {
7558 tgl 5851 ECB : PGresult *res;
5852 : int ntups;
5853 : int i;
7558 tgl 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 :
7558 tgl 5862 ECB : /*
5863 : * find all opclasses, including builtin opclasses; we filter out
5864 : * system-defined opclasses at dump-out time.
5865 : */
5866 :
215 drowley 5867 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
5868 : "opcnamespace, "
5869 : "opcowner "
5870 : "FROM pg_opclass");
5871 :
4079 rhaas 5872 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5873 :
7558 tgl 5874 118 : ntups = PQntuples(res);
7558 tgl 5875 CBC 118 : *numOpclasses = ntups;
5876 :
4153 bruce 5877 GIC 118 : opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5878 :
7064 tgl 5879 118 : i_tableoid = PQfnumber(res, "tableoid");
7558 5880 118 : i_oid = PQfnumber(res, "oid");
5881 118 : i_opcname = PQfnumber(res, "opcname");
7558 tgl 5882 CBC 118 : i_opcnamespace = PQfnumber(res, "opcnamespace");
464 tgl 5883 GIC 118 : i_opcowner = PQfnumber(res, "opcowner");
5884 :
7558 5885 21154 : for (i = 0; i < ntups; i++)
5886 : {
7064 tgl 5887 CBC 21036 : opcinfo[i].dobj.objType = DO_OPCLASS;
7064 tgl 5888 GIC 21036 : opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7064 tgl 5889 CBC 21036 : opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5890 21036 : AssignDumpId(&opcinfo[i].dobj);
4153 bruce 5891 GIC 21036 : opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
4080 rhaas 5892 CBC 42072 : opcinfo[i].dobj.namespace =
957 peter 5893 GIC 21036 : findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
464 tgl 5894 CBC 21036 : opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
7558 tgl 5895 ECB :
6247 5896 : /* Decide whether we want to dump it */
2559 sfrost 5897 CBC 21036 : selectDumpableObject(&(opcinfo[i].dobj), fout);
7558 tgl 5898 ECB : }
5899 :
7558 tgl 5900 CBC 118 : PQclear(res);
5901 :
5902 118 : destroyPQExpBuffer(query);
7558 tgl 5903 ECB :
7558 tgl 5904 CBC 118 : return opcinfo;
7558 tgl 5905 ECB : }
5906 :
5920 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 *
4080 rhaas 5915 CBC 118 : getOpfamilies(Archive *fout, int *numOpfamilies)
5916 : {
5920 tgl 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 :
5920 tgl 5928 GIC 118 : query = createPQExpBuffer();
5929 :
5920 tgl 5930 ECB : /*
5931 : * find all opfamilies, including builtin opfamilies; we filter out
5932 : * system-defined opfamilies at dump-out time.
5933 : */
5934 :
215 drowley 5935 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, opfname, "
5936 : "opfnamespace, "
5937 : "opfowner "
5938 : "FROM pg_opfamily");
5939 :
4079 rhaas 5940 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5941 :
5920 tgl 5942 118 : ntups = PQntuples(res);
5943 118 : *numOpfamilies = ntups;
5920 tgl 5944 ECB :
4153 bruce 5945 GIC 118 : opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5920 tgl 5946 EUB :
5920 tgl 5947 GBC 118 : i_tableoid = PQfnumber(res, "tableoid");
5920 tgl 5948 GIC 118 : i_oid = PQfnumber(res, "oid");
5949 118 : i_opfname = PQfnumber(res, "opfname");
5920 tgl 5950 CBC 118 : i_opfnamespace = PQfnumber(res, "opfnamespace");
464 tgl 5951 GIC 118 : i_opfowner = PQfnumber(res, "opfowner");
5952 :
5920 tgl 5953 CBC 17471 : for (i = 0; i < ntups; i++)
5954 : {
5920 tgl 5955 GIC 17353 : opfinfo[i].dobj.objType = DO_OPFAMILY;
5956 17353 : opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5920 tgl 5957 CBC 17353 : opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5920 tgl 5958 GIC 17353 : AssignDumpId(&opfinfo[i].dobj);
4153 bruce 5959 CBC 17353 : opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
4080 rhaas 5960 34706 : opfinfo[i].dobj.namespace =
957 peter 5961 GIC 17353 : findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
464 tgl 5962 CBC 17353 : opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
5963 :
5920 tgl 5964 ECB : /* Decide whether we want to dump it */
2559 sfrost 5965 CBC 17353 : selectDumpableObject(&(opfinfo[i].dobj), fout);
5920 tgl 5966 ECB : }
5967 :
5920 tgl 5968 CBC 118 : PQclear(res);
5969 :
5970 118 : destroyPQExpBuffer(query);
5971 :
5972 118 : return opfinfo;
5920 tgl 5973 ECB : }
5974 :
9770 scrappy 5975 : /*
7639 tgl 5976 : * getAggregates:
5977 : * read all the user-defined aggregates in the system catalogs and
5978 : * return them in the AggInfo* structure
9770 scrappy 5979 : *
5980 : * numAggs is set to the number of aggregates read in
5981 : */
7639 tgl 5982 : AggInfo *
2643 tgl 5983 GIC 118 : getAggregates(Archive *fout, int *numAggs)
5984 : {
2643 tgl 5985 CBC 118 : DumpOptions *dopt = fout->dopt;
5986 : PGresult *res;
9344 bruce 5987 ECB : int ntups;
5988 : int i;
8397 bruce 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 :
4436 tgl 6001 ECB : /*
6002 : * Find all interesting aggregates. See comment in getFuncs() for the
6003 : * rationale behind the filtering logic.
6004 : */
2559 sfrost 6005 GIC 118 : if (fout->remoteVersion >= 90600)
2559 sfrost 6006 ECB : {
6007 : const char *agg_check;
6008 :
1864 peter_e 6009 GIC 236 : agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
6010 118 : : "p.proisagg");
6011 :
2559 sfrost 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 "
2559 sfrost 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) "
1864 peter_e 6024 : "WHERE %s AND ("
6025 : "p.pronamespace != "
2559 sfrost 6026 : "(SELECT oid FROM pg_namespace "
6027 : "WHERE nspname = 'pg_catalog') OR "
6028 : "p.proacl IS DISTINCT FROM pip.initprivs",
1864 peter_e 6029 : agg_check);
2559 sfrost 6030 GIC 118 : if (dopt->binary_upgrade)
2559 sfrost 6031 CBC 8 : appendPQExpBufferStr(query,
2559 sfrost 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')");
2559 sfrost 6037 CBC 118 : appendPQExpBufferChar(query, ')');
6038 : }
481 tgl 6039 ECB : else
489 6040 : {
215 drowley 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')");
489 tgl 6052 LBC 0 : if (dopt->binary_upgrade)
489 tgl 6053 UIC 0 : appendPQExpBufferStr(query,
489 tgl 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')");
489 tgl 6059 UIC 0 : appendPQExpBufferChar(query, ')');
6060 : }
6061 :
4079 rhaas 6062 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6063 :
9345 bruce 6064 118 : ntups = PQntuples(res);
7639 tgl 6065 118 : *numAggs = ntups;
6066 :
4153 bruce 6067 CBC 118 : agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
6068 :
7064 tgl 6069 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
7639 6070 118 : i_oid = PQfnumber(res, "oid");
6071 118 : i_aggname = PQfnumber(res, "aggname");
6072 118 : i_aggnamespace = PQfnumber(res, "aggnamespace");
6100 6073 118 : i_pronargs = PQfnumber(res, "pronargs");
6074 118 : i_proargtypes = PQfnumber(res, "proargtypes");
464 6075 118 : i_proowner = PQfnumber(res, "proowner");
7630 peter_e 6076 118 : i_aggacl = PQfnumber(res, "aggacl");
489 tgl 6077 118 : i_acldefault = PQfnumber(res, "acldefault");
6078 :
9345 bruce 6079 420 : for (i = 0; i < ntups; i++)
9345 bruce 6080 ECB : {
7064 tgl 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);
4153 bruce 6085 302 : agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
4080 rhaas 6086 604 : agginfo[i].aggfn.dobj.namespace =
957 peter 6087 CBC 302 : findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
489 tgl 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;
464 tgl 6092 CBC 302 : agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
2118 tgl 6093 GIC 302 : agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
2118 tgl 6094 CBC 302 : agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
6100 6095 302 : agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
6100 tgl 6096 GIC 302 : if (agginfo[i].aggfn.nargs == 0)
6100 tgl 6097 CBC 40 : agginfo[i].aggfn.argtypes = NULL;
6098 : else
6100 tgl 6099 ECB : {
4153 bruce 6100 CBC 262 : agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
2370 tgl 6101 262 : parseOidArray(PQgetvalue(res, i, i_proargtypes),
6102 262 : agginfo[i].aggfn.argtypes,
6103 262 : agginfo[i].aggfn.nargs);
6104 : }
6247 tgl 6105 ECB :
6106 : /* Decide whether we want to dump it */
2559 sfrost 6107 CBC 302 : selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
2559 sfrost 6108 ECB :
489 tgl 6109 : /* Mark whether aggregate has an ACL */
489 tgl 6110 CBC 302 : if (!PQgetisnull(res, i, i_aggacl))
6111 22 : agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
7639 tgl 6112 ECB : }
9173 bruce 6113 :
7639 tgl 6114 CBC 118 : PQclear(res);
6115 :
7639 tgl 6116 GIC 118 : destroyPQExpBuffer(query);
8040 pjw 6117 ECB :
7639 tgl 6118 GIC 118 : return agginfo;
6119 : }
8040 pjw 6120 ECB :
6121 : /*
7639 tgl 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 *
2643 tgl 6129 GIC 118 : getFuncs(Archive *fout, int *numFuncs)
6130 : {
6131 118 : DumpOptions *dopt = fout->dopt;
6132 : PGresult *res;
6133 : int ntups;
6134 : int i;
7639 tgl 6135 CBC 118 : PQExpBuffer query = createPQExpBuffer();
6136 : FuncInfo *finfo;
7064 tgl 6137 ECB : int i_tableoid;
6138 : int i_oid;
6139 : int i_proname;
6140 : int i_pronamespace;
464 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
481 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 : *
2389 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
2300 sfrost 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 : */
2559 sfrost 6170 GIC 118 : if (fout->remoteVersion >= 90600)
6171 : {
6172 : const char *not_agg_check;
6173 :
1864 peter_e 6174 236 : not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
6175 118 : : "NOT p.proisagg");
6176 :
2559 sfrost 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, "
2559 sfrost 6182 ECB : "p.pronamespace, "
464 tgl 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) "
1864 peter_e 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')"
2389 tgl 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))",
1864 peter_e 6204 : not_agg_check,
2300 sfrost 6205 : g_last_builtin_oid,
6206 : g_last_builtin_oid);
2559 sfrost 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 "
2559 sfrost 6211 EUB : "objid = p.oid AND "
6212 : "refclassid = 'pg_extension'::regclass AND "
6213 : "deptype = 'e')");
2389 tgl 6214 CBC 118 : appendPQExpBufferStr(query,
6215 : "\n OR p.proacl IS DISTINCT FROM pip.initprivs");
2559 sfrost 6216 118 : appendPQExpBufferChar(query, ')');
2559 sfrost 6217 ECB : }
6218 : else
7639 tgl 6219 : {
7639 tgl 6220 UIC 0 : appendPQExpBuffer(query,
7064 tgl 6221 ECB : "SELECT tableoid, oid, proname, prolang, "
7630 peter_e 6222 : "pronargs, proargtypes, prorettype, proacl, "
481 tgl 6223 : "acldefault('f', proowner) AS acldefault, "
7639 6224 : "pronamespace, "
464 6225 : "proowner "
4436 6226 : "FROM pg_proc p "
481 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')"
2153 bruce 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);
2300 sfrost 6239 :
2300 sfrost 6240 LBC 0 : if (fout->remoteVersion >= 90500)
6241 0 : appendPQExpBuffer(query,
2153 bruce 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);
2300 sfrost 6247 :
481 tgl 6248 LBC 0 : if (dopt->binary_upgrade)
3429 heikki.linnakangas 6249 0 : appendPQExpBufferStr(query,
6250 : "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6251 : "classid = 'pg_proc'::regclass AND "
3429 heikki.linnakangas 6252 ECB : "objid = p.oid AND "
6253 : "refclassid = 'pg_extension'::regclass AND "
6254 : "deptype = 'e')");
3429 heikki.linnakangas 6255 LBC 0 : appendPQExpBufferChar(query, ')');
6256 : }
6257 :
4079 rhaas 6258 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8122 pjw 6259 ECB :
7639 tgl 6260 GIC 118 : ntups = PQntuples(res);
6261 :
7639 tgl 6262 CBC 118 : *numFuncs = ntups;
8168 bruce 6263 ECB :
3841 tgl 6264 GIC 118 : finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
6265 :
7064 tgl 6266 CBC 118 : i_tableoid = PQfnumber(res, "tableoid");
7639 tgl 6267 GIC 118 : i_oid = PQfnumber(res, "oid");
7639 tgl 6268 CBC 118 : i_proname = PQfnumber(res, "proname");
7639 tgl 6269 GIC 118 : i_pronamespace = PQfnumber(res, "pronamespace");
464 tgl 6270 CBC 118 : i_proowner = PQfnumber(res, "proowner");
7639 tgl 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");
7630 peter_e 6275 118 : i_proacl = PQfnumber(res, "proacl");
489 tgl 6276 118 : i_acldefault = PQfnumber(res, "acldefault");
6277 :
7639 6278 3364 : for (i = 0; i < ntups; i++)
6279 : {
7064 6280 3246 : finfo[i].dobj.objType = DO_FUNC;
7064 tgl 6281 CBC 3246 : finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7064 tgl 6282 GIC 3246 : finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7064 tgl 6283 CBC 3246 : AssignDumpId(&finfo[i].dobj);
4153 bruce 6284 GIC 3246 : finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
6385 6285 6492 : finfo[i].dobj.namespace =
957 peter 6286 3246 : findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
489 tgl 6287 CBC 3246 : finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
489 tgl 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;
464 6291 3246 : finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
7639 6292 3246 : finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
7064 6293 3246 : finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
7639 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 : {
4153 bruce 6299 2509 : finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
7064 tgl 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 */
2559 sfrost 6305 3246 : selectDumpableObject(&(finfo[i].dobj), fout);
6306 :
6307 : /* Mark whether function has an ACL */
489 tgl 6308 3246 : if (!PQgetisnull(res, i, i_proacl))
6309 134 : finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6310 : }
6311 :
7639 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,
537 tgl 6322 ECB : * and return them as an array of TableInfo structures
6323 : *
6324 : * *numTables is set to the number of tables read in
6325 : */
7639 6326 : TableInfo *
2643 tgl 6327 CBC 119 : getTables(Archive *fout, int *numTables)
6328 : {
6329 119 : DumpOptions *dopt = fout->dopt;
6330 : PGresult *res;
6331 : int ntups;
6332 : int i;
7639 tgl 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;
537 tgl 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;
1110 alvherre 6366 : int i_foreignserver;
6367 : int i_amname;
2194 peter_e 6368 : int i_is_identity_sequence;
6369 : int i_relacl;
6370 : int i_acldefault;
6371 : int i_ispartition;
8122 pjw 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 :
215 drowley 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, ");
537 tgl 6412 ECB :
537 tgl 6413 GIC 119 : if (fout->remoteVersion >= 120000)
537 tgl 6414 CBC 119 : appendPQExpBufferStr(query,
6415 : "false AS relhasoids, ");
537 tgl 6416 ECB : else
537 tgl 6417 UIC 0 : appendPQExpBufferStr(query,
537 tgl 6418 ECB : "c.relhasoids, ");
6419 :
537 tgl 6420 CBC 119 : if (fout->remoteVersion >= 90300)
6421 119 : appendPQExpBufferStr(query,
537 tgl 6422 ECB : "c.relispopulated, ");
6423 : else
537 tgl 6424 LBC 0 : appendPQExpBufferStr(query,
537 tgl 6425 ECB : "'t' as relispopulated, ");
6426 :
537 tgl 6427 CBC 119 : if (fout->remoteVersion >= 90400)
6428 119 : appendPQExpBufferStr(query,
6429 : "c.relreplident, ");
537 tgl 6430 ECB : else
537 tgl 6431 UIC 0 : appendPQExpBufferStr(query,
537 tgl 6432 ECB : "'d' AS relreplident, ");
6433 :
537 tgl 6434 CBC 119 : if (fout->remoteVersion >= 90500)
6435 119 : appendPQExpBufferStr(query,
537 tgl 6436 ECB : "c.relrowsecurity, c.relforcerowsecurity, ");
6437 : else
537 tgl 6438 LBC 0 : appendPQExpBufferStr(query,
537 tgl 6439 ECB : "false AS relrowsecurity, "
6440 : "false AS relforcerowsecurity, ");
6441 :
537 tgl 6442 CBC 119 : if (fout->remoteVersion >= 90300)
6443 119 : appendPQExpBufferStr(query,
537 tgl 6444 ECB : "c.relminmxid, tc.relminmxid AS tminmxid, ");
6445 : else
537 tgl 6446 LBC 0 : appendPQExpBufferStr(query,
537 tgl 6447 ECB : "0 AS relminmxid, 0 AS tminmxid, ");
6448 :
537 tgl 6449 GIC 119 : if (fout->remoteVersion >= 90300)
6450 119 : appendPQExpBufferStr(query,
537 tgl 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
537 tgl 6455 UIC 0 : appendPQExpBufferStr(query,
6456 : "c.reloptions, NULL AS checkoption, ");
537 tgl 6457 ECB :
2559 sfrost 6458 GIC 119 : if (fout->remoteVersion >= 90600)
537 tgl 6459 119 : appendPQExpBufferStr(query,
537 tgl 6460 ECB : "am.amname, ");
6461 : else
537 tgl 6462 UIC 0 : appendPQExpBufferStr(query,
6463 : "NULL AS amname, ");
2166 sfrost 6464 ECB :
537 tgl 6465 GIC 119 : if (fout->remoteVersion >= 90600)
537 tgl 6466 CBC 119 : appendPQExpBufferStr(query,
6467 : "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
537 tgl 6468 ECB : else
537 tgl 6469 UIC 0 : appendPQExpBufferStr(query,
6470 : "false AS is_identity_sequence, ");
6471 :
537 tgl 6472 GIC 119 : if (fout->remoteVersion >= 100000)
6473 119 : appendPQExpBufferStr(query,
6474 : "c.relispartition AS ispartition ");
6475 : else
537 tgl 6476 UIC 0 : appendPQExpBufferStr(query,
6477 : "false AS ispartition ");
6478 :
537 tgl 6479 ECB : /*
6480 : * Left join to pg_depend to pick up dependency info linking sequences to
481 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 : */
537 tgl 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 : */
537 tgl 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 : */
489 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 : */
537 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 :
4079 rhaas 6532 119 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6533 :
7639 tgl 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.
7639 tgl 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 : */
3841 tgl 6547 GIC 119 : tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6548 :
7064 6549 119 : i_reltableoid = PQfnumber(res, "tableoid");
7639 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");
489 6554 119 : i_reltype = PQfnumber(res, "reltype");
464 6555 119 : i_relowner = PQfnumber(res, "relowner");
7639 6556 119 : i_relchecks = PQfnumber(res, "relchecks");
6557 119 : i_relhasindex = PQfnumber(res, "relhasindex");
6558 119 : i_relhasrules = PQfnumber(res, "relhasrules");
537 6559 119 : i_relpages = PQfnumber(res, "relpages");
489 6560 119 : i_toastpages = PQfnumber(res, "toastpages");
537 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");
537 tgl 6565 CBC 119 : i_relhastriggers = PQfnumber(res, "relhastriggers");
6566 119 : i_relpersistence = PQfnumber(res, "relpersistence");
537 tgl 6567 GIC 119 : i_relispopulated = PQfnumber(res, "relispopulated");
6568 119 : i_relreplident = PQfnumber(res, "relreplident");
3119 sfrost 6569 GBC 119 : i_relrowsec = PQfnumber(res, "relrowsecurity");
2744 sfrost 6570 GIC 119 : i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
5163 bruce 6571 119 : i_relfrozenxid = PQfnumber(res, "relfrozenxid");
4384 bruce 6572 CBC 119 : i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
537 tgl 6573 119 : i_toastoid = PQfnumber(res, "toid");
537 tgl 6574 GIC 119 : i_relminmxid = PQfnumber(res, "relminmxid");
3203 bruce 6575 119 : i_toastminmxid = PQfnumber(res, "tminmxid");
6125 bruce 6576 GBC 119 : i_reloptions = PQfnumber(res, "reloptions");
3552 sfrost 6577 GIC 119 : i_checkoption = PQfnumber(res, "checkoption");
5179 alvherre 6578 119 : i_toastreloptions = PQfnumber(res, "toast_reloptions");
4819 peter_e 6579 CBC 119 : i_reloftype = PQfnumber(res, "reloftype");
537 tgl 6580 119 : i_foreignserver = PQfnumber(res, "foreignserver");
537 tgl 6581 GIC 119 : i_amname = PQfnumber(res, "amname");
2194 peter_e 6582 119 : i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
537 tgl 6583 GBC 119 : i_relacl = PQfnumber(res, "relacl");
489 tgl 6584 GIC 119 : i_acldefault = PQfnumber(res, "acldefault");
2166 sfrost 6585 119 : i_ispartition = PQfnumber(res, "ispartition");
9173 bruce 6586 ECB :
2370 tgl 6587 CBC 119 : if (dopt->lockWaitTimeout)
6588 : {
6589 : /*
5376 tgl 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
5050 bruce 6594 ECB : * applied to other things too.
5376 tgl 6595 : */
5376 tgl 6596 GIC 2 : resetPQExpBuffer(query);
3429 heikki.linnakangas 6597 2 : appendPQExpBufferStr(query, "SET statement_timeout = ");
3099 alvherre 6598 GBC 2 : appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
4079 rhaas 6599 GIC 2 : ExecuteSqlStatement(fout, query->data);
6600 : }
5376 tgl 6601 ECB :
96 tgl 6602 GNC 119 : resetPQExpBuffer(query);
6603 :
7639 tgl 6604 CBC 30724 : for (i = 0; i < ntups; i++)
6605 : {
7064 tgl 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));
7064 tgl 6609 GBC 30605 : AssignDumpId(&tblinfo[i].dobj);
4153 bruce 6610 GIC 30605 : tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4080 rhaas 6611 61210 : tblinfo[i].dobj.namespace =
957 peter 6612 CBC 30605 : findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
489 tgl 6613 30605 : tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
489 tgl 6614 GIC 30605 : tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6615 30605 : tblinfo[i].dacl.privtype = 0;
489 tgl 6616 GBC 30605 : tblinfo[i].dacl.initprivs = NULL;
7639 tgl 6617 GIC 30605 : tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
489 6618 30605 : tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
464 tgl 6619 CBC 30605 : tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
537 6620 30605 : tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
7639 tgl 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);
3668 andrew 6623 GBC 30605 : tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
489 tgl 6624 GIC 30605 : if (PQgetisnull(res, i, i_toastpages))
6625 24303 : tblinfo[i].toastpages = 0;
489 tgl 6626 ECB : else
489 tgl 6627 CBC 6302 : tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
7538 tgl 6628 GIC 30605 : if (PQgetisnull(res, i, i_owning_tab))
6629 : {
7064 tgl 6630 GBC 30330 : tblinfo[i].owning_tab = InvalidOid;
7538 tgl 6631 GIC 30330 : tblinfo[i].owning_col = 0;
6632 : }
6633 : else
6634 : {
7064 6635 275 : tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
7538 6636 275 : tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6637 : }
4153 bruce 6638 30605 : tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
537 tgl 6639 CBC 30605 : tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
537 tgl 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));
4153 bruce 6651 CBC 30605 : tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
537 tgl 6652 30605 : if (PQgetisnull(res, i, i_checkoption))
3552 sfrost 6653 GIC 30559 : tblinfo[i].checkoption = NULL;
6654 : else
6655 46 : tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
4153 bruce 6656 30605 : tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
489 tgl 6657 30605 : tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
537 6658 30605 : tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
1495 andres 6659 30605 : if (PQgetisnull(res, i, i_amname))
1495 andres 6660 CBC 18182 : tblinfo[i].amname = NULL;
6661 : else
1495 andres 6662 GIC 12423 : tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
537 tgl 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 : */
6662 6671 30605 : if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
2559 sfrost 6672 138 : tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6673 : else
6674 30467 : selectDumpableTable(&tblinfo[i], fout);
2559 sfrost 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.
489 tgl 6686 : */
489 tgl 6687 GIC 30605 : tblinfo[i].interesting = (tblinfo[i].dobj.dump &
489 tgl 6688 ECB : (DUMP_COMPONENT_DEFINITION |
489 tgl 6689 GIC 30605 : DUMP_COMPONENT_DATA)) != 0;
489 tgl 6690 ECB :
537 tgl 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 */
489 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 */
2529 sfrost 6701 ECB :
6702 : /*
6385 bruce 6703 : * Read-lock target tables to make sure they aren't DROPPED or altered
6704 : * in schema before we get around to dumping them.
7639 tgl 6705 : *
6385 bruce 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
7639 tgl 6708 : * alterations to parent tables.
6709 : *
884 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.
894 alvherre 6713 : *
884 tgl 6714 : * We only need to lock the table for certain components; see
6715 : * pg_dump.h
7639 6716 : */
489 tgl 6717 CBC 30605 : if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
884 6718 5328 : (tblinfo[i].relkind == RELKIND_RELATION ||
489 6719 1563 : tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
7639 tgl 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 : */
96 tgl 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. */
96 tgl 6738 UNC 0 : appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
6739 0 : ExecuteSqlStatement(fout, query->data);
6740 0 : resetPQExpBuffer(query);
6741 : }
6742 : }
9320 vadim4o 6743 ECB : }
9345 bruce 6744 : }
6745 :
96 tgl 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 :
2370 tgl 6753 CBC 118 : if (dopt->lockWaitTimeout)
5376 tgl 6754 ECB : {
4079 rhaas 6755 CBC 2 : ExecuteSqlStatement(fout, "SET statement_timeout = 0");
5376 tgl 6756 ECB : }
6757 :
7639 tgl 6758 CBC 118 : PQclear(res);
6075 tgl 6759 ECB :
4026 tgl 6760 CBC 118 : destroyPQExpBuffer(query);
4026 tgl 6761 ECB :
4026 tgl 6762 CBC 118 : return tblinfo;
4026 tgl 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
4026 tgl 6773 GIC 118 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
4026 tgl 6774 ECB : {
6775 : int i;
6776 :
6075 6777 : /*
6778 : * Force sequences that are "owned" by table columns to be dumped whenever
6779 : * their owning table is being dumped.
6780 : */
4026 tgl 6781 GIC 30474 : for (i = 0; i < numTables; i++)
6075 tgl 6782 ECB : {
6075 tgl 6783 GIC 30356 : TableInfo *seqinfo = &tblinfo[i];
4026 tgl 6784 ECB : TableInfo *owning_tab;
6075 6785 :
6075 tgl 6786 CBC 30356 : if (!OidIsValid(seqinfo->owning_tab))
6787 30084 : continue; /* not an owned sequence */
2443 sfrost 6788 ECB :
4026 tgl 6789 CBC 272 : owning_tab = findTableByOid(seqinfo->owning_tab);
2284 sfrost 6790 272 : if (owning_tab == NULL)
366 tgl 6791 LBC 0 : pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
366 tgl 6792 ECB : seqinfo->owning_tab, seqinfo->dobj.catId.oid);
2443 sfrost 6793 :
6794 : /*
1691 michael 6795 : * Only dump identity sequences if we're going to dump the table that
6796 : * it belongs to.
6797 : */
1691 michael 6798 CBC 272 : if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
6799 21 : seqinfo->is_identity_sequence)
1691 michael 6800 ECB : {
1691 michael 6801 CBC 6 : seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
6802 6 : continue;
1691 michael 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.
2443 sfrost 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
2428 tgl 6813 : * policies, are being dumped) while the sequence is not (and
6814 : * therefore the definition and other components should also be
6815 : * dumped).
2443 sfrost 6816 : *
6817 : * If the sequence is part of the extension then it should be properly
2428 tgl 6818 : * marked by checkExtensionMembership() and this will be a no-op as
6819 : * the table will be equivalently marked.
2443 sfrost 6820 : */
2443 sfrost 6821 CBC 266 : seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
2443 sfrost 6822 ECB :
2443 sfrost 6823 CBC 266 : if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
4026 tgl 6824 253 : seqinfo->interesting = true;
6075 tgl 6825 ECB : }
9770 scrappy 6826 CBC 118 : }
9770 scrappy 6827 ECB :
6828 : /*
6829 : * getInherits
9345 bruce 6830 : * read all the inheritance information
9770 scrappy 6831 : * from the system catalogs return them in the InhInfo* structure
6832 : *
7639 tgl 6833 : * numInherits is set to the number of pairs read in
9770 scrappy 6834 : */
7836 bruce 6835 : InhInfo *
4080 rhaas 6836 CBC 118 : getInherits(Archive *fout, int *numInherits)
9770 scrappy 6837 ECB : {
8397 bruce 6838 : PGresult *res;
6839 : int ntups;
9344 6840 : int i;
8397 bruce 6841 CBC 118 : PQExpBuffer query = createPQExpBuffer();
8397 bruce 6842 ECB : InhInfo *inhinfo;
6843 :
6844 : int i_inhrelid;
6845 : int i_inhparent;
6846 :
6847 : /* find all the inheritance information */
2166 sfrost 6848 GIC 118 : appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
9345 bruce 6849 ECB :
4079 rhaas 6850 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6851 :
9345 bruce 6852 118 : ntups = PQntuples(res);
6853 :
9345 bruce 6854 GIC 118 : *numInherits = ntups;
6855 :
4153 6856 118 : inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6857 :
8539 6858 118 : i_inhrelid = PQfnumber(res, "inhrelid");
9345 6859 118 : i_inhparent = PQfnumber(res, "inhparent");
6860 :
6861 2272 : for (i = 0; i < ntups; i++)
6862 : {
7064 tgl 6863 2154 : inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6864 2154 : inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
9345 bruce 6865 ECB : }
6866 :
9345 bruce 6867 CBC 118 : PQclear(res);
6868 :
7919 tgl 6869 118 : destroyPQExpBuffer(query);
7919 tgl 6870 ECB :
9345 bruce 6871 GIC 118 : return inhinfo;
6872 : }
9770 scrappy 6873 ECB :
6874 : /*
6875 : * getPartitioningInfo
23 tgl 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
23 tgl 6892 GIC 118 : getPartitioningInfo(Archive *fout)
6893 : {
6894 : PQExpBuffer query;
23 tgl 6895 ECB : PGresult *res;
6896 : int ntups;
6897 :
6898 : /* hash partitioning didn't exist before v11 */
23 tgl 6899 GIC 118 : if (fout->remoteVersion < 110000)
23 tgl 6900 UIC 0 : return;
6901 : /* needn't bother if schema-only dump */
23 tgl 6902 GIC 118 : if (fout->dopt->schemaOnly)
6903 10 : return;
23 tgl 6904 ECB :
23 tgl 6905 CBC 108 : query = createPQExpBuffer();
23 tgl 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 : */
23 tgl 6915 GIC 108 : appendPQExpBufferStr(query,
23 tgl 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 :
23 tgl 6923 GIC 108 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
23 tgl 6924 ECB :
23 tgl 6925 GIC 108 : ntups = PQntuples(res);
6926 :
23 tgl 6927 CBC 110 : for (int i = 0; i < ntups; i++)
23 tgl 6928 ECB : {
23 tgl 6929 GIC 2 : Oid tabrelid = atooid(PQgetvalue(res, i, 0));
6930 : TableInfo *tbinfo;
23 tgl 6931 ECB :
23 tgl 6932 GIC 2 : tbinfo = findTableByOid(tabrelid);
23 tgl 6933 CBC 2 : if (tbinfo == NULL)
23 tgl 6934 UIC 0 : pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
6935 : tabrelid);
23 tgl 6936 CBC 2 : tbinfo->unsafe_partitions = true;
6937 : }
23 tgl 6938 ECB :
23 tgl 6939 GIC 108 : PQclear(res);
23 tgl 6940 ECB :
23 tgl 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 : */
9770 scrappy 6951 ECB : void
4080 rhaas 6952 GIC 118 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6953 : {
7064 tgl 6954 118 : PQExpBuffer query = createPQExpBuffer();
489 6955 118 : PQExpBuffer tbloids = createPQExpBuffer();
6956 : PGresult *res;
6957 : int ntups;
6958 : int curtblindx;
7064 tgl 6959 ECB : IndxInfo *indxinfo;
6960 : int i_tableoid,
6961 : i_oid,
6962 : i_indrelid,
6963 : i_indexname,
1906 alvherre 6964 : i_parentidx,
7064 tgl 6965 : i_indexdef,
6966 : i_indnkeyatts,
1828 teodor 6967 : i_indnatts,
7064 tgl 6968 : i_indkey,
7064 tgl 6969 EUB : i_indisclustered,
6970 : i_indisreplident,
6971 : i_indnullsnotdistinct,
6972 : i_contype,
6973 : i_conname,
6974 : i_condeferrable,
6975 : i_condeferred,
7064 tgl 6976 ECB : i_contableoid,
6824 6977 : i_conoid,
6978 : i_condef,
6125 bruce 6979 : i_tablespace,
1573 michael 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 : */
489 tgl 6992 GIC 118 : appendPQExpBufferChar(tbloids, '{');
6993 30474 : for (int i = 0; i < numTables; i++)
6994 : {
7064 6995 30356 : TableInfo *tbinfo = &tblinfo[i];
6996 :
3689 kgrittn 6997 30356 : if (!tbinfo->hasindex)
7064 tgl 6998 21320 : continue;
7064 tgl 6999 ECB :
7000 : /*
489 7001 : * We can ignore indexes of uninteresting tables.
1906 alvherre 7002 : */
489 tgl 7003 GIC 9036 : if (!tbinfo->interesting)
7064 tgl 7004 CBC 7606 : continue;
7005 :
7006 : /* OK, we need info for this table */
489 tgl 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 :
215 drowley 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 :
475 peter 7026 ECB :
475 peter 7027 GIC 118 : if (fout->remoteVersion >= 90400)
215 drowley 7028 GNC 118 : appendPQExpBufferStr(query,
7029 : "i.indisreplident, ");
475 peter 7030 ECB : else
215 drowley 7031 UNC 0 : appendPQExpBufferStr(query,
7032 : "false AS indisreplident, ");
7033 :
475 peter 7034 CBC 118 : if (fout->remoteVersion >= 110000)
215 drowley 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, ");
475 peter 7047 ECB : else
215 drowley 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 :
430 peter 7055 GIC 118 : if (fout->remoteVersion >= 150000)
215 drowley 7056 GNC 118 : appendPQExpBufferStr(query,
7057 : "i.indnullsnotdistinct ");
7058 : else
215 drowley 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.
489 tgl 7070 ECB : */
489 tgl 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) "
489 tgl 7077 ECB : "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
489 tgl 7078 EUB : "LEFT JOIN pg_catalog.pg_constraint c "
7079 : "ON (i.indrelid = c.conrelid AND "
489 tgl 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 : */
489 tgl 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 "
489 tgl 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 : }
7064 7107 :
489 tgl 7108 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7109 :
489 tgl 7110 CBC 118 : ntups = PQntuples(res);
7064 tgl 7111 ECB :
489 tgl 7112 GBC 118 : i_tableoid = PQfnumber(res, "tableoid");
489 tgl 7113 GIC 118 : i_oid = PQfnumber(res, "oid");
489 tgl 7114 CBC 118 : i_indrelid = PQfnumber(res, "indrelid");
489 tgl 7115 GIC 118 : i_indexname = PQfnumber(res, "indexname");
7116 118 : i_parentidx = PQfnumber(res, "parentidx");
489 tgl 7117 CBC 118 : i_indexdef = PQfnumber(res, "indexdef");
489 tgl 7118 GIC 118 : i_indnkeyatts = PQfnumber(res, "indnkeyatts");
489 tgl 7119 CBC 118 : i_indnatts = PQfnumber(res, "indnatts");
489 tgl 7120 GIC 118 : i_indkey = PQfnumber(res, "indkey");
7121 118 : i_indisclustered = PQfnumber(res, "indisclustered");
7122 118 : i_indisreplident = PQfnumber(res, "indisreplident");
430 peter 7123 118 : i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
489 tgl 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");
489 tgl 7130 CBC 118 : i_condef = PQfnumber(res, "condef");
489 tgl 7131 GIC 118 : i_tablespace = PQfnumber(res, "tablespace");
489 tgl 7132 CBC 118 : i_indreloptions = PQfnumber(res, "indreloptions");
7133 118 : i_indstatcols = PQfnumber(res, "indstatcols");
489 tgl 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)
366 tgl 7165 UIC 0 : pg_fatal("unrecognized table OID %u", indrelid);
7166 : /* cross-check that we only got requested tables */
489 tgl 7167 GIC 1426 : if (!tbinfo->hasindex ||
7168 1426 : !tbinfo->interesting)
366 tgl 7169 UIC 0 : pg_fatal("unexpected index data for table \"%s\"",
366 tgl 7170 ECB : tbinfo->dobj.name);
489 7171 :
7172 : /* Save data for this table */
489 tgl 7173 CBC 1426 : tbinfo->indexes = indxinfo + j;
489 tgl 7174 GIC 1426 : tbinfo->numIndexes = numinds;
489 tgl 7175 ECB :
489 tgl 7176 CBC 3274 : for (int c = 0; c < numinds; c++, j++)
7177 : {
7178 : char contype;
7179 :
7064 tgl 7180 GIC 1848 : indxinfo[j].dobj.objType = DO_INDEX;
7064 tgl 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));
7064 tgl 7183 GIC 1848 : AssignDumpId(&indxinfo[j].dobj);
1906 alvherre 7184 1848 : indxinfo[j].dobj.dump = tbinfo->dobj.dump;
4153 bruce 7185 CBC 1848 : indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
6976 tgl 7186 1848 : indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7064 7187 1848 : indxinfo[j].indextable = tbinfo;
4153 bruce 7188 GIC 1848 : indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
1818 heikki.linnakangas 7189 CBC 1848 : indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
1828 teodor 7190 GIC 1848 : indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
4153 bruce 7191 CBC 1848 : indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
2654 tgl 7192 GIC 1848 : indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
1573 michael 7193 1848 : indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
7194 1848 : indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
1828 teodor 7195 1848 : indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7064 tgl 7196 1848 : parseOidArray(PQgetvalue(res, j, i_indkey),
1828 teodor 7197 1848 : indxinfo[j].indkeys, indxinfo[j].indnattrs);
7064 tgl 7198 1848 : indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
3439 rhaas 7199 1848 : indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
430 peter 7200 1848 : indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
1906 alvherre 7201 1848 : indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
1060 tgl 7202 1848 : indxinfo[j].partattaches = (SimplePtrList)
7203 : {
7204 : NULL, NULL
1060 tgl 7205 ECB : };
7064 tgl 7206 CBC 1848 : contype = *(PQgetvalue(res, j, i_contype));
7207 :
4871 tgl 7208 GIC 1848 : if (contype == 'p' || contype == 'u' || contype == 'x')
7064 tgl 7209 GBC 887 : {
7210 : /*
7211 : * If we found a constraint matching the index, create an
7064 tgl 7212 ECB : * entry for it.
7213 : */
7214 : ConstraintInfo *constrinfo;
7215 :
532 tgl 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;
532 tgl 7226 GBC 887 : constrinfo->contype = contype;
4871 tgl 7227 GIC 887 : if (contype == 'x')
532 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;
532 tgl 7233 CBC 887 : constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7234 887 : constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
532 tgl 7235 GIC 887 : constrinfo->conislocal = true;
7236 887 : constrinfo->separate = true;
532 tgl 7237 EUB :
532 tgl 7238 GIC 887 : indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
7239 : }
7240 : else
7241 : {
7242 : /* Plain secondary index */
7064 7243 961 : indxinfo[j].indexconstraint = 0;
7244 : }
7245 : }
7246 : }
7247 :
489 7248 118 : PQclear(res);
489 tgl 7249 ECB :
7064 tgl 7250 GIC 118 : destroyPQExpBuffer(query);
489 tgl 7251 CBC 118 : destroyPQExpBuffer(tbloids);
7064 tgl 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
1883 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;
1307 tomas.vondra 7273 EUB : int i_stattarget;
7274 : int i;
7275 :
7276 : /* Extended statistics were new in v10 */
2207 alvherre 7277 GIC 118 : if (fout->remoteVersion < 100000)
2207 alvherre 7278 UIC 0 : return;
7279 :
2207 alvherre 7280 GIC 118 : query = createPQExpBuffer();
7281 :
1307 tomas.vondra 7282 118 : if (fout->remoteVersion < 130000)
215 drowley 7283 UNC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
7284 : "stxnamespace, stxowner, (-1) AS stxstattarget "
7285 : "FROM pg_catalog.pg_statistic_ext");
1307 tomas.vondra 7286 ECB : else
215 drowley 7287 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
7288 : "stxnamespace, stxowner, stxstattarget "
7289 : "FROM pg_catalog.pg_statistic_ext");
2207 alvherre 7290 ECB :
1883 tgl 7291 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2207 alvherre 7292 ECB :
1883 tgl 7293 CBC 118 : ntups = PQntuples(res);
2207 alvherre 7294 ECB :
1883 tgl 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");
464 7299 118 : i_stxowner = PQfnumber(res, "stxowner");
1307 tomas.vondra 7300 118 : i_stattarget = PQfnumber(res, "stxstattarget");
2207 alvherre 7301 ECB :
1883 tgl 7302 CBC 118 : statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
2207 alvherre 7303 ECB :
1883 tgl 7304 CBC 273 : for (i = 0; i < ntups; i++)
1883 tgl 7305 ECB : {
1883 tgl 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 =
957 peter 7312 155 : findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
464 tgl 7313 GIC 155 : statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
1307 tomas.vondra 7314 CBC 155 : statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
7315 :
7316 : /* Decide whether we want to dump it */
1883 tgl 7317 GIC 155 : selectDumpableObject(&(statsextinfo[i].dobj), fout);
7318 : }
7319 :
1883 tgl 7320 CBC 118 : PQclear(res);
2207 alvherre 7321 118 : destroyPQExpBuffer(query);
7322 : }
2207 alvherre 7323 ECB :
7064 tgl 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
4080 rhaas 7334 GIC 118 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7335 : {
489 tgl 7336 CBC 118 : PQExpBuffer query = createPQExpBuffer();
489 tgl 7337 GIC 118 : PQExpBuffer tbloids = createPQExpBuffer();
7064 tgl 7338 ECB : PGresult *res;
489 7339 : int ntups;
7340 : int curtblindx;
489 tgl 7341 GIC 118 : TableInfo *tbinfo = NULL;
489 tgl 7342 ECB : ConstraintInfo *constrinfo;
5326 tgl 7343 EUB : int i_contableoid,
7344 : i_conoid,
489 tgl 7345 ECB : i_conrelid,
5326 7346 : i_conname,
5326 tgl 7347 EUB : i_confrelid,
7348 : i_conindid,
7349 : i_condef;
7350 :
489 tgl 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 : */
489 tgl 7359 CBC 118 : appendPQExpBufferChar(tbloids, '{');
7360 30474 : for (int i = 0; i < numTables; i++)
7064 tgl 7361 ECB : {
232 drowley 7362 CBC 30356 : TableInfo *tinfo = &tblinfo[i];
7064 tgl 7363 ECB :
1731 alvherre 7364 : /*
1714 tgl 7365 : * For partitioned tables, foreign keys have no triggers so they must
7366 : * be included anyway in case some foreign keys are defined.
1731 alvherre 7367 : */
232 drowley 7368 CBC 30356 : if ((!tinfo->hastriggers &&
7369 29516 : tinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7370 1126 : !(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7064 tgl 7371 29279 : continue;
7064 tgl 7372 ECB :
489 7373 : /* OK, we need info for this table */
489 tgl 7374 CBC 1077 : if (tbloids->len > 1) /* do we have more than the '{'? */
7375 1025 : appendPQExpBufferChar(tbloids, ',');
232 drowley 7376 1077 : appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
489 tgl 7377 ECB : }
489 tgl 7378 CBC 118 : appendPQExpBufferChar(tbloids, '}');
7064 tgl 7379 ECB :
489 tgl 7380 CBC 118 : appendPQExpBufferStr(query,
7381 : "SELECT c.tableoid, c.oid, "
7382 : "conrelid, conname, confrelid, ");
489 tgl 7383 GIC 118 : if (fout->remoteVersion >= 110000)
489 tgl 7384 CBC 118 : appendPQExpBufferStr(query, "conindid, ");
7385 : else
489 tgl 7386 LBC 0 : appendPQExpBufferStr(query, "0 AS conindid, ");
489 tgl 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);
489 tgl 7393 GIC 118 : if (fout->remoteVersion >= 110000)
489 tgl 7394 CBC 118 : appendPQExpBufferStr(query,
489 tgl 7395 ECB : "AND conparentid = 0 ");
489 tgl 7396 CBC 118 : appendPQExpBufferStr(query,
489 tgl 7397 ECB : "ORDER BY conrelid, conname");
7064 7398 :
489 tgl 7399 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7064 tgl 7400 ECB :
489 tgl 7401 CBC 118 : ntups = PQntuples(res);
7064 tgl 7402 ECB :
489 tgl 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");
489 tgl 7407 GIC 118 : i_confrelid = PQfnumber(res, "confrelid");
489 tgl 7408 CBC 118 : i_conindid = PQfnumber(res, "conindid");
7409 118 : i_condef = PQfnumber(res, "condef");
7064 tgl 7410 ECB :
489 tgl 7411 CBC 118 : constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
1270 alvherre 7412 ECB :
489 tgl 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
489 tgl 7421 ECB : * order.
7422 : */
489 tgl 7423 GIC 158 : if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
7424 : {
7425 12809 : while (++curtblindx < numTables)
1270 alvherre 7426 ECB : {
489 tgl 7427 GIC 12809 : tbinfo = &tblinfo[curtblindx];
489 tgl 7428 CBC 12809 : if (tbinfo->dobj.catId.oid == conrelid)
7429 148 : break;
489 tgl 7430 ECB : }
489 tgl 7431 GIC 148 : if (curtblindx >= numTables)
366 tgl 7432 UIC 0 : pg_fatal("unrecognized table OID %u", conrelid);
7433 : }
7434 :
489 tgl 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));
489 tgl 7440 CBC 158 : constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
489 tgl 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
489 tgl 7455 ECB : * happens by making the constraint depend on each index partition
489 tgl 7456 EUB : * attach object.
7457 : */
489 tgl 7458 CBC 158 : reftable = findTableByOid(constrinfo[j].confrelid);
489 tgl 7459 GIC 158 : if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
489 tgl 7460 ECB : {
489 tgl 7461 GBC 20 : Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));
7462 :
489 tgl 7463 GIC 20 : if (indexOid != InvalidOid)
7464 : {
489 tgl 7465 CBC 20 : for (int k = 0; k < reftable->numIndexes; k++)
7466 : {
7467 : IndxInfo *refidx;
7468 :
489 tgl 7469 ECB : /* not our index? */
489 tgl 7470 GIC 20 : if (reftable->indexes[k].dobj.catId.oid != indexOid)
489 tgl 7471 LBC 0 : continue;
7472 :
489 tgl 7473 CBC 20 : refidx = &reftable->indexes[k];
7474 20 : addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
7475 20 : break;
1270 alvherre 7476 ECB : }
7477 : }
7064 tgl 7478 : }
7479 : }
7480 :
489 tgl 7481 GIC 118 : PQclear(res);
489 tgl 7482 ECB :
7064 tgl 7483 GIC 118 : destroyPQExpBuffer(query);
489 tgl 7484 CBC 118 : destroyPQExpBuffer(tbloids);
7064 7485 118 : }
7064 tgl 7486 ECB :
968 alvherre 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
788 peter 7499 CBC 45 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
7500 : {
7501 : SimplePtrListCell *cell;
7502 :
968 alvherre 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)
968 alvherre 7512 CBC 25 : addConstrChildIdxDeps(dobj, attach->partitionIdx);
7513 : }
7514 45 : }
968 alvherre 7515 ECB :
7516 : /*
7517 : * getDomainConstraints
7518 : *
7064 tgl 7519 : * Get info about constraints on a domain.
7520 : */
7521 : static void
4080 rhaas 7522 GIC 124 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7523 : {
7524 : int i;
7525 : ConstraintInfo *constrinfo;
489 tgl 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 */
489 tgl 7537 CBC 44 : appendPQExpBufferStr(query,
481 tgl 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 :
489 tgl 7546 CBC 44 : ExecuteSqlStatement(fout, query->data);
4153 alvherre 7547 ECB :
489 tgl 7548 CBC 44 : fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
489 tgl 7549 ECB : }
7550 :
489 tgl 7551 GIC 124 : printfPQExpBuffer(query,
489 tgl 7552 ECB : "EXECUTE getDomainConstraints('%u')",
7553 : tyinfo->dobj.catId.oid);
7064 7554 :
4079 rhaas 7555 GIC 124 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7064 tgl 7556 ECB :
7064 tgl 7557 GIC 124 : ntups = PQntuples(res);
7064 tgl 7558 ECB :
7064 tgl 7559 GIC 124 : i_tableoid = PQfnumber(res, "tableoid");
7560 124 : i_oid = PQfnumber(res, "oid");
7064 tgl 7561 CBC 124 : i_conname = PQfnumber(res, "conname");
7562 124 : i_consrc = PQfnumber(res, "consrc");
7563 :
4153 bruce 7564 GBC 124 : constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7064 tgl 7565 ECB :
4855 bruce 7566 GIC 124 : tyinfo->nDomChecks = ntups;
7567 124 : tyinfo->domChecks = constrinfo;
7568 :
7064 tgl 7569 208 : for (i = 0; i < ntups; i++)
7570 : {
3955 bruce 7571 CBC 84 : bool validated = PQgetvalue(res, i, 4)[0] == 't';
4153 alvherre 7572 ECB :
7064 tgl 7573 GIC 84 : constrinfo[i].dobj.objType = DO_CONSTRAINT;
7064 tgl 7574 CBC 84 : constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7064 tgl 7575 GIC 84 : constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7576 84 : AssignDumpId(&constrinfo[i].dobj);
4153 bruce 7577 CBC 84 : constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
4855 bruce 7578 GIC 84 : constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7064 tgl 7579 CBC 84 : constrinfo[i].contable = NULL;
4855 bruce 7580 GIC 84 : constrinfo[i].condomain = tyinfo;
7064 tgl 7581 CBC 84 : constrinfo[i].contype = 'c';
4153 bruce 7582 84 : constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
5326 tgl 7583 84 : constrinfo[i].confrelid = InvalidOid;
7064 7584 84 : constrinfo[i].conindex = 0;
5002 7585 84 : constrinfo[i].condeferrable = false;
7586 84 : constrinfo[i].condeferred = false;
5448 7587 84 : constrinfo[i].conislocal = true;
7588 :
4153 alvherre 7589 84 : constrinfo[i].separate = !validated;
7590 :
7064 tgl 7591 ECB : /*
6797 bruce 7592 : * Make the domain depend on the constraint, ensuring it won't be
7593 : * output till any constraint dependencies are OK. If the constraint
4153 alvherre 7594 : * has not been validated, it's going to be dumped after the domain
7595 : * anyway, so this doesn't matter.
7596 : */
4153 alvherre 7597 GIC 84 : if (validated)
7598 84 : addObjectDependency(&tyinfo->dobj,
7599 84 : constrinfo[i].dobj.dumpId);
7600 : }
7064 tgl 7601 ECB :
7064 tgl 7602 GIC 124 : PQclear(res);
7064 tgl 7603 ECB :
7064 tgl 7604 GIC 124 : destroyPQExpBuffer(query);
7064 tgl 7605 CBC 124 : }
7064 tgl 7606 ECB :
7607 : /*
7608 : * getRules
7609 : * get basic information about every rule in the system
7064 tgl 7610 EUB : *
7611 : * numRules is set to the number of rules read in
7612 : */
7064 tgl 7613 ECB : RuleInfo *
4080 rhaas 7614 CBC 118 : getRules(Archive *fout, int *numRules)
7064 tgl 7615 ECB : {
7616 : PGresult *res;
7617 : int ntups;
7618 : int i;
7064 tgl 7619 CBC 118 : PQExpBuffer query = createPQExpBuffer();
7064 tgl 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;
5865 JanWieck 7627 : int i_ev_enabled;
7064 tgl 7628 :
481 tgl 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 :
4079 rhaas 7636 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7064 tgl 7637 ECB :
7064 tgl 7638 GIC 118 : ntups = PQntuples(res);
7064 tgl 7639 ECB :
7064 tgl 7640 GIC 118 : *numRules = ntups;
7064 tgl 7641 ECB :
4153 bruce 7642 GIC 118 : ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7064 tgl 7643 ECB :
7064 tgl 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");
7064 tgl 7648 CBC 118 : i_ev_type = PQfnumber(res, "ev_type");
7064 tgl 7649 GBC 118 : i_is_instead = PQfnumber(res, "is_instead");
5865 JanWieck 7650 GIC 118 : i_ev_enabled = PQfnumber(res, "ev_enabled");
7064 tgl 7651 ECB :
7064 tgl 7652 CBC 17867 : for (i = 0; i < ntups; i++)
7064 tgl 7653 ECB : {
7654 : Oid ruletableoid;
7655 :
7064 tgl 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));
7064 tgl 7659 CBC 17749 : AssignDumpId(&ruleinfo[i].dobj);
4153 bruce 7660 GIC 17749 : ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7064 tgl 7661 CBC 17749 : ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7662 17749 : ruleinfo[i].ruletable = findTableByOid(ruletableoid);
6600 7663 17749 : if (ruleinfo[i].ruletable == NULL)
366 tgl 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);
6976 tgl 7666 GIC 17749 : ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
6247 7667 17749 : ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7064 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';
5865 JanWieck 7670 17749 : ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7064 tgl 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
3689 kgrittn 7677 ECB : * positioning. Other rules are forced to appear after their
7678 : * table.
7679 : */
3689 kgrittn 7680 GIC 17749 : if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
3668 andrew 7681 CBC 565 : ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7064 tgl 7682 GIC 17584 : ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
6690 tgl 7683 ECB : {
7064 tgl 7684 GIC 17318 : addObjectDependency(&ruleinfo[i].ruletable->dobj,
7064 tgl 7685 CBC 17318 : ruleinfo[i].dobj.dumpId);
7686 : /* We'll merge the rule into CREATE VIEW, if possible */
6690 7687 17318 : ruleinfo[i].separate = false;
7688 : }
7064 tgl 7689 ECB : else
6690 7690 : {
7064 tgl 7691 GIC 431 : addObjectDependency(&ruleinfo[i].dobj,
7064 tgl 7692 CBC 431 : ruleinfo[i].ruletable->dobj.dumpId);
6690 tgl 7693 GIC 431 : ruleinfo[i].separate = true;
7694 : }
7695 : }
7696 : else
6690 tgl 7697 UIC 0 : ruleinfo[i].separate = true;
7698 : }
7699 :
7064 tgl 7700 CBC 118 : PQclear(res);
7701 :
7064 tgl 7702 GIC 118 : destroyPQExpBuffer(query);
7703 :
7064 tgl 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
7064 tgl 7712 ECB : * does get entered into the DumpableObject tables.
7713 : */
7714 : void
4080 rhaas 7715 CBC 118 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7716 : {
7064 tgl 7717 GIC 118 : PQExpBuffer query = createPQExpBuffer();
489 7718 118 : PQExpBuffer tbloids = createPQExpBuffer();
7719 : PGresult *res;
7720 : int ntups;
7721 : int curtblindx;
7722 : TriggerInfo *tginfo;
7723 : int i_tableoid,
7064 tgl 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,
6438 7735 : i_tgenabled,
7736 : i_tgispartition,
7064 7737 : i_tgdeferrable,
4930 peter_e 7738 : i_tginitdeferred,
7739 : i_tgdef;
7064 tgl 7740 :
7741 : /*
489 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 : */
489 tgl 7749 CBC 118 : appendPQExpBufferChar(tbloids, '{');
489 tgl 7750 GIC 30474 : for (int i = 0; i < numTables; i++)
7064 tgl 7751 ECB : {
7064 tgl 7752 CBC 30356 : TableInfo *tbinfo = &tblinfo[i];
7064 tgl 7753 ECB :
2559 sfrost 7754 CBC 30356 : if (!tbinfo->hastriggers ||
7755 840 : !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7064 tgl 7756 29565 : continue;
7064 tgl 7757 ECB :
489 7758 : /* OK, we need info for this table */
489 tgl 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);
489 tgl 7762 ECB : }
489 tgl 7763 CBC 118 : appendPQExpBufferChar(tbloids, '}');
7064 tgl 7764 ECB :
459 alvherre 7765 CBC 118 : if (fout->remoteVersion >= 150000)
7766 : {
459 alvherre 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 : */
459 alvherre 7775 CBC 118 : appendPQExpBuffer(query,
459 alvherre 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 : }
459 alvherre 7789 UIC 0 : else if (fout->remoteVersion >= 130000)
7790 : {
7791 : /*
489 tgl 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 : */
489 tgl 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) "
489 tgl 7807 ECB : "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
7808 : "ORDER BY t.tgrelid, t.tgname",
7809 : tbloids->data);
7810 : }
489 tgl 7811 UIC 0 : else if (fout->remoteVersion >= 110000)
7812 : {
7813 : /*
489 tgl 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 : */
489 tgl 7820 LBC 0 : appendPQExpBuffer(query,
7821 : "SELECT t.tgrelid, t.tgname, "
489 tgl 7822 ECB : "t.tgfoid::pg_catalog.regproc AS tgfname, "
7823 : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
459 alvherre 7824 : "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
489 tgl 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 : }
481 7836 : else
489 7837 : {
7838 : /* See above about pretty=true in pg_get_triggerdef */
489 tgl 7839 LBC 0 : appendPQExpBuffer(query,
489 tgl 7840 ECB : "SELECT t.tgrelid, t.tgname, "
7841 : "t.tgfoid::pg_catalog.regproc AS tgfname, "
489 tgl 7842 EUB : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
7843 : "t.tgenabled, false as tgispartition, "
489 tgl 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 :
489 tgl 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");
489 tgl 7858 CBC 118 : i_tgrelid = PQfnumber(res, "tgrelid");
7859 118 : i_tgname = PQfnumber(res, "tgname");
7860 118 : i_tgfname = PQfnumber(res, "tgfname");
489 tgl 7861 GIC 118 : i_tgtype = PQfnumber(res, "tgtype");
489 tgl 7862 CBC 118 : i_tgnargs = PQfnumber(res, "tgnargs");
7863 118 : i_tgargs = PQfnumber(res, "tgargs");
489 tgl 7864 GIC 118 : i_tgisconstraint = PQfnumber(res, "tgisconstraint");
489 tgl 7865 CBC 118 : i_tgconstrname = PQfnumber(res, "tgconstrname");
489 tgl 7866 GIC 118 : i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7867 118 : i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7868 118 : i_tgenabled = PQfnumber(res, "tgenabled");
459 alvherre 7869 CBC 118 : i_tgispartition = PQfnumber(res, "tgispartition");
489 tgl 7870 118 : i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7871 118 : i_tginitdeferred = PQfnumber(res, "tginitdeferred");
489 tgl 7872 GIC 118 : i_tgdef = PQfnumber(res, "tgdef");
7873 :
7874 118 : tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
2621 tgl 7875 EUB :
7876 : /*
7877 : * Outer loop iterates once per table, not once per row. Incrementing of
489 tgl 7878 ECB : * j is handled by the inner loop.
7879 : */
489 tgl 7880 CBC 118 : curtblindx = -1;
489 tgl 7881 GIC 422 : for (int j = 0; j < ntups;)
489 tgl 7882 ECB : {
489 tgl 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 : /*
489 tgl 7893 ECB : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
7894 : * order.
7895 : */
489 tgl 7896 CBC 14801 : while (++curtblindx < numTables)
7897 : {
489 tgl 7898 GIC 14801 : tbinfo = &tblinfo[curtblindx];
7899 14801 : if (tbinfo->dobj.catId.oid == tgrelid)
7900 304 : break;
7901 : }
7902 304 : if (curtblindx >= numTables)
366 tgl 7903 UIC 0 : pg_fatal("unrecognized table OID %u", tgrelid);
7904 :
7905 : /* Save data for this table */
489 tgl 7906 GIC 304 : tbinfo->triggers = tginfo + j;
7907 304 : tbinfo->numTriggers = numtrigs;
7908 :
7909 808 : for (int c = 0; c < numtrigs; c++, j++)
7910 : {
7064 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);
4153 bruce 7915 504 : tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
6976 tgl 7916 504 : tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7064 7917 504 : tginfo[j].tgtable = tbinfo;
5865 JanWieck 7918 504 : tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
459 alvherre 7919 504 : tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
4930 peter_e 7920 504 : if (i_tgdef >= 0)
7921 : {
4153 bruce 7922 504 : tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7923 :
7924 : /* remaining fields are not valid if we have tgdef */
4925 tgl 7925 504 : tginfo[j].tgfname = NULL;
7926 504 : tginfo[j].tgtype = 0;
4925 tgl 7927 CBC 504 : tginfo[j].tgnargs = 0;
7928 504 : tginfo[j].tgargs = NULL;
4925 tgl 7929 GIC 504 : tginfo[j].tgisconstraint = false;
4925 tgl 7930 CBC 504 : tginfo[j].tgdeferrable = false;
4925 tgl 7931 GIC 504 : tginfo[j].tginitdeferred = false;
4925 tgl 7932 CBC 504 : tginfo[j].tgconstrname = NULL;
7933 504 : tginfo[j].tgconstrrelid = InvalidOid;
7934 504 : tginfo[j].tgconstrrelname = NULL;
7935 : }
7936 : else
4930 peter_e 7937 ECB : {
4930 peter_e 7938 LBC 0 : tginfo[j].tgdef = NULL;
4930 peter_e 7939 ECB :
4153 bruce 7940 UIC 0 : tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
4930 peter_e 7941 LBC 0 : tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
4930 peter_e 7942 UIC 0 : tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
4153 bruce 7943 LBC 0 : tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
4930 peter_e 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 : {
4153 bruce 7950 0 : tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
4930 peter_e 7951 0 : tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7952 0 : if (OidIsValid(tginfo[j].tgconstrrelid))
7064 tgl 7953 ECB : {
4930 peter_e 7954 UIC 0 : if (PQgetisnull(res, j, i_tgconstrrelname))
366 tgl 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);
4153 bruce 7959 0 : tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7960 : }
7961 : else
4930 peter_e 7962 0 : tginfo[j].tgconstrrelname = NULL;
7963 : }
7964 : else
7965 : {
7966 0 : tginfo[j].tgconstrname = NULL;
4930 peter_e 7967 UBC 0 : tginfo[j].tgconstrrelid = InvalidOid;
7064 tgl 7968 UIC 0 : tginfo[j].tgconstrrelname = NULL;
7969 : }
7970 : }
7971 : }
7972 : }
7973 :
489 tgl 7974 GIC 118 : PQclear(res);
7975 :
7064 7976 118 : destroyPQExpBuffer(query);
489 tgl 7977 GBC 118 : destroyPQExpBuffer(tbloids);
7064 tgl 7978 GIC 118 : }
7979 :
7980 : /*
7981 : * getEventTriggers
7982 : * get information about event triggers
7983 : */
7984 : EventTriggerInfo *
3917 rhaas 7985 118 : getEventTriggers(Archive *fout, int *numEventTriggers)
7986 : {
7987 : int i;
7988 : PQExpBuffer query;
3917 rhaas 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 */
3917 rhaas 8002 GIC 118 : if (fout->remoteVersion < 90300)
8003 : {
3917 rhaas 8004 UIC 0 : *numEventTriggers = 0;
8005 0 : return NULL;
8006 : }
8007 :
3556 sfrost 8008 GIC 118 : query = createPQExpBuffer();
8009 :
215 drowley 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 :
3917 rhaas 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");
3917 rhaas 8030 CBC 118 : i_evtname = PQfnumber(res, "evtname");
3917 rhaas 8031 GIC 118 : i_evtevent = PQfnumber(res, "evtevent");
3917 rhaas 8032 CBC 118 : i_evtowner = PQfnumber(res, "evtowner");
3917 rhaas 8033 GIC 118 : i_evttags = PQfnumber(res, "evttags");
3917 rhaas 8034 CBC 118 : i_evtfname = PQfnumber(res, "evtfname");
8035 118 : i_evtenabled = PQfnumber(res, "evtenabled");
3917 rhaas 8036 ECB :
3917 rhaas 8037 CBC 163 : for (i = 0; i < ntups; i++)
3917 rhaas 8038 ECB : {
3917 rhaas 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));
464 tgl 8046 45 : evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
3917 rhaas 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));
2643 tgl 8050 ECB :
8051 : /* Decide whether we want to dump it */
2559 sfrost 8052 CBC 45 : selectDumpableObject(&(evtinfo[i].dobj), fout);
8053 : }
8054 :
3917 rhaas 8055 GIC 118 : PQclear(res);
8056 :
8057 118 : destroyPQExpBuffer(query);
3917 rhaas 8058 ECB :
3917 rhaas 8059 CBC 118 : return evtinfo;
8060 : }
3917 rhaas 8061 ECB :
7064 tgl 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 *
4080 rhaas 8072 GIC 118 : getProcLangs(Archive *fout, int *numProcLangs)
8073 : {
7064 tgl 8074 ECB : PGresult *res;
8075 : int ntups;
8076 : int i;
7064 tgl 8077 CBC 118 : PQExpBuffer query = createPQExpBuffer();
7064 tgl 8078 ECB : ProcLangInfo *planginfo;
8079 : int i_tableoid;
8080 : int i_oid;
7064 tgl 8081 EUB : int i_lanname;
8082 : int i_lanpltrusted;
8083 : int i_lanplcallfoid;
4947 tgl 8084 ECB : int i_laninline;
6336 8085 : int i_lanvalidator;
8086 : int i_lanacl;
489 8087 : int i_acldefault;
8088 : int i_lanowner;
7064 8089 :
215 drowley 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 :
4079 rhaas 8100 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8101 :
7064 tgl 8102 GIC 118 : ntups = PQntuples(res);
7064 tgl 8103 ECB :
7064 tgl 8104 CBC 118 : *numProcLangs = ntups;
7064 tgl 8105 ECB :
4153 bruce 8106 CBC 118 : planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7064 tgl 8107 ECB :
7064 tgl 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");
4947 tgl 8113 GIC 118 : i_laninline = PQfnumber(res, "laninline");
6336 8114 118 : i_lanvalidator = PQfnumber(res, "lanvalidator");
8115 118 : i_lanacl = PQfnumber(res, "lanacl");
489 tgl 8116 GBC 118 : i_acldefault = PQfnumber(res, "acldefault");
6336 tgl 8117 GIC 118 : i_lanowner = PQfnumber(res, "lanowner");
7064 tgl 8118 EUB :
7064 tgl 8119 GBC 281 : for (i = 0; i < ntups; i++)
7064 tgl 8120 EUB : {
7064 tgl 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 :
4153 bruce 8126 163 : planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
489 tgl 8127 GIC 163 : planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
489 tgl 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;
7064 tgl 8131 GIC 163 : planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7064 tgl 8132 GBC 163 : planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
2799 8133 163 : planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
2799 tgl 8134 GIC 163 : planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
464 8135 163 : planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
8136 :
2643 tgl 8137 EUB : /* Decide whether we want to dump it */
2559 sfrost 8138 GIC 163 : selectDumpableProcLang(&(planginfo[i]), fout);
8139 :
489 tgl 8140 EUB : /* Mark whether language has an ACL */
489 tgl 8141 GIC 163 : if (!PQgetisnull(res, i, i_lanacl))
8142 45 : planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
8143 : }
7064 tgl 8144 EUB :
7064 tgl 8145 GBC 118 : PQclear(res);
7064 tgl 8146 EUB :
7064 tgl 8147 GIC 118 : destroyPQExpBuffer(query);
8148 :
8149 118 : return planginfo;
8150 : }
8151 :
7064 tgl 8152 ECB : /*
8153 : * getCasts
840 akorotkov 8154 : * get basic information about most casts in the system
7064 tgl 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 *
2643 tgl 8162 GIC 118 : getCasts(Archive *fout, int *numCasts)
7064 tgl 8163 ECB : {
8164 : PGresult *res;
8165 : int ntups;
8166 : int i;
7064 tgl 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 :
840 akorotkov 8177 118 : if (fout->remoteVersion >= 140000)
8178 : {
8179 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
840 akorotkov 8180 ECB : "castsource, casttarget, castfunc, castcontext, "
8181 : "castmethod "
840 akorotkov 8182 EUB : "FROM pg_cast c "
8183 : "WHERE NOT EXISTS ( "
8184 : "SELECT 1 FROM pg_range r "
8185 : "WHERE c.castsource = r.rngtypid "
840 akorotkov 8186 ECB : "AND c.casttarget = r.rngmultitypid "
8187 : ") "
8188 : "ORDER BY 3,4");
8189 : }
8190 : else
8191 : {
3429 heikki.linnakangas 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 :
4079 rhaas 8198 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8199 :
7064 tgl 8200 118 : ntups = PQntuples(res);
8201 :
8202 118 : *numCasts = ntups;
8203 :
4153 bruce 8204 118 : castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
8205 :
7064 tgl 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");
5273 heikki.linnakangas 8212 118 : i_castmethod = PQfnumber(res, "castmethod");
7064 tgl 8213 ECB :
7064 tgl 8214 GIC 26507 : for (i = 0; i < ntups; i++)
7064 tgl 8215 ECB : {
8216 : PQExpBufferData namebuf;
6976 8217 : TypeInfo *sTypeInfo;
8218 : TypeInfo *tTypeInfo;
8219 :
7064 tgl 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));
5273 heikki.linnakangas 8228 GIC 26389 : castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
8229 :
6976 tgl 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
6385 bruce 8233 : * will be an empty string.
8234 : */
6976 tgl 8235 CBC 26389 : initPQExpBuffer(&namebuf);
6976 tgl 8236 GIC 26389 : sTypeInfo = findTypeByOid(castinfo[i].castsource);
6976 tgl 8237 CBC 26389 : tTypeInfo = findTypeByOid(castinfo[i].casttarget);
6976 tgl 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 */
2559 sfrost 8244 26389 : selectDumpableCast(&(castinfo[i]), fout);
8245 : }
8246 :
7064 tgl 8247 118 : PQclear(res);
8248 :
8249 118 : destroyPQExpBuffer(query);
7064 tgl 8250 ECB :
7064 tgl 8251 GIC 118 : return castinfo;
8252 : }
8253 :
8254 : static char *
2905 peter_e 8255 CBC 90 : get_language_name(Archive *fout, Oid langid)
8256 : {
8257 : PQExpBuffer query;
8258 : PGresult *res;
8259 : char *lanname;
8260 :
2905 peter_e 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 :
2905 peter_e 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 : {
2905 peter_e 8280 ECB : PGresult *res;
8281 : int ntups;
8282 : int i;
8283 : PQExpBuffer query;
2878 bruce 8284 : TransformInfo *transforminfo;
8285 : int i_tableoid;
2905 peter_e 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 */
2905 peter_e 8293 CBC 118 : if (fout->remoteVersion < 90500)
2905 peter_e 8294 ECB : {
2905 peter_e 8295 LBC 0 : *numTransforms = 0;
2905 peter_e 8296 UIC 0 : return NULL;
2905 peter_e 8297 ECB : }
8298 :
2894 magnus 8299 CBC 118 : query = createPQExpBuffer();
2894 magnus 8300 ECB :
1375 drowley 8301 CBC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
1375 drowley 8302 ECB : "trftype, trflang, trffromsql::oid, trftosql::oid "
8303 : "FROM pg_transform "
8304 : "ORDER BY 3,4");
2905 peter_e 8305 :
2905 peter_e 8306 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2905 peter_e 8307 ECB :
2905 peter_e 8308 CBC 118 : ntups = PQntuples(res);
2905 peter_e 8309 ECB :
2905 peter_e 8310 CBC 118 : *numTransforms = ntups;
2905 peter_e 8311 ECB :
2905 peter_e 8312 CBC 118 : transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
2905 peter_e 8313 ECB :
2905 peter_e 8314 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
8315 118 : i_oid = PQfnumber(res, "oid");
2905 peter_e 8316 CBC 118 : i_trftype = PQfnumber(res, "trftype");
2905 peter_e 8317 GIC 118 : i_trflang = PQfnumber(res, "trflang");
8318 118 : i_trffromsql = PQfnumber(res, "trffromsql");
2905 peter_e 8319 CBC 118 : i_trftosql = PQfnumber(res, "trftosql");
2905 peter_e 8320 ECB :
2905 peter_e 8321 GIC 168 : for (i = 0; i < ntups; i++)
8322 : {
2905 peter_e 8323 ECB : PQExpBufferData namebuf;
8324 : TypeInfo *typeInfo;
8325 : char *lanname;
8326 :
2905 peter_e 8327 CBC 50 : transforminfo[i].dobj.objType = DO_TRANSFORM;
2905 peter_e 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.
2905 peter_e 8340 ECB : */
2905 peter_e 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)
2905 peter_e 8345 CBC 50 : appendPQExpBuffer(&namebuf, "%s %s",
8346 : typeInfo->dobj.name, lanname);
2905 peter_e 8347 GIC 50 : transforminfo[i].dobj.name = namebuf.data;
2828 tgl 8348 50 : free(lanname);
8349 :
8350 : /* Decide whether we want to dump it */
2559 sfrost 8351 50 : selectDumpableObject(&(transforminfo[i].dobj), fout);
8352 : }
8353 :
2905 peter_e 8354 118 : PQclear(res);
2905 peter_e 8355 ECB :
2905 peter_e 8356 GIC 118 : destroyPQExpBuffer(query);
2905 peter_e 8357 ECB :
2905 peter_e 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
2643 tgl 8369 118 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
7064 tgl 8370 EUB : {
2643 tgl 8371 GIC 118 : DumpOptions *dopt = fout->dopt;
7064 8372 118 : PQExpBuffer q = createPQExpBuffer();
489 8373 118 : PQExpBuffer tbloids = createPQExpBuffer();
8374 118 : PQExpBuffer checkoids = createPQExpBuffer();
2 alvherre 8375 GNC 118 : PQExpBuffer defaultoids = createPQExpBuffer();
8376 : PGresult *res;
489 tgl 8377 ECB : int ntups;
8378 : int curtblindx;
8379 : int i_attrelid;
8380 : int i_attnum;
590 dgustafsson 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;
9345 bruce 8400 :
489 tgl 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 : */
489 tgl 8411 GIC 118 : appendPQExpBufferChar(tbloids, '{');
8412 118 : appendPQExpBufferChar(checkoids, '{');
2 alvherre 8413 GNC 118 : appendPQExpBufferChar(defaultoids, '{');
1004 peter 8414 GIC 30474 : for (int i = 0; i < numTables; i++)
9345 bruce 8415 ECB : {
7522 bruce 8416 CBC 30356 : TableInfo *tbinfo = &tblinfo[i];
7538 tgl 8417 ECB :
7639 8418 : /* Don't bother to collect info for sequences */
7538 tgl 8419 CBC 30356 : if (tbinfo->relkind == RELKIND_SEQUENCE)
9345 bruce 8420 GIC 445 : continue;
9345 bruce 8421 ECB :
8422 : /* Don't bother with uninteresting tables, either */
7538 tgl 8423 GIC 29911 : if (!tbinfo->interesting)
7639 tgl 8424 CBC 25077 : continue;
8425 :
8426 : /* OK, we need info for this table */
489 8427 4834 : if (tbloids->len > 1) /* do we have more than the '{'? */
489 tgl 8428 GIC 4756 : appendPQExpBufferChar(tbloids, ',');
489 tgl 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 */
489 tgl 8434 GIC 465 : if (checkoids->len > 1) /* do we have more than the '{'? */
489 tgl 8435 CBC 397 : appendPQExpBufferChar(checkoids, ',');
489 tgl 8436 GIC 465 : appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
8437 : }
8438 : }
8439 118 : appendPQExpBufferChar(tbloids, '}');
8440 118 : appendPQExpBufferChar(checkoids, '}');
489 tgl 8441 ECB :
481 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 : */
489 tgl 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"
481 tgl 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 : */
2 alvherre 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
2 alvherre 8485 UNC 0 : appendPQExpBufferStr(q,
8486 : "a.attnotnull, false AS local_notnull,\n");
8487 :
489 tgl 8488 GBC 118 : if (fout->remoteVersion >= 140000)
8489 118 : appendPQExpBufferStr(q,
8490 : "a.attcompression AS attcompression,\n");
8491 : else
489 tgl 8492 LBC 0 : appendPQExpBufferStr(q,
8493 : "'' AS attcompression,\n");
8019 pjw 8494 ECB :
489 tgl 8495 GIC 118 : if (fout->remoteVersion >= 100000)
8496 118 : appendPQExpBufferStr(q,
8497 : "a.attidentity,\n");
8498 : else
489 tgl 8499 LBC 0 : appendPQExpBufferStr(q,
8500 : "'' AS attidentity,\n");
1684 peter_e 8501 ECB :
489 tgl 8502 GIC 118 : if (fout->remoteVersion >= 110000)
489 tgl 8503 CBC 118 : appendPQExpBufferStr(q,
8504 : "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
489 tgl 8505 ECB : "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8506 : else
489 tgl 8507 LBC 0 : appendPQExpBufferStr(q,
489 tgl 8508 ECB : "NULL AS attmissingval,\n");
750 8509 :
489 tgl 8510 CBC 118 : if (fout->remoteVersion >= 120000)
8511 118 : appendPQExpBufferStr(q,
489 tgl 8512 ECB : "a.attgenerated\n");
8513 : else
489 tgl 8514 LBC 0 : appendPQExpBufferStr(q,
8515 : "'' AS attgenerated\n");
8516 :
8517 : /* need left join to pg_type to not fail on dropped columns ... */
489 tgl 8518 GIC 118 : appendPQExpBuffer(q,
8519 : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
489 tgl 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);
1684 peter_e 8524 :
8525 : /* in 16, need pg_constraint for NOT NULLs */
2 alvherre 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 :
489 tgl 8536 CBC 118 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8537 :
489 tgl 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");
489 tgl 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");
489 tgl 8547 GIC 118 : i_attidentity = PQfnumber(res, "attidentity");
489 tgl 8548 CBC 118 : i_attgenerated = PQfnumber(res, "attgenerated");
8549 118 : i_attisdropped = PQfnumber(res, "attisdropped");
489 tgl 8550 GIC 118 : i_attlen = PQfnumber(res, "attlen");
8551 118 : i_attalign = PQfnumber(res, "attalign");
489 tgl 8552 CBC 118 : i_attislocal = PQfnumber(res, "attislocal");
489 tgl 8553 GIC 118 : i_attnotnull = PQfnumber(res, "attnotnull");
2 alvherre 8554 GNC 118 : i_localnotnull = PQfnumber(res, "local_notnull");
489 tgl 8555 GIC 118 : i_attoptions = PQfnumber(res, "attoptions");
489 tgl 8556 CBC 118 : i_attcollation = PQfnumber(res, "attcollation");
489 tgl 8557 GIC 118 : i_attcompression = PQfnumber(res, "attcompression");
489 tgl 8558 CBC 118 : i_attfdwoptions = PQfnumber(res, "attfdwoptions");
489 tgl 8559 GIC 118 : i_attmissingval = PQfnumber(res, "attmissingval");
489 tgl 8560 CBC 118 : i_atthasdef = PQfnumber(res, "atthasdef");
8561 :
8562 : /* Within the next loop, we'll accumulate OIDs of tables with defaults */
2 alvherre 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 : */
489 tgl 8570 GIC 118 : curtblindx = -1;
489 tgl 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;
489 tgl 8575 ECB : int numatts;
8576 : bool hasdefaults;
9345 bruce 8577 :
8578 : /* Count rows for this table */
489 tgl 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)
366 tgl 8594 UIC 0 : pg_fatal("unrecognized table OID %u", attrelid);
8595 : /* cross-check that we only got requested tables */
489 tgl 8596 GIC 4698 : if (tbinfo->relkind == RELKIND_SEQUENCE ||
8597 4698 : !tbinfo->interesting)
366 tgl 8598 UIC 0 : pg_fatal("unexpected column data for table \"%s\"",
8599 : tbinfo->dobj.name);
8600 :
8601 : /* Save data for this table */
489 tgl 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));
489 tgl 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));
489 tgl 8616 GIC 4698 : tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
489 tgl 8617 CBC 4698 : tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
489 tgl 8618 GIC 4698 : tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
8619 4698 : tbinfo->notnull = (bool *) pg_malloc(numatts * sizeof(bool));
2 alvherre 8620 GNC 4698 : tbinfo->localNotNull = (bool *) pg_malloc(numatts * sizeof(bool));
489 tgl 8621 CBC 4698 : tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
7639 tgl 8622 GIC 4698 : hasdefaults = false;
8623 :
489 tgl 8624 CBC 22136 : for (int j = 0; j < numatts; j++, r++)
9345 bruce 8625 ECB : {
489 tgl 8626 GIC 17438 : if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
366 tgl 8627 UIC 0 : pg_fatal("invalid column numbering in table \"%s\"",
366 tgl 8628 ECB : tbinfo->dobj.name);
489 tgl 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));
489 tgl 8632 GIC 17438 : tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
8633 17438 : tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
489 tgl 8634 CBC 17438 : tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
8635 17438 : tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
2194 peter_e 8636 17438 : tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
489 tgl 8637 GIC 17438 : tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
8638 17438 : tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
489 tgl 8639 CBC 17438 : tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
8640 17438 : tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
489 tgl 8641 GIC 17438 : tbinfo->notnull[j] = (PQgetvalue(res, r, i_attnotnull)[0] == 't');
2 alvherre 8642 GNC 17438 : tbinfo->localNotNull[j] = (PQgetvalue(res, r, i_localnotnull)[0] == 't');
489 tgl 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));
6797 bruce 8648 17438 : tbinfo->attrdefs[j] = NULL; /* fix below */
489 tgl 8649 17438 : if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
7639 tgl 8650 CBC 882 : hasdefaults = true;
8651 : }
8652 :
489 tgl 8653 GIC 4698 : if (hasdefaults)
8654 : {
8655 : /* Collect OIDs of interesting tables that have defaults */
2 alvherre 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 :
489 tgl 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 : */
2 alvherre 8668 GNC 118 : if (!dopt->dataOnly && defaultoids->len > 1)
8669 : {
8670 : AttrDefInfo *attrdefs;
8671 : int numDefaults;
489 tgl 8672 GIC 47 : TableInfo *tbinfo = NULL;
8673 :
8674 47 : pg_log_info("finding table default expressions");
8675 :
2 alvherre 8676 GNC 47 : appendPQExpBufferChar(defaultoids, '}');
8677 :
489 tgl 8678 GIC 47 : printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
489 tgl 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);
4076 tgl 8684 EUB :
489 tgl 8685 GIC 47 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8686 :
489 tgl 8687 CBC 47 : numDefaults = PQntuples(res);
8688 47 : attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8689 :
489 tgl 8690 GIC 47 : curtblindx = -1;
489 tgl 8691 GBC 889 : for (int j = 0; j < numDefaults; j++)
8692 : {
489 tgl 8693 GIC 842 : Oid adtableoid = atooid(PQgetvalue(res, j, 0));
489 tgl 8694 CBC 842 : Oid adoid = atooid(PQgetvalue(res, j, 1));
8695 842 : Oid adrelid = atooid(PQgetvalue(res, j, 2));
489 tgl 8696 GIC 842 : int adnum = atoi(PQgetvalue(res, j, 3));
8697 842 : char *adsrc = PQgetvalue(res, j, 4);
6247 tgl 8698 EUB :
8699 : /*
8700 : * Locate the associated TableInfo; we rely on tblinfo[] being in
489 tgl 8701 ECB : * OID order.
8702 : */
489 tgl 8703 GIC 842 : if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
8704 : {
8705 14977 : while (++curtblindx < numTables)
7064 tgl 8706 EUB : {
489 tgl 8707 GIC 14977 : tbinfo = &tblinfo[curtblindx];
8708 14977 : if (tbinfo->dobj.catId.oid == adrelid)
489 tgl 8709 CBC 694 : break;
795 peter 8710 ECB : }
489 tgl 8711 GIC 694 : if (curtblindx >= numTables)
366 tgl 8712 UIC 0 : pg_fatal("unrecognized table OID %u", adrelid);
489 tgl 8713 EUB : }
8714 :
489 tgl 8715 GIC 842 : if (adnum <= 0 || adnum > tbinfo->numatts)
366 tgl 8716 UIC 0 : pg_fatal("invalid adnum value %d for table \"%s\"",
366 tgl 8717 ECB : adnum, tbinfo->dobj.name);
8718 :
8719 : /*
8720 : * dropped columns shouldn't have defaults, but just in case,
8721 : * ignore 'em
8722 : */
489 tgl 8723 GIC 842 : if (tbinfo->attisdropped[adnum - 1])
489 tgl 8724 UIC 0 : continue;
7064 tgl 8725 ECB :
489 tgl 8726 CBC 842 : attrdefs[j].dobj.objType = DO_ATTRDEF;
489 tgl 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;
489 tgl 8731 CBC 842 : attrdefs[j].adnum = adnum;
489 tgl 8732 GIC 842 : attrdefs[j].adef_expr = pg_strdup(adsrc);
8733 :
8734 842 : attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
489 tgl 8735 CBC 842 : attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8736 :
8737 842 : attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8738 :
489 tgl 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 : */
489 tgl 8746 CBC 842 : if (tbinfo->attgenerated[adnum - 1])
489 tgl 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 : */
489 tgl 8756 CBC 360 : attrdefs[j].separate = false;
489 tgl 8757 ECB : }
489 tgl 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.
4143 alvherre 8763 ECB : */
489 tgl 8764 CBC 36 : attrdefs[j].separate = true;
8765 : }
8766 446 : else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
4154 alvherre 8767 ECB : {
8768 : /* column will be suppressed, print default separately */
489 tgl 8769 GIC 4 : attrdefs[j].separate = true;
8770 : }
8771 : else
7064 tgl 8772 ECB : {
489 tgl 8773 CBC 442 : attrdefs[j].separate = false;
7064 tgl 8774 ECB : }
8775 :
489 tgl 8776 GIC 842 : if (!attrdefs[j].separate)
8777 : {
8778 : /*
8779 : * Mark the default as needing to appear before the table, so
489 tgl 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 : */
489 tgl 8784 CBC 802 : addObjectDependency(&tbinfo->dobj,
489 tgl 8785 GIC 802 : attrdefs[j].dobj.dumpId);
489 tgl 8786 ECB : }
489 tgl 8787 EUB :
489 tgl 8788 GIC 842 : tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
489 tgl 8789 ECB : }
8790 :
489 tgl 8791 GBC 47 : PQclear(res);
8792 : }
8793 :
8794 : /*
489 tgl 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 : */
489 tgl 8798 CBC 118 : if (!dopt->dataOnly && checkoids->len > 2)
489 tgl 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;
7064 8809 :
489 tgl 8810 CBC 63 : pg_log_info("finding table check constraints");
489 tgl 8811 ECB :
489 tgl 8812 CBC 63 : resetPQExpBuffer(q);
8813 63 : appendPQExpBuffer(q,
481 tgl 8814 ECB : "SELECT c.tableoid, c.oid, conrelid, conname, "
8815 : "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
8816 : "conislocal, convalidated "
489 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' "
489 tgl 8820 EUB : "ORDER BY c.conrelid, c.conname",
8821 : checkoids->data);
489 tgl 8822 ECB :
489 tgl 8823 CBC 63 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
489 tgl 8824 ECB :
489 tgl 8825 CBC 63 : numConstrs = PQntuples(res);
8826 63 : constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
489 tgl 8827 ECB :
489 tgl 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");
489 tgl 8835 ECB :
8836 : /* As above, this loop iterates once per table, not once per row */
489 tgl 8837 CBC 63 : curtblindx = -1;
8838 502 : for (int j = 0; j < numConstrs;)
489 tgl 8839 ECB : {
489 tgl 8840 CBC 439 : Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
8841 439 : TableInfo *tbinfo = NULL;
489 tgl 8842 ECB : int numcons;
8843 :
8844 : /* Count rows for this table */
489 tgl 8845 GIC 577 : for (numcons = 1; numcons < numConstrs - j; numcons++)
489 tgl 8846 CBC 514 : if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
489 tgl 8847 GIC 376 : break;
8848 :
489 tgl 8849 ECB : /*
8850 : * Locate the associated TableInfo; we rely on tblinfo[] being in
8851 : * OID order.
8852 : */
489 tgl 8853 GIC 17496 : while (++curtblindx < numTables)
8854 : {
489 tgl 8855 CBC 17496 : tbinfo = &tblinfo[curtblindx];
489 tgl 8856 GIC 17496 : if (tbinfo->dobj.catId.oid == conrelid)
8857 439 : break;
8858 : }
8859 439 : if (curtblindx >= numTables)
366 tgl 8860 UIC 0 : pg_fatal("unrecognized table OID %u", conrelid);
489 tgl 8861 ECB :
489 tgl 8862 GIC 439 : if (numcons != tbinfo->ncheck)
8863 : {
1469 peter 8864 UIC 0 : pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
1469 peter 8865 ECB : "expected %d check constraints on table \"%s\" but found %d",
8866 : tbinfo->ncheck),
489 tgl 8867 : tbinfo->ncheck, tbinfo->dobj.name, numcons);
366 tgl 8868 UIC 0 : pg_log_error_hint("The system catalogs might be corrupted.");
4070 rhaas 8869 LBC 0 : exit_nicely(1);
8870 : }
8122 pjw 8871 ECB :
489 tgl 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 :
7064 tgl 8878 CBC 577 : constrs[j].dobj.objType = DO_CONSTRAINT;
489 tgl 8879 GIC 577 : constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
489 tgl 8880 CBC 577 : constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7064 8881 577 : AssignDumpId(&constrs[j].dobj);
489 tgl 8882 GIC 577 : constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
6976 tgl 8883 CBC 577 : constrs[j].dobj.namespace = tbinfo->dobj.namespace;
7064 8884 577 : constrs[j].contable = tbinfo;
7064 tgl 8885 GIC 577 : constrs[j].condomain = NULL;
7064 tgl 8886 CBC 577 : constrs[j].contype = 'c';
489 8887 577 : constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
5326 8888 577 : constrs[j].confrelid = InvalidOid;
7064 8889 577 : constrs[j].conindex = 0;
5002 8890 577 : constrs[j].condeferrable = false;
5002 tgl 8891 GIC 577 : constrs[j].condeferred = false;
489 8892 577 : constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
8893 :
8894 : /*
8895 : * An unvalidated constraint needs to be dumped separately, so
4154 alvherre 8896 ECB : * that potentially-violating existing data is loaded before
8897 : * the constraint.
8898 : */
4006 alvherre 8899 GIC 577 : constrs[j].separate = !validated;
6385 bruce 8900 ECB :
6247 tgl 8901 CBC 577 : constrs[j].dobj.dump = tbinfo->dobj.dump;
6247 tgl 8902 ECB :
8903 : /*
6385 bruce 8904 : * Mark the constraint as needing to appear before the table
6385 bruce 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
3955 bruce 8908 ECB : * will be dumped after data is loaded anyway, so don't do it.
3955 bruce 8909 EUB : * (There's an automatic dependency in the opposite direction
8910 : * anyway, so don't need to add one manually here.)
8911 : */
4143 alvherre 8912 GIC 577 : if (!constrs[j].separate)
4154 8913 542 : addObjectDependency(&tbinfo->dobj,
8914 542 : constrs[j].dobj.dumpId);
8915 :
7064 tgl 8916 ECB : /*
481 tgl 8917 EUB : * We will detect later whether the constraint must be split
8918 : * out from the table definition.
7064 tgl 8919 ECB : */
9320 vadim4o 8920 : }
9345 bruce 8921 : }
489 tgl 8922 :
489 tgl 8923 CBC 63 : PQclear(res);
9345 bruce 8924 ECB : }
7919 tgl 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 : */
2 alvherre 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 : {
2 alvherre 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 :
2 alvherre 9025 GNC 112 : PQclear(res);
9026 : }
9027 :
7919 tgl 9028 GIC 118 : destroyPQExpBuffer(q);
489 tgl 9029 CBC 118 : destroyPQExpBuffer(tbloids);
9030 118 : destroyPQExpBuffer(checkoids);
2 alvherre 9031 GNC 118 : destroyPQExpBuffer(defaultoids);
9770 scrappy 9032 GIC 118 : }
9770 scrappy 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
1399 alvherre 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
788 peter 9052 CBC 32712 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
9053 : {
3099 alvherre 9054 32712 : if (dopt->binary_upgrade)
4076 tgl 9055 GIC 5634 : return true;
1399 alvherre 9056 27078 : if (tbinfo->attisdropped[colno])
9057 347 : return false;
9058 26731 : return (tbinfo->attislocal[colno] || tbinfo->ispartition);
9059 : }
4076 tgl 9060 ECB :
9061 :
5710 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 *
4080 rhaas 9070 GIC 118 : getTSParsers(Archive *fout, int *numTSParsers)
9071 : {
5710 tgl 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 :
4044 peter_e 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 :
3429 heikki.linnakangas 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 :
4079 rhaas 9099 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9100 :
5710 tgl 9101 118 : ntups = PQntuples(res);
9102 118 : *numTSParsers = ntups;
9103 :
4153 bruce 9104 118 : prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
9105 :
5710 tgl 9106 CBC 118 : i_tableoid = PQfnumber(res, "tableoid");
5710 tgl 9107 GIC 118 : i_oid = PQfnumber(res, "oid");
5710 tgl 9108 CBC 118 : i_prsname = PQfnumber(res, "prsname");
9109 118 : i_prsnamespace = PQfnumber(res, "prsnamespace");
5710 tgl 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;
5710 tgl 9119 CBC 163 : prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5710 tgl 9120 GIC 163 : prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5710 tgl 9121 CBC 163 : AssignDumpId(&prsinfo[i].dobj);
4153 bruce 9122 163 : prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
4080 rhaas 9123 GIC 326 : prsinfo[i].dobj.namespace =
957 peter 9124 CBC 163 : findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
5710 tgl 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));
5710 tgl 9130 ECB :
9131 : /* Decide whether we want to dump it */
2559 sfrost 9132 GIC 163 : selectDumpableObject(&(prsinfo[i].dobj), fout);
5710 tgl 9133 ECB : }
9134 :
5710 tgl 9135 GIC 118 : PQclear(res);
5710 tgl 9136 ECB :
5710 tgl 9137 CBC 118 : destroyPQExpBuffer(query);
9138 :
5710 tgl 9139 GIC 118 : return prsinfo;
9140 : }
5710 tgl 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 *
4080 rhaas 9150 GIC 118 : getTSDictionaries(Archive *fout, int *numTSDicts)
5710 tgl 9151 ECB : {
9152 : PGresult *res;
9153 : int ntups;
9154 : int i;
4044 peter_e 9155 : PQExpBuffer query;
5710 tgl 9156 EUB : TSDictInfo *dictinfo;
9157 : int i_tableoid;
5710 tgl 9158 ECB : int i_oid;
9159 : int i_dictname;
5710 tgl 9160 EUB : int i_dictnamespace;
9161 : int i_dictowner;
9162 : int i_dicttemplate;
9163 : int i_dictinitoption;
9164 :
4044 peter_e 9165 GBC 118 : query = createPQExpBuffer();
9166 :
215 drowley 9167 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
9168 : "dictnamespace, dictowner, "
9169 : "dicttemplate, dictinitoption "
9170 : "FROM pg_ts_dict");
9171 :
4079 rhaas 9172 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9173 :
5710 tgl 9174 118 : ntups = PQntuples(res);
9175 118 : *numTSDicts = ntups;
5710 tgl 9176 ECB :
4153 bruce 9177 CBC 118 : dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
5710 tgl 9178 ECB :
5710 tgl 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");
464 9183 118 : i_dictowner = PQfnumber(res, "dictowner");
5710 9184 118 : i_dictinitoption = PQfnumber(res, "dictinitoption");
9185 118 : i_dicttemplate = PQfnumber(res, "dicttemplate");
5710 tgl 9186 ECB :
5710 tgl 9187 CBC 3630 : for (i = 0; i < ntups; i++)
5710 tgl 9188 ECB : {
5710 tgl 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);
4153 bruce 9193 3512 : dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
4080 rhaas 9194 7024 : dictinfo[i].dobj.namespace =
957 peter 9195 CBC 3512 : findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
464 tgl 9196 GIC 3512 : dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
5710 tgl 9197 CBC 3512 : dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
5710 tgl 9198 GIC 3512 : if (PQgetisnull(res, i, i_dictinitoption))
9199 163 : dictinfo[i].dictinitoption = NULL;
9200 : else
4153 bruce 9201 3349 : dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
9202 :
9203 : /* Decide whether we want to dump it */
2559 sfrost 9204 3512 : selectDumpableObject(&(dictinfo[i].dobj), fout);
9205 : }
9206 :
5710 tgl 9207 118 : PQclear(res);
5710 tgl 9208 ECB :
5710 tgl 9209 CBC 118 : destroyPQExpBuffer(query);
5710 tgl 9210 ECB :
5710 tgl 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 : *
5710 tgl 9219 ECB : * numTSTemplates is set to the number of templates read in
9220 : */
9221 : TSTemplateInfo *
4080 rhaas 9222 GIC 118 : getTSTemplates(Archive *fout, int *numTSTemplates)
9223 : {
9224 : PGresult *res;
9225 : int ntups;
9226 : int i;
9227 : PQExpBuffer query;
9228 : TSTemplateInfo *tmplinfo;
5710 tgl 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 :
4044 peter_e 9236 GIC 118 : query = createPQExpBuffer();
9237 :
3429 heikki.linnakangas 9238 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
9239 : "tmplnamespace, tmplinit::oid, tmpllexize::oid "
3429 heikki.linnakangas 9240 ECB : "FROM pg_ts_template");
9241 :
4079 rhaas 9242 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9243 :
5710 tgl 9244 118 : ntups = PQntuples(res);
9245 118 : *numTSTemplates = ntups;
9246 :
4153 bruce 9247 CBC 118 : tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
5710 tgl 9248 ECB :
5710 tgl 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;
5710 tgl 9259 CBC 635 : tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5710 tgl 9260 GIC 635 : tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5710 tgl 9261 CBC 635 : AssignDumpId(&tmplinfo[i].dobj);
4153 bruce 9262 635 : tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
4080 rhaas 9263 GIC 1270 : tmplinfo[i].dobj.namespace =
957 peter 9264 CBC 635 : findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
5710 tgl 9265 635 : tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
9266 635 : tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
5710 tgl 9267 ECB :
9268 : /* Decide whether we want to dump it */
2559 sfrost 9269 CBC 635 : selectDumpableObject(&(tmplinfo[i].dobj), fout);
9270 : }
9271 :
5710 tgl 9272 118 : PQclear(res);
5710 tgl 9273 ECB :
5710 tgl 9274 GIC 118 : destroyPQExpBuffer(query);
5710 tgl 9275 EUB :
5710 tgl 9276 GBC 118 : return tmplinfo;
9277 : }
9278 :
9279 : /*
5710 tgl 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 *
4080 rhaas 9287 GIC 118 : getTSConfigurations(Archive *fout, int *numTSConfigs)
5710 tgl 9288 EUB : {
9289 : PGresult *res;
9290 : int ntups;
9291 : int i;
4044 peter_e 9292 : PQExpBuffer query;
9293 : TSConfigInfo *cfginfo;
5710 tgl 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 :
4044 peter_e 9301 GBC 118 : query = createPQExpBuffer();
4044 peter_e 9302 EUB :
215 drowley 9303 GNC 118 : appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
9304 : "cfgnamespace, cfgowner, cfgparser "
9305 : "FROM pg_ts_config");
5710 tgl 9306 EUB :
4079 rhaas 9307 GBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5710 tgl 9308 EUB :
5710 tgl 9309 GBC 118 : ntups = PQntuples(res);
9310 118 : *numTSConfigs = ntups;
5710 tgl 9311 EUB :
4153 bruce 9312 GBC 118 : cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
5710 tgl 9313 EUB :
5710 tgl 9314 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
5710 tgl 9315 GBC 118 : i_oid = PQfnumber(res, "oid");
5710 tgl 9316 GIC 118 : i_cfgname = PQfnumber(res, "cfgname");
5710 tgl 9317 GBC 118 : i_cfgnamespace = PQfnumber(res, "cfgnamespace");
464 tgl 9318 GIC 118 : i_cfgowner = PQfnumber(res, "cfgowner");
5710 9319 118 : i_cfgparser = PQfnumber(res, "cfgparser");
9320 :
5710 tgl 9321 CBC 3605 : for (i = 0; i < ntups; i++)
9322 : {
5710 tgl 9323 GIC 3487 : cfginfo[i].dobj.objType = DO_TSCONFIG;
5710 tgl 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);
4153 bruce 9327 3487 : cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
4080 rhaas 9328 6974 : cfginfo[i].dobj.namespace =
957 peter 9329 GIC 3487 : findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
464 tgl 9330 3487 : cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
5710 9331 3487 : cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
9332 :
9333 : /* Decide whether we want to dump it */
2559 sfrost 9334 3487 : selectDumpableObject(&(cfginfo[i].dobj), fout);
9335 : }
9336 :
5710 tgl 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
5224 peter_e 9348 ECB : *
9349 : * numForeignDataWrappers is set to the number of fdws read in
9350 : */
9351 : FdwInfo *
4080 rhaas 9352 CBC 118 : getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
5224 peter_e 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;
489 tgl 9366 : int i_acldefault;
9367 : int i_fdwoptions;
9368 :
3347 sfrost 9369 GIC 118 : query = createPQExpBuffer();
9370 :
215 drowley 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 :
4079 rhaas 9385 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9386 :
5224 peter_e 9387 118 : ntups = PQntuples(res);
9388 118 : *numForeignDataWrappers = ntups;
9389 :
4153 bruce 9390 CBC 118 : fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
9391 :
4581 heikki.linnakangas 9392 GIC 118 : i_tableoid = PQfnumber(res, "tableoid");
5224 peter_e 9393 118 : i_oid = PQfnumber(res, "oid");
9394 118 : i_fdwname = PQfnumber(res, "fdwname");
464 tgl 9395 CBC 118 : i_fdwowner = PQfnumber(res, "fdwowner");
4432 tgl 9396 GIC 118 : i_fdwhandler = PQfnumber(res, "fdwhandler");
5157 peter_e 9397 CBC 118 : i_fdwvalidator = PQfnumber(res, "fdwvalidator");
5224 9398 118 : i_fdwacl = PQfnumber(res, "fdwacl");
489 tgl 9399 GIC 118 : i_acldefault = PQfnumber(res, "acldefault");
5224 peter_e 9400 CBC 118 : i_fdwoptions = PQfnumber(res, "fdwoptions");
9401 :
9402 170 : for (i = 0; i < ntups; i++)
5224 peter_e 9403 ECB : {
5224 peter_e 9404 CBC 52 : fdwinfo[i].dobj.objType = DO_FDW;
4581 heikki.linnakangas 9405 52 : fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5224 peter_e 9406 52 : fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9407 52 : AssignDumpId(&fdwinfo[i].dobj);
4153 bruce 9408 52 : fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
5224 peter_e 9409 52 : fdwinfo[i].dobj.namespace = NULL;
489 tgl 9410 52 : fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
489 tgl 9411 GIC 52 : fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
489 tgl 9412 CBC 52 : fdwinfo[i].dacl.privtype = 0;
489 tgl 9413 GIC 52 : fdwinfo[i].dacl.initprivs = NULL;
464 tgl 9414 CBC 52 : fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
4153 bruce 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));
5224 peter_e 9418 ECB :
9419 : /* Decide whether we want to dump it */
2559 sfrost 9420 CBC 52 : selectDumpableObject(&(fdwinfo[i].dobj), fout);
2559 sfrost 9421 ECB :
489 tgl 9422 : /* Mark whether FDW has an ACL */
489 tgl 9423 CBC 52 : if (!PQgetisnull(res, i, i_fdwacl))
9424 45 : fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5224 peter_e 9425 ECB : }
9426 :
5224 peter_e 9427 GIC 118 : PQclear(res);
5224 peter_e 9428 ECB :
5224 peter_e 9429 GIC 118 : destroyPQExpBuffer(query);
9430 :
5224 peter_e 9431 CBC 118 : return fdwinfo;
9432 : }
5224 peter_e 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 *
4080 rhaas 9442 GIC 118 : getForeignServers(Archive *fout, int *numForeignServers)
9443 : {
9444 : PGresult *res;
9445 : int ntups;
5224 peter_e 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 :
3347 sfrost 9460 GIC 118 : query = createPQExpBuffer();
3347 sfrost 9461 ECB :
215 drowley 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");
5224 peter_e 9473 ECB :
4079 rhaas 9474 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5224 peter_e 9475 ECB :
5224 peter_e 9476 CBC 118 : ntups = PQntuples(res);
9477 118 : *numForeignServers = ntups;
5224 peter_e 9478 ECB :
4153 bruce 9479 CBC 118 : srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
5224 peter_e 9480 ECB :
4581 heikki.linnakangas 9481 CBC 118 : i_tableoid = PQfnumber(res, "tableoid");
5224 peter_e 9482 GIC 118 : i_oid = PQfnumber(res, "oid");
5224 peter_e 9483 CBC 118 : i_srvname = PQfnumber(res, "srvname");
464 tgl 9484 GIC 118 : i_srvowner = PQfnumber(res, "srvowner");
5224 peter_e 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");
489 tgl 9489 118 : i_acldefault = PQfnumber(res, "acldefault");
5224 peter_e 9490 118 : i_srvoptions = PQfnumber(res, "srvoptions");
5224 peter_e 9491 ECB :
5224 peter_e 9492 CBC 174 : for (i = 0; i < ntups; i++)
5224 peter_e 9493 ECB : {
5224 peter_e 9494 CBC 56 : srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
4581 heikki.linnakangas 9495 56 : srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5224 peter_e 9496 GIC 56 : srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5224 peter_e 9497 CBC 56 : AssignDumpId(&srvinfo[i].dobj);
4153 bruce 9498 GIC 56 : srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
5224 peter_e 9499 56 : srvinfo[i].dobj.namespace = NULL;
489 tgl 9500 CBC 56 : srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
489 tgl 9501 GIC 56 : srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9502 56 : srvinfo[i].dacl.privtype = 0;
489 tgl 9503 CBC 56 : srvinfo[i].dacl.initprivs = NULL;
464 tgl 9504 GIC 56 : srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
5224 peter_e 9505 CBC 56 : srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
4153 bruce 9506 GIC 56 : srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
4153 bruce 9507 CBC 56 : srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
4153 bruce 9508 GIC 56 : srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9509 :
9510 : /* Decide whether we want to dump it */
2559 sfrost 9511 56 : selectDumpableObject(&(srvinfo[i].dobj), fout);
9512 :
9513 : /* Servers have user mappings */
489 tgl 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))
489 tgl 9518 CBC 45 : srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9519 : }
9520 :
5224 peter_e 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
4934 tgl 9532 ECB : *
9533 : * numDefaultACLs is set to the number of ACLs read in
9534 : */
9535 : DefaultACLInfo *
2643 tgl 9536 GIC 118 : getDefaultACLs(Archive *fout, int *numDefaultACLs)
9537 : {
2643 tgl 9538 CBC 118 : DumpOptions *dopt = fout->dopt;
9539 : DefaultACLInfo *daclinfo;
4934 tgl 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;
489 9548 : int i_acldefault;
4934 9549 : int i,
9550 : ntups;
9551 :
4934 tgl 9552 CBC 118 : query = createPQExpBuffer();
9553 :
481 tgl 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 : */
215 drowley 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 :
4079 rhaas 9578 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9579 :
4934 tgl 9580 118 : ntups = PQntuples(res);
9581 118 : *numDefaultACLs = ntups;
9582 :
4153 bruce 9583 CBC 118 : daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9584 :
4934 tgl 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");
489 9591 118 : i_acldefault = PQfnumber(res, "acldefault");
9592 :
4934 9593 298 : for (i = 0; i < ntups; i++)
9594 : {
4790 bruce 9595 180 : Oid nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9596 :
4934 tgl 9597 CBC 180 : daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
4934 tgl 9598 GIC 180 : daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4934 tgl 9599 CBC 180 : daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4934 tgl 9600 GIC 180 : AssignDumpId(&daclinfo[i].dobj);
9601 : /* cheesy ... is it worth coming up with a better object name? */
4153 bruce 9602 180 : daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
4934 tgl 9603 ECB :
4934 tgl 9604 GIC 180 : if (nspid != InvalidOid)
957 peter 9605 CBC 90 : daclinfo[i].dobj.namespace = findNamespace(nspid);
4934 tgl 9606 ECB : else
4934 tgl 9607 GIC 90 : daclinfo[i].dobj.namespace = NULL;
4934 tgl 9608 ECB :
489 tgl 9609 GIC 180 : daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
489 tgl 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;
464 9613 180 : daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
4934 9614 180 : daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
4934 tgl 9615 ECB :
9616 : /* Default ACLs are ACLs, of course */
489 tgl 9617 CBC 180 : daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9618 :
4934 tgl 9619 ECB : /* Decide whether we want to dump it */
2643 tgl 9620 CBC 180 : selectDumpableDefaultACL(&(daclinfo[i]), dopt);
4934 tgl 9621 ECB : }
9622 :
4934 tgl 9623 CBC 118 : PQclear(res);
4934 tgl 9624 ECB :
4934 tgl 9625 CBC 118 : destroyPQExpBuffer(query);
4934 tgl 9626 ECB :
4934 tgl 9627 CBC 118 : return daclinfo;
9628 : }
9629 :
464 tgl 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 *
464 tgl 9636 GIC 447209 : getRoleName(const char *roleoid_str)
464 tgl 9637 ECB : {
464 tgl 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 :
464 tgl 9648 CBC 1789024 : while (low <= high)
9649 : {
464 tgl 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 :
366 tgl 9661 UIC 0 : pg_fatal("role with OID %u does not exist", roleoid);
9662 : return NULL; /* keep compiler quiet */
9663 : }
9664 :
464 tgl 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
464 tgl 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);
464 tgl 9681 ECB :
464 tgl 9682 GIC 119 : nrolenames = PQntuples(res);
464 tgl 9683 ECB :
464 tgl 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));
464 tgl 9690 ECB : }
9691 :
464 tgl 9692 CBC 119 : PQclear(res);
9693 119 : }
464 tgl 9694 ECB :
489 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
489 tgl 9707 CBC 116 : getAdditionalACLs(Archive *fout)
489 tgl 9708 ECB : {
489 tgl 9709 CBC 116 : PQExpBuffer query = createPQExpBuffer();
489 tgl 9710 ECB : PGresult *res;
9711 : int ntups,
9712 : i;
9713 :
9714 : /* Check for per-column ACLs */
481 tgl 9715 GIC 116 : appendPQExpBufferStr(query,
481 tgl 9716 ECB : "SELECT DISTINCT attrelid FROM pg_attribute "
9717 : "WHERE attacl IS NOT NULL");
9718 :
481 tgl 9719 CBC 116 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
489 tgl 9720 ECB :
481 tgl 9721 GIC 116 : ntups = PQntuples(res);
9722 351 : for (i = 0; i < ntups; i++)
481 tgl 9723 ECB : {
481 tgl 9724 GIC 235 : Oid relid = atooid(PQgetvalue(res, i, 0));
481 tgl 9725 ECB : TableInfo *tblinfo;
9726 :
481 tgl 9727 CBC 235 : tblinfo = findTableByOid(relid);
9728 : /* OK to ignore tables we haven't got a DumpableObject for */
481 tgl 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 */
489 tgl 9738 CBC 116 : if (fout->remoteVersion >= 90600)
9739 : {
489 tgl 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;
489 tgl 9756 ECB :
489 tgl 9757 GIC 25747 : objId.tableoid = classoid;
489 tgl 9758 CBC 25747 : objId.oid = objoid;
489 tgl 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;
489 tgl 9770 CBC 1877 : ((TableInfo *) dobj)->hascolumnACLs = true;
9771 : }
489 tgl 9772 ECB : else
489 tgl 9773 LBC 0 : pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
9774 : classoid, objoid, objsubid);
489 tgl 9775 CBC 1989 : continue;
9776 : }
489 tgl 9777 ECB :
9778 : /*
9779 : * We ignore any pg_init_privs.initprivs entry for the public
9780 : * schema, as explained in getNamespaces().
9781 : */
489 tgl 9782 CBC 16722 : if (dobj->objType == DO_NAMESPACE &&
9783 228 : strcmp(dobj->name, "public") == 0)
9784 112 : continue;
489 tgl 9785 ECB :
9786 : /* Else it had better be of a type we think has ACLs */
489 tgl 9787 GIC 16610 : if (dobj->objType == DO_NAMESPACE ||
489 tgl 9788 CBC 16494 : dobj->objType == DO_TYPE ||
489 tgl 9789 GIC 16473 : dobj->objType == DO_FUNC ||
489 tgl 9790 CBC 16387 : dobj->objType == DO_AGG ||
9791 16366 : dobj->objType == DO_TABLE ||
489 tgl 9792 LBC 0 : dobj->objType == DO_PROCLANG ||
9793 0 : dobj->objType == DO_FDW ||
9794 0 : dobj->objType == DO_FOREIGN_SERVER)
489 tgl 9795 CBC 16610 : {
9796 16610 : DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
489 tgl 9797 ECB :
489 tgl 9798 CBC 16610 : daobj->dacl.privtype = privtype;
9799 16610 : daobj->dacl.initprivs = pstrdup(initprivs);
489 tgl 9800 ECB : }
9801 : else
489 tgl 9802 LBC 0 : pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
489 tgl 9803 ECB : classoid, objoid, objsubid);
9804 : }
9805 : }
489 tgl 9806 GIC 116 : PQclear(res);
489 tgl 9807 ECB : }
9808 :
489 tgl 9809 GIC 116 : destroyPQExpBuffer(query);
489 tgl 9810 CBC 116 : }
9811 :
9812 : /*
650 noah 9813 ECB : * dumpCommentExtended --
8482 bruce 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
1868 tgl 9817 : * and object name (ready to print, except for schema decoration), plus
9818 : * the namespace and owner of the object (for labeling the ArchiveEntry),
7064 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).
7912 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
6690 9832 : * after dependency sorting occurs. This routine should be called just after
9833 : * calling ArchiveEntry() for the specified object.
7639 9834 : */
9835 : static void
650 noah 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 : {
2643 tgl 9842 742 : DumpOptions *dopt = fout->dopt;
9843 : CommentItem *comments;
9844 : int ncomments;
9845 :
9846 : /* do nothing, if --no-comments is supplied */
1900 9847 742 : if (dopt->no_comments)
1900 tgl 9848 LBC 0 : return;
9849 :
9850 : /* Comments are schema not data ... except LO comments are data */
1868 tgl 9851 GIC 742 : if (strcmp(type, "LARGE OBJECT") != 0)
9852 : {
3099 alvherre 9853 695 : if (dopt->dataOnly)
4798 tgl 9854 UIC 0 : return;
9855 : }
9856 : else
9857 : {
9858 : /* We do dump LO comments in binary-upgrade mode */
2225 sfrost 9859 GIC 47 : if (dopt->schemaOnly && !dopt->binary_upgrade)
4798 tgl 9860 UIC 0 : return;
9861 : }
8002 pjw 9862 ECB :
9863 : /* Search for comments associated with catalogId, using table */
465 tgl 9864 GIC 742 : ncomments = findComments(catalogId.tableoid, catalogId.oid,
9865 : &comments);
9866 :
9867 : /* Is there one matching the subid? */
6959 9868 742 : while (ncomments > 0)
9869 : {
9870 702 : if (comments->objsubid == subid)
9871 702 : break;
6959 tgl 9872 UIC 0 : comments++;
9873 0 : ncomments--;
7912 tgl 9874 ECB : }
9875 :
650 noah 9876 CBC 742 : if (initdb_comment != NULL)
650 noah 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 : */
650 noah 9886 CBC 93 : if (ncomments == 0)
650 noah 9887 ECB : {
650 noah 9888 GIC 4 : comments = &empty_comment;
650 noah 9889 CBC 4 : ncomments = 1;
9890 : }
9891 89 : else if (strcmp(comments->descr, initdb_comment) == 0)
650 noah 9892 GIC 89 : ncomments = 0;
650 noah 9893 ECB : }
9894 :
7360 bruce 9895 : /* If a comment exists, build COMMENT ON statement */
6959 tgl 9896 CBC 742 : if (ncomments > 0)
9897 : {
9898 617 : PQExpBuffer query = createPQExpBuffer();
1868 tgl 9899 GIC 617 : PQExpBuffer tag = createPQExpBuffer();
6959 tgl 9900 ECB :
1868 tgl 9901 CBC 617 : appendPQExpBuffer(query, "COMMENT ON %s ", type);
1868 tgl 9902 GIC 617 : if (namespace && *namespace)
1868 tgl 9903 CBC 471 : appendPQExpBuffer(query, "%s.", fmtId(namespace));
1868 tgl 9904 GIC 617 : appendPQExpBuffer(query, "%s IS ", name);
6160 tgl 9905 CBC 617 : appendStringLiteralAH(query, comments->descr, fout);
3429 heikki.linnakangas 9906 617 : appendPQExpBufferStr(query, ";\n");
8314 bruce 9907 ECB :
1868 tgl 9908 CBC 617 : appendPQExpBuffer(tag, "%s %s", type, name);
1868 tgl 9909 ECB :
5179 andrew 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
5050 bruce 9913 : * post-data.
9914 : */
7064 tgl 9915 GIC 617 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 9916 CBC 617 : ARCHIVE_OPTS(.tag = tag->data,
9917 : .namespace = namespace,
9918 : .owner = owner,
1528 alvherre 9919 ECB : .description = "COMMENT",
9920 : .section = SECTION_NONE,
9921 : .createStmt = query->data,
9922 : .deps = &dumpId,
9923 : .nDeps = 1));
9924 :
6959 tgl 9925 GIC 617 : destroyPQExpBuffer(query);
1868 9926 617 : destroyPQExpBuffer(tag);
9927 : }
9928 : }
9929 :
9930 : /*
9931 : * dumpComment --
650 noah 9932 ECB : *
9933 : * Typical simplification of the above function.
9934 : */
9935 : static inline void
650 noah 9936 GIC 641 : dumpComment(Archive *fout, const char *type,
9937 : const char *name, const char *namespace,
9938 : const char *owner, CatalogId catalogId,
650 noah 9939 ECB : int subid, DumpId dumpId)
9940 : {
650 noah 9941 CBC 641 : dumpCommentExtended(fout, type, name, namespace, owner,
650 noah 9942 ECB : catalogId, subid, dumpId, NULL);
650 noah 9943 GIC 641 : }
650 noah 9944 ECB :
9945 : /*
7639 tgl 9946 : * dumpTableComment --
9947 : *
6820 9948 : * As above, but dump comments for both the specified table (or view)
6959 9949 : * and its columns.
7639 9950 : */
9951 : static void
788 peter 9952 GIC 82 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
7064 tgl 9953 ECB : const char *reltypename)
9954 : {
2643 tgl 9955 GIC 82 : DumpOptions *dopt = fout->dopt;
9956 : CommentItem *comments;
6959 tgl 9957 EUB : int ncomments;
9958 : PQExpBuffer query;
9959 : PQExpBuffer tag;
9960 :
9961 : /* do nothing, if --no-comments is supplied */
1900 tgl 9962 GIC 82 : if (dopt->no_comments)
1900 tgl 9963 UIC 0 : return;
9964 :
9965 : /* Comments are SCHEMA not data */
3099 alvherre 9966 GIC 82 : if (dopt->dataOnly)
7639 tgl 9967 UIC 0 : return;
7639 tgl 9968 ECB :
9969 : /* Search for comments associated with relation, using table */
465 tgl 9970 GIC 82 : ncomments = findComments(tbinfo->dobj.catId.tableoid,
6959 9971 82 : tbinfo->dobj.catId.oid,
9972 : &comments);
9973 :
6959 tgl 9974 ECB : /* If comments exist, build COMMENT ON statements */
6959 tgl 9975 GIC 82 : if (ncomments <= 0)
6959 tgl 9976 LBC 0 : return;
9977 :
7639 tgl 9978 CBC 82 : query = createPQExpBuffer();
1868 tgl 9979 GIC 82 : tag = createPQExpBuffer();
7639 tgl 9980 ECB :
6959 tgl 9981 GIC 236 : while (ncomments > 0)
7639 tgl 9982 ECB : {
6959 tgl 9983 GIC 154 : const char *descr = comments->descr;
6959 tgl 9984 CBC 154 : int objsubid = comments->objsubid;
7639 tgl 9985 ECB :
7639 tgl 9986 GIC 154 : if (objsubid == 0)
9987 : {
1868 tgl 9988 CBC 36 : resetPQExpBuffer(tag);
9989 36 : appendPQExpBuffer(tag, "%s %s", reltypename,
6976 tgl 9990 GIC 36 : fmtId(tbinfo->dobj.name));
9991 :
7639 9992 36 : resetPQExpBuffer(query);
1868 9993 36 : appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9994 36 : fmtQualifiedDumpable(tbinfo));
6160 9995 36 : appendStringLiteralAH(query, descr, fout);
3429 heikki.linnakangas 9996 36 : appendPQExpBufferStr(query, ";\n");
9997 :
7064 tgl 9998 36 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 9999 36 : ARCHIVE_OPTS(.tag = tag->data,
10000 : .namespace = tbinfo->dobj.namespace->dobj.name,
10001 : .owner = tbinfo->rolname,
10002 : .description = "COMMENT",
1528 alvherre 10003 ECB : .section = SECTION_NONE,
10004 : .createStmt = query->data,
10005 : .deps = &(tbinfo->dobj.dumpId),
10006 : .nDeps = 1));
10007 : }
7639 tgl 10008 GIC 118 : else if (objsubid > 0 && objsubid <= tbinfo->numatts)
10009 : {
1868 10010 118 : resetPQExpBuffer(tag);
1868 tgl 10011 CBC 118 : appendPQExpBuffer(tag, "COLUMN %s.",
6976 tgl 10012 GIC 118 : fmtId(tbinfo->dobj.name));
1868 10013 118 : appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
10014 :
7639 tgl 10015 CBC 118 : resetPQExpBuffer(query);
1868 tgl 10016 GIC 118 : appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
1868 tgl 10017 CBC 118 : fmtQualifiedDumpable(tbinfo));
10018 118 : appendPQExpBuffer(query, "%s IS ",
1868 tgl 10019 GIC 118 : fmtId(tbinfo->attnames[objsubid - 1]));
6160 tgl 10020 CBC 118 : appendStringLiteralAH(query, descr, fout);
3429 heikki.linnakangas 10021 GIC 118 : appendPQExpBufferStr(query, ";\n");
10022 :
7064 tgl 10023 CBC 118 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 10024 GIC 118 : ARCHIVE_OPTS(.tag = tag->data,
1528 alvherre 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 :
6959 tgl 10034 CBC 154 : comments++;
6959 tgl 10035 GIC 154 : ncomments--;
7639 tgl 10036 ECB : }
10037 :
7919 tgl 10038 GIC 82 : destroyPQExpBuffer(query);
1868 10039 82 : destroyPQExpBuffer(tag);
8482 bruce 10040 ECB : }
10041 :
6959 tgl 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
465 tgl 10050 GIC 860 : findComments(Oid classoid, Oid objoid, CommentItem **items)
10051 : {
6959 10052 860 : CommentItem *middle = NULL;
6959 tgl 10053 ECB : CommentItem *low;
10054 : CommentItem *high;
10055 : int nmatch;
10056 :
10057 : /*
10058 : * Do binary search to find some item matching the object.
10059 : */
6959 tgl 10060 CBC 860 : low = &comments[0];
6797 bruce 10061 GIC 860 : high = &comments[ncomments - 1];
6959 tgl 10062 CBC 8410 : while (low <= high)
10063 : {
6959 tgl 10064 GIC 8370 : middle = low + (high - low) / 2;
6959 tgl 10065 ECB :
6959 tgl 10066 CBC 8370 : if (classoid < middle->classoid)
6959 tgl 10067 GIC 3522 : high = middle - 1;
10068 4848 : else if (classoid > middle->classoid)
6959 tgl 10069 GBC 2370 : low = middle + 1;
6959 tgl 10070 GIC 2478 : else if (objoid < middle->objoid)
6959 tgl 10071 CBC 199 : high = middle - 1;
6959 tgl 10072 GIC 2279 : else if (objoid > middle->objoid)
10073 1459 : low = middle + 1;
10074 : else
10075 820 : break; /* found a match */
10076 : }
10077 :
6959 tgl 10078 CBC 860 : if (low > high) /* no matches */
6959 tgl 10079 ECB : {
6959 tgl 10080 CBC 40 : *items = NULL;
6959 tgl 10081 GIC 40 : return 0;
10082 : }
6959 tgl 10083 ECB :
10084 : /*
10085 : * Now determine how many items match the object. The search loop
6385 bruce 10086 : * invariant still holds: only items between low and high inclusive could
10087 : * match.
6959 tgl 10088 EUB : */
6959 tgl 10089 GBC 820 : nmatch = 1;
10090 820 : while (middle > low)
6959 tgl 10091 ECB : {
6959 tgl 10092 CBC 497 : if (classoid != middle[-1].classoid ||
6959 tgl 10093 GIC 412 : objoid != middle[-1].objoid)
6959 tgl 10094 ECB : break;
6959 tgl 10095 LBC 0 : middle--;
6959 tgl 10096 UIC 0 : nmatch++;
10097 : }
6959 tgl 10098 EUB :
6959 tgl 10099 GIC 820 : *items = middle;
10100 :
10101 820 : middle += nmatch;
6959 tgl 10102 CBC 892 : while (middle <= high)
10103 : {
6959 tgl 10104 GIC 539 : if (classoid != middle->classoid ||
6959 tgl 10105 CBC 164 : objoid != middle->objoid)
6959 tgl 10106 ECB : break;
6959 tgl 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
489 10127 118 : collectComments(Archive *fout)
10128 : {
10129 : PGresult *res;
10130 : PQExpBuffer query;
10131 : int i_description;
6959 tgl 10132 ECB : int i_classoid;
10133 : int i_objoid;
10134 : int i_objsubid;
10135 : int ntups;
10136 : int i;
10137 : DumpableObject *dobj;
10138 :
6959 tgl 10139 GIC 118 : query = createPQExpBuffer();
10140 :
2370 10141 118 : appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
10142 : "FROM pg_catalog.pg_description "
2370 tgl 10143 ECB : "ORDER BY classoid, objoid, objsubid");
6959 tgl 10144 EUB :
4079 rhaas 10145 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10146 :
6959 tgl 10147 ECB : /* Construct lookup table containing OIDs in numeric form */
10148 :
6959 tgl 10149 CBC 118 : i_description = PQfnumber(res, "description");
6959 tgl 10150 GBC 118 : i_classoid = PQfnumber(res, "classoid");
6959 tgl 10151 GIC 118 : i_objoid = PQfnumber(res, "objoid");
10152 118 : i_objsubid = PQfnumber(res, "objsubid");
10153 :
10154 118 : ntups = PQntuples(res);
6959 tgl 10155 ECB :
4153 bruce 10156 GBC 118 : comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
489 tgl 10157 GIC 118 : ncomments = 0;
10158 118 : dobj = NULL;
10159 :
6959 tgl 10160 CBC 614578 : for (i = 0; i < ntups; i++)
10161 : {
10162 : CatalogId objId;
10163 : int subid;
489 tgl 10164 ECB :
489 tgl 10165 GIC 614460 : objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
489 tgl 10166 CBC 614460 : objId.oid = atooid(PQgetvalue(res, i, i_objoid));
10167 614460 : subid = atoi(PQgetvalue(res, i, i_objsubid));
489 tgl 10168 EUB :
10169 : /* We needn't remember comments that don't match any dumpable object */
489 tgl 10170 GIC 614460 : if (dobj == NULL ||
10171 226096 : dobj->catId.tableoid != objId.tableoid ||
489 tgl 10172 CBC 224565 : dobj->catId.oid != objId.oid)
489 tgl 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 : */
489 tgl 10182 CBC 226210 : if (subid != 0 && dobj->objType == DO_TABLE &&
489 tgl 10183 GIC 190 : ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
489 tgl 10184 CBC 45 : {
489 tgl 10185 ECB : TypeInfo *cTypeInfo;
10186 :
489 tgl 10187 CBC 45 : cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
10188 45 : if (cTypeInfo)
489 tgl 10189 GIC 45 : cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
10190 : }
10191 : else
489 tgl 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;
489 tgl 10196 GIC 226210 : comments[ncomments].objoid = objId.oid;
489 tgl 10197 CBC 226210 : comments[ncomments].objsubid = subid;
10198 226210 : ncomments++;
6959 tgl 10199 ECB : }
10200 :
489 tgl 10201 CBC 118 : PQclear(res);
6959 10202 118 : destroyPQExpBuffer(query);
6959 tgl 10203 GIC 118 : }
6959 tgl 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 : */
7064 10211 : static void
489 tgl 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 : */
489 tgl 10219 GIC 510020 : dobj->dump &= dobj->components;
10220 :
489 tgl 10221 ECB : /* Now, short-circuit if there's nothing to be done here. */
489 tgl 10222 CBC 510020 : if (dobj->dump == 0)
489 tgl 10223 GIC 462464 : return;
10224 :
7064 10225 47556 : switch (dobj->objType)
10226 : {
10227 339 : case DO_NAMESPACE:
788 peter 10228 339 : dumpNamespace(fout, (const NamespaceInfo *) dobj);
7064 tgl 10229 339 : break;
4443 10230 18 : case DO_EXTENSION:
788 peter 10231 18 : dumpExtension(fout, (const ExtensionInfo *) dobj);
4443 tgl 10232 CBC 18 : break;
7064 tgl 10233 GIC 523 : case DO_TYPE:
788 peter 10234 523 : dumpType(fout, (const TypeInfo *) dobj);
7064 tgl 10235 523 : break;
6247 10236 74 : case DO_SHELL_TYPE:
788 peter 10237 CBC 74 : dumpShellType(fout, (const ShellTypeInfo *) dobj);
6247 tgl 10238 GIC 74 : break;
7064 tgl 10239 CBC 1715 : case DO_FUNC:
788 peter 10240 GIC 1715 : dumpFunc(fout, (const FuncInfo *) dobj);
7064 tgl 10241 1715 : break;
10242 292 : case DO_AGG:
788 peter 10243 292 : dumpAgg(fout, (const AggInfo *) dobj);
7064 tgl 10244 292 : break;
10245 108 : case DO_OPERATOR:
788 peter 10246 108 : dumpOpr(fout, (const OprInfo *) dobj);
7064 tgl 10247 108 : break;
2573 alvherre 10248 CBC 82 : case DO_ACCESS_METHOD:
788 peter 10249 GIC 82 : dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
2573 alvherre 10250 82 : break;
7064 tgl 10251 CBC 132 : case DO_OPCLASS:
788 peter 10252 GIC 132 : dumpOpclass(fout, (const OpclassInfo *) dobj);
7064 tgl 10253 132 : break;
5920 10254 113 : case DO_OPFAMILY:
788 peter 10255 113 : dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
5920 tgl 10256 113 : break;
4439 peter_e 10257 81 : case DO_COLLATION:
788 peter 10258 CBC 81 : dumpCollation(fout, (const CollInfo *) dobj);
4439 peter_e 10259 GBC 81 : break;
7064 tgl 10260 GIC 39 : case DO_CONVERSION:
788 peter 10261 39 : dumpConversion(fout, (const ConvInfo *) dobj);
7064 tgl 10262 CBC 39 : break;
7064 tgl 10263 GBC 20378 : case DO_TABLE:
788 peter 10264 GIC 20378 : dumpTable(fout, (const TableInfo *) dobj);
7064 tgl 10265 20378 : break;
818 tgl 10266 CBC 1166 : case DO_TABLE_ATTACH:
788 peter 10267 1166 : dumpTableAttach(fout, (const TableAttachInfo *) dobj);
818 tgl 10268 GIC 1166 : break;
7064 10269 793 : case DO_ATTRDEF:
788 peter 10270 793 : dumpAttrDef(fout, (const AttrDefInfo *) dobj);
7064 tgl 10271 CBC 793 : break;
7064 tgl 10272 GBC 1842 : case DO_INDEX:
788 peter 10273 GIC 1842 : dumpIndex(fout, (const IndxInfo *) dobj);
7064 tgl 10274 CBC 1842 : break;
1906 alvherre 10275 567 : case DO_INDEX_ATTACH:
788 peter 10276 GIC 567 : dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
1906 alvherre 10277 CBC 567 : break;
2207 alvherre 10278 GIC 137 : case DO_STATSEXT:
788 peter 10279 CBC 137 : dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
2207 alvherre 10280 137 : break;
3689 kgrittn 10281 GIC 328 : case DO_REFRESH_MATVIEW:
788 peter 10282 CBC 328 : refreshMatViewData(fout, (const TableDataInfo *) dobj);
3689 kgrittn 10283 GIC 328 : break;
7064 tgl 10284 CBC 821 : case DO_RULE:
788 peter 10285 821 : dumpRule(fout, (const RuleInfo *) dobj);
7064 tgl 10286 821 : break;
7064 tgl 10287 GIC 504 : case DO_TRIGGER:
788 peter 10288 CBC 504 : dumpTrigger(fout, (const TriggerInfo *) dobj);
7064 tgl 10289 504 : break;
3917 rhaas 10290 38 : case DO_EVENT_TRIGGER:
788 peter 10291 38 : dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
3917 rhaas 10292 38 : break;
7064 tgl 10293 GIC 1526 : case DO_CONSTRAINT:
788 peter 10294 CBC 1526 : dumpConstraint(fout, (const ConstraintInfo *) dobj);
7064 tgl 10295 1526 : break;
7064 tgl 10296 GIC 158 : case DO_FK_CONSTRAINT:
788 peter 10297 158 : dumpConstraint(fout, (const ConstraintInfo *) dobj);
7064 tgl 10298 158 : break;
10299 83 : case DO_PROCLANG:
788 peter 10300 83 : dumpProcLang(fout, (const ProcLangInfo *) dobj);
7064 tgl 10301 83 : break;
10302 68 : case DO_CAST:
788 peter 10303 68 : dumpCast(fout, (const CastInfo *) dobj);
7064 tgl 10304 CBC 68 : break;
2905 peter_e 10305 GIC 43 : case DO_TRANSFORM:
788 peter 10306 CBC 43 : dumpTransform(fout, (const TransformInfo *) dobj);
2905 peter_e 10307 43 : break;
2420 10308 338 : case DO_SEQUENCE_SET:
788 peter 10309 338 : dumpSequenceData(fout, (const TableDataInfo *) dobj);
2420 peter_e 10310 GIC 338 : break;
7064 tgl 10311 CBC 3095 : case DO_TABLE_DATA:
788 peter 10312 3095 : dumpTableData(fout, (const TableDataInfo *) dobj);
7064 tgl 10313 3095 : break;
5194 10314 10382 : case DO_DUMMY_TYPE:
5194 tgl 10315 ECB : /* table rowtypes and array types are never dumped separately */
6976 tgl 10316 CBC 10382 : break;
5710 10317 39 : case DO_TSPARSER:
788 peter 10318 GIC 39 : dumpTSParser(fout, (const TSParserInfo *) dobj);
5710 tgl 10319 CBC 39 : break;
10320 84 : case DO_TSDICT:
788 peter 10321 GIC 84 : dumpTSDictionary(fout, (const TSDictInfo *) dobj);
5710 tgl 10322 84 : break;
10323 39 : case DO_TSTEMPLATE:
788 peter 10324 39 : dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
5710 tgl 10325 39 : break;
10326 59 : case DO_TSCONFIG:
788 peter 10327 59 : dumpTSConfig(fout, (const TSConfigInfo *) dobj);
5710 tgl 10328 59 : break;
5224 peter_e 10329 45 : case DO_FDW:
788 peter 10330 CBC 45 : dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
5224 peter_e 10331 45 : break;
5224 peter_e 10332 GIC 49 : case DO_FOREIGN_SERVER:
788 peter 10333 49 : dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
5224 peter_e 10334 CBC 49 : break;
4934 tgl 10335 154 : case DO_DEFAULT_ACL:
788 peter 10336 GIC 154 : dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
4934 tgl 10337 154 : break;
125 peter 10338 GNC 89 : case DO_LARGE_OBJECT:
10339 89 : dumpLO(fout, (const LoInfo *) dobj);
4798 tgl 10340 GIC 89 : break;
125 peter 10341 GNC 42 : case DO_LARGE_OBJECT_DATA:
2559 sfrost 10342 GIC 42 : if (dobj->dump & DUMP_COMPONENT_DATA)
10343 : {
10344 : TocEntry *te;
10345 :
1668 tgl 10346 CBC 42 : te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
1528 alvherre 10347 GIC 42 : ARCHIVE_OPTS(.tag = dobj->name,
1528 alvherre 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
1668 tgl 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 : */
489 tgl 10365 CBC 42 : te->dataLength = INT_MAX;
1668 tgl 10366 ECB : }
6976 tgl 10367 CBC 42 : break;
3055 sfrost 10368 340 : case DO_POLICY:
788 peter 10369 340 : dumpPolicy(fout, (const PolicyInfo *) dobj);
3124 sfrost 10370 GIC 340 : break;
2271 peter_e 10371 CBC 152 : case DO_PUBLICATION:
788 peter 10372 GIC 152 : dumpPublication(fout, (const PublicationInfo *) dobj);
2271 peter_e 10373 152 : break;
2271 peter_e 10374 CBC 256 : case DO_PUBLICATION_REL:
788 peter 10375 GIC 256 : dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
2271 peter_e 10376 CBC 256 : break;
516 akapila 10377 75 : case DO_PUBLICATION_TABLE_IN_SCHEMA:
529 akapila 10378 GIC 75 : dumpPublicationNamespace(fout,
10379 : (const PublicationSchemaInfo *) dobj);
10380 75 : break;
2271 peter_e 10381 114 : case DO_SUBSCRIPTION:
788 peter 10382 114 : dumpSubscription(fout, (const SubscriptionInfo *) dobj);
2271 peter_e 10383 114 : break;
3940 tgl 10384 236 : case DO_PRE_DATA_BOUNDARY:
3940 tgl 10385 ECB : case DO_POST_DATA_BOUNDARY:
10386 : /* never dumped, nothing to do */
3940 tgl 10387 GIC 236 : break;
7639 tgl 10388 ECB : }
10389 : }
10390 :
7639 tgl 10391 EUB : /*
7064 10392 : * dumpNamespace
10393 : * writes out to fout the queries to recreate a user-defined namespace
10394 : */
7064 tgl 10395 ECB : static void
788 peter 10396 GIC 339 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
7639 tgl 10397 ECB : {
2643 tgl 10398 CBC 339 : DumpOptions *dopt = fout->dopt;
10399 : PQExpBuffer q;
7064 tgl 10400 ECB : PQExpBuffer delq;
7621 10401 : char *qnspname;
10402 :
489 10403 : /* Do nothing in data-only dump */
489 tgl 10404 CBC 339 : if (dopt->dataOnly)
7064 tgl 10405 GIC 16 : return;
10406 :
7064 tgl 10407 CBC 323 : q = createPQExpBuffer();
7064 tgl 10408 GIC 323 : delq = createPQExpBuffer();
10409 :
4153 bruce 10410 323 : qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
10411 :
650 noah 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,
650 noah 10423 ECB : "-- *not* creating schema, since initdb creates it\n");
10424 : }
10425 :
3099 alvherre 10426 GIC 323 : if (dopt->binary_upgrade)
1868 tgl 10427 28 : binary_upgrade_extension_member(q, &nspinfo->dobj,
10428 : "SCHEMA", qnspname, NULL);
10429 :
2559 sfrost 10430 323 : if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10431 160 : ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
1528 alvherre 10432 160 : ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
10433 : .owner = nspinfo->rolname,
10434 : .description = "SCHEMA",
1528 alvherre 10435 ECB : .section = SECTION_PRE_DATA,
10436 : .createStmt = q->data,
10437 : .dropStmt = delq->data));
10438 :
10439 : /* Dump Schema Comments and Security Labels */
2559 sfrost 10440 GIC 323 : if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
650 noah 10441 ECB : {
650 noah 10442 GIC 101 : const char *initdb_comment = NULL;
10443 :
10444 101 : if (!nspinfo->create && strcmp(qnspname, "public") == 0)
481 tgl 10445 CBC 93 : initdb_comment = "standard public schema";
650 noah 10446 101 : dumpCommentExtended(fout, "SCHEMA", qnspname,
10447 101 : NULL, nspinfo->rolname,
10448 101 : nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
10449 : initdb_comment);
650 noah 10450 ECB : }
10451 :
2559 sfrost 10452 CBC 323 : if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
1868 tgl 10453 LBC 0 : dumpSecLabel(fout, "SCHEMA", qnspname,
2559 sfrost 10454 0 : NULL, nspinfo->rolname,
2559 sfrost 10455 UIC 0 : nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
2559 sfrost 10456 ECB :
2559 sfrost 10457 GIC 323 : if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
1002 tgl 10458 241 : dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
10459 : qnspname, NULL, NULL,
489 10460 241 : nspinfo->rolname, &nspinfo->dacl);
7138 tgl 10461 ECB :
7064 tgl 10462 CBC 323 : free(qnspname);
7639 tgl 10463 ECB :
7639 tgl 10464 GIC 323 : destroyPQExpBuffer(q);
10465 323 : destroyPQExpBuffer(delq);
7639 tgl 10466 ECB : }
10467 :
4443 10468 : /*
10469 : * dumpExtension
10470 : * writes out to fout the queries to recreate an extension
10471 : */
10472 : static void
788 peter 10473 GIC 18 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
10474 : {
2643 tgl 10475 18 : DumpOptions *dopt = fout->dopt;
10476 : PQExpBuffer q;
10477 : PQExpBuffer delq;
4443 tgl 10478 ECB : char *qextname;
10479 :
489 10480 : /* Do nothing in data-only dump */
489 tgl 10481 GIC 18 : if (dopt->dataOnly)
4443 10482 1 : return;
4443 tgl 10483 ECB :
4443 tgl 10484 CBC 17 : q = createPQExpBuffer();
10485 17 : delq = createPQExpBuffer();
10486 :
4153 bruce 10487 GIC 17 : qextname = pg_strdup(fmtId(extinfo->dobj.name));
4443 tgl 10488 ECB :
4443 tgl 10489 GIC 17 : appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
4443 tgl 10490 ECB :
3099 alvherre 10491 CBC 17 : if (!dopt->binary_upgrade)
4442 tgl 10492 ECB : {
4419 10493 : /*
1900 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.
4419 10497 : *
1900 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 : */
4419 tgl 10503 GIC 16 : appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
4442 10504 16 : qextname, fmtId(extinfo->namespace));
10505 : }
10506 : else
10507 : {
1900 tgl 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;
4442 10518 :
3429 heikki.linnakangas 10519 CBC 1 : appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
10520 :
3931 bruce 10521 ECB : /*
10522 : * We unconditionally create the extension, so we must drop it if it
3260 10523 : * exists. This could happen if the user deleted 'plpgsql' and then
2300 sfrost 10524 : * readded it, causing its oid to be greater than g_last_builtin_oid.
3931 bruce 10525 : */
3931 bruce 10526 CBC 1 : appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
3931 bruce 10527 ECB :
3429 heikki.linnakangas 10528 CBC 1 : appendPQExpBufferStr(q,
2118 tgl 10529 ECB : "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
4442 tgl 10530 CBC 1 : appendStringLiteralAH(q, extinfo->dobj.name, fout);
3429 heikki.linnakangas 10531 1 : appendPQExpBufferStr(q, ", ");
4442 tgl 10532 1 : appendStringLiteralAH(q, extinfo->namespace, fout);
3429 heikki.linnakangas 10533 1 : appendPQExpBufferStr(q, ", ");
4442 tgl 10534 1 : appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
4440 10535 1 : appendStringLiteralAH(q, extinfo->extversion, fout);
3429 heikki.linnakangas 10536 1 : appendPQExpBufferStr(q, ", ");
4382 bruce 10537 ECB :
4442 tgl 10538 : /*
10539 : * Note that we're pushing extconfig (an OID array) back into
3260 bruce 10540 : * pg_extension exactly as-is. This is OK because pg_class OIDs are
4382 10541 : * preserved in binary upgrade.
4442 tgl 10542 : */
4442 tgl 10543 CBC 1 : if (strlen(extinfo->extconfig) > 2)
10544 1 : appendStringLiteralAH(q, extinfo->extconfig, fout);
4442 tgl 10545 ECB : else
3429 heikki.linnakangas 10546 LBC 0 : appendPQExpBufferStr(q, "NULL");
3429 heikki.linnakangas 10547 CBC 1 : appendPQExpBufferStr(q, ", ");
4442 tgl 10548 1 : if (strlen(extinfo->extcondition) > 2)
10549 1 : appendStringLiteralAH(q, extinfo->extcondition, fout);
4442 tgl 10550 ECB : else
3429 heikki.linnakangas 10551 LBC 0 : appendPQExpBufferStr(q, "NULL");
3429 heikki.linnakangas 10552 CBC 1 : appendPQExpBufferStr(q, ", ");
10553 1 : appendPQExpBufferStr(q, "ARRAY[");
4442 tgl 10554 1 : n = 0;
10555 2 : for (i = 0; i < extinfo->dobj.nDeps; i++)
4442 tgl 10556 ECB : {
10557 : DumpableObject *extobj;
10558 :
4442 tgl 10559 CBC 1 : extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
10560 1 : if (extobj && extobj->objType == DO_EXTENSION)
4442 tgl 10561 ECB : {
4442 tgl 10562 LBC 0 : if (n++ > 0)
3429 heikki.linnakangas 10563 0 : appendPQExpBufferChar(q, ',');
4442 tgl 10564 0 : appendStringLiteralAH(q, extobj->name, fout);
4442 tgl 10565 ECB : }
10566 : }
3429 heikki.linnakangas 10567 CBC 1 : appendPQExpBufferStr(q, "]::pg_catalog.text[]");
10568 1 : appendPQExpBufferStr(q, ");\n");
4442 tgl 10569 ECB : }
10570 :
2559 sfrost 10571 CBC 17 : if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10572 17 : ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
1528 alvherre 10573 17 : ARCHIVE_OPTS(.tag = extinfo->dobj.name,
1528 alvherre 10574 ECB : .description = "EXTENSION",
10575 : .section = SECTION_PRE_DATA,
10576 : .createStmt = q->data,
10577 : .dropStmt = delq->data));
4443 tgl 10578 :
10579 : /* Dump Extension Comments and Security Labels */
2559 sfrost 10580 CBC 17 : if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 10581 17 : dumpComment(fout, "EXTENSION", qextname,
2559 sfrost 10582 ECB : NULL, "",
2559 sfrost 10583 CBC 17 : extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
2559 sfrost 10584 ECB :
2559 sfrost 10585 CBC 17 : if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
1868 tgl 10586 LBC 0 : dumpSecLabel(fout, "EXTENSION", qextname,
2559 sfrost 10587 ECB : NULL, "",
2559 sfrost 10588 LBC 0 : extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
4443 tgl 10589 ECB :
4443 tgl 10590 CBC 17 : free(qextname);
4443 tgl 10591 ECB :
4443 tgl 10592 CBC 17 : destroyPQExpBuffer(q);
10593 17 : destroyPQExpBuffer(delq);
4443 tgl 10594 ECB : }
10595 :
7639 10596 : /*
7064 10597 : * dumpType
10598 : * writes out to fout the queries to recreate a user-defined type
10599 : */
10600 : static void
788 peter 10601 CBC 523 : dumpType(Archive *fout, const TypeInfo *tyinfo)
7064 tgl 10602 ECB : {
2643 tgl 10603 CBC 523 : DumpOptions *dopt = fout->dopt;
2643 tgl 10604 ECB :
489 10605 : /* Do nothing in data-only dump */
489 tgl 10606 CBC 523 : if (dopt->dataOnly)
7064 10607 22 : return;
7064 tgl 10608 ECB :
10609 : /* Dump out in proper style */
4855 bruce 10610 CBC 501 : if (tyinfo->typtype == TYPTYPE_BASE)
2643 tgl 10611 GIC 71 : dumpBaseType(fout, tyinfo);
4855 bruce 10612 CBC 430 : else if (tyinfo->typtype == TYPTYPE_DOMAIN)
2643 tgl 10613 121 : dumpDomain(fout, tyinfo);
4855 bruce 10614 309 : else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
2643 tgl 10615 123 : dumpCompositeType(fout, tyinfo);
4855 bruce 10616 186 : else if (tyinfo->typtype == TYPTYPE_ENUM)
2643 tgl 10617 53 : dumpEnumType(fout, tyinfo);
4175 heikki.linnakangas 10618 133 : else if (tyinfo->typtype == TYPTYPE_RANGE)
2643 tgl 10619 92 : dumpRangeType(fout, tyinfo);
2805 10620 41 : else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
2643 10621 41 : dumpUndefinedType(fout, tyinfo);
4160 tgl 10622 ECB : else
1469 peter 10623 LBC 0 : pg_log_warning("typtype of data type \"%s\" appears to be invalid",
1418 tgl 10624 ECB : tyinfo->dobj.name);
5851 10625 : }
10626 :
10627 : /*
10628 : * dumpEnumType
10629 : * writes out to fout the queries to recreate a user-defined enum type
10630 : */
10631 : static void
788 peter 10632 CBC 53 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
5851 tgl 10633 ECB : {
2643 tgl 10634 CBC 53 : DumpOptions *dopt = fout->dopt;
5851 10635 53 : PQExpBuffer q = createPQExpBuffer();
10636 53 : PQExpBuffer delq = createPQExpBuffer();
10637 53 : PQExpBuffer query = createPQExpBuffer();
5851 tgl 10638 ECB : PGresult *res;
10639 : int num,
10640 : i;
10641 : Oid enum_oid;
3773 10642 : char *qtypname;
1868 10643 : char *qualtypname;
10644 : char *label;
10645 : int i_enumlabel;
10646 : int i_oid;
10647 :
489 tgl 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;
489 tgl 10661 ECB : }
10662 :
489 tgl 10663 CBC 53 : printfPQExpBuffer(query,
489 tgl 10664 ECB : "EXECUTE dumpEnumType('%u')",
489 tgl 10665 CBC 53 : tyinfo->dobj.catId.oid);
5851 tgl 10666 ECB :
4079 rhaas 10667 CBC 53 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5851 tgl 10668 ECB :
5851 tgl 10669 CBC 53 : num = PQntuples(res);
5851 tgl 10670 ECB :
3773 tgl 10671 CBC 53 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
1868 10672 53 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
3773 tgl 10673 ECB :
5851 10674 : /*
10675 : * CASCADE shouldn't be required here as for normal types since the I/O
5624 bruce 10676 : * functions are generic and do not get dropped.
5851 tgl 10677 : */
1868 tgl 10678 CBC 53 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
4854 bruce 10679 ECB :
3099 alvherre 10680 CBC 53 : if (dopt->binary_upgrade)
4079 rhaas 10681 GIC 4 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2017 tgl 10682 4 : tyinfo->dobj.catId.oid,
840 akorotkov 10683 ECB : false, false);
10684 :
4851 bruce 10685 GIC 53 : appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10686 : qualtypname);
10687 :
3099 alvherre 10688 53 : if (!dopt->binary_upgrade)
10689 : {
590 dgustafsson 10690 49 : i_enumlabel = PQfnumber(res, "enumlabel");
10691 :
4851 bruce 10692 ECB : /* Labels with server-assigned oids */
4851 bruce 10693 GIC 350 : for (i = 0; i < num; i++)
4851 bruce 10694 ECB : {
590 dgustafsson 10695 GIC 301 : label = PQgetvalue(res, i, i_enumlabel);
4851 bruce 10696 301 : if (i > 0)
3429 heikki.linnakangas 10697 252 : appendPQExpBufferChar(q, ',');
10698 301 : appendPQExpBufferStr(q, "\n ");
4851 bruce 10699 301 : appendStringLiteralAH(q, label, fout);
4851 bruce 10700 ECB : }
5851 tgl 10701 : }
10702 :
3429 heikki.linnakangas 10703 CBC 53 : appendPQExpBufferStr(q, "\n);\n");
5851 tgl 10704 ECB :
3099 alvherre 10705 GIC 53 : if (dopt->binary_upgrade)
4851 bruce 10706 ECB : {
590 dgustafsson 10707 GIC 4 : i_oid = PQfnumber(res, "oid");
590 dgustafsson 10708 CBC 4 : i_enumlabel = PQfnumber(res, "enumlabel");
10709 :
4851 bruce 10710 ECB : /* Labels with dump-assigned (preserved) oids */
4851 bruce 10711 CBC 51 : for (i = 0; i < num; i++)
10712 : {
590 dgustafsson 10713 GIC 47 : enum_oid = atooid(PQgetvalue(res, i, i_oid));
10714 47 : label = PQgetvalue(res, i, i_enumlabel);
10715 :
4851 bruce 10716 CBC 47 : if (i == 0)
3429 heikki.linnakangas 10717 GIC 4 : appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
4851 bruce 10718 CBC 47 : appendPQExpBuffer(q,
10719 : "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10720 : enum_oid);
1868 tgl 10721 GIC 47 : appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
4851 bruce 10722 CBC 47 : appendStringLiteralAH(q, label, fout);
3429 heikki.linnakangas 10723 47 : appendPQExpBufferStr(q, ";\n\n");
10724 : }
10725 : }
4851 bruce 10726 ECB :
3099 alvherre 10727 CBC 53 : if (dopt->binary_upgrade)
1868 tgl 10728 4 : binary_upgrade_extension_member(q, &tyinfo->dobj,
10729 : "TYPE", qtypname,
1868 tgl 10730 GIC 4 : tyinfo->dobj.namespace->dobj.name);
10731 :
2559 sfrost 10732 53 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10733 53 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
1528 alvherre 10734 53 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10735 : .namespace = tyinfo->dobj.namespace->dobj.name,
1528 alvherre 10736 ECB : .owner = tyinfo->rolname,
10737 : .description = "TYPE",
10738 : .section = SECTION_PRE_DATA,
10739 : .createStmt = q->data,
10740 : .dropStmt = delq->data));
4175 heikki.linnakangas 10741 :
10742 : /* Dump Type Comments and Security Labels */
2559 sfrost 10743 CBC 53 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 10744 36 : dumpComment(fout, "TYPE", qtypname,
2559 sfrost 10745 GIC 36 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10746 36 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10747 :
2559 sfrost 10748 CBC 53 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
1868 tgl 10749 UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
2559 sfrost 10750 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10751 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10752 :
2559 sfrost 10753 CBC 53 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1002 tgl 10754 36 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10755 : qtypname, NULL,
2559 sfrost 10756 36 : tyinfo->dobj.namespace->dobj.name,
489 tgl 10757 GIC 36 : tyinfo->rolname, &tyinfo->dacl);
3773 tgl 10758 ECB :
4175 heikki.linnakangas 10759 GIC 53 : PQclear(res);
4175 heikki.linnakangas 10760 CBC 53 : destroyPQExpBuffer(q);
10761 53 : destroyPQExpBuffer(delq);
4175 heikki.linnakangas 10762 GIC 53 : destroyPQExpBuffer(query);
1868 tgl 10763 53 : free(qtypname);
10764 53 : free(qualtypname);
4175 heikki.linnakangas 10765 53 : }
10766 :
10767 : /*
10768 : * dumpRangeType
4175 heikki.linnakangas 10769 ECB : * writes out to fout the queries to recreate a user-defined range type
10770 : */
10771 : static void
788 peter 10772 GIC 92 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
10773 : {
2643 tgl 10774 92 : DumpOptions *dopt = fout->dopt;
4175 heikki.linnakangas 10775 92 : PQExpBuffer q = createPQExpBuffer();
10776 92 : PQExpBuffer delq = createPQExpBuffer();
4175 heikki.linnakangas 10777 CBC 92 : PQExpBuffer query = createPQExpBuffer();
4175 heikki.linnakangas 10778 ECB : PGresult *res;
10779 : Oid collationOid;
3773 tgl 10780 : char *qtypname;
1868 10781 : char *qualtypname;
10782 : char *procname;
4175 heikki.linnakangas 10783 :
489 tgl 10784 GIC 92 : if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
489 tgl 10785 ECB : {
10786 : /* Set up query for range-specific details */
489 tgl 10787 CBC 41 : appendPQExpBufferStr(query,
10788 : "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
10789 :
489 tgl 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
489 tgl 10797 UIC 0 : appendPQExpBufferStr(query,
10798 : "NULL AS rngmultitype, ");
489 tgl 10799 ECB :
489 tgl 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 :
489 tgl 10814 GIC 41 : ExecuteSqlStatement(fout, query->data);
489 tgl 10815 ECB :
489 tgl 10816 GIC 41 : fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
10817 : }
10818 :
10819 92 : printfPQExpBuffer(query,
10820 : "EXECUTE dumpRangeType('%u')",
4175 heikki.linnakangas 10821 92 : tyinfo->dobj.catId.oid);
4175 heikki.linnakangas 10822 ECB :
4070 rhaas 10823 GIC 92 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
4175 heikki.linnakangas 10824 ECB :
3773 tgl 10825 GIC 92 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
1868 tgl 10826 CBC 92 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
3773 tgl 10827 ECB :
4175 heikki.linnakangas 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 : */
1868 tgl 10832 CBC 92 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10833 :
3099 alvherre 10834 GIC 92 : if (dopt->binary_upgrade)
2017 tgl 10835 6 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
10836 6 : tyinfo->dobj.catId.oid,
10837 : false, true);
10838 :
4175 heikki.linnakangas 10839 CBC 92 : appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
1868 tgl 10840 ECB : qualtypname);
10841 :
4158 tgl 10842 GBC 92 : appendPQExpBuffer(q, "\n subtype = %s",
4175 heikki.linnakangas 10843 ECB : PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10844 :
840 akorotkov 10845 CBC 92 : if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
840 akorotkov 10846 GIC 92 : appendPQExpBuffer(q, ",\n multirange_type_name = %s",
840 akorotkov 10847 EUB : PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
840 akorotkov 10848 ECB :
4158 tgl 10849 : /* print subtype_opclass only if not default for subtype */
4158 tgl 10850 CBC 92 : if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
4158 tgl 10851 ECB : {
3955 bruce 10852 GIC 36 : char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10853 36 : char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10854 :
4158 tgl 10855 CBC 36 : appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
4158 tgl 10856 ECB : fmtId(nspname));
3429 heikki.linnakangas 10857 GIC 36 : appendPQExpBufferStr(q, fmtId(opcname));
4158 tgl 10858 EUB : }
10859 :
4158 tgl 10860 GBC 92 : collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
4175 heikki.linnakangas 10861 GIC 92 : if (OidIsValid(collationOid))
10862 : {
4158 tgl 10863 CBC 41 : CollInfo *coll = findCollationByOid(collationOid);
4175 heikki.linnakangas 10864 ECB :
4175 heikki.linnakangas 10865 GIC 41 : if (coll)
1868 tgl 10866 41 : appendPQExpBuffer(q, ",\n collation = %s",
1868 tgl 10867 CBC 41 : fmtQualifiedDumpable(coll));
4175 heikki.linnakangas 10868 ECB : }
10869 :
4158 tgl 10870 GIC 92 : procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10871 92 : if (strcmp(procname, "-") != 0)
4158 tgl 10872 UIC 0 : appendPQExpBuffer(q, ",\n canonical = %s", procname);
10873 :
4158 tgl 10874 GIC 92 : procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10875 92 : if (strcmp(procname, "-") != 0)
4158 tgl 10876 CBC 5 : appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
4175 heikki.linnakangas 10877 ECB :
3429 heikki.linnakangas 10878 GIC 92 : appendPQExpBufferStr(q, "\n);\n");
4175 heikki.linnakangas 10879 ECB :
3099 alvherre 10880 GIC 92 : if (dopt->binary_upgrade)
1868 tgl 10881 CBC 6 : binary_upgrade_extension_member(q, &tyinfo->dobj,
1868 tgl 10882 EUB : "TYPE", qtypname,
1868 tgl 10883 GIC 6 : tyinfo->dobj.namespace->dobj.name);
4442 tgl 10884 EUB :
2559 sfrost 10885 GIC 92 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 10886 CBC 92 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
1528 alvherre 10887 GIC 92 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
1528 alvherre 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 */
2559 sfrost 10896 GIC 92 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 10897 CBC 36 : dumpComment(fout, "TYPE", qtypname,
2559 sfrost 10898 GIC 36 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
2559 sfrost 10899 CBC 36 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10900 :
2559 sfrost 10901 GIC 92 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
1868 tgl 10902 LBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
2559 sfrost 10903 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
2559 sfrost 10904 UIC 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10905 :
2559 sfrost 10906 CBC 92 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1002 tgl 10907 36 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
1868 tgl 10908 ECB : qtypname, NULL,
2559 sfrost 10909 CBC 36 : tyinfo->dobj.namespace->dobj.name,
489 tgl 10910 36 : tyinfo->rolname, &tyinfo->dacl);
3773 tgl 10911 ECB :
5851 tgl 10912 CBC 92 : PQclear(res);
10913 92 : destroyPQExpBuffer(q);
10914 92 : destroyPQExpBuffer(delq);
10915 92 : destroyPQExpBuffer(query);
1868 10916 92 : free(qtypname);
10917 92 : free(qualtypname);
7064 tgl 10918 GIC 92 : }
7064 tgl 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.
2805 tgl 10928 ECB : */
10929 : static void
788 peter 10930 CBC 41 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
2805 tgl 10931 ECB : {
2643 tgl 10932 CBC 41 : DumpOptions *dopt = fout->dopt;
2805 10933 41 : PQExpBuffer q = createPQExpBuffer();
2805 tgl 10934 GIC 41 : PQExpBuffer delq = createPQExpBuffer();
10935 : char *qtypname;
10936 : char *qualtypname;
10937 :
10938 41 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
1868 10939 41 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10940 :
10941 41 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10942 :
2805 10943 41 : if (dopt->binary_upgrade)
2017 tgl 10944 CBC 2 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2017 tgl 10945 GIC 2 : tyinfo->dobj.catId.oid,
10946 : false, false);
2805 tgl 10947 ECB :
2805 tgl 10948 GIC 41 : appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10949 : qualtypname);
10950 :
10951 41 : if (dopt->binary_upgrade)
1868 10952 2 : binary_upgrade_extension_member(q, &tyinfo->dobj,
10953 : "TYPE", qtypname,
1868 tgl 10954 CBC 2 : tyinfo->dobj.namespace->dobj.name);
10955 :
2559 sfrost 10956 41 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 10957 GIC 41 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
1528 alvherre 10958 41 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
1528 alvherre 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));
2805 tgl 10965 :
10966 : /* Dump Type Comments and Security Labels */
2559 sfrost 10967 CBC 41 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 10968 36 : dumpComment(fout, "TYPE", qtypname,
2559 sfrost 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)
1868 tgl 10973 UIC 0 : dumpSecLabel(fout, "TYPE", qtypname,
2559 sfrost 10974 LBC 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
2559 sfrost 10975 UIC 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
2805 tgl 10976 ECB :
2559 sfrost 10977 CBC 41 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1002 tgl 10978 LBC 0 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10979 : qtypname, NULL,
2559 sfrost 10980 UIC 0 : tyinfo->dobj.namespace->dobj.name,
489 tgl 10981 LBC 0 : tyinfo->rolname, &tyinfo->dacl);
10982 :
2805 tgl 10983 GIC 41 : destroyPQExpBuffer(q);
2805 tgl 10984 CBC 41 : destroyPQExpBuffer(delq);
1868 tgl 10985 GIC 41 : free(qtypname);
1868 tgl 10986 CBC 41 : free(qualtypname);
2805 tgl 10987 GIC 41 : }
10988 :
7064 tgl 10989 ECB : /*
10990 : * dumpBaseType
7522 bruce 10991 : * writes out to fout the queries to recreate a user-defined base type
7639 tgl 10992 : */
10993 : static void
788 peter 10994 CBC 71 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
7639 tgl 10995 ECB : {
2643 tgl 10996 GIC 71 : DumpOptions *dopt = fout->dopt;
7639 10997 71 : PQExpBuffer q = createPQExpBuffer();
10998 71 : PQExpBuffer delq = createPQExpBuffer();
7639 tgl 10999 CBC 71 : PQExpBuffer query = createPQExpBuffer();
11000 : PGresult *res;
3773 tgl 11001 ECB : char *qtypname;
11002 : char *qualtypname;
7639 11003 : char *typlen;
11004 : char *typinput;
11005 : char *typoutput;
11006 : char *typreceive;
7276 11007 : char *typsend;
11008 : char *typmodin;
5944 11009 : char *typmodout;
6996 11010 : char *typanalyze;
11011 : char *typsubscript;
7064 11012 : Oid typreceiveoid;
11013 : Oid typsendoid;
5944 11014 : Oid typmodinoid;
11015 : Oid typmodoutoid;
11016 : Oid typanalyzeoid;
851 11017 : Oid typsubscriptoid;
5366 11018 : char *typcategory;
11019 : char *typispreferred;
11020 : char *typdelim;
11021 : char *typbyval;
11022 : char *typalign;
7639 11023 : char *typstorage;
4422 peter_e 11024 : char *typcollatable;
11025 : char *typdefault;
6256 tgl 11026 CBC 71 : bool typdefault_is_literal = false;
11027 :
489 11028 71 : if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
489 tgl 11029 ECB : {
11030 : /* Set up query for type-specific details */
854 tgl 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, "
481 tgl 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, "
481 tgl 11045 EUB : "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
854 11046 :
489 tgl 11047 GBC 41 : if (fout->remoteVersion >= 140000)
489 tgl 11048 GIC 41 : appendPQExpBufferStr(query,
489 tgl 11049 ECB : "typsubscript, "
481 11050 : "typsubscript::pg_catalog.oid AS typsubscriptoid ");
11051 : else
489 tgl 11052 LBC 0 : appendPQExpBufferStr(query,
481 tgl 11053 ECB : "'-' AS typsubscript, 0 AS typsubscriptoid ");
11054 :
489 tgl 11055 CBC 41 : appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
489 tgl 11056 ECB : "WHERE oid = $1");
11057 :
489 tgl 11058 CBC 41 : ExecuteSqlStatement(fout, query->data);
489 tgl 11059 ECB :
489 tgl 11060 CBC 41 : fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
489 tgl 11061 ECB : }
11062 :
489 tgl 11063 GIC 71 : printfPQExpBuffer(query,
11064 : "EXECUTE dumpBaseType('%u')",
854 11065 71 : tyinfo->dobj.catId.oid);
11066 :
4070 rhaas 11067 71 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
7639 tgl 11068 ECB :
7639 tgl 11069 GIC 71 : typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
7639 tgl 11070 CBC 71 : typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
11071 71 : typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
7276 11072 71 : typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
11073 71 : typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
5944 tgl 11074 GIC 71 : typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
11075 71 : typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
6996 11076 71 : typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
851 11077 71 : typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
7064 11078 71 : typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
11079 71 : typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
5944 tgl 11080 CBC 71 : typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
5944 tgl 11081 GIC 71 : typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
6996 11082 71 : typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
851 tgl 11083 CBC 71 : typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
5366 tgl 11084 GIC 71 : typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
11085 71 : typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
7639 tgl 11086 CBC 71 : typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
7639 tgl 11087 GIC 71 : typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
11088 71 : typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
7639 tgl 11089 CBC 71 : typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
4422 peter_e 11090 71 : typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
6256 tgl 11091 GIC 71 : if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6256 tgl 11092 UIC 0 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6256 tgl 11093 GBC 71 : else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
11094 : {
6256 tgl 11095 GIC 46 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6031 bruce 11096 CBC 46 : typdefault_is_literal = true; /* it needs quotes */
11097 : }
11098 : else
6256 tgl 11099 GIC 25 : typdefault = NULL;
11100 :
3773 11101 71 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
1868 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);
7639 tgl 11110 ECB :
11111 : /*
2017 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 : */
3099 alvherre 11115 CBC 71 : if (dopt->binary_upgrade)
4079 rhaas 11116 GIC 8 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2017 tgl 11117 CBC 8 : tyinfo->dobj.catId.oid,
11118 : false, false);
4854 bruce 11119 ECB :
7639 tgl 11120 GIC 71 : appendPQExpBuffer(q,
7539 peter_e 11121 ECB : "CREATE TYPE %s (\n"
7276 tgl 11122 : " INTERNALLENGTH = %s",
11123 : qualtypname,
7564 peter_e 11124 GIC 71 : (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
11125 :
11126 : /* regproc result is sufficiently quoted already */
2370 tgl 11127 71 : appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
2370 tgl 11128 CBC 71 : appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
2370 tgl 11129 GIC 71 : if (OidIsValid(typreceiveoid))
2370 tgl 11130 LBC 0 : appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
2370 tgl 11131 CBC 71 : if (OidIsValid(typsendoid))
2370 tgl 11132 LBC 0 : appendPQExpBuffer(q, ",\n SEND = %s", typsend);
2370 tgl 11133 GIC 71 : if (OidIsValid(typmodinoid))
11134 5 : appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
2370 tgl 11135 CBC 71 : if (OidIsValid(typmodoutoid))
2370 tgl 11136 GIC 5 : appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
11137 71 : if (OidIsValid(typanalyzeoid))
2370 tgl 11138 LBC 0 : appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
11139 :
4422 peter_e 11140 GIC 71 : if (strcmp(typcollatable, "t") == 0)
3429 heikki.linnakangas 11141 LBC 0 : appendPQExpBufferStr(q, ",\n COLLATABLE = true");
4422 peter_e 11142 ECB :
7639 tgl 11143 GIC 71 : if (typdefault != NULL)
11144 : {
3429 heikki.linnakangas 11145 46 : appendPQExpBufferStr(q, ",\n DEFAULT = ");
6256 tgl 11146 CBC 46 : if (typdefault_is_literal)
6160 tgl 11147 GIC 46 : appendStringLiteralAH(q, typdefault, fout);
6256 tgl 11148 ECB : else
6256 tgl 11149 LBC 0 : appendPQExpBufferStr(q, typdefault);
11150 : }
7639 tgl 11151 ECB :
851 tgl 11152 GIC 71 : if (OidIsValid(typsubscriptoid))
851 tgl 11153 CBC 5 : appendPQExpBuffer(q, ",\n SUBSCRIPT = %s", typsubscript);
11154 :
4855 bruce 11155 GIC 71 : if (OidIsValid(tyinfo->typelem))
578 tgl 11156 CBC 5 : appendPQExpBuffer(q, ",\n ELEMENT = %s",
11157 5 : getFormattedTypeName(fout, tyinfo->typelem,
11158 : zeroIsError));
7639 tgl 11159 ECB :
5366 tgl 11160 GIC 71 : if (strcmp(typcategory, "U") != 0)
5366 tgl 11161 ECB : {
3429 heikki.linnakangas 11162 CBC 5 : appendPQExpBufferStr(q, ",\n CATEGORY = ");
5366 tgl 11163 5 : appendStringLiteralAH(q, typcategory, fout);
11164 : }
11165 :
11166 71 : if (strcmp(typispreferred, "t") == 0)
3429 heikki.linnakangas 11167 5 : appendPQExpBufferStr(q, ",\n PREFERRED = true");
5366 tgl 11168 EUB :
7276 tgl 11169 GIC 71 : if (typdelim && strcmp(typdelim, ",") != 0)
7276 tgl 11170 ECB : {
3429 heikki.linnakangas 11171 LBC 0 : appendPQExpBufferStr(q, ",\n DELIMITER = ");
6160 tgl 11172 0 : appendStringLiteralAH(q, typdelim, fout);
11173 : }
7276 tgl 11174 ECB :
1131 tgl 11175 GIC 71 : if (*typalign == TYPALIGN_CHAR)
3429 heikki.linnakangas 11176 LBC 0 : appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
1131 tgl 11177 CBC 71 : else if (*typalign == TYPALIGN_SHORT)
3429 heikki.linnakangas 11178 UIC 0 : appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
1131 tgl 11179 CBC 71 : else if (*typalign == TYPALIGN_INT)
3429 heikki.linnakangas 11180 GIC 56 : appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
1131 tgl 11181 CBC 15 : else if (*typalign == TYPALIGN_DOUBLE)
3429 heikki.linnakangas 11182 15 : appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
7639 tgl 11183 ECB :
1131 tgl 11184 GIC 71 : if (*typstorage == TYPSTORAGE_PLAIN)
3429 heikki.linnakangas 11185 71 : appendPQExpBufferStr(q, ",\n STORAGE = plain");
1131 tgl 11186 UIC 0 : else if (*typstorage == TYPSTORAGE_EXTERNAL)
3429 heikki.linnakangas 11187 0 : appendPQExpBufferStr(q, ",\n STORAGE = external");
1131 tgl 11188 0 : else if (*typstorage == TYPSTORAGE_EXTENDED)
3429 heikki.linnakangas 11189 0 : appendPQExpBufferStr(q, ",\n STORAGE = extended");
1131 tgl 11190 0 : else if (*typstorage == TYPSTORAGE_MAIN)
3429 heikki.linnakangas 11191 0 : appendPQExpBufferStr(q, ",\n STORAGE = main");
7639 tgl 11192 ECB :
7639 tgl 11193 CBC 71 : if (strcmp(typbyval, "t") == 0)
3429 heikki.linnakangas 11194 51 : appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
7539 peter_e 11195 ECB :
3429 heikki.linnakangas 11196 GIC 71 : appendPQExpBufferStr(q, "\n);\n");
7639 tgl 11197 ECB :
3099 alvherre 11198 GBC 71 : if (dopt->binary_upgrade)
1868 tgl 11199 8 : binary_upgrade_extension_member(q, &tyinfo->dobj,
1868 tgl 11200 EUB : "TYPE", qtypname,
1868 tgl 11201 GIC 8 : tyinfo->dobj.namespace->dobj.name);
4442 tgl 11202 ECB :
2559 sfrost 11203 CBC 71 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 11204 GIC 71 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
1528 alvherre 11205 CBC 71 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
1528 alvherre 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));
7639 tgl 11212 :
4577 rhaas 11213 : /* Dump Type Comments and Security Labels */
2559 sfrost 11214 CBC 71 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 11215 GIC 36 : dumpComment(fout, "TYPE", qtypname,
2559 sfrost 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)
1868 tgl 11220 UIC 0 : dumpSecLabel(fout, "TYPE", qtypname,
2559 sfrost 11221 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11222 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11223 :
2559 sfrost 11224 GIC 71 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1002 tgl 11225 36 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
1868 tgl 11226 ECB : qtypname, NULL,
2559 sfrost 11227 GIC 36 : tyinfo->dobj.namespace->dobj.name,
489 tgl 11228 CBC 36 : tyinfo->rolname, &tyinfo->dacl);
3773 tgl 11229 ECB :
8482 bruce 11230 CBC 71 : PQclear(res);
7639 tgl 11231 GIC 71 : destroyPQExpBuffer(q);
11232 71 : destroyPQExpBuffer(delq);
7919 11233 71 : destroyPQExpBuffer(query);
1868 tgl 11234 CBC 71 : free(qtypname);
11235 71 : free(qualtypname);
8482 bruce 11236 GIC 71 : }
8482 bruce 11237 ECB :
11238 : /*
7064 tgl 11239 : * dumpDomain
7522 bruce 11240 : * writes out to fout the queries to recreate a user-defined domain
7674 11241 : */
11242 : static void
788 peter 11243 GIC 121 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
7674 bruce 11244 ECB : {
2643 tgl 11245 GIC 121 : DumpOptions *dopt = fout->dopt;
7674 bruce 11246 121 : PQExpBuffer q = createPQExpBuffer();
7674 bruce 11247 CBC 121 : PQExpBuffer delq = createPQExpBuffer();
11248 121 : PQExpBuffer query = createPQExpBuffer();
11249 : PGresult *res;
7450 bruce 11250 ECB : int i;
11251 : char *qtypname;
1868 tgl 11252 : char *qualtypname;
7639 11253 : char *typnotnull;
11254 : char *typdefn;
11255 : char *typdefault;
11256 : Oid typcollation;
6256 tgl 11257 GIC 121 : bool typdefault_is_literal = false;
11258 :
489 11259 121 : if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
11260 : {
11261 : /* Set up query for domain-specific details */
11262 41 : appendPQExpBufferStr(query,
489 tgl 11263 ECB : "PREPARE dumpDomain(pg_catalog.oid) AS\n");
11264 :
481 tgl 11265 CBC 41 : appendPQExpBufferStr(query, "SELECT t.typnotnull, "
481 tgl 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, "
481 tgl 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) "
481 tgl 11273 ECB : "WHERE t.oid = $1");
489 tgl 11274 EUB :
489 tgl 11275 GIC 41 : ExecuteSqlStatement(fout, query->data);
489 tgl 11276 EUB :
489 tgl 11277 GBC 41 : fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
11278 : }
7674 bruce 11279 ECB :
489 tgl 11280 CBC 121 : printfPQExpBuffer(query,
489 tgl 11281 ECB : "EXECUTE dumpDomain('%u')",
489 tgl 11282 CBC 121 : tyinfo->dobj.catId.oid);
489 tgl 11283 ECB :
4070 rhaas 11284 GIC 121 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
11285 :
7639 tgl 11286 121 : typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
11287 121 : typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
6256 11288 121 : if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
11289 41 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6256 tgl 11290 CBC 80 : else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
11291 : {
7621 tgl 11292 LBC 0 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6031 bruce 11293 0 : typdefault_is_literal = true; /* it needs quotes */
6256 tgl 11294 ECB : }
11295 : else
6256 tgl 11296 GIC 80 : typdefault = NULL;
4413 11297 121 : typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
11298 :
3099 alvherre 11299 121 : if (dopt->binary_upgrade)
4079 rhaas 11300 18 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2017 tgl 11301 18 : tyinfo->dobj.catId.oid,
11302 : true, /* force array type */
11303 : false); /* force multirange type */
11304 :
3773 11305 121 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
1868 11306 121 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11307 :
7674 bruce 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 */
4413 tgl 11314 121 : if (OidIsValid(typcollation))
11315 : {
11316 : CollInfo *coll;
11317 :
11318 36 : coll = findCollationByOid(typcollation);
11319 36 : if (coll)
1868 11320 36 : appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
11321 : }
4413 tgl 11322 ECB :
7639 tgl 11323 GIC 121 : if (typnotnull[0] == 't')
3429 heikki.linnakangas 11324 CBC 10 : appendPQExpBufferStr(q, " NOT NULL");
11325 :
6256 tgl 11326 GIC 121 : if (typdefault != NULL)
6256 tgl 11327 ECB : {
3429 heikki.linnakangas 11328 GIC 41 : appendPQExpBufferStr(q, " DEFAULT ");
6256 tgl 11329 41 : if (typdefault_is_literal)
6160 tgl 11330 UIC 0 : appendStringLiteralAH(q, typdefault, fout);
11331 : else
6256 tgl 11332 GIC 41 : appendPQExpBufferStr(q, typdefault);
11333 : }
11334 :
7423 11335 121 : PQclear(res);
11336 :
11337 : /*
11338 : * Add any CHECK constraints for the domain
11339 : */
4855 bruce 11340 202 : for (i = 0; i < tyinfo->nDomChecks; i++)
11341 : {
11342 81 : ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
7450 bruce 11343 ECB :
7064 tgl 11344 CBC 81 : if (!domcheck->separate)
7064 tgl 11345 GIC 81 : appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
6385 bruce 11346 81 : fmtId(domcheck->dobj.name), domcheck->condef);
11347 : }
7188 bruce 11348 EUB :
3429 heikki.linnakangas 11349 GIC 121 : appendPQExpBufferStr(q, ";\n");
11350 :
1868 tgl 11351 CBC 121 : appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
11352 :
3099 alvherre 11353 GIC 121 : if (dopt->binary_upgrade)
1868 tgl 11354 CBC 18 : binary_upgrade_extension_member(q, &tyinfo->dobj,
11355 : "DOMAIN", qtypname,
11356 18 : tyinfo->dobj.namespace->dobj.name);
11357 :
2559 sfrost 11358 GIC 121 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 11359 CBC 121 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
1528 alvherre 11360 GIC 121 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
1528 alvherre 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));
7674 bruce 11367 :
4577 rhaas 11368 : /* Dump Domain Comments and Security Labels */
2559 sfrost 11369 CBC 121 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 11370 LBC 0 : dumpComment(fout, "DOMAIN", qtypname,
2559 sfrost 11371 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11372 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7639 tgl 11373 ECB :
2559 sfrost 11374 CBC 121 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
1868 tgl 11375 LBC 0 : dumpSecLabel(fout, "DOMAIN", qtypname,
2559 sfrost 11376 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11377 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
2559 sfrost 11378 ECB :
2559 sfrost 11379 CBC 121 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1002 tgl 11380 36 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
1868 tgl 11381 ECB : qtypname, NULL,
2559 sfrost 11382 CBC 36 : tyinfo->dobj.namespace->dobj.name,
489 tgl 11383 36 : tyinfo->rolname, &tyinfo->dacl);
3773 tgl 11384 ECB :
3029 alvherre 11385 : /* Dump any per-constraint comments */
3029 alvherre 11386 CBC 202 : for (i = 0; i < tyinfo->nDomChecks; i++)
3029 alvherre 11387 ECB : {
3029 alvherre 11388 GBC 81 : ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
1868 tgl 11389 CBC 81 : PQExpBuffer conprefix = createPQExpBuffer();
11390 :
11391 81 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
3029 alvherre 11392 81 : fmtId(domcheck->dobj.name));
11393 :
158 tgl 11394 GIC 81 : if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 11395 CBC 36 : dumpComment(fout, conprefix->data, qtypname,
2559 sfrost 11396 GIC 36 : tyinfo->dobj.namespace->dobj.name,
2559 sfrost 11397 CBC 36 : tyinfo->rolname,
11398 36 : domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
11399 :
1868 tgl 11400 GIC 81 : destroyPQExpBuffer(conprefix);
11401 : }
11402 :
7639 11403 121 : destroyPQExpBuffer(q);
11404 121 : destroyPQExpBuffer(delq);
7639 tgl 11405 CBC 121 : destroyPQExpBuffer(query);
1868 tgl 11406 GIC 121 : free(qtypname);
11407 121 : free(qualtypname);
7674 bruce 11408 121 : }
11409 :
11410 : /*
7064 tgl 11411 ECB : * dumpCompositeType
7522 bruce 11412 : * writes out to fout the queries to recreate a user-defined stand-alone
7064 tgl 11413 : * composite type
11414 : */
11415 : static void
788 peter 11416 CBC 123 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
11417 : {
2643 tgl 11418 GIC 123 : DumpOptions *dopt = fout->dopt;
7542 bruce 11419 123 : PQExpBuffer q = createPQExpBuffer();
4341 heikki.linnakangas 11420 CBC 123 : PQExpBuffer dropped = createPQExpBuffer();
7542 bruce 11421 GIC 123 : PQExpBuffer delq = createPQExpBuffer();
11422 123 : PQExpBuffer query = createPQExpBuffer();
7542 bruce 11423 ECB : PGresult *res;
3773 tgl 11424 : char *qtypname;
1868 11425 : char *qualtypname;
7542 bruce 11426 EUB : int ntups;
7522 bruce 11427 ECB : int i_attname;
7522 bruce 11428 EUB : int i_atttypdefn;
4341 heikki.linnakangas 11429 ECB : int i_attlen;
11430 : int i_attalign;
11431 : int i_attisdropped;
4375 tgl 11432 : int i_attcollation;
7542 bruce 11433 : int i;
4341 heikki.linnakangas 11434 EUB : int actual_atts;
11435 :
489 tgl 11436 CBC 123 : if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
4375 tgl 11437 EUB : {
11438 : /*
481 tgl 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.
481 tgl 11445 EUB : */
489 tgl 11446 GIC 58 : appendPQExpBufferStr(query,
11447 : "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
465 tgl 11448 ECB : "SELECT a.attname, a.attnum, "
481 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");
489 11458 :
489 tgl 11459 CBC 58 : ExecuteSqlStatement(fout, query->data);
11460 :
489 tgl 11461 GIC 58 : fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
4375 tgl 11462 ECB : }
7542 bruce 11463 :
489 tgl 11464 GIC 123 : printfPQExpBuffer(query,
489 tgl 11465 ECB : "EXECUTE dumpCompositeType('%u')",
489 tgl 11466 GIC 123 : tyinfo->dobj.catId.oid);
489 tgl 11467 EUB :
4079 rhaas 11468 GBC 123 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11469 :
7542 bruce 11470 GIC 123 : ntups = PQntuples(res);
7542 bruce 11471 ECB :
7528 tgl 11472 GBC 123 : i_attname = PQfnumber(res, "attname");
7528 tgl 11473 CBC 123 : i_atttypdefn = PQfnumber(res, "atttypdefn");
4341 heikki.linnakangas 11474 GBC 123 : i_attlen = PQfnumber(res, "attlen");
4341 heikki.linnakangas 11475 CBC 123 : i_attalign = PQfnumber(res, "attalign");
11476 123 : i_attisdropped = PQfnumber(res, "attisdropped");
4375 tgl 11477 123 : i_attcollation = PQfnumber(res, "attcollation");
7542 bruce 11478 ECB :
3099 alvherre 11479 GIC 123 : if (dopt->binary_upgrade)
4841 bruce 11480 ECB : {
4079 rhaas 11481 CBC 16 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2017 tgl 11482 GBC 16 : tyinfo->dobj.catId.oid,
840 akorotkov 11483 EUB : false, false);
3096 tgl 11484 GBC 16 : binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
4841 bruce 11485 EUB : }
4854 11486 :
3773 tgl 11487 GBC 123 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
1868 tgl 11488 GIC 123 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
3773 tgl 11489 ECB :
7528 tgl 11490 CBC 123 : appendPQExpBuffer(q, "CREATE TYPE %s AS (",
11491 : qualtypname);
7542 bruce 11492 ECB :
4341 heikki.linnakangas 11493 GIC 123 : actual_atts = 0;
7542 bruce 11494 CBC 382 : for (i = 0; i < ntups; i++)
7542 bruce 11495 ECB : {
11496 : char *attname;
7528 tgl 11497 : char *atttypdefn;
11498 : char *attlen;
4341 heikki.linnakangas 11499 : char *attalign;
11500 : bool attisdropped;
4375 tgl 11501 : Oid attcollation;
11502 :
7528 tgl 11503 GIC 259 : attname = PQgetvalue(res, i, i_attname);
11504 259 : atttypdefn = PQgetvalue(res, i, i_atttypdefn);
4341 heikki.linnakangas 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');
4375 tgl 11508 259 : attcollation = atooid(PQgetvalue(res, i, i_attcollation));
11509 :
3099 alvherre 11510 CBC 259 : if (attisdropped && !dopt->binary_upgrade)
4341 heikki.linnakangas 11511 8 : continue;
4375 tgl 11512 ECB :
4341 heikki.linnakangas 11513 : /* Format properly if not first attr */
4341 heikki.linnakangas 11514 GIC 251 : if (actual_atts++ > 0)
3429 heikki.linnakangas 11515 CBC 128 : appendPQExpBufferChar(q, ',');
3429 heikki.linnakangas 11516 GBC 251 : appendPQExpBufferStr(q, "\n\t");
4341 heikki.linnakangas 11517 EUB :
4341 heikki.linnakangas 11518 GBC 251 : if (!attisdropped)
11519 : {
4341 heikki.linnakangas 11520 CBC 249 : appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
4375 tgl 11521 ECB :
11522 : /* Add collation if not default for the column type */
4341 heikki.linnakangas 11523 CBC 249 : if (OidIsValid(attcollation))
4375 tgl 11524 ECB : {
11525 : CollInfo *coll;
4341 heikki.linnakangas 11526 :
4341 heikki.linnakangas 11527 LBC 0 : coll = findCollationByOid(attcollation);
11528 0 : if (coll)
1868 tgl 11529 0 : appendPQExpBuffer(q, " COLLATE %s",
11530 0 : fmtQualifiedDumpable(coll));
4375 tgl 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
4341 heikki.linnakangas 11539 : * afterwards. See similar code in dumpTableSchema().
11540 : */
4341 heikki.linnakangas 11541 CBC 2 : appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
4341 heikki.linnakangas 11542 ECB :
11543 : /* stash separately for insertion after the CREATE TYPE */
3429 heikki.linnakangas 11544 CBC 2 : appendPQExpBufferStr(dropped,
11545 : "\n-- For binary upgrade, recreate dropped column.\n");
4341 heikki.linnakangas 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);
3429 11551 2 : appendPQExpBufferStr(dropped, "\n AND attrelid = ");
1868 tgl 11552 2 : appendStringLiteralAH(dropped, qualtypname, fout);
3429 heikki.linnakangas 11553 CBC 2 : appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
11554 :
4341 11555 2 : appendPQExpBuffer(dropped, "ALTER TYPE %s ",
11556 : qualtypname);
4341 heikki.linnakangas 11557 GIC 2 : appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
4341 heikki.linnakangas 11558 ECB : fmtId(attname));
11559 : }
11560 : }
3429 heikki.linnakangas 11561 CBC 123 : appendPQExpBufferStr(q, "\n);\n");
4341 heikki.linnakangas 11562 GIC 123 : appendPQExpBufferStr(q, dropped->data);
11563 :
1868 tgl 11564 123 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11565 :
3099 alvherre 11566 123 : if (dopt->binary_upgrade)
1868 tgl 11567 16 : binary_upgrade_extension_member(q, &tyinfo->dobj,
11568 : "TYPE", qtypname,
11569 16 : tyinfo->dobj.namespace->dobj.name);
11570 :
2559 sfrost 11571 CBC 123 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 11572 GIC 107 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
1528 alvherre 11573 CBC 107 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11574 : .namespace = tyinfo->dobj.namespace->dobj.name,
11575 : .owner = tyinfo->rolname,
1528 alvherre 11576 ECB : .description = "TYPE",
11577 : .section = SECTION_PRE_DATA,
11578 : .createStmt = q->data,
11579 : .dropStmt = delq->data));
7103 tgl 11580 :
11581 :
4577 rhaas 11582 : /* Dump Type Comments and Security Labels */
2559 sfrost 11583 CBC 123 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 11584 36 : dumpComment(fout, "TYPE", qtypname,
2559 sfrost 11585 36 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11586 36 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11587 :
2559 sfrost 11588 GBC 123 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
1868 tgl 11589 UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
2559 sfrost 11590 UIC 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11591 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7103 tgl 11592 ECB :
2559 sfrost 11593 CBC 123 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1002 tgl 11594 GIC 17 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
1868 tgl 11595 ECB : qtypname, NULL,
2559 sfrost 11596 CBC 17 : tyinfo->dobj.namespace->dobj.name,
489 tgl 11597 17 : tyinfo->rolname, &tyinfo->dacl);
11598 :
11599 : /* Dump any per-column comments */
465 tgl 11600 GIC 123 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
465 tgl 11601 CBC 36 : dumpCompositeTypeColComments(fout, tyinfo, res);
465 tgl 11602 ECB :
7064 tgl 11603 GIC 123 : PQclear(res);
7064 tgl 11604 CBC 123 : destroyPQExpBuffer(q);
4341 heikki.linnakangas 11605 GIC 123 : destroyPQExpBuffer(dropped);
7064 tgl 11606 123 : destroyPQExpBuffer(delq);
11607 123 : destroyPQExpBuffer(query);
1868 11608 123 : free(qtypname);
11609 123 : free(qualtypname);
5008 tgl 11610 CBC 123 : }
11611 :
11612 : /*
11613 : * dumpCompositeTypeColComments
5008 tgl 11614 ECB : * writes out to fout the queries to recreate comments on the columns of
465 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.
5008 11620 : */
11621 : static void
465 tgl 11622 CBC 36 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
11623 : PGresult *res)
5008 tgl 11624 ECB : {
11625 : CommentItem *comments;
4790 bruce 11626 EUB : int ncomments;
11627 : PQExpBuffer query;
5008 tgl 11628 ECB : PQExpBuffer target;
11629 : int i;
11630 : int ntups;
4790 bruce 11631 : int i_attname;
11632 : int i_attnum;
11633 : int i_attisdropped;
11634 :
11635 : /* do nothing, if --no-comments is supplied */
1900 tgl 11636 CBC 36 : if (fout->dopt->no_comments)
1900 tgl 11637 UIC 0 : return;
1900 tgl 11638 ECB :
11639 : /* Search for comments associated with type's pg_class OID */
465 tgl 11640 CBC 36 : ncomments = findComments(RelationRelationId, tyinfo->typrelid,
5008 tgl 11641 ECB : &comments);
11642 :
11643 : /* If no comments exist, we're done */
5008 tgl 11644 GIC 36 : if (ncomments <= 0)
5008 tgl 11645 LBC 0 : return;
11646 :
5008 tgl 11647 ECB : /* Build COMMENT ON statements */
465 tgl 11648 GIC 36 : query = createPQExpBuffer();
5008 tgl 11649 CBC 36 : target = createPQExpBuffer();
5008 tgl 11650 ECB :
465 tgl 11651 GIC 36 : ntups = PQntuples(res);
5008 tgl 11652 CBC 36 : i_attnum = PQfnumber(res, "attnum");
5008 tgl 11653 GIC 36 : i_attname = PQfnumber(res, "attname");
465 tgl 11654 CBC 36 : i_attisdropped = PQfnumber(res, "attisdropped");
5008 11655 72 : while (ncomments > 0)
5008 tgl 11656 ECB : {
11657 : const char *attname;
11658 :
5008 tgl 11659 GIC 36 : attname = NULL;
11660 36 : for (i = 0; i < ntups; i++)
11661 : {
465 11662 36 : if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
11663 36 : PQgetvalue(res, i, i_attisdropped)[0] != 't')
11664 : {
5008 tgl 11665 CBC 36 : attname = PQgetvalue(res, i, i_attname);
5008 tgl 11666 GBC 36 : break;
5008 tgl 11667 EUB : }
11668 : }
5008 tgl 11669 GIC 36 : if (attname) /* just in case we don't find it */
5008 tgl 11670 ECB : {
5008 tgl 11671 GBC 36 : const char *descr = comments->descr;
5008 tgl 11672 EUB :
5008 tgl 11673 GBC 36 : resetPQExpBuffer(target);
5008 tgl 11674 GIC 36 : appendPQExpBuffer(target, "COLUMN %s.",
4855 bruce 11675 CBC 36 : fmtId(tyinfo->dobj.name));
3429 heikki.linnakangas 11676 36 : appendPQExpBufferStr(target, fmtId(attname));
11677 :
5008 tgl 11678 36 : resetPQExpBuffer(query);
1868 11679 36 : appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
1868 tgl 11680 GIC 36 : fmtQualifiedDumpable(tyinfo));
11681 36 : appendPQExpBuffer(query, "%s IS ", fmtId(attname));
5008 tgl 11682 CBC 36 : appendStringLiteralAH(query, descr, fout);
3429 heikki.linnakangas 11683 GIC 36 : appendPQExpBufferStr(query, ";\n");
5008 tgl 11684 ECB :
5008 tgl 11685 CBC 36 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 11686 GIC 36 : ARCHIVE_OPTS(.tag = target->data,
1528 alvherre 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));
5008 tgl 11694 : }
11695 :
5008 tgl 11696 CBC 36 : comments++;
5008 tgl 11697 GIC 36 : ncomments--;
11698 : }
5008 tgl 11699 ECB :
5008 tgl 11700 CBC 36 : destroyPQExpBuffer(query);
11701 36 : destroyPQExpBuffer(target);
7064 tgl 11702 ECB : }
8951 bruce 11703 :
6247 tgl 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
788 peter 11711 GIC 74 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
6247 tgl 11712 ECB : {
2643 tgl 11713 GIC 74 : DumpOptions *dopt = fout->dopt;
6247 tgl 11714 ECB : PQExpBuffer q;
11715 :
489 11716 : /* Do nothing in data-only dump */
489 tgl 11717 CBC 74 : if (dopt->dataOnly)
6247 11718 3 : return;
11719 :
6247 tgl 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 :
3099 alvherre 11731 71 : if (dopt->binary_upgrade)
4079 rhaas 11732 CBC 8 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2017 tgl 11733 GIC 8 : stinfo->baseType->dobj.catId.oid,
11734 : false, false);
11735 :
6247 11736 71 : appendPQExpBuffer(q, "CREATE TYPE %s;\n",
1868 11737 71 : fmtQualifiedDumpable(stinfo));
11738 :
2559 sfrost 11739 71 : if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11740 71 : ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
1528 alvherre 11741 71 : ARCHIVE_OPTS(.tag = stinfo->dobj.name,
1528 alvherre 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 :
6247 tgl 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
7064 tgl 11755 ECB : */
11756 : static void
788 peter 11757 CBC 83 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
11758 : {
2643 tgl 11759 GIC 83 : DumpOptions *dopt = fout->dopt;
7064 tgl 11760 ECB : PQExpBuffer defqry;
11761 : PQExpBuffer delqry;
6425 11762 : bool useParams;
11763 : char *qlanname;
7064 11764 : FuncInfo *funcInfo;
4947 tgl 11765 GIC 83 : FuncInfo *inlineInfo = NULL;
7064 tgl 11766 CBC 83 : FuncInfo *validatorInfo = NULL;
11767 :
489 tgl 11768 ECB : /* Do nothing in data-only dump */
489 tgl 11769 CBC 83 : if (dopt->dataOnly)
7064 11770 7 : return;
8951 bruce 11771 ECB :
7064 tgl 11772 : /*
6385 bruce 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.)
7064 tgl 11778 : */
11779 :
7064 tgl 11780 CBC 76 : funcInfo = findFuncByOid(plang->lanplcallfoid);
6247 tgl 11781 GIC 76 : if (funcInfo != NULL && !funcInfo->dobj.dump)
6425 11782 2 : funcInfo = NULL; /* treat not-dumped same as not-found */
8314 bruce 11783 ECB :
4947 tgl 11784 CBC 76 : if (OidIsValid(plang->laninline))
11785 : {
11786 41 : inlineInfo = findFuncByOid(plang->laninline);
4947 tgl 11787 GIC 41 : if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11788 1 : inlineInfo = NULL;
4947 tgl 11789 ECB : }
11790 :
7064 tgl 11791 GIC 76 : if (OidIsValid(plang->lanvalidator))
11792 : {
11793 41 : validatorInfo = findFuncByOid(plang->lanvalidator);
6247 11794 41 : if (validatorInfo != NULL && !validatorInfo->dobj.dump)
6425 11795 1 : validatorInfo = NULL;
11796 : }
11797 :
11798 : /*
1166 tgl 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.
6425 11802 : */
6425 tgl 11803 CBC 34 : useParams = (funcInfo != NULL &&
4947 11804 144 : (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
6425 tgl 11805 GIC 34 : (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
6425 tgl 11806 ECB :
7064 tgl 11807 CBC 76 : defqry = createPQExpBuffer();
7064 tgl 11808 GIC 76 : delqry = createPQExpBuffer();
11809 :
4153 bruce 11810 CBC 76 : qlanname = pg_strdup(fmtId(plang->dobj.name));
7079 tgl 11811 ECB :
7064 tgl 11812 CBC 76 : appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11813 : qlanname);
7079 tgl 11814 ECB :
6425 tgl 11815 GIC 76 : if (useParams)
7064 tgl 11816 ECB : {
4792 tgl 11817 GIC 34 : appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11818 34 : plang->lanpltrusted ? "TRUSTED " : "",
4792 tgl 11819 ECB : qlanname);
6425 tgl 11820 GIC 34 : appendPQExpBuffer(defqry, " HANDLER %s",
1868 11821 34 : fmtQualifiedDumpable(funcInfo));
4947 11822 34 : if (OidIsValid(plang->laninline))
1868 tgl 11823 UBC 0 : appendPQExpBuffer(defqry, " INLINE %s",
11824 0 : fmtQualifiedDumpable(inlineInfo));
6425 tgl 11825 GBC 34 : if (OidIsValid(plang->lanvalidator))
1868 tgl 11826 UBC 0 : appendPQExpBuffer(defqry, " VALIDATOR %s",
1868 tgl 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
1166 tgl 11837 ECB : * EXISTS; perhaps we should emit that instead? But it might just add
11838 : * confusion.
11839 : */
4792 tgl 11840 CBC 42 : appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11841 : qlanname);
4792 tgl 11842 ECB : }
3429 heikki.linnakangas 11843 GIC 76 : appendPQExpBufferStr(defqry, ";\n");
11844 :
3099 alvherre 11845 76 : if (dopt->binary_upgrade)
1868 tgl 11846 CBC 2 : binary_upgrade_extension_member(defqry, &plang->dobj,
1868 tgl 11847 ECB : "LANGUAGE", qlanname, NULL);
4442 11848 :
2559 sfrost 11849 CBC 76 : if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 11850 GIC 35 : ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
1528 alvherre 11851 CBC 35 : ARCHIVE_OPTS(.tag = plang->dobj.name,
11852 : .owner = plang->lanowner,
1528 alvherre 11853 ECB : .description = "PROCEDURAL LANGUAGE",
11854 : .section = SECTION_PRE_DATA,
11855 : .createStmt = defqry->data,
11856 : .dropStmt = delqry->data,
11857 : ));
8951 bruce 11858 :
11859 : /* Dump Proc Lang Comments and Security Labels */
2559 sfrost 11860 CBC 76 : if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 11861 UIC 0 : dumpComment(fout, "LANGUAGE", qlanname,
1868 tgl 11862 LBC 0 : NULL, plang->lanowner,
2559 sfrost 11863 0 : plang->dobj.catId, 0, plang->dobj.dumpId);
11864 :
2559 sfrost 11865 CBC 76 : if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
1868 tgl 11866 UIC 0 : dumpSecLabel(fout, "LANGUAGE", qlanname,
1868 tgl 11867 LBC 0 : NULL, plang->lanowner,
2559 sfrost 11868 0 : plang->dobj.catId, 0, plang->dobj.dumpId);
9345 bruce 11869 ECB :
2559 sfrost 11870 GIC 76 : if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
1002 tgl 11871 41 : dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
11872 : qlanname, NULL, NULL,
489 11873 41 : plang->lanowner, &plang->dacl);
11874 :
7064 11875 76 : free(qlanname);
11876 :
11877 76 : destroyPQExpBuffer(defqry);
11878 76 : destroyPQExpBuffer(delqry);
9770 scrappy 11879 ECB : }
11880 :
7621 tgl 11881 : /*
6582 11882 : * format_function_arguments: generate function name and argument list
11883 : *
5378 11884 : * This is used when we can rely on pg_get_function_arguments to format
3505 tgl 11885 EUB : * the argument list. Note, however, that pg_get_function_arguments
11886 : * does not special-case zero-argument aggregates.
5378 11887 : */
11888 : static char *
788 peter 11889 CBC 3948 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
5378 tgl 11890 ECB : {
11891 : PQExpBufferData fn;
11892 :
5378 tgl 11893 CBC 3948 : initPQExpBuffer(&fn);
3429 heikki.linnakangas 11894 GIC 3948 : appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
3505 tgl 11895 3948 : if (is_agg && finfo->nargs == 0)
3429 heikki.linnakangas 11896 CBC 80 : appendPQExpBufferStr(&fn, "(*)");
3505 tgl 11897 ECB : else
3505 tgl 11898 GIC 3868 : appendPQExpBuffer(&fn, "(%s)", funcargs);
5378 tgl 11899 CBC 3948 : return fn.data;
5378 tgl 11900 ECB : }
11901 :
6582 11902 : /*
11903 : * format_function_signature: generate function name and argument list
11904 : *
481 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 *
788 peter 11912 GIC 2094 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
11913 : {
11914 : PQExpBufferData fn;
11915 : int j;
11916 :
6582 tgl 11917 2094 : initPQExpBuffer(&fn);
6582 tgl 11918 CBC 2094 : if (honor_quotes)
6582 tgl 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 : {
3429 heikki.linnakangas 11924 1796 : if (j > 0)
11925 415 : appendPQExpBufferStr(&fn, ", ");
11926 :
578 tgl 11927 1796 : appendPQExpBufferStr(&fn,
11928 1796 : getFormattedTypeName(fout, finfo->argtypes[j],
11929 : zeroIsError));
11930 : }
3429 heikki.linnakangas 11931 2094 : appendPQExpBufferChar(&fn, ')');
6582 tgl 11932 CBC 2094 : return fn.data;
6582 tgl 11933 EUB : }
11934 :
11935 :
9770 scrappy 11936 ECB : /*
11937 : * dumpFunc:
11938 : * dump out one function
11939 : */
9364 bruce 11940 : static void
788 peter 11941 GBC 1715 : dumpFunc(Archive *fout, const FuncInfo *finfo)
11942 : {
2643 tgl 11943 GIC 1715 : DumpOptions *dopt = fout->dopt;
7064 tgl 11944 ECB : PQExpBuffer query;
11945 : PQExpBuffer q;
11946 : PQExpBuffer delqry;
11947 : PQExpBuffer asPart;
11948 : PGresult *res;
5050 bruce 11949 : char *funcsig; /* identity signature */
2118 tgl 11950 CBC 1715 : char *funcfullsig = NULL; /* full signature */
7064 tgl 11951 ECB : char *funcsig_tag;
11952 : char *qual_funcsig;
11953 : char *proretset;
11954 : char *prosrc;
7639 11955 : char *probin;
732 peter 11956 : char *prosqlbody;
11957 : char *funcargs;
5239 peter_e 11958 : char *funciargs;
5378 tgl 11959 : char *funcresult;
11960 : char *protrftypes;
1864 peter_e 11961 : char *prokind;
7639 tgl 11962 : char *provolatile;
11963 : char *proisstrict;
11964 : char *prosecdef;
4073 rhaas 11965 : char *proleakproof;
11966 : char *proconfig;
5921 tgl 11967 : char *procost;
11968 : char *prorows;
1520 11969 : char *prosupport;
2762 rhaas 11970 : char *proparallel;
7639 tgl 11971 : char *lanname;
5697 tgl 11972 CBC 1715 : char **configitems = NULL;
5697 tgl 11973 GIC 1715 : int nconfigitems = 0;
1956 peter_e 11974 ECB : const char *keyword;
8216 pjw 11975 :
489 tgl 11976 : /* Do nothing in data-only dump */
489 tgl 11977 CBC 1715 : if (dopt->dataOnly)
6446 11978 29 : return;
11979 :
7064 11980 1686 : query = createPQExpBuffer();
11981 1686 : q = createPQExpBuffer();
7064 tgl 11982 GIC 1686 : delqry = createPQExpBuffer();
11983 1686 : asPart = createPQExpBuffer();
11984 :
489 11985 1686 : if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
11986 : {
11987 : /* Set up query for function-specific details */
906 drowley 11988 59 : appendPQExpBufferStr(query,
11989 : "PREPARE dumpFunc(pg_catalog.oid) AS\n");
11990 :
906 drowley 11991 CBC 59 : appendPQExpBufferStr(query,
489 tgl 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"
481 12006 : "proleakproof,\n");
12007 :
489 tgl 12008 CBC 59 : if (fout->remoteVersion >= 90500)
489 tgl 12009 GIC 59 : appendPQExpBufferStr(query,
12010 : "array_to_string(protrftypes, ' ') AS protrftypes,\n");
12011 : else
476 tgl 12012 LBC 0 : appendPQExpBufferStr(query,
476 tgl 12013 ECB : "NULL AS protrftypes,\n");
12014 :
489 tgl 12015 CBC 59 : if (fout->remoteVersion >= 90600)
489 tgl 12016 GIC 59 : appendPQExpBufferStr(query,
12017 : "proparallel,\n");
12018 : else
489 tgl 12019 UIC 0 : appendPQExpBufferStr(query,
12020 : "'u' AS proparallel,\n");
12021 :
489 tgl 12022 GIC 59 : if (fout->remoteVersion >= 110000)
12023 59 : appendPQExpBufferStr(query,
12024 : "prokind,\n");
12025 : else
489 tgl 12026 LBC 0 : appendPQExpBufferStr(query,
481 tgl 12027 ECB : "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
489 12028 :
489 tgl 12029 GIC 59 : if (fout->remoteVersion >= 120000)
12030 59 : appendPQExpBufferStr(query,
489 tgl 12031 ECB : "prosupport,\n");
12032 : else
489 tgl 12033 UIC 0 : appendPQExpBufferStr(query,
489 tgl 12034 ECB : "'-' AS prosupport,\n");
12035 :
489 tgl 12036 CBC 59 : if (fout->remoteVersion >= 140000)
489 tgl 12037 GIC 59 : appendPQExpBufferStr(query,
12038 : "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
12039 : else
489 tgl 12040 UIC 0 : appendPQExpBufferStr(query,
12041 : "NULL AS prosqlbody\n");
12042 :
732 peter 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 :
489 tgl 12048 GIC 59 : ExecuteSqlStatement(fout, query->data);
12049 :
12050 59 : fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
12051 : }
489 tgl 12052 ECB :
489 tgl 12053 GIC 1686 : printfPQExpBuffer(query,
489 tgl 12054 ECB : "EXECUTE dumpFunc('%u')",
998 peter 12055 GIC 1686 : finfo->dobj.catId.oid);
12056 :
4070 rhaas 12057 1686 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
12058 :
7639 tgl 12059 1686 : proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
732 peter 12060 CBC 1686 : if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
732 peter 12061 ECB : {
732 peter 12062 GIC 1671 : prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
12063 1671 : probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
732 peter 12064 CBC 1671 : prosqlbody = NULL;
732 peter 12065 ECB : }
12066 : else
12067 : {
732 peter 12068 GIC 15 : prosrc = NULL;
12069 15 : probin = NULL;
12070 15 : prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
12071 : }
481 tgl 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"));
476 tgl 12075 CBC 1686 : protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
1864 peter_e 12076 1686 : prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
7639 tgl 12077 1686 : provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
7639 tgl 12078 GIC 1686 : proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
7631 peter_e 12079 CBC 1686 : prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
4073 rhaas 12080 GIC 1686 : proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
5697 tgl 12081 CBC 1686 : proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
5921 12082 1686 : procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
12083 1686 : prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
1520 tgl 12084 GIC 1686 : prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
998 peter 12085 1686 : proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
7639 tgl 12086 CBC 1686 : lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
12087 :
8297 pjw 12088 ECB : /*
5380 tgl 12089 : * See backend/commands/functioncmds.c for details of how the 'AS' clause
479 12090 : * is used.
12091 : */
732 peter 12092 GIC 1686 : if (prosqlbody)
12093 : {
12094 15 : appendPQExpBufferStr(asPart, prosqlbody);
12095 : }
479 tgl 12096 1671 : else if (probin[0] != '\0')
12097 : {
3429 heikki.linnakangas 12098 CBC 151 : appendPQExpBufferStr(asPart, "AS ");
6160 tgl 12099 151 : appendStringLiteralAH(asPart, probin, fout);
479 12100 151 : if (prosrc[0] != '\0')
12101 : {
3429 heikki.linnakangas 12102 151 : appendPQExpBufferStr(asPart, ", ");
6797 bruce 12103 ECB :
12104 : /*
6956 tgl 12105 : * where we have bin, use dollar quoting if allowed and src
12106 : * contains quote or backslash; else use regular quoting.
12107 : */
3099 alvherre 12108 GIC 151 : if (dopt->disable_dollar_quoting ||
2118 tgl 12109 151 : (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
6160 tgl 12110 CBC 151 : appendStringLiteralAH(asPart, prosrc, fout);
12111 : else
6160 tgl 12112 LBC 0 : appendStringLiteralDQ(asPart, prosrc, NULL);
8130 tgl 12113 ECB : }
12114 : }
8307 bruce 12115 : else
12116 : {
479 tgl 12117 CBC 1520 : appendPQExpBufferStr(asPart, "AS ");
479 tgl 12118 EUB : /* with no bin, dollar quote src unconditionally if allowed */
479 tgl 12119 GBC 1520 : if (dopt->disable_dollar_quoting)
479 tgl 12120 LBC 0 : appendStringLiteralAH(asPart, prosrc, fout);
479 tgl 12121 EUB : else
479 tgl 12122 GBC 1520 : appendStringLiteralDQ(asPart, prosrc, NULL);
12123 : }
12124 :
476 tgl 12125 GIC 1686 : if (*proconfig)
12126 : {
5697 12127 15 : if (!parsePGArray(proconfig, &configitems, &nconfigitems))
366 tgl 12128 UIC 0 : pg_fatal("could not parse %s array", "proconfig");
12129 : }
12130 : else
12131 : {
871 michael 12132 GIC 1671 : configitems = NULL;
12133 1671 : nconfigitems = 0;
12134 : }
5697 tgl 12135 ECB :
481 tgl 12136 GIC 1686 : funcfullsig = format_function_arguments(finfo, funcargs, false);
12137 1686 : funcsig = format_function_arguments(finfo, funciargs, false);
5239 peter_e 12138 ECB :
4080 rhaas 12139 GIC 1686 : funcsig_tag = format_function_signature(fout, finfo, false);
8314 bruce 12140 ECB :
532 tgl 12141 CBC 1686 : qual_funcsig = psprintf("%s.%s",
532 tgl 12142 GIC 1686 : fmtId(finfo->dobj.namespace->dobj.name),
12143 : funcsig);
532 tgl 12144 ECB :
1864 peter_e 12145 CBC 1686 : if (prokind[0] == PROKIND_PROCEDURE)
12146 81 : keyword = "PROCEDURE";
12147 : else
1864 peter_e 12148 GIC 1605 : keyword = "FUNCTION"; /* works for window functions too */
12149 :
532 tgl 12150 1686 : appendPQExpBuffer(delqry, "DROP %s %s;\n",
12151 : keyword, qual_funcsig);
12152 :
1868 12153 3372 : appendPQExpBuffer(q, "CREATE %s %s.%s",
12154 : keyword,
1868 tgl 12155 CBC 1686 : fmtId(finfo->dobj.namespace->dobj.name),
1956 peter_e 12156 EUB : funcfullsig ? funcfullsig :
3331 bruce 12157 : funcsig);
1868 tgl 12158 :
1864 peter_e 12159 GIC 1686 : if (prokind[0] == PROKIND_PROCEDURE)
1864 peter_e 12160 ECB : /* no result type to output */ ;
1956 peter_e 12161 GBC 1605 : else if (funcresult)
12162 1605 : appendPQExpBuffer(q, " RETURNS %s", funcresult);
5378 tgl 12163 EUB : else
1956 peter_e 12164 UIC 0 : appendPQExpBuffer(q, " RETURNS %s%s",
5378 tgl 12165 LBC 0 : (proretset[0] == 't') ? "SETOF " : "",
578 12166 0 : getFormattedTypeName(fout, finfo->prorettype,
12167 : zeroIsError));
9345 bruce 12168 ECB :
5395 heikki.linnakangas 12169 GIC 1686 : appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
5212 tgl 12170 ECB :
476 tgl 12171 GIC 1686 : if (*protrftypes)
2905 peter_e 12172 ECB : {
2878 bruce 12173 LBC 0 : Oid *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
12174 : int i;
12175 :
2905 peter_e 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",
2118 tgl 12183 0 : getFormattedTypeName(fout, typeids[i], zeroAsNone));
2905 peter_e 12184 ECB : }
12185 : }
12186 :
1864 peter_e 12187 GIC 1686 : if (prokind[0] == PROKIND_WINDOW)
3429 heikki.linnakangas 12188 CBC 5 : appendPQExpBufferStr(q, " WINDOW");
5212 tgl 12189 ECB :
7632 peter_e 12190 CBC 1686 : if (provolatile[0] != PROVOLATILE_VOLATILE)
8280 pjw 12191 ECB : {
7639 tgl 12192 GIC 352 : if (provolatile[0] == PROVOLATILE_IMMUTABLE)
3429 heikki.linnakangas 12193 CBC 332 : appendPQExpBufferStr(q, " IMMUTABLE");
7639 tgl 12194 20 : else if (provolatile[0] == PROVOLATILE_STABLE)
3429 heikki.linnakangas 12195 GIC 20 : appendPQExpBufferStr(q, " STABLE");
7639 tgl 12196 UIC 0 : else if (provolatile[0] != PROVOLATILE_VOLATILE)
366 12197 0 : pg_fatal("unrecognized provolatile value for function \"%s\"",
12198 : finfo->dobj.name);
12199 : }
12200 :
7632 peter_e 12201 GIC 1686 : if (proisstrict[0] == 't')
3429 heikki.linnakangas 12202 357 : appendPQExpBufferStr(q, " STRICT");
12203 :
7631 peter_e 12204 1686 : if (prosecdef[0] == 't')
3429 heikki.linnakangas 12205 UIC 0 : appendPQExpBufferStr(q, " SECURITY DEFINER");
12206 :
4073 rhaas 12207 CBC 1686 : if (proleakproof[0] == 't')
3429 heikki.linnakangas 12208 GIC 10 : appendPQExpBufferStr(q, " LEAKPROOF");
12209 :
12210 : /*
12211 : * COST and ROWS are emitted only if present and not default, so as not to
3260 bruce 12212 ECB : * break backwards-compatibility of the dump without need. Keep this code
5921 tgl 12213 : * in sync with the defaults in functioncmds.c.
12214 : */
5921 tgl 12215 GIC 1686 : if (strcmp(procost, "0") != 0)
5921 tgl 12216 ECB : {
5921 tgl 12217 CBC 1686 : if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
12218 : {
5921 tgl 12219 ECB : /* default cost is 1 */
5921 tgl 12220 CBC 388 : if (strcmp(procost, "1") != 0)
5921 tgl 12221 UIC 0 : appendPQExpBuffer(q, " COST %s", procost);
5921 tgl 12222 ECB : }
12223 : else
12224 : {
12225 : /* default cost is 100 */
5921 tgl 12226 CBC 1298 : if (strcmp(procost, "100") != 0)
12227 5 : appendPQExpBuffer(q, " COST %s", procost);
12228 : }
12229 : }
5921 tgl 12230 GIC 1686 : if (proretset[0] == 't' &&
12231 155 : strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
5921 tgl 12232 UIC 0 : appendPQExpBuffer(q, " ROWS %s", prorows);
12233 :
1520 tgl 12234 GIC 1686 : if (strcmp(prosupport, "-") != 0)
12235 : {
1520 tgl 12236 ECB : /* We rely on regprocout to provide quoting and qualification */
1520 tgl 12237 GIC 46 : appendPQExpBuffer(q, " SUPPORT %s", prosupport);
1520 tgl 12238 ECB : }
12239 :
998 peter 12240 GIC 1686 : if (proparallel[0] != PROPARALLEL_UNSAFE)
12241 : {
2762 rhaas 12242 120 : if (proparallel[0] == PROPARALLEL_SAFE)
12243 115 : appendPQExpBufferStr(q, " PARALLEL SAFE");
12244 5 : else if (proparallel[0] == PROPARALLEL_RESTRICTED)
2762 rhaas 12245 CBC 5 : appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
2762 rhaas 12246 UIC 0 : else if (proparallel[0] != PROPARALLEL_UNSAFE)
366 tgl 12247 0 : pg_fatal("unrecognized proparallel value for function \"%s\"",
12248 : finfo->dobj.name);
12249 : }
12250 :
228 drowley 12251 GNC 1721 : for (int i = 0; i < nconfigitems; i++)
12252 : {
12253 : /* we feel free to scribble on configitems[] here */
5697 tgl 12254 GIC 35 : char *configitem = configitems[i];
12255 : char *pos;
12256 :
12257 35 : pos = strchr(configitem, '=');
12258 35 : if (pos == NULL)
5697 tgl 12259 UIC 0 : continue;
5697 tgl 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
1713 tgl 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 : *
1845 12273 : * Variables that are not so marked should just be emitted as simple
12274 : * string literals. If the variable is not known to
1713 12275 : * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
12276 : * to use GUC_LIST_QUOTE for extension variables.
5697 12277 : */
1845 tgl 12278 CBC 35 : if (variable_is_guc_list_quote(configitem))
12279 : {
1713 tgl 12280 ECB : char **namelist;
12281 : char **nameptr;
12282 :
12283 : /* Parse string into list of identifiers */
12284 : /* this shouldn't fail really */
1713 tgl 12285 GIC 10 : if (SplitGUCList(pos, ',', &namelist))
1713 tgl 12286 ECB : {
1713 tgl 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
5697 12297 25 : appendStringLiteralAH(q, pos, fout);
12298 : }
12299 :
5395 heikki.linnakangas 12300 1686 : appendPQExpBuffer(q, "\n %s;\n", asPart->data);
12301 :
1124 alvherre 12302 1686 : append_depends_on_extension(fout, q, &finfo->dobj,
1124 alvherre 12303 ECB : "pg_catalog.pg_proc", keyword,
532 tgl 12304 : qual_funcsig);
12305 :
3099 alvherre 12306 GIC 1686 : if (dopt->binary_upgrade)
1868 tgl 12307 GBC 277 : binary_upgrade_extension_member(q, &finfo->dobj,
12308 : keyword, funcsig,
1868 tgl 12309 GIC 277 : finfo->dobj.namespace->dobj.name);
4442 tgl 12310 ECB :
2559 sfrost 12311 CBC 1686 : if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 12312 GIC 1584 : ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
1528 alvherre 12313 1584 : ARCHIVE_OPTS(.tag = funcsig_tag,
1528 alvherre 12314 EUB : .namespace = finfo->dobj.namespace->dobj.name,
12315 : .owner = finfo->rolname,
12316 : .description = keyword,
1528 alvherre 12317 ECB : .section = SECTION_PRE_DATA,
12318 : .createStmt = q->data,
12319 : .dropStmt = delqry->data));
12320 :
4577 rhaas 12321 EUB : /* Dump Function Comments and Security Labels */
2559 sfrost 12322 GIC 1686 : if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 12323 UIC 0 : dumpComment(fout, keyword, funcsig,
2559 sfrost 12324 LBC 0 : finfo->dobj.namespace->dobj.name, finfo->rolname,
12325 0 : finfo->dobj.catId, 0, finfo->dobj.dumpId);
12326 :
2559 sfrost 12327 GIC 1686 : if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
1868 tgl 12328 UBC 0 : dumpSecLabel(fout, keyword, funcsig,
2559 sfrost 12329 UIC 0 : finfo->dobj.namespace->dobj.name, finfo->rolname,
12330 0 : finfo->dobj.catId, 0, finfo->dobj.dumpId);
7064 tgl 12331 ECB :
2559 sfrost 12332 CBC 1686 : if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
1002 tgl 12333 GIC 104 : dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
12334 : funcsig, NULL,
2559 sfrost 12335 GBC 104 : finfo->dobj.namespace->dobj.name,
489 tgl 12336 GIC 104 : finfo->rolname, &finfo->dacl);
12337 :
7639 tgl 12338 CBC 1686 : PQclear(res);
12339 :
7639 tgl 12340 GIC 1686 : destroyPQExpBuffer(query);
7919 12341 1686 : destroyPQExpBuffer(q);
12342 1686 : destroyPQExpBuffer(delqry);
7919 tgl 12343 CBC 1686 : destroyPQExpBuffer(asPart);
7630 peter_e 12344 GIC 1686 : free(funcsig);
297 peter 12345 GNC 1686 : free(funcfullsig);
7584 bruce 12346 GIC 1686 : free(funcsig_tag);
532 tgl 12347 CBC 1686 : free(qual_funcsig);
297 peter 12348 GNC 1686 : free(configitems);
12349 : }
9770 scrappy 12350 ECB :
12351 :
7570 peter_e 12352 : /*
7064 tgl 12353 : * Dump a user-defined cast
12354 : */
12355 : static void
788 peter 12356 CBC 68 : dumpCast(Archive *fout, const CastInfo *cast)
7570 peter_e 12357 ECB : {
2643 tgl 12358 GIC 68 : DumpOptions *dopt = fout->dopt;
12359 : PQExpBuffer defqry;
12360 : PQExpBuffer delqry;
4442 tgl 12361 ECB : PQExpBuffer labelq;
1868 12362 : PQExpBuffer castargs;
7064 tgl 12363 CBC 68 : FuncInfo *funcInfo = NULL;
12364 : const char *sourceType;
578 tgl 12365 ECB : const char *targetType;
7570 peter_e 12366 :
489 tgl 12367 : /* Do nothing in data-only dump */
489 tgl 12368 CBC 68 : if (dopt->dataOnly)
7064 12369 3 : return;
7570 peter_e 12370 ECB :
4346 tgl 12371 : /* Cannot dump if we don't have the cast function's info */
7064 tgl 12372 CBC 65 : if (OidIsValid(cast->castfunc))
7570 peter_e 12373 ECB : {
7064 tgl 12374 CBC 40 : funcInfo = findFuncByOid(cast->castfunc);
12375 40 : if (funcInfo == NULL)
366 tgl 12376 LBC 0 : pg_fatal("could not find function definition for function with OID %u",
366 tgl 12377 ECB : cast->castfunc);
7570 peter_e 12378 : }
12379 :
7064 tgl 12380 GIC 65 : defqry = createPQExpBuffer();
12381 65 : delqry = createPQExpBuffer();
4442 12382 65 : labelq = createPQExpBuffer();
1868 12383 65 : castargs = createPQExpBuffer();
12384 :
2838 heikki.linnakangas 12385 CBC 65 : sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
2838 heikki.linnakangas 12386 GIC 65 : targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
7064 tgl 12387 CBC 65 : appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12388 : sourceType, targetType);
7079 tgl 12389 ECB :
7064 tgl 12390 GIC 65 : appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
2838 heikki.linnakangas 12391 ECB : sourceType, targetType);
7570 peter_e 12392 :
5050 bruce 12393 CBC 65 : switch (cast->castmethod)
12394 : {
5273 heikki.linnakangas 12395 25 : case COERCION_METHOD_BINARY:
3429 heikki.linnakangas 12396 GIC 25 : appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
5273 12397 25 : break;
5273 heikki.linnakangas 12398 UIC 0 : case COERCION_METHOD_INOUT:
3429 12399 0 : appendPQExpBufferStr(defqry, "WITH INOUT");
5273 12400 0 : break;
5273 heikki.linnakangas 12401 CBC 40 : case COERCION_METHOD_FUNCTION:
4041 peter_e 12402 40 : if (funcInfo)
4041 peter_e 12403 ECB : {
3955 bruce 12404 GIC 40 : char *fsig = format_function_signature(fout, funcInfo, true);
5050 bruce 12405 EUB :
12406 : /*
12407 : * Always qualify the function name (format_function_signature
12408 : * won't qualify it).
12409 : */
4041 peter_e 12410 CBC 40 : appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
2118 tgl 12411 GIC 40 : fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
4041 peter_e 12412 CBC 40 : free(fsig);
4041 peter_e 12413 EUB : }
12414 : else
1469 peter 12415 LBC 0 : pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
5273 heikki.linnakangas 12416 GIC 40 : break;
5273 heikki.linnakangas 12417 UIC 0 : default:
1469 peter 12418 LBC 0 : pg_log_warning("bogus value in pg_cast.castmethod field");
12419 : }
7064 tgl 12420 ECB :
7064 tgl 12421 GBC 65 : if (cast->castcontext == 'a')
3429 heikki.linnakangas 12422 GIC 35 : appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
7064 tgl 12423 30 : else if (cast->castcontext == 'i')
3429 heikki.linnakangas 12424 10 : appendPQExpBufferStr(defqry, " AS IMPLICIT");
3429 heikki.linnakangas 12425 CBC 65 : appendPQExpBufferStr(defqry, ";\n");
7064 tgl 12426 ECB :
4442 tgl 12427 GIC 65 : appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12428 : sourceType, targetType);
7064 tgl 12429 ECB :
1868 tgl 12430 CBC 65 : appendPQExpBuffer(castargs, "(%s AS %s)",
12431 : sourceType, targetType);
1868 tgl 12432 ECB :
3099 alvherre 12433 GIC 65 : if (dopt->binary_upgrade)
1868 tgl 12434 CBC 7 : binary_upgrade_extension_member(defqry, &cast->dobj,
12435 7 : "CAST", castargs->data, NULL);
12436 :
2559 sfrost 12437 GIC 65 : if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 12438 CBC 65 : ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
1528 alvherre 12439 65 : ARCHIVE_OPTS(.tag = labelq->data,
12440 : .description = "CAST",
1528 alvherre 12441 ECB : .section = SECTION_PRE_DATA,
12442 : .createStmt = defqry->data,
12443 : .dropStmt = delqry->data));
12444 :
12445 : /* Dump Cast Comments */
2559 sfrost 12446 CBC 65 : if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 12447 UIC 0 : dumpComment(fout, "CAST", castargs->data,
1868 tgl 12448 ECB : NULL, "",
2559 sfrost 12449 UIC 0 : cast->dobj.catId, 0, cast->dobj.dumpId);
12450 :
7570 peter_e 12451 GIC 65 : destroyPQExpBuffer(defqry);
7570 peter_e 12452 CBC 65 : destroyPQExpBuffer(delqry);
4442 tgl 12453 GIC 65 : destroyPQExpBuffer(labelq);
1868 tgl 12454 CBC 65 : destroyPQExpBuffer(castargs);
7570 peter_e 12455 ECB : }
12456 :
2905 peter_e 12457 EUB : /*
12458 : * Dump a transform
12459 : */
12460 : static void
788 peter 12461 GIC 43 : dumpTransform(Archive *fout, const TransformInfo *transform)
2905 peter_e 12462 ECB : {
2643 tgl 12463 GIC 43 : DumpOptions *dopt = fout->dopt;
2905 peter_e 12464 ECB : PQExpBuffer defqry;
12465 : PQExpBuffer delqry;
2905 peter_e 12466 EUB : PQExpBuffer labelq;
12467 : PQExpBuffer transformargs;
2905 peter_e 12468 GIC 43 : FuncInfo *fromsqlFuncInfo = NULL;
2905 peter_e 12469 GBC 43 : FuncInfo *tosqlFuncInfo = NULL;
2905 peter_e 12470 EUB : char *lanname;
578 tgl 12471 : const char *transformType;
12472 :
489 12473 : /* Do nothing in data-only dump */
489 tgl 12474 GBC 43 : if (dopt->dataOnly)
2905 peter_e 12475 3 : return;
2905 peter_e 12476 EUB :
12477 : /* Cannot dump if we don't have the transform functions' info */
2905 peter_e 12478 GIC 40 : if (OidIsValid(transform->trffromsql))
12479 : {
2905 peter_e 12480 CBC 40 : fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12481 40 : if (fromsqlFuncInfo == NULL)
366 tgl 12482 UIC 0 : pg_fatal("could not find function definition for function with OID %u",
366 tgl 12483 ECB : transform->trffromsql);
12484 : }
2905 peter_e 12485 CBC 40 : if (OidIsValid(transform->trftosql))
2905 peter_e 12486 ECB : {
2905 peter_e 12487 CBC 40 : tosqlFuncInfo = findFuncByOid(transform->trftosql);
12488 40 : if (tosqlFuncInfo == NULL)
366 tgl 12489 UBC 0 : pg_fatal("could not find function definition for function with OID %u",
366 tgl 12490 EUB : transform->trftosql);
12491 : }
12492 :
2905 peter_e 12493 GIC 40 : defqry = createPQExpBuffer();
2905 peter_e 12494 CBC 40 : delqry = createPQExpBuffer();
12495 40 : labelq = createPQExpBuffer();
1868 tgl 12496 GIC 40 : transformargs = createPQExpBuffer();
2905 peter_e 12497 ECB :
2905 peter_e 12498 GBC 40 : lanname = get_language_name(fout, transform->trflang);
2838 heikki.linnakangas 12499 GIC 40 : transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
2905 peter_e 12500 ECB :
2905 peter_e 12501 CBC 40 : appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12502 : transformType, lanname);
12503 :
2905 peter_e 12504 GIC 40 : appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12505 : transformType, lanname);
12506 :
12507 40 : if (!transform->trffromsql && !transform->trftosql)
1469 peter 12508 LBC 0 : pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
12509 :
2905 peter_e 12510 CBC 40 : if (transform->trffromsql)
12511 : {
2905 peter_e 12512 GIC 40 : if (fromsqlFuncInfo)
2905 peter_e 12513 ECB : {
2905 peter_e 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).
2905 peter_e 12519 ECB : */
2905 peter_e 12520 CBC 40 : appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
2118 tgl 12521 GIC 40 : fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
2905 peter_e 12522 40 : free(fsig);
2905 peter_e 12523 ECB : }
12524 : else
1469 peter 12525 UBC 0 : pg_log_warning("bogus value in pg_transform.trffromsql field");
12526 : }
2905 peter_e 12527 ECB :
2905 peter_e 12528 GIC 40 : if (transform->trftosql)
12529 : {
2905 peter_e 12530 CBC 40 : if (transform->trffromsql)
1375 drowley 12531 GIC 40 : appendPQExpBufferStr(defqry, ", ");
12532 :
2905 peter_e 12533 CBC 40 : if (tosqlFuncInfo)
12534 : {
12535 40 : char *fsig = format_function_signature(fout, tosqlFuncInfo, true);
2905 peter_e 12536 ECB :
12537 : /*
1868 tgl 12538 : * Always qualify the function name (format_function_signature
1868 tgl 12539 EUB : * won't qualify it).
2905 peter_e 12540 : */
2905 peter_e 12541 GIC 40 : appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
2118 tgl 12542 40 : fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
2905 peter_e 12543 40 : free(fsig);
2905 peter_e 12544 ECB : }
12545 : else
1469 peter 12546 UIC 0 : pg_log_warning("bogus value in pg_transform.trftosql field");
2905 peter_e 12547 ECB : }
12548 :
1375 drowley 12549 GIC 40 : appendPQExpBufferStr(defqry, ");\n");
2905 peter_e 12550 ECB :
2905 peter_e 12551 CBC 40 : appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
2838 heikki.linnakangas 12552 EUB : transformType, lanname);
2905 peter_e 12553 ECB :
1868 tgl 12554 CBC 40 : appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12555 : transformType, lanname);
12556 :
2905 peter_e 12557 GIC 40 : if (dopt->binary_upgrade)
1868 tgl 12558 2 : binary_upgrade_extension_member(defqry, &transform->dobj,
12559 2 : "TRANSFORM", transformargs->data, NULL);
12560 :
2559 sfrost 12561 40 : if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12562 40 : ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
1528 alvherre 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 :
2905 peter_e 12571 ECB : /* Dump Transform Comments */
2559 sfrost 12572 GIC 40 : if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 12573 UIC 0 : dumpComment(fout, "TRANSFORM", transformargs->data,
12574 : NULL, "",
2559 sfrost 12575 0 : transform->dobj.catId, 0, transform->dobj.dumpId);
12576 :
2905 peter_e 12577 GIC 40 : free(lanname);
2905 peter_e 12578 CBC 40 : destroyPQExpBuffer(defqry);
2905 peter_e 12579 GIC 40 : destroyPQExpBuffer(delqry);
2905 peter_e 12580 CBC 40 : destroyPQExpBuffer(labelq);
1868 tgl 12581 GIC 40 : destroyPQExpBuffer(transformargs);
2905 peter_e 12582 ECB : }
12583 :
12584 :
12585 : /*
12586 : * dumpOpr
7639 tgl 12587 : * write out a single operator definition
12588 : */
12589 : static void
788 peter 12590 CBC 108 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
12591 : {
2643 tgl 12592 GIC 108 : DumpOptions *dopt = fout->dopt;
7064 tgl 12593 ECB : PQExpBuffer query;
12594 : PQExpBuffer q;
12595 : PQExpBuffer delq;
12596 : PQExpBuffer oprid;
12597 : PQExpBuffer details;
12598 : PGresult *res;
7639 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;
7639 tgl 12616 EUB : char *oprjoin;
5951 12617 : char *oprcanmerge;
7639 12618 : char *oprcanhash;
12619 : char *oprregproc;
3326 sfrost 12620 ECB : char *oprref;
7639 tgl 12621 EUB :
489 12622 : /* Do nothing in data-only dump */
489 tgl 12623 GBC 108 : if (dopt->dataOnly)
7064 tgl 12624 GIC 3 : return;
7064 tgl 12625 ECB :
12626 : /*
12627 : * some operators are invalid because they were the result of user
12628 : * defining operators before commutators exist
12629 : */
7064 tgl 12630 GIC 105 : if (!OidIsValid(oprinfo->oprcode))
7064 tgl 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();
7064 tgl 12638 ECB :
489 tgl 12639 CBC 91 : if (!fout->is_prepared[PREPQUERY_DUMPOPR])
5951 tgl 12640 ECB : {
489 12641 : /* Set up query for operator-specific details */
489 tgl 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, "
481 tgl 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 :
489 tgl 12656 CBC 41 : ExecuteSqlStatement(fout, query->data);
12657 :
489 tgl 12658 GIC 41 : fout->is_prepared[PREPQUERY_DUMPOPR] = true;
12659 : }
12660 :
489 tgl 12661 CBC 91 : printfPQExpBuffer(query,
489 tgl 12662 ECB : "EXECUTE dumpOpr('%u')",
489 tgl 12663 GIC 91 : oprinfo->dobj.catId.oid);
12664 :
4070 rhaas 12665 CBC 91 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
12666 :
7639 tgl 12667 91 : i_oprkind = PQfnumber(res, "oprkind");
12668 91 : i_oprcode = PQfnumber(res, "oprcode");
7639 tgl 12669 GBC 91 : i_oprleft = PQfnumber(res, "oprleft");
7639 tgl 12670 GIC 91 : i_oprright = PQfnumber(res, "oprright");
12671 91 : i_oprcom = PQfnumber(res, "oprcom");
12672 91 : i_oprnegate = PQfnumber(res, "oprnegate");
7639 tgl 12673 CBC 91 : i_oprrest = PQfnumber(res, "oprrest");
12674 91 : i_oprjoin = PQfnumber(res, "oprjoin");
5951 12675 91 : i_oprcanmerge = PQfnumber(res, "oprcanmerge");
7639 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);
7639 tgl 12681 GIC 91 : oprright = PQgetvalue(res, 0, i_oprright);
12682 91 : oprcom = PQgetvalue(res, 0, i_oprcom);
7639 tgl 12683 CBC 91 : oprnegate = PQgetvalue(res, 0, i_oprnegate);
7639 tgl 12684 GIC 91 : oprrest = PQgetvalue(res, 0, i_oprrest);
12685 91 : oprjoin = PQgetvalue(res, 0, i_oprjoin);
5951 tgl 12686 CBC 91 : oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
7639 tgl 12687 GIC 91 : oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
7639 tgl 12688 ECB :
934 12689 : /* In PG14 upwards postfix operator support does not exist anymore. */
934 tgl 12690 CBC 91 : if (strcmp(oprkind, "r") == 0)
934 tgl 12691 UBC 0 : pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
934 tgl 12692 EUB : oprcode);
12693 :
957 peter 12694 CBC 91 : oprregproc = convertRegProcReference(oprcode);
3326 sfrost 12695 91 : if (oprregproc)
12696 : {
1698 peter_e 12697 91 : appendPQExpBuffer(details, " FUNCTION = %s", oprregproc);
3326 sfrost 12698 GIC 91 : free(oprregproc);
12699 : }
12700 :
7639 tgl 12701 91 : appendPQExpBuffer(oprid, "%s (",
6976 12702 91 : oprinfo->dobj.name);
7639 tgl 12703 ECB :
12704 : /*
7522 bruce 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.)
7639 tgl 12708 EUB : */
7639 tgl 12709 CBC 91 : if (strcmp(oprkind, "r") == 0 ||
7639 tgl 12710 GBC 91 : strcmp(oprkind, "b") == 0)
7639 tgl 12711 EUB : {
2370 tgl 12712 GIC 71 : appendPQExpBuffer(details, ",\n LEFTARG = %s", oprleft);
12713 71 : appendPQExpBufferStr(oprid, oprleft);
7639 tgl 12714 ECB : }
12715 : else
3429 heikki.linnakangas 12716 CBC 20 : appendPQExpBufferStr(oprid, "NONE");
7639 tgl 12717 ECB :
7639 tgl 12718 CBC 91 : if (strcmp(oprkind, "l") == 0 ||
7639 tgl 12719 GIC 71 : strcmp(oprkind, "b") == 0)
7639 tgl 12720 ECB : {
2370 tgl 12721 GIC 91 : appendPQExpBuffer(details, ",\n RIGHTARG = %s", oprright);
12722 91 : appendPQExpBuffer(oprid, ", %s)", oprright);
7639 tgl 12723 ECB : }
12724 : else
3429 heikki.linnakangas 12725 UIC 0 : appendPQExpBufferStr(oprid, ", NONE)");
7639 tgl 12726 ECB :
957 peter 12727 CBC 91 : oprref = getFormattedOperatorName(oprcom);
3326 sfrost 12728 91 : if (oprref)
12729 : {
12730 20 : appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
12731 20 : free(oprref);
3326 sfrost 12732 ECB : }
12733 :
957 peter 12734 GIC 91 : oprref = getFormattedOperatorName(oprnegate);
3326 sfrost 12735 91 : if (oprref)
12736 : {
12737 5 : appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
12738 5 : free(oprref);
3326 sfrost 12739 ECB : }
7639 tgl 12740 EUB :
5951 tgl 12741 GIC 91 : if (strcmp(oprcanmerge, "t") == 0)
3429 heikki.linnakangas 12742 GBC 20 : appendPQExpBufferStr(details, ",\n MERGES");
12743 :
7639 tgl 12744 CBC 91 : if (strcmp(oprcanhash, "t") == 0)
3429 heikki.linnakangas 12745 LBC 0 : appendPQExpBufferStr(details, ",\n HASHES");
7639 tgl 12746 ECB :
957 peter 12747 CBC 91 : oprregproc = convertRegProcReference(oprrest);
3326 sfrost 12748 GIC 91 : if (oprregproc)
12749 : {
12750 20 : appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
12751 20 : free(oprregproc);
12752 : }
12753 :
957 peter 12754 CBC 91 : oprregproc = convertRegProcReference(oprjoin);
3326 sfrost 12755 GIC 91 : if (oprregproc)
3326 sfrost 12756 ECB : {
3326 sfrost 12757 GIC 20 : appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
12758 20 : free(oprregproc);
12759 : }
12760 :
7621 tgl 12761 CBC 91 : appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
6976 12762 91 : fmtId(oprinfo->dobj.namespace->dobj.name),
12763 : oprid->data);
12764 :
1868 tgl 12765 GIC 91 : appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12766 91 : fmtId(oprinfo->dobj.namespace->dobj.name),
6976 tgl 12767 CBC 91 : oprinfo->dobj.name, details->data);
7639 tgl 12768 ECB :
3099 alvherre 12769 GIC 91 : if (dopt->binary_upgrade)
1868 tgl 12770 12 : binary_upgrade_extension_member(q, &oprinfo->dobj,
1868 tgl 12771 CBC 12 : "OPERATOR", oprid->data,
1868 tgl 12772 GIC 12 : oprinfo->dobj.namespace->dobj.name);
4442 tgl 12773 ECB :
2559 sfrost 12774 CBC 91 : if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 12775 GBC 91 : ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
1528 alvherre 12776 GIC 91 : ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
12777 : .namespace = oprinfo->dobj.namespace->dobj.name,
1528 alvherre 12778 ECB : .owner = oprinfo->rolname,
12779 : .description = "OPERATOR",
12780 : .section = SECTION_PRE_DATA,
12781 : .createStmt = q->data,
1528 alvherre 12782 EUB : .dropStmt = delq->data));
12783 :
12784 : /* Dump Operator Comments */
2559 sfrost 12785 GIC 91 : if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 12786 LBC 0 : dumpComment(fout, "OPERATOR", oprid->data,
2559 sfrost 12787 0 : oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12788 0 : oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
7639 tgl 12789 ECB :
7639 tgl 12790 GIC 91 : PQclear(res);
7639 tgl 12791 ECB :
7639 tgl 12792 CBC 91 : destroyPQExpBuffer(query);
7639 tgl 12793 GIC 91 : destroyPQExpBuffer(q);
7639 tgl 12794 CBC 91 : destroyPQExpBuffer(delq);
7639 tgl 12795 GIC 91 : destroyPQExpBuffer(oprid);
12796 91 : destroyPQExpBuffer(details);
7639 tgl 12797 ECB : }
12798 :
12799 : /*
12800 : * Convert a function reference obtained from pg_operator
7639 tgl 12801 EUB : *
12802 : * Returns allocated string of what to print, or NULL if function references
3326 sfrost 12803 ECB : * is InvalidOid. Returned string is expected to be free'd by the caller.
12804 : *
2370 tgl 12805 : * The input is a REGPROCEDURE display; we have to strip the argument-types
12806 : * part.
7639 12807 : */
12808 : static char *
957 peter 12809 GIC 273 : convertRegProcReference(const char *proc)
12810 : {
12811 : char *name;
12812 : char *paren;
2370 tgl 12813 ECB : bool inquote;
12814 :
7639 12815 : /* In all cases "-" means a null reference */
7639 tgl 12816 GIC 273 : if (strcmp(proc, "-") == 0)
12817 142 : return NULL;
7639 tgl 12818 EUB :
2370 tgl 12819 GIC 131 : name = pg_strdup(proc);
12820 : /* find non-double-quoted left paren */
2370 tgl 12821 CBC 131 : inquote = false;
2370 tgl 12822 GIC 1462 : for (paren = name; *paren; paren++)
7639 tgl 12823 ECB : {
2370 tgl 12824 CBC 1462 : if (*paren == '(' && !inquote)
12825 : {
12826 131 : *paren = '\0';
2370 tgl 12827 GIC 131 : break;
8106 pjw 12828 ECB : }
2370 tgl 12829 GIC 1331 : if (*paren == '"')
12830 50 : inquote = !inquote;
12831 : }
12832 131 : return name;
12833 : }
7639 tgl 12834 ECB :
12835 : /*
1868 12836 : * getFormattedOperatorName - retrieve the operator name for the
12837 : * given operator OID (presented in string form).
12838 : *
1868 tgl 12839 EUB : * Returns an allocated string, or NULL if the given OID is invalid.
12840 : * Caller is responsible for free'ing result string.
12841 : *
1868 tgl 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 *
957 peter 12850 CBC 470 : getFormattedOperatorName(const char *oproid)
7639 tgl 12851 ECB : {
1868 12852 : OprInfo *oprInfo;
12853 :
7639 12854 : /* In all cases "0" means a null reference */
1868 tgl 12855 CBC 470 : if (strcmp(oproid, "0") == 0)
7639 12856 445 : return NULL;
12857 :
1868 tgl 12858 GIC 25 : oprInfo = findOprByOid(atooid(oproid));
12859 25 : if (oprInfo == NULL)
12860 : {
1469 peter 12861 UIC 0 : pg_log_warning("could not find operator with OID %s",
12862 : oproid);
1868 tgl 12863 0 : return NULL;
12864 : }
1868 tgl 12865 ECB :
1868 tgl 12866 GBC 25 : return psprintf("OPERATOR(%s.%s)",
1868 tgl 12867 GIC 25 : fmtId(oprInfo->dobj.namespace->dobj.name),
1868 tgl 12868 EUB : oprInfo->dobj.name);
12869 : }
7558 tgl 12870 ECB :
5710 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 *
4079 rhaas 12880 GIC 180 : convertTSFunction(Archive *fout, Oid funcOid)
12881 : {
12882 : char *result;
5710 tgl 12883 ECB : char query[128];
12884 : PGresult *res;
12885 :
5710 tgl 12886 GIC 180 : snprintf(query, sizeof(query),
12887 : "SELECT '%u'::pg_catalog.regproc", funcOid);
4070 rhaas 12888 180 : res = ExecuteSqlQueryForSingleRow(fout, query);
12889 :
4153 bruce 12890 180 : result = pg_strdup(PQgetvalue(res, 0, 0));
12891 :
5710 tgl 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
788 peter 12902 82 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
12903 : {
2573 alvherre 12904 82 : DumpOptions *dopt = fout->dopt;
12905 : PQExpBuffer q;
12906 : PQExpBuffer delq;
12907 : char *qamname;
12908 :
12909 : /* Do nothing in data-only dump */
489 tgl 12910 82 : if (dopt->dataOnly)
2573 alvherre 12911 6 : return;
12912 :
12913 76 : q = createPQExpBuffer();
12914 76 : delq = createPQExpBuffer();
12915 :
2573 alvherre 12916 CBC 76 : qamname = pg_strdup(fmtId(aminfo->dobj.name));
2573 alvherre 12917 ECB :
2573 alvherre 12918 GIC 76 : appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12919 :
12920 76 : switch (aminfo->amtype)
12921 : {
12922 36 : case AMTYPE_INDEX:
1375 drowley 12923 CBC 36 : appendPQExpBufferStr(q, "TYPE INDEX ");
2573 alvherre 12924 36 : break;
1495 andres 12925 GIC 40 : case AMTYPE_TABLE:
1375 drowley 12926 CBC 40 : appendPQExpBufferStr(q, "TYPE TABLE ");
1495 andres 12927 40 : break;
2573 alvherre 12928 LBC 0 : default:
1469 peter 12929 0 : pg_log_warning("invalid type \"%c\" of access method \"%s\"",
1418 tgl 12930 ECB : aminfo->amtype, qamname);
2573 alvherre 12931 UIC 0 : destroyPQExpBuffer(q);
2573 alvherre 12932 LBC 0 : destroyPQExpBuffer(delq);
1868 tgl 12933 UIC 0 : free(qamname);
2573 alvherre 12934 0 : return;
2573 alvherre 12935 ECB : }
12936 :
2573 alvherre 12937 GIC 76 : appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12938 :
12939 76 : appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12940 : qamname);
12941 :
2380 tgl 12942 76 : if (dopt->binary_upgrade)
1868 12943 4 : binary_upgrade_extension_member(q, &aminfo->dobj,
12944 : "ACCESS METHOD", qamname, NULL);
12945 :
2497 sfrost 12946 76 : if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12947 76 : ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
1528 alvherre 12948 76 : ARCHIVE_OPTS(.tag = aminfo->dobj.name,
1528 alvherre 12949 ECB : .description = "ACCESS METHOD",
12950 : .section = SECTION_PRE_DATA,
12951 : .createStmt = q->data,
12952 : .dropStmt = delq->data));
12953 :
2573 12954 : /* Dump Access Method Comments */
2497 sfrost 12955 GIC 76 : if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 12956 LBC 0 : dumpComment(fout, "ACCESS METHOD", qamname,
12957 : NULL, "",
2497 sfrost 12958 0 : aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12959 :
2573 alvherre 12960 CBC 76 : destroyPQExpBuffer(q);
12961 76 : destroyPQExpBuffer(delq);
1868 tgl 12962 76 : free(qamname);
2573 alvherre 12963 ECB : }
5710 tgl 12964 :
7558 12965 : /*
7064 12966 : * dumpOpclass
7558 12967 : * write out a single operator class definition
12968 : */
12969 : static void
788 peter 12970 GIC 132 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
7558 tgl 12971 ECB : {
2643 tgl 12972 CBC 132 : DumpOptions *dopt = fout->dopt;
7064 tgl 12973 ECB : PQExpBuffer query;
12974 : PQExpBuffer q;
12975 : PQExpBuffer delq;
1868 12976 : PQExpBuffer nameusing;
7558 12977 : PGresult *res;
12978 : int ntups;
12979 : int i_opcintype;
12980 : int i_opckeytype;
12981 : int i_opcdefault;
12982 : int i_opcfamily;
4519 12983 : int i_opcfamilyname;
5920 tgl 12984 EUB : int i_opcfamilynsp;
12985 : int i_amname;
12986 : int i_amopstrategy;
7558 tgl 12987 ECB : int i_amopopr;
4519 12988 : int i_sortfamily;
12989 : int i_sortfamilynsp;
7558 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;
4519 13003 : char *sortfamily;
13004 : char *sortfamilynsp;
7558 13005 : char *amprocnum;
13006 : char *amproc;
13007 : char *amproclefttype;
13008 : char *amprocrighttype;
13009 : bool needComma;
13010 : int i;
13011 :
489 13012 : /* Do nothing in data-only dump */
489 tgl 13013 GIC 132 : if (dopt->dataOnly)
7064 tgl 13014 CBC 9 : return;
7064 tgl 13015 ECB :
7064 tgl 13016 GIC 123 : query = createPQExpBuffer();
13017 123 : q = createPQExpBuffer();
7064 tgl 13018 GBC 123 : delq = createPQExpBuffer();
1868 tgl 13019 GIC 123 : nameusing = createPQExpBuffer();
7558 tgl 13020 ECB :
13021 : /* Get additional fields from the pg_opclass row */
481 tgl 13022 GIC 123 : appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
481 tgl 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",
481 tgl 13032 GIC 123 : opcinfo->dobj.catId.oid);
13033 :
4070 rhaas 13034 CBC 123 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
7558 tgl 13035 ECB :
7558 tgl 13036 GIC 123 : i_opcintype = PQfnumber(res, "opcintype");
7558 tgl 13037 CBC 123 : i_opckeytype = PQfnumber(res, "opckeytype");
7558 tgl 13038 GBC 123 : i_opcdefault = PQfnumber(res, "opcdefault");
5920 tgl 13039 GIC 123 : i_opcfamily = PQfnumber(res, "opcfamily");
4519 tgl 13040 CBC 123 : i_opcfamilyname = PQfnumber(res, "opcfamilyname");
5920 13041 123 : i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
7558 tgl 13042 GIC 123 : i_amname = PQfnumber(res, "amname");
7558 tgl 13043 ECB :
2144 13044 : /* opcintype may still be needed after we PQclear res */
2144 tgl 13045 GIC 123 : opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
7558 13046 123 : opckeytype = PQgetvalue(res, 0, i_opckeytype);
7558 tgl 13047 CBC 123 : opcdefault = PQgetvalue(res, 0, i_opcdefault);
4519 tgl 13048 ECB : /* opcfamily will still be needed after we PQclear res */
4153 bruce 13049 GIC 123 : opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
4519 tgl 13050 CBC 123 : opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
5920 13051 123 : opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
13052 : /* amname will still be needed after we PQclear res */
4153 bruce 13053 GIC 123 : amname = pg_strdup(PQgetvalue(res, 0, i_amname));
7558 tgl 13054 ECB :
7558 tgl 13055 CBC 123 : appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
1868 tgl 13056 GIC 123 : fmtQualifiedDumpable(opcinfo));
7558 13057 123 : appendPQExpBuffer(delq, " USING %s;\n",
7539 peter_e 13058 ECB : fmtId(amname));
7558 tgl 13059 :
13060 : /* Build the fixed portion of the CREATE command */
7539 peter_e 13061 GIC 123 : appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
1868 tgl 13062 CBC 123 : fmtQualifiedDumpable(opcinfo));
7558 13063 123 : if (strcmp(opcdefault, "t") == 0)
3429 heikki.linnakangas 13064 LBC 0 : appendPQExpBufferStr(q, "DEFAULT ");
5920 tgl 13065 CBC 123 : appendPQExpBuffer(q, "FOR TYPE %s USING %s",
13066 : opcintype,
7539 peter_e 13067 ECB : fmtId(amname));
2552 tgl 13068 CBC 123 : if (strlen(opcfamilyname) > 0)
5920 tgl 13069 ECB : {
3429 heikki.linnakangas 13070 GIC 123 : appendPQExpBufferStr(q, " FAMILY ");
1868 tgl 13071 123 : appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
2838 heikki.linnakangas 13072 123 : appendPQExpBufferStr(q, fmtId(opcfamilyname));
13073 : }
3429 13074 123 : appendPQExpBufferStr(q, " AS\n ");
13075 :
7558 tgl 13076 123 : needComma = false;
13077 :
7558 tgl 13078 CBC 123 : if (strcmp(opckeytype, "-") != 0)
7558 tgl 13079 EUB : {
7539 peter_e 13080 UBC 0 : appendPQExpBuffer(q, "STORAGE %s",
7558 tgl 13081 EUB : opckeytype);
7558 tgl 13082 UIC 0 : needComma = true;
7558 tgl 13083 ECB : }
13084 :
7558 tgl 13085 CBC 123 : PQclear(res);
7558 tgl 13086 ECB :
13087 : /*
13088 : * Now fetch and print the OPERATOR entries (pg_amop rows).
4519 13089 : *
13090 : * Print only those opfamily members that are tied to the opclass by
13091 : * pg_depend entries.
13092 : */
7558 tgl 13093 GIC 123 : resetPQExpBuffer(query);
481 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 "
481 tgl 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",
481 tgl 13106 GIC 123 : opcinfo->dobj.catId.oid,
13107 : opcfamily);
13108 :
4079 rhaas 13109 CBC 123 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7558 tgl 13110 ECB :
7558 tgl 13111 GIC 123 : ntups = PQntuples(res);
7558 tgl 13112 ECB :
7558 tgl 13113 GIC 123 : i_amopstrategy = PQfnumber(res, "amopstrategy");
7558 tgl 13114 CBC 123 : i_amopopr = PQfnumber(res, "amopopr");
4519 13115 123 : i_sortfamily = PQfnumber(res, "sortfamily");
4519 tgl 13116 GIC 123 : i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
7558 tgl 13117 ECB :
7558 tgl 13118 GIC 349 : for (i = 0; i < ntups; i++)
7558 tgl 13119 ECB : {
7558 tgl 13120 CBC 226 : amopstrategy = PQgetvalue(res, i, i_amopstrategy);
7558 tgl 13121 GIC 226 : amopopr = PQgetvalue(res, i, i_amopopr);
4519 tgl 13122 CBC 226 : sortfamily = PQgetvalue(res, i, i_sortfamily);
13123 226 : sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
13124 :
7558 13125 226 : if (needComma)
3429 heikki.linnakangas 13126 GIC 144 : appendPQExpBufferStr(q, " ,\n ");
13127 :
7539 peter_e 13128 226 : appendPQExpBuffer(q, "OPERATOR %s %s",
13129 : amopstrategy, amopopr);
13130 :
4519 tgl 13131 226 : if (strlen(sortfamily) > 0)
13132 : {
3429 heikki.linnakangas 13133 UIC 0 : appendPQExpBufferStr(q, " FOR ORDER BY ");
1868 tgl 13134 0 : appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
3429 heikki.linnakangas 13135 0 : appendPQExpBufferStr(q, fmtId(sortfamily));
13136 : }
13137 :
7558 tgl 13138 GIC 226 : needComma = true;
13139 : }
13140 :
13141 123 : PQclear(res);
13142 :
7558 tgl 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.
4141 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
481 13151 : * of a btree sort support function for a cross-type comparison.
7558 13152 : */
7558 tgl 13153 GIC 123 : resetPQExpBuffer(query);
7558 tgl 13154 EUB :
481 tgl 13155 GIC 123 : appendPQExpBuffer(query, "SELECT amprocnum, "
481 tgl 13156 EUB : "amproc::pg_catalog.regprocedure, "
13157 : "amproclefttype::pg_catalog.regtype, "
13158 : "amprocrighttype::pg_catalog.regtype "
481 tgl 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",
481 tgl 13165 GIC 123 : opcinfo->dobj.catId.oid);
13166 :
4079 rhaas 13167 123 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13168 :
7558 tgl 13169 123 : ntups = PQntuples(res);
13170 :
13171 123 : i_amprocnum = PQfnumber(res, "amprocnum");
13172 123 : i_amproc = PQfnumber(res, "amproc");
4141 tgl 13173 CBC 123 : i_amproclefttype = PQfnumber(res, "amproclefttype");
4141 tgl 13174 GIC 123 : i_amprocrighttype = PQfnumber(res, "amprocrighttype");
13175 :
7558 13176 159 : for (i = 0; i < ntups; i++)
13177 : {
13178 36 : amprocnum = PQgetvalue(res, i, i_amprocnum);
7558 tgl 13179 CBC 36 : amproc = PQgetvalue(res, i, i_amproc);
4141 tgl 13180 GIC 36 : amproclefttype = PQgetvalue(res, i, i_amproclefttype);
4141 tgl 13181 CBC 36 : amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
13182 :
7558 13183 36 : if (needComma)
3429 heikki.linnakangas 13184 GIC 36 : appendPQExpBufferStr(q, " ,\n ");
7558 tgl 13185 ECB :
4141 tgl 13186 GIC 36 : appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
4141 tgl 13187 ECB :
4141 tgl 13188 GIC 36 : if (*amproclefttype && *amprocrighttype)
13189 36 : appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
13190 :
13191 36 : appendPQExpBuffer(q, " %s", amproc);
13192 :
7558 13193 36 : needComma = true;
13194 : }
7558 tgl 13195 ECB :
7558 tgl 13196 GIC 123 : PQclear(res);
7558 tgl 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.
2144 13203 : */
2144 tgl 13204 CBC 123 : if (!needComma)
2144 tgl 13205 GIC 41 : appendPQExpBuffer(q, "STORAGE %s", opcintype);
2144 tgl 13206 ECB :
3429 heikki.linnakangas 13207 CBC 123 : appendPQExpBufferStr(q, ";\n");
13208 :
1868 tgl 13209 123 : appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
1868 tgl 13210 GIC 123 : appendPQExpBuffer(nameusing, " USING %s",
4442 tgl 13211 ECB : fmtId(amname));
13212 :
3099 alvherre 13213 CBC 123 : if (dopt->binary_upgrade)
1868 tgl 13214 GIC 6 : binary_upgrade_extension_member(q, &opcinfo->dobj,
1868 tgl 13215 CBC 6 : "OPERATOR CLASS", nameusing->data,
13216 6 : opcinfo->dobj.namespace->dobj.name);
4442 tgl 13217 ECB :
2559 sfrost 13218 CBC 123 : if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13219 123 : ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
1528 alvherre 13220 123 : ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
1528 alvherre 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));
7558 tgl 13227 :
13228 : /* Dump Operator Class Comments */
2559 sfrost 13229 GIC 123 : if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 13230 LBC 0 : dumpComment(fout, "OPERATOR CLASS", nameusing->data,
2225 tgl 13231 UIC 0 : opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
2559 sfrost 13232 LBC 0 : opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13233 :
2144 tgl 13234 GIC 123 : free(opcintype);
2144 tgl 13235 CBC 123 : free(opcfamily);
7079 13236 123 : free(amname);
7558 tgl 13237 GIC 123 : destroyPQExpBuffer(query);
13238 123 : destroyPQExpBuffer(q);
7558 tgl 13239 CBC 123 : destroyPQExpBuffer(delq);
1868 13240 123 : destroyPQExpBuffer(nameusing);
7558 tgl 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
4519 13248 : * specific opclass within the opfamily.
5920 tgl 13249 EUB : */
13250 : static void
788 peter 13251 GBC 113 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
13252 : {
2643 tgl 13253 CBC 113 : DumpOptions *dopt = fout->dopt;
5920 tgl 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;
4519 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 */
489 tgl 13284 GIC 113 : if (dopt->dataOnly)
5920 13285 6 : return;
13286 :
13287 107 : query = createPQExpBuffer();
13288 107 : q = createPQExpBuffer();
13289 107 : delq = createPQExpBuffer();
1868 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 : */
481 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 "
481 tgl 13306 ECB : "AND amopfamily = '%u'::pg_catalog.oid "
13307 : "ORDER BY amopstrategy",
481 tgl 13308 GIC 107 : opfinfo->dobj.catId.oid,
481 tgl 13309 CBC 107 : opfinfo->dobj.catId.oid);
5920 tgl 13310 ECB :
4079 rhaas 13311 CBC 107 : res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5920 tgl 13312 ECB :
5920 tgl 13313 GIC 107 : resetPQExpBuffer(query);
13314 :
5920 tgl 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 :
4079 rhaas 13327 107 : res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13328 :
5920 tgl 13329 ECB : /* Get additional fields from the pg_opfamily row */
5920 tgl 13330 CBC 107 : resetPQExpBuffer(query);
5920 tgl 13331 ECB :
5920 tgl 13332 CBC 107 : appendPQExpBuffer(query, "SELECT "
2118 tgl 13333 ECB : "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
5920 13334 : "FROM pg_catalog.pg_opfamily "
13335 : "WHERE oid = '%u'::pg_catalog.oid",
5920 tgl 13336 GIC 107 : opfinfo->dobj.catId.oid);
13337 :
4070 rhaas 13338 CBC 107 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
5920 tgl 13339 ECB :
5920 tgl 13340 CBC 107 : i_amname = PQfnumber(res, "amname");
13341 :
5920 tgl 13342 ECB : /* amname will still be needed after we PQclear res */
4153 bruce 13343 CBC 107 : amname = pg_strdup(PQgetvalue(res, 0, i_amname));
5920 tgl 13344 ECB :
5920 tgl 13345 GIC 107 : appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
1868 tgl 13346 CBC 107 : fmtQualifiedDumpable(opfinfo));
5920 tgl 13347 GIC 107 : appendPQExpBuffer(delq, " USING %s;\n",
5920 tgl 13348 ECB : fmtId(amname));
13349 :
13350 : /* Build the fixed portion of the CREATE command */
5920 tgl 13351 GIC 107 : appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
1868 13352 107 : fmtQualifiedDumpable(opfinfo));
5920 13353 107 : appendPQExpBuffer(q, " USING %s;\n",
5920 tgl 13354 ECB : fmtId(amname));
13355 :
5920 tgl 13356 CBC 107 : PQclear(res);
5920 tgl 13357 EUB :
5920 tgl 13358 ECB : /* Do we need an ALTER to add loose members? */
5920 tgl 13359 GIC 107 : if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13360 : {
5920 tgl 13361 CBC 51 : appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
1868 tgl 13362 GIC 51 : fmtQualifiedDumpable(opfinfo));
5920 tgl 13363 CBC 51 : appendPQExpBuffer(q, " USING %s ADD\n ",
5920 tgl 13364 ECB : fmtId(amname));
13365 :
5920 tgl 13366 GIC 51 : needComma = false;
5920 tgl 13367 ECB :
13368 : /*
13369 : * Now fetch and print the OPERATOR entries (pg_amop rows).
13370 : */
5920 tgl 13371 CBC 51 : ntups = PQntuples(res_ops);
13372 :
5920 tgl 13373 GBC 51 : i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
5920 tgl 13374 GIC 51 : i_amopopr = PQfnumber(res_ops, "amopopr");
4519 tgl 13375 GBC 51 : i_sortfamily = PQfnumber(res_ops, "sortfamily");
4519 tgl 13376 GIC 51 : i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13377 :
5920 tgl 13378 CBC 231 : for (i = 0; i < ntups; i++)
13379 : {
5920 tgl 13380 GIC 180 : amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13381 180 : amopopr = PQgetvalue(res_ops, i, i_amopopr);
4519 13382 180 : sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13383 180 : sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13384 :
5920 13385 180 : if (needComma)
3429 heikki.linnakangas 13386 CBC 144 : appendPQExpBufferStr(q, " ,\n ");
5920 tgl 13387 ECB :
5920 tgl 13388 GIC 180 : appendPQExpBuffer(q, "OPERATOR %s %s",
13389 : amopstrategy, amopopr);
13390 :
4519 13391 180 : if (strlen(sortfamily) > 0)
13392 : {
3429 heikki.linnakangas 13393 UIC 0 : appendPQExpBufferStr(q, " FOR ORDER BY ");
1868 tgl 13394 0 : appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
3429 heikki.linnakangas 13395 0 : appendPQExpBufferStr(q, fmtId(sortfamily));
13396 : }
13397 :
5920 tgl 13398 GIC 180 : needComma = true;
5920 tgl 13399 ECB : }
13400 :
13401 : /*
13402 : * Now fetch and print the FUNCTION entries (pg_amproc rows).
13403 : */
5920 tgl 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)
3429 heikki.linnakangas 13419 180 : appendPQExpBufferStr(q, " ,\n ");
13420 :
5920 tgl 13421 195 : appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13422 : amprocnum, amproclefttype, amprocrighttype,
13423 : amproc);
5920 tgl 13424 ECB :
5920 tgl 13425 GIC 195 : needComma = true;
5920 tgl 13426 EUB : }
13427 :
3429 heikki.linnakangas 13428 GBC 51 : appendPQExpBufferStr(q, ";\n");
13429 : }
13430 :
1868 tgl 13431 CBC 107 : appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
1868 tgl 13432 GIC 107 : appendPQExpBuffer(nameusing, " USING %s",
13433 : fmtId(amname));
4442 tgl 13434 ECB :
3099 alvherre 13435 GIC 107 : if (dopt->binary_upgrade)
1868 tgl 13436 9 : binary_upgrade_extension_member(q, &opfinfo->dobj,
13437 9 : "OPERATOR FAMILY", nameusing->data,
13438 9 : opfinfo->dobj.namespace->dobj.name);
13439 :
2559 sfrost 13440 107 : if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13441 107 : ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
1528 alvherre 13442 107 : ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
13443 : .namespace = opfinfo->dobj.namespace->dobj.name,
13444 : .owner = opfinfo->rolname,
13445 : .description = "OPERATOR FAMILY",
1528 alvherre 13446 ECB : .section = SECTION_PRE_DATA,
13447 : .createStmt = q->data,
13448 : .dropStmt = delq->data));
13449 :
13450 : /* Dump Operator Family Comments */
2559 sfrost 13451 GIC 107 : if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 13452 UIC 0 : dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
2225 13453 0 : opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
2559 sfrost 13454 0 : opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13455 :
5920 tgl 13456 GIC 107 : free(amname);
13457 107 : PQclear(res_ops);
5920 tgl 13458 CBC 107 : PQclear(res_procs);
5920 tgl 13459 GIC 107 : destroyPQExpBuffer(query);
5920 tgl 13460 CBC 107 : destroyPQExpBuffer(q);
5920 tgl 13461 GIC 107 : destroyPQExpBuffer(delq);
1868 tgl 13462 CBC 107 : destroyPQExpBuffer(nameusing);
13463 : }
5920 tgl 13464 ECB :
4439 peter_e 13465 : /*
13466 : * dumpCollation
13467 : * write out a single collation definition
13468 : */
13469 : static void
788 peter 13470 GIC 81 : dumpCollation(Archive *fout, const CollInfo *collinfo)
4439 peter_e 13471 ECB : {
2643 tgl 13472 CBC 81 : DumpOptions *dopt = fout->dopt;
4439 peter_e 13473 ECB : PQExpBuffer query;
13474 : PQExpBuffer q;
13475 : PQExpBuffer delq;
1868 tgl 13476 : char *qcollname;
4439 peter_e 13477 : PGresult *res;
13478 : int i_collprovider;
1479 peter 13479 : int i_collisdeterministic;
13480 : int i_collcollate;
4439 peter_e 13481 : int i_collctype;
228 peter 13482 : int i_colliculocale;
13483 : int i_collicurules;
13484 : const char *collprovider;
4439 peter_e 13485 : const char *collcollate;
13486 : const char *collctype;
228 peter 13487 : const char *colliculocale;
13488 : const char *collicurules;
13489 :
13490 : /* Do nothing in data-only dump */
489 tgl 13491 CBC 81 : if (dopt->dataOnly)
4439 peter_e 13492 GIC 6 : return;
13493 :
13494 75 : query = createPQExpBuffer();
13495 75 : q = createPQExpBuffer();
13496 75 : delq = createPQExpBuffer();
13497 :
1868 tgl 13498 75 : qcollname = pg_strdup(fmtId(collinfo->dobj.name));
4439 peter_e 13499 ECB :
3224 noah 13500 : /* Get collation-specific details */
1375 drowley 13501 GIC 75 : appendPQExpBufferStr(query, "SELECT ");
1479 peter 13502 ECB :
2208 peter_e 13503 GIC 75 : if (fout->remoteVersion >= 100000)
1375 drowley 13504 CBC 75 : appendPQExpBufferStr(query,
702 tmunro 13505 ECB : "collprovider, "
13506 : "collversion, ");
13507 : else
1375 drowley 13508 LBC 0 : appendPQExpBufferStr(query,
702 tmunro 13509 ECB : "'c' AS collprovider, "
13510 : "NULL AS collversion, ");
1479 peter 13511 :
1479 peter 13512 GIC 75 : if (fout->remoteVersion >= 120000)
1375 drowley 13513 CBC 75 : appendPQExpBufferStr(query,
1375 drowley 13514 ECB : "collisdeterministic, ");
1479 peter 13515 : else
1375 drowley 13516 UIC 0 : appendPQExpBufferStr(query,
13517 : "true AS collisdeterministic, ");
13518 :
228 peter 13519 GIC 75 : if (fout->remoteVersion >= 150000)
13520 75 : appendPQExpBufferStr(query,
13521 : "colliculocale, ");
13522 : else
228 peter 13523 UIC 0 : appendPQExpBufferStr(query,
228 peter 13524 ECB : "NULL AS colliculocale, ");
228 peter 13525 EUB :
32 peter 13526 GNC 75 : if (fout->remoteVersion >= 160000)
13527 75 : appendPQExpBufferStr(query,
13528 : "collicurules, ");
13529 : else
32 peter 13530 UNC 0 : appendPQExpBufferStr(query,
13531 : "NULL AS collicurules, ");
13532 :
1479 peter 13533 GBC 75 : appendPQExpBuffer(query,
1479 peter 13534 EUB : "collcollate, "
13535 : "collctype "
1479 peter 13536 ECB : "FROM pg_catalog.pg_collation c "
13537 : "WHERE c.oid = '%u'::pg_catalog.oid",
1479 peter 13538 CBC 75 : collinfo->dobj.catId.oid);
4439 peter_e 13539 ECB :
4070 rhaas 13540 CBC 75 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
4439 peter_e 13541 ECB :
2208 peter_e 13542 CBC 75 : i_collprovider = PQfnumber(res, "collprovider");
1479 peter 13543 GIC 75 : i_collisdeterministic = PQfnumber(res, "collisdeterministic");
4439 peter_e 13544 75 : i_collcollate = PQfnumber(res, "collcollate");
13545 75 : i_collctype = PQfnumber(res, "collctype");
228 peter 13546 75 : i_colliculocale = PQfnumber(res, "colliculocale");
32 peter 13547 GNC 75 : i_collicurules = PQfnumber(res, "collicurules");
13548 :
2208 peter_e 13549 GIC 75 : collprovider = PQgetvalue(res, 0, i_collprovider);
13550 :
228 peter 13551 75 : if (!PQgetisnull(res, 0, i_collcollate))
13552 35 : collcollate = PQgetvalue(res, 0, i_collcollate);
13553 : else
228 peter 13554 CBC 40 : collcollate = NULL;
13555 :
13556 75 : if (!PQgetisnull(res, 0, i_collctype))
228 peter 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 :
32 peter 13566 GNC 75 : if (!PQgetisnull(res, 0, i_collicurules))
32 peter 13567 UNC 0 : collicurules = PQgetvalue(res, 0, i_collicurules);
13568 : else
32 peter 13569 GNC 75 : collicurules = NULL;
13570 :
1868 tgl 13571 GIC 75 : appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13572 75 : fmtQualifiedDumpable(collinfo));
13573 :
2208 peter_e 13574 75 : appendPQExpBuffer(q, "CREATE COLLATION %s (",
1868 tgl 13575 75 : fmtQualifiedDumpable(collinfo));
13576 :
2208 peter_e 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");
2126 peter_e 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
366 tgl 13586 0 : pg_fatal("unrecognized collation provider: %s",
13587 : collprovider);
13588 :
1479 peter 13589 GIC 75 : if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
1479 peter 13590 UIC 0 : appendPQExpBufferStr(q, ", deterministic = false");
13591 :
228 peter 13592 CBC 75 : if (colliculocale != NULL)
2208 peter_e 13593 ECB : {
2208 peter_e 13594 GIC 40 : appendPQExpBufferStr(q, ", locale = ");
228 peter 13595 CBC 40 : appendStringLiteralAH(q, colliculocale, fout);
2208 peter_e 13596 ECB : }
13597 : else
13598 : {
228 peter 13599 GIC 35 : Assert(collcollate != NULL);
13600 35 : Assert(collctype != NULL);
13601 :
13602 35 : if (strcmp(collcollate, collctype) == 0)
13603 : {
228 peter 13604 CBC 35 : appendPQExpBufferStr(q, ", locale = ");
228 peter 13605 GIC 35 : appendStringLiteralAH(q, collcollate, fout);
13606 : }
13607 : else
13608 : {
228 peter 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 :
32 peter 13616 GNC 75 : if (collicurules)
13617 : {
32 peter 13618 UNC 0 : appendPQExpBufferStr(q, ", rules = ");
13619 0 : appendStringLiteralAH(q, collicurules, fout);
13620 : }
13621 :
702 tmunro 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 : */
702 tmunro 13626 GIC 75 : if (dopt->binary_upgrade)
702 tmunro 13627 ECB : {
13628 : int i_collversion;
13629 :
702 tmunro 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 : }
702 tmunro 13639 ECB :
3429 heikki.linnakangas 13640 GIC 75 : appendPQExpBufferStr(q, ");\n");
4439 peter_e 13641 ECB :
3099 alvherre 13642 GIC 75 : if (dopt->binary_upgrade)
1868 tgl 13643 3 : binary_upgrade_extension_member(q, &collinfo->dobj,
1868 tgl 13644 ECB : "COLLATION", qcollname,
1868 tgl 13645 GIC 3 : collinfo->dobj.namespace->dobj.name);
4439 peter_e 13646 ECB :
2559 sfrost 13647 GIC 75 : if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13648 75 : ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
1528 alvherre 13649 75 : ARCHIVE_OPTS(.tag = collinfo->dobj.name,
1528 alvherre 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 :
4439 peter_e 13657 : /* Dump Collation Comments */
2559 sfrost 13658 GIC 75 : if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 13659 CBC 35 : dumpComment(fout, "COLLATION", qcollname,
2559 sfrost 13660 35 : collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13661 35 : collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13662 :
4439 peter_e 13663 GIC 75 : PQclear(res);
13664 :
4439 peter_e 13665 CBC 75 : destroyPQExpBuffer(query);
13666 75 : destroyPQExpBuffer(q);
13667 75 : destroyPQExpBuffer(delq);
1868 tgl 13668 GIC 75 : free(qcollname);
13669 : }
4439 peter_e 13670 ECB :
13671 : /*
13672 : * dumpConversion
7079 tgl 13673 : * write out a single conversion definition
13674 : */
13675 : static void
788 peter 13676 CBC 39 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
7079 tgl 13677 ECB : {
2643 tgl 13678 GIC 39 : DumpOptions *dopt = fout->dopt;
13679 : PQExpBuffer query;
7064 tgl 13680 ECB : PQExpBuffer q;
13681 : PQExpBuffer delq;
13682 : char *qconvname;
13683 : PGresult *res;
13684 : int i_conforencoding;
7079 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 */
489 tgl 13694 CBC 39 : if (dopt->dataOnly)
7064 13695 3 : return;
7064 tgl 13696 ECB :
7064 tgl 13697 CBC 36 : query = createPQExpBuffer();
7064 tgl 13698 GIC 36 : q = createPQExpBuffer();
7064 tgl 13699 CBC 36 : delq = createPQExpBuffer();
7064 tgl 13700 ECB :
1868 tgl 13701 GIC 36 : qconvname = pg_strdup(fmtId(convinfo->dobj.name));
7079 tgl 13702 ECB :
13703 : /* Get conversion-specific details */
4381 peter_e 13704 GIC 36 : appendPQExpBuffer(query, "SELECT "
2118 tgl 13705 ECB : "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13706 : "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
7076 tgl 13707 EUB : "conproc, condefault "
13708 : "FROM pg_catalog.pg_conversion c "
7064 13709 : "WHERE c.oid = '%u'::pg_catalog.oid",
7064 tgl 13710 GIC 36 : convinfo->dobj.catId.oid);
13711 :
4070 rhaas 13712 CBC 36 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13713 :
7079 tgl 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");
7079 tgl 13718 ECB :
7079 tgl 13719 GIC 36 : conforencoding = PQgetvalue(res, 0, i_conforencoding);
7079 tgl 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');
7079 tgl 13723 ECB :
1868 tgl 13724 GIC 36 : appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
1868 tgl 13725 CBC 36 : fmtQualifiedDumpable(convinfo));
13726 :
7079 13727 36 : appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
6797 bruce 13728 ECB : (condefault) ? "DEFAULT " : "",
1868 tgl 13729 CBC 36 : fmtQualifiedDumpable(convinfo));
6160 13730 36 : appendStringLiteralAH(q, conforencoding, fout);
3429 heikki.linnakangas 13731 GIC 36 : appendPQExpBufferStr(q, " TO ");
6160 tgl 13732 CBC 36 : appendStringLiteralAH(q, contoencoding, fout);
2370 tgl 13733 ECB : /* regproc output is already sufficiently quoted */
7079 tgl 13734 GIC 36 : appendPQExpBuffer(q, " FROM %s;\n", conproc);
6869 tgl 13735 ECB :
3099 alvherre 13736 GIC 36 : if (dopt->binary_upgrade)
1868 tgl 13737 1 : binary_upgrade_extension_member(q, &convinfo->dobj,
13738 : "CONVERSION", qconvname,
1868 tgl 13739 CBC 1 : convinfo->dobj.namespace->dobj.name);
13740 :
2559 sfrost 13741 GIC 36 : if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 13742 CBC 36 : ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
1528 alvherre 13743 GIC 36 : ARCHIVE_OPTS(.tag = convinfo->dobj.name,
13744 : .namespace = convinfo->dobj.namespace->dobj.name,
1528 alvherre 13745 ECB : .owner = convinfo->rolname,
13746 : .description = "CONVERSION",
13747 : .section = SECTION_PRE_DATA,
13748 : .createStmt = q->data,
13749 : .dropStmt = delq->data));
7079 tgl 13750 :
13751 : /* Dump Conversion Comments */
2559 sfrost 13752 CBC 36 : if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 13753 GIC 36 : dumpComment(fout, "CONVERSION", qconvname,
2559 sfrost 13754 CBC 36 : convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13755 36 : convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
7639 tgl 13756 ECB :
7064 tgl 13757 GIC 36 : PQclear(res);
13758 :
13759 36 : destroyPQExpBuffer(query);
13760 36 : destroyPQExpBuffer(q);
13761 36 : destroyPQExpBuffer(delq);
1868 13762 36 : free(qconvname);
13763 : }
13764 :
7621 tgl 13765 ECB : /*
7621 tgl 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.
7621 tgl 13770 ECB : */
7630 peter_e 13771 : static char *
788 peter 13772 CBC 288 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
7630 peter_e 13773 ECB : {
13774 : PQExpBufferData buf;
6100 tgl 13775 : int j;
7630 peter_e 13776 :
7630 peter_e 13777 GIC 288 : initPQExpBuffer(&buf);
7584 bruce 13778 288 : if (honor_quotes)
3429 heikki.linnakangas 13779 UIC 0 : appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13780 : else
3429 heikki.linnakangas 13781 GIC 288 : appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13782 :
6100 tgl 13783 288 : if (agginfo->aggfn.nargs == 0)
1375 drowley 13784 CBC 40 : appendPQExpBufferStr(&buf, "(*)");
13785 : else
7630 peter_e 13786 ECB : {
3429 heikki.linnakangas 13787 GIC 248 : appendPQExpBufferChar(&buf, '(');
6100 tgl 13788 541 : for (j = 0; j < agginfo->aggfn.nargs; j++)
13789 293 : appendPQExpBuffer(&buf, "%s%s",
13790 : (j > 0) ? ", " : "",
13791 : getFormattedTypeName(fout,
578 13792 293 : agginfo->aggfn.argtypes[j],
13793 : zeroIsError));
3429 heikki.linnakangas 13794 248 : appendPQExpBufferChar(&buf, ')');
13795 : }
7630 peter_e 13796 288 : return buf.data;
13797 : }
13798 :
13799 : /*
13800 : * dumpAgg
13801 : * write out a single aggregate definition
13802 : */
13803 : static void
788 peter 13804 292 : dumpAgg(Archive *fout, const AggInfo *agginfo)
7639 tgl 13805 ECB : {
2643 tgl 13806 CBC 292 : DumpOptions *dopt = fout->dopt;
13807 : PQExpBuffer query;
7064 tgl 13808 ECB : PQExpBuffer q;
13809 : PQExpBuffer delq;
13810 : PQExpBuffer details;
13811 : char *aggsig; /* identity signature */
2118 tgl 13812 CBC 292 : char *aggfullsig = NULL; /* full signature */
13813 : char *aggsig_tag;
13814 : PGresult *res;
7639 tgl 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;
3284 tgl 13822 EUB : const char *aggmtransfn;
13823 : const char *aggminvtransfn;
13824 : const char *aggmfinalfn;
13825 : bool aggfinalextra;
3273 tgl 13826 ECB : bool aggmfinalextra;
2003 13827 : char aggfinalmodify;
13828 : char aggmfinalmodify;
13829 : const char *aggsortop;
3326 sfrost 13830 EUB : char *aggsortconvop;
13831 : char aggkind;
13832 : const char *aggtranstype;
3431 tgl 13833 ECB : const char *aggtransspace;
3284 13834 : const char *aggmtranstype;
13835 : const char *aggmtransspace;
13836 : const char *agginitval;
3284 tgl 13837 EUB : const char *aggminitval;
13838 : const char *proparallel;
13839 : char defaultfinalmodify;
7639 tgl 13840 ECB :
489 13841 : /* Do nothing in data-only dump */
489 tgl 13842 GIC 292 : if (dopt->dataOnly)
7064 13843 4 : return;
7064 tgl 13844 EUB :
7064 tgl 13845 GIC 288 : query = createPQExpBuffer();
13846 288 : q = createPQExpBuffer();
7064 tgl 13847 CBC 288 : delq = createPQExpBuffer();
7064 tgl 13848 GIC 288 : details = createPQExpBuffer();
13849 :
489 13850 288 : if (!fout->is_prepared[PREPQUERY_DUMPAGG])
13851 : {
489 tgl 13852 ECB : /* Set up query for aggregate-specific details */
906 drowley 13853 GIC 58 : appendPQExpBufferStr(query,
489 tgl 13854 ECB : "PREPARE dumpAgg(pg_catalog.oid) AS\n");
13855 :
906 drowley 13856 CBC 58 : appendPQExpBufferStr(query,
489 tgl 13857 ECB : "SELECT "
13858 : "aggtransfn,\n"
13859 : "aggfinalfn,\n"
13860 : "aggtranstype::pg_catalog.regtype,\n"
481 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");
489 13865 :
489 tgl 13866 CBC 58 : if (fout->remoteVersion >= 90400)
489 tgl 13867 GIC 58 : appendPQExpBufferStr(query,
489 tgl 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
489 tgl 13879 UIC 0 : appendPQExpBufferStr(query,
489 tgl 13880 ECB : "'n' AS aggkind,\n"
489 tgl 13881 EUB : "'-' AS aggmtransfn,\n"
13882 : "'-' AS aggminvtransfn,\n"
489 tgl 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 :
489 tgl 13891 CBC 58 : if (fout->remoteVersion >= 90600)
13892 58 : appendPQExpBufferStr(query,
489 tgl 13893 ECB : "aggcombinefn,\n"
13894 : "aggserialfn,\n"
13895 : "aggdeserialfn,\n"
489 tgl 13896 EUB : "proparallel,\n");
13897 : else
489 tgl 13898 UBC 0 : appendPQExpBufferStr(query,
13899 : "'-' AS aggcombinefn,\n"
489 tgl 13900 EUB : "'-' AS aggserialfn,\n"
13901 : "'-' AS aggdeserialfn,\n"
13902 : "'u' AS proparallel,\n");
489 tgl 13903 ECB :
489 tgl 13904 GBC 58 : if (fout->remoteVersion >= 110000)
489 tgl 13905 GIC 58 : appendPQExpBufferStr(query,
489 tgl 13906 ECB : "aggfinalmodify,\n"
13907 : "aggmfinalmodify\n");
13908 : else
489 tgl 13909 LBC 0 : appendPQExpBufferStr(query,
13910 : "'0' AS aggfinalmodify,\n"
13911 : "'0' AS aggmfinalmodify\n");
13912 :
906 drowley 13913 CBC 58 : appendPQExpBufferStr(query,
489 tgl 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 :
489 tgl 13918 CBC 58 : ExecuteSqlStatement(fout, query->data);
489 tgl 13919 ECB :
489 tgl 13920 GIC 58 : fout->is_prepared[PREPQUERY_DUMPAGG] = true;
13921 : }
13922 :
489 tgl 13923 GBC 288 : printfPQExpBuffer(query,
489 tgl 13924 EUB : "EXECUTE dumpAgg('%u')",
998 peter 13925 GBC 288 : agginfo->aggfn.dobj.catId.oid);
9345 bruce 13926 EUB :
4070 rhaas 13927 GIC 288 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13928 :
7639 tgl 13929 288 : i_agginitval = PQfnumber(res, "agginitval");
3284 tgl 13930 CBC 288 : i_aggminitval = PQfnumber(res, "aggminitval");
13931 :
998 peter 13932 GBC 288 : aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
13933 288 : aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
998 peter 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"));
998 peter 13940 CBC 288 : aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
998 peter 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];
998 peter 13944 CBC 288 : aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
13945 288 : aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
998 peter 13946 GIC 288 : aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
998 peter 13947 CBC 288 : aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
13948 288 : aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
998 peter 13949 GIC 288 : aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
7639 tgl 13950 288 : agginitval = PQgetvalue(res, 0, i_agginitval);
3284 13951 288 : aggminitval = PQgetvalue(res, 0, i_aggminitval);
998 peter 13952 288 : proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13953 :
3505 tgl 13954 ECB : {
13955 : char *funcargs;
13956 : char *funciargs;
13957 :
3505 tgl 13958 GIC 288 : funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
3505 tgl 13959 CBC 288 : funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
3505 tgl 13960 GIC 288 : aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
3505 tgl 13961 CBC 288 : aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
3505 tgl 13962 ECB : }
13963 :
7064 tgl 13964 GIC 288 : aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13965 :
13966 : /* identify default modify flag for aggkind (must match DefineAggregate) */
2003 13967 288 : defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
13968 : /* replace omitted flags for old versions */
13969 288 : if (aggfinalmodify == '0')
2003 tgl 13970 UIC 0 : aggfinalmodify = defaultfinalmodify;
2003 tgl 13971 GIC 288 : if (aggmfinalmodify == '0')
2003 tgl 13972 LBC 0 : aggmfinalmodify = defaultfinalmodify;
2003 tgl 13973 ECB :
2370 13974 : /* regproc and regtype output is already sufficiently quoted */
2370 tgl 13975 CBC 288 : appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
13976 : aggtransfn, aggtranstype);
7950 peter_e 13977 ECB :
3431 tgl 13978 GIC 288 : if (strcmp(aggtransspace, "0") != 0)
3431 tgl 13979 ECB : {
3431 tgl 13980 CBC 5 : appendPQExpBuffer(details, ",\n SSPACE = %s",
3431 tgl 13981 ECB : aggtransspace);
13982 : }
13983 :
7639 tgl 13984 GIC 288 : if (!PQgetisnull(res, 0, i_agginitval))
13985 : {
3429 heikki.linnakangas 13986 211 : appendPQExpBufferStr(details, ",\n INITCOND = ");
6160 tgl 13987 211 : appendStringLiteralAH(details, agginitval, fout);
13988 : }
13989 :
7639 tgl 13990 CBC 288 : if (strcmp(aggfinalfn, "-") != 0)
13991 : {
7539 peter_e 13992 136 : appendPQExpBuffer(details, ",\n FINALFUNC = %s",
13993 : aggfinalfn);
3273 tgl 13994 GIC 136 : if (aggfinalextra)
13995 10 : appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
2003 13996 136 : if (aggfinalmodify != defaultfinalmodify)
13997 : {
13998 36 : switch (aggfinalmodify)
13999 : {
2003 tgl 14000 UIC 0 : case AGGMODIFY_READ_ONLY:
14001 0 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_ONLY");
14002 0 : break;
1784 tgl 14003 GIC 36 : case AGGMODIFY_SHAREABLE:
14004 36 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = SHAREABLE");
2003 14005 36 : break;
2003 tgl 14006 UIC 0 : case AGGMODIFY_READ_WRITE:
14007 0 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_WRITE");
2003 tgl 14008 LBC 0 : break;
14009 0 : default:
366 tgl 14010 UIC 0 : pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
366 tgl 14011 ECB : agginfo->aggfn.dobj.name);
2003 14012 : break;
14013 : }
14014 : }
7639 14015 : }
14016 :
2636 rhaas 14017 GIC 288 : if (strcmp(aggcombinefn, "-") != 0)
2495 rhaas 14018 LBC 0 : appendPQExpBuffer(details, ",\n COMBINEFUNC = %s", aggcombinefn);
14019 :
2567 rhaas 14020 GIC 288 : if (strcmp(aggserialfn, "-") != 0)
2495 rhaas 14021 UIC 0 : appendPQExpBuffer(details, ",\n SERIALFUNC = %s", aggserialfn);
14022 :
2482 tgl 14023 GIC 288 : if (strcmp(aggdeserialfn, "-") != 0)
2495 rhaas 14024 LBC 0 : appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
14025 :
3284 tgl 14026 CBC 288 : if (strcmp(aggmtransfn, "-") != 0)
14027 : {
14028 30 : appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
3284 tgl 14029 ECB : aggmtransfn,
14030 : aggminvtransfn,
14031 : aggmtranstype);
14032 : }
14033 :
3284 tgl 14034 CBC 288 : if (strcmp(aggmtransspace, "0") != 0)
3284 tgl 14035 ECB : {
3284 tgl 14036 LBC 0 : appendPQExpBuffer(details, ",\n MSSPACE = %s",
14037 : aggmtransspace);
3284 tgl 14038 ECB : }
14039 :
3284 tgl 14040 GIC 288 : if (!PQgetisnull(res, 0, i_aggminitval))
3284 tgl 14041 ECB : {
3284 tgl 14042 GIC 10 : appendPQExpBufferStr(details, ",\n MINITCOND = ");
3284 tgl 14043 CBC 10 : appendStringLiteralAH(details, aggminitval, fout);
3284 tgl 14044 ECB : }
14045 :
3284 tgl 14046 CBC 288 : if (strcmp(aggmfinalfn, "-") != 0)
14047 : {
3284 tgl 14048 LBC 0 : appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
14049 : aggmfinalfn);
3273 14050 0 : if (aggmfinalextra)
14051 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
2003 tgl 14052 UIC 0 : if (aggmfinalmodify != defaultfinalmodify)
2003 tgl 14053 ECB : {
2003 tgl 14054 UIC 0 : switch (aggmfinalmodify)
2003 tgl 14055 ECB : {
2003 tgl 14056 LBC 0 : case AGGMODIFY_READ_ONLY:
14057 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_ONLY");
2003 tgl 14058 UIC 0 : break;
1784 14059 0 : case AGGMODIFY_SHAREABLE:
14060 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = SHAREABLE");
2003 14061 0 : break;
14062 0 : case AGGMODIFY_READ_WRITE:
14063 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_WRITE");
14064 0 : break;
14065 0 : default:
366 tgl 14066 LBC 0 : pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
366 tgl 14067 ECB : agginfo->aggfn.dobj.name);
2003 14068 : break;
14069 : }
14070 : }
3284 14071 : }
14072 :
957 peter 14073 CBC 288 : aggsortconvop = getFormattedOperatorName(aggsortop);
3326 sfrost 14074 288 : if (aggsortconvop)
6571 tgl 14075 ECB : {
6571 tgl 14076 LBC 0 : appendPQExpBuffer(details, ",\n SORTOP = %s",
14077 : aggsortconvop);
3326 sfrost 14078 UIC 0 : free(aggsortconvop);
14079 : }
14080 :
2003 tgl 14081 GIC 288 : if (aggkind == AGGKIND_HYPOTHETICAL)
3394 14082 5 : appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
14083 :
998 peter 14084 288 : if (proparallel[0] != PROPARALLEL_UNSAFE)
14085 : {
2545 rhaas 14086 CBC 5 : if (proparallel[0] == PROPARALLEL_SAFE)
2545 rhaas 14087 GIC 5 : appendPQExpBufferStr(details, ",\n PARALLEL = safe");
2545 rhaas 14088 UIC 0 : else if (proparallel[0] == PROPARALLEL_RESTRICTED)
14089 0 : appendPQExpBufferStr(details, ",\n PARALLEL = restricted");
14090 0 : else if (proparallel[0] != PROPARALLEL_UNSAFE)
366 tgl 14091 LBC 0 : pg_fatal("unrecognized proparallel value for function \"%s\"",
366 tgl 14092 ECB : agginfo->aggfn.dobj.name);
2545 rhaas 14093 EUB : }
14094 :
7621 tgl 14095 CBC 288 : appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
6976 tgl 14096 GIC 288 : fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
7584 bruce 14097 ECB : aggsig);
9345 14098 :
1868 tgl 14099 GIC 576 : appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
14100 288 : fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
3331 bruce 14101 ECB : aggfullsig ? aggfullsig : aggsig, details->data);
8844 14102 :
3099 alvherre 14103 CBC 288 : if (dopt->binary_upgrade)
1868 tgl 14104 GIC 49 : binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
14105 : "AGGREGATE", aggsig,
1868 tgl 14106 CBC 49 : agginfo->aggfn.dobj.namespace->dobj.name);
14107 :
2559 sfrost 14108 288 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 14109 GIC 272 : ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
2559 sfrost 14110 CBC 272 : agginfo->aggfn.dobj.dumpId,
1528 alvherre 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));
9345 bruce 14118 ECB :
14119 : /* Dump Aggregate Comments */
2559 sfrost 14120 CBC 288 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 14121 GIC 10 : dumpComment(fout, "AGGREGATE", aggsig,
2559 sfrost 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 :
2559 sfrost 14126 CBC 288 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
1868 tgl 14127 UIC 0 : dumpSecLabel(fout, "AGGREGATE", aggsig,
2559 sfrost 14128 0 : agginfo->aggfn.dobj.namespace->dobj.name,
14129 0 : agginfo->aggfn.rolname,
2118 tgl 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 : */
7064 tgl 14137 GIC 288 : free(aggsig);
14138 :
4080 rhaas 14139 288 : aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14140 :
2559 sfrost 14141 288 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
1002 tgl 14142 17 : dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
14143 : "FUNCTION", aggsig, NULL,
2559 sfrost 14144 17 : agginfo->aggfn.dobj.namespace->dobj.name,
489 tgl 14145 17 : agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
14146 :
7064 14147 288 : free(aggsig);
297 peter 14148 GNC 288 : free(aggfullsig);
7064 tgl 14149 GIC 288 : free(aggsig_tag);
14150 :
7639 14151 288 : PQclear(res);
14152 :
14153 288 : destroyPQExpBuffer(query);
7919 14154 288 : destroyPQExpBuffer(q);
7919 tgl 14155 CBC 288 : destroyPQExpBuffer(delq);
14156 288 : destroyPQExpBuffer(details);
14157 : }
9770 scrappy 14158 ECB :
5710 tgl 14159 : /*
14160 : * dumpTSParser
14161 : * write out a single text search parser
14162 : */
14163 : static void
788 peter 14164 GIC 39 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
14165 : {
2643 tgl 14166 CBC 39 : DumpOptions *dopt = fout->dopt;
14167 : PQExpBuffer q;
14168 : PQExpBuffer delq;
1868 tgl 14169 ECB : char *qprsname;
14170 :
14171 : /* Do nothing in data-only dump */
489 tgl 14172 GIC 39 : if (dopt->dataOnly)
5710 14173 3 : return;
14174 :
14175 36 : q = createPQExpBuffer();
14176 36 : delq = createPQExpBuffer();
14177 :
1868 14178 36 : qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
5710 tgl 14179 ECB :
5710 tgl 14180 CBC 36 : appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
1868 tgl 14181 GIC 36 : fmtQualifiedDumpable(prsinfo));
14182 :
5710 14183 36 : appendPQExpBuffer(q, " START = %s,\n",
4079 rhaas 14184 36 : convertTSFunction(fout, prsinfo->prsstart));
5710 tgl 14185 36 : appendPQExpBuffer(q, " GETTOKEN = %s,\n",
4079 rhaas 14186 36 : convertTSFunction(fout, prsinfo->prstoken));
5710 tgl 14187 36 : appendPQExpBuffer(q, " END = %s,\n",
4079 rhaas 14188 36 : convertTSFunction(fout, prsinfo->prsend));
5710 tgl 14189 36 : if (prsinfo->prsheadline != InvalidOid)
5710 tgl 14190 UIC 0 : appendPQExpBuffer(q, " HEADLINE = %s,\n",
4079 rhaas 14191 0 : convertTSFunction(fout, prsinfo->prsheadline));
5710 tgl 14192 GBC 36 : appendPQExpBuffer(q, " LEXTYPES = %s );\n",
4079 rhaas 14193 GIC 36 : convertTSFunction(fout, prsinfo->prslextype));
14194 :
1868 tgl 14195 36 : appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14196 36 : fmtQualifiedDumpable(prsinfo));
14197 :
3099 alvherre 14198 36 : if (dopt->binary_upgrade)
1868 tgl 14199 1 : binary_upgrade_extension_member(q, &prsinfo->dobj,
14200 : "TEXT SEARCH PARSER", qprsname,
14201 1 : prsinfo->dobj.namespace->dobj.name);
14202 :
2559 sfrost 14203 36 : if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 14204 CBC 36 : ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
1528 alvherre 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));
5710 tgl 14211 EUB :
14212 : /* Dump Parser Comments */
2559 sfrost 14213 GIC 36 : if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 14214 36 : dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
2225 14215 36 : prsinfo->dobj.namespace->dobj.name, "",
2559 sfrost 14216 36 : prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
5710 tgl 14217 ECB :
5710 tgl 14218 CBC 36 : destroyPQExpBuffer(q);
5710 tgl 14219 GIC 36 : destroyPQExpBuffer(delq);
1868 14220 36 : free(qprsname);
14221 : }
5710 tgl 14222 EUB :
14223 : /*
14224 : * dumpTSDictionary
14225 : * write out a single text search dictionary
5710 tgl 14226 ECB : */
14227 : static void
788 peter 14228 GIC 84 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
14229 : {
2643 tgl 14230 84 : DumpOptions *dopt = fout->dopt;
5710 tgl 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 */
489 tgl 14240 CBC 84 : if (dopt->dataOnly)
5710 tgl 14241 GIC 3 : return;
5710 tgl 14242 ECB :
5710 tgl 14243 CBC 81 : q = createPQExpBuffer();
5710 tgl 14244 GIC 81 : delq = createPQExpBuffer();
5710 tgl 14245 CBC 81 : query = createPQExpBuffer();
5710 tgl 14246 ECB :
1868 tgl 14247 CBC 81 : qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
1868 tgl 14248 ECB :
5710 14249 : /* Fetch name and namespace of the dictionary's template */
5710 tgl 14250 CBC 81 : appendPQExpBuffer(query, "SELECT nspname, tmplname "
5710 tgl 14251 ECB : "FROM pg_ts_template p, pg_namespace n "
14252 : "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
5710 tgl 14253 CBC 81 : dictinfo->dicttemplate);
4070 rhaas 14254 81 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
5710 tgl 14255 81 : nspname = PQgetvalue(res, 0, 0);
14256 81 : tmplname = PQgetvalue(res, 0, 1);
5710 tgl 14257 ECB :
5710 tgl 14258 CBC 81 : appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
1868 14259 81 : fmtQualifiedDumpable(dictinfo));
5710 tgl 14260 ECB :
3429 heikki.linnakangas 14261 CBC 81 : appendPQExpBufferStr(q, " TEMPLATE = ");
1868 tgl 14262 81 : appendPQExpBuffer(q, "%s.", fmtId(nspname));
3429 heikki.linnakangas 14263 81 : appendPQExpBufferStr(q, fmtId(tmplname));
5710 tgl 14264 ECB :
5710 tgl 14265 CBC 81 : PQclear(res);
14266 :
14267 : /* the dictinitoption can be dumped straight into the command */
5710 tgl 14268 GIC 81 : if (dictinfo->dictinitoption)
5709 14269 45 : appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
14270 :
3429 heikki.linnakangas 14271 CBC 81 : appendPQExpBufferStr(q, " );\n");
5710 tgl 14272 ECB :
1868 tgl 14273 CBC 81 : appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14274 81 : fmtQualifiedDumpable(dictinfo));
14275 :
3099 alvherre 14276 GIC 81 : if (dopt->binary_upgrade)
1868 tgl 14277 CBC 10 : binary_upgrade_extension_member(q, &dictinfo->dobj,
14278 : "TEXT SEARCH DICTIONARY", qdictname,
1868 tgl 14279 GIC 10 : dictinfo->dobj.namespace->dobj.name);
4442 tgl 14280 ECB :
2559 sfrost 14281 GIC 81 : if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 14282 CBC 81 : ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
1528 alvherre 14283 GBC 81 : ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
1528 alvherre 14284 ECB : .namespace = dictinfo->dobj.namespace->dobj.name,
1528 alvherre 14285 EUB : .owner = dictinfo->rolname,
14286 : .description = "TEXT SEARCH DICTIONARY",
14287 : .section = SECTION_PRE_DATA,
1528 alvherre 14288 ECB : .createStmt = q->data,
14289 : .dropStmt = delq->data));
14290 :
5710 tgl 14291 : /* Dump Dictionary Comments */
2559 sfrost 14292 GIC 81 : if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 14293 CBC 36 : dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
2225 tgl 14294 GIC 36 : dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
2559 sfrost 14295 36 : dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14296 :
5710 tgl 14297 CBC 81 : destroyPQExpBuffer(q);
5710 tgl 14298 GIC 81 : destroyPQExpBuffer(delq);
5710 tgl 14299 CBC 81 : destroyPQExpBuffer(query);
1868 14300 81 : free(qdictname);
14301 : }
14302 :
5710 tgl 14303 ECB : /*
14304 : * dumpTSTemplate
14305 : * write out a single text search template
14306 : */
14307 : static void
788 peter 14308 CBC 39 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
5710 tgl 14309 ECB : {
2643 tgl 14310 GIC 39 : DumpOptions *dopt = fout->dopt;
5710 tgl 14311 ECB : PQExpBuffer q;
14312 : PQExpBuffer delq;
1868 tgl 14313 EUB : char *qtmplname;
5710 14314 :
489 14315 : /* Do nothing in data-only dump */
489 tgl 14316 CBC 39 : if (dopt->dataOnly)
5710 14317 3 : return;
5710 tgl 14318 ECB :
5710 tgl 14319 GBC 36 : q = createPQExpBuffer();
14320 36 : delq = createPQExpBuffer();
5710 tgl 14321 EUB :
1868 tgl 14322 GBC 36 : qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
5710 tgl 14323 EUB :
5710 tgl 14324 GIC 36 : appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
1868 14325 36 : fmtQualifiedDumpable(tmplinfo));
14326 :
5710 14327 36 : if (tmplinfo->tmplinit != InvalidOid)
5710 tgl 14328 UIC 0 : appendPQExpBuffer(q, " INIT = %s,\n",
4079 rhaas 14329 0 : convertTSFunction(fout, tmplinfo->tmplinit));
5710 tgl 14330 CBC 36 : appendPQExpBuffer(q, " LEXIZE = %s );\n",
4079 rhaas 14331 GBC 36 : convertTSFunction(fout, tmplinfo->tmpllexize));
14332 :
1868 tgl 14333 CBC 36 : appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
1868 tgl 14334 GBC 36 : fmtQualifiedDumpable(tmplinfo));
14335 :
3099 alvherre 14336 CBC 36 : if (dopt->binary_upgrade)
1868 tgl 14337 GBC 1 : binary_upgrade_extension_member(q, &tmplinfo->dobj,
14338 : "TEXT SEARCH TEMPLATE", qtmplname,
1868 tgl 14339 CBC 1 : tmplinfo->dobj.namespace->dobj.name);
14340 :
2559 sfrost 14341 36 : if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 14342 GIC 36 : ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
1528 alvherre 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,
1528 alvherre 14347 ECB : .createStmt = q->data,
14348 : .dropStmt = delq->data));
5710 tgl 14349 EUB :
14350 : /* Dump Template Comments */
2559 sfrost 14351 GIC 36 : if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 14352 36 : dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
2225 tgl 14353 CBC 36 : tmplinfo->dobj.namespace->dobj.name, "",
2559 sfrost 14354 GIC 36 : tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
5710 tgl 14355 ECB :
5710 tgl 14356 CBC 36 : destroyPQExpBuffer(q);
5710 tgl 14357 GIC 36 : destroyPQExpBuffer(delq);
1868 14358 36 : free(qtmplname);
5710 tgl 14359 ECB : }
14360 :
5710 tgl 14361 EUB : /*
14362 : * dumpTSConfig
14363 : * write out a single text search configuration
14364 : */
14365 : static void
788 peter 14366 GIC 59 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
5710 tgl 14367 EUB : {
2643 tgl 14368 GIC 59 : DumpOptions *dopt = fout->dopt;
5710 tgl 14369 EUB : PQExpBuffer q;
14370 : PQExpBuffer delq;
14371 : PQExpBuffer query;
1868 14372 : char *qcfgname;
5710 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 */
489 tgl 14382 GIC 59 : if (dopt->dataOnly)
5710 14383 3 : return;
14384 :
14385 56 : q = createPQExpBuffer();
5710 tgl 14386 CBC 56 : delq = createPQExpBuffer();
14387 56 : query = createPQExpBuffer();
14388 :
1868 tgl 14389 GBC 56 : qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14390 :
5710 tgl 14391 EUB : /* Fetch name and namespace of the config's parser */
5710 tgl 14392 GIC 56 : appendPQExpBuffer(query, "SELECT nspname, prsname "
14393 : "FROM pg_ts_parser p, pg_namespace n "
5710 tgl 14394 ECB : "WHERE p.oid = '%u' AND n.oid = prsnamespace",
5710 tgl 14395 CBC 56 : cfginfo->cfgparser);
4070 rhaas 14396 GIC 56 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
5710 tgl 14397 CBC 56 : nspname = PQgetvalue(res, 0, 0);
5710 tgl 14398 GIC 56 : prsname = PQgetvalue(res, 0, 1);
5710 tgl 14399 ECB :
5710 tgl 14400 CBC 56 : appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
1868 tgl 14401 GBC 56 : fmtQualifiedDumpable(cfginfo));
5710 tgl 14402 EUB :
1868 tgl 14403 GBC 56 : appendPQExpBuffer(q, " PARSER = %s.", fmtId(nspname));
5710 14404 56 : appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14405 :
5710 tgl 14406 GIC 56 : PQclear(res);
14407 :
5710 tgl 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"
2187 peter_e 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"
5710 tgl 14416 : "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
5710 tgl 14417 CBC 56 : cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14418 :
4079 rhaas 14419 56 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5710 tgl 14420 GIC 56 : ntups = PQntuples(res);
5710 tgl 14421 ECB :
5710 tgl 14422 CBC 56 : i_tokenname = PQfnumber(res, "tokenname");
14423 56 : i_dictname = PQfnumber(res, "dictname");
5710 tgl 14424 ECB :
5710 tgl 14425 GIC 1255 : for (i = 0; i < ntups; i++)
14426 : {
5624 bruce 14427 1199 : char *tokenname = PQgetvalue(res, i, i_tokenname);
14428 1199 : char *dictname = PQgetvalue(res, i, i_dictname);
14429 :
5710 tgl 14430 1199 : if (i == 0 ||
5624 bruce 14431 1143 : strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14432 : {
5710 tgl 14433 ECB : /* starting a new token type, so start a new command */
5710 tgl 14434 CBC 1064 : if (i > 0)
3429 heikki.linnakangas 14435 1008 : appendPQExpBufferStr(q, ";\n");
5710 tgl 14436 1064 : appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
1868 14437 1064 : fmtQualifiedDumpable(cfginfo));
14438 : /* tokenname needs quoting, dictname does NOT */
5710 14439 1064 : appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
5710 tgl 14440 EUB : fmtId(tokenname), dictname);
14441 : }
14442 : else
5710 tgl 14443 GBC 135 : appendPQExpBuffer(q, ", %s", dictname);
14444 : }
14445 :
5710 tgl 14446 GIC 56 : if (ntups > 0)
3429 heikki.linnakangas 14447 56 : appendPQExpBufferStr(q, ";\n");
14448 :
5710 tgl 14449 56 : PQclear(res);
5710 tgl 14450 ECB :
1868 tgl 14451 GIC 56 : appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
1868 tgl 14452 CBC 56 : fmtQualifiedDumpable(cfginfo));
14453 :
3099 alvherre 14454 56 : if (dopt->binary_upgrade)
1868 tgl 14455 5 : binary_upgrade_extension_member(q, &cfginfo->dobj,
14456 : "TEXT SEARCH CONFIGURATION", qcfgname,
14457 5 : cfginfo->dobj.namespace->dobj.name);
4442 tgl 14458 ECB :
2559 sfrost 14459 GIC 56 : if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 14460 CBC 56 : ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
1528 alvherre 14461 56 : ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
1528 alvherre 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));
5710 tgl 14468 :
14469 : /* Dump Configuration Comments */
2559 sfrost 14470 GIC 56 : if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 14471 36 : dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
2225 14472 36 : cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
2559 sfrost 14473 36 : cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14474 :
5710 tgl 14475 56 : destroyPQExpBuffer(q);
14476 56 : destroyPQExpBuffer(delq);
5710 tgl 14477 CBC 56 : destroyPQExpBuffer(query);
1868 tgl 14478 GIC 56 : free(qcfgname);
5710 tgl 14479 ECB : }
14480 :
14481 : /*
14482 : * dumpForeignDataWrapper
14483 : * write out a single foreign-data wrapper definition
14484 : */
5224 peter_e 14485 : static void
788 peter 14486 CBC 45 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
14487 : {
2643 tgl 14488 45 : DumpOptions *dopt = fout->dopt;
5224 peter_e 14489 ECB : PQExpBuffer q;
14490 : PQExpBuffer delq;
4442 tgl 14491 : char *qfdwname;
14492 :
489 14493 : /* Do nothing in data-only dump */
489 tgl 14494 CBC 45 : if (dopt->dataOnly)
5224 peter_e 14495 GIC 4 : return;
5224 peter_e 14496 ECB :
5224 peter_e 14497 CBC 41 : q = createPQExpBuffer();
14498 41 : delq = createPQExpBuffer();
4442 tgl 14499 ECB :
4153 bruce 14500 CBC 41 : qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
5224 peter_e 14501 ECB :
5157 peter_e 14502 CBC 41 : appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
4442 tgl 14503 EUB : qfdwname);
5157 peter_e 14504 :
4432 tgl 14505 CBC 41 : if (strcmp(fdwinfo->fdwhandler, "-") != 0)
4432 tgl 14506 LBC 0 : appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14507 :
4432 tgl 14508 CBC 41 : if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
4432 tgl 14509 LBC 0 : appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14510 :
4432 tgl 14511 CBC 41 : if (strlen(fdwinfo->fdwoptions) > 0)
4112 peter_e 14512 LBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
14513 :
3429 heikki.linnakangas 14514 CBC 41 : appendPQExpBufferStr(q, ";\n");
14515 :
5224 peter_e 14516 41 : appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
4442 tgl 14517 ECB : qfdwname);
14518 :
3099 alvherre 14519 GIC 41 : if (dopt->binary_upgrade)
1868 tgl 14520 2 : binary_upgrade_extension_member(q, &fdwinfo->dobj,
14521 : "FOREIGN DATA WRAPPER", qfdwname,
14522 : NULL);
14523 :
2559 sfrost 14524 41 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14525 41 : ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
1528 alvherre 14526 CBC 41 : ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
1528 alvherre 14527 ECB : .owner = fdwinfo->rolname,
14528 : .description = "FOREIGN DATA WRAPPER",
14529 : .section = SECTION_PRE_DATA,
14530 : .createStmt = q->data,
14531 : .dropStmt = delq->data));
5224 peter_e 14532 :
1903 tgl 14533 : /* Dump Foreign Data Wrapper Comments */
1903 tgl 14534 GIC 41 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 14535 UIC 0 : dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
1903 14536 0 : NULL, fdwinfo->rolname,
14537 0 : fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14538 :
14539 : /* Handle the ACL */
2559 sfrost 14540 GIC 41 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
1002 tgl 14541 CBC 35 : dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
14542 : "FOREIGN DATA WRAPPER", qfdwname, NULL,
489 14543 35 : NULL, fdwinfo->rolname, &fdwinfo->dacl);
14544 :
4442 tgl 14545 GIC 41 : free(qfdwname);
14546 :
5224 peter_e 14547 41 : destroyPQExpBuffer(q);
14548 41 : destroyPQExpBuffer(delq);
14549 : }
14550 :
14551 : /*
14552 : * dumpForeignServer
5224 peter_e 14553 ECB : * write out a foreign server definition
14554 : */
14555 : static void
788 peter 14556 CBC 49 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
5224 peter_e 14557 ECB : {
2643 tgl 14558 CBC 49 : DumpOptions *dopt = fout->dopt;
14559 : PQExpBuffer q;
5224 peter_e 14560 ECB : PQExpBuffer delq;
14561 : PQExpBuffer query;
14562 : PGresult *res;
4442 tgl 14563 : char *qsrvname;
14564 : char *fdwname;
14565 :
489 14566 : /* Do nothing in data-only dump */
489 tgl 14567 CBC 49 : if (dopt->dataOnly)
5224 peter_e 14568 6 : return;
5224 peter_e 14569 ECB :
5224 peter_e 14570 GIC 43 : q = createPQExpBuffer();
5224 peter_e 14571 CBC 43 : delq = createPQExpBuffer();
14572 43 : query = createPQExpBuffer();
14573 :
4153 bruce 14574 43 : qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
4442 tgl 14575 ECB :
5224 peter_e 14576 : /* look up the foreign-data wrapper */
5224 peter_e 14577 GIC 43 : appendPQExpBuffer(query, "SELECT fdwname "
5224 peter_e 14578 ECB : "FROM pg_foreign_data_wrapper w "
14579 : "WHERE w.oid = '%u'",
5224 peter_e 14580 GIC 43 : srvinfo->srvfdw);
4070 rhaas 14581 CBC 43 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
5224 peter_e 14582 43 : fdwname = PQgetvalue(res, 0, 0);
14583 :
4442 tgl 14584 43 : appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
5224 peter_e 14585 GIC 43 : if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
5114 heikki.linnakangas 14586 ECB : {
3429 heikki.linnakangas 14587 LBC 0 : appendPQExpBufferStr(q, " TYPE ");
5114 heikki.linnakangas 14588 UIC 0 : appendStringLiteralAH(q, srvinfo->srvtype, fout);
5114 heikki.linnakangas 14589 ECB : }
5224 peter_e 14590 CBC 43 : if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14591 : {
3429 heikki.linnakangas 14592 LBC 0 : appendPQExpBufferStr(q, " VERSION ");
5114 heikki.linnakangas 14593 UIC 0 : appendStringLiteralAH(q, srvinfo->srvversion, fout);
5114 heikki.linnakangas 14594 ECB : }
5224 peter_e 14595 :
3429 heikki.linnakangas 14596 CBC 43 : appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
3429 heikki.linnakangas 14597 GIC 43 : appendPQExpBufferStr(q, fmtId(fdwname));
14598 :
5224 peter_e 14599 43 : if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
4112 peter_e 14600 UIC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
14601 :
3429 heikki.linnakangas 14602 GIC 43 : appendPQExpBufferStr(q, ";\n");
14603 :
5224 peter_e 14604 43 : appendPQExpBuffer(delq, "DROP SERVER %s;\n",
4442 tgl 14605 ECB : qsrvname);
14606 :
3099 alvherre 14607 CBC 43 : if (dopt->binary_upgrade)
1868 tgl 14608 2 : binary_upgrade_extension_member(q, &srvinfo->dobj,
14609 : "SERVER", qsrvname, NULL);
5224 peter_e 14610 ECB :
2559 sfrost 14611 CBC 43 : if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14612 43 : ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
1528 alvherre 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 */
1903 tgl 14621 43 : if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 14622 UIC 0 : dumpComment(fout, "SERVER", qsrvname,
1903 tgl 14623 LBC 0 : NULL, srvinfo->rolname,
1903 tgl 14624 UIC 0 : srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14625 :
14626 : /* Handle the ACL */
2559 sfrost 14627 GIC 43 : if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
1002 tgl 14628 35 : dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
1868 tgl 14629 ECB : "FOREIGN SERVER", qsrvname, NULL,
489 tgl 14630 CBC 35 : NULL, srvinfo->rolname, &srvinfo->dacl);
14631 :
5224 peter_e 14632 ECB : /* Dump user mappings */
2559 sfrost 14633 CBC 43 : if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
2559 sfrost 14634 GIC 43 : dumpUserMappings(fout,
2559 sfrost 14635 CBC 43 : srvinfo->dobj.name, NULL,
2559 sfrost 14636 GIC 43 : srvinfo->rolname,
2559 sfrost 14637 CBC 43 : srvinfo->dobj.catId, srvinfo->dobj.dumpId);
5224 peter_e 14638 ECB :
532 tgl 14639 GIC 43 : PQclear(res);
532 tgl 14640 ECB :
4442 tgl 14641 GBC 43 : free(qsrvname);
4442 tgl 14642 EUB :
5224 peter_e 14643 CBC 43 : destroyPQExpBuffer(q);
14644 43 : destroyPQExpBuffer(delq);
2554 tgl 14645 GIC 43 : destroyPQExpBuffer(query);
5224 peter_e 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
4652 tgl 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;
5224 peter_e 14664 ECB : PQExpBuffer tag;
14665 : PGresult *res;
14666 : int ntups;
4652 tgl 14667 : int i_usename;
14668 : int i_umoptions;
5224 peter_e 14669 : int i;
14670 :
5224 peter_e 14671 CBC 43 : q = createPQExpBuffer();
5224 peter_e 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
4652 tgl 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
3260 bruce 14681 : * OPTIONS clause. A possible alternative is to skip such mappings
14682 : * altogether, but it's not clear that that's an improvement.
14683 : */
5224 peter_e 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",
5224 peter_e 14695 ECB : catalogId.oid);
14696 :
4079 rhaas 14697 GIC 43 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5224 peter_e 14698 ECB :
5224 peter_e 14699 CBC 43 : ntups = PQntuples(res);
4652 tgl 14700 43 : i_usename = PQfnumber(res, "usename");
5224 peter_e 14701 GIC 43 : i_umoptions = PQfnumber(res, "umoptions");
5224 peter_e 14702 ECB :
5224 peter_e 14703 GIC 78 : for (i = 0; i < ntups; i++)
14704 : {
4652 tgl 14705 ECB : char *usename;
14706 : char *umoptions;
14707 :
4652 tgl 14708 CBC 35 : usename = PQgetvalue(res, i, i_usename);
5224 peter_e 14709 35 : umoptions = PQgetvalue(res, i, i_umoptions);
5224 peter_e 14710 ECB :
5224 peter_e 14711 CBC 35 : resetPQExpBuffer(q);
4652 tgl 14712 GIC 35 : appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
5224 peter_e 14713 CBC 35 : appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
5224 peter_e 14714 ECB :
5224 peter_e 14715 GIC 35 : if (umoptions && strlen(umoptions) > 0)
4112 peter_e 14716 LBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
5224 peter_e 14717 ECB :
3429 heikki.linnakangas 14718 GIC 35 : appendPQExpBufferStr(q, ";\n");
5224 peter_e 14719 ECB :
5224 peter_e 14720 GIC 35 : resetPQExpBuffer(delq);
4652 tgl 14721 CBC 35 : appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14722 35 : appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14723 :
5224 peter_e 14724 GIC 35 : resetPQExpBuffer(tag);
4652 tgl 14725 35 : appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14726 : usename, servername);
14727 :
5224 peter_e 14728 35 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 14729 35 : ARCHIVE_OPTS(.tag = tag->data,
1528 alvherre 14730 ECB : .namespace = namespace,
14731 : .owner = owner,
14732 : .description = "USER MAPPING",
14733 : .section = SECTION_PRE_DATA,
14734 : .createStmt = q->data,
14735 : .dropStmt = delq->data));
5224 peter_e 14736 : }
14737 :
5224 peter_e 14738 CBC 43 : PQclear(res);
14739 :
14740 43 : destroyPQExpBuffer(query);
14741 43 : destroyPQExpBuffer(delq);
3326 sfrost 14742 GIC 43 : destroyPQExpBuffer(tag);
5224 peter_e 14743 CBC 43 : destroyPQExpBuffer(q);
14744 43 : }
14745 :
14746 : /*
4934 tgl 14747 ECB : * Write out default privileges information
14748 : */
14749 : static void
788 peter 14750 CBC 154 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
14751 : {
2643 tgl 14752 154 : DumpOptions *dopt = fout->dopt;
14753 : PQExpBuffer q;
14754 : PQExpBuffer tag;
14755 : const char *type;
4934 tgl 14756 ECB :
14757 : /* Do nothing in data-only dump, or if we're skipping ACLs */
489 tgl 14758 GIC 154 : if (dopt->dataOnly || dopt->aclsSkip)
4934 tgl 14759 CBC 16 : return;
4934 tgl 14760 ECB :
4934 tgl 14761 GIC 138 : q = createPQExpBuffer();
4934 tgl 14762 CBC 138 : tag = createPQExpBuffer();
14763 :
14764 138 : switch (daclinfo->defaclobjtype)
4934 tgl 14765 ECB : {
4934 tgl 14766 GIC 69 : case DEFACLOBJ_RELATION:
4927 tgl 14767 CBC 69 : type = "TABLES";
4934 14768 69 : break;
4934 tgl 14769 UIC 0 : case DEFACLOBJ_SEQUENCE:
4927 tgl 14770 LBC 0 : type = "SEQUENCES";
4934 tgl 14771 UIC 0 : break;
4934 tgl 14772 CBC 69 : case DEFACLOBJ_FUNCTION:
4927 14773 69 : type = "FUNCTIONS";
4934 14774 69 : break;
3773 tgl 14775 UIC 0 : case DEFACLOBJ_TYPE:
14776 0 : type = "TYPES";
14777 0 : break;
2203 teodor 14778 0 : case DEFACLOBJ_NAMESPACE:
14779 0 : type = "SCHEMAS";
14780 0 : break;
4934 tgl 14781 0 : default:
14782 : /* shouldn't get here */
366 tgl 14783 LBC 0 : pg_fatal("unrecognized object type in default privileges: %d",
366 tgl 14784 ECB : (int) daclinfo->defaclobjtype);
4934 14785 : type = ""; /* keep compiler quiet */
14786 : }
14787 :
4927 tgl 14788 CBC 138 : appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
4934 tgl 14789 ECB :
14790 : /* build the actual command(s) for this tuple */
4934 tgl 14791 CBC 138 : if (!buildDefaultACLCommands(type,
4934 tgl 14792 GIC 138 : daclinfo->dobj.namespace != NULL ?
14793 70 : daclinfo->dobj.namespace->dobj.name : NULL,
489 14794 138 : daclinfo->dacl.acl,
14795 138 : daclinfo->dacl.acldefault,
4934 14796 138 : daclinfo->defaclrole,
14797 : fout->remoteVersion,
14798 : q))
366 tgl 14799 LBC 0 : pg_fatal("could not parse default ACL list (%s)",
14800 : daclinfo->dacl.acl);
4934 tgl 14801 ECB :
2559 sfrost 14802 GIC 138 : if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14803 138 : ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
1528 alvherre 14804 138 : ARCHIVE_OPTS(.tag = tag->data,
14805 : .namespace = daclinfo->dobj.namespace ?
14806 : daclinfo->dobj.namespace->dobj.name : NULL,
1528 alvherre 14807 ECB : .owner = daclinfo->defaclrole,
14808 : .description = "DEFAULT ACL",
14809 : .section = SECTION_POST_DATA,
1444 14810 : .createStmt = q->data));
4934 tgl 14811 :
4934 tgl 14812 GIC 138 : destroyPQExpBuffer(tag);
4934 tgl 14813 CBC 138 : destroyPQExpBuffer(q);
14814 : }
4934 tgl 14815 ECB :
14816 : /*----------
14817 : * Write out grant/revoke information
7630 peter_e 14818 : *
7064 tgl 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,
1002 tgl 14821 ECB : * or InvalidDumpId if there is no need for a second dependency.
4798 tgl 14822 EUB : * 'type' must be one of
14823 : * TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
4798 tgl 14824 ECB : * FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
3260 bruce 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.
1868 tgl 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).
7381 peter_e 14829 : * 'owner' is the owner, NULL if there is no owner (for languages).
14830 : * 'dacl' is the DumpableAcl struct fpr the object.
14831 : *
1002 tgl 14832 : * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
14833 : * no ACL entry was created.
14834 : *----------
14835 : */
14836 : static DumpId
1002 tgl 14837 CBC 18280 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
5190 tgl 14838 ECB : const char *type, const char *name, const char *subname,
1868 14839 : const char *nspname, const char *owner,
14840 : const DumpableAcl *dacl)
14841 : {
1002 tgl 14842 GIC 18280 : DumpId aclDumpId = InvalidDumpId;
2643 14843 18280 : DumpOptions *dopt = fout->dopt;
489 14844 18280 : const char *acls = dacl->acl;
14845 18280 : const char *acldefault = dacl->acldefault;
14846 18280 : char privtype = dacl->privtype;
489 tgl 14847 CBC 18280 : const char *initprivs = dacl->initprivs;
489 tgl 14848 EUB : const char *baseacls;
7254 14849 : PQExpBuffer sql;
8891 14850 :
14851 : /* Do nothing if ACL dump is not enabled */
3099 alvherre 14852 GIC 18280 : if (dopt->aclsSkip)
1002 tgl 14853 CBC 312 : return InvalidDumpId;
4798 tgl 14854 ECB :
14855 : /* --data-only skips ACLs *except* large object ACLs */
3099 alvherre 14856 CBC 17968 : if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
1002 tgl 14857 UIC 0 : return InvalidDumpId;
7318 bruce 14858 ECB :
7643 tgl 14859 GIC 17968 : sql = createPQExpBuffer();
8891 tgl 14860 ECB :
2559 sfrost 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 : *
489 tgl 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 : */
489 tgl 14874 GIC 17968 : if (dopt->binary_upgrade && privtype == 'e' &&
14875 11 : initprivs && *initprivs != '\0')
14876 : {
1375 drowley 14877 11 : appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
1868 tgl 14878 11 : if (!buildACLCommands(name, subname, nspname, type,
14879 : initprivs, acldefault, owner,
2559 sfrost 14880 ECB : "", fout->remoteVersion, sql))
366 tgl 14881 LBC 0 : pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
14882 : initprivs, acldefault, name, type);
1375 drowley 14883 CBC 11 : appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
2559 sfrost 14884 ECB : }
14885 :
14886 : /*
489 tgl 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 : */
489 tgl 14894 CBC 17968 : if (initprivs && *initprivs != '\0')
489 tgl 14895 ECB : {
489 tgl 14896 GIC 16166 : baseacls = initprivs;
489 tgl 14897 CBC 16166 : if (acls == NULL || *acls == '\0')
14898 16 : acls = acldefault;
14899 : }
489 tgl 14900 EUB : else
489 tgl 14901 GBC 1802 : baseacls = acldefault;
14902 :
1868 tgl 14903 CBC 17968 : if (!buildACLCommands(name, subname, nspname, type,
14904 : acls, baseacls, owner,
4934 tgl 14905 EUB : "", fout->remoteVersion, sql))
366 tgl 14906 UBC 0 : pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
14907 : acls, baseacls, name, type);
14908 :
7254 tgl 14909 CBC 17968 : if (sql->len > 0)
1868 tgl 14910 ECB : {
1868 tgl 14911 GIC 1886 : PQExpBuffer tag = createPQExpBuffer();
1002 tgl 14912 ECB : DumpId aclDeps[2];
1002 tgl 14913 GBC 1886 : int nDeps = 0;
14914 :
1868 tgl 14915 CBC 1886 : if (subname)
1868 tgl 14916 GIC 1102 : appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
1868 tgl 14917 ECB : else
1868 tgl 14918 GIC 784 : appendPQExpBuffer(tag, "%s %s", type, name);
14919 :
1002 tgl 14920 CBC 1886 : aclDeps[nDeps++] = objDumpId;
14921 1886 : if (altDumpId != InvalidDumpId)
1002 tgl 14922 GIC 1022 : aclDeps[nDeps++] = altDumpId;
14923 :
1002 tgl 14924 CBC 1886 : aclDumpId = createDumpId();
1002 tgl 14925 ECB :
1002 tgl 14926 CBC 1886 : ArchiveEntry(fout, nilCatalogId, aclDumpId,
1528 alvherre 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,
1002 tgl 14934 ECB : .nDeps = nDeps));
1002 tgl 14935 EUB :
1868 tgl 14936 GBC 1886 : destroyPQExpBuffer(tag);
1868 tgl 14937 EUB : }
14938 :
7643 tgl 14939 GIC 17968 : destroyPQExpBuffer(sql);
1002 tgl 14940 ECB :
1002 tgl 14941 CBC 17968 : return aclDumpId;
14942 : }
9133 bruce 14943 ECB :
14944 : /*
14945 : * dumpSecLabel
4577 rhaas 14946 : *
14947 : * This routine is used to dump any security labels associated with the
1868 tgl 14948 : * object handed to this routine. The routine takes the object type
14949 : * and object name (ready to print, except for schema decoration), plus
4577 rhaas 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
1868 tgl 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 : {
2643 14967 0 : DumpOptions *dopt = fout->dopt;
14968 : SecLabelItem *labels;
4382 bruce 14969 ECB : int nlabels;
14970 : int i;
14971 : PQExpBuffer query;
14972 :
14973 : /* do nothing, if --no-security-labels is supplied */
3099 alvherre 14974 UIC 0 : if (dopt->no_security_labels)
4577 rhaas 14975 0 : return;
14976 :
14977 : /* Security labels are schema not data ... except large object labels are data */
1868 tgl 14978 0 : if (strcmp(type, "LARGE OBJECT") != 0)
14979 : {
3099 alvherre 14980 0 : if (dopt->dataOnly)
4577 rhaas 14981 0 : return;
14982 : }
14983 : else
4577 rhaas 14984 ECB : {
14985 : /* We do dump large object security labels in binary-upgrade mode */
2225 sfrost 14986 LBC 0 : if (dopt->schemaOnly && !dopt->binary_upgrade)
4577 rhaas 14987 0 : return;
14988 : }
14989 :
14990 : /* Search for security labels associated with catalogId, using table */
465 tgl 14991 UIC 0 : nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
14992 :
4577 rhaas 14993 0 : query = createPQExpBuffer();
14994 :
14995 0 : for (i = 0; i < nlabels; i++)
14996 : {
4577 rhaas 14997 ECB : /*
14998 : * Ignore label entries for which the subid doesn't match.
14999 : */
4577 rhaas 15000 UIC 0 : if (labels[i].objsubid != subid)
15001 0 : continue;
15002 :
15003 0 : appendPQExpBuffer(query,
15004 : "SECURITY LABEL FOR %s ON %s ",
1868 tgl 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);
4577 rhaas 15009 0 : appendStringLiteralAH(query, labels[i].label, fout);
3429 heikki.linnakangas 15010 LBC 0 : appendPQExpBufferStr(query, ";\n");
15011 : }
4577 rhaas 15012 ECB :
4577 rhaas 15013 LBC 0 : if (query->len > 0)
4577 rhaas 15014 ECB : {
1868 tgl 15015 UIC 0 : PQExpBuffer tag = createPQExpBuffer();
1868 tgl 15016 ECB :
1868 tgl 15017 UIC 0 : appendPQExpBuffer(tag, "%s %s", type, name);
4577 rhaas 15018 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 15019 0 : ARCHIVE_OPTS(.tag = tag->data,
15020 : .namespace = namespace,
1528 alvherre 15021 ECB : .owner = owner,
15022 : .description = "SECURITY LABEL",
15023 : .section = SECTION_NONE,
15024 : .createStmt = query->data,
15025 : .deps = &dumpId,
15026 : .nDeps = 1));
1868 tgl 15027 UIC 0 : destroyPQExpBuffer(tag);
4577 rhaas 15028 ECB : }
1868 tgl 15029 EUB :
4577 rhaas 15030 UIC 0 : destroyPQExpBuffer(query);
4577 rhaas 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
788 peter 15040 UIC 0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
4577 rhaas 15041 ECB : {
2643 tgl 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 */
3099 alvherre 15050 UIC 0 : if (dopt->no_security_labels)
4577 rhaas 15051 LBC 0 : return;
15052 :
4577 rhaas 15053 ECB : /* SecLabel are SCHEMA not data */
3099 alvherre 15054 LBC 0 : if (dopt->dataOnly)
4577 rhaas 15055 0 : return;
4577 rhaas 15056 ECB :
15057 : /* Search for comments associated with relation, using table */
465 tgl 15058 UIC 0 : nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
4577 rhaas 15059 0 : tbinfo->dobj.catId.oid,
15060 : &labels);
15061 :
15062 : /* If security labels exist, build SECURITY LABEL statements */
4577 rhaas 15063 LBC 0 : if (nlabels <= 0)
4577 rhaas 15064 UIC 0 : return;
4577 rhaas 15065 ECB :
4577 rhaas 15066 UIC 0 : query = createPQExpBuffer();
15067 0 : target = createPQExpBuffer();
15068 :
15069 0 : for (i = 0; i < nlabels; i++)
15070 : {
4577 rhaas 15071 ECB : const char *colname;
4382 bruce 15072 LBC 0 : const char *provider = labels[i].provider;
4382 bruce 15073 UIC 0 : const char *label = labels[i].label;
4382 bruce 15074 LBC 0 : int objsubid = labels[i].objsubid;
4577 rhaas 15075 ECB :
4577 rhaas 15076 UIC 0 : resetPQExpBuffer(target);
4577 rhaas 15077 LBC 0 : if (objsubid == 0)
15078 : {
15079 0 : appendPQExpBuffer(target, "%s %s", reltypename,
1868 tgl 15080 0 : fmtQualifiedDumpable(tbinfo));
4577 rhaas 15081 ECB : }
4577 rhaas 15082 EUB : else
15083 : {
4577 rhaas 15084 UBC 0 : colname = getAttrName(objsubid, tbinfo);
1868 tgl 15085 ECB : /* first fmtXXX result must be consumed before calling again */
1868 tgl 15086 LBC 0 : appendPQExpBuffer(target, "COLUMN %s",
15087 0 : fmtQualifiedDumpable(tbinfo));
4481 rhaas 15088 UBC 0 : appendPQExpBuffer(target, ".%s", fmtId(colname));
4577 rhaas 15089 EUB : }
4577 rhaas 15090 UBC 0 : appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
4577 rhaas 15091 EUB : fmtId(provider), target->data);
4577 rhaas 15092 UBC 0 : appendStringLiteralAH(query, label, fout);
3429 heikki.linnakangas 15093 0 : appendPQExpBufferStr(query, ";\n");
4577 rhaas 15094 EUB : }
4577 rhaas 15095 UIC 0 : if (query->len > 0)
4577 rhaas 15096 EUB : {
4577 rhaas 15097 UIC 0 : resetPQExpBuffer(target);
15098 0 : appendPQExpBuffer(target, "%s %s", reltypename,
15099 0 : fmtId(tbinfo->dobj.name));
15100 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 15101 LBC 0 : ARCHIVE_OPTS(.tag = target->data,
15102 : .namespace = tbinfo->dobj.namespace->dobj.name,
15103 : .owner = tbinfo->rolname,
1528 alvherre 15104 ECB : .description = "SECURITY LABEL",
15105 : .section = SECTION_NONE,
15106 : .createStmt = query->data,
15107 : .deps = &(tbinfo->dobj.dumpId),
15108 : .nDeps = 1));
4577 rhaas 15109 : }
4577 rhaas 15110 UIC 0 : destroyPQExpBuffer(query);
15111 0 : destroyPQExpBuffer(target);
4577 rhaas 15112 EUB : }
15113 :
15114 : /*
4577 rhaas 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
465 tgl 15122 UIC 0 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
15123 : {
4382 bruce 15124 0 : SecLabelItem *middle = NULL;
4382 bruce 15125 ECB : SecLabelItem *low;
15126 : SecLabelItem *high;
15127 : int nmatch;
15128 :
489 tgl 15129 UIC 0 : if (nseclabels <= 0) /* no labels, so no match is possible */
15130 : {
4168 15131 0 : *items = NULL;
15132 0 : return 0;
15133 : }
15134 :
15135 : /*
15136 : * Do binary search to find some item matching the object.
15137 : */
489 15138 0 : low = &seclabels[0];
15139 0 : high = &seclabels[nseclabels - 1];
4577 rhaas 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;
4577 rhaas 15150 LBC 0 : else if (objoid > middle->objoid)
4577 rhaas 15151 UIC 0 : low = middle + 1;
15152 : else
4382 bruce 15153 0 : break; /* found a match */
15154 : }
4577 rhaas 15155 ECB :
4382 bruce 15156 LBC 0 : if (low > high) /* no matches */
4577 rhaas 15157 ECB : {
4577 rhaas 15158 LBC 0 : *items = NULL;
15159 0 : return 0;
4577 rhaas 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 : */
4577 rhaas 15167 UIC 0 : nmatch = 1;
15168 0 : while (middle > low)
4577 rhaas 15169 ECB : {
4577 rhaas 15170 UBC 0 : if (classoid != middle[-1].classoid ||
4577 rhaas 15171 UIC 0 : objoid != middle[-1].objoid)
4577 rhaas 15172 ECB : break;
4577 rhaas 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++;
4577 rhaas 15187 ECB : }
15188 :
4577 rhaas 15189 UIC 0 : return nmatch;
4577 rhaas 15190 ECB : }
15191 :
15192 : /*
15193 : * collectSecLabels
4577 rhaas 15194 EUB : *
15195 : * Construct a table of all security labels available for database objects;
489 tgl 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
489 tgl 15201 GIC 118 : collectSecLabels(Archive *fout)
15202 : {
15203 : PGresult *res;
15204 : PQExpBuffer query;
15205 : int i_label;
15206 : int i_provider;
4382 bruce 15207 ECB : int i_classoid;
15208 : int i_objoid;
15209 : int i_objsubid;
15210 : int ntups;
15211 : int i;
15212 : DumpableObject *dobj;
15213 :
4577 rhaas 15214 CBC 118 : query = createPQExpBuffer();
15215 :
3429 heikki.linnakangas 15216 118 : appendPQExpBufferStr(query,
15217 : "SELECT label, provider, classoid, objoid, objsubid "
15218 : "FROM pg_catalog.pg_seclabel "
3429 heikki.linnakangas 15219 EUB : "ORDER BY classoid, objoid, objsubid");
15220 :
4079 rhaas 15221 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4577 rhaas 15222 ECB :
15223 : /* Construct lookup table containing OIDs in numeric form */
4382 bruce 15224 CBC 118 : i_label = PQfnumber(res, "label");
4382 bruce 15225 GIC 118 : i_provider = PQfnumber(res, "provider");
4382 bruce 15226 CBC 118 : i_classoid = PQfnumber(res, "classoid");
4382 bruce 15227 GIC 118 : i_objoid = PQfnumber(res, "objoid");
4382 bruce 15228 CBC 118 : i_objsubid = PQfnumber(res, "objsubid");
4577 rhaas 15229 ECB :
4577 rhaas 15230 GIC 118 : ntups = PQntuples(res);
4577 rhaas 15231 ECB :
489 tgl 15232 GIC 118 : seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
489 tgl 15233 CBC 118 : nseclabels = 0;
15234 118 : dobj = NULL;
4577 rhaas 15235 ECB :
4577 rhaas 15236 GIC 118 : for (i = 0; i < ntups; i++)
4577 rhaas 15237 ECB : {
15238 : CatalogId objId;
489 tgl 15239 : int subid;
15240 :
489 tgl 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)
489 tgl 15249 LBC 0 : dobj = findObjectByCatalogId(objId);
489 tgl 15250 UIC 0 : if (dobj == NULL)
15251 0 : continue;
489 tgl 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 : */
489 tgl 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++;
4577 rhaas 15276 EUB : }
15277 :
489 tgl 15278 GIC 118 : PQclear(res);
4382 bruce 15279 118 : destroyPQExpBuffer(query);
4577 rhaas 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
788 peter 15287 20378 : dumpTable(Archive *fout, const TableInfo *tbinfo)
8019 pjw 15288 EUB : {
2559 sfrost 15289 GIC 20378 : DumpOptions *dopt = fout->dopt;
1002 tgl 15290 20378 : DumpId tableAclDumpId = InvalidDumpId;
2559 sfrost 15291 EUB : char *namecopy;
15292 :
489 tgl 15293 : /* Do nothing in data-only dump */
489 tgl 15294 GBC 20378 : if (dopt->dataOnly)
2557 sfrost 15295 GIC 831 : return;
15296 :
489 tgl 15297 19547 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15298 : {
489 tgl 15299 GBC 5015 : if (tbinfo->relkind == RELKIND_SEQUENCE)
15300 315 : dumpSequence(fout, tbinfo);
15301 : else
489 tgl 15302 GIC 4700 : dumpTableSchema(fout, tbinfo);
15303 : }
7064 tgl 15304 EUB :
15305 : /* Handle the ACL here */
2559 sfrost 15306 GBC 19547 : namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
2559 sfrost 15307 GIC 19547 : if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
1903 tgl 15308 EUB : {
1903 tgl 15309 GIC 14841 : const char *objtype =
15310 14841 : (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15311 :
15312 : tableAclDumpId =
1002 tgl 15313 GBC 14841 : dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
1002 tgl 15314 EUB : objtype, namecopy, NULL,
1002 tgl 15315 GIC 14841 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
489 tgl 15316 EUB : &tbinfo->dacl);
15317 : }
5190 15318 :
2559 sfrost 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
489 tgl 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 : */
489 tgl 15325 GIC 19547 : if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
2559 sfrost 15326 EUB : {
2559 sfrost 15327 GIC 196 : PQExpBuffer query = createPQExpBuffer();
2559 sfrost 15328 EUB : PGresult *res;
15329 : int i;
5190 tgl 15330 :
489 tgl 15331 GBC 196 : if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
2559 sfrost 15332 EUB : {
15333 : /* Set up query for column ACLs */
489 tgl 15334 GIC 103 : appendPQExpBufferStr(query,
15335 : "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
15336 :
15337 103 : if (fout->remoteVersion >= 90600)
15338 : {
15339 : /*
489 tgl 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 : */
489 tgl 15349 GIC 103 : appendPQExpBufferStr(query,
15350 : "SELECT at.attname, "
15351 : "at.attacl, "
15352 : "'{}' AS acldefault, "
489 tgl 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 : {
489 tgl 15366 UIC 0 : appendPQExpBufferStr(query,
489 tgl 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 :
489 tgl 15375 GIC 103 : ExecuteSqlStatement(fout, query->data);
489 tgl 15376 EUB :
489 tgl 15377 GBC 103 : fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
15378 : }
2559 sfrost 15379 EUB :
489 tgl 15380 GBC 196 : printfPQExpBuffer(query,
15381 : "EXECUTE getColumnACLs('%u')",
15382 196 : tbinfo->dobj.catId.oid);
15383 :
2559 sfrost 15384 GIC 196 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5190 tgl 15385 EUB :
2559 sfrost 15386 GBC 2914 : for (i = 0; i < PQntuples(res); i++)
2559 sfrost 15387 EUB : {
2559 sfrost 15388 GIC 2718 : char *attname = PQgetvalue(res, i, 0);
2559 sfrost 15389 GBC 2718 : char *attacl = PQgetvalue(res, i, 1);
489 tgl 15390 2718 : char *acldefault = PQgetvalue(res, i, 2);
489 tgl 15391 GIC 2718 : char privtype = *(PQgetvalue(res, i, 3));
489 tgl 15392 GBC 2718 : char *initprivs = PQgetvalue(res, i, 4);
489 tgl 15393 EUB : DumpableAcl coldacl;
15394 : char *attnamecopy;
15395 :
489 tgl 15396 GIC 2718 : coldacl.acl = attacl;
489 tgl 15397 GBC 2718 : coldacl.acldefault = acldefault;
489 tgl 15398 GIC 2718 : coldacl.privtype = privtype;
489 tgl 15399 GBC 2718 : coldacl.initprivs = initprivs;
2559 sfrost 15400 2718 : attnamecopy = pg_strdup(fmtId(attname));
1002 tgl 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 : */
1002 tgl 15407 GIC 2718 : dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
1868 tgl 15408 EUB : "TABLE", namecopy, attnamecopy,
2559 sfrost 15409 GIC 2718 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
489 tgl 15410 EUB : &coldacl);
2559 sfrost 15411 GBC 2718 : free(attnamecopy);
5190 tgl 15412 EUB : }
2559 sfrost 15413 GBC 196 : PQclear(res);
15414 196 : destroyPQExpBuffer(query);
15415 : }
15416 :
2559 sfrost 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.
3689 kgrittn 15423 EUB : *
15424 : * This returns a new buffer which must be freed by the caller.
15425 : */
15426 : static PQExpBuffer
788 peter 15427 GIC 599 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
15428 : {
3689 kgrittn 15429 599 : PQExpBuffer query = createPQExpBuffer();
15430 599 : PQExpBuffer result = createPQExpBuffer();
15431 : PGresult *res;
15432 : int len;
15433 :
15434 : /* Fetch the view definition */
2370 tgl 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 :
3689 kgrittn 15439 GIC 599 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15440 :
15441 599 : if (PQntuples(res) != 1)
3689 kgrittn 15442 EUB : {
3689 kgrittn 15443 UIC 0 : if (PQntuples(res) < 1)
366 tgl 15444 UBC 0 : pg_fatal("query to obtain definition of view \"%s\" returned no data",
366 tgl 15445 EUB : tbinfo->dobj.name);
15446 : else
366 tgl 15447 UIC 0 : pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
15448 : tbinfo->dobj.name);
15449 : }
15450 :
3689 kgrittn 15451 GBC 599 : len = PQgetlength(res, 0, 0);
3689 kgrittn 15452 EUB :
3689 kgrittn 15453 GBC 599 : if (len == 0)
366 tgl 15454 UIC 0 : pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
366 tgl 15455 EUB : tbinfo->dobj.name);
15456 :
3689 kgrittn 15457 : /* Strip off the trailing semicolon so that other things may follow. */
3668 andrew 15458 GBC 599 : Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
3689 kgrittn 15459 599 : appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
3689 kgrittn 15460 EUB :
3689 kgrittn 15461 GBC 599 : PQclear(res);
15462 599 : destroyPQExpBuffer(query);
3689 kgrittn 15463 EUB :
3689 kgrittn 15464 GBC 599 : return result;
15465 : }
3689 kgrittn 15466 EUB :
15467 : /*
15468 : * Create a dummy AS clause for a view. This is used when the real view
2334 tgl 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
788 peter 15476 GIC 20 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
15477 : {
2334 tgl 15478 20 : PQExpBuffer result = createPQExpBuffer();
15479 : int j;
2334 tgl 15480 EUB :
2334 tgl 15481 GBC 20 : appendPQExpBufferStr(result, "SELECT");
15482 :
15483 40 : for (j = 0; j < tbinfo->numatts; j++)
2334 tgl 15484 EUB : {
2334 tgl 15485 GIC 20 : if (j > 0)
2334 tgl 15486 GBC 10 : appendPQExpBufferChar(result, ',');
15487 20 : appendPQExpBufferStr(result, "\n ");
15488 :
2334 tgl 15489 GIC 20 : appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
2334 tgl 15490 EUB :
15491 : /*
15492 : * Must add collation if not default for the type, because CREATE OR
15493 : * REPLACE VIEW won't change it
15494 : */
2334 tgl 15495 GBC 20 : if (OidIsValid(tbinfo->attcollation[j]))
2334 tgl 15496 EUB : {
15497 : CollInfo *coll;
15498 :
2334 tgl 15499 UBC 0 : coll = findCollationByOid(tbinfo->attcollation[j]);
2334 tgl 15500 UIC 0 : if (coll)
1868 15501 0 : appendPQExpBuffer(result, " COLLATE %s",
1868 tgl 15502 UBC 0 : fmtQualifiedDumpable(coll));
15503 : }
15504 :
2334 tgl 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
9770 scrappy 15514 ECB : */
15515 : static void
788 peter 15516 GIC 4700 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
15517 : {
2643 tgl 15518 4700 : DumpOptions *dopt = fout->dopt;
8397 bruce 15519 4700 : PQExpBuffer q = createPQExpBuffer();
8314 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;
7325 bruce 15527 ECB : char *storage;
15528 : int j,
7639 tgl 15529 : k;
15530 :
15531 : /* We had better have loaded per-column details about this table */
914 tgl 15532 GIC 4700 : Assert(tbinfo->interesting);
15533 :
1868 tgl 15534 CBC 4700 : qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
1868 tgl 15535 GIC 4700 : qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15536 :
1601 andres 15537 CBC 4700 : if (tbinfo->hasoids)
1469 peter 15538 LBC 0 : pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
1418 tgl 15539 ECB : qrelname);
1601 andres 15540 :
3099 alvherre 15541 CBC 4700 : if (dopt->binary_upgrade)
489 tgl 15542 GIC 709 : binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
4854 bruce 15543 ECB :
15544 : /* Is it a table or a view? */
7639 tgl 15545 CBC 4700 : if (tbinfo->relkind == RELKIND_VIEW)
9345 bruce 15546 ECB : {
3689 kgrittn 15547 : PQExpBuffer result;
15548 :
2334 tgl 15549 : /*
15550 : * Note: keep this code in sync with the is_view case in dumpRule()
15551 : */
15552 :
7639 tgl 15553 GIC 271 : reltypename = "VIEW";
9345 bruce 15554 EUB :
1868 tgl 15555 GBC 271 : appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
7621 tgl 15556 EUB :
3099 alvherre 15557 GIC 271 : if (dopt->binary_upgrade)
4079 rhaas 15558 48 : binary_upgrade_set_pg_class_oids(fout, q,
4079 rhaas 15559 GBC 48 : tbinfo->dobj.catId.oid, false);
4841 bruce 15560 EUB :
1868 tgl 15561 GBC 271 : appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
1868 tgl 15562 EUB :
2334 tgl 15563 GBC 271 : if (tbinfo->dummy_view)
15564 10 : result = createDummyViewAsClause(fout, tbinfo);
15565 : else
15566 : {
2334 tgl 15567 GIC 261 : if (nonemptyReloptions(tbinfo->reloptions))
15568 : {
15569 56 : appendPQExpBufferStr(q, " WITH (");
15570 56 : appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
2334 tgl 15571 GBC 56 : appendPQExpBufferChar(q, ')');
2334 tgl 15572 EUB : }
2334 tgl 15573 GBC 261 : result = createViewAsClause(fout, tbinfo);
15574 : }
3552 sfrost 15575 GIC 271 : appendPQExpBuffer(q, " AS\n%s", result->data);
3689 kgrittn 15576 GBC 271 : destroyPQExpBuffer(result);
8241 pjw 15577 EUB :
2334 tgl 15578 GBC 271 : if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
3552 sfrost 15579 GIC 36 : appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
3429 heikki.linnakangas 15580 271 : appendPQExpBufferStr(q, ";\n");
7639 tgl 15581 EUB : }
15582 : else
15583 : {
489 tgl 15584 GBC 4429 : char *partkeydef = NULL;
1585 sfrost 15585 4429 : char *ftoptions = NULL;
15586 4429 : char *srvname = NULL;
1115 alvherre 15587 4429 : char *foreign = "";
1585 sfrost 15588 EUB :
15589 : /*
15590 : * Set reltypename, and collect any relkind-specific data that we
489 tgl 15591 ECB : * didn't fetch during getTables().
15592 : */
3689 kgrittn 15593 CBC 4429 : switch (tbinfo->relkind)
15594 : {
489 tgl 15595 GIC 466 : case RELKIND_PARTITIONED_TABLE:
15596 : {
15597 466 : PQExpBuffer query = createPQExpBuffer();
15598 : PGresult *res;
15599 :
489 tgl 15600 CBC 466 : reltypename = "TABLE";
15601 :
489 tgl 15602 ECB : /* retrieve partition key definition */
489 tgl 15603 CBC 466 : appendPQExpBuffer(query,
15604 : "SELECT pg_get_partkeydef('%u')",
489 tgl 15605 GIC 466 : tbinfo->dobj.catId.oid);
15606 466 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
489 tgl 15607 CBC 466 : partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
15608 466 : PQclear(res);
489 tgl 15609 GIC 466 : destroyPQExpBuffer(query);
489 tgl 15610 CBC 466 : break;
15611 : }
2222 15612 38 : case RELKIND_FOREIGN_TABLE:
3668 andrew 15613 ECB : {
3668 andrew 15614 GIC 38 : PQExpBuffer query = createPQExpBuffer();
3668 andrew 15615 ECB : PGresult *res;
15616 : int i_srvname;
15617 : int i_ftoptions;
15618 :
3668 andrew 15619 CBC 38 : reltypename = "FOREIGN TABLE";
3668 andrew 15620 ECB :
15621 : /* retrieve name of foreign server and generic options */
3668 andrew 15622 CBC 38 : appendPQExpBuffer(query,
3668 andrew 15623 ECB : "SELECT fs.srvname, "
15624 : "pg_catalog.array_to_string(ARRAY("
15625 : "SELECT pg_catalog.quote_ident(option_name) || "
2118 tgl 15626 : "' ' || pg_catalog.quote_literal(option_value) "
15627 : "FROM pg_catalog.pg_options_to_table(ftoptions) "
3668 andrew 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'",
3668 andrew 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");
3668 andrew 15638 CBC 38 : srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
3668 andrew 15639 GIC 38 : ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
3668 andrew 15640 CBC 38 : PQclear(res);
3668 andrew 15641 GIC 38 : destroyPQExpBuffer(query);
15642 :
1115 alvherre 15643 38 : foreign = "FOREIGN ";
3668 andrew 15644 CBC 38 : break;
15645 : }
2222 tgl 15646 GIC 328 : case RELKIND_MATVIEW:
3689 kgrittn 15647 CBC 328 : reltypename = "MATERIALIZED VIEW";
3689 kgrittn 15648 GIC 328 : break;
15649 3597 : default:
3689 kgrittn 15650 CBC 3597 : reltypename = "TABLE";
489 tgl 15651 GIC 3597 : break;
15652 : }
15653 :
7639 15654 4429 : numParents = tbinfo->numParents;
7064 15655 4429 : parents = tbinfo->parents;
15656 :
1868 15657 4429 : appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15658 :
3099 alvherre 15659 4429 : if (dopt->binary_upgrade)
4079 rhaas 15660 661 : binary_upgrade_set_pg_class_oids(fout, q,
15661 661 : tbinfo->dobj.catId.oid, false);
4841 bruce 15662 ECB :
4481 rhaas 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 : */
489 tgl 15673 4429 : if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
15674 24 : appendPQExpBuffer(q, " OF %s",
15675 24 : getFormattedTypeName(fout, tbinfo->reloftype,
15676 : zeroIsError));
15677 :
3689 kgrittn 15678 4429 : if (tbinfo->relkind != RELKIND_MATVIEW)
3689 kgrittn 15679 EUB : {
15680 : /* Dump the attributes */
3668 andrew 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
3668 andrew 15688 ECB : * below.
15689 : */
3099 alvherre 15690 CBC 16157 : if (shouldPrintColumn(dopt, tbinfo, j))
15691 : {
15692 : bool print_default;
1399 alvherre 15693 ECB : bool print_notnull;
15694 :
5029 tgl 15695 : /*
15696 : * Default value --- suppress if to be printed separately
15697 : * or not at all.
15698 : */
1399 alvherre 15699 GIC 31614 : print_default = (tbinfo->attrdefs[j] != NULL &&
40 tgl 15700 GNC 16162 : tbinfo->attrdefs[j]->dobj.dump &&
1399 alvherre 15701 CBC 753 : !tbinfo->attrdefs[j]->separate);
15702 :
3668 andrew 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 : */
1399 alvherre 15708 GIC 16327 : print_notnull = (tbinfo->notnull[j] &&
2 alvherre 15709 GNC 918 : (tbinfo->localNotNull[j] ||
1399 alvherre 15710 GIC 425 : tbinfo->ispartition || dopt->binary_upgrade));
3668 andrew 15711 ECB :
1434 alvherre 15712 : /*
1399 15713 : * Skip column if fully defined by reloftype, except in
15714 : * binary upgrade
1434 15715 : */
489 tgl 15716 GIC 15409 : if (OidIsValid(tbinfo->reloftype) &&
15717 50 : !print_default && !print_notnull &&
1399 alvherre 15718 40 : !dopt->binary_upgrade)
3668 andrew 15719 32 : continue;
15720 :
15721 : /* Format properly if not first attr */
3668 andrew 15722 CBC 15377 : if (actual_atts == 0)
3429 heikki.linnakangas 15723 GIC 3877 : appendPQExpBufferStr(q, " (");
3668 andrew 15724 ECB : else
2838 heikki.linnakangas 15725 GIC 11500 : appendPQExpBufferChar(q, ',');
3429 heikki.linnakangas 15726 CBC 15377 : appendPQExpBufferStr(q, "\n ");
3668 andrew 15727 GIC 15377 : actual_atts++;
8951 bruce 15728 ECB :
3668 andrew 15729 : /* Attribute name */
3429 heikki.linnakangas 15730 GIC 15377 : appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15731 :
3668 andrew 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 : */
3429 heikki.linnakangas 15740 GIC 79 : appendPQExpBufferStr(q, " INTEGER /* dummy */");
15741 : /* and skip to the next column */
3668 andrew 15742 CBC 79 : continue;
15743 : }
3668 andrew 15744 ECB :
2173 sfrost 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 : */
489 tgl 15750 CBC 15298 : if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
15751 : {
3668 andrew 15752 15290 : appendPQExpBuffer(q, " %s",
2370 tgl 15753 GIC 15290 : tbinfo->atttypnames[j]);
3668 andrew 15754 ECB : }
15755 :
1399 alvherre 15756 CBC 15298 : if (print_default)
15757 : {
1471 peter 15758 GBC 640 : if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
15759 274 : appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
1471 peter 15760 GIC 274 : tbinfo->attrdefs[j]->adef_expr);
15761 : else
1471 peter 15762 GBC 366 : appendPQExpBuffer(q, " DEFAULT %s",
1471 peter 15763 GIC 366 : tbinfo->attrdefs[j]->adef_expr);
15764 : }
15765 :
1471 peter 15766 ECB :
1399 alvherre 15767 GIC 15298 : if (print_notnull)
1471 peter 15768 CBC 883 : appendPQExpBufferStr(q, " NOT NULL");
1471 peter 15769 EUB :
15770 : /* Add collation if not default for the type */
3668 andrew 15771 GIC 15298 : if (OidIsValid(tbinfo->attcollation[j]))
15772 : {
3668 andrew 15773 ECB : CollInfo *coll;
15774 :
3668 andrew 15775 GIC 5 : coll = findCollationByOid(tbinfo->attcollation[j]);
3668 andrew 15776 CBC 5 : if (coll)
1868 tgl 15777 5 : appendPQExpBuffer(q, " COLLATE %s",
1868 tgl 15778 GIC 5 : fmtQualifiedDumpable(coll));
4413 tgl 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 : */
3668 andrew 15791 CBC 4659 : for (j = 0; j < tbinfo->ncheck; j++)
15792 : {
15793 558 : ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15794 :
1399 alvherre 15795 GIC 558 : if (constr->separate ||
1399 alvherre 15796 CBC 518 : (!constr->conislocal && !tbinfo->ispartition))
3668 andrew 15797 GIC 81 : continue;
8397 bruce 15798 ECB :
3668 andrew 15799 GIC 477 : if (actual_atts == 0)
3429 heikki.linnakangas 15800 CBC 16 : appendPQExpBufferStr(q, " (\n ");
3668 andrew 15801 ECB : else
3429 heikki.linnakangas 15802 CBC 461 : appendPQExpBufferStr(q, ",\n ");
15803 :
3668 andrew 15804 477 : appendPQExpBuffer(q, "CONSTRAINT %s ",
3668 andrew 15805 GIC 477 : fmtId(constr->dobj.name));
3429 heikki.linnakangas 15806 477 : appendPQExpBufferStr(q, constr->condef);
15807 :
3668 andrew 15808 477 : actual_atts++;
15809 : }
7919 tgl 15810 ECB :
3668 andrew 15811 GIC 4101 : if (actual_atts)
3429 heikki.linnakangas 15812 3893 : appendPQExpBufferStr(q, "\n)");
489 tgl 15813 208 : else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
3668 andrew 15814 EUB : {
15815 : /*
1399 alvherre 15816 : * No attributes? we must have a parenthesized attribute list,
15817 : * even though empty, when not using the OF TYPE syntax.
15818 : */
3429 heikki.linnakangas 15819 GIC 192 : appendPQExpBufferStr(q, " (\n)");
3668 andrew 15820 ECB : }
15821 :
15822 : /*
1399 alvherre 15823 : * Emit the INHERITS clause (not for partitions), except in
15824 : * binary-upgrade mode.
15825 : */
1399 alvherre 15826 GIC 4101 : if (numParents > 0 && !tbinfo->ispartition &&
2166 sfrost 15827 303 : !dopt->binary_upgrade)
15828 : {
3429 heikki.linnakangas 15829 261 : appendPQExpBufferStr(q, "\nINHERITS (");
3668 andrew 15830 542 : for (k = 0; k < numParents; k++)
3668 andrew 15831 ECB : {
3668 andrew 15832 GIC 281 : TableInfo *parentRel = parents[k];
8122 pjw 15833 ECB :
3668 andrew 15834 CBC 281 : if (k > 0)
3429 heikki.linnakangas 15835 20 : appendPQExpBufferStr(q, ", ");
1868 tgl 15836 GIC 281 : appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15837 : }
3429 heikki.linnakangas 15838 261 : appendPQExpBufferChar(q, ')');
15839 : }
15840 :
2314 rhaas 15841 4101 : if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
489 tgl 15842 466 : appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
15843 :
3668 andrew 15844 4101 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15845 38 : appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15846 : }
4481 rhaas 15847 ECB :
2654 tgl 15848 GIC 8712 : if (nonemptyReloptions(tbinfo->reloptions) ||
2654 tgl 15849 CBC 4283 : nonemptyReloptions(tbinfo->toast_reloptions))
5179 alvherre 15850 ECB : {
5050 bruce 15851 GIC 146 : bool addcomma = false;
5179 alvherre 15852 ECB :
3429 heikki.linnakangas 15853 GBC 146 : appendPQExpBufferStr(q, "\nWITH (");
2654 tgl 15854 GIC 146 : if (nonemptyReloptions(tbinfo->reloptions))
15855 : {
5179 alvherre 15856 CBC 146 : addcomma = true;
2529 dean.a.rasheed 15857 146 : appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15858 : }
2654 tgl 15859 GIC 146 : if (nonemptyReloptions(tbinfo->toast_reloptions))
5179 alvherre 15860 ECB : {
2654 tgl 15861 GIC 5 : if (addcomma)
15862 5 : appendPQExpBufferStr(q, ", ");
2529 dean.a.rasheed 15863 5 : appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15864 : fout);
15865 : }
3429 heikki.linnakangas 15866 146 : appendPQExpBufferChar(q, ')');
15867 : }
6125 bruce 15868 ECB :
15869 : /* Dump generic options if any */
4481 rhaas 15870 CBC 4429 : if (ftoptions && ftoptions[0])
4112 peter_e 15871 GIC 36 : appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
4481 rhaas 15872 ECB :
3689 kgrittn 15873 : /*
3602 bruce 15874 : * For materialized views, create the AS clause just like a view. At
15875 : * this point, we always mark the view as not populated.
3689 kgrittn 15876 : */
3689 kgrittn 15877 GIC 4429 : if (tbinfo->relkind == RELKIND_MATVIEW)
3689 kgrittn 15878 ECB : {
15879 : PQExpBuffer result;
15880 :
3689 kgrittn 15881 GIC 328 : result = createViewAsClause(fout, tbinfo);
3689 kgrittn 15882 CBC 328 : appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
15883 : result->data);
15884 328 : destroyPQExpBuffer(result);
3689 kgrittn 15885 ECB : }
15886 : else
3429 heikki.linnakangas 15887 GIC 4101 : appendPQExpBufferStr(q, ";\n");
7557 tgl 15888 ECB :
15889 : /* Materialized views can depend on extensions */
1124 alvherre 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",
1124 alvherre 15894 ECB : qualrelname);
15895 :
15896 : /*
15897 : * in binary upgrade mode, update the catalog with any missing values
1752 andrew 15898 : * that might be present.
15899 : */
1752 andrew 15900 CBC 4429 : if (dopt->binary_upgrade)
1752 andrew 15901 ECB : {
1752 andrew 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");
1752 andrew 15907 CBC 2 : appendPQExpBufferStr(q,
15908 : "SELECT pg_catalog.binary_upgrade_set_missing_value(");
15909 2 : appendStringLiteralAH(q, qualrelname, fout);
1752 andrew 15910 GIC 2 : appendPQExpBufferStr(q, "::pg_catalog.regclass,");
1752 andrew 15911 CBC 2 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
215 drowley 15912 GNC 2 : appendPQExpBufferChar(q, ',');
1752 andrew 15913 GIC 2 : appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
1752 andrew 15914 CBC 2 : appendPQExpBufferStr(q, ");\n\n");
15915 : }
15916 : }
1752 andrew 15917 ECB : }
15918 :
5164 bruce 15919 : /*
4790 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
3260 15924 : * dropped column can be skipped properly. (We do not bother with
15925 : * restoring the original attbyval setting.) Also, inheritance
2878 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
1873 tgl 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 : */
2940 tgl 15940 GIC 4429 : if (dopt->binary_upgrade &&
15941 661 : (tbinfo->relkind == RELKIND_RELATION ||
2314 rhaas 15942 97 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15943 96 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15944 : {
5164 bruce 15945 3466 : for (j = 0; j < tbinfo->numatts; j++)
15946 : {
15947 2821 : if (tbinfo->attisdropped[j])
5164 bruce 15948 ECB : {
3429 heikki.linnakangas 15949 CBC 79 : appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
5029 tgl 15950 79 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
5029 tgl 15951 ECB : "SET attlen = %d, "
15952 : "attalign = '%c', attbyval = false\n"
15953 : "WHERE attname = ",
5029 tgl 15954 CBC 79 : tbinfo->attlen[j],
15955 79 : tbinfo->attalign[j]);
5029 tgl 15956 GIC 79 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
3429 heikki.linnakangas 15957 CBC 79 : appendPQExpBufferStr(q, "\n AND attrelid = ");
1868 tgl 15958 79 : appendStringLiteralAH(q, qualrelname, fout);
3429 heikki.linnakangas 15959 GIC 79 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
5029 tgl 15960 ECB :
2314 rhaas 15961 CBC 79 : if (tbinfo->relkind == RELKIND_RELATION ||
15962 16 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
3575 andrew 15963 79 : appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
1868 tgl 15964 ECB : qualrelname);
3575 andrew 15965 : else
2940 tgl 15966 UIC 0 : appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15967 : qualrelname);
5164 bruce 15968 CBC 79 : appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15969 79 : fmtId(tbinfo->attnames[j]));
15970 : }
5029 tgl 15971 2742 : else if (!tbinfo->attislocal[j])
15972 : {
3429 heikki.linnakangas 15973 534 : appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15974 534 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
3260 bruce 15975 ECB : "SET attislocal = false\n"
15976 : "WHERE attname = ");
5029 tgl 15977 CBC 534 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
3429 heikki.linnakangas 15978 534 : appendPQExpBufferStr(q, "\n AND attrelid = ");
1868 tgl 15979 GIC 534 : appendStringLiteralAH(q, qualrelname, fout);
3429 heikki.linnakangas 15980 534 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15981 : }
15982 : }
15983 :
15984 : /*
15985 : * Add inherited CHECK constraints, if any.
15986 : *
1399 alvherre 15987 ECB : * For partitions, they were already dumped, and conislocal
15988 : * doesn't need fixing.
15989 : */
5029 tgl 15990 GIC 696 : for (k = 0; k < tbinfo->ncheck; k++)
15991 : {
5029 tgl 15992 CBC 51 : ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15993 :
1399 alvherre 15994 GIC 51 : if (constr->separate || constr->conislocal || tbinfo->ispartition)
5029 tgl 15995 CBC 49 : continue;
5029 tgl 15996 ECB :
3429 heikki.linnakangas 15997 GIC 2 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
1115 alvherre 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);
3429 heikki.linnakangas 16002 2 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
16003 : "SET conislocal = false\n"
3260 bruce 16004 ECB : "WHERE contype = 'c' AND conname = ");
5029 tgl 16005 GIC 2 : appendStringLiteralAH(q, constr->dobj.name, fout);
3429 heikki.linnakangas 16006 2 : appendPQExpBufferStr(q, "\n AND conrelid = ");
1868 tgl 16007 2 : appendStringLiteralAH(q, qualrelname, fout);
3429 heikki.linnakangas 16008 2 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16009 : }
16010 :
1399 alvherre 16011 645 : if (numParents > 0 && !tbinfo->ispartition)
16012 : {
1399 alvherre 16013 CBC 42 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
5029 tgl 16014 89 : for (k = 0; k < numParents; k++)
5029 tgl 16015 ECB : {
5029 tgl 16016 GIC 47 : TableInfo *parentRel = parents[k];
16017 :
1115 alvherre 16018 47 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
16019 : qualrelname,
1399 16020 47 : fmtQualifiedDumpable(parentRel));
16021 : }
5164 bruce 16022 ECB : }
5029 tgl 16023 :
489 tgl 16024 CBC 645 : if (OidIsValid(tbinfo->reloftype))
16025 : {
3429 heikki.linnakangas 16026 GIC 6 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
4365 peter_e 16027 6 : appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
16028 : qualrelname,
489 tgl 16029 6 : getFormattedTypeName(fout, tbinfo->reloftype,
489 tgl 16030 ECB : zeroIsError));
4365 peter_e 16031 : }
1873 tgl 16032 : }
4365 peter_e 16033 :
16034 : /*
16035 : * In binary_upgrade mode, arrange to restore the old relfrozenxid and
1873 tgl 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 : */
1873 tgl 16041 CBC 4429 : if (dopt->binary_upgrade &&
1873 tgl 16042 GIC 661 : (tbinfo->relkind == RELKIND_RELATION ||
16043 97 : tbinfo->relkind == RELKIND_MATVIEW))
1873 tgl 16044 ECB : {
3203 bruce 16045 GIC 580 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
5029 tgl 16046 CBC 580 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16047 : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16048 : "WHERE oid = ",
3203 bruce 16049 GIC 580 : tbinfo->frozenxid, tbinfo->minmxid);
1868 tgl 16050 580 : appendStringLiteralAH(q, qualrelname, fout);
3429 heikki.linnakangas 16051 580 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16052 :
4384 bruce 16053 580 : if (tbinfo->toast_oid)
4384 bruce 16054 ECB : {
16055 : /*
1873 tgl 16056 : * The toast table will have the same OID at restore, so we
16057 : * can safely target it by OID.
16058 : */
3203 bruce 16059 GIC 251 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
4384 16060 251 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16061 : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16062 : "WHERE oid = '%u';\n",
3203 16063 251 : tbinfo->toast_frozenxid,
3203 bruce 16064 CBC 251 : tbinfo->toast_minmxid, tbinfo->toast_oid);
16065 : }
5164 bruce 16066 ECB : }
5050 16067 :
16068 : /*
16069 : * In binary_upgrade mode, restore matviews' populated status by
3625 tgl 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
1873 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.
3625 16074 : */
3099 alvherre 16075 GIC 4429 : if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
3625 tgl 16076 CBC 16 : tbinfo->relispopulated)
3625 tgl 16077 ECB : {
3429 heikki.linnakangas 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"
3260 bruce 16081 ECB : "WHERE oid = ");
1868 tgl 16082 CBC 14 : appendStringLiteralAH(q, qualrelname, fout);
3429 heikki.linnakangas 16083 GIC 14 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16084 : }
3625 tgl 16085 ECB :
16086 : /*
16087 : * Dump additional per-column properties that we can't handle in the
16088 : * main CREATE TABLE command.
4076 16089 : */
7522 bruce 16090 CBC 20924 : for (j = 0; j < tbinfo->numatts; j++)
7557 tgl 16091 ECB : {
4076 16092 : /* None of this applies to dropped columns */
4076 tgl 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 : */
3099 alvherre 16101 16069 : if (!shouldPrintColumn(dopt, tbinfo, j) &&
2 alvherre 16102 GNC 401 : tbinfo->notnull[j] && tbinfo->localNotNull[j] &&
16103 7 : tbinfo->ispartition)
1115 alvherre 16104 UIC 0 : appendPQExpBuffer(q,
16105 : "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET NOT NULL;\n",
1115 alvherre 16106 ECB : foreign, qualrelname,
4076 tgl 16107 UIC 0 : fmtId(tbinfo->attnames[j]));
4076 tgl 16108 ECB :
16109 : /*
6385 bruce 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 : */
4076 tgl 16114 CBC 16069 : if (tbinfo->attstattarget[j] >= 0)
1115 alvherre 16115 36 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
16116 : foreign, qualrelname,
16117 36 : fmtId(tbinfo->attnames[j]),
7557 tgl 16118 GIC 36 : tbinfo->attstattarget[j]);
7325 bruce 16119 ECB :
16120 : /*
7188 16121 : * Dump per-column storage information. The statement is only
16122 : * dumped if the storage has been changed from the type's default.
7325 16123 : */
4076 tgl 16124 GIC 16069 : if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
16125 : {
7188 bruce 16126 CBC 87 : switch (tbinfo->attstorage[j])
7188 bruce 16127 ECB : {
1131 tgl 16128 CBC 10 : case TYPSTORAGE_PLAIN:
7325 bruce 16129 GIC 10 : storage = "PLAIN";
16130 10 : break;
1131 tgl 16131 41 : case TYPSTORAGE_EXTERNAL:
7325 bruce 16132 41 : storage = "EXTERNAL";
16133 41 : break;
1131 tgl 16134 LBC 0 : case TYPSTORAGE_EXTENDED:
7325 bruce 16135 UIC 0 : storage = "EXTENDED";
16136 0 : break;
1131 tgl 16137 GIC 36 : case TYPSTORAGE_MAIN:
16138 36 : storage = "MAIN";
16139 36 : break;
7325 bruce 16140 UIC 0 : default:
7325 bruce 16141 LBC 0 : storage = NULL;
7325 bruce 16142 ECB : }
16143 :
7188 16144 : /*
6385 16145 : * Only dump the statement if it's a storage type we recognize
16146 : */
7188 bruce 16147 CBC 87 : if (storage != NULL)
1115 alvherre 16148 GIC 87 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
1115 alvherre 16149 ECB : foreign, qualrelname,
1115 alvherre 16150 CBC 87 : fmtId(tbinfo->attnames[j]),
7325 bruce 16151 ECB : storage);
16152 : }
4825 rhaas 16153 :
16154 : /*
16155 : * Dump per-column compression, if it's been set.
750 tgl 16156 : */
750 tgl 16157 CBC 16069 : if (!dopt->no_toast_compression)
16158 : {
750 tgl 16159 ECB : const char *cmname;
16160 :
750 tgl 16161 GIC 15998 : switch (tbinfo->attcompression[j])
16162 : {
750 tgl 16163 CBC 55 : case 'p':
16164 55 : cmname = "pglz";
750 tgl 16165 GIC 55 : break;
750 tgl 16166 CBC 100 : case 'l':
750 tgl 16167 GIC 100 : cmname = "lz4";
750 tgl 16168 CBC 100 : break;
16169 15843 : default:
750 tgl 16170 GIC 15843 : cmname = NULL;
750 tgl 16171 CBC 15843 : break;
750 tgl 16172 ECB : }
16173 :
682 tgl 16174 CBC 15998 : if (cmname != NULL)
750 tgl 16175 GIC 155 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
750 tgl 16176 ECB : foreign, qualrelname,
750 tgl 16177 CBC 155 : fmtId(tbinfo->attnames[j]),
750 tgl 16178 ECB : cmname);
16179 : }
16180 :
682 16181 : /*
16182 : * Dump per-column attributes.
16183 : */
682 tgl 16184 GIC 16069 : if (tbinfo->attoptions[j][0] != '\0')
682 tgl 16185 CBC 36 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
682 tgl 16186 ECB : foreign, qualrelname,
682 tgl 16187 GIC 36 : fmtId(tbinfo->attnames[j]),
16188 36 : tbinfo->attoptions[j]);
16189 :
16190 : /*
16191 : * Dump per-column fdw options.
682 tgl 16192 ECB : */
682 tgl 16193 GIC 16069 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16194 38 : tbinfo->attfdwoptions[j][0] != '\0')
16195 36 : appendPQExpBuffer(q,
682 tgl 16196 ECB : "ALTER FOREIGN TABLE %s ALTER COLUMN %s OPTIONS (\n"
16197 : " %s\n"
16198 : ");\n",
16199 : qualrelname,
682 tgl 16200 GIC 36 : fmtId(tbinfo->attnames[j]),
16201 36 : tbinfo->attfdwoptions[j]);
750 tgl 16202 ECB : } /* end loop over columns */
16203 :
297 peter 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 : */
2940 tgl 16212 CBC 4700 : if ((tbinfo->relkind == RELKIND_RELATION ||
2314 rhaas 16213 GIC 1103 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
2940 tgl 16214 CBC 637 : tbinfo->relkind == RELKIND_MATVIEW) &&
3437 peter_e 16215 GIC 4391 : tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
3439 rhaas 16216 ECB : {
3439 rhaas 16217 UIC 0 : if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
3439 rhaas 16218 ECB : {
16219 : /* nothing to do, will be set when the index is dumped */
16220 : }
3439 rhaas 16221 LBC 0 : else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
3439 rhaas 16222 ECB : {
3439 rhaas 16223 LBC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
1868 tgl 16224 ECB : qualrelname);
3439 rhaas 16225 : }
3439 rhaas 16226 LBC 0 : else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16227 : {
3439 rhaas 16228 UIC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16229 : qualrelname);
16230 : }
16231 : }
16232 :
2744 sfrost 16233 GIC 4700 : if (tbinfo->forcerowsec)
16234 5 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16235 : qualrelname);
16236 :
3099 alvherre 16237 4700 : if (dopt->binary_upgrade)
1868 tgl 16238 709 : binary_upgrade_extension_member(q, &tbinfo->dobj,
16239 : reltypename, qrelname,
16240 709 : tbinfo->dobj.namespace->dobj.name);
16241 :
2559 sfrost 16242 4700 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16243 : {
492 peter 16244 4700 : char *tablespace = NULL;
1418 tgl 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
492 peter 16252 ECB : * tablespace (not NULL).
16253 : */
492 peter 16254 CBC 4700 : if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
16255 4391 : tablespace = tbinfo->reltablespace;
16256 :
16257 4700 : if (RELKIND_HAS_TABLE_AM(tbinfo->relkind))
1495 andres 16258 GIC 3925 : tableam = tbinfo->amname;
1495 andres 16259 ECB :
2559 sfrost 16260 GIC 4700 : ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
1528 alvherre 16261 CBC 4700 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
1528 alvherre 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));
1495 andres 16271 : }
16272 :
7639 tgl 16273 : /* Dump Table Comments */
2559 sfrost 16274 CBC 4700 : if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16275 82 : dumpTableComment(fout, tbinfo, reltypename);
16276 :
16277 : /* Dump Table Security Labels */
2559 sfrost 16278 GBC 4700 : if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2559 sfrost 16279 UIC 0 : dumpTableSecLabel(fout, tbinfo, reltypename);
4577 rhaas 16280 ECB :
6690 tgl 16281 : /* Dump comments on inlined table constraints */
6690 tgl 16282 GIC 5258 : for (j = 0; j < tbinfo->ncheck; j++)
6690 tgl 16283 ECB : {
6690 tgl 16284 GIC 558 : ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
6690 tgl 16285 ECB :
5448 tgl 16286 CBC 558 : if (constr->separate || !constr->conislocal)
6690 tgl 16287 GIC 229 : continue;
16288 :
158 tgl 16289 CBC 329 : if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
2559 sfrost 16290 41 : dumpTableConstraintComment(fout, constr);
6690 tgl 16291 ECB : }
16292 :
7639 tgl 16293 GIC 4700 : destroyPQExpBuffer(q);
16294 4700 : destroyPQExpBuffer(delq);
1868 16295 4700 : free(qrelname);
16296 4700 : free(qualrelname);
8122 pjw 16297 4700 : }
16298 :
16299 : /*
16300 : * dumpTableAttach
16301 : * write to fout the commands to attach a child partition
818 tgl 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
788 peter 16315 GIC 1166 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
16316 : {
818 tgl 16317 CBC 1166 : DumpOptions *dopt = fout->dopt;
818 tgl 16318 ECB : PQExpBuffer q;
489 16319 : PGresult *res;
16320 : char *partbound;
16321 :
16322 : /* Do nothing in data-only dump */
818 tgl 16323 CBC 1166 : if (dopt->dataOnly)
818 tgl 16324 GIC 15 : return;
818 tgl 16325 ECB :
818 tgl 16326 GIC 1151 : q = createPQExpBuffer();
818 tgl 16327 ECB :
489 tgl 16328 GIC 1151 : if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
489 tgl 16329 ECB : {
16330 : /* Set up query for partbound details */
489 tgl 16331 GIC 47 : appendPQExpBufferStr(q,
16332 : "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
489 tgl 16333 ECB :
489 tgl 16334 GIC 47 : appendPQExpBufferStr(q,
489 tgl 16335 ECB : "SELECT pg_get_expr(c.relpartbound, c.oid) "
16336 : "FROM pg_class c "
16337 : "WHERE c.oid = $1");
16338 :
489 tgl 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);
489 tgl 16350 ECB :
16351 : /* Perform ALTER TABLE on the parent */
489 tgl 16352 CBC 1151 : printfPQExpBuffer(q,
16353 : "ALTER TABLE ONLY %s ",
818 16354 1151 : fmtQualifiedDumpable(attachinfo->parentTbl));
16355 1151 : appendPQExpBuffer(q,
16356 : "ATTACH PARTITION %s %s;\n",
818 tgl 16357 GIC 1151 : fmtQualifiedDumpable(attachinfo->partitionTbl),
489 tgl 16358 ECB : partbound);
818 16359 :
817 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 : */
818 tgl 16367 GIC 1151 : ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
818 tgl 16368 CBC 1151 : ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
818 tgl 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 :
489 tgl 16375 GIC 1151 : PQclear(res);
818 16376 1151 : destroyPQExpBuffer(q);
16377 : }
16378 :
16379 : /*
16380 : * dumpAttrDef --- dump an attribute's default-value declaration
16381 : */
16382 : static void
788 peter 16383 793 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
7064 tgl 16384 ECB : {
2643 tgl 16385 CBC 793 : DumpOptions *dopt = fout->dopt;
7064 tgl 16386 GIC 793 : TableInfo *tbinfo = adinfo->adtable;
7064 tgl 16387 CBC 793 : int adnum = adinfo->adnum;
7064 tgl 16388 ECB : PQExpBuffer q;
16389 : PQExpBuffer delq;
16390 : char *qualrelname;
2600 peter_e 16391 : char *tag;
1115 alvherre 16392 : char *foreign;
16393 :
16394 : /* Do nothing in data-only dump */
489 tgl 16395 GIC 793 : if (dopt->dataOnly)
7064 tgl 16396 UIC 0 : return;
16397 :
16398 : /* Skip if not "separate"; it was dumped in the table's definition */
4076 tgl 16399 CBC 793 : if (!adinfo->separate)
7064 tgl 16400 GIC 640 : return;
16401 :
7064 tgl 16402 CBC 153 : q = createPQExpBuffer();
16403 153 : delq = createPQExpBuffer();
16404 :
1868 tgl 16405 GIC 153 : qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16406 :
1115 alvherre 16407 153 : foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
16408 :
16409 153 : appendPQExpBuffer(q,
1115 alvherre 16410 ECB : "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
1115 alvherre 16411 CBC 153 : foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
7064 tgl 16412 153 : adinfo->adef_expr);
7064 tgl 16413 EUB :
1115 alvherre 16414 GIC 153 : appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
16415 : foreign, qualrelname,
7064 tgl 16416 GBC 153 : fmtId(tbinfo->attnames[adnum - 1]));
16417 :
2600 peter_e 16418 GIC 153 : tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16419 :
2559 sfrost 16420 153 : if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16421 153 : ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
1528 alvherre 16422 153 : ARCHIVE_OPTS(.tag = tag,
1528 alvherre 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 :
2600 peter_e 16430 GIC 153 : free(tag);
7064 tgl 16431 153 : destroyPQExpBuffer(q);
16432 153 : destroyPQExpBuffer(delq);
1868 tgl 16433 CBC 153 : free(qualrelname);
16434 : }
7064 tgl 16435 ECB :
16436 : /*
8022 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 : */
8022 tgl 16443 EUB : static const char *
788 peter 16444 GBC 1165 : getAttrName(int attrnum, const TableInfo *tblInfo)
8022 tgl 16445 EUB : {
8022 tgl 16446 CBC 1165 : if (attrnum > 0 && attrnum <= tblInfo->numatts)
7836 bruce 16447 1165 : return tblInfo->attnames[attrnum - 1];
8022 tgl 16448 LBC 0 : switch (attrnum)
8022 tgl 16449 EUB : {
8022 tgl 16450 UBC 0 : case SelfItemPointerAttributeNumber:
8022 tgl 16451 UIC 0 : return "ctid";
16452 0 : case MinTransactionIdAttributeNumber:
16453 0 : return "xmin";
16454 0 : case MinCommandIdAttributeNumber:
16455 0 : return "cmin";
8022 tgl 16456 LBC 0 : case MaxTransactionIdAttributeNumber:
16457 0 : return "xmax";
8022 tgl 16458 UIC 0 : case MaxCommandIdAttributeNumber:
8022 tgl 16459 LBC 0 : return "cmax";
8022 tgl 16460 UIC 0 : case TableOidAttributeNumber:
16461 0 : return "tableoid";
16462 : }
366 16463 0 : pg_fatal("invalid column number %d for table \"%s\"",
16464 : attrnum, tblInfo->dobj.name);
16465 : return NULL; /* keep compiler quiet */
8022 tgl 16466 ECB : }
16467 :
16468 : /*
16469 : * dumpIndex
7064 16470 : * write out to fout a user-defined index
16471 : */
16472 : static void
788 peter 16473 CBC 1842 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
9770 scrappy 16474 ECB : {
2643 tgl 16475 CBC 1842 : DumpOptions *dopt = fout->dopt;
7064 16476 1842 : TableInfo *tbinfo = indxinfo->indextable;
3573 16477 1842 : bool is_constraint = (indxinfo->indexconstraint != 0);
7064 tgl 16478 ECB : PQExpBuffer q;
16479 : PQExpBuffer delq;
1868 16480 : char *qindxname;
16481 : char *qqindxname;
16482 :
489 16483 : /* Do nothing in data-only dump */
3099 alvherre 16484 CBC 1842 : if (dopt->dataOnly)
7064 tgl 16485 GIC 48 : return;
7950 peter_e 16486 ECB :
7064 tgl 16487 GIC 1794 : q = createPQExpBuffer();
16488 1794 : delq = createPQExpBuffer();
16489 :
1868 16490 1794 : qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
1124 alvherre 16491 1794 : qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
16492 :
7064 tgl 16493 ECB : /*
6385 bruce 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
3260 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 : */
3573 tgl 16500 GIC 1794 : if (!is_constraint)
16501 : {
1573 michael 16502 CBC 939 : char *indstatcols = indxinfo->indstatcols;
16503 939 : char *indstatvals = indxinfo->indstatvals;
16504 939 : char **indstatcolsarray = NULL;
1573 michael 16505 GIC 939 : char **indstatvalsarray = NULL;
871 16506 939 : int nstatcols = 0;
16507 939 : int nstatvals = 0;
16508 :
3099 alvherre 16509 CBC 939 : if (dopt->binary_upgrade)
4079 rhaas 16510 147 : binary_upgrade_set_pg_class_oids(fout, q,
4079 rhaas 16511 GIC 147 : indxinfo->dobj.catId.oid, true);
16512 :
7064 tgl 16513 ECB : /* Plain secondary index */
7064 tgl 16514 CBC 939 : appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
8397 bruce 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 : */
1714 tgl 16521 :
7064 16522 : /* If the index is clustered, we need to record that. */
7064 tgl 16523 CBC 939 : if (indxinfo->indisclustered)
7064 tgl 16524 ECB : {
7064 tgl 16525 UIC 0 : appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
1868 tgl 16526 UBC 0 : fmtQualifiedDumpable(tbinfo));
16527 : /* index name is not qualified in this syntax */
7064 tgl 16528 UIC 0 : appendPQExpBuffer(q, " ON %s;\n",
16529 : qindxname);
7064 tgl 16530 EUB : }
16531 :
1573 michael 16532 : /*
16533 : * If the index has any statistics on some of its columns, generate
16534 : * the associated ALTER INDEX queries.
16535 : */
871 michael 16536 GIC 939 : if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
1573 michael 16537 EUB : {
16538 : int j;
16539 :
871 michael 16540 GIC 36 : if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
366 tgl 16541 UIC 0 : pg_fatal("could not parse index statistic columns");
871 michael 16542 CBC 36 : if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
366 tgl 16543 LBC 0 : pg_fatal("could not parse index statistic values");
871 michael 16544 GIC 36 : if (nstatcols != nstatvals)
366 tgl 16545 UIC 0 : pg_fatal("mismatched number of columns and values for index statistics");
871 michael 16546 ECB :
1573 michael 16547 CBC 108 : for (j = 0; j < nstatcols; j++)
16548 : {
1124 alvherre 16549 72 : appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
16550 :
1573 michael 16551 ECB : /*
16552 : * Note that this is a column number, so no quotes should be
16553 : * used.
16554 : */
1573 michael 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 */
1124 alvherre 16563 CBC 939 : append_depends_on_extension(fout, q, &indxinfo->dobj,
1124 alvherre 16564 ECB : "pg_catalog.pg_class",
16565 : "INDEX", qqindxname);
16566 :
3318 simon 16567 : /* If the index defines identity, we need to record that. */
3439 rhaas 16568 GIC 939 : if (indxinfo->indisreplident)
3439 rhaas 16569 ECB : {
3439 rhaas 16570 LBC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
1868 tgl 16571 UIC 0 : fmtQualifiedDumpable(tbinfo));
16572 : /* index name is not qualified in this syntax */
3439 rhaas 16573 0 : appendPQExpBuffer(q, " INDEX %s;\n",
16574 : qindxname);
16575 : }
16576 :
1124 alvherre 16577 GIC 939 : appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
16578 :
2559 sfrost 16579 939 : if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16580 939 : ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
1528 alvherre 16581 939 : ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
16582 : .namespace = tbinfo->dobj.namespace->dobj.name,
1528 alvherre 16583 ECB : .tablespace = indxinfo->tablespace,
16584 : .owner = tbinfo->rolname,
16585 : .description = "INDEX",
16586 : .section = SECTION_POST_DATA,
16587 : .createStmt = q->data,
1528 alvherre 16588 EUB : .dropStmt = delq->data));
16589 :
297 peter 16590 GNC 939 : free(indstatcolsarray);
16591 939 : free(indstatvalsarray);
16592 : }
9345 bruce 16593 ECB :
7064 tgl 16594 : /* Dump Index Comments */
2559 sfrost 16595 GIC 1794 : if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 16596 CBC 15 : dumpComment(fout, "INDEX", qindxname,
2559 sfrost 16597 15 : tbinfo->dobj.namespace->dobj.name,
16598 : tbinfo->rolname,
16599 : indxinfo->dobj.catId, 0,
2559 sfrost 16600 ECB : is_constraint ? indxinfo->indexconstraint :
16601 : indxinfo->dobj.dumpId);
9345 bruce 16602 :
7064 tgl 16603 CBC 1794 : destroyPQExpBuffer(q);
16604 1794 : destroyPQExpBuffer(delq);
1868 tgl 16605 GIC 1794 : free(qindxname);
1124 alvherre 16606 1794 : free(qqindxname);
16607 : }
16608 :
16609 : /*
16610 : * dumpIndexAttach
16611 : * write out to fout a partitioned-index attachment clause
16612 : */
16613 : static void
788 peter 16614 567 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
16615 : {
16616 : /* Do nothing in data-only dump */
1906 alvherre 16617 567 : if (fout->dopt->dataOnly)
16618 24 : return;
16619 :
16620 543 : if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16621 : {
1903 tgl 16622 CBC 543 : PQExpBuffer q = createPQExpBuffer();
16623 :
1685 16624 543 : appendPQExpBuffer(q, "ALTER INDEX %s ",
1868 tgl 16625 GIC 543 : fmtQualifiedDumpable(attachinfo->parentIdx));
1906 alvherre 16626 543 : appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
1868 tgl 16627 543 : fmtQualifiedDumpable(attachinfo->partitionIdx));
16628 :
16629 : /*
817 tgl 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 : */
1906 alvherre 16636 GIC 543 : ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
1528 16637 543 : ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
1528 alvherre 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 :
1906 alvherre 16644 GIC 543 : destroyPQExpBuffer(q);
16645 : }
1906 alvherre 16646 ECB : }
16647 :
2207 16648 : /*
16649 : * dumpStatisticsExt
16650 : * write out to fout an extended statistics object
16651 : */
16652 : static void
788 peter 16653 CBC 137 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
16654 : {
2207 alvherre 16655 137 : DumpOptions *dopt = fout->dopt;
2207 alvherre 16656 ECB : PQExpBuffer q;
16657 : PQExpBuffer delq;
16658 : PQExpBuffer query;
1868 tgl 16659 : char *qstatsextname;
16660 : PGresult *res;
1883 16661 : char *stxdef;
2207 alvherre 16662 :
16663 : /* Do nothing in data-only dump */
489 tgl 16664 CBC 137 : if (dopt->dataOnly)
2207 alvherre 16665 GIC 9 : return;
16666 :
16667 128 : q = createPQExpBuffer();
16668 128 : delq = createPQExpBuffer();
1883 tgl 16669 128 : query = createPQExpBuffer();
16670 :
1868 16671 128 : qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16672 :
1883 16673 128 : appendPQExpBuffer(query, "SELECT "
1883 tgl 16674 ECB : "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
1883 tgl 16675 CBC 128 : statsextinfo->dobj.catId.oid);
16676 :
1883 tgl 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 */
1883 tgl 16682 CBC 128 : appendPQExpBuffer(q, "%s;\n", stxdef);
2207 alvherre 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 : */
1307 tomas.vondra 16689 GIC 128 : if (statsextinfo->stattarget >= 0)
1307 tomas.vondra 16690 ECB : {
1307 tomas.vondra 16691 GIC 36 : appendPQExpBuffer(q, "ALTER STATISTICS %s ",
1307 tomas.vondra 16692 CBC 36 : fmtQualifiedDumpable(statsextinfo));
16693 36 : appendPQExpBuffer(q, "SET STATISTICS %d;\n",
16694 36 : statsextinfo->stattarget);
16695 : }
16696 :
1868 tgl 16697 GIC 128 : appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16698 128 : fmtQualifiedDumpable(statsextinfo));
16699 :
2207 alvherre 16700 128 : if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2153 bruce 16701 128 : ArchiveEntry(fout, statsextinfo->dobj.catId,
2153 bruce 16702 CBC 128 : statsextinfo->dobj.dumpId,
1528 alvherre 16703 GBC 128 : ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
16704 : .namespace = statsextinfo->dobj.namespace->dobj.name,
16705 : .owner = statsextinfo->rolname,
1528 alvherre 16706 ECB : .description = "STATISTICS",
16707 : .section = SECTION_POST_DATA,
16708 : .createStmt = q->data,
16709 : .dropStmt = delq->data));
2207 16710 :
16711 : /* Dump Statistics Comments */
2207 alvherre 16712 CBC 128 : if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 16713 UIC 0 : dumpComment(fout, "STATISTICS", qstatsextname,
1883 tgl 16714 LBC 0 : statsextinfo->dobj.namespace->dobj.name,
1883 tgl 16715 UIC 0 : statsextinfo->rolname,
2207 alvherre 16716 ECB : statsextinfo->dobj.catId, 0,
2207 alvherre 16717 UIC 0 : statsextinfo->dobj.dumpId);
2207 alvherre 16718 ECB :
1883 tgl 16719 CBC 128 : PQclear(res);
2207 alvherre 16720 GIC 128 : destroyPQExpBuffer(q);
2207 alvherre 16721 CBC 128 : destroyPQExpBuffer(delq);
1883 tgl 16722 GIC 128 : destroyPQExpBuffer(query);
1868 tgl 16723 CBC 128 : free(qstatsextname);
16724 : }
2207 alvherre 16725 ECB :
16726 : /*
7064 tgl 16727 : * dumpConstraint
16728 : * write out to fout a user-defined constraint
16729 : */
16730 : static void
788 peter 16731 GIC 1684 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
16732 : {
2643 tgl 16733 1684 : DumpOptions *dopt = fout->dopt;
7064 16734 1684 : TableInfo *tbinfo = coninfo->contable;
16735 : PQExpBuffer q;
16736 : PQExpBuffer delq;
2600 peter_e 16737 CBC 1684 : char *tag = NULL;
1115 alvherre 16738 ECB : char *foreign;
7064 tgl 16739 :
489 16740 : /* Do nothing in data-only dump */
489 tgl 16741 GIC 1684 : if (dopt->dataOnly)
7064 16742 38 : return;
16743 :
16744 1646 : q = createPQExpBuffer();
16745 1646 : delq = createPQExpBuffer();
16746 :
1115 alvherre 16747 3211 : foreign = tbinfo &&
1060 tgl 16748 1646 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
16749 :
4871 16750 1646 : if (coninfo->contype == 'p' ||
4871 tgl 16751 CBC 839 : coninfo->contype == 'u' ||
4871 tgl 16752 GIC 801 : coninfo->contype == 'x')
7064 tgl 16753 CBC 855 : {
7064 tgl 16754 ECB : /* Index-related constraint */
7064 tgl 16755 EUB : IndxInfo *indxinfo;
16756 : int k;
16757 :
7064 tgl 16758 GBC 855 : indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
7064 tgl 16759 EUB :
7064 tgl 16760 GBC 855 : if (indxinfo == NULL)
366 tgl 16761 UBC 0 : pg_fatal("missing index for constraint \"%s\"",
366 tgl 16762 EUB : coninfo->dobj.name);
9345 bruce 16763 :
3099 alvherre 16764 GBC 855 : if (dopt->binary_upgrade)
4079 rhaas 16765 108 : binary_upgrade_set_pg_class_oids(fout, q,
4079 rhaas 16766 EUB : indxinfo->dobj.catId.oid, true);
4841 bruce 16767 :
1115 alvherre 16768 GBC 855 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
1868 tgl 16769 GIC 855 : fmtQualifiedDumpable(tbinfo));
4871 tgl 16770 GBC 855 : appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
4871 tgl 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 : {
215 drowley 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 : */
44 dgustafsson 16787 845 : if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
215 drowley 16788 UNC 0 : appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
215 drowley 16789 GNC 845 : appendPQExpBufferStr(q, " (");
1828 teodor 16790 GIC 1970 : for (k = 0; k < indxinfo->indnkeyattrs; k++)
16791 : {
4871 tgl 16792 1125 : int indkey = (int) indxinfo->indkeys[k];
16793 : const char *attname;
16794 :
16795 1125 : if (indkey == InvalidAttrNumber)
4871 tgl 16796 LBC 0 : break;
4871 tgl 16797 CBC 1125 : attname = getAttrName(indkey, tbinfo);
16798 :
16799 1125 : appendPQExpBuffer(q, "%s%s",
4871 tgl 16800 ECB : (k == 0) ? "" : ", ",
16801 : fmtId(attname));
16802 : }
7639 16803 :
1828 teodor 16804 GIC 845 : if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
1375 drowley 16805 20 : appendPQExpBufferStr(q, ") INCLUDE (");
16806 :
1828 teodor 16807 885 : for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16808 : {
16809 40 : int indkey = (int) indxinfo->indkeys[k];
16810 : const char *attname;
16811 :
1828 teodor 16812 CBC 40 : if (indkey == InvalidAttrNumber)
1828 teodor 16813 UIC 0 : break;
1828 teodor 16814 CBC 40 : attname = getAttrName(indkey, tbinfo);
1828 teodor 16815 ECB :
1828 teodor 16816 CBC 80 : appendPQExpBuffer(q, "%s%s",
16817 40 : (k == indxinfo->indnkeyattrs) ? "" : ", ",
1828 teodor 16818 ECB : fmtId(attname));
16819 : }
16820 :
3429 heikki.linnakangas 16821 CBC 845 : appendPQExpBufferChar(q, ')');
6125 bruce 16822 ECB :
2654 tgl 16823 CBC 845 : if (nonemptyReloptions(indxinfo->indreloptions))
16824 : {
2654 tgl 16825 UIC 0 : appendPQExpBufferStr(q, " WITH (");
2529 dean.a.rasheed 16826 LBC 0 : appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
2654 tgl 16827 UIC 0 : appendPQExpBufferChar(q, ')');
16828 : }
16829 :
4871 tgl 16830 GIC 845 : if (coninfo->condeferrable)
16831 : {
3429 heikki.linnakangas 16832 UIC 0 : appendPQExpBufferStr(q, " DEFERRABLE");
4871 tgl 16833 0 : if (coninfo->condeferred)
3429 heikki.linnakangas 16834 0 : appendPQExpBufferStr(q, " INITIALLY DEFERRED");
4871 tgl 16835 ECB : }
16836 :
3429 heikki.linnakangas 16837 GBC 845 : appendPQExpBufferStr(q, ";\n");
4871 tgl 16838 EUB : }
16839 :
1714 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. */
7064 tgl 16847 GIC 855 : if (indxinfo->indisclustered)
7064 tgl 16848 ECB : {
7064 tgl 16849 GIC 36 : appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
1868 16850 36 : fmtQualifiedDumpable(tbinfo));
16851 : /* index name is not qualified in this syntax */
7064 tgl 16852 CBC 36 : appendPQExpBuffer(q, " ON %s;\n",
6976 tgl 16853 GBC 36 : fmtId(indxinfo->dobj.name));
7064 tgl 16854 ECB : }
9345 bruce 16855 EUB :
1714 tgl 16856 ECB : /* If the index defines identity, we need to record that. */
1714 tgl 16857 GBC 855 : if (indxinfo->indisreplident)
16858 : {
1714 tgl 16859 LBC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
1714 tgl 16860 UIC 0 : fmtQualifiedDumpable(tbinfo));
1714 tgl 16861 ECB : /* index name is not qualified in this syntax */
1714 tgl 16862 UIC 0 : appendPQExpBuffer(q, " INDEX %s;\n",
16863 0 : fmtId(indxinfo->dobj.name));
16864 : }
16865 :
16866 : /* Indexes can depend on extensions */
1124 alvherre 16867 CBC 855 : append_depends_on_extension(fout, q, &indxinfo->dobj,
1124 alvherre 16868 ECB : "pg_catalog.pg_class", "INDEX",
1124 alvherre 16869 CBC 855 : fmtQualifiedDumpable(indxinfo));
1124 alvherre 16870 ECB :
1115 alvherre 16871 GIC 855 : appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
1868 tgl 16872 855 : fmtQualifiedDumpable(tbinfo));
7064 16873 855 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
6976 16874 855 : fmtId(coninfo->dobj.name));
7639 tgl 16875 ECB :
2600 peter_e 16876 GIC 855 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16877 :
2559 sfrost 16878 855 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16879 855 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
1528 alvherre 16880 CBC 855 : ARCHIVE_OPTS(.tag = tag,
16881 : .namespace = tbinfo->dobj.namespace->dobj.name,
1528 alvherre 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 : }
7064 tgl 16889 CBC 791 : else if (coninfo->contype == 'f')
16890 : {
1809 tgl 16891 ECB : char *only;
1831 alvherre 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 : */
1831 alvherre 16899 GIC 152 : only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
16900 :
16901 : /*
6385 bruce 16902 ECB : * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16903 : * current table data is not processed
16904 : */
1115 alvherre 16905 GIC 152 : appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
1831 16906 152 : only, fmtQualifiedDumpable(tbinfo));
7064 tgl 16907 CBC 152 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
6976 16908 152 : fmtId(coninfo->dobj.name),
7064 16909 152 : coninfo->condef);
16910 :
1115 alvherre 16911 GIC 152 : appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
1831 16912 152 : only, fmtQualifiedDumpable(tbinfo));
7064 tgl 16913 152 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
6976 16914 152 : fmtId(coninfo->dobj.name));
7639 tgl 16915 ECB :
2600 peter_e 16916 CBC 152 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
2600 peter_e 16917 ECB :
2559 sfrost 16918 CBC 152 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 16919 GIC 152 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
1528 alvherre 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,
1528 alvherre 16926 ECB : .dropStmt = delq->data));
16927 : }
2 alvherre 16928 GNC 639 : else if (coninfo->contype == 'n')
16929 : {
2 alvherre 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 : }
7064 tgl 16953 GIC 639 : else if (coninfo->contype == 'c' && tbinfo)
7064 tgl 16954 ECB : {
16955 : /* CHECK constraint on a table */
16956 :
2747 16957 : /* Ignore if not to be dumped separately, or if it was inherited */
2747 tgl 16958 GIC 558 : if (coninfo->separate && coninfo->conislocal)
7064 tgl 16959 ECB : {
16960 : /* not ONLY since we want it to propagate to children */
1115 alvherre 16961 CBC 25 : appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
1868 tgl 16962 25 : fmtQualifiedDumpable(tbinfo));
7064 16963 25 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
6976 16964 25 : fmtId(coninfo->dobj.name),
7064 tgl 16965 GIC 25 : coninfo->condef);
16966 :
1115 alvherre 16967 25 : appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
1868 tgl 16968 25 : fmtQualifiedDumpable(tbinfo));
7064 16969 25 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
6976 16970 25 : fmtId(coninfo->dobj.name));
16971 :
2600 peter_e 16972 25 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
2600 peter_e 16973 ECB :
2559 sfrost 16974 CBC 25 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 16975 GIC 25 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
1528 alvherre 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,
1528 alvherre 16981 ECB : .createStmt = q->data,
16982 : .dropStmt = delq->data));
16983 : }
16984 : }
7064 tgl 16985 GIC 81 : else if (coninfo->contype == 'c' && tbinfo == NULL)
16986 81 : {
16987 : /* CHECK constraint on a domain */
4855 bruce 16988 81 : TypeInfo *tyinfo = coninfo->condomain;
16989 :
6247 tgl 16990 ECB : /* Ignore if not to be dumped separately */
6247 tgl 16991 GIC 81 : if (coninfo->separate)
7064 tgl 16992 ECB : {
7064 tgl 16993 UIC 0 : appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
1868 16994 0 : fmtQualifiedDumpable(tyinfo));
7064 16995 0 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
6976 16996 0 : fmtId(coninfo->dobj.name),
7064 16997 0 : coninfo->condef);
16998 :
1868 16999 0 : appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
17000 0 : fmtQualifiedDumpable(tyinfo));
7064 tgl 17001 LBC 0 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
6976 17002 0 : fmtId(coninfo->dobj.name));
17003 :
2600 peter_e 17004 0 : tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
2600 peter_e 17005 ECB :
2559 sfrost 17006 LBC 0 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 17007 UIC 0 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
1528 alvherre 17008 LBC 0 : ARCHIVE_OPTS(.tag = tag,
17009 : .namespace = tyinfo->dobj.namespace->dobj.name,
1528 alvherre 17010 ECB : .owner = tyinfo->rolname,
17011 : .description = "CHECK CONSTRAINT",
17012 : .section = SECTION_POST_DATA,
17013 : .createStmt = q->data,
17014 : .dropStmt = delq->data));
17015 : }
7064 tgl 17016 : }
17017 : else
17018 : {
366 tgl 17019 LBC 0 : pg_fatal("unrecognized constraint type: %c",
17020 : coninfo->contype);
17021 : }
17022 :
17023 : /* Dump Constraint Comments --- only works for table constraints */
2559 sfrost 17024 GIC 1646 : if (tbinfo && coninfo->separate &&
17025 1047 : coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2643 tgl 17026 CBC 10 : dumpTableConstraintComment(fout, coninfo);
17027 :
2600 peter_e 17028 1646 : free(tag);
7639 tgl 17029 1646 : destroyPQExpBuffer(q);
17030 1646 : destroyPQExpBuffer(delq);
9770 scrappy 17031 ECB : }
17032 :
17033 : /*
6690 tgl 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
788 peter 17041 GIC 51 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
17042 : {
6690 tgl 17043 51 : TableInfo *tbinfo = coninfo->contable;
1868 17044 51 : PQExpBuffer conprefix = createPQExpBuffer();
17045 : char *qtabname;
17046 :
17047 51 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17048 :
1868 tgl 17049 CBC 51 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
6690 tgl 17050 GBC 51 : fmtId(coninfo->dobj.name));
2559 sfrost 17051 EUB :
2559 sfrost 17052 GBC 51 : if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 17053 GIC 51 : dumpComment(fout, conprefix->data, qtabname,
2559 sfrost 17054 GBC 51 : tbinfo->dobj.namespace->dobj.name,
17055 : tbinfo->rolname,
2559 sfrost 17056 ECB : coninfo->dobj.catId, 0,
2118 tgl 17057 CBC 51 : coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
6690 tgl 17058 ECB :
1868 tgl 17059 CBC 51 : destroyPQExpBuffer(conprefix);
17060 51 : free(qtabname);
6690 tgl 17061 GIC 51 : }
17062 :
17063 : /*
17064 : * dumpSequence
17065 : * write the declaration (not data) of one user-defined sequence
17066 : */
17067 : static void
788 peter 17068 CBC 315 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
17069 : {
2643 tgl 17070 315 : DumpOptions *dopt = fout->dopt;
8397 bruce 17071 ECB : PGresult *res;
17072 : char *startv,
17073 : *incby,
2249 peter_e 17074 : *maxv,
17075 : *minv,
17076 : *cache,
17077 : *seqtype;
3817 tgl 17078 : bool cycled;
2249 peter_e 17079 : bool is_ascending;
17080 : int64 default_minv,
1874 tgl 17081 : default_maxv;
17082 : char bufm[32],
17083 : bufx[32];
8397 bruce 17084 CBC 315 : PQExpBuffer query = createPQExpBuffer();
8314 17085 315 : PQExpBuffer delqry = createPQExpBuffer();
17086 : char *qseqname;
367 peter 17087 315 : TableInfo *owning_tab = NULL;
1868 tgl 17088 ECB :
1868 tgl 17089 CBC 315 : qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
9345 bruce 17090 ECB :
2301 peter_e 17091 GIC 315 : if (fout->remoteVersion >= 100000)
17092 : {
17093 315 : appendPQExpBuffer(query,
17094 : "SELECT format_type(seqtypid, NULL), "
2249 peter_e 17095 ECB : "seqstart, seqincrement, "
17096 : "seqmax, seqmin, "
2301 17097 : "seqcache, seqcycle "
1868 tgl 17098 EUB : "FROM pg_catalog.pg_sequence "
17099 : "WHERE seqrelid = '%u'::oid",
2266 peter_e 17100 GIC 315 : tbinfo->dobj.catId.oid);
2301 peter_e 17101 ECB : }
481 tgl 17102 : else
17103 : {
17104 : /*
1868 17105 : * Before PostgreSQL 10, sequence metadata is in the sequence itself.
1986 17106 : *
17107 : * Note: it might seem that 'bigint' potentially needs to be
17108 : * schema-qualified, but actually that's a keyword.
17109 : */
5441 tgl 17110 LBC 0 : appendPQExpBuffer(query,
17111 : "SELECT 'bigint' AS sequence_type, "
17112 : "start_value, increment_by, max_value, min_value, "
3817 tgl 17113 ECB : "cache_value, is_cycled FROM %s",
1868 tgl 17114 UIC 0 : fmtQualifiedDumpable(tbinfo));
17115 : }
17116 :
4079 rhaas 17117 CBC 315 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9345 bruce 17118 ECB :
9345 bruce 17119 GIC 315 : if (PQntuples(res) != 1)
366 tgl 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));
9345 bruce 17124 ECB :
2249 peter_e 17125 GBC 315 : seqtype = PQgetvalue(res, 0, 0);
2249 peter_e 17126 CBC 315 : startv = PQgetvalue(res, 0, 1);
17127 315 : incby = PQgetvalue(res, 0, 2);
2249 peter_e 17128 GIC 315 : maxv = PQgetvalue(res, 0, 3);
2249 peter_e 17129 CBC 315 : minv = PQgetvalue(res, 0, 4);
2249 peter_e 17130 GIC 315 : cache = PQgetvalue(res, 0, 5);
17131 315 : cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
2249 peter_e 17132 ECB :
1874 tgl 17133 EUB : /* Calculate default limits for a sequence of this type */
1874 tgl 17134 CBC 315 : is_ascending = (incby[0] != '-');
2249 peter_e 17135 GIC 315 : if (strcmp(seqtype, "smallint") == 0)
2249 peter_e 17136 ECB : {
1874 tgl 17137 GIC 25 : default_minv = is_ascending ? 1 : PG_INT16_MIN;
17138 25 : default_maxv = is_ascending ? PG_INT16_MAX : -1;
17139 : }
2249 peter_e 17140 290 : else if (strcmp(seqtype, "integer") == 0)
2249 peter_e 17141 ECB : {
1874 tgl 17142 CBC 241 : default_minv = is_ascending ? 1 : PG_INT32_MIN;
1874 tgl 17143 GIC 241 : default_maxv = is_ascending ? PG_INT32_MAX : -1;
2249 peter_e 17144 ECB : }
2249 peter_e 17145 GIC 49 : else if (strcmp(seqtype, "bigint") == 0)
2249 peter_e 17146 ECB : {
1874 tgl 17147 GIC 49 : default_minv = is_ascending ? 1 : PG_INT64_MIN;
17148 49 : default_maxv = is_ascending ? PG_INT64_MAX : -1;
1874 tgl 17149 ECB : }
1874 tgl 17150 EUB : else
1874 tgl 17151 ECB : {
366 tgl 17152 UIC 0 : pg_fatal("unrecognized sequence type: %s", seqtype);
1874 tgl 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 : */
1874 tgl 17160 CBC 315 : snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
1874 tgl 17161 GIC 315 : snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
2249 peter_e 17162 EUB :
1874 tgl 17163 : /* Don't print minv/maxv if they match the respective default limit */
1874 tgl 17164 GBC 315 : if (strcmp(minv, bufm) == 0)
1874 tgl 17165 GIC 300 : minv = NULL;
17166 315 : if (strcmp(maxv, bufx) == 0)
1874 tgl 17167 CBC 300 : maxv = NULL;
17168 :
8213 pjw 17169 EUB : /*
1868 tgl 17170 : * Identity sequences are not to be dropped separately.
8213 pjw 17171 : */
2194 peter_e 17172 GIC 315 : if (!tbinfo->is_identity_sequence)
17173 : {
1868 tgl 17174 CBC 209 : appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
1868 tgl 17175 GIC 209 : fmtQualifiedDumpable(tbinfo));
17176 : }
17177 :
3817 17178 315 : resetPQExpBuffer(query);
17179 :
3099 alvherre 17180 315 : if (dopt->binary_upgrade)
17181 : {
3817 tgl 17182 48 : binary_upgrade_set_pg_class_oids(fout, query,
17183 48 : tbinfo->dobj.catId.oid, false);
1006 tgl 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 : */
3817 17189 : }
4854 bruce 17190 :
2194 peter_e 17191 GIC 315 : if (tbinfo->is_identity_sequence)
17192 : {
367 peter 17193 106 : owning_tab = findTableByOid(tbinfo->owning_tab);
7314 bruce 17194 ECB :
2194 peter_e 17195 GIC 106 : appendPQExpBuffer(query,
2194 peter_e 17196 EUB : "ALTER TABLE %s ",
1868 tgl 17197 GBC 106 : fmtQualifiedDumpable(owning_tab));
2194 peter_e 17198 GIC 106 : appendPQExpBuffer(query,
2194 peter_e 17199 EUB : "ALTER COLUMN %s ADD GENERATED ",
2118 tgl 17200 GBC 106 : fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
2194 peter_e 17201 GIC 106 : if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
1375 drowley 17202 71 : appendPQExpBufferStr(query, "ALWAYS");
2194 peter_e 17203 35 : else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
1375 drowley 17204 CBC 35 : appendPQExpBufferStr(query, "BY DEFAULT");
2194 peter_e 17205 GIC 106 : appendPQExpBuffer(query, " AS IDENTITY (\n SEQUENCE NAME %s\n",
1868 tgl 17206 CBC 106 : fmtQualifiedDumpable(tbinfo));
17207 : }
2194 peter_e 17208 ECB : else
17209 : {
2194 peter_e 17210 CBC 209 : appendPQExpBuffer(query,
367 peter 17211 ECB : "CREATE %sSEQUENCE %s\n",
367 peter 17212 GIC 209 : tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
367 peter 17213 ECB : "UNLOGGED " : "",
1868 tgl 17214 GIC 209 : fmtQualifiedDumpable(tbinfo));
2194 peter_e 17215 ECB :
2194 peter_e 17216 CBC 209 : if (strcmp(seqtype, "bigint") != 0)
17217 165 : appendPQExpBuffer(query, " AS %s\n", seqtype);
17218 : }
17219 :
481 tgl 17220 GIC 315 : appendPQExpBuffer(query, " START WITH %s\n", startv);
17221 :
3817 17222 315 : appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
17223 :
17224 315 : if (minv)
17225 15 : appendPQExpBuffer(query, " MINVALUE %s\n", minv);
3817 tgl 17226 ECB : else
3429 heikki.linnakangas 17227 GIC 300 : appendPQExpBufferStr(query, " NO MINVALUE\n");
17228 :
3817 tgl 17229 315 : if (maxv)
17230 15 : appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
17231 : else
3429 heikki.linnakangas 17232 300 : appendPQExpBufferStr(query, " NO MAXVALUE\n");
17233 :
3817 tgl 17234 315 : appendPQExpBuffer(query,
17235 : " CACHE %s%s",
3817 tgl 17236 ECB : cache, (cycled ? "\n CYCLE" : ""));
17237 :
2194 peter_e 17238 GIC 315 : if (tbinfo->is_identity_sequence)
17239 : {
17240 106 : appendPQExpBufferStr(query, "\n);\n");
367 peter 17241 106 : if (tbinfo->relpersistence != owning_tab->relpersistence)
367 peter 17242 LBC 0 : appendPQExpBuffer(query,
367 peter 17243 ECB : "ALTER SEQUENCE %s SET %s;\n",
367 peter 17244 LBC 0 : fmtQualifiedDumpable(tbinfo),
17245 0 : tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
367 peter 17246 ECB : "UNLOGGED" : "LOGGED");
17247 : }
2194 peter_e 17248 : else
2194 peter_e 17249 CBC 209 : appendPQExpBufferStr(query, ";\n");
6869 tgl 17250 ECB :
3817 17251 : /* binary_upgrade: no need to clear TOAST table oid */
17252 :
3099 alvherre 17253 CBC 315 : if (dopt->binary_upgrade)
3817 tgl 17254 GIC 48 : binary_upgrade_extension_member(query, &tbinfo->dobj,
1868 tgl 17255 ECB : "SEQUENCE", qseqname,
1868 tgl 17256 CBC 48 : tbinfo->dobj.namespace->dobj.name);
4442 tgl 17257 ECB :
2559 sfrost 17258 GIC 315 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17259 315 : ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
1528 alvherre 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,
1528 alvherre 17265 ECB : .createStmt = query->data,
17266 : .dropStmt = delqry->data));
6075 tgl 17267 EUB :
3817 17268 : /*
17269 : * If the sequence is owned by a table column, emit the ALTER for it as a
3668 andrew 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
3817 tgl 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 : */
2194 peter_e 17280 GBC 315 : if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
3817 tgl 17281 EUB : {
232 drowley 17282 GBC 120 : owning_tab = findTableByOid(tbinfo->owning_tab);
17283 :
2284 sfrost 17284 GIC 120 : if (owning_tab == NULL)
366 tgl 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 :
2284 sfrost 17288 GIC 120 : if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
17289 : {
3817 tgl 17290 CBC 118 : resetPQExpBuffer(query);
3817 tgl 17291 GIC 118 : appendPQExpBuffer(query, "ALTER SEQUENCE %s",
1868 17292 118 : fmtQualifiedDumpable(tbinfo));
3817 17293 118 : appendPQExpBuffer(query, " OWNED BY %s",
1868 17294 118 : fmtQualifiedDumpable(owning_tab));
3817 tgl 17295 CBC 118 : appendPQExpBuffer(query, ".%s;\n",
2118 tgl 17296 GIC 118 : fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17297 :
2559 sfrost 17298 CBC 118 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17299 118 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 17300 118 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
1528 alvherre 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 : }
8069 pjw 17309 : }
17310 :
3817 tgl 17311 : /* Dump Sequence Comments and Security Labels */
2559 sfrost 17312 CBC 315 : if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 17313 LBC 0 : dumpComment(fout, "SEQUENCE", qseqname,
2559 sfrost 17314 UIC 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17315 0 : tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17316 :
2559 sfrost 17317 GIC 315 : if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
1868 tgl 17318 UIC 0 : dumpSecLabel(fout, "SEQUENCE", qseqname,
2559 sfrost 17319 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17320 0 : tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17321 :
7906 tgl 17322 CBC 315 : PQclear(res);
7906 tgl 17323 ECB :
7919 tgl 17324 GIC 315 : destroyPQExpBuffer(query);
7919 tgl 17325 CBC 315 : destroyPQExpBuffer(delqry);
1868 tgl 17326 GIC 315 : free(qseqname);
9503 vadim4o 17327 315 : }
9320 vadim4o 17328 ECB :
17329 : /*
3817 tgl 17330 EUB : * dumpSequenceData
17331 : * write the data of one user-defined sequence
17332 : */
17333 : static void
788 peter 17334 GBC 338 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
17335 : {
3817 tgl 17336 338 : TableInfo *tbinfo = tdinfo->tdtable;
3817 tgl 17337 EUB : PGresult *res;
17338 : char *last;
17339 : bool called;
3817 tgl 17340 GIC 338 : PQExpBuffer query = createPQExpBuffer();
3817 tgl 17341 EUB :
3817 tgl 17342 GIC 338 : appendPQExpBuffer(query,
3817 tgl 17343 EUB : "SELECT last_value, is_called FROM %s",
1868 tgl 17344 GBC 338 : fmtQualifiedDumpable(tbinfo));
3817 tgl 17345 EUB :
3817 tgl 17346 GIC 338 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17347 :
17348 338 : if (PQntuples(res) != 1)
366 tgl 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 :
3817 tgl 17354 GIC 338 : last = PQgetvalue(res, 0, 0);
17355 338 : called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
3817 tgl 17356 EUB :
3817 tgl 17357 GIC 338 : resetPQExpBuffer(query);
3429 heikki.linnakangas 17358 338 : appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
1868 tgl 17359 338 : appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
3817 17360 338 : appendPQExpBuffer(query, ", %s, %s);\n",
3817 tgl 17361 ECB : last, (called ? "true" : "false"));
17362 :
2271 sfrost 17363 CBC 338 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2559 sfrost 17364 GIC 338 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1528 alvherre 17365 CBC 338 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
1528 alvherre 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 :
3817 tgl 17374 GIC 338 : PQclear(res);
17375 :
17376 338 : destroyPQExpBuffer(query);
17377 338 : }
3817 tgl 17378 ECB :
17379 : /*
3387 17380 : * dumpTrigger
17381 : * write the declaration of one user-defined table trigger
17382 : */
17383 : static void
788 peter 17384 CBC 504 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
17385 : {
2643 tgl 17386 504 : DumpOptions *dopt = fout->dopt;
7064 17387 504 : TableInfo *tbinfo = tginfo->tgtable;
17388 : PQExpBuffer query;
7541 tgl 17389 ECB : PQExpBuffer delqry;
1868 17390 : PQExpBuffer trigprefix;
1124 alvherre 17391 : PQExpBuffer trigidentity;
17392 : char *qtabname;
17393 : char *tgargs;
4996 tgl 17394 : size_t lentgargs;
17395 : const char *p;
7064 17396 : int findx;
2600 peter_e 17397 : char *tag;
7541 tgl 17398 :
17399 : /* Do nothing in data-only dump */
3099 alvherre 17400 GIC 504 : if (dopt->dataOnly)
7541 tgl 17401 16 : return;
17402 :
7064 17403 488 : query = createPQExpBuffer();
17404 488 : delqry = createPQExpBuffer();
1868 tgl 17405 CBC 488 : trigprefix = createPQExpBuffer();
1124 alvherre 17406 GIC 488 : trigidentity = createPQExpBuffer();
1868 tgl 17407 ECB :
1868 tgl 17408 GIC 488 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17409 :
1124 alvherre 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 :
4930 peter_e 17415 488 : if (tginfo->tgdef)
17416 : {
17417 488 : appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17418 : }
17419 : else
17420 : {
4930 peter_e 17421 LBC 0 : if (tginfo->tgisconstraint)
4930 peter_e 17422 ECB : {
3429 heikki.linnakangas 17423 UIC 0 : appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
4930 peter_e 17424 LBC 0 : appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
17425 : }
7064 tgl 17426 ECB : else
17427 : {
3429 heikki.linnakangas 17428 LBC 0 : appendPQExpBufferStr(query, "CREATE TRIGGER ");
4930 peter_e 17429 UIC 0 : appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
4930 peter_e 17430 ECB : }
3429 heikki.linnakangas 17431 UIC 0 : appendPQExpBufferStr(query, "\n ");
17432 :
17433 : /* Trigger type */
4930 peter_e 17434 0 : if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
3429 heikki.linnakangas 17435 0 : appendPQExpBufferStr(query, "BEFORE");
4564 tgl 17436 0 : else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
3429 heikki.linnakangas 17437 LBC 0 : appendPQExpBufferStr(query, "AFTER");
4564 tgl 17438 UIC 0 : else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
3429 heikki.linnakangas 17439 0 : appendPQExpBufferStr(query, "INSTEAD OF");
17440 : else
366 tgl 17441 0 : pg_fatal("unexpected tgtype value: %d", tginfo->tgtype);
17442 :
4564 17443 0 : findx = 0;
4930 peter_e 17444 0 : if (TRIGGER_FOR_INSERT(tginfo->tgtype))
17445 : {
3429 heikki.linnakangas 17446 0 : appendPQExpBufferStr(query, " INSERT");
4930 peter_e 17447 UBC 0 : findx++;
17448 : }
4930 peter_e 17449 UIC 0 : if (TRIGGER_FOR_DELETE(tginfo->tgtype))
17450 : {
4930 peter_e 17451 UBC 0 : if (findx > 0)
3429 heikki.linnakangas 17452 UIC 0 : appendPQExpBufferStr(query, " OR DELETE");
17453 : else
3429 heikki.linnakangas 17454 LBC 0 : appendPQExpBufferStr(query, " DELETE");
4930 peter_e 17455 UIC 0 : findx++;
4930 peter_e 17456 ECB : }
4930 peter_e 17457 UBC 0 : if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
17458 : {
4930 peter_e 17459 UIC 0 : if (findx > 0)
3429 heikki.linnakangas 17460 0 : appendPQExpBufferStr(query, " OR UPDATE");
17461 : else
3429 heikki.linnakangas 17462 LBC 0 : appendPQExpBufferStr(query, " UPDATE");
4888 tgl 17463 0 : findx++;
4930 peter_e 17464 ECB : }
4930 peter_e 17465 LBC 0 : if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
4930 peter_e 17466 ECB : {
4930 peter_e 17467 LBC 0 : if (findx > 0)
3429 heikki.linnakangas 17468 0 : appendPQExpBufferStr(query, " OR TRUNCATE");
17469 : else
3429 heikki.linnakangas 17470 UIC 0 : appendPQExpBufferStr(query, " TRUNCATE");
4888 tgl 17471 LBC 0 : findx++;
4930 peter_e 17472 ECB : }
4930 peter_e 17473 UIC 0 : appendPQExpBuffer(query, " ON %s\n",
1868 tgl 17474 LBC 0 : fmtQualifiedDumpable(tbinfo));
7639 tgl 17475 ECB :
4930 peter_e 17476 UIC 0 : if (tginfo->tgisconstraint)
7064 tgl 17477 ECB : {
4930 peter_e 17478 UIC 0 : if (OidIsValid(tginfo->tgconstrrelid))
4930 peter_e 17479 ECB : {
2370 tgl 17480 : /* regclass output is already quoted */
2370 tgl 17481 UIC 0 : appendPQExpBuffer(query, " FROM %s\n ",
2370 tgl 17482 LBC 0 : tginfo->tgconstrrelname);
17483 : }
4930 peter_e 17484 0 : if (!tginfo->tgdeferrable)
3429 heikki.linnakangas 17485 0 : appendPQExpBufferStr(query, "NOT ");
3429 heikki.linnakangas 17486 UIC 0 : appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
4930 peter_e 17487 0 : if (tginfo->tginitdeferred)
3429 heikki.linnakangas 17488 0 : appendPQExpBufferStr(query, "DEFERRED\n");
7639 tgl 17489 EUB : else
3429 heikki.linnakangas 17490 UIC 0 : appendPQExpBufferStr(query, "IMMEDIATE\n");
17491 : }
17492 :
4930 peter_e 17493 0 : if (TRIGGER_FOR_ROW(tginfo->tgtype))
3429 heikki.linnakangas 17494 0 : appendPQExpBufferStr(query, " FOR EACH ROW\n ");
17495 : else
17496 0 : appendPQExpBufferStr(query, " FOR EACH STATEMENT\n ");
7639 tgl 17497 ECB :
2370 17498 : /* regproc output is already sufficiently quoted */
1522 peter 17499 UIC 0 : appendPQExpBuffer(query, "EXECUTE FUNCTION %s(",
2370 tgl 17500 0 : tginfo->tgfname);
7522 bruce 17501 ECB :
4930 peter_e 17502 LBC 0 : tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
4930 peter_e 17503 ECB : &lentgargs);
4930 peter_e 17504 LBC 0 : p = tgargs;
4930 peter_e 17505 UIC 0 : for (findx = 0; findx < tginfo->tgnargs; findx++)
17506 : {
17507 : /* find the embedded null that terminates this trigger argument */
4790 bruce 17508 0 : size_t tlen = strlen(p);
7639 tgl 17509 ECB :
4930 peter_e 17510 UIC 0 : if (p + tlen >= tgargs + lentgargs)
4930 peter_e 17511 ECB : {
17512 : /* hm, not found before end of bytea value... */
366 tgl 17513 UIC 0 : pg_fatal("invalid argument string (%s) for trigger \"%s\" on table \"%s\"",
17514 : tginfo->tgargs,
366 tgl 17515 ECB : tginfo->dobj.name,
17516 : tbinfo->dobj.name);
4930 peter_e 17517 : }
17518 :
4930 peter_e 17519 LBC 0 : if (findx > 0)
3429 heikki.linnakangas 17520 0 : appendPQExpBufferStr(query, ", ");
4930 peter_e 17521 UIC 0 : appendStringLiteralAH(query, p, fout);
17522 0 : p += tlen + 1;
17523 : }
17524 0 : free(tgargs);
3429 heikki.linnakangas 17525 0 : appendPQExpBufferStr(query, ");\n");
17526 : }
17527 :
1124 alvherre 17528 ECB : /* Triggers can depend on extensions */
1124 alvherre 17529 GIC 488 : append_depends_on_extension(fout, query, &tginfo->dobj,
1124 alvherre 17530 ECB : "pg_catalog.pg_trigger", "TRIGGER",
1124 alvherre 17531 GIC 488 : trigidentity->data);
1124 alvherre 17532 ECB :
459 alvherre 17533 GIC 488 : if (tginfo->tgispartition)
632 alvherre 17534 ECB : {
459 alvherre 17535 CBC 121 : Assert(tbinfo->ispartition);
17536 :
632 alvherre 17537 ECB : /*
459 17538 : * Partition triggers only appear here because their 'tgenabled' flag
17539 : * differs from its parent's. The trigger is created already, so
632 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 : */
632 alvherre 17543 CBC 121 : resetPQExpBuffer(query);
632 alvherre 17544 GIC 121 : resetPQExpBuffer(delqry);
17545 121 : appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
17546 121 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
632 alvherre 17547 CBC 121 : fmtQualifiedDumpable(tbinfo));
632 alvherre 17548 GIC 121 : switch (tginfo->tgenabled)
632 alvherre 17549 ECB : {
632 alvherre 17550 GIC 42 : case 'f':
632 alvherre 17551 ECB : case 'D':
632 alvherre 17552 GIC 42 : appendPQExpBufferStr(query, "DISABLE");
632 alvherre 17553 CBC 42 : break;
632 alvherre 17554 LBC 0 : case 't':
17555 : case 'O':
632 alvherre 17556 UIC 0 : appendPQExpBufferStr(query, "ENABLE");
632 alvherre 17557 LBC 0 : break;
632 alvherre 17558 GIC 37 : case 'R':
632 alvherre 17559 CBC 37 : appendPQExpBufferStr(query, "ENABLE REPLICA");
632 alvherre 17560 GIC 37 : break;
632 alvherre 17561 CBC 42 : case 'A':
17562 42 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
632 alvherre 17563 GIC 42 : break;
632 alvherre 17564 ECB : }
632 alvherre 17565 GIC 121 : appendPQExpBuffer(query, " TRIGGER %s;\n",
632 alvherre 17566 CBC 121 : fmtId(tginfo->dobj.name));
632 alvherre 17567 ECB : }
632 alvherre 17568 GIC 367 : else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
6438 tgl 17569 ECB : {
1115 alvherre 17570 UIC 0 : appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
1115 alvherre 17571 LBC 0 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
1868 tgl 17572 UIC 0 : fmtQualifiedDumpable(tbinfo));
5865 JanWieck 17573 0 : switch (tginfo->tgenabled)
17574 : {
5865 JanWieck 17575 LBC 0 : case 'D':
17576 : case 'f':
3429 heikki.linnakangas 17577 0 : appendPQExpBufferStr(query, "DISABLE");
5865 JanWieck 17578 0 : break;
5865 JanWieck 17579 UBC 0 : case 'A':
3429 heikki.linnakangas 17580 UIC 0 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
5865 JanWieck 17581 UBC 0 : break;
17582 0 : case 'R':
3429 heikki.linnakangas 17583 UIC 0 : appendPQExpBufferStr(query, "ENABLE REPLICA");
5865 JanWieck 17584 0 : break;
17585 0 : default:
3429 heikki.linnakangas 17586 LBC 0 : appendPQExpBufferStr(query, "ENABLE");
5865 JanWieck 17587 UIC 0 : break;
17588 : }
17589 0 : appendPQExpBuffer(query, " TRIGGER %s;\n",
6438 tgl 17590 LBC 0 : fmtId(tginfo->dobj.name));
6438 tgl 17591 ECB : }
17592 :
1868 tgl 17593 CBC 488 : appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
4442 tgl 17594 GIC 488 : fmtId(tginfo->dobj.name));
4442 tgl 17595 ECB :
2600 peter_e 17596 CBC 488 : tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
2600 peter_e 17597 ECB :
2559 sfrost 17598 GIC 488 : if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17599 488 : ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
1528 alvherre 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 :
2559 sfrost 17608 488 : if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 17609 UIC 0 : dumpComment(fout, trigprefix->data, qtabname,
2559 sfrost 17610 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17611 0 : tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17612 :
2600 peter_e 17613 GIC 488 : free(tag);
7064 tgl 17614 488 : destroyPQExpBuffer(query);
17615 488 : destroyPQExpBuffer(delqry);
1868 17616 488 : destroyPQExpBuffer(trigprefix);
1124 alvherre 17617 CBC 488 : destroyPQExpBuffer(trigidentity);
1868 tgl 17618 GIC 488 : free(qtabname);
7064 tgl 17619 ECB : }
17620 :
3387 17621 : /*
3387 tgl 17622 EUB : * dumpEventTrigger
17623 : * write the declaration of one user-defined event trigger
17624 : */
3917 rhaas 17625 ECB : static void
788 peter 17626 GIC 38 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
3917 rhaas 17627 ECB : {
2643 tgl 17628 CBC 38 : DumpOptions *dopt = fout->dopt;
3917 rhaas 17629 ECB : PQExpBuffer query;
2087 tgl 17630 : PQExpBuffer delqry;
1868 17631 : char *qevtname;
3917 rhaas 17632 :
489 tgl 17633 : /* Do nothing in data-only dump */
489 tgl 17634 GIC 38 : if (dopt->dataOnly)
3387 tgl 17635 CBC 3 : return;
3387 tgl 17636 ECB :
3917 rhaas 17637 CBC 35 : query = createPQExpBuffer();
2087 tgl 17638 GIC 35 : delqry = createPQExpBuffer();
17639 :
1868 17640 35 : qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17641 :
3429 heikki.linnakangas 17642 35 : appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
1868 tgl 17643 35 : appendPQExpBufferStr(query, qevtname);
3429 heikki.linnakangas 17644 35 : appendPQExpBufferStr(query, " ON ");
3917 rhaas 17645 35 : appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17646 :
17647 35 : if (strcmp("", evtinfo->evttags) != 0)
17648 : {
3917 rhaas 17649 LBC 0 : appendPQExpBufferStr(query, "\n WHEN TAG IN (");
3917 rhaas 17650 UBC 0 : appendPQExpBufferStr(query, evtinfo->evttags);
2838 heikki.linnakangas 17651 0 : appendPQExpBufferChar(query, ')');
3917 rhaas 17652 EUB : }
17653 :
1522 peter 17654 CBC 35 : appendPQExpBufferStr(query, "\n EXECUTE FUNCTION ");
3917 rhaas 17655 GBC 35 : appendPQExpBufferStr(query, evtinfo->evtfname);
3429 heikki.linnakangas 17656 35 : appendPQExpBufferStr(query, "();\n");
3917 rhaas 17657 EUB :
3917 rhaas 17658 GIC 35 : if (evtinfo->evtenabled != 'O')
3917 rhaas 17659 ECB : {
3917 rhaas 17660 UIC 0 : appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
1868 tgl 17661 ECB : qevtname);
3917 rhaas 17662 LBC 0 : switch (evtinfo->evtenabled)
3917 rhaas 17663 ECB : {
3917 rhaas 17664 LBC 0 : case 'D':
3429 heikki.linnakangas 17665 UIC 0 : appendPQExpBufferStr(query, "DISABLE");
3917 rhaas 17666 0 : break;
17667 0 : case 'A':
3429 heikki.linnakangas 17668 0 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
3917 rhaas 17669 0 : break;
17670 0 : case 'R':
3429 heikki.linnakangas 17671 LBC 0 : appendPQExpBufferStr(query, "ENABLE REPLICA");
3917 rhaas 17672 UIC 0 : break;
3917 rhaas 17673 LBC 0 : default:
3429 heikki.linnakangas 17674 UIC 0 : appendPQExpBufferStr(query, "ENABLE");
3917 rhaas 17675 0 : break;
17676 : }
3429 heikki.linnakangas 17677 LBC 0 : appendPQExpBufferStr(query, ";\n");
17678 : }
2087 tgl 17679 ECB :
2087 tgl 17680 GIC 35 : appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
1868 tgl 17681 ECB : qevtname);
17682 :
1706 tgl 17683 CBC 35 : if (dopt->binary_upgrade)
1706 tgl 17684 GIC 1 : binary_upgrade_extension_member(query, &evtinfo->dobj,
1706 tgl 17685 ECB : "EVENT TRIGGER", qevtname, NULL);
1706 tgl 17686 EUB :
2559 sfrost 17687 GIC 35 : if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17688 35 : ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
1528 alvherre 17689 35 : ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
17690 : .owner = evtinfo->evtowner,
1528 alvherre 17691 ECB : .description = "EVENT TRIGGER",
17692 : .section = SECTION_POST_DATA,
17693 : .createStmt = query->data,
17694 : .dropStmt = delqry->data));
3917 rhaas 17695 :
2559 sfrost 17696 CBC 35 : if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 17697 LBC 0 : dumpComment(fout, "EVENT TRIGGER", qevtname,
2559 sfrost 17698 UIC 0 : NULL, evtinfo->evtowner,
17699 0 : evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
3917 rhaas 17700 ECB :
3917 rhaas 17701 CBC 35 : destroyPQExpBuffer(query);
2087 tgl 17702 35 : destroyPQExpBuffer(delqry);
1868 tgl 17703 GIC 35 : free(qevtname);
17704 : }
17705 :
17706 : /*
17707 : * dumpRule
17708 : * Dump a rule
17709 : */
17710 : static void
788 peter 17711 CBC 821 : dumpRule(Archive *fout, const RuleInfo *rinfo)
17712 : {
2643 tgl 17713 821 : DumpOptions *dopt = fout->dopt;
7064 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;
7064 tgl 17721 ECB : PGresult *res;
17722 : char *tag;
7639 17723 :
489 17724 : /* Do nothing in data-only dump */
489 tgl 17725 GIC 821 : if (dopt->dataOnly)
7064 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 : */
6690 17732 794 : if (!rinfo->separate)
7064 17733 589 : return;
17734 :
17735 : /*
17736 : * If it's an ON SELECT rule, we want to print it as a view definition,
2334 tgl 17737 ECB : * instead of a rule.
17738 : */
2334 tgl 17739 GIC 205 : is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
2334 tgl 17740 ECB :
7064 tgl 17741 CBC 205 : query = createPQExpBuffer();
17742 205 : cmd = createPQExpBuffer();
17743 205 : delcmd = createPQExpBuffer();
1868 tgl 17744 GIC 205 : ruleprefix = createPQExpBuffer();
1868 tgl 17745 ECB :
1868 tgl 17746 GIC 205 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
7639 tgl 17747 ECB :
2334 tgl 17748 CBC 205 : if (is_view)
17749 : {
2334 tgl 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 : */
2334 tgl 17756 GIC 10 : appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
1868 17757 10 : fmtQualifiedDumpable(tbinfo));
2334 tgl 17758 GBC 10 : if (nonemptyReloptions(tbinfo->reloptions))
17759 : {
2334 tgl 17760 UBC 0 : appendPQExpBufferStr(cmd, " WITH (");
17761 0 : appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
2334 tgl 17762 UIC 0 : appendPQExpBufferChar(cmd, ')');
17763 : }
2334 tgl 17764 GIC 10 : result = createViewAsClause(fout, tbinfo);
2334 tgl 17765 GBC 10 : appendPQExpBuffer(cmd, " AS\n%s", result->data);
17766 10 : destroyPQExpBuffer(result);
2334 tgl 17767 GIC 10 : if (tbinfo->checkoption != NULL)
2334 tgl 17768 UBC 0 : appendPQExpBuffer(cmd, "\n WITH %s CHECK OPTION",
17769 : tbinfo->checkoption);
2334 tgl 17770 GIC 10 : appendPQExpBufferStr(cmd, ";\n");
9320 vadim4o 17771 EUB : }
2334 tgl 17772 : else
17773 : {
17774 : /* In the rule case, just print pg_get_ruledef's result verbatim */
2334 tgl 17775 GBC 195 : appendPQExpBuffer(query,
2118 tgl 17776 EUB : "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
2334 tgl 17777 GIC 195 : rinfo->dobj.catId.oid);
2334 tgl 17778 EUB :
2334 tgl 17779 GIC 195 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2334 tgl 17780 EUB :
2334 tgl 17781 GBC 195 : if (PQntuples(res) != 1)
366 tgl 17782 UIC 0 : pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
366 tgl 17783 EUB : rinfo->dobj.name, tbinfo->dobj.name);
7639 17784 :
2334 tgl 17785 GIC 195 : printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
2334 tgl 17786 EUB :
2334 tgl 17787 GIC 195 : PQclear(res);
2334 tgl 17788 EUB : }
7064 17789 :
17790 : /*
5624 bruce 17791 : * Add the command to alter the rules replication firing semantics if it
17792 : * differs from the default.
17793 : */
5865 JanWieck 17794 GBC 205 : if (rinfo->ev_enabled != 'O')
17795 : {
1868 tgl 17796 UBC 0 : appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
5865 JanWieck 17797 0 : switch (rinfo->ev_enabled)
17798 : {
17799 0 : case 'A':
17800 0 : appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
5624 bruce 17801 UIC 0 : fmtId(rinfo->dobj.name));
5865 JanWieck 17802 UBC 0 : break;
5865 JanWieck 17803 UIC 0 : case 'R':
5865 JanWieck 17804 UBC 0 : appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
5624 bruce 17805 0 : fmtId(rinfo->dobj.name));
5865 JanWieck 17806 UIC 0 : break;
5865 JanWieck 17807 UBC 0 : case 'D':
17808 0 : appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
5624 bruce 17809 UIC 0 : fmtId(rinfo->dobj.name));
5865 JanWieck 17810 UBC 0 : break;
5865 JanWieck 17811 EUB : }
17812 : }
17813 :
2334 tgl 17814 GIC 205 : if (is_view)
3883 tgl 17815 EUB : {
17816 : /*
17817 : * We can't DROP a view's ON SELECT rule. Instead, use CREATE OR
2334 17818 : * REPLACE VIEW to replace the rule with something with minimal
17819 : * dependencies.
17820 : */
17821 : PQExpBuffer result;
17822 :
1868 tgl 17823 GBC 10 : appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17824 10 : fmtQualifiedDumpable(tbinfo));
2334 17825 10 : result = createDummyViewAsClause(fout, tbinfo);
2334 tgl 17826 GIC 10 : appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
2334 tgl 17827 GBC 10 : destroyPQExpBuffer(result);
17828 : }
17829 : else
2334 tgl 17830 EUB : {
2334 tgl 17831 GBC 195 : appendPQExpBuffer(delcmd, "DROP RULE %s ",
2334 tgl 17832 GIC 195 : fmtId(rinfo->dobj.name));
1868 tgl 17833 GBC 195 : appendPQExpBuffer(delcmd, "ON %s;\n",
1868 tgl 17834 GIC 195 : fmtQualifiedDumpable(tbinfo));
17835 : }
7064 tgl 17836 EUB :
1868 tgl 17837 GBC 205 : appendPQExpBuffer(ruleprefix, "RULE %s ON",
4442 tgl 17838 GIC 205 : fmtId(rinfo->dobj.name));
4442 tgl 17839 EUB :
2600 peter_e 17840 GIC 205 : tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
2600 peter_e 17841 EUB :
2559 sfrost 17842 GBC 205 : if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2559 sfrost 17843 GIC 205 : ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
1528 alvherre 17844 205 : ARCHIVE_OPTS(.tag = tag,
1528 alvherre 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 */
2559 sfrost 17853 GIC 205 : if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1868 tgl 17854 UIC 0 : dumpComment(fout, ruleprefix->data, qtabname,
2559 sfrost 17855 0 : tbinfo->dobj.namespace->dobj.name,
2559 sfrost 17856 EUB : tbinfo->rolname,
2559 sfrost 17857 UBC 0 : rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
7064 tgl 17858 EUB :
2600 peter_e 17859 GBC 205 : free(tag);
7639 tgl 17860 GIC 205 : destroyPQExpBuffer(query);
7064 tgl 17861 GBC 205 : destroyPQExpBuffer(cmd);
17862 205 : destroyPQExpBuffer(delcmd);
1868 tgl 17863 GIC 205 : destroyPQExpBuffer(ruleprefix);
17864 205 : free(qtabname);
17865 : }
9030 bruce 17866 ECB :
17867 : /*
4442 tgl 17868 : * getExtensionMembership --- obtain extension membership data
17869 : *
2643 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
2643 tgl 17878 GIC 119 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17879 : int numExtensions)
4442 tgl 17880 ECB : {
17881 : PQExpBuffer query;
17882 : PGresult *res;
17883 : int ntups,
17884 : i;
17885 : int i_classid,
17886 : i_objid,
2643 17887 : i_refobjid;
17888 : ExtensionInfo *ext;
4442 17889 :
17890 : /* Nothing to do if no extensions */
4442 tgl 17891 GBC 119 : if (numExtensions == 0)
4442 tgl 17892 UIC 0 : return;
4442 tgl 17893 EUB :
4442 tgl 17894 GBC 119 : query = createPQExpBuffer();
4442 tgl 17895 ECB :
17896 : /* refclassid constraint is redundant but may speed the search */
3429 heikki.linnakangas 17897 CBC 119 : appendPQExpBufferStr(query, "SELECT "
2643 tgl 17898 ECB : "classid, objid, refobjid "
3429 heikki.linnakangas 17899 : "FROM pg_depend "
17900 : "WHERE refclassid = 'pg_extension'::regclass "
17901 : "AND deptype = 'e' "
2643 tgl 17902 : "ORDER BY 3");
4442 17903 :
4079 rhaas 17904 GIC 119 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4442 tgl 17905 ECB :
4442 tgl 17906 GIC 119 : ntups = PQntuples(res);
4442 tgl 17907 EUB :
4442 tgl 17908 GBC 119 : i_classid = PQfnumber(res, "classid");
17909 119 : i_objid = PQfnumber(res, "objid");
17910 119 : i_refobjid = PQfnumber(res, "refobjid");
17911 :
4442 tgl 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 : */
2643 tgl 17917 GBC 119 : ext = NULL;
4442 tgl 17918 EUB :
4442 tgl 17919 GBC 925 : for (i = 0; i < ntups; i++)
4442 tgl 17920 EUB : {
17921 : CatalogId objId;
2643 17922 : Oid extId;
4442 17923 :
4442 tgl 17924 GBC 806 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
4442 tgl 17925 GIC 806 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
2643 tgl 17926 GBC 806 : extId = atooid(PQgetvalue(res, i, i_refobjid));
4442 tgl 17927 EUB :
2643 tgl 17928 GIC 806 : if (ext == NULL ||
17929 687 : ext->dobj.catId.oid != extId)
2643 tgl 17930 CBC 141 : ext = findExtensionByOid(extId);
4442 tgl 17931 ECB :
2643 tgl 17932 GIC 806 : if (ext == NULL)
4442 tgl 17933 ECB : {
17934 : /* shouldn't happen */
1469 peter 17935 LBC 0 : pg_log_warning("could not find referenced extension %u", extId);
4442 tgl 17936 0 : continue;
4442 tgl 17937 ECB : }
17938 :
534 tgl 17939 GIC 806 : recordExtensionMembership(objId, ext);
17940 : }
17941 :
2643 17942 119 : PQclear(res);
17943 :
17944 119 : destroyPQExpBuffer(query);
2643 tgl 17945 ECB : }
4442 tgl 17946 EUB :
2643 17947 : /*
17948 : * processExtensionTables --- deal with extension configuration tables
17949 : *
2643 tgl 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
2643 tgl 17971 CBC 118 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
2643 tgl 17972 ECB : int numExtensions)
17973 : {
2643 tgl 17974 CBC 118 : DumpOptions *dopt = fout->dopt;
2643 tgl 17975 ECB : PQExpBuffer query;
17976 : PGresult *res;
17977 : int ntups,
17978 : i;
17979 : int i_conrelid,
17980 : i_confrelid;
4442 17981 :
2643 17982 : /* Nothing to do if no extensions */
2643 tgl 17983 GIC 118 : if (numExtensions == 0)
2643 tgl 17984 LBC 0 : return;
17985 :
4442 tgl 17986 EUB : /*
2643 17987 : * Identify extension configuration tables and create TableDataInfo
4442 17988 : * objects for them, ensuring their data will be dumped even though the
17989 : * tables themselves won't be.
17990 : *
4382 bruce 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
724 michael 17995 : * list of extensions to be included, none of its data is dumped.
17996 : */
4442 tgl 17997 GBC 258 : for (i = 0; i < numExtensions; i++)
17998 : {
4076 17999 140 : ExtensionInfo *curext = &(extinfo[i]);
4076 tgl 18000 GIC 140 : char *extconfig = curext->extconfig;
4076 tgl 18001 GBC 140 : char *extcondition = curext->extcondition;
4382 bruce 18002 140 : char **extconfigarray = NULL;
18003 140 : char **extconditionarray = NULL;
871 michael 18004 140 : int nconfigitems = 0;
18005 140 : int nconditionitems = 0;
4442 tgl 18006 EUB :
724 michael 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 : */
724 michael 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 :
871 michael 18016 GIC 136 : if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
4442 tgl 18017 ECB : {
18018 : int j;
18019 :
871 michael 18020 CBC 19 : if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
366 tgl 18021 LBC 0 : pg_fatal("could not parse %s array", "extconfig");
871 michael 18022 GIC 19 : if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
366 tgl 18023 UIC 0 : pg_fatal("could not parse %s array", "extcondition");
871 michael 18024 CBC 19 : if (nconfigitems != nconditionitems)
366 tgl 18025 LBC 0 : pg_fatal("mismatched number of configurations and conditions for extension");
871 michael 18026 ECB :
4442 tgl 18027 GIC 57 : for (j = 0; j < nconfigitems; j++)
18028 : {
18029 : TableInfo *configtbl;
3635 mail 18030 38 : Oid configtbloid = atooid(extconfigarray[j]);
2559 sfrost 18031 38 : bool dumpobj =
18032 38 : curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
4442 tgl 18033 ECB :
3635 mail 18034 GBC 38 : configtbl = findTableByOid(configtbloid);
4078 tgl 18035 38 : if (configtbl == NULL)
4078 tgl 18036 UBC 0 : continue;
18037 :
4078 tgl 18038 ECB : /*
3635 mail 18039 : * Tables of not-to-be-dumped extensions shouldn't be dumped
18040 : * unless the table or its schema is explicitly included
18041 : */
2559 sfrost 18042 GIC 38 : if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
18043 : {
18044 : /* check table explicitly requested */
3635 mail 18045 2 : if (table_include_oids.head != NULL &&
3635 mail 18046 UIC 0 : simple_oid_list_member(&table_include_oids,
18047 : configtbloid))
3635 mail 18048 LBC 0 : dumpobj = true;
18049 :
3635 mail 18050 ECB : /* check table's schema explicitly requested */
2559 sfrost 18051 CBC 2 : if (configtbl->dobj.namespace->dobj.dump &
18052 : DUMP_COMPONENT_DATA)
3635 mail 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 :
3635 mail 18062 ECB : /* check schema excluded by an exclusion switch */
3635 mail 18063 CBC 38 : if (simple_oid_list_member(&schema_exclude_oids,
2118 tgl 18064 GIC 38 : configtbl->dobj.namespace->dobj.catId.oid))
3635 mail 18065 UIC 0 : dumpobj = false;
18066 :
3635 mail 18067 GIC 38 : if (dumpobj)
18068 : {
1601 andres 18069 CBC 37 : makeTableDataInfo(dopt, configtbl);
3635 mail 18070 37 : if (configtbl->dataObj != NULL)
18071 : {
3635 mail 18072 GIC 37 : if (strlen(extconditionarray[j]) > 0)
3635 mail 18073 UIC 0 : configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
18074 : }
18075 : }
4442 tgl 18076 ECB : }
18077 : }
4442 tgl 18078 CBC 136 : if (extconfigarray)
18079 19 : free(extconfigarray);
18080 136 : if (extconditionarray)
18081 19 : free(extconditionarray);
18082 : }
4442 tgl 18083 ECB :
18084 : /*
1329 michael 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 :
2643 tgl 18093 CBC 118 : query = createPQExpBuffer();
2643 tgl 18094 ECB :
2960 sfrost 18095 CBC 118 : printfPQExpBuffer(query,
18096 : "SELECT conrelid, confrelid "
2878 bruce 18097 EUB : "FROM pg_constraint "
18098 : "JOIN pg_depend ON (objid = confrelid) "
18099 : "WHERE contype = 'f' "
18100 : "AND refclassid = 'pg_extension'::regclass "
2878 bruce 18101 ECB : "AND classid = 'pg_class'::regclass;");
2960 sfrost 18102 :
2960 sfrost 18103 CBC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18104 118 : ntups = PQntuples(res);
2960 sfrost 18105 EUB :
2960 sfrost 18106 GIC 118 : i_conrelid = PQfnumber(res, "conrelid");
2960 sfrost 18107 CBC 118 : i_confrelid = PQfnumber(res, "confrelid");
18108 :
18109 : /* Now get the dependencies and register them */
2960 sfrost 18110 GIC 118 : for (i = 0; i < ntups; i++)
18111 : {
2878 bruce 18112 ECB : Oid conrelid,
18113 : confrelid;
18114 : TableInfo *reftable,
18115 : *contable;
2960 sfrost 18116 :
2960 sfrost 18117 UIC 0 : conrelid = atooid(PQgetvalue(res, i, i_conrelid));
2960 sfrost 18118 LBC 0 : confrelid = atooid(PQgetvalue(res, i, i_confrelid));
2960 sfrost 18119 UBC 0 : contable = findTableByOid(conrelid);
2960 sfrost 18120 UIC 0 : reftable = findTableByOid(confrelid);
18121 :
2960 sfrost 18122 LBC 0 : if (reftable == NULL ||
2960 sfrost 18123 UIC 0 : reftable->dataObj == NULL ||
2960 sfrost 18124 LBC 0 : contable == NULL ||
2960 sfrost 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.
2960 sfrost 18131 ECB : */
2960 sfrost 18132 UIC 0 : addObjectDependency(&contable->dataObj->dobj,
2960 sfrost 18133 UBC 0 : reftable->dataObj->dobj.dumpId);
2960 sfrost 18134 EUB : }
2828 tgl 18135 GIC 118 : PQclear(res);
4442 tgl 18136 GBC 118 : destroyPQExpBuffer(query);
4442 tgl 18137 EUB : }
18138 :
7064 18139 : /*
18140 : * getDependencies --- obtain available dependency data
18141 : */
8951 bruce 18142 : static void
4080 rhaas 18143 GBC 118 : getDependencies(Archive *fout)
8951 bruce 18144 EUB : {
7064 tgl 18145 : PQExpBuffer query;
8720 bruce 18146 : PGresult *res;
7064 tgl 18147 : int ntups,
18148 : i;
18149 : int i_classid,
18150 : i_objid,
7064 tgl 18151 ECB : i_refclassid,
18152 : i_refobjid,
18153 : i_deptype;
18154 : DumpableObject *dobj,
18155 : *refdobj;
18156 :
1469 peter 18157 GIC 118 : pg_log_info("reading dependency data");
18158 :
7064 tgl 18159 118 : query = createPQExpBuffer();
7064 tgl 18160 ECB :
4442 18161 : /*
1348 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.
4442 18168 : */
3429 heikki.linnakangas 18169 CBC 118 : appendPQExpBufferStr(query, "SELECT "
3429 heikki.linnakangas 18170 ECB : "classid, objid, refclassid, refobjid, deptype "
18171 : "FROM pg_depend "
18172 : "WHERE deptype != 'p' AND deptype != 'e'\n");
18173 :
1348 tgl 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 : */
481 tgl 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");
481 tgl 18190 ECB :
481 tgl 18191 EUB : /* Likewise for pg_amproc entries */
481 tgl 18192 GBC 118 : appendPQExpBufferStr(query, "UNION ALL\n"
18193 : "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
481 tgl 18194 EUB : "FROM pg_depend d, pg_amproc p "
18195 : "WHERE deptype NOT IN ('p', 'e', 'i') AND "
481 tgl 18196 ECB : "classid = 'pg_amproc'::regclass AND objid = p.oid "
18197 : "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
1348 18198 :
18199 : /* Sort the output for efficiency below */
1348 tgl 18200 CBC 118 : appendPQExpBufferStr(query, "ORDER BY 1,2");
7064 tgl 18201 ECB :
4079 rhaas 18202 GIC 118 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18203 :
7064 tgl 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
6385 bruce 18215 ECB : * on searches.
18216 : */
7064 tgl 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));
7064 tgl 18228 CBC 253881 : refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
7064 tgl 18229 GBC 253881 : deptype = *(PQgetvalue(res, i, i_deptype));
18230 :
7064 tgl 18231 CBC 253881 : if (dobj == NULL ||
7064 tgl 18232 GIC 239304 : dobj->catId.tableoid != objId.tableoid ||
18233 237783 : dobj->catId.oid != objId.oid)
7064 tgl 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 : */
7064 tgl 18240 GIC 253881 : if (dobj == NULL)
8951 bruce 18241 ECB : {
18242 : #ifdef NOT_USED
1469 peter 18243 : pg_log_warning("no referencing object %u %u",
18244 : objId.tableoid, objId.oid);
7064 tgl 18245 : #endif
7064 tgl 18246 CBC 15043 : continue;
8951 bruce 18247 ECB : }
18248 :
7064 tgl 18249 GIC 239415 : refdobj = findObjectByCatalogId(refobjId);
18250 :
18251 239415 : if (refdobj == NULL)
18252 : {
18253 : #ifdef NOT_USED
1469 peter 18254 ECB : pg_log_warning("no referenced object %u %u",
18255 : refobjId.tableoid, refobjId.oid);
7064 tgl 18256 : #endif
7064 tgl 18257 GIC 577 : continue;
18258 : }
18259 :
18260 : /*
1124 alvherre 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 : */
1124 alvherre 18266 CBC 238838 : if (deptype == 'x')
18267 40 : dobj->depends_on_ext = true;
18268 :
6662 tgl 18269 ECB : /*
18270 : * Ordinarily, table rowtypes have implicit dependencies on their
18271 : * tables. However, for a composite type the implicit dependency goes
6385 bruce 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 : */
6662 tgl 18276 CBC 238838 : if (deptype == 'i' &&
6662 tgl 18277 GIC 65124 : dobj->objType == DO_TABLE &&
18278 786 : refdobj->objType == DO_TYPE)
6662 tgl 18279 CBC 137 : addObjectDependency(refdobj, dobj->dumpId);
18280 : else
6385 bruce 18281 ECB : /* normal case */
6662 tgl 18282 GIC 238701 : addObjectDependency(dobj, refdobj->dumpId);
18283 : }
18284 :
7064 18285 118 : PQclear(res);
18286 :
7919 18287 118 : destroyPQExpBuffer(query);
8951 bruce 18288 118 : }
18289 :
18290 :
18291 : /*
18292 : * createBoundaryObjects - create dummy DumpableObjects to represent
18293 : * dump section boundaries.
18294 : */
18295 : static DumpableObject *
3940 tgl 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;
3940 tgl 18308 CBC 118 : dobjs[1].catId = nilCatalogId;
3940 tgl 18309 GIC 118 : AssignDumpId(dobjs + 1);
18310 118 : dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
3940 tgl 18311 ECB :
3940 tgl 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
3940 tgl 18320 CBC 118 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
3940 tgl 18321 EUB : DumpableObject *boundaryObjs)
18322 : {
3940 tgl 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!
3940 tgl 18334 ECB : */
3940 tgl 18335 GIC 510020 : switch (dobj->objType)
3940 tgl 18336 ECB : {
3940 tgl 18337 CBC 482225 : case DO_NAMESPACE:
3940 tgl 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:
3940 tgl 18358 EUB : case DO_TSCONFIG:
3940 tgl 18359 ECB : case DO_FDW:
3940 tgl 18360 EUB : case DO_FOREIGN_SERVER:
2905 peter_e 18361 ECB : case DO_TRANSFORM:
18362 : case DO_LARGE_OBJECT:
18363 : /* Pre-data objects: must come before the pre-data boundary */
3940 tgl 18364 CBC 482225 : addObjectDependency(preDataBound, dobj->dumpId);
3940 tgl 18365 GIC 482225 : break;
18366 3475 : case DO_TABLE_DATA:
2420 peter_e 18367 ECB : case DO_SEQUENCE_SET:
18368 : case DO_LARGE_OBJECT_DATA:
3940 tgl 18369 : /* Data objects: must come between the boundaries */
3940 tgl 18370 GIC 3475 : addObjectDependency(dobj, preDataBound->dumpId);
3940 tgl 18371 CBC 3475 : addObjectDependency(postDataBound, dobj->dumpId);
18372 3475 : break;
3940 tgl 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:
3940 tgl 18379 ECB : case DO_DEFAULT_ACL:
18380 : case DO_POLICY:
18381 : case DO_PUBLICATION:
2271 peter_e 18382 : case DO_PUBLICATION_REL:
516 akapila 18383 EUB : case DO_PUBLICATION_TABLE_IN_SCHEMA:
18384 : case DO_SUBSCRIPTION:
3940 tgl 18385 : /* Post-data objects: must come after the post-data boundary */
3940 tgl 18386 GIC 4629 : addObjectDependency(dobj, postDataBound->dumpId);
18387 4629 : break;
3940 tgl 18388 CBC 17749 : case DO_RULE:
18389 : /* Rules are post-data, but only if dumped separately */
18390 17749 : if (((RuleInfo *) dobj)->separate)
3940 tgl 18391 GIC 431 : addObjectDependency(dobj, postDataBound->dumpId);
18392 17749 : break;
18393 1706 : case DO_CONSTRAINT:
3940 tgl 18394 ECB : case DO_FK_CONSTRAINT:
18395 : /* Constraints are post-data, but only if dumped separately */
3940 tgl 18396 GIC 1706 : if (((ConstraintInfo *) dobj)->separate)
3940 tgl 18397 CBC 1080 : addObjectDependency(dobj, postDataBound->dumpId);
3940 tgl 18398 GIC 1706 : break;
18399 118 : case DO_PRE_DATA_BOUNDARY:
3940 tgl 18400 ECB : /* nothing to do */
3940 tgl 18401 CBC 118 : break;
3940 tgl 18402 GBC 118 : case DO_POST_DATA_BOUNDARY:
18403 : /* must come after the pre-data boundary */
3940 tgl 18404 CBC 118 : addObjectDependency(dobj, preDataBound->dumpId);
3940 tgl 18405 GIC 118 : break;
3940 tgl 18406 ECB : }
18407 : }
3940 tgl 18408 GIC 118 : }
3940 tgl 18409 ECB :
3940 tgl 18410 EUB :
18411 : /*
18412 : * BuildArchiveDependencies - create dependency data for archive TOC entries
18413 : *
18414 : * The raw dependency data obtained by getDependencies() is not terribly
3940 tgl 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
3940 tgl 18435 GIC 25 : BuildArchiveDependencies(Archive *fout)
18436 : {
18437 25 : ArchiveHandle *AH = (ArchiveHandle *) fout;
18438 : TocEntry *te;
18439 :
3940 tgl 18440 ECB : /* Scan all TOC entries in the archive */
3940 tgl 18441 CBC 4956 : for (te = AH->toc->next; te != AH->toc; te = te->next)
18442 : {
3940 tgl 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 */
3940 tgl 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;
3940 tgl 18454 EUB : /* Otherwise, look up the item's original DumpableObject, if any */
3940 tgl 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;
3940 tgl 18461 EUB : /* Set up work array */
3940 tgl 18462 GBC 3355 : allocDeps = 64;
18463 3355 : dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
3940 tgl 18464 GIC 3355 : nDeps = 0;
18465 : /* Recursively find all dumpable dependencies */
18466 3355 : findDumpableDependencies(AH, dobj,
18467 : &dependencies, &nDeps, &allocDeps);
18468 : /* And save 'em ... */
3940 tgl 18469 GBC 3355 : if (nDeps > 0)
3940 tgl 18470 EUB : {
3940 tgl 18471 GIC 2586 : dependencies = (DumpId *) pg_realloc(dependencies,
3940 tgl 18472 ECB : nDeps * sizeof(DumpId));
3940 tgl 18473 CBC 2586 : te->dependencies = dependencies;
3940 tgl 18474 GIC 2586 : te->nDeps = nDeps;
18475 : }
18476 : else
18477 769 : free(dependencies);
18478 : }
18479 25 : }
3940 tgl 18480 ECB :
18481 : /* Recursive search subroutine for BuildArchiveDependencies */
18482 : static void
788 peter 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 : */
3940 tgl 18492 8271 : if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18493 8261 : dobj->objType == DO_POST_DATA_BOUNDARY)
3940 tgl 18494 CBC 1525 : return;
18495 :
18496 17284 : for (i = 0; i < dobj->nDeps; i++)
18497 : {
3940 tgl 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 : {
3940 tgl 18505 UIC 0 : *allocDeps *= 2;
3940 tgl 18506 LBC 0 : *dependencies = (DumpId *) pg_realloc(*dependencies,
2118 tgl 18507 UIC 0 : *allocDeps * sizeof(DumpId));
18508 : }
3940 tgl 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 :
3940 tgl 18521 CBC 4916 : if (otherdobj)
3940 tgl 18522 GIC 4916 : findDumpableDependencies(AH, otherdobj,
18523 : dependencies, nDeps, allocDeps);
18524 : }
18525 : }
18526 : }
18527 :
18528 :
7639 tgl 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 *
4080 rhaas 18539 CBC 2294 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18540 : {
586 tgl 18541 ECB : TypeInfo *typeInfo;
18542 : char *result;
7639 18543 : PQExpBuffer query;
18544 : PGresult *res;
18545 :
7064 tgl 18546 CBC 2294 : if (oid == 0)
7639 tgl 18547 ECB : {
1130 tgl 18548 UIC 0 : if ((opts & zeroAsStar) != 0)
578 18549 0 : return "*";
7639 18550 0 : else if ((opts & zeroAsNone) != 0)
578 18551 0 : return "NONE";
18552 : }
18553 :
586 tgl 18554 ECB : /* see if we have the result cached in the type's TypeInfo record */
586 tgl 18555 GIC 2294 : typeInfo = findTypeByOid(oid);
586 tgl 18556 CBC 2294 : if (typeInfo && typeInfo->ftypname)
578 tgl 18557 GIC 1818 : return typeInfo->ftypname;
18558 :
7639 18559 476 : query = createPQExpBuffer();
2370 18560 476 : appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18561 : oid);
7639 tgl 18562 ECB :
4070 rhaas 18563 CBC 476 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
7639 tgl 18564 ECB :
2370 18565 : /* result of format_type is already quoted */
2370 tgl 18566 CBC 476 : result = pg_strdup(PQgetvalue(res, 0, 0));
18567 :
7639 18568 476 : PQclear(res);
18569 476 : destroyPQExpBuffer(query);
7639 tgl 18570 ECB :
578 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 : */
586 tgl 18577 CBC 476 : if (typeInfo)
578 tgl 18578 GIC 476 : typeInfo->ftypname = result;
18579 :
7639 18580 476 : return result;
18581 : }
18582 :
7570 bruce 18583 ECB : /*
18584 : * Return a column list clause for the given relation.
18585 : *
7423 tgl 18586 : * Special case: if there are no undropped columns in the relation, return
18587 : * "", not an invalid "()" column list.
7570 bruce 18588 : */
18589 : static const char *
3668 andrew 18590 GIC 6020 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18591 : {
7570 bruce 18592 6020 : int numatts = ti->numatts;
7522 18593 6020 : char **attnames = ti->attnames;
7522 bruce 18594 CBC 6020 : bool *attisdropped = ti->attisdropped;
1471 peter 18595 GIC 6020 : char *attgenerated = ti->attgenerated;
18596 : bool needComma;
18597 : int i;
18598 :
3429 heikki.linnakangas 18599 6020 : appendPQExpBufferChar(buffer, '(');
7555 tgl 18600 6020 : needComma = false;
7570 bruce 18601 30584 : for (i = 0; i < numatts; i++)
18602 : {
7555 tgl 18603 CBC 24564 : if (attisdropped[i])
18604 564 : continue;
1471 peter 18605 GIC 24000 : if (attgenerated[i])
18606 620 : continue;
7555 tgl 18607 23380 : if (needComma)
3429 heikki.linnakangas 18608 17594 : appendPQExpBufferStr(buffer, ", ");
18609 23380 : appendPQExpBufferStr(buffer, fmtId(attnames[i]));
7555 tgl 18610 23380 : needComma = true;
18611 : }
18612 :
7423 tgl 18613 CBC 6020 : if (!needComma)
7289 18614 234 : return ""; /* no undropped columns */
7423 tgl 18615 ECB :
3429 heikki.linnakangas 18616 CBC 5786 : appendPQExpBufferChar(buffer, ')');
3668 andrew 18617 GIC 5786 : return buffer->data;
18618 : }
4070 rhaas 18619 ECB :
18620 : /*
18621 : * Check if a reloptions array is nonempty.
2654 tgl 18622 : */
18623 : static bool
2654 tgl 18624 CBC 10120 : nonemptyReloptions(const char *reloptions)
2654 tgl 18625 ECB : {
18626 : /* Don't want to print it if it's just "{}" */
2654 tgl 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 : *
2654 tgl 18633 ECB : * "prefix" is prepended to the option names; typically it's "" or "toast.".
18634 : */
18635 : static void
2529 dean.a.rasheed 18636 GIC 207 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
2529 dean.a.rasheed 18637 ECB : const char *prefix, Archive *fout)
18638 : {
18639 : bool res;
2654 tgl 18640 :
2529 dean.a.rasheed 18641 CBC 207 : res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18642 207 : fout->std_strings);
2529 dean.a.rasheed 18643 GIC 207 : if (!res)
526 peter 18644 LBC 0 : pg_log_warning("could not parse %s array", "reloptions");
2654 tgl 18645 CBC 207 : }
|