Age Owner Branch data 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-2024, 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 "filter.h"
64 : : #include "getopt_long.h"
65 : : #include "libpq/libpq-fs.h"
66 : : #include "parallel.h"
67 : : #include "pg_backup_db.h"
68 : : #include "pg_backup_utils.h"
69 : : #include "pg_dump.h"
70 : : #include "storage/block.h"
71 : :
72 : : typedef struct
73 : : {
74 : : Oid roleoid; /* role's OID */
75 : : const char *rolename; /* role's name */
76 : : } RoleNameItem;
77 : :
78 : : typedef struct
79 : : {
80 : : const char *descr; /* comment for an object */
81 : : Oid classoid; /* object class (catalog OID) */
82 : : Oid objoid; /* object OID */
83 : : int objsubid; /* subobject (table column #) */
84 : : } CommentItem;
85 : :
86 : : typedef struct
87 : : {
88 : : const char *provider; /* label provider of this security label */
89 : : const char *label; /* security label for an object */
90 : : Oid classoid; /* object class (catalog OID) */
91 : : Oid objoid; /* object OID */
92 : : int objsubid; /* subobject (table column #) */
93 : : } SecLabelItem;
94 : :
95 : : typedef enum OidOptions
96 : : {
97 : : zeroIsError = 1,
98 : : zeroAsStar = 2,
99 : : zeroAsNone = 4,
100 : : } OidOptions;
101 : :
102 : : /* global decls */
103 : : static bool dosync = true; /* Issue fsync() to make dump durable on disk. */
104 : :
105 : : static Oid g_last_builtin_oid; /* value of the last builtin oid */
106 : :
107 : : /* The specified names/patterns should to match at least one entity */
108 : : static int strict_names = 0;
109 : :
110 : : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
111 : :
112 : : /*
113 : : * Object inclusion/exclusion lists
114 : : *
115 : : * The string lists record the patterns given by command-line switches,
116 : : * which we then convert to lists of OIDs of matching objects.
117 : : */
118 : : static SimpleStringList schema_include_patterns = {NULL, NULL};
119 : : static SimpleOidList schema_include_oids = {NULL, NULL};
120 : : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
121 : : static SimpleOidList schema_exclude_oids = {NULL, NULL};
122 : :
123 : : static SimpleStringList table_include_patterns = {NULL, NULL};
124 : : static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
125 : : static SimpleOidList table_include_oids = {NULL, NULL};
126 : : static SimpleStringList table_exclude_patterns = {NULL, NULL};
127 : : static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
128 : : static SimpleOidList table_exclude_oids = {NULL, NULL};
129 : : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
130 : : static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
131 : : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
132 : :
133 : : static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
134 : : static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
135 : :
136 : : static SimpleStringList extension_include_patterns = {NULL, NULL};
137 : : static SimpleOidList extension_include_oids = {NULL, NULL};
138 : :
139 : : static SimpleStringList extension_exclude_patterns = {NULL, NULL};
140 : : static SimpleOidList extension_exclude_oids = {NULL, NULL};
141 : :
142 : : static const CatalogId nilCatalogId = {0, 0};
143 : :
144 : : /* override for standard extra_float_digits setting */
145 : : static bool have_extra_float_digits = false;
146 : : static int extra_float_digits;
147 : :
148 : : /* sorted table of role names */
149 : : static RoleNameItem *rolenames = NULL;
150 : : static int nrolenames = 0;
151 : :
152 : : /* sorted table of comments */
153 : : static CommentItem *comments = NULL;
154 : : static int ncomments = 0;
155 : :
156 : : /* sorted table of security labels */
157 : : static SecLabelItem *seclabels = NULL;
158 : : static int nseclabels = 0;
159 : :
160 : : /*
161 : : * The default number of rows per INSERT when
162 : : * --inserts is specified without --rows-per-insert
163 : : */
164 : : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
165 : :
166 : : /*
167 : : * Maximum number of large objects to group into a single ArchiveEntry.
168 : : * At some point we might want to make this user-controllable, but for now
169 : : * a hard-wired setting will suffice.
170 : : */
171 : : #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
172 : :
173 : : /*
174 : : * Macro for producing quoted, schema-qualified name of a dumpable object.
175 : : */
176 : : #define fmtQualifiedDumpable(obj) \
177 : : fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
178 : : (obj)->dobj.name)
179 : :
180 : : static void help(const char *progname);
181 : : static void setup_connection(Archive *AH,
182 : : const char *dumpencoding, const char *dumpsnapshot,
183 : : char *use_role);
184 : : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
185 : : static void expand_schema_name_patterns(Archive *fout,
186 : : SimpleStringList *patterns,
187 : : SimpleOidList *oids,
188 : : bool strict_names);
189 : : static void expand_extension_name_patterns(Archive *fout,
190 : : SimpleStringList *patterns,
191 : : SimpleOidList *oids,
192 : : bool strict_names);
193 : : static void expand_foreign_server_name_patterns(Archive *fout,
194 : : SimpleStringList *patterns,
195 : : SimpleOidList *oids);
196 : : static void expand_table_name_patterns(Archive *fout,
197 : : SimpleStringList *patterns,
198 : : SimpleOidList *oids,
199 : : bool strict_names,
200 : : bool with_child_tables);
201 : : static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
202 : : const char *pattern);
203 : :
204 : : static NamespaceInfo *findNamespace(Oid nsoid);
205 : : static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
206 : : static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
207 : : static const char *getRoleName(const char *roleoid_str);
208 : : static void collectRoleNames(Archive *fout);
209 : : static void getAdditionalACLs(Archive *fout);
210 : : static void dumpCommentExtended(Archive *fout, const char *type,
211 : : const char *name, const char *namespace,
212 : : const char *owner, CatalogId catalogId,
213 : : int subid, DumpId dumpId,
214 : : const char *initdb_comment);
215 : : static inline void dumpComment(Archive *fout, const char *type,
216 : : const char *name, const char *namespace,
217 : : const char *owner, CatalogId catalogId,
218 : : int subid, DumpId dumpId);
219 : : static int findComments(Oid classoid, Oid objoid, CommentItem **items);
220 : : static void collectComments(Archive *fout);
221 : : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
222 : : const char *namespace, const char *owner,
223 : : CatalogId catalogId, int subid, DumpId dumpId);
224 : : static int findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
225 : : static void collectSecLabels(Archive *fout);
226 : : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
227 : : static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
228 : : static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
229 : : static void dumpType(Archive *fout, const TypeInfo *tyinfo);
230 : : static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
231 : : static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
232 : : static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
233 : : static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
234 : : static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
235 : : static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
236 : : static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
237 : : PGresult *res);
238 : : static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
239 : : static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
240 : : static void dumpFunc(Archive *fout, const FuncInfo *finfo);
241 : : static void dumpCast(Archive *fout, const CastInfo *cast);
242 : : static void dumpTransform(Archive *fout, const TransformInfo *transform);
243 : : static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
244 : : static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
245 : : static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
246 : : static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
247 : : static void dumpCollation(Archive *fout, const CollInfo *collinfo);
248 : : static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
249 : : static void dumpRule(Archive *fout, const RuleInfo *rinfo);
250 : : static void dumpAgg(Archive *fout, const AggInfo *agginfo);
251 : : static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
252 : : static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
253 : : static void dumpTable(Archive *fout, const TableInfo *tbinfo);
254 : : static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
255 : : static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
256 : : static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
257 : : static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
258 : : static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
259 : : static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
260 : : static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
261 : : static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
262 : : static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
263 : : static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
264 : : static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
265 : : static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
266 : : static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
267 : : static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
268 : : static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
269 : : static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
270 : : static void dumpUserMappings(Archive *fout,
271 : : const char *servername, const char *namespace,
272 : : const char *owner, CatalogId catalogId, DumpId dumpId);
273 : : static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
274 : :
275 : : static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
276 : : const char *type, const char *name, const char *subname,
277 : : const char *nspname, const char *tag, const char *owner,
278 : : const DumpableAcl *dacl);
279 : :
280 : : static void getDependencies(Archive *fout);
281 : : static void BuildArchiveDependencies(Archive *fout);
282 : : static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
283 : : DumpId **dependencies, int *nDeps, int *allocDeps);
284 : :
285 : : static DumpableObject *createBoundaryObjects(void);
286 : : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
287 : : DumpableObject *boundaryObjs);
288 : :
289 : : static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
290 : : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
291 : : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
292 : : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
293 : : static void buildMatViewRefreshDependencies(Archive *fout);
294 : : static void getTableDataFKConstraints(void);
295 : : static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
296 : : bool is_agg);
297 : : static char *format_function_signature(Archive *fout,
298 : : const FuncInfo *finfo, bool honor_quotes);
299 : : static char *convertRegProcReference(const char *proc);
300 : : static char *getFormattedOperatorName(const char *oproid);
301 : : static char *convertTSFunction(Archive *fout, Oid funcOid);
302 : : static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
303 : : static void getLOs(Archive *fout);
304 : : static void dumpLO(Archive *fout, const LoInfo *loinfo);
305 : : static int dumpLOs(Archive *fout, const void *arg);
306 : : static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
307 : : static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
308 : : static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
309 : : static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
310 : : static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
311 : : static void dumpDatabase(Archive *fout);
312 : : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
313 : : const char *dbname, Oid dboid);
314 : : static void dumpEncoding(Archive *AH);
315 : : static void dumpStdStrings(Archive *AH);
316 : : static void dumpSearchPath(Archive *AH);
317 : : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
318 : : PQExpBuffer upgrade_buffer,
319 : : Oid pg_type_oid,
320 : : bool force_array_type,
321 : : bool include_multirange_type);
322 : : static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
323 : : PQExpBuffer upgrade_buffer,
324 : : const TableInfo *tbinfo);
325 : : static void binary_upgrade_set_pg_class_oids(Archive *fout,
326 : : PQExpBuffer upgrade_buffer,
327 : : Oid pg_class_oid, bool is_index);
328 : : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
329 : : const DumpableObject *dobj,
330 : : const char *objtype,
331 : : const char *objname,
332 : : const char *objnamespace);
333 : : static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
334 : : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
335 : : static bool nonemptyReloptions(const char *reloptions);
336 : : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
337 : : const char *prefix, Archive *fout);
338 : : static char *get_synchronized_snapshot(Archive *fout);
339 : : static void setupDumpWorker(Archive *AH);
340 : : static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
341 : : static bool forcePartitionRootLoad(const TableInfo *tbinfo);
342 : : static void read_dump_filters(const char *filename, DumpOptions *dopt);
343 : :
344 : :
345 : : int
8010 tgl@sss.pgh.pa.us 346 :CBC 244 : main(int argc, char **argv)
347 : : {
348 : : int c;
349 : 244 : const char *filename = NULL;
350 : 244 : const char *format = "p";
351 : : TableInfo *tblinfo;
352 : : int numTables;
353 : : DumpableObject **dobjs;
354 : : int numObjs;
355 : : DumpableObject *boundaryObjs;
356 : : int i;
357 : : int optindex;
358 : : RestoreOptions *ropt;
359 : : Archive *fout; /* the script file */
1840 peter@eisentraut.org 360 : 244 : bool g_verbose = false;
3470 alvherre@alvh.no-ip. 361 : 244 : const char *dumpencoding = NULL;
3436 simon@2ndQuadrant.co 362 : 244 : const char *dumpsnapshot = NULL;
3470 alvherre@alvh.no-ip. 363 : 244 : char *use_role = NULL;
4039 andrew@dunslane.net 364 : 244 : int numWorkers = 1;
8010 tgl@sss.pgh.pa.us 365 : 244 : int plainText = 0;
4830 heikki.linnakangas@i 366 : 244 : ArchiveFormat archiveFormat = archUnknown;
367 : : ArchiveMode archiveMode;
499 michael@paquier.xyz 368 : 244 : pg_compress_specification compression_spec = {0};
369 : 244 : char *compression_detail = NULL;
370 : 244 : char *compression_algorithm_str = "none";
371 : 244 : char *error_detail = NULL;
372 : 244 : bool user_compression_defined = false;
221 nathan@postgresql.or 373 :GNC 244 : DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
374 : :
375 : : static DumpOptions dopt;
376 : :
377 : : static struct option long_options[] = {
378 : : {"data-only", no_argument, NULL, 'a'},
379 : : {"blobs", no_argument, NULL, 'b'},
380 : : {"large-objects", no_argument, NULL, 'b'},
381 : : {"no-blobs", no_argument, NULL, 'B'},
382 : : {"no-large-objects", no_argument, NULL, 'B'},
383 : : {"clean", no_argument, NULL, 'c'},
384 : : {"create", no_argument, NULL, 'C'},
385 : : {"dbname", required_argument, NULL, 'd'},
386 : : {"extension", required_argument, NULL, 'e'},
387 : : {"file", required_argument, NULL, 'f'},
388 : : {"format", required_argument, NULL, 'F'},
389 : : {"host", required_argument, NULL, 'h'},
390 : : {"jobs", 1, NULL, 'j'},
391 : : {"no-reconnect", no_argument, NULL, 'R'},
392 : : {"no-owner", no_argument, NULL, 'O'},
393 : : {"port", required_argument, NULL, 'p'},
394 : : {"schema", required_argument, NULL, 'n'},
395 : : {"exclude-schema", required_argument, NULL, 'N'},
396 : : {"schema-only", no_argument, NULL, 's'},
397 : : {"superuser", required_argument, NULL, 'S'},
398 : : {"table", required_argument, NULL, 't'},
399 : : {"exclude-table", required_argument, NULL, 'T'},
400 : : {"no-password", no_argument, NULL, 'w'},
401 : : {"password", no_argument, NULL, 'W'},
402 : : {"username", required_argument, NULL, 'U'},
403 : : {"verbose", no_argument, NULL, 'v'},
404 : : {"no-privileges", no_argument, NULL, 'x'},
405 : : {"no-acl", no_argument, NULL, 'x'},
406 : : {"compress", required_argument, NULL, 'Z'},
407 : : {"encoding", required_argument, NULL, 'E'},
408 : : {"help", no_argument, NULL, '?'},
409 : : {"version", no_argument, NULL, 'V'},
410 : :
411 : : /*
412 : : * the following options don't have an equivalent short option letter
413 : : */
414 : : {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
415 : : {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
416 : : {"column-inserts", no_argument, &dopt.column_inserts, 1},
417 : : {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
418 : : {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
419 : : {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
420 : : {"exclude-table-data", required_argument, NULL, 4},
421 : : {"extra-float-digits", required_argument, NULL, 8},
422 : : {"if-exists", no_argument, &dopt.if_exists, 1},
423 : : {"inserts", no_argument, NULL, 9},
424 : : {"lock-wait-timeout", required_argument, NULL, 2},
425 : : {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
426 : : {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
427 : : {"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
428 : : {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
429 : : {"role", required_argument, NULL, 3},
430 : : {"section", required_argument, NULL, 5},
431 : : {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
432 : : {"snapshot", required_argument, NULL, 6},
433 : : {"strict-names", no_argument, &strict_names, 1},
434 : : {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
435 : : {"no-comments", no_argument, &dopt.no_comments, 1},
436 : : {"no-publications", no_argument, &dopt.no_publications, 1},
437 : : {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
438 : : {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
439 : : {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
440 : : {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
441 : : {"no-sync", no_argument, NULL, 7},
442 : : {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
443 : : {"rows-per-insert", required_argument, NULL, 10},
444 : : {"include-foreign-data", required_argument, NULL, 11},
445 : : {"table-and-children", required_argument, NULL, 12},
446 : : {"exclude-table-and-children", required_argument, NULL, 13},
447 : : {"exclude-table-data-and-children", required_argument, NULL, 14},
448 : : {"sync-method", required_argument, NULL, 15},
449 : : {"filter", required_argument, NULL, 16},
450 : : {"exclude-extension", required_argument, NULL, 17},
451 : :
452 : : {NULL, 0, NULL, 0}
453 : : };
454 : :
1840 peter@eisentraut.org 455 :CBC 244 : pg_logging_init(argv[0]);
456 : 244 : pg_logging_set_level(PG_LOG_WARNING);
5603 peter_e@gmx.net 457 : 244 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
458 : :
459 : : /*
460 : : * Initialize what we need for parallel execution, especially for thread
461 : : * support on Windows.
462 : : */
4039 andrew@dunslane.net 463 : 244 : init_parallel_dump_utils();
464 : :
7681 bruce@momjian.us 465 : 244 : progname = get_progname(argv[0]);
466 : :
8010 tgl@sss.pgh.pa.us 467 [ + - ]: 244 : if (argc > 1)
468 : : {
469 [ + + - + ]: 244 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
470 : : {
471 : 1 : help(progname);
4441 rhaas@postgresql.org 472 : 1 : exit_nicely(0);
473 : : }
8010 tgl@sss.pgh.pa.us 474 [ + + + + ]: 243 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
475 : : {
476 : 47 : puts("pg_dump (PostgreSQL) " PG_VERSION);
4441 rhaas@postgresql.org 477 : 47 : exit_nicely(0);
478 : : }
479 : : }
480 : :
3381 tgl@sss.pgh.pa.us 481 : 196 : InitDumpOptions(&dopt);
482 : :
1110 michael@paquier.xyz 483 : 846 : while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
7769 peter_e@gmx.net 484 [ + + ]: 846 : long_options, &optindex)) != -1)
485 : : {
8010 tgl@sss.pgh.pa.us 486 [ + + + + : 658 : switch (c)
+ + + + +
+ + + + +
+ + + + +
+ + + + +
- + + + +
+ + + - +
+ + + + +
+ + - + +
+ ]
487 : : {
488 : 8 : case 'a': /* Dump data only */
3381 489 : 8 : dopt.dataOnly = true;
8010 490 : 8 : break;
491 : :
496 peter@eisentraut.org 492 : 1 : case 'b': /* Dump LOs */
493 : 1 : dopt.outputLOs = true;
8010 tgl@sss.pgh.pa.us 494 : 1 : break;
495 : :
496 peter@eisentraut.org 496 : 2 : case 'B': /* Don't dump LOs */
497 : 2 : dopt.dontOutputLOs = true;
2693 sfrost@snowman.net 498 : 2 : break;
499 : :
6756 bruce@momjian.us 500 : 6 : case 'c': /* clean (i.e., drop) schema prior to create */
3381 tgl@sss.pgh.pa.us 501 : 6 : dopt.outputClean = 1;
8010 502 : 6 : break;
503 : :
504 : 29 : case 'C': /* Create DB */
3381 505 : 29 : dopt.outputCreateDB = 1;
8010 506 : 29 : break;
507 : :
4066 heikki.linnakangas@i 508 : 5 : case 'd': /* database name */
1298 tgl@sss.pgh.pa.us 509 : 5 : dopt.cparams.dbname = pg_strdup(optarg);
4066 heikki.linnakangas@i 510 : 5 : break;
511 : :
1110 michael@paquier.xyz 512 : 4 : case 'e': /* include extension(s) */
513 : 4 : simple_string_list_append(&extension_include_patterns, optarg);
514 : 4 : dopt.include_everything = false;
515 : 4 : break;
516 : :
6853 bruce@momjian.us 517 : 2 : case 'E': /* Dump encoding */
4202 518 : 2 : dumpencoding = pg_strdup(optarg);
6853 519 : 2 : break;
520 : :
8010 tgl@sss.pgh.pa.us 521 : 154 : case 'f':
4202 bruce@momjian.us 522 : 154 : filename = pg_strdup(optarg);
8010 tgl@sss.pgh.pa.us 523 : 154 : break;
524 : :
525 : 88 : case 'F':
4202 bruce@momjian.us 526 : 88 : format = pg_strdup(optarg);
8010 tgl@sss.pgh.pa.us 527 : 88 : break;
528 : :
529 : 12 : case 'h': /* server host */
1298 530 : 12 : dopt.cparams.pghost = pg_strdup(optarg);
8010 531 : 12 : break;
532 : :
4039 andrew@dunslane.net 533 : 12 : case 'j': /* number of dump jobs */
995 michael@paquier.xyz 534 [ + + ]: 12 : if (!option_parse_int(optarg, "-j/--jobs", 1,
535 : : PG_MAX_JOBS,
536 : : &numWorkers))
537 : 1 : exit_nicely(1);
4039 andrew@dunslane.net 538 : 11 : break;
539 : :
6397 tgl@sss.pgh.pa.us 540 : 15 : case 'n': /* include schema(s) */
541 : 15 : simple_string_list_append(&schema_include_patterns, optarg);
3381 542 : 15 : dopt.include_everything = false;
6397 543 : 15 : break;
544 : :
545 : 1 : case 'N': /* exclude schema(s) */
546 : 1 : simple_string_list_append(&schema_exclude_patterns, optarg);
7731 bruce@momjian.us 547 : 1 : break;
548 : :
8010 tgl@sss.pgh.pa.us 549 : 2 : case 'O': /* Don't reconnect to match owner */
3381 550 : 2 : dopt.outputNoOwner = 1;
8010 551 : 2 : break;
552 : :
553 : 48 : case 'p': /* server port */
1298 554 : 48 : dopt.cparams.pgport = pg_strdup(optarg);
8010 555 : 48 : break;
556 : :
7509 557 : 2 : case 'R':
558 : : /* no-op, still accepted for backwards compatibility */
8010 559 : 2 : break;
560 : :
561 : 18 : case 's': /* dump schema only */
3381 562 : 18 : dopt.schemaOnly = true;
8010 563 : 18 : break;
564 : :
6756 bruce@momjian.us 565 : 1 : case 'S': /* Username for superuser in plain text output */
3381 tgl@sss.pgh.pa.us 566 : 1 : dopt.outputSuperuser = pg_strdup(optarg);
8010 567 : 1 : break;
568 : :
6397 569 : 8 : case 't': /* include table(s) */
570 : 8 : simple_string_list_append(&table_include_patterns, optarg);
3381 571 : 8 : dopt.include_everything = false;
6397 572 : 8 : break;
573 : :
574 : 4 : case 'T': /* exclude table(s) */
575 : 4 : simple_string_list_append(&table_exclude_patterns, optarg);
576 : 4 : break;
577 : :
8010 578 : 14 : case 'U':
1298 579 : 14 : dopt.cparams.username = pg_strdup(optarg);
8010 580 : 14 : break;
581 : :
582 : 6 : case 'v': /* verbose */
583 : 6 : g_verbose = true;
1305 584 : 6 : pg_logging_increase_verbosity();
8010 585 : 6 : break;
586 : :
5526 peter_e@gmx.net 587 : 1 : case 'w':
1298 tgl@sss.pgh.pa.us 588 : 1 : dopt.cparams.promptPassword = TRI_NO;
5526 peter_e@gmx.net 589 : 1 : break;
590 : :
8010 tgl@sss.pgh.pa.us 591 :UBC 0 : case 'W':
1298 592 : 0 : dopt.cparams.promptPassword = TRI_YES;
8010 593 : 0 : break;
594 : :
8010 tgl@sss.pgh.pa.us 595 :CBC 2 : case 'x': /* skip ACL dump */
3381 596 : 2 : dopt.aclsSkip = true;
8010 597 : 2 : break;
598 : :
499 michael@paquier.xyz 599 : 15 : case 'Z': /* Compression */
600 : 15 : parse_compress_options(optarg, &compression_algorithm_str,
601 : : &compression_detail);
602 : 15 : user_compression_defined = true;
8010 tgl@sss.pgh.pa.us 603 : 15 : break;
604 : :
605 : 49 : case 0:
606 : : /* This covers the long options. */
607 : 49 : break;
608 : :
5578 609 : 2 : case 2: /* lock-wait-timeout */
3381 610 : 2 : dopt.lockWaitTimeout = pg_strdup(optarg);
5747 611 : 2 : break;
612 : :
5578 613 : 3 : case 3: /* SET ROLE */
4202 bruce@momjian.us 614 : 3 : use_role = pg_strdup(optarg);
5578 tgl@sss.pgh.pa.us 615 : 3 : break;
616 : :
4326 bruce@momjian.us 617 : 1 : case 4: /* exclude table(s) data */
4505 andrew@dunslane.net 618 : 1 : simple_string_list_append(&tabledata_exclude_patterns, optarg);
619 : 1 : break;
620 : :
4503 621 : 6 : case 5: /* section */
3381 tgl@sss.pgh.pa.us 622 : 6 : set_dump_section(optarg, &dopt.dumpSections);
4503 andrew@dunslane.net 623 : 6 : break;
624 : :
3436 simon@2ndQuadrant.co 625 :UBC 0 : case 6: /* snapshot */
626 : 0 : dumpsnapshot = pg_strdup(optarg);
627 : 0 : break;
628 : :
2580 andrew@dunslane.net 629 :CBC 97 : case 7: /* no-sync */
630 : 97 : dosync = false;
631 : 97 : break;
632 : :
1882 633 : 1 : case 8:
634 : 1 : have_extra_float_digits = true;
995 michael@paquier.xyz 635 [ + - ]: 1 : if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
636 : : &extra_float_digits))
1882 andrew@dunslane.net 637 : 1 : exit_nicely(1);
1882 andrew@dunslane.net 638 :UBC 0 : break;
639 : :
1865 alvherre@alvh.no-ip. 640 :CBC 2 : case 9: /* inserts */
641 : :
642 : : /*
643 : : * dump_inserts also stores --rows-per-insert, careful not to
644 : : * overwrite that.
645 : : */
646 [ + - ]: 2 : if (dopt.dump_inserts == 0)
647 : 2 : dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
648 : 2 : break;
649 : :
650 : 2 : case 10: /* rows per insert */
995 michael@paquier.xyz 651 [ + + ]: 2 : if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
652 : : &dopt.dump_inserts))
1865 alvherre@alvh.no-ip. 653 : 1 : exit_nicely(1);
654 : 1 : break;
655 : :
1481 656 : 4 : case 11: /* include foreign data */
657 : 4 : simple_string_list_append(&foreign_servers_include_patterns,
658 : : optarg);
659 : 4 : break;
660 : :
397 tgl@sss.pgh.pa.us 661 : 1 : case 12: /* include table(s) and their children */
662 : 1 : simple_string_list_append(&table_include_patterns_and_children,
663 : : optarg);
664 : 1 : dopt.include_everything = false;
665 : 1 : break;
666 : :
667 : 1 : case 13: /* exclude table(s) and their children */
668 : 1 : simple_string_list_append(&table_exclude_patterns_and_children,
669 : : optarg);
670 : 1 : break;
671 : :
672 : 1 : case 14: /* exclude data of table(s) and children */
673 : 1 : simple_string_list_append(&tabledata_exclude_patterns_and_children,
674 : : optarg);
675 : 1 : break;
676 : :
221 nathan@postgresql.or 677 :UNC 0 : case 15:
678 [ # # ]: 0 : if (!parse_sync_method(optarg, &sync_method))
679 : 0 : exit_nicely(1);
680 : 0 : break;
681 : :
137 dgustafsson@postgres 682 :GNC 26 : case 16: /* read object filters from file */
683 : 26 : read_dump_filters(optarg, &dopt);
684 : 22 : break;
685 : :
25 dean.a.rasheed@gmail 686 : 1 : case 17: /* exclude extension(s) */
687 : 1 : simple_string_list_append(&extension_exclude_patterns,
688 : : optarg);
689 : 1 : break;
690 : :
8010 tgl@sss.pgh.pa.us 691 :CBC 1 : default:
692 : : /* getopt_long already emitted a complaint */
737 693 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4441 rhaas@postgresql.org 694 : 1 : exit_nicely(1);
695 : : }
696 : : }
697 : :
698 : : /*
699 : : * Non-option argument specifies database name as long as it wasn't
700 : : * already specified with -d / --dbname
701 : : */
1298 tgl@sss.pgh.pa.us 702 [ + + + - ]: 188 : if (optind < argc && dopt.cparams.dbname == NULL)
703 : 156 : dopt.cparams.dbname = argv[optind++];
704 : :
705 : : /* Complain if any arguments remain */
4993 706 [ + + ]: 188 : if (optind < argc)
707 : : {
1840 peter@eisentraut.org 708 : 1 : pg_log_error("too many command-line arguments (first is \"%s\")",
709 : : argv[optind]);
737 tgl@sss.pgh.pa.us 710 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4441 rhaas@postgresql.org 711 : 1 : exit_nicely(1);
712 : : }
713 : :
714 : : /* --column-inserts implies --inserts */
1865 alvherre@alvh.no-ip. 715 [ + + + - ]: 187 : if (dopt.column_inserts && dopt.dump_inserts == 0)
716 : 1 : dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
717 : :
718 : : /*
719 : : * Binary upgrade mode implies dumping sequence data even in schema-only
720 : : * mode. This is not exposed as a separate option, but kept separate
721 : : * internally for clarity.
722 : : */
2791 peter_e@gmx.net 723 [ + + ]: 187 : if (dopt.binary_upgrade)
724 : 14 : dopt.sequence_data = 1;
725 : :
3381 tgl@sss.pgh.pa.us 726 [ + + + + ]: 187 : if (dopt.dataOnly && dopt.schemaOnly)
737 727 : 1 : pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
728 : :
1481 alvherre@alvh.no-ip. 729 [ + + + + ]: 186 : if (dopt.schemaOnly && foreign_servers_include_patterns.head != NULL)
737 tgl@sss.pgh.pa.us 730 : 1 : pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
731 : :
1481 alvherre@alvh.no-ip. 732 [ + + + + ]: 185 : if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
737 tgl@sss.pgh.pa.us 733 : 1 : pg_fatal("option --include-foreign-data is not supported with parallel backup");
734 : :
3381 735 [ + + + + ]: 184 : if (dopt.dataOnly && dopt.outputClean)
737 736 : 1 : pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
737 : :
3381 738 [ + + + + ]: 183 : if (dopt.if_exists && !dopt.outputClean)
737 739 : 1 : pg_fatal("option --if-exists requires option -c/--clean");
740 : :
741 : : /*
742 : : * --inserts are already implied above if --column-inserts or
743 : : * --rows-per-insert were specified.
744 : : */
1865 alvherre@alvh.no-ip. 745 [ + + + - ]: 182 : if (dopt.do_nothing && dopt.dump_inserts == 0)
737 tgl@sss.pgh.pa.us 746 : 1 : pg_fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
747 : :
748 : : /* Identify archive format to emit */
4830 heikki.linnakangas@i 749 : 181 : archiveFormat = parseArchiveFormat(format, &archiveMode);
750 : :
751 : : /* archiveFormat specific setup */
752 [ + + ]: 180 : if (archiveFormat == archNull)
6233 bruce@momjian.us 753 : 146 : plainText = 1;
754 : :
755 : : /*
756 : : * Custom and directory formats are compressed by default with gzip when
757 : : * available, not the others. If gzip is not available, no compression is
758 : : * done by default.
759 : : */
353 michael@paquier.xyz 760 [ + + + + ]: 180 : if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
761 [ + + ]: 31 : !user_compression_defined)
762 : : {
763 : : #ifdef HAVE_LIBZ
764 : 24 : compression_algorithm_str = "gzip";
765 : : #else
766 : : compression_algorithm_str = "none";
767 : : #endif
768 : : }
769 : :
770 : : /*
771 : : * Compression options
772 : : */
499 773 [ + + ]: 180 : if (!parse_compress_algorithm(compression_algorithm_str,
774 : : &compression_algorithm))
775 : 1 : pg_fatal("unrecognized compression algorithm: \"%s\"",
776 : : compression_algorithm_str);
777 : :
778 : 179 : parse_compress_specification(compression_algorithm, compression_detail,
779 : : &compression_spec);
780 : 179 : error_detail = validate_compress_specification(&compression_spec);
781 [ + + ]: 179 : if (error_detail != NULL)
782 : 3 : pg_fatal("invalid compression specification: %s",
783 : : error_detail);
784 : :
375 tomas.vondra@postgre 785 : 176 : error_detail = supports_compression(compression_spec);
786 [ - + ]: 176 : if (error_detail != NULL)
375 tomas.vondra@postgre 787 :UBC 0 : pg_fatal("%s", error_detail);
788 : :
789 : : /*
790 : : * Disable support for zstd workers for now - these are based on
791 : : * threading, and it's unclear how it interacts with parallel dumps on
792 : : * platforms where that relies on threads too (e.g. Windows).
793 : : */
375 tomas.vondra@postgre 794 [ - + ]:CBC 176 : if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
375 tomas.vondra@postgre 795 :UBC 0 : pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
796 : : "workers");
797 : :
798 : : /*
799 : : * If emitting an archive format, we always want to emit a DATABASE item,
800 : : * in case --create is specified at pg_restore time.
801 : : */
2271 tgl@sss.pgh.pa.us 802 [ + + ]:CBC 176 : if (!plainText)
803 : 34 : dopt.outputCreateDB = 1;
804 : :
805 : : /* Parallel backup only in the directory archive format so far */
4039 andrew@dunslane.net 806 [ + + + + ]: 176 : if (archiveFormat != archDirectory && numWorkers > 1)
737 tgl@sss.pgh.pa.us 807 : 1 : pg_fatal("parallel backup only supported by the directory format");
808 : :
809 : : /* Open the output file */
499 michael@paquier.xyz 810 : 175 : fout = CreateArchive(filename, archiveFormat, compression_spec,
811 : : dosync, archiveMode, setupDumpWorker, sync_method);
812 : :
813 : : /* Make dump options accessible right away */
3014 tgl@sss.pgh.pa.us 814 : 174 : SetArchiveOptions(fout, &dopt, NULL);
815 : :
816 : : /* Register the cleanup hook */
4408 alvherre@alvh.no-ip. 817 : 174 : on_exit_close_archive(fout);
818 : :
819 : : /* Let the archiver know how noisy to be */
4451 rhaas@postgresql.org 820 : 174 : fout->verbose = g_verbose;
821 : :
822 : :
823 : : /*
824 : : * We allow the server to be back to 9.2, and up to any minor release of
825 : : * our own major version. (See also version check in pg_dumpall.c.)
826 : : */
852 tgl@sss.pgh.pa.us 827 : 174 : fout->minRemoteVersion = 90200;
4037 heikki.linnakangas@i 828 : 174 : fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
829 : :
4039 andrew@dunslane.net 830 : 174 : fout->numWorkers = numWorkers;
831 : :
832 : : /*
833 : : * Open the database using the Archiver, so it knows about it. Errors mean
834 : : * death.
835 : : */
1298 tgl@sss.pgh.pa.us 836 : 174 : ConnectDatabase(fout, &dopt.cparams, false);
3014 837 : 172 : setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
838 : :
839 : : /*
840 : : * On hot standbys, never try to dump unlogged table data, since it will
841 : : * just throw an error.
842 : : */
2880 magnus@hagander.net 843 [ + + ]: 172 : if (fout->isStandby)
844 : 3 : dopt.no_unlogged_table_data = true;
845 : :
846 : : /*
847 : : * Find the last built-in OID, if needed (prior to 8.1)
848 : : *
849 : : * With 8.1 and above, we can just use FirstNormalObjectId - 1.
850 : : */
852 tgl@sss.pgh.pa.us 851 : 172 : g_last_builtin_oid = FirstNormalObjectId - 1;
852 : :
1840 peter@eisentraut.org 853 : 172 : pg_log_info("last built-in OID is %u", g_last_builtin_oid);
854 : :
855 : : /* Expand schema selection patterns into OID lists */
6397 tgl@sss.pgh.pa.us 856 [ + + ]: 172 : if (schema_include_patterns.head != NULL)
857 : : {
4451 rhaas@postgresql.org 858 : 16 : expand_schema_name_patterns(fout, &schema_include_patterns,
859 : : &schema_include_oids,
860 : : strict_names);
6397 tgl@sss.pgh.pa.us 861 [ + + ]: 10 : if (schema_include_oids.head == NULL)
737 862 : 1 : pg_fatal("no matching schemas were found");
863 : : }
4451 rhaas@postgresql.org 864 : 165 : expand_schema_name_patterns(fout, &schema_exclude_patterns,
865 : : &schema_exclude_oids,
866 : : false);
867 : : /* non-matching exclusion patterns aren't an error */
868 : :
869 : : /* Expand table selection patterns into OID lists */
397 tgl@sss.pgh.pa.us 870 : 165 : expand_table_name_patterns(fout, &table_include_patterns,
871 : : &table_include_oids,
872 : : strict_names, false);
873 : 160 : expand_table_name_patterns(fout, &table_include_patterns_and_children,
874 : : &table_include_oids,
875 : : strict_names, true);
876 [ + + ]: 160 : if ((table_include_patterns.head != NULL ||
877 [ + + ]: 149 : table_include_patterns_and_children.head != NULL) &&
878 [ + + ]: 13 : table_include_oids.head == NULL)
879 : 2 : pg_fatal("no matching tables were found");
880 : :
4450 rhaas@postgresql.org 881 : 158 : expand_table_name_patterns(fout, &table_exclude_patterns,
882 : : &table_exclude_oids,
883 : : false, false);
397 tgl@sss.pgh.pa.us 884 : 158 : expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
885 : : &table_exclude_oids,
886 : : false, true);
887 : :
4450 rhaas@postgresql.org 888 : 158 : expand_table_name_patterns(fout, &tabledata_exclude_patterns,
889 : : &tabledata_exclude_oids,
890 : : false, false);
397 tgl@sss.pgh.pa.us 891 : 158 : expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
892 : : &tabledata_exclude_oids,
893 : : false, true);
894 : :
1481 alvherre@alvh.no-ip. 895 : 158 : expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
896 : : &foreign_servers_include_oids);
897 : :
898 : : /* non-matching exclusion patterns aren't an error */
899 : :
900 : : /* Expand extension selection patterns into OID lists */
1110 michael@paquier.xyz 901 [ + + ]: 157 : if (extension_include_patterns.head != NULL)
902 : : {
903 : 5 : expand_extension_name_patterns(fout, &extension_include_patterns,
904 : : &extension_include_oids,
905 : : strict_names);
906 [ + + ]: 5 : if (extension_include_oids.head == NULL)
737 tgl@sss.pgh.pa.us 907 :GBC 1 : pg_fatal("no matching extensions were found");
908 : : }
25 dean.a.rasheed@gmail 909 :GNC 156 : expand_extension_name_patterns(fout, &extension_exclude_patterns,
910 : : &extension_exclude_oids,
911 : : false);
912 : : /* non-matching exclusion patterns aren't an error */
913 : :
914 : : /*
915 : : * Dumping LOs is the default for dumps where an inclusion switch is not
916 : : * used (an "include everything" dump). -B can be used to exclude LOs
917 : : * from those dumps. -b can be used to include LOs even when an inclusion
918 : : * switch is used.
919 : : *
920 : : * -s means "schema only" and LOs are data, not schema, so we never
921 : : * include LOs when -s is used.
922 : : */
496 peter@eisentraut.org 923 [ + + + + :CBC 156 : if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputLOs)
+ + ]
924 : 117 : dopt.outputLOs = true;
925 : :
926 : : /*
927 : : * Collect role names so we can map object owner OIDs to names.
928 : : */
835 tgl@sss.pgh.pa.us 929 : 156 : collectRoleNames(fout);
930 : :
931 : : /*
932 : : * Now scan the database and create DumpableObject structs for all the
933 : : * objects we intend to dump.
934 : : */
3014 935 : 156 : tblinfo = getSchemaData(fout, &numTables);
936 : :
3381 937 [ + + ]: 155 : if (!dopt.schemaOnly)
938 : : {
1972 andres@anarazel.de 939 : 139 : getTableData(&dopt, tblinfo, numTables, 0);
4060 kgrittn@postgresql.o 940 : 139 : buildMatViewRefreshDependencies(fout);
3381 tgl@sss.pgh.pa.us 941 [ + + ]: 139 : if (dopt.dataOnly)
5697 942 : 6 : getTableDataFKConstraints();
943 : : }
944 : :
2791 peter_e@gmx.net 945 [ + + + + ]: 155 : if (dopt.schemaOnly && dopt.sequence_data)
1972 andres@anarazel.de 946 : 14 : getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
947 : :
948 : : /*
949 : : * In binary-upgrade mode, we do not have to worry about the actual LO
950 : : * data or the associated metadata that resides in the pg_largeobject and
951 : : * pg_largeobject_metadata tables, respectively.
952 : : *
953 : : * However, we do need to collect LO information as there may be comments
954 : : * or other information on LOs that we do need to dump out.
955 : : */
496 peter@eisentraut.org 956 [ + + + + ]: 155 : if (dopt.outputLOs || dopt.binary_upgrade)
957 : 131 : getLOs(fout);
958 : :
959 : : /*
960 : : * Collect dependency data to assist in ordering the objects.
961 : : */
4451 rhaas@postgresql.org 962 : 155 : getDependencies(fout);
963 : :
964 : : /*
965 : : * Collect ACLs, comments, and security labels, if wanted.
966 : : */
860 tgl@sss.pgh.pa.us 967 [ + + ]: 155 : if (!dopt.aclsSkip)
968 : 153 : getAdditionalACLs(fout);
969 [ + - ]: 155 : if (!dopt.no_comments)
970 : 155 : collectComments(fout);
971 [ + - ]: 155 : if (!dopt.no_security_labels)
972 : 155 : collectSecLabels(fout);
973 : :
974 : : /* Lastly, create dummy objects to represent the section boundaries */
4311 975 : 155 : boundaryObjs = createBoundaryObjects();
976 : :
977 : : /* Get pointers to all the known DumpableObjects */
978 : 155 : getDumpableObjects(&dobjs, &numObjs);
979 : :
980 : : /*
981 : : * Add dummy dependencies to enforce the dump section ordering.
982 : : */
983 : 155 : addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
984 : :
985 : : /*
986 : : * Sort the objects into a safe dump order (no forward references).
987 : : *
988 : : * We rely on dependency information to help us determine a safe order, so
989 : : * the initial sort is mostly for cosmetic purposes: we sort by name to
990 : : * ensure that logically identical schemas will dump identically.
991 : : */
2741 992 : 155 : sortDumpableObjectsByTypeName(dobjs, numObjs);
993 : :
4311 994 : 155 : sortDumpableObjects(dobjs, numObjs,
995 : 155 : boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
996 : :
997 : : /*
998 : : * Create archive TOC entries for all the objects to be dumped, in a safe
999 : : * order.
1000 : : */
1001 : :
1002 : : /*
1003 : : * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
1004 : : */
4451 rhaas@postgresql.org 1005 : 155 : dumpEncoding(fout);
1006 : 155 : dumpStdStrings(fout);
2239 tgl@sss.pgh.pa.us 1007 : 155 : dumpSearchPath(fout);
1008 : :
1009 : : /* The database items are always next, unless we don't want them at all */
2271 1010 [ + + ]: 155 : if (dopt.outputCreateDB)
3014 1011 : 62 : dumpDatabase(fout);
1012 : :
1013 : : /* Now the rearrangeable objects. */
7435 1014 [ + + ]: 664403 : for (i = 0; i < numObjs; i++)
3014 1015 : 664248 : dumpDumpableObject(fout, dobjs[i]);
1016 : :
1017 : : /*
1018 : : * Set up options info to ensure we dump what we want.
1019 : : */
4338 1020 : 155 : ropt = NewRestoreOptions();
1021 : 155 : ropt->filename = filename;
1022 : :
1023 : : /* if you change this list, see dumpOptionsFromRestoreOptions */
1298 1024 [ + + ]: 155 : ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
1025 [ + + ]: 155 : ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
1026 [ + + ]: 155 : ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
1027 [ + + ]: 155 : ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
1028 : 155 : ropt->cparams.promptPassword = dopt.cparams.promptPassword;
3381 1029 : 155 : ropt->dropSchema = dopt.outputClean;
1030 : 155 : ropt->dataOnly = dopt.dataOnly;
1031 : 155 : ropt->schemaOnly = dopt.schemaOnly;
1032 : 155 : ropt->if_exists = dopt.if_exists;
1033 : 155 : ropt->column_inserts = dopt.column_inserts;
1034 : 155 : ropt->dumpSections = dopt.dumpSections;
1035 : 155 : ropt->aclsSkip = dopt.aclsSkip;
1036 : 155 : ropt->superuser = dopt.outputSuperuser;
1037 : 155 : ropt->createDB = dopt.outputCreateDB;
1038 : 155 : ropt->noOwner = dopt.outputNoOwner;
818 michael@paquier.xyz 1039 : 155 : ropt->noTableAm = dopt.outputNoTableAm;
3381 tgl@sss.pgh.pa.us 1040 : 155 : ropt->noTablespace = dopt.outputNoTablespaces;
1041 : 155 : ropt->disable_triggers = dopt.disable_triggers;
1042 : 155 : ropt->use_setsessauth = dopt.use_setsessauth;
1043 : 155 : ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
1044 : 155 : ropt->dump_inserts = dopt.dump_inserts;
2271 1045 : 155 : ropt->no_comments = dopt.no_comments;
2529 peter_e@gmx.net 1046 : 155 : ropt->no_publications = dopt.no_publications;
3381 tgl@sss.pgh.pa.us 1047 : 155 : ropt->no_security_labels = dopt.no_security_labels;
2532 peter_e@gmx.net 1048 : 155 : ropt->no_subscriptions = dopt.no_subscriptions;
3381 tgl@sss.pgh.pa.us 1049 : 155 : ropt->lockWaitTimeout = dopt.lockWaitTimeout;
1050 : 155 : ropt->include_everything = dopt.include_everything;
1051 : 155 : ropt->enable_row_security = dopt.enable_row_security;
2791 peter_e@gmx.net 1052 : 155 : ropt->sequence_data = dopt.sequence_data;
2596 sfrost@snowman.net 1053 : 155 : ropt->binary_upgrade = dopt.binary_upgrade;
1054 : :
499 michael@paquier.xyz 1055 : 155 : ropt->compression_spec = compression_spec;
1056 : :
4326 bruce@momjian.us 1057 : 155 : ropt->suppressDumpWarnings = true; /* We've already shown them */
1058 : :
3014 tgl@sss.pgh.pa.us 1059 : 155 : SetArchiveOptions(fout, &dopt, ropt);
1060 : :
1061 : : /* Mark which entries should be output */
1062 : 155 : ProcessArchiveRestoreOptions(fout);
1063 : :
1064 : : /*
1065 : : * The archive's TOC entries are now marked as to which ones will actually
1066 : : * be output, so we can set up their dependency lists properly. This isn't
1067 : : * necessary for plain-text output, though.
1068 : : */
4311 1069 [ + + ]: 155 : if (!plainText)
1070 : 33 : BuildArchiveDependencies(fout);
1071 : :
1072 : : /*
1073 : : * And finally we can do the actual output.
1074 : : *
1075 : : * Note: for non-plain-text output formats, the output file is written
1076 : : * inside CloseArchive(). This is, um, bizarre; but not worth changing
1077 : : * right now.
1078 : : */
4338 1079 [ + + ]: 155 : if (plainText)
1080 : 122 : RestoreArchive(fout);
1081 : :
3014 1082 : 154 : CloseArchive(fout);
1083 : :
4441 rhaas@postgresql.org 1084 : 154 : exit_nicely(0);
1085 : : }
1086 : :
1087 : :
1088 : : static void
8010 tgl@sss.pgh.pa.us 1089 : 1 : help(const char *progname)
1090 : : {
7900 peter_e@gmx.net 1091 : 1 : printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
1092 : 1 : printf(_("Usage:\n"));
7849 1093 : 1 : printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
1094 : :
1095 : 1 : printf(_("\nGeneral options:\n"));
4349 1096 : 1 : printf(_(" -f, --file=FILENAME output file or directory name\n"));
1097 : 1 : printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
1098 : : " plain text (default))\n"));
4039 andrew@dunslane.net 1099 : 1 : printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
4349 peter_e@gmx.net 1100 : 1 : printf(_(" -v, --verbose verbose mode\n"));
4318 1101 : 1 : printf(_(" -V, --version output version information, then exit\n"));
331 peter@eisentraut.org 1102 : 1 : printf(_(" -Z, --compress=METHOD[:DETAIL]\n"
1103 : : " compress as specified\n"));
4349 peter_e@gmx.net 1104 : 1 : printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
2580 andrew@dunslane.net 1105 : 1 : printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
221 nathan@postgresql.or 1106 :GNC 1 : printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
4318 peter_e@gmx.net 1107 :CBC 1 : printf(_(" -?, --help show this help, then exit\n"));
1108 : :
7849 1109 : 1 : printf(_("\nOptions controlling the output content:\n"));
4349 1110 : 1 : printf(_(" -a, --data-only dump only the data, not the schema\n"));
331 peter@eisentraut.org 1111 : 1 : printf(_(" -b, --large-objects include large objects in dump\n"));
1112 : 1 : printf(_(" --blobs (same as --large-objects, deprecated)\n"));
1113 : 1 : printf(_(" -B, --no-large-objects exclude large objects in dump\n"));
1114 : 1 : printf(_(" --no-blobs (same as --no-large-objects, deprecated)\n"));
4349 peter_e@gmx.net 1115 : 1 : printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
1116 : 1 : printf(_(" -C, --create include commands to create database in dump\n"));
1110 michael@paquier.xyz 1117 : 1 : printf(_(" -e, --extension=PATTERN dump the specified extension(s) only\n"));
25 dean.a.rasheed@gmail 1118 :GNC 1 : printf(_(" --exclude-extension=PATTERN do NOT dump the specified extension(s)\n"));
4349 peter_e@gmx.net 1119 :CBC 1 : printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
1685 peter@eisentraut.org 1120 : 1 : printf(_(" -n, --schema=PATTERN dump the specified schema(s) only\n"));
1121 : 1 : printf(_(" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
4349 peter_e@gmx.net 1122 : 1 : printf(_(" -O, --no-owner skip restoration of object ownership in\n"
1123 : : " plain-text format\n"));
1124 : 1 : printf(_(" -s, --schema-only dump only the schema, no data\n"));
1125 : 1 : printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
397 tgl@sss.pgh.pa.us 1126 : 1 : printf(_(" -t, --table=PATTERN dump only the specified table(s)\n"));
1685 peter@eisentraut.org 1127 : 1 : printf(_(" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n"));
4349 peter_e@gmx.net 1128 : 1 : printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
1129 : 1 : printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
1130 : 1 : printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
1131 : 1 : printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
1132 : 1 : printf(_(" --disable-triggers disable triggers during data-only restore\n"));
3133 1133 : 1 : printf(_(" --enable-row-security enable row security (dump only content user has\n"
1134 : : " access to)\n"));
397 tgl@sss.pgh.pa.us 1135 : 1 : printf(_(" --exclude-table-and-children=PATTERN\n"
1136 : : " do NOT dump the specified table(s), including\n"
1137 : : " child and partition tables\n"));
1685 peter@eisentraut.org 1138 : 1 : printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
397 tgl@sss.pgh.pa.us 1139 : 1 : printf(_(" --exclude-table-data-and-children=PATTERN\n"
1140 : : " do NOT dump data for the specified table(s),\n"
1141 : : " including child and partition tables\n"));
1882 andrew@dunslane.net 1142 : 1 : printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
137 dgustafsson@postgres 1143 :GNC 1 : printf(_(" --filter=FILENAME include or exclude objects and data from dump\n"
1144 : : " based on expressions in FILENAME\n"));
3695 alvherre@alvh.no-ip. 1145 :CBC 1 : printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
1481 1146 : 1 : printf(_(" --include-foreign-data=PATTERN\n"
1147 : : " include data of foreign tables on foreign\n"
1148 : : " servers matching PATTERN\n"));
4349 peter_e@gmx.net 1149 : 1 : printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
2141 1150 : 1 : printf(_(" --load-via-partition-root load partitions via the root table\n"));
2271 tgl@sss.pgh.pa.us 1151 : 1 : printf(_(" --no-comments do not dump comments\n"));
2529 peter_e@gmx.net 1152 : 1 : printf(_(" --no-publications do not dump publications\n"));
4349 1153 : 1 : printf(_(" --no-security-labels do not dump security label assignments\n"));
2532 1154 : 1 : printf(_(" --no-subscriptions do not dump subscriptions\n"));
818 michael@paquier.xyz 1155 : 1 : printf(_(" --no-table-access-method do not dump table access methods\n"));
4349 peter_e@gmx.net 1156 : 1 : printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
1066 peter@eisentraut.org 1157 : 1 : printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
4349 peter_e@gmx.net 1158 : 1 : printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
2102 tmunro@postgresql.or 1159 : 1 : printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
4349 peter_e@gmx.net 1160 : 1 : printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
1865 alvherre@alvh.no-ip. 1161 : 1 : printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
4349 peter_e@gmx.net 1162 : 1 : printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
1163 : 1 : printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
3122 1164 : 1 : printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
3135 teodor@sigaev.ru 1165 : 1 : printf(_(" --strict-names require table and/or schema include patterns to\n"
1166 : : " match at least one entity each\n"));
331 peter@eisentraut.org 1167 : 1 : printf(_(" --table-and-children=PATTERN dump only the specified table(s), including\n"
1168 : : " child and partition tables\n"));
6399 peter_e@gmx.net 1169 : 1 : printf(_(" --use-set-session-authorization\n"
1170 : : " use SET SESSION AUTHORIZATION commands instead of\n"
1171 : : " ALTER OWNER commands to set ownership\n"));
1172 : :
7849 1173 : 1 : printf(_("\nConnection options:\n"));
4066 heikki.linnakangas@i 1174 : 1 : printf(_(" -d, --dbname=DBNAME database to dump\n"));
7613 bruce@momjian.us 1175 : 1 : printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
7849 peter_e@gmx.net 1176 : 1 : printf(_(" -p, --port=PORT database server port number\n"));
1177 : 1 : printf(_(" -U, --username=NAME connect as specified database user\n"));
5507 1178 : 1 : printf(_(" -w, --no-password never prompt for password\n"));
7849 1179 : 1 : printf(_(" -W, --password force password prompt (should happen automatically)\n"));
4708 1180 : 1 : printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
1181 : :
7571 1182 : 1 : printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1183 : : "variable value is used.\n\n"));
1507 peter@eisentraut.org 1184 : 1 : printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1185 : 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
8010 tgl@sss.pgh.pa.us 1186 : 1 : }
1187 : :
1188 : : static void
3014 1189 : 190 : setup_connection(Archive *AH, const char *dumpencoding,
1190 : : const char *dumpsnapshot, char *use_role)
1191 : : {
1192 : 190 : DumpOptions *dopt = AH->dopt;
4441 rhaas@postgresql.org 1193 : 190 : PGconn *conn = GetConnection(AH);
1194 : : const char *std_strings;
1195 : :
2239 noah@leadboat.com 1196 : 190 : PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1197 : :
1198 : : /*
1199 : : * Set the client encoding if requested.
1200 : : */
4461 rhaas@postgresql.org 1201 [ + + ]: 190 : if (dumpencoding)
1202 : : {
4441 1203 [ - + ]: 20 : if (PQsetClientEncoding(conn, dumpencoding) < 0)
737 tgl@sss.pgh.pa.us 1204 :UBC 0 : pg_fatal("invalid client encoding \"%s\" specified",
1205 : : dumpencoding);
1206 : : }
1207 : :
1208 : : /*
1209 : : * Get the active encoding and the standard_conforming_strings setting, so
1210 : : * we know how to escape strings.
1211 : : */
4441 rhaas@postgresql.org 1212 :CBC 190 : AH->encoding = PQclientEncoding(conn);
1213 : :
1214 : 190 : std_strings = PQparameterStatus(conn, "standard_conforming_strings");
4461 1215 [ + - + - ]: 190 : AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1216 : :
1217 : : /*
1218 : : * Set the role if requested. In a parallel dump worker, we'll be passed
1219 : : * use_role == NULL, but AH->use_role is already set (if user specified it
1220 : : * originally) and we should use that.
1221 : : */
4039 andrew@dunslane.net 1222 [ + + + + ]: 190 : if (!use_role && AH->use_role)
1223 : 2 : use_role = AH->use_role;
1224 : :
1225 : : /* Set the role if requested */
852 tgl@sss.pgh.pa.us 1226 [ + + ]: 190 : if (use_role)
1227 : : {
4461 rhaas@postgresql.org 1228 : 5 : PQExpBuffer query = createPQExpBuffer();
1229 : :
1230 : 5 : appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
4450 1231 : 5 : ExecuteSqlStatement(AH, query->data);
4461 1232 : 5 : destroyPQExpBuffer(query);
1233 : :
1234 : : /* save it for possible later use by parallel workers */
4039 andrew@dunslane.net 1235 [ + + ]: 5 : if (!AH->use_role)
2874 tgl@sss.pgh.pa.us 1236 : 3 : AH->use_role = pg_strdup(use_role);
1237 : : }
1238 : :
1239 : : /* Set the datestyle to ISO to ensure the dump's portability */
4450 rhaas@postgresql.org 1240 : 190 : ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1241 : :
1242 : : /* Likewise, avoid using sql_standard intervalstyle */
852 tgl@sss.pgh.pa.us 1243 : 190 : ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1244 : :
1245 : : /*
1246 : : * Use an explicitly specified extra_float_digits if it has been provided.
1247 : : * Otherwise, set extra_float_digits so that we can dump float data
1248 : : * exactly (given correctly implemented float I/O code, anyway).
1249 : : */
1882 andrew@dunslane.net 1250 [ - + ]: 190 : if (have_extra_float_digits)
1251 : : {
1882 andrew@dunslane.net 1252 :UBC 0 : PQExpBuffer q = createPQExpBuffer();
1253 : :
1254 : 0 : appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1255 : : extra_float_digits);
1256 : 0 : ExecuteSqlStatement(AH, q->data);
1257 : 0 : destroyPQExpBuffer(q);
1258 : : }
1259 : : else
852 tgl@sss.pgh.pa.us 1260 :CBC 190 : ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1261 : :
1262 : : /*
1263 : : * Disable synchronized scanning, to prevent unpredictable changes in row
1264 : : * ordering across a dump and reload.
1265 : : */
1266 : 190 : ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1267 : :
1268 : : /*
1269 : : * Disable timeouts if supported.
1270 : : */
2741 1271 : 190 : ExecuteSqlStatement(AH, "SET statement_timeout = 0");
4047 1272 [ + - ]: 190 : if (AH->remoteVersion >= 90300)
1273 : 190 : ExecuteSqlStatement(AH, "SET lock_timeout = 0");
2860 1274 [ + - ]: 190 : if (AH->remoteVersion >= 90600)
1275 : 190 : ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
59 akorotkov@postgresql 1276 [ + - ]:GNC 190 : if (AH->remoteVersion >= 170000)
1277 : 190 : ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
1278 : :
1279 : : /*
1280 : : * Quote all identifiers, if requested.
1281 : : */
852 tgl@sss.pgh.pa.us 1282 [ + + ]:CBC 190 : if (quote_all_identifiers)
4450 rhaas@postgresql.org 1283 : 12 : ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1284 : :
1285 : : /*
1286 : : * Adjust row-security mode, if supported.
1287 : : */
3343 tgl@sss.pgh.pa.us 1288 [ + - ]: 190 : if (AH->remoteVersion >= 90500)
1289 : : {
1290 [ - + ]: 190 : if (dopt->enable_row_security)
3343 tgl@sss.pgh.pa.us 1291 :UBC 0 : ExecuteSqlStatement(AH, "SET row_security = on");
1292 : : else
3343 tgl@sss.pgh.pa.us 1293 :CBC 190 : ExecuteSqlStatement(AH, "SET row_security = off");
1294 : : }
1295 : :
1296 : : /*
1297 : : * Initialize prepared-query state to "nothing prepared". We do this here
1298 : : * so that a parallel dump worker will have its own state.
1299 : : */
860 1300 : 190 : AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
1301 : :
1302 : : /*
1303 : : * Start transaction-snapshot mode transaction to dump consistent data.
1304 : : */
4039 andrew@dunslane.net 1305 : 190 : ExecuteSqlStatement(AH, "BEGIN");
1306 : :
1307 : : /*
1308 : : * To support the combination of serializable_deferrable with the jobs
1309 : : * option we use REPEATABLE READ for the worker connections that are
1310 : : * passed a snapshot. As long as the snapshot is acquired in a
1311 : : * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1312 : : * REPEATABLE READ transaction provides the appropriate integrity
1313 : : * guarantees. This is a kluge, but safe for back-patching.
1314 : : */
852 tgl@sss.pgh.pa.us 1315 [ - + - - ]: 190 : if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
852 tgl@sss.pgh.pa.us 1316 :UBC 0 : ExecuteSqlStatement(AH,
1317 : : "SET TRANSACTION ISOLATION LEVEL "
1318 : : "SERIALIZABLE, READ ONLY, DEFERRABLE");
1319 : : else
4039 andrew@dunslane.net 1320 :CBC 190 : ExecuteSqlStatement(AH,
1321 : : "SET TRANSACTION ISOLATION LEVEL "
1322 : : "REPEATABLE READ, READ ONLY");
1323 : :
1324 : : /*
1325 : : * If user specified a snapshot to use, select that. In a parallel dump
1326 : : * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1327 : : * is already set (if the server can handle it) and we should use that.
1328 : : */
3436 simon@2ndQuadrant.co 1329 [ - + ]: 190 : if (dumpsnapshot)
2874 tgl@sss.pgh.pa.us 1330 :UBC 0 : AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1331 : :
3436 simon@2ndQuadrant.co 1332 [ + + ]:CBC 190 : if (AH->sync_snapshot_id)
1333 : : {
1334 : 18 : PQExpBuffer query = createPQExpBuffer();
1335 : :
1746 drowley@postgresql.o 1336 : 18 : appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
3436 simon@2ndQuadrant.co 1337 : 18 : appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1338 : 18 : ExecuteSqlStatement(AH, query->data);
1339 : 18 : destroyPQExpBuffer(query);
1340 : : }
851 tgl@sss.pgh.pa.us 1341 [ + + ]: 172 : else if (AH->numWorkers > 1)
1342 : : {
2433 peter_e@gmx.net 1343 [ - + - - ]: 9 : if (AH->isStandby && AH->remoteVersion < 100000)
737 tgl@sss.pgh.pa.us 1344 :UBC 0 : pg_fatal("parallel dumps from standby servers are not supported by this server version");
3436 simon@2ndQuadrant.co 1345 :CBC 9 : AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1346 : : }
4039 andrew@dunslane.net 1347 : 190 : }
1348 : :
1349 : : /* Set up connection for a parallel worker process */
1350 : : static void
2874 tgl@sss.pgh.pa.us 1351 : 18 : setupDumpWorker(Archive *AH)
1352 : : {
1353 : : /*
1354 : : * We want to re-select all the same values the leader connection is
1355 : : * using. We'll have inherited directly-usable values in
1356 : : * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1357 : : * inherited encoding value back to a string to pass to setup_connection.
1358 : : */
1359 : 18 : setup_connection(AH,
1360 : : pg_encoding_to_char(AH->encoding),
1361 : : NULL,
1362 : : NULL);
4039 andrew@dunslane.net 1363 : 18 : }
1364 : :
1365 : : static char *
1366 : 9 : get_synchronized_snapshot(Archive *fout)
1367 : : {
2874 tgl@sss.pgh.pa.us 1368 : 9 : char *query = "SELECT pg_catalog.pg_export_snapshot()";
1369 : : char *result;
1370 : : PGresult *res;
1371 : :
4039 andrew@dunslane.net 1372 : 9 : res = ExecuteSqlQueryForSingleRow(fout, query);
2874 tgl@sss.pgh.pa.us 1373 : 9 : result = pg_strdup(PQgetvalue(res, 0, 0));
4039 andrew@dunslane.net 1374 : 9 : PQclear(res);
1375 : :
1376 : 9 : return result;
1377 : : }
1378 : :
1379 : : static ArchiveFormat
4830 heikki.linnakangas@i 1380 : 181 : parseArchiveFormat(const char *format, ArchiveMode *mode)
1381 : : {
1382 : : ArchiveFormat archiveFormat;
1383 : :
1384 : 181 : *mode = archModeWrite;
1385 : :
1386 [ + + - + ]: 181 : if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1387 : : {
1388 : : /* This is used by pg_dumpall, and is not documented */
1389 : 43 : archiveFormat = archNull;
1390 : 43 : *mode = archModeAppend;
1391 : : }
1392 [ + + ]: 138 : else if (pg_strcasecmp(format, "c") == 0)
1393 : 4 : archiveFormat = archCustom;
1394 [ + + ]: 134 : else if (pg_strcasecmp(format, "custom") == 0)
1395 : 16 : archiveFormat = archCustom;
1396 [ + + ]: 118 : else if (pg_strcasecmp(format, "d") == 0)
1397 : 7 : archiveFormat = archDirectory;
1398 [ + + ]: 111 : else if (pg_strcasecmp(format, "directory") == 0)
1399 : 4 : archiveFormat = archDirectory;
1400 [ + + ]: 107 : else if (pg_strcasecmp(format, "p") == 0)
1401 : 99 : archiveFormat = archNull;
1402 [ + + ]: 8 : else if (pg_strcasecmp(format, "plain") == 0)
1403 : 4 : archiveFormat = archNull;
1404 [ + + ]: 4 : else if (pg_strcasecmp(format, "t") == 0)
1405 : 2 : archiveFormat = archTar;
1406 [ + + ]: 2 : else if (pg_strcasecmp(format, "tar") == 0)
1407 : 1 : archiveFormat = archTar;
1408 : : else
737 tgl@sss.pgh.pa.us 1409 : 1 : pg_fatal("invalid output format \"%s\" specified", format);
4830 heikki.linnakangas@i 1410 : 180 : return archiveFormat;
1411 : : }
1412 : :
1413 : : /*
1414 : : * Find the OIDs of all schemas matching the given list of patterns,
1415 : : * and append them to the given OID list.
1416 : : */
1417 : : static void
4451 rhaas@postgresql.org 1418 : 181 : expand_schema_name_patterns(Archive *fout,
1419 : : SimpleStringList *patterns,
1420 : : SimpleOidList *oids,
1421 : : bool strict_names)
1422 : : {
1423 : : PQExpBuffer query;
1424 : : PGresult *res;
1425 : : SimpleStringListCell *cell;
1426 : : int i;
1427 : :
6397 tgl@sss.pgh.pa.us 1428 [ + + ]: 181 : if (patterns->head == NULL)
1429 : 162 : return; /* nothing to do */
1430 : :
1431 : 19 : query = createPQExpBuffer();
1432 : :
1433 : : /*
1434 : : * The loop below runs multiple SELECTs might sometimes result in
1435 : : * duplicate entries in the OID list, but we don't care.
1436 : : */
1437 : :
1438 [ + + ]: 32 : for (cell = patterns->head; cell; cell = cell->next)
1439 : : {
1440 : : PQExpBufferData dbbuf;
1441 : : int dotcnt;
1442 : :
1746 drowley@postgresql.o 1443 : 19 : appendPQExpBufferStr(query,
1444 : : "SELECT oid FROM pg_catalog.pg_namespace n\n");
725 rhaas@postgresql.org 1445 : 19 : initPQExpBuffer(&dbbuf);
4441 1446 : 19 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1447 : : false, NULL, "n.nspname", NULL, NULL, &dbbuf,
1448 : : &dotcnt);
725 1449 [ + + ]: 19 : if (dotcnt > 1)
1450 : 2 : pg_fatal("improper qualified name (too many dotted names): %s",
1451 : : cell->val);
1452 [ + + ]: 17 : else if (dotcnt == 1)
1453 : 3 : prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
1454 : 14 : termPQExpBuffer(&dbbuf);
1455 : :
3135 teodor@sigaev.ru 1456 : 14 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1457 [ + + + - ]: 14 : if (strict_names && PQntuples(res) == 0)
737 tgl@sss.pgh.pa.us 1458 : 1 : pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
1459 : :
3135 teodor@sigaev.ru 1460 [ + + ]: 25 : for (i = 0; i < PQntuples(res); i++)
1461 : : {
1462 : 12 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1463 : : }
1464 : :
1465 : 13 : PQclear(res);
1466 : 13 : resetPQExpBuffer(query);
1467 : : }
1468 : :
6397 tgl@sss.pgh.pa.us 1469 : 13 : destroyPQExpBuffer(query);
1470 : : }
1471 : :
1472 : : /*
1473 : : * Find the OIDs of all extensions matching the given list of patterns,
1474 : : * and append them to the given OID list.
1475 : : */
1476 : : static void
1110 michael@paquier.xyz 1477 : 161 : expand_extension_name_patterns(Archive *fout,
1478 : : SimpleStringList *patterns,
1479 : : SimpleOidList *oids,
1480 : : bool strict_names)
1481 : : {
1482 : : PQExpBuffer query;
1483 : : PGresult *res;
1484 : : SimpleStringListCell *cell;
1485 : : int i;
1486 : :
1487 [ + + ]: 161 : if (patterns->head == NULL)
1110 michael@paquier.xyz 1488 :GBC 154 : return; /* nothing to do */
1489 : :
1110 michael@paquier.xyz 1490 :CBC 7 : query = createPQExpBuffer();
1491 : :
1492 : : /*
1493 : : * The loop below runs multiple SELECTs might sometimes result in
1494 : : * duplicate entries in the OID list, but we don't care.
1495 : : */
1496 [ + + ]: 14 : for (cell = patterns->head; cell; cell = cell->next)
1497 : : {
1498 : : int dotcnt;
1499 : :
1500 : 7 : appendPQExpBufferStr(query,
1501 : : "SELECT oid FROM pg_catalog.pg_extension e\n");
1502 : 7 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1503 : : false, NULL, "e.extname", NULL, NULL, NULL,
1504 : : &dotcnt);
725 rhaas@postgresql.org 1505 [ - + ]: 7 : if (dotcnt > 0)
725 rhaas@postgresql.org 1506 :UBC 0 : pg_fatal("improper qualified name (too many dotted names): %s",
1507 : : cell->val);
1508 : :
1110 michael@paquier.xyz 1509 :CBC 7 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1510 [ - + - - ]: 7 : if (strict_names && PQntuples(res) == 0)
737 tgl@sss.pgh.pa.us 1511 :UBC 0 : pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
1512 : :
1110 michael@paquier.xyz 1513 [ + + ]:CBC 13 : for (i = 0; i < PQntuples(res); i++)
1514 : : {
1515 : 6 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1516 : : }
1517 : :
1518 : 7 : PQclear(res);
1519 : 7 : resetPQExpBuffer(query);
1520 : : }
1521 : :
1522 : 7 : destroyPQExpBuffer(query);
1523 : : }
1524 : :
1525 : : /*
1526 : : * Find the OIDs of all foreign servers matching the given list of patterns,
1527 : : * and append them to the given OID list.
1528 : : */
1529 : : static void
1481 alvherre@alvh.no-ip. 1530 : 158 : expand_foreign_server_name_patterns(Archive *fout,
1531 : : SimpleStringList *patterns,
1532 : : SimpleOidList *oids)
1533 : : {
1534 : : PQExpBuffer query;
1535 : : PGresult *res;
1536 : : SimpleStringListCell *cell;
1537 : : int i;
1538 : :
1539 [ + + ]: 158 : if (patterns->head == NULL)
1540 : 155 : return; /* nothing to do */
1541 : :
1542 : 3 : query = createPQExpBuffer();
1543 : :
1544 : : /*
1545 : : * The loop below runs multiple SELECTs might sometimes result in
1546 : : * duplicate entries in the OID list, but we don't care.
1547 : : */
1548 : :
1549 [ + + ]: 5 : for (cell = patterns->head; cell; cell = cell->next)
1550 : : {
1551 : : int dotcnt;
1552 : :
1277 drowley@postgresql.o 1553 : 3 : appendPQExpBufferStr(query,
1554 : : "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
1481 alvherre@alvh.no-ip. 1555 : 3 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1556 : : false, NULL, "s.srvname", NULL, NULL, NULL,
1557 : : &dotcnt);
725 rhaas@postgresql.org 1558 [ - + ]: 3 : if (dotcnt > 0)
725 rhaas@postgresql.org 1559 :UBC 0 : pg_fatal("improper qualified name (too many dotted names): %s",
1560 : : cell->val);
1561 : :
1481 alvherre@alvh.no-ip. 1562 :CBC 3 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1563 [ + + ]: 3 : if (PQntuples(res) == 0)
737 tgl@sss.pgh.pa.us 1564 :GBC 1 : pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
1565 : :
1481 alvherre@alvh.no-ip. 1566 [ + + ]:CBC 4 : for (i = 0; i < PQntuples(res); i++)
1567 : 2 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1568 : :
1569 : 2 : PQclear(res);
1570 : 2 : resetPQExpBuffer(query);
1571 : : }
1572 : :
1573 : 2 : destroyPQExpBuffer(query);
1574 : : }
1575 : :
1576 : : /*
1577 : : * Find the OIDs of all tables matching the given list of patterns,
1578 : : * and append them to the given OID list. See also expand_dbname_patterns()
1579 : : * in pg_dumpall.c
1580 : : */
1581 : : static void
4450 rhaas@postgresql.org 1582 : 957 : expand_table_name_patterns(Archive *fout,
1583 : : SimpleStringList *patterns, SimpleOidList *oids,
1584 : : bool strict_names, bool with_child_tables)
1585 : : {
1586 : : PQExpBuffer query;
1587 : : PGresult *res;
1588 : : SimpleStringListCell *cell;
1589 : : int i;
1590 : :
6397 tgl@sss.pgh.pa.us 1591 [ + + ]: 957 : if (patterns->head == NULL)
1592 : 928 : return; /* nothing to do */
1593 : :
1594 : 29 : query = createPQExpBuffer();
1595 : :
1596 : : /*
1597 : : * this might sometimes result in duplicate entries in the OID list, but
1598 : : * we don't care.
1599 : : */
1600 : :
1601 [ + + ]: 59 : for (cell = patterns->head; cell; cell = cell->next)
1602 : : {
1603 : : PQExpBufferData dbbuf;
1604 : : int dotcnt;
1605 : :
1606 : : /*
1607 : : * Query must remain ABSOLUTELY devoid of unqualified names. This
1608 : : * would be unnecessary given a pg_table_is_visible() variant taking a
1609 : : * search_path argument.
1610 : : *
1611 : : * For with_child_tables, we start with the basic query's results and
1612 : : * recursively search the inheritance tree to add child tables.
1613 : : */
397 1614 [ + + ]: 35 : if (with_child_tables)
1615 : : {
1616 : 6 : appendPQExpBuffer(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
1617 : : }
1618 : :
6397 1619 : 35 : appendPQExpBuffer(query,
1620 : : "SELECT c.oid"
1621 : : "\nFROM pg_catalog.pg_class c"
1622 : : "\n LEFT JOIN pg_catalog.pg_namespace n"
1623 : : "\n ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1624 : : "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1625 : : "\n (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1626 : : RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1627 : : RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1628 : : RELKIND_PARTITIONED_TABLE);
725 rhaas@postgresql.org 1629 : 35 : initPQExpBuffer(&dbbuf);
4441 1630 : 35 : processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1631 : : false, "n.nspname", "c.relname", NULL,
1632 : : "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
1633 : : &dotcnt);
725 1634 [ + + ]: 35 : if (dotcnt > 2)
1635 : 1 : pg_fatal("improper relation name (too many dotted names): %s",
1636 : : cell->val);
1637 [ + + ]: 34 : else if (dotcnt == 2)
1638 : 2 : prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
1639 : 32 : termPQExpBuffer(&dbbuf);
1640 : :
397 tgl@sss.pgh.pa.us 1641 [ + + ]: 32 : if (with_child_tables)
1642 : : {
1643 : 6 : appendPQExpBuffer(query, "UNION"
1644 : : "\nSELECT i.inhrelid"
1645 : : "\nFROM partition_tree p"
1646 : : "\n JOIN pg_catalog.pg_inherits i"
1647 : : "\n ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
1648 : : "\n)"
1649 : : "\nSELECT relid FROM partition_tree");
1650 : : }
1651 : :
2239 noah@leadboat.com 1652 : 32 : ExecuteSqlStatement(fout, "RESET search_path");
3135 teodor@sigaev.ru 1653 : 32 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2239 noah@leadboat.com 1654 : 32 : PQclear(ExecuteSqlQueryForSingleRow(fout,
1655 : : ALWAYS_SECURE_SEARCH_PATH_SQL));
3135 teodor@sigaev.ru 1656 [ + + + + ]: 32 : if (strict_names && PQntuples(res) == 0)
737 tgl@sss.pgh.pa.us 1657 : 2 : pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
1658 : :
3135 teodor@sigaev.ru 1659 [ + + ]: 74 : for (i = 0; i < PQntuples(res); i++)
1660 : : {
1661 : 44 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1662 : : }
1663 : :
1664 : 30 : PQclear(res);
1665 : 30 : resetPQExpBuffer(query);
1666 : : }
1667 : :
6397 tgl@sss.pgh.pa.us 1668 : 24 : destroyPQExpBuffer(query);
1669 : : }
1670 : :
1671 : : /*
1672 : : * Verifies that the connected database name matches the given database name,
1673 : : * and if not, dies with an error about the given pattern.
1674 : : *
1675 : : * The 'dbname' argument should be a literal name parsed from 'pattern'.
1676 : : */
1677 : : static void
725 rhaas@postgresql.org 1678 : 5 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
1679 : : {
1680 : : const char *db;
1681 : :
1682 : 5 : db = PQdb(conn);
1683 [ - + ]: 5 : if (db == NULL)
725 rhaas@postgresql.org 1684 :UBC 0 : pg_fatal("You are currently not connected to a database.");
1685 : :
725 rhaas@postgresql.org 1686 [ + - ]:CBC 5 : if (strcmp(db, dbname) != 0)
1687 : 5 : pg_fatal("cross-database references are not implemented: %s",
1688 : : pattern);
725 rhaas@postgresql.org 1689 :UBC 0 : }
1690 : :
1691 : : /*
1692 : : * checkExtensionMembership
1693 : : * Determine whether object is an extension member, and if so,
1694 : : * record an appropriate dependency and set the object's dump flag.
1695 : : *
1696 : : * It's important to call this for each object that could be an extension
1697 : : * member. Generally, we integrate this with determining the object's
1698 : : * to-be-dumped-ness, since extension membership overrides other rules for that.
1699 : : *
1700 : : * Returns true if object is an extension member, else false.
1701 : : */
1702 : : static bool
2930 sfrost@snowman.net 1703 :CBC 582840 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1704 : : {
3014 tgl@sss.pgh.pa.us 1705 : 582840 : ExtensionInfo *ext = findOwningExtension(dobj->catId);
1706 : :
1707 [ + + ]: 582840 : if (ext == NULL)
1708 : 582143 : return false;
1709 : :
1710 : 697 : dobj->ext_member = true;
1711 : :
1712 : : /* Record dependency so that getDependencies needn't deal with that */
1713 : 697 : addObjectDependency(dobj, ext->dobj.dumpId);
1714 : :
1715 : : /*
1716 : : * In 9.6 and above, mark the member object to have any non-initial ACLs
1717 : : * dumped. (Any initial ACLs will be removed later, using data from
1718 : : * pg_init_privs, so that we'll dump only the delta from the extension's
1719 : : * initial setup.)
1720 : : *
1721 : : * Prior to 9.6, we do not include any extension member components.
1722 : : *
1723 : : * In binary upgrades, we still dump all components of the members
1724 : : * individually, since the idea is to exactly reproduce the database
1725 : : * contents rather than replace the extension contents with something
1726 : : * different.
1727 : : *
1728 : : * Note: it might be interesting someday to implement storage and delta
1729 : : * dumping of extension members' RLS policies and/or security labels.
1730 : : * However there is a pitfall for RLS policies: trying to dump them
1731 : : * requires getting a lock on their tables, and the calling user might not
1732 : : * have privileges for that. We need no lock to examine a table's ACLs,
1733 : : * so the current feature doesn't have a problem of that sort.
1734 : : */
2900 sfrost@snowman.net 1735 [ + + ]: 697 : if (fout->dopt->binary_upgrade)
3014 tgl@sss.pgh.pa.us 1736 : 76 : dobj->dump = ext->dobj.dump;
1737 : : else
1738 : : {
2900 sfrost@snowman.net 1739 [ - + ]: 621 : if (fout->remoteVersion < 90600)
2900 sfrost@snowman.net 1740 :UBC 0 : dobj->dump = DUMP_COMPONENT_NONE;
1741 : : else
153 tgl@sss.pgh.pa.us 1742 :CBC 621 : dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
1743 : : }
1744 : :
3014 1745 : 697 : return true;
1746 : : }
1747 : :
1748 : : /*
1749 : : * selectDumpableNamespace: policy-setting subroutine
1750 : : * Mark a namespace as to be dumped or not
1751 : : */
1752 : : static void
2930 sfrost@snowman.net 1753 : 1152 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1754 : : {
1755 : : /*
1756 : : * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
1757 : : * and (for --clean) a DROP SCHEMA statement. (In the absence of
1758 : : * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
1759 : : */
1021 noah@leadboat.com 1760 : 1152 : nsinfo->create = true;
1761 : :
1762 : : /*
1763 : : * If specific tables are being dumped, do not dump any complete
1764 : : * namespaces. If specific namespaces are being dumped, dump just those
1765 : : * namespaces. Otherwise, dump all non-system namespaces.
1766 : : */
6397 tgl@sss.pgh.pa.us 1767 [ + + ]: 1152 : if (table_include_oids.head != NULL)
2930 sfrost@snowman.net 1768 : 50 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
6397 tgl@sss.pgh.pa.us 1769 [ + + ]: 1102 : else if (schema_include_oids.head != NULL)
2930 sfrost@snowman.net 1770 : 49 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1771 : 49 : simple_oid_list_member(&schema_include_oids,
1772 : : nsinfo->dobj.catId.oid) ?
1773 [ + + ]: 49 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1774 [ + - ]: 1053 : else if (fout->remoteVersion >= 90600 &&
2775 tgl@sss.pgh.pa.us 1775 [ + + ]: 1053 : strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1776 : : {
1777 : : /*
1778 : : * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1779 : : * they are interesting (and not the original ACLs which were set at
1780 : : * initdb time, see pg_init_privs).
1781 : : */
2930 sfrost@snowman.net 1782 : 136 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1783 : : }
6397 tgl@sss.pgh.pa.us 1784 [ + + ]: 917 : else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1785 [ + + ]: 417 : strcmp(nsinfo->dobj.name, "information_schema") == 0)
1786 : : {
1787 : : /* Other system schemas don't get dumped */
2930 sfrost@snowman.net 1788 : 636 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1789 : : }
2271 tgl@sss.pgh.pa.us 1790 [ + + ]: 281 : else if (strcmp(nsinfo->dobj.name, "public") == 0)
1791 : : {
1792 : : /*
1793 : : * The public schema is a strange beast that sits in a sort of
1794 : : * no-mans-land between being a system object and a user object.
1795 : : * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
1796 : : * a comment and an indication of ownership. If the owner is the
1797 : : * default, omit that superfluous DUMP_COMPONENT_DEFINITION. Before
1798 : : * v15, the default owner was BOOTSTRAP_SUPERUSERID.
1799 : : */
1021 noah@leadboat.com 1800 : 132 : nsinfo->create = false;
1801 : 132 : nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
948 1802 [ + + ]: 132 : if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
1021 1803 : 89 : nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
2271 tgl@sss.pgh.pa.us 1804 : 132 : nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
1805 : :
1806 : : /*
1807 : : * Also, make like it has a comment even if it doesn't; this is so
1808 : : * that we'll emit a command to drop the comment, if appropriate.
1809 : : * (Without this, we'd not call dumpCommentExtended for it.)
1810 : : */
860 1811 : 132 : nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
1812 : : }
1813 : : else
2930 sfrost@snowman.net 1814 : 149 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1815 : :
1816 : : /*
1817 : : * In any case, a namespace can be excluded by an exclusion switch
1818 : : */
1819 [ + + + + ]: 1578 : if (nsinfo->dobj.dump_contains &&
6397 tgl@sss.pgh.pa.us 1820 : 426 : simple_oid_list_member(&schema_exclude_oids,
1821 : : nsinfo->dobj.catId.oid))
2930 sfrost@snowman.net 1822 : 3 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1823 : :
1824 : : /*
1825 : : * If the schema belongs to an extension, allow extension membership to
1826 : : * override the dump decision for the schema itself. However, this does
1827 : : * not change dump_contains, so this won't change what we do with objects
1828 : : * within the schema. (If they belong to the extension, they'll get
1829 : : * suppressed by it, otherwise not.)
1830 : : */
2775 tgl@sss.pgh.pa.us 1831 : 1152 : (void) checkExtensionMembership(&nsinfo->dobj, fout);
6397 1832 : 1152 : }
1833 : :
1834 : : /*
1835 : : * selectDumpableTable: policy-setting subroutine
1836 : : * Mark a table as to be dumped or not
1837 : : */
1838 : : static void
2930 sfrost@snowman.net 1839 : 39371 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1840 : : {
1841 [ + + ]: 39371 : if (checkExtensionMembership(&tbinfo->dobj, fout))
3014 tgl@sss.pgh.pa.us 1842 : 225 : return; /* extension membership overrides all else */
1843 : :
1844 : : /*
1845 : : * If specific tables are being dumped, dump just those tables; else, dump
1846 : : * according to the parent namespace's dump flag.
1847 : : */
6397 1848 [ + + ]: 39146 : if (table_include_oids.head != NULL)
1849 : 5052 : tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1850 : : tbinfo->dobj.catId.oid) ?
2930 sfrost@snowman.net 1851 [ + + ]: 2526 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1852 : : else
1853 : 36620 : tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1854 : :
1855 : : /*
1856 : : * In any case, a table can be excluded by an exclusion switch
1857 : : */
6397 tgl@sss.pgh.pa.us 1858 [ + + + + ]: 64442 : if (tbinfo->dobj.dump &&
1859 : 25296 : simple_oid_list_member(&table_exclude_oids,
1860 : : tbinfo->dobj.catId.oid))
2930 sfrost@snowman.net 1861 : 12 : tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1862 : : }
1863 : :
1864 : : /*
1865 : : * selectDumpableType: policy-setting subroutine
1866 : : * Mark a type as to be dumped or not
1867 : : *
1868 : : * If it's a table's rowtype or an autogenerated array type, we also apply a
1869 : : * special type code to facilitate sorting into the desired order. (We don't
1870 : : * want to consider those to be ordinary types because that would bring tables
1871 : : * up into the datatype part of the dump order.) We still set the object's
1872 : : * dump flag; that's not going to cause the dummy type to be dumped, but we
1873 : : * need it so that casts involving such types will be dumped correctly -- see
1874 : : * dumpCast. This means the flag should be set the same as for the underlying
1875 : : * object (the table or base type).
1876 : : */
1877 : : static void
1878 : 108802 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1879 : : {
1880 : : /* skip complex types, except for standalone composite types */
5226 bruce@momjian.us 1881 [ + + ]: 108802 : if (OidIsValid(tyinfo->typrelid) &&
1882 [ + + ]: 38749 : tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1883 : : {
4562 tgl@sss.pgh.pa.us 1884 : 38598 : TableInfo *tytable = findTableByOid(tyinfo->typrelid);
1885 : :
5226 bruce@momjian.us 1886 : 38598 : tyinfo->dobj.objType = DO_DUMMY_TYPE;
4562 tgl@sss.pgh.pa.us 1887 [ + - ]: 38598 : if (tytable != NULL)
1888 : 38598 : tyinfo->dobj.dump = tytable->dobj.dump;
1889 : : else
2930 sfrost@snowman.net 1890 :UBC 0 : tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
4562 tgl@sss.pgh.pa.us 1891 :CBC 38598 : return;
1892 : : }
1893 : :
1894 : : /* skip auto-generated array and multirange types */
1211 akorotkov@postgresql 1895 [ + + + + ]: 70204 : if (tyinfo->isArray || tyinfo->isMultirange)
1896 : : {
5226 bruce@momjian.us 1897 : 53170 : tyinfo->dobj.objType = DO_DUMMY_TYPE;
1898 : :
1899 : : /*
1900 : : * Fall through to set the dump flag; we assume that the subsequent
1901 : : * rules will do the same thing as they would for the array's base
1902 : : * type or multirange's range type. (We cannot reliably look up the
1903 : : * base type here, since getTypes may not have processed it yet.)
1904 : : */
1905 : : }
1906 : :
2930 sfrost@snowman.net 1907 [ + + ]: 70204 : if (checkExtensionMembership(&tyinfo->dobj, fout))
3014 tgl@sss.pgh.pa.us 1908 : 150 : return; /* extension membership overrides all else */
1909 : :
1910 : : /* Dump based on if the contents of the namespace are being dumped */
2930 sfrost@snowman.net 1911 : 70054 : tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1912 : : }
1913 : :
1914 : : /*
1915 : : * selectDumpableDefaultACL: policy-setting subroutine
1916 : : * Mark a default ACL as to be dumped or not
1917 : : *
1918 : : * For per-schema default ACLs, dump if the schema is to be dumped.
1919 : : * Otherwise dump if we are dumping "everything". Note that dataOnly
1920 : : * and aclsSkip are checked separately.
1921 : : */
1922 : : static void
3014 tgl@sss.pgh.pa.us 1923 : 184 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1924 : : {
1925 : : /* Default ACLs can't be extension members */
1926 : :
5305 1927 [ + + ]: 184 : if (dinfo->dobj.namespace)
1928 : : /* default ACLs are considered part of the namespace */
2900 sfrost@snowman.net 1929 : 92 : dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1930 : : else
2930 1931 : 92 : dinfo->dobj.dump = dopt->include_everything ?
1932 [ + + ]: 92 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
5305 tgl@sss.pgh.pa.us 1933 : 184 : }
1934 : :
1935 : : /*
1936 : : * selectDumpableCast: policy-setting subroutine
1937 : : * Mark a cast as to be dumped or not
1938 : : *
1939 : : * Casts do not belong to any particular namespace (since they haven't got
1940 : : * names), nor do they have identifiable owners. To distinguish user-defined
1941 : : * casts from built-in ones, we must resort to checking whether the cast's
1942 : : * OID is in the range reserved for initdb.
1943 : : */
1944 : : static void
2930 sfrost@snowman.net 1945 : 34641 : selectDumpableCast(CastInfo *cast, Archive *fout)
1946 : : {
1947 [ - + ]: 34641 : if (checkExtensionMembership(&cast->dobj, fout))
3014 tgl@sss.pgh.pa.us 1948 :UBC 0 : return; /* extension membership overrides all else */
1949 : :
1950 : : /*
1951 : : * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1952 : : * support ACLs currently.
1953 : : */
2671 sfrost@snowman.net 1954 [ + + ]:CBC 34641 : if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2930 1955 : 34565 : cast->dobj.dump = DUMP_COMPONENT_NONE;
1956 : : else
1957 : 76 : cast->dobj.dump = fout->dopt->include_everything ?
1958 [ + + ]: 76 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1959 : : }
1960 : :
1961 : : /*
1962 : : * selectDumpableProcLang: policy-setting subroutine
1963 : : * Mark a procedural language as to be dumped or not
1964 : : *
1965 : : * Procedural languages do not belong to any particular namespace. To
1966 : : * identify built-in languages, we must resort to checking whether the
1967 : : * language's OID is in the range reserved for initdb.
1968 : : */
1969 : : static void
1970 : 201 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1971 : : {
1972 [ + + ]: 201 : if (checkExtensionMembership(&plang->dobj, fout))
3014 tgl@sss.pgh.pa.us 1973 : 155 : return; /* extension membership overrides all else */
1974 : :
1975 : : /*
1976 : : * Only include procedural languages when we are dumping everything.
1977 : : *
1978 : : * For from-initdb procedural languages, only include ACLs, as we do for
1979 : : * the pg_catalog namespace. We need this because procedural languages do
1980 : : * not live in any namespace.
1981 : : */
2900 sfrost@snowman.net 1982 [ + + ]: 46 : if (!fout->dopt->include_everything)
2930 1983 : 8 : plang->dobj.dump = DUMP_COMPONENT_NONE;
1984 : : else
1985 : : {
2671 1986 [ - + ]: 38 : if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2900 sfrost@snowman.net 1987 :UBC 0 : plang->dobj.dump = fout->remoteVersion < 90600 ?
1988 [ # # ]: 0 : DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1989 : : else
2900 sfrost@snowman.net 1990 :CBC 38 : plang->dobj.dump = DUMP_COMPONENT_ALL;
1991 : : }
1992 : : }
1993 : :
1994 : : /*
1995 : : * selectDumpableAccessMethod: policy-setting subroutine
1996 : : * Mark an access method as to be dumped or not
1997 : : *
1998 : : * Access methods do not belong to any particular namespace. To identify
1999 : : * built-in access methods, we must resort to checking whether the
2000 : : * method's OID is in the range reserved for initdb.
2001 : : */
2002 : : static void
2930 2003 : 1207 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
2004 : : {
2005 [ + + ]: 1207 : if (checkExtensionMembership(&method->dobj, fout))
2944 alvherre@alvh.no-ip. 2006 : 25 : return; /* extension membership overrides all else */
2007 : :
2008 : : /*
2009 : : * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
2010 : : * they do not support ACLs currently.
2011 : : */
2671 sfrost@snowman.net 2012 [ + + ]: 1182 : if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2930 2013 : 1085 : method->dobj.dump = DUMP_COMPONENT_NONE;
2014 : : else
2015 : 97 : method->dobj.dump = fout->dopt->include_everything ?
2016 [ + + ]: 97 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2017 : : }
2018 : :
2019 : : /*
2020 : : * selectDumpableExtension: policy-setting subroutine
2021 : : * Mark an extension as to be dumped or not
2022 : : *
2023 : : * Built-in extensions should be skipped except for checking ACLs, since we
2024 : : * assume those will already be installed in the target database. We identify
2025 : : * such extensions by their having OIDs in the range reserved for initdb.
2026 : : * We dump all user-added extensions by default. No extensions are dumped
2027 : : * if include_everything is false (i.e., a --schema or --table switch was
2028 : : * given), except if --extension specifies a list of extensions to dump.
2029 : : */
2030 : : static void
3014 tgl@sss.pgh.pa.us 2031 : 181 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
2032 : : {
2033 : : /*
2034 : : * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
2035 : : * change permissions on their member objects, if they wish to, and have
2036 : : * those changes preserved.
2037 : : */
2271 2038 [ + + ]: 181 : if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2900 sfrost@snowman.net 2039 : 156 : extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
2040 : : else
2041 : : {
2042 : : /* check if there is a list of extensions to dump */
1110 michael@paquier.xyz 2043 [ + + ]: 25 : if (extension_include_oids.head != NULL)
2044 : 4 : extinfo->dobj.dump = extinfo->dobj.dump_contains =
2045 : 4 : simple_oid_list_member(&extension_include_oids,
2046 : : extinfo->dobj.catId.oid) ?
2047 [ + + ]: 4 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2048 : : else
2049 : 21 : extinfo->dobj.dump = extinfo->dobj.dump_contains =
2050 : 21 : dopt->include_everything ?
2051 [ + + ]: 21 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2052 : :
2053 : : /* check that the extension is not explicitly excluded */
25 dean.a.rasheed@gmail 2054 [ + + + + ]:GNC 46 : if (extinfo->dobj.dump &&
2055 : 21 : simple_oid_list_member(&extension_exclude_oids,
2056 : : extinfo->dobj.catId.oid))
2057 : 2 : extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
2058 : : }
4790 tgl@sss.pgh.pa.us 2059 :CBC 181 : }
2060 : :
2061 : : /*
2062 : : * selectDumpablePublicationObject: policy-setting subroutine
2063 : : * Mark a publication object as to be dumped or not
2064 : : *
2065 : : * A publication can have schemas and tables which have schemas, but those are
2066 : : * ignored in decision making, because publications are only dumped when we are
2067 : : * dumping everything.
2068 : : */
2069 : : static void
900 akapila@postgresql.o 2070 : 353 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
2071 : : {
2581 peter_e@gmx.net 2072 [ - + ]: 353 : if (checkExtensionMembership(dobj, fout))
2581 peter_e@gmx.net 2073 :UBC 0 : return; /* extension membership overrides all else */
2074 : :
2581 peter_e@gmx.net 2075 :CBC 353 : dobj->dump = fout->dopt->include_everything ?
2076 [ + + ]: 353 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2077 : : }
2078 : :
2079 : : /*
2080 : : * selectDumpableStatisticsObject: policy-setting subroutine
2081 : : * Mark an extended statistics object as to be dumped or not
2082 : : *
2083 : : * We dump an extended statistics object if the schema it's in and the table
2084 : : * it's for are being dumped. (This'll need more thought if statistics
2085 : : * objects ever support cross-table stats.)
2086 : : */
2087 : : static void
107 tgl@sss.pgh.pa.us 2088 : 158 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
2089 : : {
2090 [ - + ]: 158 : if (checkExtensionMembership(&sobj->dobj, fout))
107 tgl@sss.pgh.pa.us 2091 :UBC 0 : return; /* extension membership overrides all else */
2092 : :
107 tgl@sss.pgh.pa.us 2093 :CBC 158 : sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
2094 [ + - ]: 158 : if (sobj->stattable == NULL ||
2095 [ + + ]: 158 : !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
2096 : 20 : sobj->dobj.dump = DUMP_COMPONENT_NONE;
2097 : : }
2098 : :
2099 : : /*
2100 : : * selectDumpableObject: policy-setting subroutine
2101 : : * Mark a generic dumpable object as to be dumped or not
2102 : : *
2103 : : * Use this only for object types without a special-case routine above.
2104 : : */
2105 : : static void
2930 sfrost@snowman.net 2106 : 435553 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
2107 : : {
2108 [ + + ]: 435553 : if (checkExtensionMembership(dobj, fout))
3014 tgl@sss.pgh.pa.us 2109 : 117 : return; /* extension membership overrides all else */
2110 : :
2111 : : /*
2112 : : * Default policy is to dump if parent namespace is dumpable, or for
2113 : : * non-namespace-associated items, dump if we're dumping "everything".
2114 : : */
6618 2115 [ + + ]: 435436 : if (dobj->namespace)
2930 sfrost@snowman.net 2116 : 434869 : dobj->dump = dobj->namespace->dobj.dump_contains;
2117 : : else
2118 : 567 : dobj->dump = fout->dopt->include_everything ?
2119 [ + + ]: 567 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2120 : : }
2121 : :
2122 : : /*
2123 : : * Dump a table's contents for loading using the COPY command
2124 : : * - this routine is called by the Archiver when it wants the table
2125 : : * to be dumped.
2126 : : */
2127 : : static int
1159 peter@eisentraut.org 2128 : 3479 : dumpTableData_copy(Archive *fout, const void *dcontext)
2129 : : {
7435 tgl@sss.pgh.pa.us 2130 : 3479 : TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2131 : 3479 : TableInfo *tbinfo = tdinfo->tdtable;
7347 2132 : 3479 : const char *classname = tbinfo->dobj.name;
8010 2133 : 3479 : PQExpBuffer q = createPQExpBuffer();
2134 : :
2135 : : /*
2136 : : * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
2137 : : * which uses it already.
2138 : : */
4039 andrew@dunslane.net 2139 : 3479 : PQExpBuffer clistBuf = createPQExpBuffer();
4441 rhaas@postgresql.org 2140 : 3479 : PGconn *conn = GetConnection(fout);
2141 : : PGresult *res;
2142 : : int ret;
2143 : : char *copybuf;
2144 : : const char *column_list;
2145 : :
1840 peter@eisentraut.org 2146 : 3479 : pg_log_info("dumping contents of table \"%s.%s\"",
2147 : : tbinfo->dobj.namespace->dobj.name, classname);
2148 : :
2149 : : /*
2150 : : * Specify the column list explicitly so that we have no possibility of
2151 : : * retrieving data in the wrong column order. (The default column
2152 : : * ordering of COPY will not be what we want in certain corner cases
2153 : : * involving ADD COLUMN and inheritance.)
2154 : : */
2741 tgl@sss.pgh.pa.us 2155 : 3479 : column_list = fmtCopyColumnList(tbinfo, clistBuf);
2156 : :
2157 : : /*
2158 : : * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
2159 : : * a filter condition was specified. For other cases a simple COPY
2160 : : * suffices.
2161 : : */
1481 alvherre@alvh.no-ip. 2162 [ + - + + ]: 3479 : if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2163 : : {
4814 tgl@sss.pgh.pa.us 2164 : 1 : appendPQExpBufferStr(q, "COPY (SELECT ");
2165 : : /* klugery to get rid of parens in column list */
2166 [ + - ]: 1 : if (strlen(column_list) > 2)
2167 : : {
2168 : 1 : appendPQExpBufferStr(q, column_list + 1);
2169 : 1 : q->data[q->len - 1] = ' ';
2170 : : }
2171 : : else
4814 tgl@sss.pgh.pa.us 2172 :UBC 0 : appendPQExpBufferStr(q, "* ");
2173 : :
2174 : 0 : appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
2239 tgl@sss.pgh.pa.us 2175 :CBC 1 : fmtQualifiedDumpable(tbinfo),
1481 alvherre@alvh.no-ip. 2176 [ - + ]: 1 : tdinfo->filtercond ? tdinfo->filtercond : "");
2177 : : }
2178 : : else
2179 : : {
7941 bruce@momjian.us 2180 : 3478 : appendPQExpBuffer(q, "COPY %s %s TO stdout;",
2239 tgl@sss.pgh.pa.us 2181 : 3478 : fmtQualifiedDumpable(tbinfo),
2182 : : column_list);
2183 : : }
4450 rhaas@postgresql.org 2184 : 3479 : res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
6617 tgl@sss.pgh.pa.us 2185 : 3478 : PQclear(res);
4039 andrew@dunslane.net 2186 : 3478 : destroyPQExpBuffer(clistBuf);
2187 : :
2188 : : for (;;)
2189 : : {
4441 rhaas@postgresql.org 2190 : 1713857 : ret = PQgetCopyData(conn, ©buf, 0);
2191 : :
6617 tgl@sss.pgh.pa.us 2192 [ + + ]: 1713857 : if (ret < 0)
2193 : 3478 : break; /* done or error */
2194 : :
2195 [ + - ]: 1710379 : if (copybuf)
2196 : : {
2197 : 1710379 : WriteData(fout, copybuf, ret);
2198 : 1710379 : PQfreemem(copybuf);
2199 : : }
2200 : :
2201 : : /* ----------
2202 : : * THROTTLE:
2203 : : *
2204 : : * There was considerable discussion in late July, 2000 regarding
2205 : : * slowing down pg_dump when backing up large tables. Users with both
2206 : : * slow & fast (multi-processor) machines experienced performance
2207 : : * degradation when doing a backup.
2208 : : *
2209 : : * Initial attempts based on sleeping for a number of ms for each ms
2210 : : * of work were deemed too complex, then a simple 'sleep in each loop'
2211 : : * implementation was suggested. The latter failed because the loop
2212 : : * was too tight. Finally, the following was implemented:
2213 : : *
2214 : : * If throttle is non-zero, then
2215 : : * See how long since the last sleep.
2216 : : * Work out how long to sleep (based on ratio).
2217 : : * If sleep is more than 100ms, then
2218 : : * sleep
2219 : : * reset timer
2220 : : * EndIf
2221 : : * EndIf
2222 : : *
2223 : : * where the throttle value was the number of ms to sleep per ms of
2224 : : * work. The calculation was done in each loop.
2225 : : *
2226 : : * Most of the hard work is done in the backend, and this solution
2227 : : * still did not work particularly well: on slow machines, the ratio
2228 : : * was 50:1, and on medium paced machines, 1:1, and on fast
2229 : : * multi-processor machines, it had little or no effect, for reasons
2230 : : * that were unclear.
2231 : : *
2232 : : * Further discussion ensued, and the proposal was dropped.
2233 : : *
2234 : : * For those people who want this feature, it can be implemented using
2235 : : * gettimeofday in each loop, calculating the time since last sleep,
2236 : : * multiplying that by the sleep ratio, then if the result is more
2237 : : * than a preset 'minimum sleep time' (say 100ms), call the 'select'
2238 : : * function to sleep for a subsecond period ie.
2239 : : *
2240 : : * select(0, NULL, NULL, NULL, &tvi);
2241 : : *
2242 : : * This will return after the interval specified in the structure tvi.
2243 : : * Finally, call gettimeofday again to save the 'last sleep time'.
2244 : : * ----------
2245 : : */
2246 : : }
7910 peter_e@gmx.net 2247 : 3478 : archprintf(fout, "\\.\n\n\n");
2248 : :
6617 tgl@sss.pgh.pa.us 2249 [ - + ]: 3478 : if (ret == -2)
2250 : : {
2251 : : /* copy data transfer failed */
1840 peter@eisentraut.org 2252 :UBC 0 : pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
737 tgl@sss.pgh.pa.us 2253 : 0 : pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2254 : 0 : pg_log_error_detail("Command was: %s", q->data);
4441 rhaas@postgresql.org 2255 : 0 : exit_nicely(1);
2256 : : }
2257 : :
2258 : : /* Check command status and return to normal libpq state */
4441 rhaas@postgresql.org 2259 :CBC 3478 : res = PQgetResult(conn);
4450 2260 [ - + ]: 3478 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
2261 : : {
1840 peter@eisentraut.org 2262 :UBC 0 : pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
737 tgl@sss.pgh.pa.us 2263 : 0 : pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2264 : 0 : pg_log_error_detail("Command was: %s", q->data);
4441 rhaas@postgresql.org 2265 : 0 : exit_nicely(1);
2266 : : }
7957 bruce@momjian.us 2267 :CBC 3478 : PQclear(res);
2268 : :
2269 : : /* Do this to ensure we've pumped libpq back to idle state */
2873 tgl@sss.pgh.pa.us 2270 [ - + ]: 3478 : if (PQgetResult(conn) != NULL)
1840 peter@eisentraut.org 2271 :UBC 0 : pg_log_warning("unexpected extra results during COPY of table \"%s\"",
2272 : : classname);
2273 : :
8010 tgl@sss.pgh.pa.us 2274 :CBC 3478 : destroyPQExpBuffer(q);
2275 : 3478 : return 1;
2276 : : }
2277 : :
2278 : : /*
2279 : : * Dump table data using INSERT commands.
2280 : : *
2281 : : * Caution: when we restore from an archive file direct to database, the
2282 : : * INSERT commands emitted by this function have to be parsed by
2283 : : * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
2284 : : * E'' strings, or dollar-quoted strings. So don't emit anything like that.
2285 : : */
2286 : : static int
1159 peter@eisentraut.org 2287 : 69 : dumpTableData_insert(Archive *fout, const void *dcontext)
2288 : : {
7435 tgl@sss.pgh.pa.us 2289 : 69 : TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2290 : 69 : TableInfo *tbinfo = tdinfo->tdtable;
3014 2291 : 69 : DumpOptions *dopt = fout->dopt;
8010 2292 : 69 : PQExpBuffer q = createPQExpBuffer();
3803 2293 : 69 : PQExpBuffer insertStmt = NULL;
2294 : : char *attgenerated;
2295 : : PGresult *res;
2296 : : int nfields,
2297 : : i;
1865 alvherre@alvh.no-ip. 2298 : 69 : int rows_per_statement = dopt->dump_inserts;
2299 : 69 : int rows_this_statement = 0;
2300 : :
2301 : : /*
2302 : : * If we're going to emit INSERTs with column names, the most efficient
2303 : : * way to deal with generated columns is to exclude them entirely. For
2304 : : * INSERTs without column names, we have to emit DEFAULT rather than the
2305 : : * actual column value --- but we can save a few cycles by fetching nulls
2306 : : * rather than the uninteresting-to-us value.
2307 : : */
874 tgl@sss.pgh.pa.us 2308 : 69 : attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
2309 : 69 : appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
2310 : 69 : nfields = 0;
2311 [ + + ]: 221 : for (i = 0; i < tbinfo->numatts; i++)
2312 : : {
2313 [ + + ]: 152 : if (tbinfo->attisdropped[i])
2314 : 2 : continue;
2315 [ + + + + ]: 150 : if (tbinfo->attgenerated[i] && dopt->column_inserts)
2316 : 5 : continue;
2317 [ + + ]: 145 : if (nfields > 0)
2318 : 83 : appendPQExpBufferStr(q, ", ");
2319 [ + + ]: 145 : if (tbinfo->attgenerated[i])
2320 : 5 : appendPQExpBufferStr(q, "NULL");
2321 : : else
2322 : 140 : appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
2323 : 145 : attgenerated[nfields] = tbinfo->attgenerated[i];
2324 : 145 : nfields++;
2325 : : }
2326 : : /* Servers before 9.4 will complain about zero-column SELECT */
2327 [ + + ]: 69 : if (nfields == 0)
2328 : 7 : appendPQExpBufferStr(q, "NULL");
2329 : 69 : appendPQExpBuffer(q, " FROM ONLY %s",
2239 2330 : 69 : fmtQualifiedDumpable(tbinfo));
4814 2331 [ - + ]: 69 : if (tdinfo->filtercond)
4814 tgl@sss.pgh.pa.us 2332 :UBC 0 : appendPQExpBuffer(q, " %s", tdinfo->filtercond);
2333 : :
4450 rhaas@postgresql.org 2334 :CBC 69 : ExecuteSqlStatement(fout, q->data);
2335 : :
2336 : : while (1)
2337 : : {
2338 : 119 : res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
2339 : : PGRES_TUPLES_OK);
2340 : :
2341 : : /* cross-check field count, allowing for dummy NULL if any */
874 tgl@sss.pgh.pa.us 2342 [ + + + - ]: 119 : if (nfields != PQnfields(res) &&
2343 [ - + ]: 10 : !(nfields == 0 && PQnfields(res) == 1))
737 tgl@sss.pgh.pa.us 2344 :UBC 0 : pg_fatal("wrong number of fields retrieved from table \"%s\"",
2345 : : tbinfo->dobj.name);
2346 : :
2347 : : /*
2348 : : * First time through, we build as much of the INSERT statement as
2349 : : * possible in "insertStmt", which we can then just print for each
2350 : : * statement. If the table happens to have zero dumpable columns then
2351 : : * this will be a complete statement, otherwise it will end in
2352 : : * "VALUES" and be ready to have the row's column values printed.
2353 : : */
1865 alvherre@alvh.no-ip. 2354 [ + + ]:CBC 119 : if (insertStmt == NULL)
2355 : : {
2356 : : TableInfo *targettab;
2357 : :
2358 : 69 : insertStmt = createPQExpBuffer();
2359 : :
2360 : : /*
2361 : : * When load-via-partition-root is set or forced, get the root
2362 : : * table name for the partition table, so that we can reload data
2363 : : * through the root table.
2364 : : */
394 tgl@sss.pgh.pa.us 2365 [ + + ]: 69 : if (tbinfo->ispartition &&
2366 [ + - + + ]: 40 : (dopt->load_via_partition_root ||
2367 : 20 : forcePartitionRootLoad(tbinfo)))
1865 alvherre@alvh.no-ip. 2368 : 3 : targettab = getRootTableInfo(tbinfo);
2369 : : else
2370 : 66 : targettab = tbinfo;
2371 : :
2372 : 69 : appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
2373 : 69 : fmtQualifiedDumpable(targettab));
2374 : :
2375 : : /* corner case for zero-column table */
2376 [ + + ]: 69 : if (nfields == 0)
2377 : : {
2378 : 7 : appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
2379 : : }
2380 : : else
2381 : : {
2382 : : /* append the list of column names if required */
2383 [ + + ]: 62 : if (dopt->column_inserts)
2384 : : {
2385 : 27 : appendPQExpBufferChar(insertStmt, '(');
2386 [ + + ]: 88 : for (int field = 0; field < nfields; field++)
2387 : : {
2388 [ + + ]: 61 : if (field > 0)
2389 : 34 : appendPQExpBufferStr(insertStmt, ", ");
2390 : 61 : appendPQExpBufferStr(insertStmt,
2391 : 61 : fmtId(PQfname(res, field)));
2392 : : }
2393 : 27 : appendPQExpBufferStr(insertStmt, ") ");
2394 : : }
2395 : :
2396 [ + + ]: 62 : if (tbinfo->needs_override)
2397 : 2 : appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
2398 : :
2399 : 62 : appendPQExpBufferStr(insertStmt, "VALUES");
2400 : : }
2401 : : }
2402 : :
2403 [ + + ]: 3190 : for (int tuple = 0; tuple < PQntuples(res); tuple++)
2404 : : {
2405 : : /* Write the INSERT if not in the middle of a multi-row INSERT. */
2406 [ + + ]: 3071 : if (rows_this_statement == 0)
2407 : 3065 : archputs(insertStmt->data, fout);
2408 : :
2409 : : /*
2410 : : * If it is zero-column table then we've already written the
2411 : : * complete statement, which will mean we've disobeyed
2412 : : * --rows-per-insert when it's set greater than 1. We do support
2413 : : * a way to make this multi-row with: SELECT UNION ALL SELECT
2414 : : * UNION ALL ... but that's non-standard so we should avoid it
2415 : : * given that using INSERTs is mostly only ever needed for
2416 : : * cross-database exports.
2417 : : */
3803 tgl@sss.pgh.pa.us 2418 [ + + ]: 3071 : if (nfields == 0)
2419 : 6 : continue;
2420 : :
2421 : : /* Emit a row heading */
1865 alvherre@alvh.no-ip. 2422 [ + + ]: 3065 : if (rows_per_statement == 1)
2423 : 3056 : archputs(" (", fout);
2424 [ + + ]: 9 : else if (rows_this_statement > 0)
2425 : 6 : archputs(",\n\t(", fout);
2426 : : else
2427 : 3 : archputs("\n\t(", fout);
2428 : :
2429 [ + + ]: 9249 : for (int field = 0; field < nfields; field++)
2430 : : {
8010 tgl@sss.pgh.pa.us 2431 [ + + ]: 6184 : if (field > 0)
3803 2432 : 3119 : archputs(", ", fout);
874 2433 [ + + ]: 6184 : if (attgenerated[field])
2434 : : {
1842 peter@eisentraut.org 2435 : 2 : archputs("DEFAULT", fout);
2436 : 2 : continue;
2437 : : }
8010 tgl@sss.pgh.pa.us 2438 [ + + ]: 6182 : if (PQgetisnull(res, tuple, field))
2439 : : {
3803 2440 : 83 : archputs("NULL", fout);
8010 2441 : 83 : continue;
2442 : : }
2443 : :
2444 : : /* XXX This code is partially duplicated in ruleutils.c */
2445 [ + + + + ]: 6099 : switch (PQftype(res, field))
2446 : : {
2447 : 4069 : case INT2OID:
2448 : : case INT4OID:
2449 : : case INT8OID:
2450 : : case OIDOID:
2451 : : case FLOAT4OID:
2452 : : case FLOAT8OID:
2453 : : case NUMERICOID:
2454 : : {
2455 : : /*
2456 : : * These types are printed without quotes unless
2457 : : * they contain values that aren't accepted by the
2458 : : * scanner unquoted (e.g., 'NaN'). Note that
2459 : : * strtod() and friends might accept NaN, so we
2460 : : * can't use that to test.
2461 : : *
2462 : : * In reality we only need to defend against
2463 : : * infinity and NaN, so we need not get too crazy
2464 : : * about pattern matching here.
2465 : : */
7893 bruce@momjian.us 2466 : 4069 : const char *s = PQgetvalue(res, tuple, field);
2467 : :
2468 [ + + ]: 4069 : if (strspn(s, "0123456789 +-eE.") == strlen(s))
3803 tgl@sss.pgh.pa.us 2469 : 4067 : archputs(s, fout);
2470 : : else
7893 bruce@momjian.us 2471 : 2 : archprintf(fout, "'%s'", s);
2472 : : }
2473 : 4069 : break;
2474 : :
8010 tgl@sss.pgh.pa.us 2475 : 2 : case BITOID:
2476 : : case VARBITOID:
2477 : 2 : archprintf(fout, "B'%s'",
2478 : : PQgetvalue(res, tuple, field));
2479 : 2 : break;
2480 : :
7910 peter_e@gmx.net 2481 : 4 : case BOOLOID:
7893 bruce@momjian.us 2482 [ + + ]: 4 : if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
3803 tgl@sss.pgh.pa.us 2483 : 2 : archputs("true", fout);
2484 : : else
2485 : 2 : archputs("false", fout);
7910 peter_e@gmx.net 2486 : 4 : break;
2487 : :
2488 : 2024 : default:
2489 : : /* All other types are printed as string literals. */
8010 tgl@sss.pgh.pa.us 2490 : 2024 : resetPQExpBuffer(q);
6531 2491 : 2024 : appendStringLiteralAH(q,
2492 : : PQgetvalue(res, tuple, field),
2493 : : fout);
7018 2494 : 2024 : archputs(q->data, fout);
8010 2495 : 2024 : break;
2496 : : }
2497 : : }
2498 : :
2499 : : /* Terminate the row ... */
1865 alvherre@alvh.no-ip. 2500 : 3065 : archputs(")", fout);
2501 : :
2502 : : /* ... and the statement, if the target no. of rows is reached */
2503 [ + + ]: 3065 : if (++rows_this_statement >= rows_per_statement)
2504 : : {
2505 [ - + ]: 3058 : if (dopt->do_nothing)
1865 alvherre@alvh.no-ip. 2506 :UBC 0 : archputs(" ON CONFLICT DO NOTHING;\n", fout);
2507 : : else
1865 alvherre@alvh.no-ip. 2508 :CBC 3058 : archputs(";\n", fout);
2509 : : /* Reset the row counter */
2510 : 3058 : rows_this_statement = 0;
2511 : : }
2512 : : }
2513 : :
4450 rhaas@postgresql.org 2514 [ + + ]: 119 : if (PQntuples(res) <= 0)
2515 : : {
2516 : 69 : PQclear(res);
2517 : 69 : break;
2518 : : }
2519 : 50 : PQclear(res);
2520 : : }
2521 : :
2522 : : /* Terminate any statements that didn't make the row count. */
1865 alvherre@alvh.no-ip. 2523 [ + + ]: 69 : if (rows_this_statement > 0)
2524 : : {
2525 [ - + ]: 1 : if (dopt->do_nothing)
1865 alvherre@alvh.no-ip. 2526 :UBC 0 : archputs(" ON CONFLICT DO NOTHING;\n", fout);
2527 : : else
1865 alvherre@alvh.no-ip. 2528 :CBC 1 : archputs(";\n", fout);
2529 : : }
2530 : :
3803 tgl@sss.pgh.pa.us 2531 : 69 : archputs("\n\n", fout);
2532 : :
4450 rhaas@postgresql.org 2533 : 69 : ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2534 : :
8010 tgl@sss.pgh.pa.us 2535 : 69 : destroyPQExpBuffer(q);
3803 2536 [ + - ]: 69 : if (insertStmt != NULL)
2537 : 69 : destroyPQExpBuffer(insertStmt);
874 2538 : 69 : free(attgenerated);
2539 : :
8010 2540 : 69 : return 1;
2541 : : }
2542 : :
2543 : : /*
2544 : : * getRootTableInfo:
2545 : : * get the root TableInfo for the given partition table.
2546 : : */
2547 : : static TableInfo *
1159 peter@eisentraut.org 2548 : 9 : getRootTableInfo(const TableInfo *tbinfo)
2549 : : {
2550 : : TableInfo *parentTbinfo;
2551 : :
2435 rhaas@postgresql.org 2552 [ - + ]: 9 : Assert(tbinfo->ispartition);
2553 [ - + ]: 9 : Assert(tbinfo->numParents == 1);
2554 : :
2555 : 9 : parentTbinfo = tbinfo->parents[0];
2556 [ - + ]: 9 : while (parentTbinfo->ispartition)
2557 : : {
2435 rhaas@postgresql.org 2558 [ # # ]:UBC 0 : Assert(parentTbinfo->numParents == 1);
2559 : 0 : parentTbinfo = parentTbinfo->parents[0];
2560 : : }
2561 : :
2435 rhaas@postgresql.org 2562 :CBC 9 : return parentTbinfo;
2563 : : }
2564 : :
2565 : : /*
2566 : : * forcePartitionRootLoad
2567 : : * Check if we must force load_via_partition_root for this partition.
2568 : : *
2569 : : * This is required if any level of ancestral partitioned table has an
2570 : : * unsafe partitioning scheme.
2571 : : */
2572 : : static bool
394 tgl@sss.pgh.pa.us 2573 : 955 : forcePartitionRootLoad(const TableInfo *tbinfo)
2574 : : {
2575 : : TableInfo *parentTbinfo;
2576 : :
2577 [ - + ]: 955 : Assert(tbinfo->ispartition);
2578 [ - + ]: 955 : Assert(tbinfo->numParents == 1);
2579 : :
2580 : 955 : parentTbinfo = tbinfo->parents[0];
2581 [ + + ]: 955 : if (parentTbinfo->unsafe_partitions)
2582 : 9 : return true;
2583 [ + + ]: 1162 : while (parentTbinfo->ispartition)
2584 : : {
2585 [ - + ]: 216 : Assert(parentTbinfo->numParents == 1);
2586 : 216 : parentTbinfo = parentTbinfo->parents[0];
2587 [ - + ]: 216 : if (parentTbinfo->unsafe_partitions)
394 tgl@sss.pgh.pa.us 2588 :UBC 0 : return true;
2589 : : }
2590 : :
394 tgl@sss.pgh.pa.us 2591 :CBC 946 : return false;
2592 : : }
2593 : :
2594 : : /*
2595 : : * dumpTableData -
2596 : : * dump the contents of a single table
2597 : : *
2598 : : * Actually, this just makes an ArchiveEntry for the table contents.
2599 : : */
2600 : : static void
1159 peter@eisentraut.org 2601 : 3616 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
2602 : : {
3014 tgl@sss.pgh.pa.us 2603 : 3616 : DumpOptions *dopt = fout->dopt;
7435 2604 : 3616 : TableInfo *tbinfo = tdinfo->tdtable;
4813 2605 : 3616 : PQExpBuffer copyBuf = createPQExpBuffer();
4039 andrew@dunslane.net 2606 : 3616 : PQExpBuffer clistBuf = createPQExpBuffer();
2607 : : DataDumperPtr dumpFn;
394 tgl@sss.pgh.pa.us 2608 : 3616 : char *tdDefn = NULL;
2609 : : char *copyStmt;
2610 : : const char *copyFrom;
2611 : :
2612 : : /* We had better have loaded per-column details about this table */
1285 2613 [ - + ]: 3616 : Assert(tbinfo->interesting);
2614 : :
2615 : : /*
2616 : : * When load-via-partition-root is set or forced, get the root table name
2617 : : * for the partition table, so that we can reload data through the root
2618 : : * table. Then construct a comment to be inserted into the TOC entry's
2619 : : * defn field, so that such cases can be identified reliably.
2620 : : */
394 2621 [ + + ]: 3616 : if (tbinfo->ispartition &&
2622 [ + - + + ]: 1870 : (dopt->load_via_partition_root ||
2623 : 935 : forcePartitionRootLoad(tbinfo)))
2624 : 6 : {
2625 : : TableInfo *parentTbinfo;
2626 : :
2627 : 6 : parentTbinfo = getRootTableInfo(tbinfo);
2628 : 6 : copyFrom = fmtQualifiedDumpable(parentTbinfo);
2629 : 6 : printfPQExpBuffer(copyBuf, "-- load via partition root %s",
2630 : : copyFrom);
2631 : 6 : tdDefn = pg_strdup(copyBuf->data);
2632 : : }
2633 : : else
2634 : 3610 : copyFrom = fmtQualifiedDumpable(tbinfo);
2635 : :
1376 alvherre@alvh.no-ip. 2636 [ + + ]: 3616 : if (dopt->dump_inserts == 0)
2637 : : {
2638 : : /* Dump/restore using COPY */
7435 tgl@sss.pgh.pa.us 2639 : 3547 : dumpFn = dumpTableData_copy;
2640 : : /* must use 2 steps here 'cause fmtId is nonreentrant */
394 2641 : 3547 : printfPQExpBuffer(copyBuf, "COPY %s ",
2642 : : copyFrom);
1972 andres@anarazel.de 2643 : 3547 : appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2644 : : fmtCopyColumnList(tbinfo, clistBuf));
7435 tgl@sss.pgh.pa.us 2645 : 3547 : copyStmt = copyBuf->data;
2646 : : }
2647 : : else
2648 : : {
2649 : : /* Restore using INSERT */
2650 : 69 : dumpFn = dumpTableData_insert;
2651 : 69 : copyStmt = NULL;
2652 : : }
2653 : :
2654 : : /*
2655 : : * Note: although the TableDataInfo is a full DumpableObject, we treat its
2656 : : * dependency on its table as "special" and pass it to ArchiveEntry now.
2657 : : * See comments for BuildArchiveDependencies.
2658 : : */
2930 sfrost@snowman.net 2659 [ + - ]: 3616 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2660 : : {
2661 : : TocEntry *te;
2662 : :
2039 tgl@sss.pgh.pa.us 2663 : 3616 : te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 2664 : 3616 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2665 : : .namespace = tbinfo->dobj.namespace->dobj.name,
2666 : : .owner = tbinfo->rolname,
2667 : : .description = "TABLE DATA",
2668 : : .section = SECTION_DATA,
2669 : : .createStmt = tdDefn,
2670 : : .copyStmt = copyStmt,
2671 : : .deps = &(tbinfo->dobj.dumpId),
2672 : : .nDeps = 1,
2673 : : .dumpFn = dumpFn,
2674 : : .dumpArg = tdinfo));
2675 : :
2676 : : /*
2677 : : * Set the TocEntry's dataLength in case we are doing a parallel dump
2678 : : * and want to order dump jobs by table size. We choose to measure
2679 : : * dataLength in table pages (including TOAST pages) during dump, so
2680 : : * no scaling is needed.
2681 : : *
2682 : : * However, relpages is declared as "integer" in pg_class, and hence
2683 : : * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2684 : : * Cast so that we get the right interpretation of table sizes
2685 : : * exceeding INT_MAX pages.
2686 : : */
2039 tgl@sss.pgh.pa.us 2687 : 3616 : te->dataLength = (BlockNumber) tbinfo->relpages;
860 2688 : 3616 : te->dataLength += (BlockNumber) tbinfo->toastpages;
2689 : :
2690 : : /*
2691 : : * If pgoff_t is only 32 bits wide, the above refinement is useless,
2692 : : * and instead we'd better worry about integer overflow. Clamp to
2693 : : * INT_MAX if the correct result exceeds that.
2694 : : */
2695 : : if (sizeof(te->dataLength) == 4 &&
2696 : : (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
2697 : : te->dataLength < 0))
2698 : : te->dataLength = INT_MAX;
2699 : : }
2700 : :
7435 2701 : 3616 : destroyPQExpBuffer(copyBuf);
4039 andrew@dunslane.net 2702 : 3616 : destroyPQExpBuffer(clistBuf);
7435 tgl@sss.pgh.pa.us 2703 : 3616 : }
2704 : :
2705 : : /*
2706 : : * refreshMatViewData -
2707 : : * load or refresh the contents of a single materialized view
2708 : : *
2709 : : * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2710 : : * statement.
2711 : : */
2712 : : static void
1159 peter@eisentraut.org 2713 : 365 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
2714 : : {
4060 kgrittn@postgresql.o 2715 : 365 : TableInfo *tbinfo = tdinfo->tdtable;
2716 : : PQExpBuffer q;
2717 : :
2718 : : /* If the materialized view is not flagged as populated, skip this. */
3996 tgl@sss.pgh.pa.us 2719 [ + + ]: 365 : if (!tbinfo->relispopulated)
4060 kgrittn@postgresql.o 2720 : 74 : return;
2721 : :
2722 : 291 : q = createPQExpBuffer();
2723 : :
2724 : 291 : appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2239 tgl@sss.pgh.pa.us 2725 : 291 : fmtQualifiedDumpable(tbinfo));
2726 : :
2930 sfrost@snowman.net 2727 [ + - ]: 291 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2728 : 291 : ArchiveEntry(fout,
2729 : : tdinfo->dobj.catId, /* catalog ID */
2489 tgl@sss.pgh.pa.us 2730 : 291 : tdinfo->dobj.dumpId, /* dump ID */
1899 alvherre@alvh.no-ip. 2731 : 291 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2732 : : .namespace = tbinfo->dobj.namespace->dobj.name,
2733 : : .owner = tbinfo->rolname,
2734 : : .description = "MATERIALIZED VIEW DATA",
2735 : : .section = SECTION_POST_DATA,
2736 : : .createStmt = q->data,
2737 : : .deps = tdinfo->dobj.dependencies,
2738 : : .nDeps = tdinfo->dobj.nDeps));
2739 : :
4060 kgrittn@postgresql.o 2740 : 291 : destroyPQExpBuffer(q);
2741 : : }
2742 : :
2743 : : /*
2744 : : * getTableData -
2745 : : * set up dumpable objects representing the contents of tables
2746 : : */
2747 : : static void
1972 andres@anarazel.de 2748 : 153 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2749 : : {
2750 : : int i;
2751 : :
8010 tgl@sss.pgh.pa.us 2752 [ + + ]: 38935 : for (i = 0; i < numTables; i++)
2753 : : {
2791 peter_e@gmx.net 2754 [ + + + + ]: 38782 : if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2755 [ + + ]: 818 : (!relkind || tblinfo[i].relkind == relkind))
1972 andres@anarazel.de 2756 : 5128 : makeTableDataInfo(dopt, &(tblinfo[i]));
2757 : : }
4814 tgl@sss.pgh.pa.us 2758 : 153 : }
2759 : :
2760 : : /*
2761 : : * Make a dumpable object for the data of this specific table
2762 : : *
2763 : : * Note: we make a TableDataInfo if and only if we are going to dump the
2764 : : * table data; the "dump" field in such objects isn't very interesting.
2765 : : */
2766 : : static void
1972 andres@anarazel.de 2767 : 5167 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
2768 : : {
2769 : : TableDataInfo *tdinfo;
2770 : :
2771 : : /*
2772 : : * Nothing to do if we already decided to dump the table. This will
2773 : : * happen for "config" tables.
2774 : : */
4449 tgl@sss.pgh.pa.us 2775 [ + + ]: 5167 : if (tbinfo->dataObj != NULL)
2776 : 1 : return;
2777 : :
2778 : : /* Skip VIEWs (no data to dump) */
2779 [ + + ]: 5166 : if (tbinfo->relkind == RELKIND_VIEW)
2780 : 303 : return;
2781 : : /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
1481 alvherre@alvh.no-ip. 2782 [ + + ]: 4863 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
2783 [ + + ]: 41 : (foreign_servers_include_oids.head == NULL ||
1431 tgl@sss.pgh.pa.us 2784 [ + + ]: 4 : !simple_oid_list_member(&foreign_servers_include_oids,
2785 : : tbinfo->foreign_server)))
4449 2786 : 40 : return;
2787 : : /* Skip partitioned tables (data in partitions) */
2685 rhaas@postgresql.org 2788 [ + + ]: 4823 : if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2789 : 435 : return;
2790 : :
2791 : : /* Don't dump data in unlogged tables, if so requested */
4449 tgl@sss.pgh.pa.us 2792 [ + + ]: 4388 : if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
3470 alvherre@alvh.no-ip. 2793 [ + + ]: 32 : dopt->no_unlogged_table_data)
4449 tgl@sss.pgh.pa.us 2794 : 14 : return;
2795 : :
2796 : : /* Check that the data is not explicitly excluded */
2797 [ + + ]: 4374 : if (simple_oid_list_member(&tabledata_exclude_oids,
2798 : : tbinfo->dobj.catId.oid))
2799 : 8 : return;
2800 : :
2801 : : /* OK, let's dump it */
4524 bruce@momjian.us 2802 : 4366 : tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2803 : :
4060 kgrittn@postgresql.o 2804 [ + + ]: 4366 : if (tbinfo->relkind == RELKIND_MATVIEW)
2805 : 365 : tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2791 peter_e@gmx.net 2806 [ + + ]: 4001 : else if (tbinfo->relkind == RELKIND_SEQUENCE)
2807 : 385 : tdinfo->dobj.objType = DO_SEQUENCE_SET;
2808 : : else
4060 kgrittn@postgresql.o 2809 : 3616 : tdinfo->dobj.objType = DO_TABLE_DATA;
2810 : :
2811 : : /*
2812 : : * Note: use tableoid 0 so that this object won't be mistaken for
2813 : : * something that pg_depend entries apply to.
2814 : : */
4814 tgl@sss.pgh.pa.us 2815 : 4366 : tdinfo->dobj.catId.tableoid = 0;
2816 : 4366 : tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2817 : 4366 : AssignDumpId(&tdinfo->dobj);
2818 : 4366 : tdinfo->dobj.name = tbinfo->dobj.name;
2819 : 4366 : tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2820 : 4366 : tdinfo->tdtable = tbinfo;
4753 bruce@momjian.us 2821 : 4366 : tdinfo->filtercond = NULL; /* might get set later */
4814 tgl@sss.pgh.pa.us 2822 : 4366 : addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2823 : :
2824 : : /* A TableDataInfo contains data, of course */
860 2825 : 4366 : tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
2826 : :
4814 2827 : 4366 : tbinfo->dataObj = tdinfo;
2828 : :
2829 : : /* Make sure that we'll collect per-column info for this table. */
1285 2830 : 4366 : tbinfo->interesting = true;
2831 : : }
2832 : :
2833 : : /*
2834 : : * The refresh for a materialized view must be dependent on the refresh for
2835 : : * any materialized view that this one is dependent on.
2836 : : *
2837 : : * This must be called after all the objects are created, but before they are
2838 : : * sorted.
2839 : : */
2840 : : static void
4060 kgrittn@postgresql.o 2841 : 139 : buildMatViewRefreshDependencies(Archive *fout)
2842 : : {
2843 : : PQExpBuffer query;
2844 : : PGresult *res;
2845 : : int ntups,
2846 : : i;
2847 : : int i_classid,
2848 : : i_objid,
2849 : : i_refobjid;
2850 : :
2851 : : /* No Mat Views before 9.3. */
4050 2852 [ - + ]: 139 : if (fout->remoteVersion < 90300)
4050 kgrittn@postgresql.o 2853 :UBC 0 : return;
2854 : :
4050 kgrittn@postgresql.o 2855 :CBC 139 : query = createPQExpBuffer();
2856 : :
3800 heikki.linnakangas@i 2857 : 139 : appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2858 : : "( "
2859 : : "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2860 : : "FROM pg_depend d1 "
2861 : : "JOIN pg_class c1 ON c1.oid = d1.objid "
2862 : : "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2863 : : " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2864 : : "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2865 : : "AND d2.objid = r1.oid "
2866 : : "AND d2.refobjid <> d1.objid "
2867 : : "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2868 : : "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2869 : : CppAsString2(RELKIND_VIEW) ") "
2870 : : "WHERE d1.classid = 'pg_class'::regclass "
2871 : : "UNION "
2872 : : "SELECT w.objid, d3.refobjid, c3.relkind "
2873 : : "FROM w "
2874 : : "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2875 : : "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2876 : : "AND d3.objid = r3.oid "
2877 : : "AND d3.refobjid <> w.refobjid "
2878 : : "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2879 : : "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2880 : : CppAsString2(RELKIND_VIEW) ") "
2881 : : ") "
2882 : : "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2883 : : "FROM w "
2884 : : "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2885 : :
4060 kgrittn@postgresql.o 2886 : 139 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2887 : :
2888 : 139 : ntups = PQntuples(res);
2889 : :
2890 : 139 : i_classid = PQfnumber(res, "classid");
2891 : 139 : i_objid = PQfnumber(res, "objid");
2892 : 139 : i_refobjid = PQfnumber(res, "refobjid");
2893 : :
2894 [ + + ]: 415 : for (i = 0; i < ntups; i++)
2895 : : {
2896 : : CatalogId objId;
2897 : : CatalogId refobjId;
2898 : : DumpableObject *dobj;
2899 : : DumpableObject *refdobj;
2900 : : TableInfo *tbinfo;
2901 : : TableInfo *reftbinfo;
2902 : :
2903 : 276 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2904 : 276 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
2905 : 276 : refobjId.tableoid = objId.tableoid;
2906 : 276 : refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2907 : :
2908 : 276 : dobj = findObjectByCatalogId(objId);
2909 [ - + ]: 276 : if (dobj == NULL)
4060 kgrittn@postgresql.o 2910 :UBC 0 : continue;
2911 : :
4060 kgrittn@postgresql.o 2912 [ - + ]:CBC 276 : Assert(dobj->objType == DO_TABLE);
2913 : 276 : tbinfo = (TableInfo *) dobj;
2914 [ - + ]: 276 : Assert(tbinfo->relkind == RELKIND_MATVIEW);
2915 : 276 : dobj = (DumpableObject *) tbinfo->dataObj;
2916 [ + + ]: 276 : if (dobj == NULL)
2917 : 42 : continue;
2918 [ - + ]: 234 : Assert(dobj->objType == DO_REFRESH_MATVIEW);
2919 : :
2920 : 234 : refdobj = findObjectByCatalogId(refobjId);
2921 [ - + ]: 234 : if (refdobj == NULL)
4060 kgrittn@postgresql.o 2922 :UBC 0 : continue;
2923 : :
4060 kgrittn@postgresql.o 2924 [ - + ]:CBC 234 : Assert(refdobj->objType == DO_TABLE);
2925 : 234 : reftbinfo = (TableInfo *) refdobj;
2926 [ - + ]: 234 : Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2927 : 234 : refdobj = (DumpableObject *) reftbinfo->dataObj;
2928 [ - + ]: 234 : if (refdobj == NULL)
4060 kgrittn@postgresql.o 2929 :UBC 0 : continue;
4060 kgrittn@postgresql.o 2930 [ - + ]:CBC 234 : Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2931 : :
2932 : 234 : addObjectDependency(dobj, refdobj->dumpId);
2933 : :
3996 tgl@sss.pgh.pa.us 2934 [ + + ]: 234 : if (!reftbinfo->relispopulated)
2935 : 37 : tbinfo->relispopulated = false;
2936 : : }
2937 : :
4060 kgrittn@postgresql.o 2938 : 139 : PQclear(res);
2939 : :
2940 : 139 : destroyPQExpBuffer(query);
2941 : : }
2942 : :
2943 : : /*
2944 : : * getTableDataFKConstraints -
2945 : : * add dump-order dependencies reflecting foreign key constraints
2946 : : *
2947 : : * This code is executed only in a data-only dump --- in schema+data dumps
2948 : : * we handle foreign key issues by not creating the FK constraints until
2949 : : * after the data is loaded. In a data-only dump, however, we want to
2950 : : * order the table data objects in such a way that a table's referenced
2951 : : * tables are restored first. (In the presence of circular references or
2952 : : * self-references this may be impossible; we'll detect and complain about
2953 : : * that during the dependency sorting step.)
2954 : : */
2955 : : static void
5697 tgl@sss.pgh.pa.us 2956 : 6 : getTableDataFKConstraints(void)
2957 : : {
2958 : : DumpableObject **dobjs;
2959 : : int numObjs;
2960 : : int i;
2961 : :
2962 : : /* Search through all the dumpable objects for FK constraints */
2963 : 6 : getDumpableObjects(&dobjs, &numObjs);
2964 [ + + ]: 25399 : for (i = 0; i < numObjs; i++)
2965 : : {
2966 [ + + ]: 25393 : if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2967 : : {
2968 : 6 : ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2969 : : TableInfo *ftable;
2970 : :
2971 : : /* Not interesting unless both tables are to be dumped */
2972 [ + - ]: 6 : if (cinfo->contable == NULL ||
2973 [ + + ]: 6 : cinfo->contable->dataObj == NULL)
2974 : 3 : continue;
2975 : 3 : ftable = findTableByOid(cinfo->confrelid);
2976 [ + - ]: 3 : if (ftable == NULL ||
2977 [ - + ]: 3 : ftable->dataObj == NULL)
5697 tgl@sss.pgh.pa.us 2978 :UBC 0 : continue;
2979 : :
2980 : : /*
2981 : : * Okay, make referencing table's TABLE_DATA object depend on the
2982 : : * referenced table's TABLE_DATA object.
2983 : : */
5697 tgl@sss.pgh.pa.us 2984 :CBC 3 : addObjectDependency(&cinfo->contable->dataObj->dobj,
2985 : 3 : ftable->dataObj->dobj.dumpId);
2986 : : }
2987 : : }
2988 : 6 : free(dobjs);
2989 : 6 : }
2990 : :
2991 : :
2992 : : /*
2993 : : * dumpDatabase:
2994 : : * dump the database definition
2995 : : */
2996 : : static void
3014 2997 : 62 : dumpDatabase(Archive *fout)
2998 : : {
2999 : 62 : DumpOptions *dopt = fout->dopt;
8424 bruce@momjian.us 3000 : 62 : PQExpBuffer dbQry = createPQExpBuffer();
3001 : 62 : PQExpBuffer delQry = createPQExpBuffer();
3002 : 62 : PQExpBuffer creaQry = createPQExpBuffer();
2274 tgl@sss.pgh.pa.us 3003 : 62 : PQExpBuffer labelq = createPQExpBuffer();
4441 rhaas@postgresql.org 3004 : 62 : PGconn *conn = GetConnection(fout);
3005 : : PGresult *res;
3006 : : int i_tableoid,
3007 : : i_oid,
3008 : : i_datname,
3009 : : i_datdba,
3010 : : i_encoding,
3011 : : i_datlocprovider,
3012 : : i_collate,
3013 : : i_ctype,
3014 : : i_datlocale,
3015 : : i_daticurules,
3016 : : i_frozenxid,
3017 : : i_minmxid,
3018 : : i_datacl,
3019 : : i_acldefault,
3020 : : i_datistemplate,
3021 : : i_datconnlimit,
3022 : : i_datcollversion,
3023 : : i_tablespace;
3024 : : CatalogId dbCatId;
3025 : : DumpId dbDumpId;
3026 : : DumpableAcl dbdacl;
3027 : : const char *datname,
3028 : : *dba,
3029 : : *encoding,
3030 : : *datlocprovider,
3031 : : *collate,
3032 : : *ctype,
3033 : : *locale,
3034 : : *icurules,
3035 : : *datistemplate,
3036 : : *datconnlimit,
3037 : : *tablespace;
3038 : : uint32 frozenxid,
3039 : : minmxid;
3040 : : char *qdatname;
3041 : :
1840 peter@eisentraut.org 3042 : 62 : pg_log_info("saving database definition");
3043 : :
3044 : : /*
3045 : : * Fetch the database-level properties for this database.
3046 : : */
586 drowley@postgresql.o 3047 : 62 : appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
3048 : : "datdba, "
3049 : : "pg_encoding_to_char(encoding) AS encoding, "
3050 : : "datcollate, datctype, datfrozenxid, "
3051 : : "datacl, acldefault('d', datdba) AS acldefault, "
3052 : : "datistemplate, datconnlimit, ");
860 tgl@sss.pgh.pa.us 3053 [ + - ]: 62 : if (fout->remoteVersion >= 90300)
586 drowley@postgresql.o 3054 : 62 : appendPQExpBufferStr(dbQry, "datminmxid, ");
3055 : : else
586 drowley@postgresql.o 3056 :UBC 0 : appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
36 jdavis@postgresql.or 3057 [ + - ]:GNC 62 : if (fout->remoteVersion >= 170000)
3058 : 62 : appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
36 jdavis@postgresql.or 3059 [ # # ]:UNC 0 : else if (fout->remoteVersion >= 150000)
3060 : 0 : appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
3061 : : else
3062 : 0 : appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
403 peter@eisentraut.org 3063 [ + - ]:CBC 62 : if (fout->remoteVersion >= 160000)
3064 : 62 : appendPQExpBufferStr(dbQry, "daticurules, ");
3065 : : else
403 peter@eisentraut.org 3066 :UBC 0 : appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
586 drowley@postgresql.o 3067 :CBC 62 : appendPQExpBufferStr(dbQry,
3068 : : "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
3069 : : "shobj_description(oid, 'pg_database') AS description "
3070 : : "FROM pg_database "
3071 : : "WHERE datname = current_database()");
3072 : :
4441 rhaas@postgresql.org 3073 : 62 : res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
3074 : :
7435 tgl@sss.pgh.pa.us 3075 : 62 : i_tableoid = PQfnumber(res, "tableoid");
3076 : 62 : i_oid = PQfnumber(res, "oid");
2196 peter_e@gmx.net 3077 : 62 : i_datname = PQfnumber(res, "datname");
835 tgl@sss.pgh.pa.us 3078 : 62 : i_datdba = PQfnumber(res, "datdba");
8098 3079 : 62 : i_encoding = PQfnumber(res, "encoding");
759 peter@eisentraut.org 3080 : 62 : i_datlocprovider = PQfnumber(res, "datlocprovider");
5681 heikki.linnakangas@i 3081 : 62 : i_collate = PQfnumber(res, "datcollate");
3082 : 62 : i_ctype = PQfnumber(res, "datctype");
36 jdavis@postgresql.or 3083 :GNC 62 : i_datlocale = PQfnumber(res, "datlocale");
403 peter@eisentraut.org 3084 :CBC 62 : i_daticurules = PQfnumber(res, "daticurules");
5534 bruce@momjian.us 3085 : 62 : i_frozenxid = PQfnumber(res, "datfrozenxid");
3574 3086 : 62 : i_minmxid = PQfnumber(res, "datminmxid");
2274 tgl@sss.pgh.pa.us 3087 : 62 : i_datacl = PQfnumber(res, "datacl");
860 3088 : 62 : i_acldefault = PQfnumber(res, "acldefault");
2274 3089 : 62 : i_datistemplate = PQfnumber(res, "datistemplate");
3090 : 62 : i_datconnlimit = PQfnumber(res, "datconnlimit");
790 peter@eisentraut.org 3091 : 62 : i_datcollversion = PQfnumber(res, "datcollversion");
7240 tgl@sss.pgh.pa.us 3092 : 62 : i_tablespace = PQfnumber(res, "tablespace");
3093 : :
7435 3094 : 62 : dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
3095 : 62 : dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2196 peter_e@gmx.net 3096 : 62 : datname = PQgetvalue(res, 0, i_datname);
835 tgl@sss.pgh.pa.us 3097 : 62 : dba = getRoleName(PQgetvalue(res, 0, i_datdba));
8098 3098 : 62 : encoding = PQgetvalue(res, 0, i_encoding);
759 peter@eisentraut.org 3099 : 62 : datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
5682 heikki.linnakangas@i 3100 : 62 : collate = PQgetvalue(res, 0, i_collate);
3101 : 62 : ctype = PQgetvalue(res, 0, i_ctype);
36 jdavis@postgresql.or 3102 [ + + ]:GNC 62 : if (!PQgetisnull(res, 0, i_datlocale))
3103 : 14 : locale = PQgetvalue(res, 0, i_datlocale);
3104 : : else
3105 : 48 : locale = NULL;
403 peter@eisentraut.org 3106 [ - + ]:CBC 62 : if (!PQgetisnull(res, 0, i_daticurules))
403 peter@eisentraut.org 3107 :UBC 0 : icurules = PQgetvalue(res, 0, i_daticurules);
3108 : : else
403 peter@eisentraut.org 3109 :CBC 62 : icurules = NULL;
5534 bruce@momjian.us 3110 : 62 : frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
3574 3111 : 62 : minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
860 tgl@sss.pgh.pa.us 3112 : 62 : dbdacl.acl = PQgetvalue(res, 0, i_datacl);
3113 : 62 : dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
2274 3114 : 62 : datistemplate = PQgetvalue(res, 0, i_datistemplate);
3115 : 62 : datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
7240 3116 : 62 : tablespace = PQgetvalue(res, 0, i_tablespace);
3117 : :
2196 peter_e@gmx.net 3118 : 62 : qdatname = pg_strdup(fmtId(datname));
3119 : :
3120 : : /*
3121 : : * Prepare the CREATE DATABASE command. We must specify OID (if we want
3122 : : * to preserve that), as well as the encoding, locale, and tablespace
3123 : : * since those can't be altered later. Other DB properties are left to
3124 : : * the DATABASE PROPERTIES entry, so that they can be applied after
3125 : : * reconnecting to the target DB.
3126 : : */
811 rhaas@postgresql.org 3127 [ + + ]: 62 : if (dopt->binary_upgrade)
3128 : : {
3129 : 13 : appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0 OID = %u",
3130 : : qdatname, dbCatId.oid);
3131 : : }
3132 : : else
3133 : : {
3134 : 49 : appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
3135 : : qdatname);
3136 : : }
7785 tgl@sss.pgh.pa.us 3137 [ + - ]: 62 : if (strlen(encoding) > 0)
3138 : : {
3800 heikki.linnakangas@i 3139 : 62 : appendPQExpBufferStr(creaQry, " ENCODING = ");
4451 rhaas@postgresql.org 3140 : 62 : appendStringLiteralAH(creaQry, encoding, fout);
3141 : : }
3142 : :
759 peter@eisentraut.org 3143 : 62 : appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
32 jdavis@postgresql.or 3144 [ + + ]:GNC 62 : if (datlocprovider[0] == 'b')
3145 : 14 : appendPQExpBufferStr(creaQry, "builtin");
3146 [ + - ]: 48 : else if (datlocprovider[0] == 'c')
759 peter@eisentraut.org 3147 :CBC 48 : appendPQExpBufferStr(creaQry, "libc");
759 peter@eisentraut.org 3148 [ # # ]:LBC (14) : else if (datlocprovider[0] == 'i')
3149 : (14) : appendPQExpBufferStr(creaQry, "icu");
3150 : : else
737 tgl@sss.pgh.pa.us 3151 :UBC 0 : pg_fatal("unrecognized locale provider: %s",
3152 : : datlocprovider);
3153 : :
1727 peter@eisentraut.org 3154 [ + - + - ]:CBC 62 : if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
3155 : : {
3156 : 62 : appendPQExpBufferStr(creaQry, " LOCALE = ");
4451 rhaas@postgresql.org 3157 : 62 : appendStringLiteralAH(creaQry, collate, fout);
3158 : : }
3159 : : else
3160 : : {
1727 peter@eisentraut.org 3161 [ # # ]:UBC 0 : if (strlen(collate) > 0)
3162 : : {
3163 : 0 : appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
3164 : 0 : appendStringLiteralAH(creaQry, collate, fout);
3165 : : }
3166 [ # # ]: 0 : if (strlen(ctype) > 0)
3167 : : {
3168 : 0 : appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
3169 : 0 : appendStringLiteralAH(creaQry, ctype, fout);
3170 : : }
3171 : : }
36 jdavis@postgresql.or 3172 [ + + ]:GNC 62 : if (locale)
3173 : : {
32 3174 [ + - ]: 14 : if (datlocprovider[0] == 'b')
3175 : 14 : appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
3176 : : else
32 jdavis@postgresql.or 3177 :UNC 0 : appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
3178 : :
36 jdavis@postgresql.or 3179 :GNC 14 : appendStringLiteralAH(creaQry, locale, fout);
3180 : : }
3181 : :
403 peter@eisentraut.org 3182 [ - + ]:CBC 62 : if (icurules)
3183 : : {
403 peter@eisentraut.org 3184 :UBC 0 : appendPQExpBufferStr(creaQry, " ICU_RULES = ");
3185 : 0 : appendStringLiteralAH(creaQry, icurules, fout);
3186 : : }
3187 : :
3188 : : /*
3189 : : * For binary upgrade, carry over the collation version. For normal
3190 : : * dump/restore, omit the version, so that it is computed upon restore.
3191 : : */
790 peter@eisentraut.org 3192 [ + + ]:CBC 62 : if (dopt->binary_upgrade)
3193 : : {
3194 [ + - ]: 13 : if (!PQgetisnull(res, 0, i_datcollversion))
3195 : : {
3196 : 13 : appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
3197 : 13 : appendStringLiteralAH(creaQry,
3198 : : PQgetvalue(res, 0, i_datcollversion),
3199 : : fout);
3200 : : }
3201 : : }
3202 : :
3203 : : /*
3204 : : * Note: looking at dopt->outputNoTablespaces here is completely the wrong
3205 : : * thing; the decision whether to specify a tablespace should be left till
3206 : : * pg_restore, so that pg_restore --no-tablespaces applies. Ideally we'd
3207 : : * label the DATABASE entry with the tablespace and let the normal
3208 : : * tablespace selection logic work ... but CREATE DATABASE doesn't pay
3209 : : * attention to default_tablespace, so that won't work.
3210 : : */
2775 tgl@sss.pgh.pa.us 3211 [ + - - + ]: 62 : if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2775 tgl@sss.pgh.pa.us 3212 [ # # ]:UBC 0 : !dopt->outputNoTablespaces)
7118 3213 : 0 : appendPQExpBuffer(creaQry, " TABLESPACE = %s",
3214 : : fmtId(tablespace));
3800 heikki.linnakangas@i 3215 :CBC 62 : appendPQExpBufferStr(creaQry, ";\n");
3216 : :
8098 tgl@sss.pgh.pa.us 3217 : 62 : appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
3218 : : qdatname);
3219 : :
7435 3220 : 62 : dbDumpId = createDumpId();
3221 : :
4451 rhaas@postgresql.org 3222 : 62 : ArchiveEntry(fout,
3223 : : dbCatId, /* catalog ID */
3224 : : dbDumpId, /* dump ID */
1899 alvherre@alvh.no-ip. 3225 : 62 : ARCHIVE_OPTS(.tag = datname,
3226 : : .owner = dba,
3227 : : .description = "DATABASE",
3228 : : .section = SECTION_PRE_DATA,
3229 : : .createStmt = creaQry->data,
3230 : : .dropStmt = delQry->data));
3231 : :
3232 : : /* Compute correct tag for archive entry */
2274 tgl@sss.pgh.pa.us 3233 : 62 : appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
3234 : :
3235 : : /* Dump DB comment if any */
3236 : : {
3237 : : /*
3238 : : * 8.2 and up keep comments on shared objects in a shared table, so we
3239 : : * cannot use the dumpComment() code used for other database objects.
3240 : : * Be careful that the ArchiveEntry parameters match that function.
3241 : : */
3242 : 62 : char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
3243 : :
2271 3244 [ + - + + : 62 : if (comment && *comment && !dopt->no_comments)
+ - ]
3245 : : {
2274 3246 : 27 : resetPQExpBuffer(dbQry);
3247 : :
3248 : : /*
3249 : : * Generates warning when loaded into a differently-named
3250 : : * database.
3251 : : */
3252 : 27 : appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
3253 : 27 : appendStringLiteralAH(dbQry, comment, fout);
3254 : 27 : appendPQExpBufferStr(dbQry, ";\n");
3255 : :
3256 : 27 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 3257 : 27 : ARCHIVE_OPTS(.tag = labelq->data,
3258 : : .owner = dba,
3259 : : .description = "COMMENT",
3260 : : .section = SECTION_NONE,
3261 : : .createStmt = dbQry->data,
3262 : : .deps = &dbDumpId,
3263 : : .nDeps = 1));
3264 : : }
3265 : : }
3266 : :
3267 : : /* Dump DB security label, if enabled */
852 tgl@sss.pgh.pa.us 3268 [ + - ]: 62 : if (!dopt->no_security_labels)
3269 : : {
3270 : : PGresult *shres;
3271 : : PQExpBuffer seclabelQry;
3272 : :
2274 3273 : 62 : seclabelQry = createPQExpBuffer();
3274 : :
1328 peter@eisentraut.org 3275 : 62 : buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
2274 tgl@sss.pgh.pa.us 3276 : 62 : shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
3277 : 62 : resetPQExpBuffer(seclabelQry);
3278 : 62 : emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
3279 [ - + ]: 62 : if (seclabelQry->len > 0)
2274 tgl@sss.pgh.pa.us 3280 :UBC 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 3281 : 0 : ARCHIVE_OPTS(.tag = labelq->data,
3282 : : .owner = dba,
3283 : : .description = "SECURITY LABEL",
3284 : : .section = SECTION_NONE,
3285 : : .createStmt = seclabelQry->data,
3286 : : .deps = &dbDumpId,
3287 : : .nDeps = 1));
2274 tgl@sss.pgh.pa.us 3288 :CBC 62 : destroyPQExpBuffer(seclabelQry);
3289 : 62 : PQclear(shres);
3290 : : }
3291 : :
3292 : : /*
3293 : : * Dump ACL if any. Note that we do not support initial privileges
3294 : : * (pg_init_privs) on databases.
3295 : : */
860 3296 : 62 : dbdacl.privtype = 0;
3297 : 62 : dbdacl.initprivs = NULL;
3298 : :
1373 3299 : 62 : dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
3300 : : qdatname, NULL, NULL,
3301 : : NULL, dba, &dbdacl);
3302 : :
3303 : : /*
3304 : : * Now construct a DATABASE PROPERTIES archive entry to restore any
3305 : : * non-default database-level properties. (The reason this must be
3306 : : * separate is that we cannot put any additional commands into the TOC
3307 : : * entry that has CREATE DATABASE. pg_restore would execute such a group
3308 : : * in an implicit transaction block, and the backend won't allow CREATE
3309 : : * DATABASE in that context.)
3310 : : */
2274 3311 : 62 : resetPQExpBuffer(creaQry);
3312 : 62 : resetPQExpBuffer(delQry);
3313 : :
3314 [ + - - + ]: 62 : if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2274 tgl@sss.pgh.pa.us 3315 :UBC 0 : appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
3316 : : qdatname, datconnlimit);
3317 : :
2274 tgl@sss.pgh.pa.us 3318 [ + + ]:CBC 62 : if (strcmp(datistemplate, "t") == 0)
3319 : : {
3320 : 4 : appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
3321 : : qdatname);
3322 : :
3323 : : /*
3324 : : * The backend won't accept DROP DATABASE on a template database. We
3325 : : * can deal with that by removing the template marking before the DROP
3326 : : * gets issued. We'd prefer to use ALTER DATABASE IF EXISTS here, but
3327 : : * since no such command is currently supported, fake it with a direct
3328 : : * UPDATE on pg_database.
3329 : : */
3330 : 4 : appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
3331 : : "SET datistemplate = false WHERE datname = ");
3332 : 4 : appendStringLiteralAH(delQry, datname, fout);
3333 : 4 : appendPQExpBufferStr(delQry, ";\n");
3334 : : }
3335 : :
3336 : : /*
3337 : : * We do not restore pg_database.dathasloginevt because it is set
3338 : : * automatically on login event trigger creation.
3339 : : */
3340 : :
3341 : : /* Add database-specific SET options */
3342 : 62 : dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
3343 : :
3344 : : /*
3345 : : * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
3346 : : * entry, too, for lack of a better place.
3347 : : */
3348 [ + + ]: 62 : if (dopt->binary_upgrade)
3349 : : {
3350 : 13 : appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
3351 : 13 : appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
3352 : : "SET datfrozenxid = '%u', datminmxid = '%u'\n"
3353 : : "WHERE datname = ",
3354 : : frozenxid, minmxid);
3355 : 13 : appendStringLiteralAH(creaQry, datname, fout);
3356 : 13 : appendPQExpBufferStr(creaQry, ";\n");
3357 : : }
3358 : :
3359 [ + + ]: 62 : if (creaQry->len > 0)
3360 : 17 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 3361 : 17 : ARCHIVE_OPTS(.tag = datname,
3362 : : .owner = dba,
3363 : : .description = "DATABASE PROPERTIES",
3364 : : .section = SECTION_PRE_DATA,
3365 : : .createStmt = creaQry->data,
3366 : : .dropStmt = delQry->data,
3367 : : .deps = &dbDumpId));
3368 : :
3369 : : /*
3370 : : * pg_largeobject comes from the old system intact, so set its
3371 : : * relfrozenxids, relminmxids and relfilenode.
3372 : : */
3470 3373 [ + + ]: 62 : if (dopt->binary_upgrade)
3374 : : {
3375 : : PGresult *lo_res;
5382 bruce@momjian.us 3376 : 13 : PQExpBuffer loFrozenQry = createPQExpBuffer();
3377 : 13 : PQExpBuffer loOutQry = createPQExpBuffer();
625 rhaas@postgresql.org 3378 : 13 : PQExpBuffer loHorizonQry = createPQExpBuffer();
3379 : : int ii_relfrozenxid,
3380 : : ii_relfilenode,
3381 : : ii_oid,
3382 : : ii_relminmxid;
3383 : :
3384 : : /*
3385 : : * pg_largeobject
3386 : : */
3574 bruce@momjian.us 3387 [ + - ]: 13 : if (fout->remoteVersion >= 90300)
646 rhaas@postgresql.org 3388 : 13 : appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
3389 : : "FROM pg_catalog.pg_class\n"
3390 : : "WHERE oid IN (%u, %u);\n",
3391 : : LargeObjectRelationId, LargeObjectLOidPNIndexId);
3392 : : else
646 rhaas@postgresql.org 3393 :UBC 0 : appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
3394 : : "FROM pg_catalog.pg_class\n"
3395 : : "WHERE oid IN (%u, %u);\n",
3396 : : LargeObjectRelationId, LargeObjectLOidPNIndexId);
3397 : :
646 rhaas@postgresql.org 3398 :CBC 13 : lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
3399 : :
603 drowley@postgresql.o 3400 : 13 : ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
3401 : 13 : ii_relminmxid = PQfnumber(lo_res, "relminmxid");
3402 : 13 : ii_relfilenode = PQfnumber(lo_res, "relfilenode");
3403 : 13 : ii_oid = PQfnumber(lo_res, "oid");
3404 : :
625 rhaas@postgresql.org 3405 : 13 : appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3406 : 13 : appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
646 3407 [ + + ]: 39 : for (int i = 0; i < PQntuples(lo_res); ++i)
3408 : : {
3409 : : Oid oid;
3410 : : RelFileNumber relfilenumber;
3411 : :
625 3412 : 26 : appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
3413 : : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3414 : : "WHERE oid = %u;\n",
603 drowley@postgresql.o 3415 : 26 : atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
3416 : 26 : atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
3417 : 26 : atooid(PQgetvalue(lo_res, i, ii_oid)));
3418 : :
3419 : 26 : oid = atooid(PQgetvalue(lo_res, i, ii_oid));
564 rhaas@postgresql.org 3420 : 26 : relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
3421 : :
626 3422 [ + + ]: 26 : if (oid == LargeObjectRelationId)
625 3423 : 13 : appendPQExpBuffer(loOutQry,
3424 : : "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
3425 : : relfilenumber);
626 3426 [ + - ]: 13 : else if (oid == LargeObjectLOidPNIndexId)
625 3427 : 13 : appendPQExpBuffer(loOutQry,
3428 : : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
3429 : : relfilenumber);
3430 : : }
3431 : :
3432 : 13 : appendPQExpBufferStr(loOutQry,
3433 : : "TRUNCATE pg_catalog.pg_largeobject;\n");
3434 : 13 : appendPQExpBufferStr(loOutQry, loHorizonQry->data);
3435 : :
4451 3436 : 13 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 3437 : 13 : ARCHIVE_OPTS(.tag = "pg_largeobject",
3438 : : .description = "pg_largeobject",
3439 : : .section = SECTION_PRE_DATA,
3440 : : .createStmt = loOutQry->data));
3441 : :
5382 bruce@momjian.us 3442 : 13 : PQclear(lo_res);
3443 : :
3444 : 13 : destroyPQExpBuffer(loFrozenQry);
625 rhaas@postgresql.org 3445 : 13 : destroyPQExpBuffer(loHorizonQry);
5382 bruce@momjian.us 3446 : 13 : destroyPQExpBuffer(loOutQry);
3447 : : }
3448 : :
3374 andres@anarazel.de 3449 : 62 : PQclear(res);
3450 : :
2274 tgl@sss.pgh.pa.us 3451 : 62 : free(qdatname);
8290 3452 : 62 : destroyPQExpBuffer(dbQry);
3453 : 62 : destroyPQExpBuffer(delQry);
3454 : 62 : destroyPQExpBuffer(creaQry);
2274 3455 : 62 : destroyPQExpBuffer(labelq);
8657 pjw@rhyme.com.au 3456 : 62 : }
3457 : :
3458 : : /*
3459 : : * Collect any database-specific or role-and-database-specific SET options
3460 : : * for this database, and append them to outbuf.
3461 : : */
3462 : : static void
2274 tgl@sss.pgh.pa.us 3463 : 62 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
3464 : : const char *dbname, Oid dboid)
3465 : : {
3466 : 62 : PGconn *conn = GetConnection(AH);
3467 : 62 : PQExpBuffer buf = createPQExpBuffer();
3468 : : PGresult *res;
3469 : :
3470 : : /* First collect database-specific options */
333 akorotkov@postgresql 3471 : 62 : printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
3472 : : "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3473 : : dboid);
3474 : :
852 tgl@sss.pgh.pa.us 3475 : 62 : res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3476 : :
3477 [ + + ]: 92 : for (int i = 0; i < PQntuples(res); i++)
333 akorotkov@postgresql 3478 : 30 : makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
3479 : : "DATABASE", dbname, NULL, NULL,
3480 : : outbuf);
3481 : :
852 tgl@sss.pgh.pa.us 3482 : 62 : PQclear(res);
3483 : :
3484 : : /* Now look for role-and-database-specific options */
333 akorotkov@postgresql 3485 : 62 : printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3486 : : "FROM pg_db_role_setting s, pg_roles r "
3487 : : "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3488 : : dboid);
3489 : :
852 tgl@sss.pgh.pa.us 3490 : 62 : res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3491 : :
3492 [ - + ]: 62 : for (int i = 0; i < PQntuples(res); i++)
333 akorotkov@postgresql 3493 :UBC 0 : makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
852 tgl@sss.pgh.pa.us 3494 : 0 : "ROLE", PQgetvalue(res, i, 0),
3495 : : "DATABASE", dbname,
3496 : : outbuf);
3497 : :
852 tgl@sss.pgh.pa.us 3498 :CBC 62 : PQclear(res);
3499 : :
2274 3500 : 62 : destroyPQExpBuffer(buf);
3501 : 62 : }
3502 : :
3503 : : /*
3504 : : * dumpEncoding: put the correct encoding into the archive
3505 : : */
3506 : : static void
7355 3507 : 155 : dumpEncoding(Archive *AH)
3508 : : {
6531 3509 : 155 : const char *encname = pg_encoding_to_char(AH->encoding);
3510 : 155 : PQExpBuffer qry = createPQExpBuffer();
3511 : :
1840 peter@eisentraut.org 3512 : 155 : pg_log_info("saving encoding = %s", encname);
3513 : :
3800 heikki.linnakangas@i 3514 : 155 : appendPQExpBufferStr(qry, "SET client_encoding = ");
6531 tgl@sss.pgh.pa.us 3515 : 155 : appendStringLiteralAH(qry, encname, AH);
3800 heikki.linnakangas@i 3516 : 155 : appendPQExpBufferStr(qry, ";\n");
3517 : :
7355 tgl@sss.pgh.pa.us 3518 : 155 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 3519 : 155 : ARCHIVE_OPTS(.tag = "ENCODING",
3520 : : .description = "ENCODING",
3521 : : .section = SECTION_PRE_DATA,
3522 : : .createStmt = qry->data));
3523 : :
7355 tgl@sss.pgh.pa.us 3524 : 155 : destroyPQExpBuffer(qry);
3525 : 155 : }
3526 : :
3527 : :
3528 : : /*
3529 : : * dumpStdStrings: put the correct escape string behavior into the archive
3530 : : */
3531 : : static void
6533 bruce@momjian.us 3532 : 155 : dumpStdStrings(Archive *AH)
3533 : : {
6531 tgl@sss.pgh.pa.us 3534 [ + - ]: 155 : const char *stdstrings = AH->std_strings ? "on" : "off";
3535 : 155 : PQExpBuffer qry = createPQExpBuffer();
3536 : :
1840 peter@eisentraut.org 3537 : 155 : pg_log_info("saving standard_conforming_strings = %s",
3538 : : stdstrings);
3539 : :
6531 tgl@sss.pgh.pa.us 3540 : 155 : appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3541 : : stdstrings);
3542 : :
6533 bruce@momjian.us 3543 : 155 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 3544 : 155 : ARCHIVE_OPTS(.tag = "STDSTRINGS",
3545 : : .description = "STDSTRINGS",
3546 : : .section = SECTION_PRE_DATA,
3547 : : .createStmt = qry->data));
3548 : :
6533 bruce@momjian.us 3549 : 155 : destroyPQExpBuffer(qry);
3550 : 155 : }
3551 : :
3552 : : /*
3553 : : * dumpSearchPath: record the active search_path in the archive
3554 : : */
3555 : : static void
2239 tgl@sss.pgh.pa.us 3556 : 155 : dumpSearchPath(Archive *AH)
3557 : : {
3558 : 155 : PQExpBuffer qry = createPQExpBuffer();
3559 : 155 : PQExpBuffer path = createPQExpBuffer();
3560 : : PGresult *res;
3561 : 155 : char **schemanames = NULL;
3562 : 155 : int nschemanames = 0;
3563 : : int i;
3564 : :
3565 : : /*
3566 : : * We use the result of current_schemas(), not the search_path GUC,
3567 : : * because that might contain wildcards such as "$user", which won't
3568 : : * necessarily have the same value during restore. Also, this way avoids
3569 : : * listing schemas that may appear in search_path but not actually exist,
3570 : : * which seems like a prudent exclusion.
3571 : : */
3572 : 155 : res = ExecuteSqlQueryForSingleRow(AH,
3573 : : "SELECT pg_catalog.current_schemas(false)");
3574 : :
3575 [ - + ]: 155 : if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
737 tgl@sss.pgh.pa.us 3576 :UBC 0 : pg_fatal("could not parse result of current_schemas()");
3577 : :
3578 : : /*
3579 : : * We use set_config(), not a simple "SET search_path" command, because
3580 : : * the latter has less-clean behavior if the search path is empty. While
3581 : : * that's likely to get fixed at some point, it seems like a good idea to
3582 : : * be as backwards-compatible as possible in what we put into archives.
3583 : : */
2239 tgl@sss.pgh.pa.us 3584 [ - + ]:CBC 155 : for (i = 0; i < nschemanames; i++)
3585 : : {
2239 tgl@sss.pgh.pa.us 3586 [ # # ]:UBC 0 : if (i > 0)
3587 : 0 : appendPQExpBufferStr(path, ", ");
3588 : 0 : appendPQExpBufferStr(path, fmtId(schemanames[i]));
3589 : : }
3590 : :
2239 tgl@sss.pgh.pa.us 3591 :CBC 155 : appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3592 : 155 : appendStringLiteralAH(qry, path->data, AH);
3593 : 155 : appendPQExpBufferStr(qry, ", false);\n");
3594 : :
1840 peter@eisentraut.org 3595 : 155 : pg_log_info("saving search_path = %s", path->data);
3596 : :
2239 tgl@sss.pgh.pa.us 3597 : 155 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 3598 : 155 : ARCHIVE_OPTS(.tag = "SEARCHPATH",
3599 : : .description = "SEARCHPATH",
3600 : : .section = SECTION_PRE_DATA,
3601 : : .createStmt = qry->data));
3602 : :
3603 : : /* Also save it in AH->searchpath, in case we're doing plain text dump */
2239 tgl@sss.pgh.pa.us 3604 : 155 : AH->searchpath = pg_strdup(qry->data);
3605 : :
668 peter@eisentraut.org 3606 : 155 : free(schemanames);
2239 tgl@sss.pgh.pa.us 3607 : 155 : PQclear(res);
3608 : 155 : destroyPQExpBuffer(qry);
3609 : 155 : destroyPQExpBuffer(path);
3610 : 155 : }
3611 : :
3612 : :
3613 : : /*
3614 : : * getLOs:
3615 : : * Collect schema-level data about large objects
3616 : : */
3617 : : static void
496 peter@eisentraut.org 3618 : 131 : getLOs(Archive *fout)
3619 : : {
2930 sfrost@snowman.net 3620 : 131 : DumpOptions *dopt = fout->dopt;
496 peter@eisentraut.org 3621 : 131 : PQExpBuffer loQry = createPQExpBuffer();
3622 : : PGresult *res;
3623 : : int ntups;
3624 : : int i;
3625 : : int n;
3626 : : int i_oid;
3627 : : int i_lomowner;
3628 : : int i_lomacl;
3629 : : int i_acldefault;
3630 : :
1840 3631 : 131 : pg_log_info("reading large objects");
3632 : :
3633 : : /*
3634 : : * Fetch LO OIDs and owner/ACL data. Order the data so that all the blobs
3635 : : * with the same owner/ACL appear together.
3636 : : */
496 3637 : 131 : appendPQExpBufferStr(loQry,
3638 : : "SELECT oid, lomowner, lomacl, "
3639 : : "acldefault('L', lomowner) AS acldefault "
3640 : : "FROM pg_largeobject_metadata "
3641 : : "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
3642 : :
3643 : 131 : res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
3644 : :
2930 sfrost@snowman.net 3645 : 131 : i_oid = PQfnumber(res, "oid");
835 tgl@sss.pgh.pa.us 3646 : 131 : i_lomowner = PQfnumber(res, "lomowner");
2930 sfrost@snowman.net 3647 : 131 : i_lomacl = PQfnumber(res, "lomacl");
860 tgl@sss.pgh.pa.us 3648 : 131 : i_acldefault = PQfnumber(res, "acldefault");
3649 : :
5169 3650 : 131 : ntups = PQntuples(res);
3651 : :
3652 : : /*
3653 : : * Group the blobs into suitably-sized groups that have the same owner and
3654 : : * ACL setting, and build a metadata and a data DumpableObject for each
3655 : : * group. (If we supported initprivs for blobs, we'd have to insist that
3656 : : * groups also share initprivs settings, since the DumpableObject only has
3657 : : * room for one.) i is the index of the first tuple in the current group,
3658 : : * and n is the number of tuples we include in the group.
3659 : : */
13 tgl@sss.pgh.pa.us 3660 [ + + ]:GNC 210 : for (i = 0; i < ntups; i += n)
3661 : : {
3662 : 79 : Oid thisoid = atooid(PQgetvalue(res, i, i_oid));
3663 : 79 : char *thisowner = PQgetvalue(res, i, i_lomowner);
3664 : 79 : char *thisacl = PQgetvalue(res, i, i_lomacl);
3665 : : LoInfo *loinfo;
3666 : : DumpableObject *lodata;
3667 : : char namebuf[64];
3668 : :
3669 : : /* Scan to find first tuple not to be included in group */
3670 : 79 : n = 1;
3671 [ + - + + ]: 89 : while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
3672 : : {
3673 [ + - ]: 47 : if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
3674 [ + + ]: 47 : strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
3675 : : break;
3676 : 10 : n++;
3677 : : }
3678 : :
3679 : : /* Build the metadata DumpableObject */
3680 : 79 : loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
3681 : :
3682 : 79 : loinfo->dobj.objType = DO_LARGE_OBJECT;
3683 : 79 : loinfo->dobj.catId.tableoid = LargeObjectRelationId;
3684 : 79 : loinfo->dobj.catId.oid = thisoid;
3685 : 79 : AssignDumpId(&loinfo->dobj);
3686 : :
3687 [ + + ]: 79 : if (n > 1)
3688 : 5 : snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
3689 : 5 : atooid(PQgetvalue(res, i + n - 1, i_oid)));
3690 : : else
3691 : 74 : snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
3692 : 79 : loinfo->dobj.name = pg_strdup(namebuf);
3693 : 79 : loinfo->dacl.acl = pg_strdup(thisacl);
3694 : 79 : loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
3695 : 79 : loinfo->dacl.privtype = 0;
3696 : 79 : loinfo->dacl.initprivs = NULL;
3697 : 79 : loinfo->rolname = getRoleName(thisowner);
3698 : 79 : loinfo->numlos = n;
3699 : 79 : loinfo->looids[0] = thisoid;
3700 : : /* Collect OIDs of the remaining blobs in this group */
3701 [ + + ]: 89 : for (int k = 1; k < n; k++)
3702 : : {
3703 : : CatalogId extraID;
3704 : :
3705 : 10 : loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
3706 : :
3707 : : /* Make sure we can look up loinfo by any of the blobs' OIDs */
3708 : 10 : extraID.tableoid = LargeObjectRelationId;
3709 : 10 : extraID.oid = loinfo->looids[k];
3710 : 10 : recordAdditionalCatalogID(extraID, &loinfo->dobj);
3711 : : }
3712 : :
3713 : : /* LOs have data */
3714 : 79 : loinfo->dobj.components |= DUMP_COMPONENT_DATA;
3715 : :
3716 : : /* Mark whether LO group has a non-empty ACL */
860 tgl@sss.pgh.pa.us 3717 [ + + ]:CBC 79 : if (!PQgetisnull(res, i, i_lomacl))
13 tgl@sss.pgh.pa.us 3718 :GNC 37 : loinfo->dobj.components |= DUMP_COMPONENT_ACL;
3719 : :
3720 : : /*
3721 : : * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
3722 : : * as it will be copied by pg_upgrade, which simply copies the
3723 : : * pg_largeobject table. We *do* however dump out anything but the
3724 : : * data, as pg_upgrade copies just pg_largeobject, but not
3725 : : * pg_largeobject_metadata, after the dump is restored.
3726 : : */
2596 sfrost@snowman.net 3727 [ + + ]:CBC 79 : if (dopt->binary_upgrade)
13 tgl@sss.pgh.pa.us 3728 :GNC 3 : loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
3729 : :
3730 : : /*
3731 : : * Create a "BLOBS" data item for the group, too. This is just a
3732 : : * placeholder for sorting; it carries no data now.
3733 : : */
496 peter@eisentraut.org 3734 :CBC 79 : lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3735 : 79 : lodata->objType = DO_LARGE_OBJECT_DATA;
3736 : 79 : lodata->catId = nilCatalogId;
3737 : 79 : AssignDumpId(lodata);
13 tgl@sss.pgh.pa.us 3738 :GNC 79 : lodata->name = pg_strdup(namebuf);
496 peter@eisentraut.org 3739 :CBC 79 : lodata->components |= DUMP_COMPONENT_DATA;
3740 : : /* Set up explicit dependency from data to metadata */
13 tgl@sss.pgh.pa.us 3741 :GNC 79 : lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
3742 : 79 : lodata->dependencies[0] = loinfo->dobj.dumpId;
3743 : 79 : lodata->nDeps = lodata->allocDeps = 1;
3744 : : }
3745 : :
6863 tgl@sss.pgh.pa.us 3746 :CBC 131 : PQclear(res);
496 peter@eisentraut.org 3747 : 131 : destroyPQExpBuffer(loQry);
5169 tgl@sss.pgh.pa.us 3748 : 131 : }
3749 : :
3750 : : /*
3751 : : * dumpLO
3752 : : *
3753 : : * dump the definition (metadata) of the given large object group
3754 : : */
3755 : : static void
496 peter@eisentraut.org 3756 : 79 : dumpLO(Archive *fout, const LoInfo *loinfo)
3757 : : {
5161 bruce@momjian.us 3758 : 79 : PQExpBuffer cquery = createPQExpBuffer();
3759 : :
3760 : : /*
3761 : : * The "definition" is just a newline-separated list of OIDs. We need to
3762 : : * put something into the dropStmt too, but it can just be a comment.
3763 : : */
13 tgl@sss.pgh.pa.us 3764 [ + + ]:GNC 168 : for (int i = 0; i < loinfo->numlos; i++)
3765 : 89 : appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
3766 : :
496 peter@eisentraut.org 3767 [ + - ]:CBC 79 : if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3768 : 79 : ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
3769 : 79 : ARCHIVE_OPTS(.tag = loinfo->dobj.name,
3770 : : .owner = loinfo->rolname,
3771 : : .description = "BLOB METADATA",
3772 : : .section = SECTION_DATA,
3773 : : .createStmt = cquery->data,
3774 : : .dropStmt = "-- dummy"));
3775 : :
3776 : : /*
3777 : : * Dump per-blob comments and seclabels if any. We assume these are rare
3778 : : * enough that it's okay to generate retail TOC entries for them.
3779 : : */
13 tgl@sss.pgh.pa.us 3780 [ + + ]:GNC 79 : if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
3781 : : DUMP_COMPONENT_SECLABEL))
3782 : : {
3783 [ + + ]: 94 : for (int i = 0; i < loinfo->numlos; i++)
3784 : : {
3785 : : CatalogId catId;
3786 : : char namebuf[32];
3787 : :
3788 : : /* Build identifying info for this blob */
3789 : 52 : catId.tableoid = loinfo->dobj.catId.tableoid;
3790 : 52 : catId.oid = loinfo->looids[i];
3791 : 52 : snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
3792 : :
3793 [ + - ]: 52 : if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3794 : 52 : dumpComment(fout, "LARGE OBJECT", namebuf,
3795 : 52 : NULL, loinfo->rolname,
3796 : 52 : catId, 0, loinfo->dobj.dumpId);
3797 : :
3798 [ - + ]: 52 : if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
13 tgl@sss.pgh.pa.us 3799 :UNC 0 : dumpSecLabel(fout, "LARGE OBJECT", namebuf,
3800 : 0 : NULL, loinfo->rolname,
3801 : 0 : catId, 0, loinfo->dobj.dumpId);
3802 : : }
3803 : : }
3804 : :
3805 : : /*
3806 : : * Dump the ACLs if any (remember that all blobs in the group will have
3807 : : * the same ACL). If there's just one blob, dump a simple ACL entry; if
3808 : : * there's more, make a "LARGE OBJECTS" entry that really contains only
3809 : : * the ACL for the first blob. _printTocEntry() will be cued by the tag
3810 : : * string to emit a mutated version for each blob.
3811 : : */
496 peter@eisentraut.org 3812 [ + + ]:CBC 79 : if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
3813 : : {
3814 : : char namebuf[32];
3815 : :
3816 : : /* Build identifying info for the first blob */
13 tgl@sss.pgh.pa.us 3817 :GNC 37 : snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
3818 : :
3819 [ - + ]: 37 : if (loinfo->numlos > 1)
3820 : : {
3821 : : char tagbuf[64];
3822 : :
13 tgl@sss.pgh.pa.us 3823 :UNC 0 : snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
3824 : 0 : loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
3825 : :
3826 : 0 : dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
3827 : : "LARGE OBJECT", namebuf, NULL, NULL,
3828 : 0 : tagbuf, loinfo->rolname, &loinfo->dacl);
3829 : : }
3830 : : else
3831 : : {
13 tgl@sss.pgh.pa.us 3832 :GNC 37 : dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
3833 : : "LARGE OBJECT", namebuf, NULL, NULL,
3834 : 37 : NULL, loinfo->rolname, &loinfo->dacl);
3835 : : }
3836 : : }
3837 : :
5169 tgl@sss.pgh.pa.us 3838 :CBC 79 : destroyPQExpBuffer(cquery);
6863 3839 : 79 : }
3840 : :
3841 : : /*
3842 : : * dumpLOs:
3843 : : * dump the data contents of the large objects in the given group
3844 : : */
3845 : : static int
496 peter@eisentraut.org 3846 : 72 : dumpLOs(Archive *fout, const void *arg)
3847 : : {
13 tgl@sss.pgh.pa.us 3848 :GNC 72 : const LoInfo *loinfo = (const LoInfo *) arg;
4441 rhaas@postgresql.org 3849 :CBC 72 : PGconn *conn = GetConnection(fout);
3850 : : char buf[LOBBUFSIZE];
3851 : :
13 tgl@sss.pgh.pa.us 3852 :GNC 72 : pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
3853 : :
3854 [ + + ]: 152 : for (int i = 0; i < loinfo->numlos; i++)
3855 : : {
3856 : 80 : Oid loOid = loinfo->looids[i];
3857 : : int loFd;
3858 : : int cnt;
3859 : :
3860 : : /* Open the LO */
3861 : 80 : loFd = lo_open(conn, loOid, INV_READ);
3862 [ - + ]: 80 : if (loFd == -1)
13 tgl@sss.pgh.pa.us 3863 :UNC 0 : pg_fatal("could not open large object %u: %s",
3864 : : loOid, PQerrorMessage(conn));
3865 : :
13 tgl@sss.pgh.pa.us 3866 :GNC 80 : StartLO(fout, loOid);
3867 : :
3868 : : /* Now read it in chunks, sending data to archive */
3869 : : do
3870 : : {
3871 : 122 : cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3872 [ - + ]: 122 : if (cnt < 0)
13 tgl@sss.pgh.pa.us 3873 :UNC 0 : pg_fatal("error reading large object %u: %s",
3874 : : loOid, PQerrorMessage(conn));
3875 : :
13 tgl@sss.pgh.pa.us 3876 :GNC 122 : WriteData(fout, buf, cnt);
3877 [ + + ]: 122 : } while (cnt > 0);
3878 : :
3879 : 80 : lo_close(conn, loFd);
3880 : :
3881 : 80 : EndLO(fout, loOid);
3882 : : }
3883 : :
6863 tgl@sss.pgh.pa.us 3884 :CBC 72 : return 1;
3885 : : }
3886 : :
3887 : : /*
3888 : : * getPolicies
3889 : : * get information about all RLS policies on dumpable tables.
3890 : : */
3891 : : void
3426 sfrost@snowman.net 3892 : 155 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3893 : : {
3894 : : PQExpBuffer query;
3895 : : PQExpBuffer tbloids;
3896 : : PGresult *res;
3897 : : PolicyInfo *polinfo;
3898 : : int i_oid;
3899 : : int i_tableoid;
3900 : : int i_polrelid;
3901 : : int i_polname;
3902 : : int i_polcmd;
3903 : : int i_polpermissive;
3904 : : int i_polroles;
3905 : : int i_polqual;
3906 : : int i_polwithcheck;
3907 : : int i,
3908 : : j,
3909 : : ntups;
3910 : :
3911 : : /* No policies before 9.5 */
3495 3912 [ - + ]: 155 : if (fout->remoteVersion < 90500)
3495 sfrost@snowman.net 3913 :UBC 0 : return;
3914 : :
3490 sfrost@snowman.net 3915 :CBC 155 : query = createPQExpBuffer();
835 tgl@sss.pgh.pa.us 3916 : 155 : tbloids = createPQExpBuffer();
3917 : :
3918 : : /*
3919 : : * Identify tables of interest, and check which ones have RLS enabled.
3920 : : */
3921 : 155 : appendPQExpBufferChar(tbloids, '{');
3495 sfrost@snowman.net 3922 [ + + ]: 39419 : for (i = 0; i < numTables; i++)
3923 : : {
3467 tgl@sss.pgh.pa.us 3924 : 39264 : TableInfo *tbinfo = &tblinfo[i];
3925 : :
3926 : : /* Ignore row security on tables not to be dumped */
2930 sfrost@snowman.net 3927 [ + + ]: 39264 : if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3495 3928 : 33327 : continue;
3929 : :
3930 : : /* It can't have RLS or policies if it's not a table */
835 tgl@sss.pgh.pa.us 3931 [ + + ]: 5937 : if (tbinfo->relkind != RELKIND_RELATION &&
3932 [ + + ]: 1684 : tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
3933 : 1163 : continue;
3934 : :
3935 : : /* Add it to the list of table OIDs to be probed below */
3936 [ + + ]: 4774 : if (tbloids->len > 1) /* do we have more than the '{'? */
3937 : 4675 : appendPQExpBufferChar(tbloids, ',');
3938 : 4774 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
3939 : :
3940 : : /* Is RLS enabled? (That's separate from whether it has policies) */
3490 sfrost@snowman.net 3941 [ + + ]: 4774 : if (tbinfo->rowsec)
3942 : : {
860 tgl@sss.pgh.pa.us 3943 : 55 : tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
3944 : :
3945 : : /*
3946 : : * We represent RLS being enabled on a table by creating a
3947 : : * PolicyInfo object with null polname.
3948 : : *
3949 : : * Note: use tableoid 0 so that this object won't be mistaken for
3950 : : * something that pg_depend entries apply to.
3951 : : */
3426 sfrost@snowman.net 3952 : 55 : polinfo = pg_malloc(sizeof(PolicyInfo));
3953 : 55 : polinfo->dobj.objType = DO_POLICY;
3954 : 55 : polinfo->dobj.catId.tableoid = 0;
3955 : 55 : polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3956 : 55 : AssignDumpId(&polinfo->dobj);
3957 : 55 : polinfo->dobj.namespace = tbinfo->dobj.namespace;
3958 : 55 : polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3959 : 55 : polinfo->poltable = tbinfo;
3960 : 55 : polinfo->polname = NULL;
2687 3961 : 55 : polinfo->polcmd = '\0';
3962 : 55 : polinfo->polpermissive = 0;
3426 3963 : 55 : polinfo->polroles = NULL;
3964 : 55 : polinfo->polqual = NULL;
3965 : 55 : polinfo->polwithcheck = NULL;
3966 : : }
3967 : : }
835 tgl@sss.pgh.pa.us 3968 : 155 : appendPQExpBufferChar(tbloids, '}');
3969 : :
3970 : : /*
3971 : : * Now, read all RLS policies belonging to the tables of interest, and
3972 : : * create PolicyInfo objects for them. (Note that we must filter the
3973 : : * results server-side not locally, because we dare not apply pg_get_expr
3974 : : * to tables we don't have lock on.)
3975 : : */
957 3976 : 155 : pg_log_info("reading row-level security policies");
3977 : :
3978 : 155 : printfPQExpBuffer(query,
3979 : : "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
3980 [ + - ]: 155 : if (fout->remoteVersion >= 100000)
586 drowley@postgresql.o 3981 : 155 : appendPQExpBufferStr(query, "pol.polpermissive, ");
3982 : : else
586 drowley@postgresql.o 3983 :UBC 0 : appendPQExpBufferStr(query, "'t' as polpermissive, ");
957 tgl@sss.pgh.pa.us 3984 :CBC 155 : appendPQExpBuffer(query,
3985 : : "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3986 : : " 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, "
3987 : : "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3988 : : "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3989 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
3990 : : "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
3991 : : tbloids->data);
3992 : :
3993 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3994 : :
3995 : 155 : ntups = PQntuples(res);
3996 [ + + ]: 155 : if (ntups > 0)
3997 : : {
3495 sfrost@snowman.net 3998 : 45 : i_oid = PQfnumber(res, "oid");
3999 : 45 : i_tableoid = PQfnumber(res, "tableoid");
957 tgl@sss.pgh.pa.us 4000 : 45 : i_polrelid = PQfnumber(res, "polrelid");
3426 sfrost@snowman.net 4001 : 45 : i_polname = PQfnumber(res, "polname");
4002 : 45 : i_polcmd = PQfnumber(res, "polcmd");
2687 4003 : 45 : i_polpermissive = PQfnumber(res, "polpermissive");
3426 4004 : 45 : i_polroles = PQfnumber(res, "polroles");
4005 : 45 : i_polqual = PQfnumber(res, "polqual");
4006 : 45 : i_polwithcheck = PQfnumber(res, "polwithcheck");
4007 : :
4008 : 45 : polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
4009 : :
3495 4010 [ + + ]: 330 : for (j = 0; j < ntups; j++)
4011 : : {
957 tgl@sss.pgh.pa.us 4012 : 285 : Oid polrelid = atooid(PQgetvalue(res, j, i_polrelid));
4013 : 285 : TableInfo *tbinfo = findTableByOid(polrelid);
4014 : :
860 4015 : 285 : tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
4016 : :
3426 sfrost@snowman.net 4017 : 285 : polinfo[j].dobj.objType = DO_POLICY;
4018 : 285 : polinfo[j].dobj.catId.tableoid =
3495 4019 : 285 : atooid(PQgetvalue(res, j, i_tableoid));
3426 4020 : 285 : polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4021 : 285 : AssignDumpId(&polinfo[j].dobj);
4022 : 285 : polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4023 : 285 : polinfo[j].poltable = tbinfo;
4024 : 285 : polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
4025 : 285 : polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
4026 : :
2687 4027 : 285 : polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
4028 : 285 : polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
4029 : :
4030 [ + + ]: 285 : if (PQgetisnull(res, j, i_polroles))
4031 : 125 : polinfo[j].polroles = NULL;
4032 : : else
4033 : 160 : polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
4034 : :
3426 4035 [ + + ]: 285 : if (PQgetisnull(res, j, i_polqual))
4036 : 40 : polinfo[j].polqual = NULL;
4037 : : else
4038 : 245 : polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
4039 : :
4040 [ + + ]: 285 : if (PQgetisnull(res, j, i_polwithcheck))
4041 : 150 : polinfo[j].polwithcheck = NULL;
4042 : : else
4043 : 135 : polinfo[j].polwithcheck
4044 : 135 : = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
4045 : : }
4046 : : }
4047 : :
957 tgl@sss.pgh.pa.us 4048 : 155 : PQclear(res);
4049 : :
3495 sfrost@snowman.net 4050 : 155 : destroyPQExpBuffer(query);
835 tgl@sss.pgh.pa.us 4051 : 155 : destroyPQExpBuffer(tbloids);
4052 : : }
4053 : :
4054 : : /*
4055 : : * dumpPolicy
4056 : : * dump the definition of the given policy
4057 : : */
4058 : : static void
1159 peter@eisentraut.org 4059 : 340 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
4060 : : {
3014 tgl@sss.pgh.pa.us 4061 : 340 : DumpOptions *dopt = fout->dopt;
3426 sfrost@snowman.net 4062 : 340 : TableInfo *tbinfo = polinfo->poltable;
4063 : : PQExpBuffer query;
4064 : : PQExpBuffer delqry;
4065 : : PQExpBuffer polprefix;
4066 : : char *qtabname;
4067 : : const char *cmd;
4068 : : char *tag;
4069 : :
4070 : : /* Do nothing in data-only dump */
3470 alvherre@alvh.no-ip. 4071 [ + + ]: 340 : if (dopt->dataOnly)
3495 sfrost@snowman.net 4072 : 28 : return;
4073 : :
4074 : : /*
4075 : : * If polname is NULL, then this record is just indicating that ROW LEVEL
4076 : : * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
4077 : : * ROW LEVEL SECURITY.
4078 : : */
3426 4079 [ + + ]: 312 : if (polinfo->polname == NULL)
4080 : : {
3495 4081 : 51 : query = createPQExpBuffer();
4082 : :
4083 : 51 : appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
2057 tgl@sss.pgh.pa.us 4084 : 51 : fmtQualifiedDumpable(tbinfo));
4085 : :
4086 : : /*
4087 : : * We must emit the ROW SECURITY object's dependency on its table
4088 : : * explicitly, because it will not match anything in pg_depend (unlike
4089 : : * the case for other PolicyInfo objects).
4090 : : */
860 4091 [ + - ]: 51 : if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2930 sfrost@snowman.net 4092 : 51 : ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 4093 : 51 : ARCHIVE_OPTS(.tag = polinfo->dobj.name,
4094 : : .namespace = polinfo->dobj.namespace->dobj.name,
4095 : : .owner = tbinfo->rolname,
4096 : : .description = "ROW SECURITY",
4097 : : .section = SECTION_POST_DATA,
4098 : : .createStmt = query->data,
4099 : : .deps = &(tbinfo->dobj.dumpId),
4100 : : .nDeps = 1));
4101 : :
3495 sfrost@snowman.net 4102 : 51 : destroyPQExpBuffer(query);
4103 : 51 : return;
4104 : : }
4105 : :
2687 4106 [ + + ]: 261 : if (polinfo->polcmd == '*')
4107 : 87 : cmd = "";
4108 [ + + ]: 174 : else if (polinfo->polcmd == 'r')
4109 : 46 : cmd = " FOR SELECT";
4110 [ + + ]: 128 : else if (polinfo->polcmd == 'a')
4111 : 36 : cmd = " FOR INSERT";
4112 [ + + ]: 92 : else if (polinfo->polcmd == 'w')
4113 : 46 : cmd = " FOR UPDATE";
4114 [ + - ]: 46 : else if (polinfo->polcmd == 'd')
4115 : 46 : cmd = " FOR DELETE";
4116 : : else
737 tgl@sss.pgh.pa.us 4117 :UBC 0 : pg_fatal("unexpected policy command type: %c",
4118 : : polinfo->polcmd);
4119 : :
3495 sfrost@snowman.net 4120 :CBC 261 : query = createPQExpBuffer();
4121 : 261 : delqry = createPQExpBuffer();
1518 tgl@sss.pgh.pa.us 4122 : 261 : polprefix = createPQExpBuffer();
4123 : :
4124 : 261 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
4125 : :
3368 4126 : 261 : appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
4127 : :
2239 4128 : 261 : appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
2687 sfrost@snowman.net 4129 [ + + ]: 261 : !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
4130 : :
3426 4131 [ + + ]: 261 : if (polinfo->polroles != NULL)
4132 : 144 : appendPQExpBuffer(query, " TO %s", polinfo->polroles);
4133 : :
4134 [ + + ]: 261 : if (polinfo->polqual != NULL)
3184 mail@joeconway.com 4135 : 225 : appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
4136 : :
3426 sfrost@snowman.net 4137 [ + + ]: 261 : if (polinfo->polwithcheck != NULL)
3184 mail@joeconway.com 4138 : 123 : appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
4139 : :
1746 drowley@postgresql.o 4140 : 261 : appendPQExpBufferStr(query, ";\n");
4141 : :
3368 tgl@sss.pgh.pa.us 4142 : 261 : appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
2239 4143 : 261 : appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
4144 : :
1518 4145 : 261 : appendPQExpBuffer(polprefix, "POLICY %s ON",
4146 : 261 : fmtId(polinfo->polname));
4147 : :
2971 peter_e@gmx.net 4148 : 261 : tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
4149 : :
860 tgl@sss.pgh.pa.us 4150 [ + - ]: 261 : if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2930 sfrost@snowman.net 4151 : 261 : ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 4152 : 261 : ARCHIVE_OPTS(.tag = tag,
4153 : : .namespace = polinfo->dobj.namespace->dobj.name,
4154 : : .owner = tbinfo->rolname,
4155 : : .description = "POLICY",
4156 : : .section = SECTION_POST_DATA,
4157 : : .createStmt = query->data,
4158 : : .dropStmt = delqry->data));
4159 : :
1518 tgl@sss.pgh.pa.us 4160 [ - + ]: 261 : if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
1518 tgl@sss.pgh.pa.us 4161 :UBC 0 : dumpComment(fout, polprefix->data, qtabname,
4162 : 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
4163 : 0 : polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
4164 : :
2971 peter_e@gmx.net 4165 :CBC 261 : free(tag);
3495 sfrost@snowman.net 4166 : 261 : destroyPQExpBuffer(query);
4167 : 261 : destroyPQExpBuffer(delqry);
1518 tgl@sss.pgh.pa.us 4168 : 261 : destroyPQExpBuffer(polprefix);
4169 : 261 : free(qtabname);
4170 : : }
4171 : :
4172 : : /*
4173 : : * getPublications
4174 : : * get information about publications
4175 : : */
4176 : : PublicationInfo *
1186 4177 : 155 : getPublications(Archive *fout, int *numPublications)
4178 : : {
2529 peter_e@gmx.net 4179 : 155 : DumpOptions *dopt = fout->dopt;
4180 : : PQExpBuffer query;
4181 : : PGresult *res;
4182 : : PublicationInfo *pubinfo;
4183 : : int i_tableoid;
4184 : : int i_oid;
4185 : : int i_pubname;
4186 : : int i_pubowner;
4187 : : int i_puballtables;
4188 : : int i_pubinsert;
4189 : : int i_pubupdate;
4190 : : int i_pubdelete;
4191 : : int i_pubtruncate;
4192 : : int i_pubviaroot;
4193 : : int i,
4194 : : ntups;
4195 : :
4196 [ + - - + ]: 155 : if (dopt->no_publications || fout->remoteVersion < 100000)
4197 : : {
1186 tgl@sss.pgh.pa.us 4198 :UBC 0 : *numPublications = 0;
4199 : 0 : return NULL;
4200 : : }
4201 : :
2642 peter_e@gmx.net 4202 :CBC 155 : query = createPQExpBuffer();
4203 : :
4204 : 155 : resetPQExpBuffer(query);
4205 : :
4206 : : /* Get the publications. */
738 tomas.vondra@postgre 4207 [ + - ]: 155 : if (fout->remoteVersion >= 130000)
586 drowley@postgresql.o 4208 : 155 : appendPQExpBufferStr(query,
4209 : : "SELECT p.tableoid, p.oid, p.pubname, "
4210 : : "p.pubowner, "
4211 : : "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate, p.pubviaroot "
4212 : : "FROM pg_publication p");
1467 peter@eisentraut.org 4213 [ # # ]:UBC 0 : else if (fout->remoteVersion >= 110000)
586 drowley@postgresql.o 4214 : 0 : appendPQExpBufferStr(query,
4215 : : "SELECT p.tableoid, p.oid, p.pubname, "
4216 : : "p.pubowner, "
4217 : : "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate, false AS pubviaroot "
4218 : : "FROM pg_publication p");
4219 : : else
4220 : 0 : appendPQExpBufferStr(query,
4221 : : "SELECT p.tableoid, p.oid, p.pubname, "
4222 : : "p.pubowner, "
4223 : : "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate, false AS pubviaroot "
4224 : : "FROM pg_publication p");
4225 : :
2642 peter_e@gmx.net 4226 :CBC 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4227 : :
4228 : 155 : ntups = PQntuples(res);
4229 : :
4230 : 155 : i_tableoid = PQfnumber(res, "tableoid");
4231 : 155 : i_oid = PQfnumber(res, "oid");
4232 : 155 : i_pubname = PQfnumber(res, "pubname");
835 tgl@sss.pgh.pa.us 4233 : 155 : i_pubowner = PQfnumber(res, "pubowner");
2642 peter_e@gmx.net 4234 : 155 : i_puballtables = PQfnumber(res, "puballtables");
4235 : 155 : i_pubinsert = PQfnumber(res, "pubinsert");
4236 : 155 : i_pubupdate = PQfnumber(res, "pubupdate");
4237 : 155 : i_pubdelete = PQfnumber(res, "pubdelete");
2199 4238 : 155 : i_pubtruncate = PQfnumber(res, "pubtruncate");
1467 peter@eisentraut.org 4239 : 155 : i_pubviaroot = PQfnumber(res, "pubviaroot");
4240 : :
2642 peter_e@gmx.net 4241 : 155 : pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
4242 : :
4243 [ + + ]: 340 : for (i = 0; i < ntups; i++)
4244 : : {
4245 : 185 : pubinfo[i].dobj.objType = DO_PUBLICATION;
4246 : 185 : pubinfo[i].dobj.catId.tableoid =
4247 : 185 : atooid(PQgetvalue(res, i, i_tableoid));
4248 : 185 : pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4249 : 185 : AssignDumpId(&pubinfo[i].dobj);
4250 : 185 : pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
835 tgl@sss.pgh.pa.us 4251 : 185 : pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
2642 peter_e@gmx.net 4252 : 185 : pubinfo[i].puballtables =
4253 : 185 : (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
4254 : 185 : pubinfo[i].pubinsert =
4255 : 185 : (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
4256 : 185 : pubinfo[i].pubupdate =
4257 : 185 : (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
4258 : 185 : pubinfo[i].pubdelete =
4259 : 185 : (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
2199 4260 : 185 : pubinfo[i].pubtruncate =
4261 : 185 : (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
1467 peter@eisentraut.org 4262 : 185 : pubinfo[i].pubviaroot =
4263 : 185 : (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
4264 : :
4265 : : /* Decide whether we want to dump it */
2581 peter_e@gmx.net 4266 : 185 : selectDumpableObject(&(pubinfo[i].dobj), fout);
4267 : : }
2642 4268 : 155 : PQclear(res);
4269 : :
4270 : 155 : destroyPQExpBuffer(query);
4271 : :
1186 tgl@sss.pgh.pa.us 4272 : 155 : *numPublications = ntups;
4273 : 155 : return pubinfo;
4274 : : }
4275 : :
4276 : : /*
4277 : : * dumpPublication
4278 : : * dump the definition of the given publication
4279 : : */
4280 : : static void
1159 peter@eisentraut.org 4281 : 153 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
4282 : : {
836 tgl@sss.pgh.pa.us 4283 : 153 : DumpOptions *dopt = fout->dopt;
4284 : : PQExpBuffer delq;
4285 : : PQExpBuffer query;
4286 : : char *qpubname;
2529 peter_e@gmx.net 4287 : 153 : bool first = true;
4288 : :
4289 : : /* Do nothing in data-only dump */
836 tgl@sss.pgh.pa.us 4290 [ + + ]: 153 : if (dopt->dataOnly)
4291 : 12 : return;
4292 : :
2642 peter_e@gmx.net 4293 : 141 : delq = createPQExpBuffer();
4294 : 141 : query = createPQExpBuffer();
4295 : :
2239 tgl@sss.pgh.pa.us 4296 : 141 : qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
4297 : :
2642 peter_e@gmx.net 4298 : 141 : appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
4299 : : qpubname);
4300 : :
4301 : 141 : appendPQExpBuffer(query, "CREATE PUBLICATION %s",
4302 : : qpubname);
4303 : :
4304 [ + + ]: 141 : if (pubinfo->puballtables)
4305 : 36 : appendPQExpBufferStr(query, " FOR ALL TABLES");
4306 : :
2529 4307 : 141 : appendPQExpBufferStr(query, " WITH (publish = '");
2642 4308 [ + + ]: 141 : if (pubinfo->pubinsert)
4309 : : {
2529 4310 : 106 : appendPQExpBufferStr(query, "insert");
4311 : 106 : first = false;
4312 : : }
4313 : :
2642 4314 [ + + ]: 141 : if (pubinfo->pubupdate)
4315 : : {
2526 tgl@sss.pgh.pa.us 4316 [ + - ]: 106 : if (!first)
4317 : 106 : appendPQExpBufferStr(query, ", ");
4318 : :
2529 peter_e@gmx.net 4319 : 106 : appendPQExpBufferStr(query, "update");
4320 : 106 : first = false;
4321 : : }
4322 : :
2642 4323 [ + + ]: 141 : if (pubinfo->pubdelete)
4324 : : {
2526 tgl@sss.pgh.pa.us 4325 [ + - ]: 106 : if (!first)
4326 : 106 : appendPQExpBufferStr(query, ", ");
4327 : :
2529 peter_e@gmx.net 4328 : 106 : appendPQExpBufferStr(query, "delete");
4329 : 106 : first = false;
4330 : : }
4331 : :
2199 4332 [ + + ]: 141 : if (pubinfo->pubtruncate)
4333 : : {
4334 [ + - ]: 106 : if (!first)
4335 : 106 : appendPQExpBufferStr(query, ", ");
4336 : :
4337 : 106 : appendPQExpBufferStr(query, "truncate");
4338 : 106 : first = false;
4339 : : }
4340 : :
586 drowley@postgresql.o 4341 : 141 : appendPQExpBufferChar(query, '\'');
4342 : :
1467 peter@eisentraut.org 4343 [ - + ]: 141 : if (pubinfo->pubviaroot)
1467 peter@eisentraut.org 4344 :UBC 0 : appendPQExpBufferStr(query, ", publish_via_partition_root = true");
4345 : :
1467 peter@eisentraut.org 4346 :CBC 141 : appendPQExpBufferStr(query, ");\n");
4347 : :
860 tgl@sss.pgh.pa.us 4348 [ + - ]: 141 : if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4349 : 141 : ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
4350 : 141 : ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
4351 : : .owner = pubinfo->rolname,
4352 : : .description = "PUBLICATION",
4353 : : .section = SECTION_POST_DATA,
4354 : : .createStmt = query->data,
4355 : : .dropStmt = delq->data));
4356 : :
2558 peter_e@gmx.net 4357 [ + + ]: 141 : if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 4358 : 35 : dumpComment(fout, "PUBLICATION", qpubname,
2558 peter_e@gmx.net 4359 : 35 : NULL, pubinfo->rolname,
4360 : 35 : pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4361 : :
4362 [ - + ]: 141 : if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 4363 :UBC 0 : dumpSecLabel(fout, "PUBLICATION", qpubname,
2558 peter_e@gmx.net 4364 : 0 : NULL, pubinfo->rolname,
4365 : 0 : pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4366 : :
2642 peter_e@gmx.net 4367 :CBC 141 : destroyPQExpBuffer(delq);
4368 : 141 : destroyPQExpBuffer(query);
2239 tgl@sss.pgh.pa.us 4369 : 141 : free(qpubname);
4370 : : }
4371 : :
4372 : : /*
4373 : : * getPublicationNamespaces
4374 : : * get information about publication membership for dumpable schemas.
4375 : : */
4376 : : void
900 akapila@postgresql.o 4377 : 155 : getPublicationNamespaces(Archive *fout)
4378 : : {
4379 : : PQExpBuffer query;
4380 : : PGresult *res;
4381 : : PublicationSchemaInfo *pubsinfo;
4382 : 155 : DumpOptions *dopt = fout->dopt;
4383 : : int i_tableoid;
4384 : : int i_oid;
4385 : : int i_pnpubid;
4386 : : int i_pnnspid;
4387 : : int i,
4388 : : j,
4389 : : ntups;
4390 : :
4391 [ + - - + ]: 155 : if (dopt->no_publications || fout->remoteVersion < 150000)
900 akapila@postgresql.o 4392 :UBC 0 : return;
4393 : :
900 akapila@postgresql.o 4394 :CBC 155 : query = createPQExpBuffer();
4395 : :
4396 : : /* Collect all publication membership info. */
4397 : 155 : appendPQExpBufferStr(query,
4398 : : "SELECT tableoid, oid, pnpubid, pnnspid "
4399 : : "FROM pg_catalog.pg_publication_namespace");
4400 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4401 : :
4402 : 155 : ntups = PQntuples(res);
4403 : :
4404 : 155 : i_tableoid = PQfnumber(res, "tableoid");
4405 : 155 : i_oid = PQfnumber(res, "oid");
4406 : 155 : i_pnpubid = PQfnumber(res, "pnpubid");
4407 : 155 : i_pnnspid = PQfnumber(res, "pnnspid");
4408 : :
4409 : : /* this allocation may be more than we need */
4410 : 155 : pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
4411 : 155 : j = 0;
4412 : :
4413 [ + + ]: 247 : for (i = 0; i < ntups; i++)
4414 : : {
4415 : 92 : Oid pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
4416 : 92 : Oid pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
4417 : : PublicationInfo *pubinfo;
4418 : : NamespaceInfo *nspinfo;
4419 : :
4420 : : /*
4421 : : * Ignore any entries for which we aren't interested in either the
4422 : : * publication or the rel.
4423 : : */
4424 : 92 : pubinfo = findPublicationByOid(pnpubid);
4425 [ - + ]: 92 : if (pubinfo == NULL)
900 akapila@postgresql.o 4426 :UBC 0 : continue;
900 akapila@postgresql.o 4427 :CBC 92 : nspinfo = findNamespaceByOid(pnnspid);
4428 [ - + ]: 92 : if (nspinfo == NULL)
900 akapila@postgresql.o 4429 :UBC 0 : continue;
4430 : :
4431 : : /*
4432 : : * We always dump publication namespaces unless the corresponding
4433 : : * namespace is excluded from the dump.
4434 : : */
900 akapila@postgresql.o 4435 [ + + ]:CBC 92 : if (nspinfo->dobj.dump == DUMP_COMPONENT_NONE)
4436 : 15 : continue;
4437 : :
4438 : : /* OK, make a DumpableObject for this relationship */
887 4439 : 77 : pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
900 4440 : 77 : pubsinfo[j].dobj.catId.tableoid =
4441 : 77 : atooid(PQgetvalue(res, i, i_tableoid));
4442 : 77 : pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4443 : 77 : AssignDumpId(&pubsinfo[j].dobj);
4444 : 77 : pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
4445 : 77 : pubsinfo[j].dobj.name = nspinfo->dobj.name;
4446 : 77 : pubsinfo[j].publication = pubinfo;
4447 : 77 : pubsinfo[j].pubschema = nspinfo;
4448 : :
4449 : : /* Decide whether we want to dump it */
4450 : 77 : selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
4451 : :
4452 : 77 : j++;
4453 : : }
4454 : :
4455 : 155 : PQclear(res);
4456 : 155 : destroyPQExpBuffer(query);
4457 : : }
4458 : :
4459 : : /*
4460 : : * getPublicationTables
4461 : : * get information about publication membership for dumpable tables.
4462 : : */
4463 : : void
2642 peter_e@gmx.net 4464 : 155 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
4465 : : {
4466 : : PQExpBuffer query;
4467 : : PGresult *res;
4468 : : PublicationRelInfo *pubrinfo;
2028 michael@paquier.xyz 4469 : 155 : DumpOptions *dopt = fout->dopt;
4470 : : int i_tableoid;
4471 : : int i_oid;
4472 : : int i_prpubid;
4473 : : int i_prrelid;
4474 : : int i_prrelqual;
4475 : : int i_prattrs;
4476 : : int i,
4477 : : j,
4478 : : ntups;
4479 : :
4480 [ + - - + ]: 155 : if (dopt->no_publications || fout->remoteVersion < 100000)
2642 peter_e@gmx.net 4481 :UBC 0 : return;
4482 : :
2642 peter_e@gmx.net 4483 :CBC 155 : query = createPQExpBuffer();
4484 : :
4485 : : /* Collect all publication membership info. */
782 akapila@postgresql.o 4486 [ + - ]: 155 : if (fout->remoteVersion >= 150000)
4487 : 155 : appendPQExpBufferStr(query,
4488 : : "SELECT tableoid, oid, prpubid, prrelid, "
4489 : : "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
4490 : : "(CASE\n"
4491 : : " WHEN pr.prattrs IS NOT NULL THEN\n"
4492 : : " (SELECT array_agg(attname)\n"
4493 : : " FROM\n"
4494 : : " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
4495 : : " pg_catalog.pg_attribute\n"
4496 : : " WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
4497 : : " ELSE NULL END) prattrs "
4498 : : "FROM pg_catalog.pg_publication_rel pr");
4499 : : else
782 akapila@postgresql.o 4500 :UBC 0 : appendPQExpBufferStr(query,
4501 : : "SELECT tableoid, oid, prpubid, prrelid, "
4502 : : "NULL AS prrelqual, NULL AS prattrs "
4503 : : "FROM pg_catalog.pg_publication_rel");
1186 tgl@sss.pgh.pa.us 4504 :CBC 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4505 : :
4506 : 155 : ntups = PQntuples(res);
4507 : :
4508 : 155 : i_tableoid = PQfnumber(res, "tableoid");
4509 : 155 : i_oid = PQfnumber(res, "oid");
4510 : 155 : i_prpubid = PQfnumber(res, "prpubid");
4511 : 155 : i_prrelid = PQfnumber(res, "prrelid");
782 akapila@postgresql.o 4512 : 155 : i_prrelqual = PQfnumber(res, "prrelqual");
750 tomas.vondra@postgre 4513 : 155 : i_prattrs = PQfnumber(res, "prattrs");
4514 : :
4515 : : /* this allocation may be more than we need */
1186 tgl@sss.pgh.pa.us 4516 : 155 : pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
4517 : 155 : j = 0;
4518 : :
4519 [ + + ]: 477 : for (i = 0; i < ntups; i++)
4520 : : {
4521 : 322 : Oid prpubid = atooid(PQgetvalue(res, i, i_prpubid));
4522 : 322 : Oid prrelid = atooid(PQgetvalue(res, i, i_prrelid));
4523 : : PublicationInfo *pubinfo;
4524 : : TableInfo *tbinfo;
4525 : :
4526 : : /*
4527 : : * Ignore any entries for which we aren't interested in either the
4528 : : * publication or the rel.
4529 : : */
4530 : 322 : pubinfo = findPublicationByOid(prpubid);
4531 [ - + ]: 322 : if (pubinfo == NULL)
1186 tgl@sss.pgh.pa.us 4532 :UBC 0 : continue;
1186 tgl@sss.pgh.pa.us 4533 :CBC 322 : tbinfo = findTableByOid(prrelid);
4534 [ - + ]: 322 : if (tbinfo == NULL)
2642 peter_e@gmx.net 4535 :UBC 0 : continue;
4536 : :
4537 : : /*
4538 : : * Ignore publication membership of tables whose definitions are not
4539 : : * to be dumped.
4540 : : */
2642 peter_e@gmx.net 4541 [ + + ]:CBC 322 : if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4542 : 46 : continue;
4543 : :
4544 : : /* OK, make a DumpableObject for this relationship */
1186 tgl@sss.pgh.pa.us 4545 : 276 : pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
4546 : 276 : pubrinfo[j].dobj.catId.tableoid =
4547 : 276 : atooid(PQgetvalue(res, i, i_tableoid));
4548 : 276 : pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4549 : 276 : AssignDumpId(&pubrinfo[j].dobj);
4550 : 276 : pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4551 : 276 : pubrinfo[j].dobj.name = tbinfo->dobj.name;
4552 : 276 : pubrinfo[j].publication = pubinfo;
4553 : 276 : pubrinfo[j].pubtable = tbinfo;
782 akapila@postgresql.o 4554 [ + + ]: 276 : if (PQgetisnull(res, i, i_prrelqual))
4555 : 158 : pubrinfo[j].pubrelqual = NULL;
4556 : : else
4557 : 118 : pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
4558 : :
750 tomas.vondra@postgre 4559 [ + + ]: 276 : if (!PQgetisnull(res, i, i_prattrs))
4560 : : {
4561 : : char **attnames;
4562 : : int nattnames;
4563 : : PQExpBuffer attribs;
4564 : :
4565 [ - + ]: 78 : if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
4566 : : &attnames, &nattnames))
737 tgl@sss.pgh.pa.us 4567 :UBC 0 : pg_fatal("could not parse %s array", "prattrs");
750 tomas.vondra@postgre 4568 :CBC 78 : attribs = createPQExpBuffer();
4569 [ + + ]: 234 : for (int k = 0; k < nattnames; k++)
4570 : : {
4571 [ + + ]: 156 : if (k > 0)
4572 : 78 : appendPQExpBufferStr(attribs, ", ");
4573 : :
4574 : 156 : appendPQExpBufferStr(attribs, fmtId(attnames[k]));
4575 : : }
4576 : 78 : pubrinfo[j].pubrattrs = attribs->data;
4577 : : }
4578 : : else
4579 : 198 : pubrinfo[j].pubrattrs = NULL;
4580 : :
4581 : : /* Decide whether we want to dump it */
900 akapila@postgresql.o 4582 : 276 : selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
4583 : :
1186 tgl@sss.pgh.pa.us 4584 : 276 : j++;
4585 : : }
4586 : :
4587 : 155 : PQclear(res);
2642 peter_e@gmx.net 4588 : 155 : destroyPQExpBuffer(query);
4589 : : }
4590 : :
4591 : : /*
4592 : : * dumpPublicationNamespace
4593 : : * dump the definition of the given publication schema mapping.
4594 : : */
4595 : : static void
900 akapila@postgresql.o 4596 : 75 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
4597 : : {
836 tgl@sss.pgh.pa.us 4598 : 75 : DumpOptions *dopt = fout->dopt;
900 akapila@postgresql.o 4599 : 75 : NamespaceInfo *schemainfo = pubsinfo->pubschema;
4600 : 75 : PublicationInfo *pubinfo = pubsinfo->publication;
4601 : : PQExpBuffer query;
4602 : : char *tag;
4603 : :
4604 : : /* Do nothing in data-only dump */
836 tgl@sss.pgh.pa.us 4605 [ + + ]: 75 : if (dopt->dataOnly)
900 akapila@postgresql.o 4606 : 6 : return;
4607 : :
4608 : 69 : tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
4609 : :
4610 : 69 : query = createPQExpBuffer();
4611 : :
4612 : 69 : appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
570 alvherre@alvh.no-ip. 4613 : 69 : appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
4614 : :
4615 : : /*
4616 : : * There is no point in creating drop query as the drop is done by schema
4617 : : * drop.
4618 : : */
836 tgl@sss.pgh.pa.us 4619 [ + - ]: 69 : if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4620 : 69 : ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
4621 : 69 : ARCHIVE_OPTS(.tag = tag,
4622 : : .namespace = schemainfo->dobj.name,
4623 : : .owner = pubinfo->rolname,
4624 : : .description = "PUBLICATION TABLES IN SCHEMA",
4625 : : .section = SECTION_POST_DATA,
4626 : : .createStmt = query->data));
4627 : :
4628 : : /* These objects can't currently have comments or seclabels */
4629 : :
900 akapila@postgresql.o 4630 : 69 : free(tag);
4631 : 69 : destroyPQExpBuffer(query);
4632 : : }
4633 : :
4634 : : /*
4635 : : * dumpPublicationTable
4636 : : * dump the definition of the given publication table mapping
4637 : : */
4638 : : static void
1159 peter@eisentraut.org 4639 : 256 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
4640 : : {
836 tgl@sss.pgh.pa.us 4641 : 256 : DumpOptions *dopt = fout->dopt;
1186 4642 : 256 : PublicationInfo *pubinfo = pubrinfo->publication;
2642 peter_e@gmx.net 4643 : 256 : TableInfo *tbinfo = pubrinfo->pubtable;
4644 : : PQExpBuffer query;
4645 : : char *tag;
4646 : :
4647 : : /* Do nothing in data-only dump */
836 tgl@sss.pgh.pa.us 4648 [ + + ]: 256 : if (dopt->dataOnly)
4649 : 21 : return;
4650 : :
1186 4651 : 235 : tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
4652 : :
2642 peter_e@gmx.net 4653 : 235 : query = createPQExpBuffer();
4654 : :
738 tomas.vondra@postgre 4655 : 235 : appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4656 : 235 : fmtId(pubinfo->dobj.name));
782 akapila@postgresql.o 4657 : 235 : appendPQExpBuffer(query, " %s",
2239 tgl@sss.pgh.pa.us 4658 : 235 : fmtQualifiedDumpable(tbinfo));
4659 : :
750 tomas.vondra@postgre 4660 [ + + ]: 235 : if (pubrinfo->pubrattrs)
4661 : 68 : appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
4662 : :
782 akapila@postgresql.o 4663 [ + + ]: 235 : if (pubrinfo->pubrelqual)
4664 : : {
4665 : : /*
4666 : : * It's necessary to add parentheses around the expression because
4667 : : * pg_get_expr won't supply the parentheses for things like WHERE
4668 : : * TRUE.
4669 : : */
4670 : 101 : appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
4671 : : }
4672 : 235 : appendPQExpBufferStr(query, ";\n");
4673 : :
4674 : : /*
4675 : : * There is no point in creating a drop query as the drop is done by table
4676 : : * drop. (If you think to change this, see also _printTocEntry().)
4677 : : * Although this object doesn't really have ownership as such, set the
4678 : : * owner field anyway to ensure that the command is run by the correct
4679 : : * role at restore time.
4680 : : */
860 tgl@sss.pgh.pa.us 4681 [ + - ]: 235 : if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4682 : 235 : ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
4683 : 235 : ARCHIVE_OPTS(.tag = tag,
4684 : : .namespace = tbinfo->dobj.namespace->dobj.name,
4685 : : .owner = pubinfo->rolname,
4686 : : .description = "PUBLICATION TABLE",
4687 : : .section = SECTION_POST_DATA,
4688 : : .createStmt = query->data));
4689 : :
4690 : : /* These objects can't currently have comments or seclabels */
4691 : :
2642 peter_e@gmx.net 4692 : 235 : free(tag);
4693 : 235 : destroyPQExpBuffer(query);
4694 : : }
4695 : :
4696 : : /*
4697 : : * Is the currently connected user a superuser?
4698 : : */
4699 : : static bool
2560 4700 : 155 : is_superuser(Archive *fout)
4701 : : {
4702 : 155 : ArchiveHandle *AH = (ArchiveHandle *) fout;
4703 : : const char *val;
4704 : :
4705 : 155 : val = PQparameterStatus(AH->connection, "is_superuser");
4706 : :
4707 [ + - + + ]: 155 : if (val && strcmp(val, "on") == 0)
4708 : 152 : return true;
4709 : :
4710 : 3 : return false;
4711 : : }
4712 : :
4713 : : /*
4714 : : * getSubscriptions
4715 : : * get information about subscriptions
4716 : : */
4717 : : void
2642 4718 : 155 : getSubscriptions(Archive *fout)
4719 : : {
2532 4720 : 155 : DumpOptions *dopt = fout->dopt;
4721 : : PQExpBuffer query;
4722 : : PGresult *res;
4723 : : SubscriptionInfo *subinfo;
4724 : : int i_tableoid;
4725 : : int i_oid;
4726 : : int i_subname;
4727 : : int i_subowner;
4728 : : int i_subbinary;
4729 : : int i_substream;
4730 : : int i_subtwophasestate;
4731 : : int i_subdisableonerr;
4732 : : int i_subpasswordrequired;
4733 : : int i_subrunasowner;
4734 : : int i_subconninfo;
4735 : : int i_subslotname;
4736 : : int i_subsynccommit;
4737 : : int i_subpublications;
4738 : : int i_suborigin;
4739 : : int i_suboriginremotelsn;
4740 : : int i_subenabled;
4741 : : int i_subfailover;
4742 : : int i,
4743 : : ntups;
4744 : :
4745 [ + - - + ]: 155 : if (dopt->no_subscriptions || fout->remoteVersion < 100000)
2560 peter_e@gmx.net 4746 :UBC 0 : return;
4747 : :
2560 peter_e@gmx.net 4748 [ + + ]:CBC 155 : if (!is_superuser(fout))
4749 : : {
4750 : : int n;
4751 : :
4752 : 3 : res = ExecuteSqlQuery(fout,
4753 : : "SELECT count(*) FROM pg_subscription "
4754 : : "WHERE subdbid = (SELECT oid FROM pg_database"
4755 : : " WHERE datname = current_database())",
4756 : : PGRES_TUPLES_OK);
4757 : 3 : n = atoi(PQgetvalue(res, 0, 0));
4758 [ + + ]: 3 : if (n > 0)
1840 peter@eisentraut.org 4759 : 2 : pg_log_warning("subscriptions not dumped because current user is not a superuser");
2560 peter_e@gmx.net 4760 : 3 : PQclear(res);
2642 4761 : 3 : return;
4762 : : }
4763 : :
4764 : 152 : query = createPQExpBuffer();
4765 : :
4766 : : /* Get the subscriptions in current database. */
586 drowley@postgresql.o 4767 : 152 : appendPQExpBufferStr(query,
4768 : : "SELECT s.tableoid, s.oid, s.subname,\n"
4769 : : " s.subowner,\n"
4770 : : " s.subconninfo, s.subslotname, s.subsynccommit,\n"
4771 : : " s.subpublications,\n");
4772 : :
1366 tgl@sss.pgh.pa.us 4773 [ + - ]: 152 : if (fout->remoteVersion >= 140000)
1277 drowley@postgresql.o 4774 : 152 : appendPQExpBufferStr(query, " s.subbinary,\n");
4775 : : else
1277 drowley@postgresql.o 4776 :UBC 0 : appendPQExpBufferStr(query, " false AS subbinary,\n");
4777 : :
1319 akapila@postgresql.o 4778 [ + - ]:CBC 152 : if (fout->remoteVersion >= 140000)
1005 4779 : 152 : appendPQExpBufferStr(query, " s.substream,\n");
4780 : : else
461 akapila@postgresql.o 4781 :UBC 0 : appendPQExpBufferStr(query, " 'f' AS substream,\n");
4782 : :
1005 akapila@postgresql.o 4783 [ + - ]:CBC 152 : if (fout->remoteVersion >= 150000)
762 4784 : 152 : appendPQExpBufferStr(query,
4785 : : " s.subtwophasestate,\n"
4786 : : " s.subdisableonerr,\n");
4787 : : else
1005 akapila@postgresql.o 4788 :UBC 0 : appendPQExpBuffer(query,
4789 : : " '%c' AS subtwophasestate,\n"
4790 : : " false AS subdisableonerr,\n",
4791 : : LOGICALREP_TWOPHASE_STATE_DISABLED);
4792 : :
633 akapila@postgresql.o 4793 [ + - ]:CBC 152 : if (fout->remoteVersion >= 160000)
381 rhaas@postgresql.org 4794 : 152 : appendPQExpBufferStr(query,
4795 : : " s.subpasswordrequired,\n"
4796 : : " s.subrunasowner,\n"
4797 : : " s.suborigin,\n");
4798 : : else
381 rhaas@postgresql.org 4799 :UBC 0 : appendPQExpBuffer(query,
4800 : : " 't' AS subpasswordrequired,\n"
4801 : : " 't' AS subrunasowner,\n"
4802 : : " '%s' AS suborigin,\n",
4803 : : LOGICALREP_ORIGIN_ANY);
4804 : :
103 akapila@postgresql.o 4805 [ + + + - ]:GNC 152 : if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
4806 : 14 : appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
4807 : : " s.subenabled,\n"
4808 : : " s.subfailover\n");
4809 : : else
4810 : 138 : appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
4811 : : " false AS subenabled,\n"
4812 : : " false AS subfailover\n");
4813 : :
4814 : 152 : appendPQExpBufferStr(query,
4815 : : "FROM pg_subscription s\n");
4816 : :
4817 [ + + + - ]: 152 : if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
4818 : 14 : appendPQExpBufferStr(query,
4819 : : "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
4820 : : " ON o.external_id = 'pg_' || s.oid::text \n");
4821 : :
1277 drowley@postgresql.o 4822 :CBC 152 : appendPQExpBufferStr(query,
4823 : : "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
4824 : : " WHERE datname = current_database())");
4825 : :
2642 peter_e@gmx.net 4826 : 152 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4827 : :
4828 : 152 : ntups = PQntuples(res);
4829 : :
4830 : : /*
4831 : : * Get subscription fields. We don't include subskiplsn in the dump as
4832 : : * after restoring the dump this value may no longer be relevant.
4833 : : */
4834 : 152 : i_tableoid = PQfnumber(res, "tableoid");
4835 : 152 : i_oid = PQfnumber(res, "oid");
4836 : 152 : i_subname = PQfnumber(res, "subname");
835 tgl@sss.pgh.pa.us 4837 : 152 : i_subowner = PQfnumber(res, "subowner");
1366 4838 : 152 : i_subbinary = PQfnumber(res, "subbinary");
1319 akapila@postgresql.o 4839 : 152 : i_substream = PQfnumber(res, "substream");
1005 4840 : 152 : i_subtwophasestate = PQfnumber(res, "subtwophasestate");
762 4841 : 152 : i_subdisableonerr = PQfnumber(res, "subdisableonerr");
381 rhaas@postgresql.org 4842 : 152 : i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
168 tgl@sss.pgh.pa.us 4843 : 152 : i_subrunasowner = PQfnumber(res, "subrunasowner");
4844 : 152 : i_subconninfo = PQfnumber(res, "subconninfo");
4845 : 152 : i_subslotname = PQfnumber(res, "subslotname");
4846 : 152 : i_subsynccommit = PQfnumber(res, "subsynccommit");
4847 : 152 : i_subpublications = PQfnumber(res, "subpublications");
4848 : 152 : i_suborigin = PQfnumber(res, "suborigin");
103 akapila@postgresql.o 4849 :GNC 152 : i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
4850 : 152 : i_subenabled = PQfnumber(res, "subenabled");
75 4851 : 152 : i_subfailover = PQfnumber(res, "subfailover");
4852 : :
2642 peter_e@gmx.net 4853 :CBC 152 : subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4854 : :
4855 [ + + ]: 286 : for (i = 0; i < ntups; i++)
4856 : : {
4857 : 134 : subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4858 : 134 : subinfo[i].dobj.catId.tableoid =
4859 : 134 : atooid(PQgetvalue(res, i, i_tableoid));
4860 : 134 : subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4861 : 134 : AssignDumpId(&subinfo[i].dobj);
4862 : 134 : subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
835 tgl@sss.pgh.pa.us 4863 : 134 : subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
4864 : :
1366 4865 : 268 : subinfo[i].subbinary =
4866 : 134 : pg_strdup(PQgetvalue(res, i, i_subbinary));
1319 akapila@postgresql.o 4867 : 268 : subinfo[i].substream =
4868 : 134 : pg_strdup(PQgetvalue(res, i, i_substream));
1005 4869 : 268 : subinfo[i].subtwophasestate =
4870 : 134 : pg_strdup(PQgetvalue(res, i, i_subtwophasestate));
762 4871 : 268 : subinfo[i].subdisableonerr =
4872 : 134 : pg_strdup(PQgetvalue(res, i, i_subdisableonerr));
381 rhaas@postgresql.org 4873 : 268 : subinfo[i].subpasswordrequired =
4874 : 134 : pg_strdup(PQgetvalue(res, i, i_subpasswordrequired));
168 tgl@sss.pgh.pa.us 4875 : 268 : subinfo[i].subrunasowner =
4876 : 134 : pg_strdup(PQgetvalue(res, i, i_subrunasowner));
4877 : 268 : subinfo[i].subconninfo =
4878 : 134 : pg_strdup(PQgetvalue(res, i, i_subconninfo));
4879 [ - + ]: 134 : if (PQgetisnull(res, i, i_subslotname))
168 tgl@sss.pgh.pa.us 4880 :UBC 0 : subinfo[i].subslotname = NULL;
4881 : : else
168 tgl@sss.pgh.pa.us 4882 :CBC 134 : subinfo[i].subslotname =
4883 : 134 : pg_strdup(PQgetvalue(res, i, i_subslotname));
4884 : 268 : subinfo[i].subsynccommit =
4885 : 134 : pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4886 : 268 : subinfo[i].subpublications =
4887 : 134 : pg_strdup(PQgetvalue(res, i, i_subpublications));
4888 : 134 : subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
103 akapila@postgresql.o 4889 [ + + ]:GNC 134 : if (PQgetisnull(res, i, i_suboriginremotelsn))
4890 : 133 : subinfo[i].suboriginremotelsn = NULL;
4891 : : else
4892 : 1 : subinfo[i].suboriginremotelsn =
4893 : 1 : pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
4894 : 268 : subinfo[i].subenabled =
4895 : 134 : pg_strdup(PQgetvalue(res, i, i_subenabled));
75 4896 : 268 : subinfo[i].subfailover =
4897 : 134 : pg_strdup(PQgetvalue(res, i, i_subfailover));
4898 : :
4899 : : /* Decide whether we want to dump it */
2560 peter_e@gmx.net 4900 :CBC 134 : selectDumpableObject(&(subinfo[i].dobj), fout);
4901 : : }
2642 4902 : 152 : PQclear(res);
4903 : :
4904 : 152 : destroyPQExpBuffer(query);
4905 : : }
4906 : :
4907 : : /*
4908 : : * getSubscriptionTables
4909 : : * Get information about subscription membership for dumpable tables. This
4910 : : * will be used only in binary-upgrade mode for PG17 or later versions.
4911 : : */
4912 : : void
103 akapila@postgresql.o 4913 :GNC 155 : getSubscriptionTables(Archive *fout)
4914 : : {
4915 : 155 : DumpOptions *dopt = fout->dopt;
4916 : 155 : SubscriptionInfo *subinfo = NULL;
4917 : : SubRelInfo *subrinfo;
4918 : : PGresult *res;
4919 : : int i_srsubid;
4920 : : int i_srrelid;
4921 : : int i_srsubstate;
4922 : : int i_srsublsn;
4923 : : int ntups;
4924 : 155 : Oid last_srsubid = InvalidOid;
4925 : :
4926 [ + - + + ]: 155 : if (dopt->no_subscriptions || !dopt->binary_upgrade ||
4927 [ - + ]: 14 : fout->remoteVersion < 170000)
4928 : 141 : return;
4929 : :
4930 : 14 : res = ExecuteSqlQuery(fout,
4931 : : "SELECT srsubid, srrelid, srsubstate, srsublsn "
4932 : : "FROM pg_catalog.pg_subscription_rel "
4933 : : "ORDER BY srsubid",
4934 : : PGRES_TUPLES_OK);
4935 : 14 : ntups = PQntuples(res);
4936 [ + + ]: 14 : if (ntups == 0)
4937 : 13 : goto cleanup;
4938 : :
4939 : : /* Get pg_subscription_rel attributes */
4940 : 1 : i_srsubid = PQfnumber(res, "srsubid");
4941 : 1 : i_srrelid = PQfnumber(res, "srrelid");
4942 : 1 : i_srsubstate = PQfnumber(res, "srsubstate");
4943 : 1 : i_srsublsn = PQfnumber(res, "srsublsn");
4944 : :
4945 : 1 : subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
4946 [ + + ]: 3 : for (int i = 0; i < ntups; i++)
4947 : : {
4948 : 2 : Oid cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
4949 : 2 : Oid relid = atooid(PQgetvalue(res, i, i_srrelid));
4950 : : TableInfo *tblinfo;
4951 : :
4952 : : /*
4953 : : * If we switched to a new subscription, check if the subscription
4954 : : * exists.
4955 : : */
4956 [ + - ]: 2 : if (cur_srsubid != last_srsubid)
4957 : : {
4958 : 2 : subinfo = findSubscriptionByOid(cur_srsubid);
4959 [ - + ]: 2 : if (subinfo == NULL)
103 akapila@postgresql.o 4960 :UNC 0 : pg_fatal("subscription with OID %u does not exist", cur_srsubid);
4961 : :
103 akapila@postgresql.o 4962 :GNC 2 : last_srsubid = cur_srsubid;
4963 : : }
4964 : :
4965 : 2 : tblinfo = findTableByOid(relid);
4966 [ - + ]: 2 : if (tblinfo == NULL)
103 akapila@postgresql.o 4967 :UNC 0 : pg_fatal("failed sanity check, table with OID %u not found",
4968 : : relid);
4969 : :
4970 : : /* OK, make a DumpableObject for this relationship */
103 akapila@postgresql.o 4971 :GNC 2 : subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
4972 : 2 : subrinfo[i].dobj.catId.tableoid = relid;
4973 : 2 : subrinfo[i].dobj.catId.oid = cur_srsubid;
4974 : 2 : AssignDumpId(&subrinfo[i].dobj);
4975 : 2 : subrinfo[i].dobj.name = pg_strdup(subinfo->dobj.name);
4976 : 2 : subrinfo[i].tblinfo = tblinfo;
4977 : 2 : subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
4978 [ + + ]: 2 : if (PQgetisnull(res, i, i_srsublsn))
4979 : 1 : subrinfo[i].srsublsn = NULL;
4980 : : else
4981 : 1 : subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
4982 : :
4983 : 2 : subrinfo[i].subinfo = subinfo;
4984 : :
4985 : : /* Decide whether we want to dump it */
4986 : 2 : selectDumpableObject(&(subrinfo[i].dobj), fout);
4987 : : }
4988 : :
4989 : 1 : cleanup:
4990 : 14 : PQclear(res);
4991 : : }
4992 : :
4993 : : /*
4994 : : * dumpSubscriptionTable
4995 : : * Dump the definition of the given subscription table mapping. This will be
4996 : : * used only in binary-upgrade mode for PG17 or later versions.
4997 : : */
4998 : : static void
4999 : 2 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
5000 : : {
5001 : 2 : DumpOptions *dopt = fout->dopt;
5002 : 2 : SubscriptionInfo *subinfo = subrinfo->subinfo;
5003 : : PQExpBuffer query;
5004 : : char *tag;
5005 : :
5006 : : /* Do nothing in data-only dump */
5007 [ - + ]: 2 : if (dopt->dataOnly)
103 akapila@postgresql.o 5008 :UNC 0 : return;
5009 : :
103 akapila@postgresql.o 5010 [ + - + - ]:GNC 2 : Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
5011 : :
5012 : 2 : tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->dobj.name);
5013 : :
5014 : 2 : query = createPQExpBuffer();
5015 : :
5016 [ + - ]: 2 : if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5017 : : {
5018 : : /*
5019 : : * binary_upgrade_add_sub_rel_state will add the subscription relation
5020 : : * to pg_subscription_rel table. This will be used only in
5021 : : * binary-upgrade mode.
5022 : : */
5023 : 2 : appendPQExpBufferStr(query,
5024 : : "\n-- For binary upgrade, must preserve the subscriber table.\n");
5025 : 2 : appendPQExpBufferStr(query,
5026 : : "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
5027 : 2 : appendStringLiteralAH(query, subrinfo->dobj.name, fout);
5028 : 2 : appendPQExpBuffer(query,
5029 : : ", %u, '%c'",
5030 : 2 : subrinfo->tblinfo->dobj.catId.oid,
5031 : 2 : subrinfo->srsubstate);
5032 : :
5033 [ + + + - ]: 2 : if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
5034 : 1 : appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
5035 : : else
5036 : 1 : appendPQExpBuffer(query, ", NULL");
5037 : :
5038 : 2 : appendPQExpBufferStr(query, ");\n");
5039 : : }
5040 : :
5041 : : /*
5042 : : * There is no point in creating a drop query as the drop is done by table
5043 : : * drop. (If you think to change this, see also _printTocEntry().)
5044 : : * Although this object doesn't really have ownership as such, set the
5045 : : * owner field anyway to ensure that the command is run by the correct
5046 : : * role at restore time.
5047 : : */
5048 [ + - ]: 2 : if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5049 : 2 : ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
5050 : 2 : ARCHIVE_OPTS(.tag = tag,
5051 : : .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
5052 : : .owner = subinfo->rolname,
5053 : : .description = "SUBSCRIPTION TABLE",
5054 : : .section = SECTION_POST_DATA,
5055 : : .createStmt = query->data));
5056 : :
5057 : : /* These objects can't currently have comments or seclabels */
5058 : :
5059 : 2 : free(tag);
5060 : 2 : destroyPQExpBuffer(query);
5061 : : }
5062 : :
5063 : : /*
5064 : : * dumpSubscription
5065 : : * dump the definition of the given subscription
5066 : : */
5067 : : static void
1159 peter@eisentraut.org 5068 :CBC 116 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
5069 : : {
836 tgl@sss.pgh.pa.us 5070 : 116 : DumpOptions *dopt = fout->dopt;
5071 : : PQExpBuffer delq;
5072 : : PQExpBuffer query;
5073 : : PQExpBuffer publications;
5074 : : char *qsubname;
2642 peter_e@gmx.net 5075 : 116 : char **pubnames = NULL;
5076 : 116 : int npubnames = 0;
5077 : : int i;
1005 akapila@postgresql.o 5078 : 116 : char two_phase_disabled[] = {LOGICALREP_TWOPHASE_STATE_DISABLED, '\0'};
5079 : :
5080 : : /* Do nothing in data-only dump */
836 tgl@sss.pgh.pa.us 5081 [ + + ]: 116 : if (dopt->dataOnly)
5082 : 9 : return;
5083 : :
2642 peter_e@gmx.net 5084 : 107 : delq = createPQExpBuffer();
5085 : 107 : query = createPQExpBuffer();
5086 : :
2239 tgl@sss.pgh.pa.us 5087 : 107 : qsubname = pg_strdup(fmtId(subinfo->dobj.name));
5088 : :
2642 peter_e@gmx.net 5089 : 107 : appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
5090 : : qsubname);
5091 : :
5092 : 107 : appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
5093 : : qsubname);
5094 : 107 : appendStringLiteralAH(query, subinfo->subconninfo, fout);
5095 : :
5096 : : /* Build list of quoted publications and append them to query. */
5097 [ - + ]: 107 : if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
737 tgl@sss.pgh.pa.us 5098 :UBC 0 : pg_fatal("could not parse %s array", "subpublications");
5099 : :
2642 peter_e@gmx.net 5100 :CBC 107 : publications = createPQExpBuffer();
5101 [ + + ]: 214 : for (i = 0; i < npubnames; i++)
5102 : : {
5103 [ - + ]: 107 : if (i > 0)
2642 peter_e@gmx.net 5104 :UBC 0 : appendPQExpBufferStr(publications, ", ");
5105 : :
2642 peter_e@gmx.net 5106 :CBC 107 : appendPQExpBufferStr(publications, fmtId(pubnames[i]));
5107 : : }
5108 : :
2529 5109 : 107 : appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
2524 5110 [ + - ]: 107 : if (subinfo->subslotname)
5111 : 107 : appendStringLiteralAH(query, subinfo->subslotname, fout);
5112 : : else
2524 peter_e@gmx.net 5113 :UBC 0 : appendPQExpBufferStr(query, "NONE");
5114 : :
1366 tgl@sss.pgh.pa.us 5115 [ - + ]:CBC 107 : if (strcmp(subinfo->subbinary, "t") == 0)
1277 drowley@postgresql.o 5116 :UBC 0 : appendPQExpBufferStr(query, ", binary = true");
5117 : :
461 akapila@postgresql.o 5118 [ - + ]:CBC 107 : if (strcmp(subinfo->substream, "t") == 0)
1277 drowley@postgresql.o 5119 :UBC 0 : appendPQExpBufferStr(query, ", streaming = on");
461 akapila@postgresql.o 5120 [ - + ]:CBC 107 : else if (strcmp(subinfo->substream, "p") == 0)
461 akapila@postgresql.o 5121 :UBC 0 : appendPQExpBufferStr(query, ", streaming = parallel");
5122 : :
1005 akapila@postgresql.o 5123 [ - + ]:CBC 107 : if (strcmp(subinfo->subtwophasestate, two_phase_disabled) != 0)
1005 akapila@postgresql.o 5124 :UBC 0 : appendPQExpBufferStr(query, ", two_phase = on");
5125 : :
762 akapila@postgresql.o 5126 [ - + ]:CBC 107 : if (strcmp(subinfo->subdisableonerr, "t") == 0)
762 akapila@postgresql.o 5127 :UBC 0 : appendPQExpBufferStr(query, ", disable_on_error = true");
5128 : :
168 tgl@sss.pgh.pa.us 5129 [ - + ]:CBC 107 : if (strcmp(subinfo->subpasswordrequired, "t") != 0)
168 tgl@sss.pgh.pa.us 5130 :UBC 0 : appendPQExpBuffer(query, ", password_required = false");
5131 : :
168 tgl@sss.pgh.pa.us 5132 [ - + ]:CBC 107 : if (strcmp(subinfo->subrunasowner, "t") == 0)
168 tgl@sss.pgh.pa.us 5133 :UBC 0 : appendPQExpBufferStr(query, ", run_as_owner = true");
5134 : :
2557 peter_e@gmx.net 5135 [ - + ]:CBC 107 : if (strcmp(subinfo->subsynccommit, "off") != 0)
2529 peter_e@gmx.net 5136 :UBC 0 : appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
5137 : :
168 tgl@sss.pgh.pa.us 5138 [ + + ]:CBC 107 : if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
5139 : 35 : appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
5140 : :
2642 peter_e@gmx.net 5141 : 107 : appendPQExpBufferStr(query, ");\n");
5142 : :
5143 : : /*
5144 : : * In binary-upgrade mode, we allow the replication to continue after the
5145 : : * upgrade.
5146 : : */
103 akapila@postgresql.o 5147 [ + + + - ]:GNC 107 : if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5148 : : {
5149 [ + + ]: 5 : if (subinfo->suboriginremotelsn)
5150 : : {
5151 : : /*
5152 : : * Preserve the remote_lsn for the subscriber's replication
5153 : : * origin. This value is required to start the replication from
5154 : : * the position before the upgrade. This value will be stale if
5155 : : * the publisher gets upgraded before the subscriber node.
5156 : : * However, this shouldn't be a problem as the upgrade of the
5157 : : * publisher ensures that all the transactions were replicated
5158 : : * before upgrading it.
5159 : : */
5160 : 1 : appendPQExpBufferStr(query,
5161 : : "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
5162 : 1 : appendPQExpBufferStr(query,
5163 : : "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
5164 : 1 : appendStringLiteralAH(query, subinfo->dobj.name, fout);
5165 : 1 : appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
5166 : : }
5167 : :
75 5168 [ + + ]: 5 : if (strcmp(subinfo->subfailover, "t") == 0)
5169 : : {
5170 : : /*
5171 : : * Enable the failover to allow the subscription's slot to be
5172 : : * synced to the standbys after the upgrade.
5173 : : */
5174 : 1 : appendPQExpBufferStr(query,
5175 : : "\n-- For binary upgrade, must preserve the subscriber's failover option.\n");
5176 : 1 : appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s SET(failover = true);\n", qsubname);
5177 : : }
5178 : :
103 5179 [ + + ]: 5 : if (strcmp(subinfo->subenabled, "t") == 0)
5180 : : {
5181 : : /*
5182 : : * Enable the subscription to allow the replication to continue
5183 : : * after the upgrade.
5184 : : */
5185 : 1 : appendPQExpBufferStr(query,
5186 : : "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
5187 : 1 : appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
5188 : : }
5189 : : }
5190 : :
860 tgl@sss.pgh.pa.us 5191 [ + - ]:CBC 107 : if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5192 : 107 : ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
5193 : 107 : ARCHIVE_OPTS(.tag = subinfo->dobj.name,
5194 : : .owner = subinfo->rolname,
5195 : : .description = "SUBSCRIPTION",
5196 : : .section = SECTION_POST_DATA,
5197 : : .createStmt = query->data,
5198 : : .dropStmt = delq->data));
5199 : :
2558 peter_e@gmx.net 5200 [ + + ]: 107 : if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 5201 : 35 : dumpComment(fout, "SUBSCRIPTION", qsubname,
2558 peter_e@gmx.net 5202 : 35 : NULL, subinfo->rolname,
5203 : 35 : subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5204 : :
5205 [ - + ]: 107 : if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 5206 :UBC 0 : dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
2558 peter_e@gmx.net 5207 : 0 : NULL, subinfo->rolname,
5208 : 0 : subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5209 : :
2642 peter_e@gmx.net 5210 :CBC 107 : destroyPQExpBuffer(publications);
668 peter@eisentraut.org 5211 : 107 : free(pubnames);
5212 : :
2642 peter_e@gmx.net 5213 : 107 : destroyPQExpBuffer(delq);
5214 : 107 : destroyPQExpBuffer(query);
2239 tgl@sss.pgh.pa.us 5215 : 107 : free(qsubname);
5216 : : }
5217 : :
5218 : : /*
5219 : : * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
5220 : : * the object needs.
5221 : : */
5222 : : static void
1495 alvherre@alvh.no-ip. 5223 : 4772 : append_depends_on_extension(Archive *fout,
5224 : : PQExpBuffer create,
5225 : : const DumpableObject *dobj,
5226 : : const char *catalog,
5227 : : const char *keyword,
5228 : : const char *objname)
5229 : : {
5230 [ + + ]: 4772 : if (dobj->depends_on_ext)
5231 : : {
5232 : : char *nm;
5233 : : PGresult *res;
5234 : : PQExpBuffer query;
5235 : : int ntups;
5236 : : int i_extname;
5237 : : int i;
5238 : :
5239 : : /* dodge fmtId() non-reentrancy */
5240 : 42 : nm = pg_strdup(objname);
5241 : :
5242 : 42 : query = createPQExpBuffer();
5243 : 42 : appendPQExpBuffer(query,
5244 : : "SELECT e.extname "
5245 : : "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
5246 : : "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
5247 : : "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
5248 : : "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
5249 : : catalog,
5250 : 42 : dobj->catId.oid);
5251 : 42 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5252 : 42 : ntups = PQntuples(res);
5253 : 42 : i_extname = PQfnumber(res, "extname");
5254 [ + + ]: 84 : for (i = 0; i < ntups; i++)
5255 : : {
233 alvherre@alvh.no-ip. 5256 :GNC 42 : appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
5257 : : keyword, nm,
1495 alvherre@alvh.no-ip. 5258 :CBC 42 : fmtId(PQgetvalue(res, i, i_extname)));
5259 : : }
5260 : :
5261 : 42 : PQclear(res);
1490 5262 : 42 : destroyPQExpBuffer(query);
1495 5263 : 42 : pg_free(nm);
5264 : : }
5265 : 4772 : }
5266 : :
5267 : : static Oid
1211 akorotkov@postgresql 5268 :UBC 0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
5269 : : {
5270 : : /*
5271 : : * If the old version didn't assign an array type, but the new version
5272 : : * does, we must select an unused type OID to assign. This currently only
5273 : : * happens for domains, when upgrading pre-v11 to v11 and up.
5274 : : *
5275 : : * Note: local state here is kind of ugly, but we must have some, since we
5276 : : * mustn't choose the same unused OID more than once.
5277 : : */
5278 : : static Oid next_possible_free_oid = FirstNormalObjectId;
5279 : : PGresult *res;
5280 : : bool is_dup;
5281 : :
5282 : : do
5283 : : {
5284 : 0 : ++next_possible_free_oid;
5285 : 0 : printfPQExpBuffer(upgrade_query,
5286 : : "SELECT EXISTS(SELECT 1 "
5287 : : "FROM pg_catalog.pg_type "
5288 : : "WHERE oid = '%u'::pg_catalog.oid);",
5289 : : next_possible_free_oid);
5290 : 0 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5291 : 0 : is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
5292 : 0 : PQclear(res);
5293 [ # # ]: 0 : } while (is_dup);
5294 : :
5295 : 0 : return next_possible_free_oid;
5296 : : }
5297 : :
5298 : : static void
4450 rhaas@postgresql.org 5299 :CBC 827 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
5300 : : PQExpBuffer upgrade_buffer,
5301 : : Oid pg_type_oid,
5302 : : bool force_array_type,
5303 : : bool include_multirange_type)
5304 : : {
5225 bruce@momjian.us 5305 : 827 : PQExpBuffer upgrade_query = createPQExpBuffer();
5306 : : PGresult *res;
5307 : : Oid pg_type_array_oid;
5308 : : Oid pg_type_multirange_oid;
5309 : : Oid pg_type_multirange_array_oid;
5310 : :
3800 heikki.linnakangas@i 5311 : 827 : appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
5225 bruce@momjian.us 5312 : 827 : appendPQExpBuffer(upgrade_buffer,
5313 : : "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5314 : : pg_type_oid);
5315 : :
5316 : 827 : appendPQExpBuffer(upgrade_query,
5317 : : "SELECT typarray "
5318 : : "FROM pg_catalog.pg_type "
5319 : : "WHERE oid = '%u'::pg_catalog.oid;",
5320 : : pg_type_oid);
5321 : :
2388 tgl@sss.pgh.pa.us 5322 : 827 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5323 : :
5324 : 827 : pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
5325 : :
5326 : 827 : PQclear(res);
5327 : :
5328 [ + + - + ]: 827 : if (!OidIsValid(pg_type_array_oid) && force_array_type)
1211 akorotkov@postgresql 5329 :UBC 0 : pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5330 : :
5225 bruce@momjian.us 5331 [ + + ]:CBC 827 : if (OidIsValid(pg_type_array_oid))
5332 : : {
3800 heikki.linnakangas@i 5333 : 825 : appendPQExpBufferStr(upgrade_buffer,
5334 : : "\n-- For binary upgrade, must preserve pg_type array oid\n");
5225 bruce@momjian.us 5335 : 825 : appendPQExpBuffer(upgrade_buffer,
5336 : : "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5337 : : pg_type_array_oid);
5338 : : }
5339 : :
5340 : : /*
5341 : : * Pre-set the multirange type oid and its own array type oid.
5342 : : */
1211 akorotkov@postgresql 5343 [ + + ]: 827 : if (include_multirange_type)
5344 : : {
5345 [ + - ]: 6 : if (fout->remoteVersion >= 140000)
5346 : : {
812 tgl@sss.pgh.pa.us 5347 : 6 : printfPQExpBuffer(upgrade_query,
5348 : : "SELECT t.oid, t.typarray "
5349 : : "FROM pg_catalog.pg_type t "
5350 : : "JOIN pg_catalog.pg_range r "
5351 : : "ON t.oid = r.rngmultitypid "
5352 : : "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
5353 : : pg_type_oid);
5354 : :
1211 akorotkov@postgresql 5355 : 6 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5356 : :
5357 : 6 : pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
5358 : 6 : pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
5359 : :
5360 : 6 : PQclear(res);
5361 : : }
5362 : : else
5363 : : {
1211 akorotkov@postgresql 5364 :UBC 0 : pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5365 : 0 : pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5366 : : }
5367 : :
1211 akorotkov@postgresql 5368 :CBC 6 : appendPQExpBufferStr(upgrade_buffer,
5369 : : "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
5370 : 6 : appendPQExpBuffer(upgrade_buffer,
5371 : : "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5372 : : pg_type_multirange_oid);
5373 : 6 : appendPQExpBufferStr(upgrade_buffer,
5374 : : "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
5375 : 6 : appendPQExpBuffer(upgrade_buffer,
5376 : : "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5377 : : pg_type_multirange_array_oid);
5378 : : }
5379 : :
5225 bruce@momjian.us 5380 : 827 : destroyPQExpBuffer(upgrade_query);
5381 : 827 : }
5382 : :
5383 : : static void
860 tgl@sss.pgh.pa.us 5384 : 760 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
5385 : : PQExpBuffer upgrade_buffer,
5386 : : const TableInfo *tbinfo)
5387 : : {
5388 : 760 : Oid pg_type_oid = tbinfo->reltype;
5389 : :
1377 5390 [ + - ]: 760 : if (OidIsValid(pg_type_oid))
5391 : 760 : binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
5392 : : pg_type_oid, false, false);
5225 bruce@momjian.us 5393 : 760 : }
5394 : :
5395 : : static void
4450 rhaas@postgresql.org 5396 : 1119 : binary_upgrade_set_pg_class_oids(Archive *fout,
5397 : : PQExpBuffer upgrade_buffer, Oid pg_class_oid,
5398 : : bool is_index)
5399 : : {
818 5400 : 1119 : PQExpBuffer upgrade_query = createPQExpBuffer();
5401 : : PGresult *upgrade_res;
5402 : : RelFileNumber relfilenumber;
5403 : : Oid toast_oid;
5404 : : RelFileNumber toast_relfilenumber;
5405 : : char relkind;
5406 : : Oid toast_index_oid;
5407 : : RelFileNumber toast_index_relfilenumber;
5408 : :
5409 : : /*
5410 : : * Preserve the OID and relfilenumber of the table, table's index, table's
5411 : : * toast table and toast table's index if any.
5412 : : *
5413 : : * One complexity is that the current table definition might not require
5414 : : * the creation of a TOAST table, but the old database might have a TOAST
5415 : : * table that was created earlier, before some wide columns were dropped.
5416 : : * By setting the TOAST oid we force creation of the TOAST heap and index
5417 : : * by the new backend, so we can copy the files during binary upgrade
5418 : : * without worrying about this case.
5419 : : */
5420 : 1119 : appendPQExpBuffer(upgrade_query,
5421 : : "SELECT c.relkind, c.relfilenode, c.reltoastrelid, ct.relfilenode AS toast_relfilenode, i.indexrelid, cti.relfilenode AS toast_index_relfilenode "
5422 : : "FROM pg_catalog.pg_class c LEFT JOIN "
5423 : : "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
5424 : : "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
5425 : : "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
5426 : : "WHERE c.oid = '%u'::pg_catalog.oid;",
5427 : : pg_class_oid);
5428 : :
5429 : 1119 : upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5430 : :
5431 : 1119 : relkind = *PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "relkind"));
5432 : :
564 5433 : 1119 : relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
5434 : : PQfnumber(upgrade_res, "relfilenode")));
818 5435 : 1119 : toast_oid = atooid(PQgetvalue(upgrade_res, 0,
5436 : : PQfnumber(upgrade_res, "reltoastrelid")));
564 5437 : 1119 : toast_relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
5438 : : PQfnumber(upgrade_res, "toast_relfilenode")));
818 5439 : 1119 : toast_index_oid = atooid(PQgetvalue(upgrade_res, 0,
5440 : : PQfnumber(upgrade_res, "indexrelid")));
564 5441 : 1119 : toast_index_relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
5442 : : PQfnumber(upgrade_res, "toast_index_relfilenode")));
5443 : :
3800 heikki.linnakangas@i 5444 : 1119 : appendPQExpBufferStr(upgrade_buffer,
5445 : : "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
5446 : :
5212 bruce@momjian.us 5447 [ + + ]: 1119 : if (!is_index)
5448 : : {
5449 : 836 : appendPQExpBuffer(upgrade_buffer,
5450 : : "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
5451 : : pg_class_oid);
5452 : :
5453 : : /*
5454 : : * Not every relation has storage. Also, in a pre-v12 database,
5455 : : * partitioned tables have a relfilenumber, which should not be
5456 : : * preserved when upgrading.
5457 : : */
648 rhaas@postgresql.org 5458 [ + + + - ]: 836 : if (RelFileNumberIsValid(relfilenumber) && relkind != RELKIND_PARTITIONED_TABLE)
818 5459 : 686 : appendPQExpBuffer(upgrade_buffer,
5460 : : "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
5461 : : relfilenumber);
5462 : :
5463 : : /*
5464 : : * In a pre-v12 database, partitioned tables might be marked as having
5465 : : * toast tables, but we should ignore them if so.
5466 : : */
5467 [ + + + - ]: 836 : if (OidIsValid(toast_oid) &&
5468 : : relkind != RELKIND_PARTITIONED_TABLE)
5469 : : {
4848 bruce@momjian.us 5470 : 272 : appendPQExpBuffer(upgrade_buffer,
5471 : : "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
5472 : : toast_oid);
818 rhaas@postgresql.org 5473 : 272 : appendPQExpBuffer(upgrade_buffer,
5474 : : "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
5475 : : toast_relfilenumber);
5476 : :
5477 : : /* every toast table has an index */
4848 bruce@momjian.us 5478 : 272 : appendPQExpBuffer(upgrade_buffer,
5479 : : "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5480 : : toast_index_oid);
818 rhaas@postgresql.org 5481 : 272 : appendPQExpBuffer(upgrade_buffer,
5482 : : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5483 : : toast_index_relfilenumber);
5484 : : }
5485 : :
1377 tgl@sss.pgh.pa.us 5486 : 836 : PQclear(upgrade_res);
5487 : : }
5488 : : else
5489 : : {
5490 : : /* Preserve the OID and relfilenumber of the index */
5212 bruce@momjian.us 5491 : 283 : appendPQExpBuffer(upgrade_buffer,
5492 : : "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5493 : : pg_class_oid);
818 rhaas@postgresql.org 5494 : 283 : appendPQExpBuffer(upgrade_buffer,
5495 : : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5496 : : relfilenumber);
5497 : : }
5498 : :
3800 heikki.linnakangas@i 5499 : 1119 : appendPQExpBufferChar(upgrade_buffer, '\n');
5500 : :
812 tgl@sss.pgh.pa.us 5501 : 1119 : destroyPQExpBuffer(upgrade_query);
5225 bruce@momjian.us 5502 : 1119 : }
5503 : :
5504 : : /*
5505 : : * If the DumpableObject is a member of an extension, add a suitable
5506 : : * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
5507 : : *
5508 : : * For somewhat historical reasons, objname should already be quoted,
5509 : : * but not objnamespace (if any).
5510 : : */
5511 : : static void
4813 tgl@sss.pgh.pa.us 5512 : 1318 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
5513 : : const DumpableObject *dobj,
5514 : : const char *objtype,
5515 : : const char *objname,
5516 : : const char *objnamespace)
5517 : : {
5518 : 1318 : DumpableObject *extobj = NULL;
5519 : : int i;
5520 : :
5521 [ + + ]: 1318 : if (!dobj->ext_member)
5522 : 1302 : return;
5523 : :
5524 : : /*
5525 : : * Find the parent extension. We could avoid this search if we wanted to
5526 : : * add a link field to DumpableObject, but the space costs of that would
5527 : : * be considerable. We assume that member objects could only have a
5528 : : * direct dependency on their own extension, not any others.
5529 : : */
5530 [ + - ]: 16 : for (i = 0; i < dobj->nDeps; i++)
5531 : : {
5532 : 16 : extobj = findObjectByDumpId(dobj->dependencies[i]);
5533 [ + - + - ]: 16 : if (extobj && extobj->objType == DO_EXTENSION)
5534 : 16 : break;
4813 tgl@sss.pgh.pa.us 5535 :UBC 0 : extobj = NULL;
5536 : : }
4813 tgl@sss.pgh.pa.us 5537 [ - + ]:CBC 16 : if (extobj == NULL)
737 tgl@sss.pgh.pa.us 5538 :UBC 0 : pg_fatal("could not find parent extension for %s %s",
5539 : : objtype, objname);
5540 : :
3800 heikki.linnakangas@i 5541 :CBC 16 : appendPQExpBufferStr(upgrade_buffer,
5542 : : "\n-- For binary upgrade, handle extension membership the hard way\n");
2239 tgl@sss.pgh.pa.us 5543 : 16 : appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4813 5544 : 16 : fmtId(extobj->name),
5545 : : objtype);
2239 5546 [ + + + - ]: 16 : if (objnamespace && *objnamespace)
5547 : 13 : appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
5548 : 16 : appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
5549 : : }
5550 : :
5551 : : /*
5552 : : * getNamespaces:
5553 : : * read all namespaces in the system catalogs and return them in the
5554 : : * NamespaceInfo* structure
5555 : : *
5556 : : * numNamespaces is set to the number of namespaces read in
5557 : : */
5558 : : NamespaceInfo *
4451 rhaas@postgresql.org 5559 : 156 : getNamespaces(Archive *fout, int *numNamespaces)
5560 : : {
5561 : : PGresult *res;
5562 : : int ntups;
5563 : : int i;
5564 : : PQExpBuffer query;
5565 : : NamespaceInfo *nsinfo;
5566 : : int i_tableoid;
5567 : : int i_oid;
5568 : : int i_nspname;
5569 : : int i_nspowner;
5570 : : int i_nspacl;
5571 : : int i_acldefault;
5572 : :
8010 tgl@sss.pgh.pa.us 5573 : 156 : query = createPQExpBuffer();
5574 : :
5575 : : /*
5576 : : * we fetch all namespaces including system ones, so that every object we
5577 : : * read in can be linked to a containing namespace.
5578 : : */
586 drowley@postgresql.o 5579 : 156 : appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
5580 : : "n.nspowner, "
5581 : : "n.nspacl, "
5582 : : "acldefault('n', n.nspowner) AS acldefault "
5583 : : "FROM pg_namespace n");
5584 : :
4450 rhaas@postgresql.org 5585 : 156 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5586 : :
9716 bruce@momjian.us 5587 : 156 : ntups = PQntuples(res);
5588 : :
4524 5589 : 156 : nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
5590 : :
7435 tgl@sss.pgh.pa.us 5591 : 156 : i_tableoid = PQfnumber(res, "tableoid");
9716 bruce@momjian.us 5592 : 156 : i_oid = PQfnumber(res, "oid");
8010 tgl@sss.pgh.pa.us 5593 : 156 : i_nspname = PQfnumber(res, "nspname");
1021 noah@leadboat.com 5594 : 156 : i_nspowner = PQfnumber(res, "nspowner");
8010 tgl@sss.pgh.pa.us 5595 : 156 : i_nspacl = PQfnumber(res, "nspacl");
860 5596 : 156 : i_acldefault = PQfnumber(res, "acldefault");
5597 : :
9716 bruce@momjian.us 5598 [ + + ]: 1308 : for (i = 0; i < ntups; i++)
5599 : : {
5600 : : const char *nspowner;
5601 : :
7435 tgl@sss.pgh.pa.us 5602 : 1152 : nsinfo[i].dobj.objType = DO_NAMESPACE;
5603 : 1152 : nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5604 : 1152 : nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5605 : 1152 : AssignDumpId(&nsinfo[i].dobj);
4524 bruce@momjian.us 5606 : 1152 : nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
860 tgl@sss.pgh.pa.us 5607 : 1152 : nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
5608 : 1152 : nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
5609 : 1152 : nsinfo[i].dacl.privtype = 0;
5610 : 1152 : nsinfo[i].dacl.initprivs = NULL;
835 5611 : 1152 : nspowner = PQgetvalue(res, i, i_nspowner);
5612 : 1152 : nsinfo[i].nspowner = atooid(nspowner);
5613 : 1152 : nsinfo[i].rolname = getRoleName(nspowner);
5614 : :
5615 : : /* Decide whether to dump this namespace */
2930 sfrost@snowman.net 5616 : 1152 : selectDumpableNamespace(&nsinfo[i], fout);
5617 : :
5618 : : /* Mark whether namespace has an ACL */
860 tgl@sss.pgh.pa.us 5619 [ + + ]: 1152 : if (!PQgetisnull(res, i, i_nspacl))
5620 : 515 : nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5621 : :
5622 : : /*
5623 : : * We ignore any pg_init_privs.initprivs entry for the public schema
5624 : : * and assume a predetermined default, for several reasons. First,
5625 : : * dropping and recreating the schema removes its pg_init_privs entry,
5626 : : * but an empty destination database starts with this ACL nonetheless.
5627 : : * Second, we support dump/reload of public schema ownership changes.
5628 : : * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
5629 : : * initprivs continues to reflect the initial owner. Hence,
5630 : : * synthesize the value that nspacl will have after the restore's
5631 : : * ALTER SCHEMA OWNER. Third, this makes the destination database
5632 : : * match the source's ACL, even if the latter was an initdb-default
5633 : : * ACL, which changed in v15. An upgrade pulls in changes to most
5634 : : * system object ACLs that the DBA had not customized. We've made the
5635 : : * public schema depart from that, because changing its ACL so easily
5636 : : * breaks applications.
5637 : : */
5638 [ + + ]: 1152 : if (strcmp(nsinfo[i].dobj.name, "public") == 0)
5639 : : {
5640 : 152 : PQExpBuffer aclarray = createPQExpBuffer();
5641 : 152 : PQExpBuffer aclitem = createPQExpBuffer();
5642 : :
5643 : : /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
5644 : 152 : appendPQExpBufferChar(aclarray, '{');
5645 : 152 : quoteAclUserName(aclitem, nsinfo[i].rolname);
5646 : 152 : appendPQExpBufferStr(aclitem, "=UC/");
5647 : 152 : quoteAclUserName(aclitem, nsinfo[i].rolname);
5648 : 152 : appendPGArray(aclarray, aclitem->data);
5649 : 152 : resetPQExpBuffer(aclitem);
5650 : 152 : appendPQExpBufferStr(aclitem, "=U/");
5651 : 152 : quoteAclUserName(aclitem, nsinfo[i].rolname);
5652 : 152 : appendPGArray(aclarray, aclitem->data);
5653 : 152 : appendPQExpBufferChar(aclarray, '}');
5654 : :
5655 : 152 : nsinfo[i].dacl.privtype = 'i';
5656 : 152 : nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
5657 : 152 : nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5658 : :
5659 : 152 : destroyPQExpBuffer(aclarray);
5660 : 152 : destroyPQExpBuffer(aclitem);
5661 : : }
5662 : : }
5663 : :
9716 bruce@momjian.us 5664 : 156 : PQclear(res);
8290 tgl@sss.pgh.pa.us 5665 : 156 : destroyPQExpBuffer(query);
5666 : :
4342 5667 : 156 : *numNamespaces = ntups;
5668 : :
8010 5669 : 156 : return nsinfo;
5670 : : }
5671 : :
5672 : : /*
5673 : : * findNamespace:
5674 : : * given a namespace OID, look up the info read by getNamespaces
5675 : : */
5676 : : static NamespaceInfo *
1328 peter@eisentraut.org 5677 : 583561 : findNamespace(Oid nsoid)
5678 : : {
5679 : : NamespaceInfo *nsinfo;
5680 : :
2741 tgl@sss.pgh.pa.us 5681 : 583561 : nsinfo = findNamespaceByOid(nsoid);
4342 5682 [ - + ]: 583561 : if (nsinfo == NULL)
737 tgl@sss.pgh.pa.us 5683 :UBC 0 : pg_fatal("schema with OID %u does not exist", nsoid);
4342 tgl@sss.pgh.pa.us 5684 :CBC 583561 : return nsinfo;
5685 : : }
5686 : :
5687 : : /*
5688 : : * getExtensions:
5689 : : * read all extensions in the system catalogs and return them in the
5690 : : * ExtensionInfo* structure
5691 : : *
5692 : : * numExtensions is set to the number of extensions read in
5693 : : */
5694 : : ExtensionInfo *
3014 5695 : 156 : getExtensions(Archive *fout, int *numExtensions)
5696 : : {
5697 : 156 : DumpOptions *dopt = fout->dopt;
5698 : : PGresult *res;
5699 : : int ntups;
5700 : : int i;
5701 : : PQExpBuffer query;
5702 : : ExtensionInfo *extinfo;
5703 : : int i_tableoid;
5704 : : int i_oid;
5705 : : int i_extname;
5706 : : int i_nspname;
5707 : : int i_extrelocatable;
5708 : : int i_extversion;
5709 : : int i_extconfig;
5710 : : int i_extcondition;
5711 : :
4814 5712 : 156 : query = createPQExpBuffer();
5713 : :
3800 heikki.linnakangas@i 5714 : 156 : appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
5715 : : "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
5716 : : "FROM pg_extension x "
5717 : : "JOIN pg_namespace n ON n.oid = x.extnamespace");
5718 : :
4450 rhaas@postgresql.org 5719 : 156 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5720 : :
4814 tgl@sss.pgh.pa.us 5721 : 156 : ntups = PQntuples(res);
5722 : :
4524 bruce@momjian.us 5723 : 156 : extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
5724 : :
4814 tgl@sss.pgh.pa.us 5725 : 156 : i_tableoid = PQfnumber(res, "tableoid");
5726 : 156 : i_oid = PQfnumber(res, "oid");
5727 : 156 : i_extname = PQfnumber(res, "extname");
5728 : 156 : i_nspname = PQfnumber(res, "nspname");
4813 5729 : 156 : i_extrelocatable = PQfnumber(res, "extrelocatable");
5730 : 156 : i_extversion = PQfnumber(res, "extversion");
4814 5731 : 156 : i_extconfig = PQfnumber(res, "extconfig");
5732 : 156 : i_extcondition = PQfnumber(res, "extcondition");
5733 : :
5734 [ + + ]: 337 : for (i = 0; i < ntups; i++)
5735 : : {
5736 : 181 : extinfo[i].dobj.objType = DO_EXTENSION;
5737 : 181 : extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5738 : 181 : extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5739 : 181 : AssignDumpId(&extinfo[i].dobj);
4524 bruce@momjian.us 5740 : 181 : extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
5741 : 181 : extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4813 tgl@sss.pgh.pa.us 5742 : 181 : extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4524 bruce@momjian.us 5743 : 181 : extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
5744 : 181 : extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
5745 : 181 : extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
5746 : :
5747 : : /* Decide whether we want to dump it */
3014 tgl@sss.pgh.pa.us 5748 : 181 : selectDumpableExtension(&(extinfo[i]), dopt);
5749 : : }
5750 : :
4814 5751 : 156 : PQclear(res);
5752 : 156 : destroyPQExpBuffer(query);
5753 : :
5754 : 156 : *numExtensions = ntups;
5755 : :
5756 : 156 : return extinfo;
5757 : : }
5758 : :
5759 : : /*
5760 : : * getTypes:
5761 : : * read all types in the system catalogs and return them in the
5762 : : * TypeInfo* structure
5763 : : *
5764 : : * numTypes is set to the number of types read in
5765 : : *
5766 : : * NB: this must run after getFuncs() because we assume we can do
5767 : : * findFuncByOid().
5768 : : */
5769 : : TypeInfo *
4451 rhaas@postgresql.org 5770 : 155 : getTypes(Archive *fout, int *numTypes)
5771 : : {
5772 : : PGresult *res;
5773 : : int ntups;
5774 : : int i;
8768 bruce@momjian.us 5775 : 155 : PQExpBuffer query = createPQExpBuffer();
5776 : : TypeInfo *tyinfo;
5777 : : ShellTypeInfo *stinfo;
5778 : : int i_tableoid;
5779 : : int i_oid;
5780 : : int i_typname;
5781 : : int i_typnamespace;
5782 : : int i_typacl;
5783 : : int i_acldefault;
5784 : : int i_typowner;
5785 : : int i_typelem;
5786 : : int i_typrelid;
5787 : : int i_typrelkind;
5788 : : int i_typtype;
5789 : : int i_typisdefined;
5790 : : int i_isarray;
5791 : :
5792 : : /*
5793 : : * we include even the built-in types because those may be used as array
5794 : : * elements by user-defined types
5795 : : *
5796 : : * we filter out the built-in types when we dump out the types
5797 : : *
5798 : : * same approach for undefined (shell) types and array types
5799 : : *
5800 : : * Note: as of 8.3 we can reliably detect whether a type is an
5801 : : * auto-generated array type by checking the element type's typarray.
5802 : : * (Before that the test is capable of generating false positives.) We
5803 : : * still check for name beginning with '_', though, so as to avoid the
5804 : : * cost of the subselect probe for all standard types. This would have to
5805 : : * be revisited if the backend ever allows renaming of array types.
5806 : : */
586 drowley@postgresql.o 5807 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
5808 : : "typnamespace, typacl, "
5809 : : "acldefault('T', typowner) AS acldefault, "
5810 : : "typowner, "
5811 : : "typelem, typrelid, "
5812 : : "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
5813 : : "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
5814 : : "typtype, typisdefined, "
5815 : : "typname[0] = '_' AND typelem != 0 AND "
5816 : : "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
5817 : : "FROM pg_type");
5818 : :
4450 rhaas@postgresql.org 5819 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5820 : :
9716 bruce@momjian.us 5821 : 155 : ntups = PQntuples(res);
5822 : :
4524 5823 : 155 : tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
5824 : :
7435 tgl@sss.pgh.pa.us 5825 : 155 : i_tableoid = PQfnumber(res, "tableoid");
9716 bruce@momjian.us 5826 : 155 : i_oid = PQfnumber(res, "oid");
8010 tgl@sss.pgh.pa.us 5827 : 155 : i_typname = PQfnumber(res, "typname");
5828 : 155 : i_typnamespace = PQfnumber(res, "typnamespace");
4144 5829 : 155 : i_typacl = PQfnumber(res, "typacl");
860 5830 : 155 : i_acldefault = PQfnumber(res, "acldefault");
835 5831 : 155 : i_typowner = PQfnumber(res, "typowner");
8010 5832 : 155 : i_typelem = PQfnumber(res, "typelem");
5833 : 155 : i_typrelid = PQfnumber(res, "typrelid");
7913 bruce@momjian.us 5834 : 155 : i_typrelkind = PQfnumber(res, "typrelkind");
8010 tgl@sss.pgh.pa.us 5835 : 155 : i_typtype = PQfnumber(res, "typtype");
5836 : 155 : i_typisdefined = PQfnumber(res, "typisdefined");
6183 5837 : 155 : i_isarray = PQfnumber(res, "isarray");
5838 : :
9716 bruce@momjian.us 5839 [ + + ]: 108957 : for (i = 0; i < ntups; i++)
5840 : : {
5226 5841 : 108802 : tyinfo[i].dobj.objType = DO_TYPE;
5842 : 108802 : tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5843 : 108802 : tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5844 : 108802 : AssignDumpId(&tyinfo[i].dobj);
4524 5845 : 108802 : tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4451 rhaas@postgresql.org 5846 : 217604 : tyinfo[i].dobj.namespace =
1328 peter@eisentraut.org 5847 : 108802 : findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
860 tgl@sss.pgh.pa.us 5848 : 108802 : tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
5849 : 108802 : tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
5850 : 108802 : tyinfo[i].dacl.privtype = 0;
5851 : 108802 : tyinfo[i].dacl.initprivs = NULL;
957 5852 : 108802 : tyinfo[i].ftypname = NULL; /* may get filled later */
835 5853 : 108802 : tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
5226 bruce@momjian.us 5854 : 108802 : tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
5855 : 108802 : tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
5856 : 108802 : tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
5857 : 108802 : tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
5858 : 108802 : tyinfo[i].shellType = NULL;
5859 : :
8010 tgl@sss.pgh.pa.us 5860 [ + + ]: 108802 : if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
5226 bruce@momjian.us 5861 : 108751 : tyinfo[i].isDefined = true;
5862 : : else
5863 : 51 : tyinfo[i].isDefined = false;
5864 : :
6183 tgl@sss.pgh.pa.us 5865 [ + + ]: 108802 : if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
5226 bruce@momjian.us 5866 : 52128 : tyinfo[i].isArray = true;
5867 : : else
5868 : 56674 : tyinfo[i].isArray = false;
5869 : :
60 tgl@sss.pgh.pa.us 5870 [ + + ]:GNC 108802 : if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
1211 akorotkov@postgresql 5871 :CBC 1042 : tyinfo[i].isMultirange = true;
5872 : : else
5873 : 107760 : tyinfo[i].isMultirange = false;
5874 : :
5875 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 5876 : 108802 : selectDumpableType(&tyinfo[i], fout);
5877 : :
5878 : : /* Mark whether type has an ACL */
860 tgl@sss.pgh.pa.us 5879 [ + + ]: 108802 : if (!PQgetisnull(res, i, i_typacl))
5880 : 209 : tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5881 : :
5882 : : /*
5883 : : * If it's a domain, fetch info about its constraints, if any
5884 : : */
5226 bruce@momjian.us 5885 : 108802 : tyinfo[i].nDomChecks = 0;
5886 : 108802 : tyinfo[i].domChecks = NULL;
2930 sfrost@snowman.net 5887 [ + + ]: 108802 : if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
5888 [ + + ]: 12510 : tyinfo[i].typtype == TYPTYPE_DOMAIN)
4451 rhaas@postgresql.org 5889 : 134 : getDomainConstraints(fout, &(tyinfo[i]));
5890 : :
5891 : : /*
5892 : : * If it's a base type, make a DumpableObject representing a shell
5893 : : * definition of the type. We will need to dump that ahead of the I/O
5894 : : * functions for the type. Similarly, range types need a shell
5895 : : * definition in case they have a canonicalize function.
5896 : : *
5897 : : * Note: the shell type doesn't have a catId. You might think it
5898 : : * should copy the base type's catId, but then it might capture the
5899 : : * pg_depend entries for the type, which we don't want.
5900 : : */
2930 sfrost@snowman.net 5901 [ + + ]: 108802 : if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
5902 [ + + ]: 12510 : (tyinfo[i].typtype == TYPTYPE_BASE ||
5903 [ + + ]: 6153 : tyinfo[i].typtype == TYPTYPE_RANGE))
5904 : : {
4524 bruce@momjian.us 5905 : 6461 : stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
6618 tgl@sss.pgh.pa.us 5906 : 6461 : stinfo->dobj.objType = DO_SHELL_TYPE;
5907 : 6461 : stinfo->dobj.catId = nilCatalogId;
5908 : 6461 : AssignDumpId(&stinfo->dobj);
4524 bruce@momjian.us 5909 : 6461 : stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
5226 5910 : 6461 : stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
5911 : 6461 : stinfo->baseType = &(tyinfo[i]);
5912 : 6461 : tyinfo[i].shellType = stinfo;
5913 : :
5914 : : /*
5915 : : * Initially mark the shell type as not to be dumped. We'll only
5916 : : * dump it if the I/O or canonicalize functions need to be dumped;
5917 : : * this is taken care of while sorting dependencies.
5918 : : */
2930 sfrost@snowman.net 5919 : 6461 : stinfo->dobj.dump = DUMP_COMPONENT_NONE;
5920 : : }
5921 : : }
5922 : :
8010 tgl@sss.pgh.pa.us 5923 : 155 : *numTypes = ntups;
5924 : :
9716 bruce@momjian.us 5925 : 155 : PQclear(res);
5926 : :
8290 tgl@sss.pgh.pa.us 5927 : 155 : destroyPQExpBuffer(query);
5928 : :
5226 bruce@momjian.us 5929 : 155 : return tyinfo;
5930 : : }
5931 : :
5932 : : /*
5933 : : * getOperators:
5934 : : * read all operators in the system catalogs and return them in the
5935 : : * OprInfo* structure
5936 : : *
5937 : : * numOprs is set to the number of operators read in
5938 : : */
5939 : : OprInfo *
4451 rhaas@postgresql.org 5940 : 155 : getOperators(Archive *fout, int *numOprs)
5941 : : {
5942 : : PGresult *res;
5943 : : int ntups;
5944 : : int i;
8768 bruce@momjian.us 5945 : 155 : PQExpBuffer query = createPQExpBuffer();
5946 : : OprInfo *oprinfo;
5947 : : int i_tableoid;
5948 : : int i_oid;
5949 : : int i_oprname;
5950 : : int i_oprnamespace;
5951 : : int i_oprowner;
5952 : : int i_oprkind;
5953 : : int i_oprcode;
5954 : :
5955 : : /*
5956 : : * find all operators, including builtin operators; we filter out
5957 : : * system-defined operators at dump-out time.
5958 : : */
5959 : :
586 drowley@postgresql.o 5960 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
5961 : : "oprnamespace, "
5962 : : "oprowner, "
5963 : : "oprkind, "
5964 : : "oprcode::oid AS oprcode "
5965 : : "FROM pg_operator");
5966 : :
4450 rhaas@postgresql.org 5967 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5968 : :
9716 bruce@momjian.us 5969 : 155 : ntups = PQntuples(res);
8010 tgl@sss.pgh.pa.us 5970 : 155 : *numOprs = ntups;
5971 : :
4524 bruce@momjian.us 5972 : 155 : oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
5973 : :
7435 tgl@sss.pgh.pa.us 5974 : 155 : i_tableoid = PQfnumber(res, "tableoid");
9716 bruce@momjian.us 5975 : 155 : i_oid = PQfnumber(res, "oid");
8010 tgl@sss.pgh.pa.us 5976 : 155 : i_oprname = PQfnumber(res, "oprname");
5977 : 155 : i_oprnamespace = PQfnumber(res, "oprnamespace");
835 5978 : 155 : i_oprowner = PQfnumber(res, "oprowner");
4483 peter_e@gmx.net 5979 : 155 : i_oprkind = PQfnumber(res, "oprkind");
8010 tgl@sss.pgh.pa.us 5980 : 155 : i_oprcode = PQfnumber(res, "oprcode");
5981 : :
9716 bruce@momjian.us 5982 [ + + ]: 124115 : for (i = 0; i < ntups; i++)
5983 : : {
7435 tgl@sss.pgh.pa.us 5984 : 123960 : oprinfo[i].dobj.objType = DO_OPERATOR;
5985 : 123960 : oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5986 : 123960 : oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5987 : 123960 : AssignDumpId(&oprinfo[i].dobj);
4524 bruce@momjian.us 5988 : 123960 : oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
4451 rhaas@postgresql.org 5989 : 247920 : oprinfo[i].dobj.namespace =
1328 peter@eisentraut.org 5990 : 123960 : findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
835 tgl@sss.pgh.pa.us 5991 : 123960 : oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
4483 peter_e@gmx.net 5992 : 123960 : oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
7435 tgl@sss.pgh.pa.us 5993 : 123960 : oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
5994 : :
5995 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 5996 : 123960 : selectDumpableObject(&(oprinfo[i].dobj), fout);
5997 : : }
5998 : :
9716 bruce@momjian.us 5999 : 155 : PQclear(res);
6000 : :
8290 tgl@sss.pgh.pa.us 6001 : 155 : destroyPQExpBuffer(query);
6002 : :
8010 6003 : 155 : return oprinfo;
6004 : : }
6005 : :
6006 : : /*
6007 : : * getCollations:
6008 : : * read all collations in the system catalogs and return them in the
6009 : : * CollInfo* structure
6010 : : *
6011 : : * numCollations is set to the number of collations read in
6012 : : */
6013 : : CollInfo *
4451 rhaas@postgresql.org 6014 : 155 : getCollations(Archive *fout, int *numCollations)
6015 : : {
6016 : : PGresult *res;
6017 : : int ntups;
6018 : : int i;
6019 : : PQExpBuffer query;
6020 : : CollInfo *collinfo;
6021 : : int i_tableoid;
6022 : : int i_oid;
6023 : : int i_collname;
6024 : : int i_collnamespace;
6025 : : int i_collowner;
6026 : :
4415 peter_e@gmx.net 6027 : 155 : query = createPQExpBuffer();
6028 : :
6029 : : /*
6030 : : * find all collations, including builtin collations; we filter out
6031 : : * system-defined collations at dump-out time.
6032 : : */
6033 : :
586 drowley@postgresql.o 6034 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
6035 : : "collnamespace, "
6036 : : "collowner "
6037 : : "FROM pg_collation");
6038 : :
4450 rhaas@postgresql.org 6039 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6040 : :
4810 peter_e@gmx.net 6041 : 155 : ntups = PQntuples(res);
6042 : 155 : *numCollations = ntups;
6043 : :
4524 bruce@momjian.us 6044 : 155 : collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
6045 : :
4810 peter_e@gmx.net 6046 : 155 : i_tableoid = PQfnumber(res, "tableoid");
6047 : 155 : i_oid = PQfnumber(res, "oid");
6048 : 155 : i_collname = PQfnumber(res, "collname");
6049 : 155 : i_collnamespace = PQfnumber(res, "collnamespace");
835 tgl@sss.pgh.pa.us 6050 : 155 : i_collowner = PQfnumber(res, "collowner");
6051 : :
4810 peter_e@gmx.net 6052 [ + + ]: 226712 : for (i = 0; i < ntups; i++)
6053 : : {
6054 : 226557 : collinfo[i].dobj.objType = DO_COLLATION;
6055 : 226557 : collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6056 : 226557 : collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6057 : 226557 : AssignDumpId(&collinfo[i].dobj);
4524 bruce@momjian.us 6058 : 226557 : collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
4451 rhaas@postgresql.org 6059 : 453114 : collinfo[i].dobj.namespace =
1328 peter@eisentraut.org 6060 : 226557 : findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
835 tgl@sss.pgh.pa.us 6061 : 226557 : collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
6062 : :
6063 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 6064 : 226557 : selectDumpableObject(&(collinfo[i].dobj), fout);
6065 : : }
6066 : :
4810 peter_e@gmx.net 6067 : 155 : PQclear(res);
6068 : :
6069 : 155 : destroyPQExpBuffer(query);
6070 : :
6071 : 155 : return collinfo;
6072 : : }
6073 : :
6074 : : /*
6075 : : * getConversions:
6076 : : * read all conversions in the system catalogs and return them in the
6077 : : * ConvInfo* structure
6078 : : *
6079 : : * numConversions is set to the number of conversions read in
6080 : : */
6081 : : ConvInfo *
4451 rhaas@postgresql.org 6082 : 155 : getConversions(Archive *fout, int *numConversions)
6083 : : {
6084 : : PGresult *res;
6085 : : int ntups;
6086 : : int i;
6087 : : PQExpBuffer query;
6088 : : ConvInfo *convinfo;
6089 : : int i_tableoid;
6090 : : int i_oid;
6091 : : int i_conname;
6092 : : int i_connamespace;
6093 : : int i_conowner;
6094 : :
3731 sfrost@snowman.net 6095 : 155 : query = createPQExpBuffer();
6096 : :
6097 : : /*
6098 : : * find all conversions, including builtin conversions; we filter out
6099 : : * system-defined conversions at dump-out time.
6100 : : */
6101 : :
586 drowley@postgresql.o 6102 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
6103 : : "connamespace, "
6104 : : "conowner "
6105 : : "FROM pg_conversion");
6106 : :
4450 rhaas@postgresql.org 6107 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6108 : :
7450 tgl@sss.pgh.pa.us 6109 : 155 : ntups = PQntuples(res);
6110 : 155 : *numConversions = ntups;
6111 : :
4524 bruce@momjian.us 6112 : 155 : convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
6113 : :
7435 tgl@sss.pgh.pa.us 6114 : 155 : i_tableoid = PQfnumber(res, "tableoid");
7450 6115 : 155 : i_oid = PQfnumber(res, "oid");
6116 : 155 : i_conname = PQfnumber(res, "conname");
6117 : 155 : i_connamespace = PQfnumber(res, "connamespace");
835 6118 : 155 : i_conowner = PQfnumber(res, "conowner");
6119 : :
7450 6120 [ + + ]: 20041 : for (i = 0; i < ntups; i++)
6121 : : {
7435 6122 : 19886 : convinfo[i].dobj.objType = DO_CONVERSION;
6123 : 19886 : convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6124 : 19886 : convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6125 : 19886 : AssignDumpId(&convinfo[i].dobj);
4524 bruce@momjian.us 6126 : 19886 : convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
4451 rhaas@postgresql.org 6127 : 39772 : convinfo[i].dobj.namespace =
1328 peter@eisentraut.org 6128 : 19886 : findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
835 tgl@sss.pgh.pa.us 6129 : 19886 : convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
6130 : :
6131 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 6132 : 19886 : selectDumpableObject(&(convinfo[i].dobj), fout);
6133 : : }
6134 : :
7450 tgl@sss.pgh.pa.us 6135 : 155 : PQclear(res);
6136 : :
6137 : 155 : destroyPQExpBuffer(query);
6138 : :
6139 : 155 : return convinfo;
6140 : : }
6141 : :
6142 : : /*
6143 : : * getAccessMethods:
6144 : : * read all user-defined access methods in the system catalogs and return
6145 : : * them in the AccessMethodInfo* structure
6146 : : *
6147 : : * numAccessMethods is set to the number of access methods read in
6148 : : */
6149 : : AccessMethodInfo *
2944 alvherre@alvh.no-ip. 6150 : 155 : getAccessMethods(Archive *fout, int *numAccessMethods)
6151 : : {
6152 : : PGresult *res;
6153 : : int ntups;
6154 : : int i;
6155 : : PQExpBuffer query;
6156 : : AccessMethodInfo *aminfo;
6157 : : int i_tableoid;
6158 : : int i_oid;
6159 : : int i_amname;
6160 : : int i_amhandler;
6161 : : int i_amtype;
6162 : :
6163 : : /* Before 9.6, there are no user-defined access methods */
6164 [ - + ]: 155 : if (fout->remoteVersion < 90600)
6165 : : {
2944 alvherre@alvh.no-ip. 6166 :UBC 0 : *numAccessMethods = 0;
6167 : 0 : return NULL;
6168 : : }
6169 : :
2944 alvherre@alvh.no-ip. 6170 :CBC 155 : query = createPQExpBuffer();
6171 : :
6172 : : /* Select all access methods from pg_am table */
1746 drowley@postgresql.o 6173 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
6174 : : "amhandler::pg_catalog.regproc AS amhandler "
6175 : : "FROM pg_am");
6176 : :
2944 alvherre@alvh.no-ip. 6177 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6178 : :
6179 : 155 : ntups = PQntuples(res);
6180 : 155 : *numAccessMethods = ntups;
6181 : :
6182 : 155 : aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
6183 : :
6184 : 155 : i_tableoid = PQfnumber(res, "tableoid");
6185 : 155 : i_oid = PQfnumber(res, "oid");
6186 : 155 : i_amname = PQfnumber(res, "amname");
6187 : 155 : i_amhandler = PQfnumber(res, "amhandler");
6188 : 155 : i_amtype = PQfnumber(res, "amtype");
6189 : :
6190 [ + + ]: 1362 : for (i = 0; i < ntups; i++)
6191 : : {
6192 : 1207 : aminfo[i].dobj.objType = DO_ACCESS_METHOD;
6193 : 1207 : aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6194 : 1207 : aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6195 : 1207 : AssignDumpId(&aminfo[i].dobj);
6196 : 1207 : aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
6197 : 1207 : aminfo[i].dobj.namespace = NULL;
6198 : 1207 : aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
6199 : 1207 : aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
6200 : :
6201 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 6202 : 1207 : selectDumpableAccessMethod(&(aminfo[i]), fout);
6203 : : }
6204 : :
2944 alvherre@alvh.no-ip. 6205 : 155 : PQclear(res);
6206 : :
6207 : 155 : destroyPQExpBuffer(query);
6208 : :
6209 : 155 : return aminfo;
6210 : : }
6211 : :
6212 : :
6213 : : /*
6214 : : * getOpclasses:
6215 : : * read all opclasses in the system catalogs and return them in the
6216 : : * OpclassInfo* structure
6217 : : *
6218 : : * numOpclasses is set to the number of opclasses read in
6219 : : */
6220 : : OpclassInfo *
4451 rhaas@postgresql.org 6221 : 155 : getOpclasses(Archive *fout, int *numOpclasses)
6222 : : {
6223 : : PGresult *res;
6224 : : int ntups;
6225 : : int i;
7929 tgl@sss.pgh.pa.us 6226 : 155 : PQExpBuffer query = createPQExpBuffer();
6227 : : OpclassInfo *opcinfo;
6228 : : int i_tableoid;
6229 : : int i_oid;
6230 : : int i_opcname;
6231 : : int i_opcnamespace;
6232 : : int i_opcowner;
6233 : :
6234 : : /*
6235 : : * find all opclasses, including builtin opclasses; we filter out
6236 : : * system-defined opclasses at dump-out time.
6237 : : */
6238 : :
586 drowley@postgresql.o 6239 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
6240 : : "opcnamespace, "
6241 : : "opcowner "
6242 : : "FROM pg_opclass");
6243 : :
4450 rhaas@postgresql.org 6244 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6245 : :
7929 tgl@sss.pgh.pa.us 6246 : 155 : ntups = PQntuples(res);
6247 : 155 : *numOpclasses = ntups;
6248 : :
4524 bruce@momjian.us 6249 : 155 : opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
6250 : :
7435 tgl@sss.pgh.pa.us 6251 : 155 : i_tableoid = PQfnumber(res, "tableoid");
7929 6252 : 155 : i_oid = PQfnumber(res, "oid");
6253 : 155 : i_opcname = PQfnumber(res, "opcname");
6254 : 155 : i_opcnamespace = PQfnumber(res, "opcnamespace");
835 6255 : 155 : i_opcowner = PQfnumber(res, "opcowner");
6256 : :
7929 6257 [ + + ]: 27743 : for (i = 0; i < ntups; i++)
6258 : : {
7435 6259 : 27588 : opcinfo[i].dobj.objType = DO_OPCLASS;
6260 : 27588 : opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6261 : 27588 : opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6262 : 27588 : AssignDumpId(&opcinfo[i].dobj);
4524 bruce@momjian.us 6263 : 27588 : opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
4451 rhaas@postgresql.org 6264 : 55176 : opcinfo[i].dobj.namespace =
1328 peter@eisentraut.org 6265 : 27588 : findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
835 tgl@sss.pgh.pa.us 6266 : 27588 : opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
6267 : :
6268 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 6269 : 27588 : selectDumpableObject(&(opcinfo[i].dobj), fout);
6270 : : }
6271 : :
7929 tgl@sss.pgh.pa.us 6272 : 155 : PQclear(res);
6273 : :
6274 : 155 : destroyPQExpBuffer(query);
6275 : :
6276 : 155 : return opcinfo;
6277 : : }
6278 : :
6279 : : /*
6280 : : * getOpfamilies:
6281 : : * read all opfamilies in the system catalogs and return them in the
6282 : : * OpfamilyInfo* structure
6283 : : *
6284 : : * numOpfamilies is set to the number of opfamilies read in
6285 : : */
6286 : : OpfamilyInfo *
4451 rhaas@postgresql.org 6287 : 155 : getOpfamilies(Archive *fout, int *numOpfamilies)
6288 : : {
6289 : : PGresult *res;
6290 : : int ntups;
6291 : : int i;
6292 : : PQExpBuffer query;
6293 : : OpfamilyInfo *opfinfo;
6294 : : int i_tableoid;
6295 : : int i_oid;
6296 : : int i_opfname;
6297 : : int i_opfnamespace;
6298 : : int i_opfowner;
6299 : :
6291 tgl@sss.pgh.pa.us 6300 : 155 : query = createPQExpBuffer();
6301 : :
6302 : : /*
6303 : : * find all opfamilies, including builtin opfamilies; we filter out
6304 : : * system-defined opfamilies at dump-out time.
6305 : : */
6306 : :
586 drowley@postgresql.o 6307 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, opfname, "
6308 : : "opfnamespace, "
6309 : : "opfowner "
6310 : : "FROM pg_opfamily");
6311 : :
4450 rhaas@postgresql.org 6312 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6313 : :
6291 tgl@sss.pgh.pa.us 6314 : 155 : ntups = PQntuples(res);
6315 : 155 : *numOpfamilies = ntups;
6316 : :
4524 bruce@momjian.us 6317 : 155 : opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
6318 : :
6291 tgl@sss.pgh.pa.us 6319 : 155 : i_tableoid = PQfnumber(res, "tableoid");
6320 : 155 : i_oid = PQfnumber(res, "oid");
6321 : 155 : i_opfname = PQfnumber(res, "opfname");
6322 : 155 : i_opfnamespace = PQfnumber(res, "opfnamespace");
835 6323 : 155 : i_opfowner = PQfnumber(res, "opfowner");
6324 : :
6291 6325 [ + + ]: 22912 : for (i = 0; i < ntups; i++)
6326 : : {
6327 : 22757 : opfinfo[i].dobj.objType = DO_OPFAMILY;
6328 : 22757 : opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6329 : 22757 : opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6330 : 22757 : AssignDumpId(&opfinfo[i].dobj);
4524 bruce@momjian.us 6331 : 22757 : opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
4451 rhaas@postgresql.org 6332 : 45514 : opfinfo[i].dobj.namespace =
1328 peter@eisentraut.org 6333 : 22757 : findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
835 tgl@sss.pgh.pa.us 6334 : 22757 : opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
6335 : :
6336 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 6337 : 22757 : selectDumpableObject(&(opfinfo[i].dobj), fout);
6338 : : }
6339 : :
6291 tgl@sss.pgh.pa.us 6340 : 155 : PQclear(res);
6341 : :
6342 : 155 : destroyPQExpBuffer(query);
6343 : :
6344 : 155 : return opfinfo;
6345 : : }
6346 : :
6347 : : /*
6348 : : * getAggregates:
6349 : : * read all the user-defined aggregates in the system catalogs and
6350 : : * return them in the AggInfo* structure
6351 : : *
6352 : : * numAggs is set to the number of aggregates read in
6353 : : */
6354 : : AggInfo *
3014 6355 : 155 : getAggregates(Archive *fout, int *numAggs)
6356 : : {
6357 : 155 : DumpOptions *dopt = fout->dopt;
6358 : : PGresult *res;
6359 : : int ntups;
6360 : : int i;
8768 bruce@momjian.us 6361 : 155 : PQExpBuffer query = createPQExpBuffer();
6362 : : AggInfo *agginfo;
6363 : : int i_tableoid;
6364 : : int i_oid;
6365 : : int i_aggname;
6366 : : int i_aggnamespace;
6367 : : int i_pronargs;
6368 : : int i_proargtypes;
6369 : : int i_proowner;
6370 : : int i_aggacl;
6371 : : int i_acldefault;
6372 : :
6373 : : /*
6374 : : * Find all interesting aggregates. See comment in getFuncs() for the
6375 : : * rationale behind the filtering logic.
6376 : : */
2930 sfrost@snowman.net 6377 [ + - ]: 155 : if (fout->remoteVersion >= 90600)
6378 : : {
6379 : : const char *agg_check;
6380 : :
2235 peter_e@gmx.net 6381 : 310 : agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
6382 [ + - ]: 155 : : "p.proisagg");
6383 : :
2930 sfrost@snowman.net 6384 : 155 : appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
6385 : : "p.proname AS aggname, "
6386 : : "p.pronamespace AS aggnamespace, "
6387 : : "p.pronargs, p.proargtypes, "
6388 : : "p.proowner, "
6389 : : "p.proacl AS aggacl, "
6390 : : "acldefault('f', p.proowner) AS acldefault "
6391 : : "FROM pg_proc p "
6392 : : "LEFT JOIN pg_init_privs pip ON "
6393 : : "(p.oid = pip.objoid "
6394 : : "AND pip.classoid = 'pg_proc'::regclass "
6395 : : "AND pip.objsubid = 0) "
6396 : : "WHERE %s AND ("
6397 : : "p.pronamespace != "
6398 : : "(SELECT oid FROM pg_namespace "
6399 : : "WHERE nspname = 'pg_catalog') OR "
6400 : : "p.proacl IS DISTINCT FROM pip.initprivs",
6401 : : agg_check);
6402 [ + + ]: 155 : if (dopt->binary_upgrade)
6403 : 14 : appendPQExpBufferStr(query,
6404 : : " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6405 : : "classid = 'pg_proc'::regclass AND "
6406 : : "objid = p.oid AND "
6407 : : "refclassid = 'pg_extension'::regclass AND "
6408 : : "deptype = 'e')");
6409 : 155 : appendPQExpBufferChar(query, ')');
6410 : : }
6411 : : else
6412 : : {
586 drowley@postgresql.o 6413 :UBC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
6414 : : "pronamespace AS aggnamespace, "
6415 : : "pronargs, proargtypes, "
6416 : : "proowner, "
6417 : : "proacl AS aggacl, "
6418 : : "acldefault('f', proowner) AS acldefault "
6419 : : "FROM pg_proc p "
6420 : : "WHERE proisagg AND ("
6421 : : "pronamespace != "
6422 : : "(SELECT oid FROM pg_namespace "
6423 : : "WHERE nspname = 'pg_catalog')");
860 tgl@sss.pgh.pa.us 6424 [ # # ]: 0 : if (dopt->binary_upgrade)
6425 : 0 : appendPQExpBufferStr(query,
6426 : : " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6427 : : "classid = 'pg_proc'::regclass AND "
6428 : : "objid = p.oid AND "
6429 : : "refclassid = 'pg_extension'::regclass AND "
6430 : : "deptype = 'e')");
6431 : 0 : appendPQExpBufferChar(query, ')');
6432 : : }
6433 : :
4450 rhaas@postgresql.org 6434 :CBC 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6435 : :
9716 bruce@momjian.us 6436 : 155 : ntups = PQntuples(res);
8010 tgl@sss.pgh.pa.us 6437 : 155 : *numAggs = ntups;
6438 : :
4524 bruce@momjian.us 6439 : 155 : agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
6440 : :
7435 tgl@sss.pgh.pa.us 6441 : 155 : i_tableoid = PQfnumber(res, "tableoid");
8010 6442 : 155 : i_oid = PQfnumber(res, "oid");
6443 : 155 : i_aggname = PQfnumber(res, "aggname");
6444 : 155 : i_aggnamespace = PQfnumber(res, "aggnamespace");
6471 6445 : 155 : i_pronargs = PQfnumber(res, "pronargs");
6446 : 155 : i_proargtypes = PQfnumber(res, "proargtypes");
835 6447 : 155 : i_proowner = PQfnumber(res, "proowner");
8001 peter_e@gmx.net 6448 : 155 : i_aggacl = PQfnumber(res, "aggacl");
860 tgl@sss.pgh.pa.us 6449 : 155 : i_acldefault = PQfnumber(res, "acldefault");
6450 : :
9716 bruce@momjian.us 6451 [ + + ]: 461 : for (i = 0; i < ntups; i++)
6452 : : {
7435 tgl@sss.pgh.pa.us 6453 : 306 : agginfo[i].aggfn.dobj.objType = DO_AGG;
6454 : 306 : agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6455 : 306 : agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6456 : 306 : AssignDumpId(&agginfo[i].aggfn.dobj);
4524 bruce@momjian.us 6457 : 306 : agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
4451 rhaas@postgresql.org 6458 : 612 : agginfo[i].aggfn.dobj.namespace =
1328 peter@eisentraut.org 6459 : 306 : findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
860 tgl@sss.pgh.pa.us 6460 : 306 : agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
6461 : 306 : agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6462 : 306 : agginfo[i].aggfn.dacl.privtype = 0;
6463 : 306 : agginfo[i].aggfn.dacl.initprivs = NULL;
835 6464 : 306 : agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
2489 6465 : 306 : agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
6466 : 306 : agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
6471 6467 : 306 : agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
6468 [ + + ]: 306 : if (agginfo[i].aggfn.nargs == 0)
6469 : 40 : agginfo[i].aggfn.argtypes = NULL;
6470 : : else
6471 : : {
4524 bruce@momjian.us 6472 : 266 : agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
2741 tgl@sss.pgh.pa.us 6473 : 266 : parseOidArray(PQgetvalue(res, i, i_proargtypes),
6474 : 266 : agginfo[i].aggfn.argtypes,
6475 : 266 : agginfo[i].aggfn.nargs);
6476 : : }
315 6477 : 306 : agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
6478 : :
6479 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 6480 : 306 : selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
6481 : :
6482 : : /* Mark whether aggregate has an ACL */
860 tgl@sss.pgh.pa.us 6483 [ + + ]: 306 : if (!PQgetisnull(res, i, i_aggacl))
6484 : 25 : agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
6485 : : }
6486 : :
8010 6487 : 155 : PQclear(res);
6488 : :
6489 : 155 : destroyPQExpBuffer(query);
6490 : :
6491 : 155 : return agginfo;
6492 : : }
6493 : :
6494 : : /*
6495 : : * getFuncs:
6496 : : * read all the user-defined functions in the system catalogs and
6497 : : * return them in the FuncInfo* structure
6498 : : *
6499 : : * numFuncs is set to the number of functions read in
6500 : : */
6501 : : FuncInfo *
3014 6502 : 155 : getFuncs(Archive *fout, int *numFuncs)
6503 : : {
6504 : 155 : DumpOptions *dopt = fout->dopt;
6505 : : PGresult *res;
6506 : : int ntups;
6507 : : int i;
8010 6508 : 155 : PQExpBuffer query = createPQExpBuffer();
6509 : : FuncInfo *finfo;
6510 : : int i_tableoid;
6511 : : int i_oid;
6512 : : int i_proname;
6513 : : int i_pronamespace;
6514 : : int i_proowner;
6515 : : int i_prolang;
6516 : : int i_pronargs;
6517 : : int i_proargtypes;
6518 : : int i_prorettype;
6519 : : int i_proacl;
6520 : : int i_acldefault;
6521 : :
6522 : : /*
6523 : : * Find all interesting functions. This is a bit complicated:
6524 : : *
6525 : : * 1. Always exclude aggregates; those are handled elsewhere.
6526 : : *
6527 : : * 2. Always exclude functions that are internally dependent on something
6528 : : * else, since presumably those will be created as a result of creating
6529 : : * the something else. This currently acts only to suppress constructor
6530 : : * functions for range types. Note this is OK only because the
6531 : : * constructors don't have any dependencies the range type doesn't have;
6532 : : * otherwise we might not get creation ordering correct.
6533 : : *
6534 : : * 3. Otherwise, we normally exclude functions in pg_catalog. However, if
6535 : : * they're members of extensions and we are in binary-upgrade mode then
6536 : : * include them, since we want to dump extension members individually in
6537 : : * that mode. Also, if they are used by casts or transforms then we need
6538 : : * to gather the information about them, though they won't be dumped if
6539 : : * they are built-in. Also, in 9.6 and up, include functions in
6540 : : * pg_catalog if they have an ACL different from what's shown in
6541 : : * pg_init_privs (so we have to join to pg_init_privs; annoying).
6542 : : */
2930 sfrost@snowman.net 6543 [ + - ]: 155 : if (fout->remoteVersion >= 90600)
6544 : : {
6545 : : const char *not_agg_check;
6546 : :
2235 peter_e@gmx.net 6547 : 310 : not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
6548 [ + - ]: 155 : : "NOT p.proisagg");
6549 : :
2930 sfrost@snowman.net 6550 : 155 : appendPQExpBuffer(query,
6551 : : "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
6552 : : "p.pronargs, p.proargtypes, p.prorettype, "
6553 : : "p.proacl, "
6554 : : "acldefault('f', p.proowner) AS acldefault, "
6555 : : "p.pronamespace, "
6556 : : "p.proowner "
6557 : : "FROM pg_proc p "
6558 : : "LEFT JOIN pg_init_privs pip ON "
6559 : : "(p.oid = pip.objoid "
6560 : : "AND pip.classoid = 'pg_proc'::regclass "
6561 : : "AND pip.objsubid = 0) "
6562 : : "WHERE %s"
6563 : : "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6564 : : "WHERE classid = 'pg_proc'::regclass AND "
6565 : : "objid = p.oid AND deptype = 'i')"
6566 : : "\n AND ("
6567 : : "\n pronamespace != "
6568 : : "(SELECT oid FROM pg_namespace "
6569 : : "WHERE nspname = 'pg_catalog')"
6570 : : "\n OR EXISTS (SELECT 1 FROM pg_cast"
6571 : : "\n WHERE pg_cast.oid > %u "
6572 : : "\n AND p.oid = pg_cast.castfunc)"
6573 : : "\n OR EXISTS (SELECT 1 FROM pg_transform"
6574 : : "\n WHERE pg_transform.oid > %u AND "
6575 : : "\n (p.oid = pg_transform.trffromsql"
6576 : : "\n OR p.oid = pg_transform.trftosql))",
6577 : : not_agg_check,
6578 : : g_last_builtin_oid,
6579 : : g_last_builtin_oid);
6580 [ + + ]: 155 : if (dopt->binary_upgrade)
6581 : 14 : appendPQExpBufferStr(query,
6582 : : "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6583 : : "classid = 'pg_proc'::regclass AND "
6584 : : "objid = p.oid AND "
6585 : : "refclassid = 'pg_extension'::regclass AND "
6586 : : "deptype = 'e')");
2760 tgl@sss.pgh.pa.us 6587 : 155 : appendPQExpBufferStr(query,
6588 : : "\n OR p.proacl IS DISTINCT FROM pip.initprivs");
2930 sfrost@snowman.net 6589 : 155 : appendPQExpBufferChar(query, ')');
6590 : : }
6591 : : else
6592 : : {
8010 tgl@sss.pgh.pa.us 6593 :UBC 0 : appendPQExpBuffer(query,
6594 : : "SELECT tableoid, oid, proname, prolang, "
6595 : : "pronargs, proargtypes, prorettype, proacl, "
6596 : : "acldefault('f', proowner) AS acldefault, "
6597 : : "pronamespace, "
6598 : : "proowner "
6599 : : "FROM pg_proc p "
6600 : : "WHERE NOT proisagg"
6601 : : "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6602 : : "WHERE classid = 'pg_proc'::regclass AND "
6603 : : "objid = p.oid AND deptype = 'i')"
6604 : : "\n AND ("
6605 : : "\n pronamespace != "
6606 : : "(SELECT oid FROM pg_namespace "
6607 : : "WHERE nspname = 'pg_catalog')"
6608 : : "\n OR EXISTS (SELECT 1 FROM pg_cast"
6609 : : "\n WHERE pg_cast.oid > '%u'::oid"
6610 : : "\n AND p.oid = pg_cast.castfunc)",
6611 : : g_last_builtin_oid);
6612 : :
2671 sfrost@snowman.net 6613 [ # # ]: 0 : if (fout->remoteVersion >= 90500)
6614 : 0 : appendPQExpBuffer(query,
6615 : : "\n OR EXISTS (SELECT 1 FROM pg_transform"
6616 : : "\n WHERE pg_transform.oid > '%u'::oid"
6617 : : "\n AND (p.oid = pg_transform.trffromsql"
6618 : : "\n OR p.oid = pg_transform.trftosql))",
6619 : : g_last_builtin_oid);
6620 : :
852 tgl@sss.pgh.pa.us 6621 [ # # ]: 0 : if (dopt->binary_upgrade)
3800 heikki.linnakangas@i 6622 : 0 : appendPQExpBufferStr(query,
6623 : : "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6624 : : "classid = 'pg_proc'::regclass AND "
6625 : : "objid = p.oid AND "
6626 : : "refclassid = 'pg_extension'::regclass AND "
6627 : : "deptype = 'e')");
6628 : 0 : appendPQExpBufferChar(query, ')');
6629 : : }
6630 : :
4450 rhaas@postgresql.org 6631 :CBC 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6632 : :
8010 tgl@sss.pgh.pa.us 6633 : 155 : ntups = PQntuples(res);
6634 : :
6635 : 155 : *numFuncs = ntups;
6636 : :
4212 6637 : 155 : finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
6638 : :
7435 6639 : 155 : i_tableoid = PQfnumber(res, "tableoid");
8010 6640 : 155 : i_oid = PQfnumber(res, "oid");
6641 : 155 : i_proname = PQfnumber(res, "proname");
6642 : 155 : i_pronamespace = PQfnumber(res, "pronamespace");
835 6643 : 155 : i_proowner = PQfnumber(res, "proowner");
8010 6644 : 155 : i_prolang = PQfnumber(res, "prolang");
6645 : 155 : i_pronargs = PQfnumber(res, "pronargs");
6646 : 155 : i_proargtypes = PQfnumber(res, "proargtypes");
6647 : 155 : i_prorettype = PQfnumber(res, "prorettype");
8001 peter_e@gmx.net 6648 : 155 : i_proacl = PQfnumber(res, "proacl");
860 tgl@sss.pgh.pa.us 6649 : 155 : i_acldefault = PQfnumber(res, "acldefault");
6650 : :
8010 6651 [ + + ]: 3918 : for (i = 0; i < ntups; i++)
6652 : : {
7435 6653 : 3763 : finfo[i].dobj.objType = DO_FUNC;
6654 : 3763 : finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6655 : 3763 : finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6656 : 3763 : AssignDumpId(&finfo[i].dobj);
4524 bruce@momjian.us 6657 : 3763 : finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
6756 6658 : 7526 : finfo[i].dobj.namespace =
1328 peter@eisentraut.org 6659 : 3763 : findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
860 tgl@sss.pgh.pa.us 6660 : 3763 : finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
6661 : 3763 : finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6662 : 3763 : finfo[i].dacl.privtype = 0;
6663 : 3763 : finfo[i].dacl.initprivs = NULL;
835 6664 : 3763 : finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
8010 6665 : 3763 : finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
7435 6666 : 3763 : finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
8010 6667 : 3763 : finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
6668 [ + + ]: 3763 : if (finfo[i].nargs == 0)
6669 : 827 : finfo[i].argtypes = NULL;
6670 : : else
6671 : : {
4524 bruce@momjian.us 6672 : 2936 : finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
7435 tgl@sss.pgh.pa.us 6673 : 2936 : parseOidArray(PQgetvalue(res, i, i_proargtypes),
6674 : 2936 : finfo[i].argtypes, finfo[i].nargs);
6675 : : }
315 6676 : 3763 : finfo[i].postponed_def = false; /* might get set during sort */
6677 : :
6678 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 6679 : 3763 : selectDumpableObject(&(finfo[i].dobj), fout);
6680 : :
6681 : : /* Mark whether function has an ACL */
860 tgl@sss.pgh.pa.us 6682 [ + + ]: 3763 : if (!PQgetisnull(res, i, i_proacl))
6683 : 142 : finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6684 : : }
6685 : :
8010 6686 : 155 : PQclear(res);
6687 : :
6688 : 155 : destroyPQExpBuffer(query);
6689 : :
6690 : 155 : return finfo;
6691 : : }
6692 : :
6693 : : /*
6694 : : * getTables
6695 : : * read all the tables (no indexes) in the system catalogs,
6696 : : * and return them as an array of TableInfo structures
6697 : : *
6698 : : * *numTables is set to the number of tables read in
6699 : : */
6700 : : TableInfo *
3014 6701 : 156 : getTables(Archive *fout, int *numTables)
6702 : : {
6703 : 156 : DumpOptions *dopt = fout->dopt;
6704 : : PGresult *res;
6705 : : int ntups;
6706 : : int i;
8010 6707 : 156 : PQExpBuffer query = createPQExpBuffer();
6708 : : TableInfo *tblinfo;
6709 : : int i_reltableoid;
6710 : : int i_reloid;
6711 : : int i_relname;
6712 : : int i_relnamespace;
6713 : : int i_relkind;
6714 : : int i_reltype;
6715 : : int i_relowner;
6716 : : int i_relchecks;
6717 : : int i_relhasindex;
6718 : : int i_relhasrules;
6719 : : int i_relpages;
6720 : : int i_toastpages;
6721 : : int i_owning_tab;
6722 : : int i_owning_col;
6723 : : int i_reltablespace;
6724 : : int i_relhasoids;
6725 : : int i_relhastriggers;
6726 : : int i_relpersistence;
6727 : : int i_relispopulated;
6728 : : int i_relreplident;
6729 : : int i_relrowsec;
6730 : : int i_relforcerowsec;
6731 : : int i_relfrozenxid;
6732 : : int i_toastfrozenxid;
6733 : : int i_toastoid;
6734 : : int i_relminmxid;
6735 : : int i_toastminmxid;
6736 : : int i_reloptions;
6737 : : int i_checkoption;
6738 : : int i_toastreloptions;
6739 : : int i_reloftype;
6740 : : int i_foreignserver;
6741 : : int i_amname;
6742 : : int i_is_identity_sequence;
6743 : : int i_relacl;
6744 : : int i_acldefault;
6745 : : int i_ispartition;
6746 : :
6747 : : /*
6748 : : * Find all the tables and table-like objects.
6749 : : *
6750 : : * We must fetch all tables in this phase because otherwise we cannot
6751 : : * correctly identify inherited columns, owned sequences, etc.
6752 : : *
6753 : : * We include system catalogs, so that we can work if a user table is
6754 : : * defined to inherit from a system catalog (pretty weird, but...)
6755 : : *
6756 : : * Note: in this phase we should collect only a minimal amount of
6757 : : * information about each table, basically just enough to decide if it is
6758 : : * interesting. In particular, since we do not yet have lock on any user
6759 : : * table, we MUST NOT invoke any server-side data collection functions
6760 : : * (for instance, pg_get_partkeydef()). Those are likely to fail or give
6761 : : * wrong answers if any concurrent DDL is happening.
6762 : : */
6763 : :
586 drowley@postgresql.o 6764 : 156 : appendPQExpBufferStr(query,
6765 : : "SELECT c.tableoid, c.oid, c.relname, "
6766 : : "c.relnamespace, c.relkind, c.reltype, "
6767 : : "c.relowner, "
6768 : : "c.relchecks, "
6769 : : "c.relhasindex, c.relhasrules, c.relpages, "
6770 : : "c.relhastriggers, "
6771 : : "c.relpersistence, "
6772 : : "c.reloftype, "
6773 : : "c.relacl, "
6774 : : "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
6775 : : " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
6776 : : "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
6777 : : "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
6778 : : "ELSE 0 END AS foreignserver, "
6779 : : "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
6780 : : "tc.oid AS toid, "
6781 : : "tc.relpages AS toastpages, "
6782 : : "tc.reloptions AS toast_reloptions, "
6783 : : "d.refobjid AS owning_tab, "
6784 : : "d.refobjsubid AS owning_col, "
6785 : : "tsp.spcname AS reltablespace, ");
6786 : :
908 tgl@sss.pgh.pa.us 6787 [ + - ]: 156 : if (fout->remoteVersion >= 120000)
6788 : 156 : appendPQExpBufferStr(query,
6789 : : "false AS relhasoids, ");
6790 : : else
908 tgl@sss.pgh.pa.us 6791 :UBC 0 : appendPQExpBufferStr(query,
6792 : : "c.relhasoids, ");
6793 : :
908 tgl@sss.pgh.pa.us 6794 [ + - ]:CBC 156 : if (fout->remoteVersion >= 90300)
6795 : 156 : appendPQExpBufferStr(query,
6796 : : "c.relispopulated, ");
6797 : : else
908 tgl@sss.pgh.pa.us 6798 :UBC 0 : appendPQExpBufferStr(query,
6799 : : "'t' as relispopulated, ");
6800 : :
908 tgl@sss.pgh.pa.us 6801 [ + - ]:CBC 156 : if (fout->remoteVersion >= 90400)
6802 : 156 : appendPQExpBufferStr(query,
6803 : : "c.relreplident, ");
6804 : : else
908 tgl@sss.pgh.pa.us 6805 :UBC 0 : appendPQExpBufferStr(query,
6806 : : "'d' AS relreplident, ");
6807 : :
908 tgl@sss.pgh.pa.us 6808 [ + - ]:CBC 156 : if (fout->remoteVersion >= 90500)
6809 : 156 : appendPQExpBufferStr(query,
6810 : : "c.relrowsecurity, c.relforcerowsecurity, ");
6811 : : else
908 tgl@sss.pgh.pa.us 6812 :UBC 0 : appendPQExpBufferStr(query,
6813 : : "false AS relrowsecurity, "
6814 : : "false AS relforcerowsecurity, ");
6815 : :
908 tgl@sss.pgh.pa.us 6816 [ + - ]:CBC 156 : if (fout->remoteVersion >= 90300)
6817 : 156 : appendPQExpBufferStr(query,
6818 : : "c.relminmxid, tc.relminmxid AS tminmxid, ");
6819 : : else
908 tgl@sss.pgh.pa.us 6820 :UBC 0 : appendPQExpBufferStr(query,
6821 : : "0 AS relminmxid, 0 AS tminmxid, ");
6822 : :
908 tgl@sss.pgh.pa.us 6823 [ + - ]:CBC 156 : if (fout->remoteVersion >= 90300)
6824 : 156 : appendPQExpBufferStr(query,
6825 : : "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6826 : : "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6827 : : "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
6828 : : else
908 tgl@sss.pgh.pa.us 6829 :UBC 0 : appendPQExpBufferStr(query,
6830 : : "c.reloptions, NULL AS checkoption, ");
6831 : :
2930 sfrost@snowman.net 6832 [ + - ]:CBC 156 : if (fout->remoteVersion >= 90600)
908 tgl@sss.pgh.pa.us 6833 : 156 : appendPQExpBufferStr(query,
6834 : : "am.amname, ");
6835 : : else
908 tgl@sss.pgh.pa.us 6836 :UBC 0 : appendPQExpBufferStr(query,
6837 : : "NULL AS amname, ");
6838 : :
908 tgl@sss.pgh.pa.us 6839 [ + - ]:CBC 156 : if (fout->remoteVersion >= 90600)
6840 : 156 : appendPQExpBufferStr(query,
6841 : : "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
6842 : : else
908 tgl@sss.pgh.pa.us 6843 :UBC 0 : appendPQExpBufferStr(query,
6844 : : "false AS is_identity_sequence, ");
6845 : :
908 tgl@sss.pgh.pa.us 6846 [ + - ]:CBC 156 : if (fout->remoteVersion >= 100000)
6847 : 156 : appendPQExpBufferStr(query,
6848 : : "c.relispartition AS ispartition ");
6849 : : else
908 tgl@sss.pgh.pa.us 6850 :UBC 0 : appendPQExpBufferStr(query,
6851 : : "false AS ispartition ");
6852 : :
6853 : : /*
6854 : : * Left join to pg_depend to pick up dependency info linking sequences to
6855 : : * their owning column, if any (note this dependency is AUTO except for
6856 : : * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
6857 : : * collect the spcname.
6858 : : */
908 tgl@sss.pgh.pa.us 6859 :CBC 156 : appendPQExpBufferStr(query,
6860 : : "\nFROM pg_class c\n"
6861 : : "LEFT JOIN pg_depend d ON "
6862 : : "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
6863 : : "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
6864 : : "d.objsubid = 0 AND "
6865 : : "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
6866 : : "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
6867 : :
6868 : : /*
6869 : : * In 9.6 and up, left join to pg_am to pick up the amname.
6870 : : */
6871 [ + - ]: 156 : if (fout->remoteVersion >= 90600)
6872 : 156 : appendPQExpBufferStr(query,
6873 : : "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
6874 : :
6875 : : /*
6876 : : * We purposefully ignore toast OIDs for partitioned tables; the reason is
6877 : : * that versions 10 and 11 have them, but later versions do not, so
6878 : : * emitting them causes the upgrade to fail.
6879 : : */
860 6880 : 156 : appendPQExpBufferStr(query,
6881 : : "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
6882 : : " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
6883 : : " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
6884 : :
6885 : : /*
6886 : : * Restrict to interesting relkinds (in particular, not indexes). Not all
6887 : : * relkinds are possible in older servers, but it's not worth the trouble
6888 : : * to emit a version-dependent list.
6889 : : *
6890 : : * Composite-type table entries won't be dumped as such, but we have to
6891 : : * make a DumpableObject for them so that we can track dependencies of the
6892 : : * composite type (pg_depend entries for columns of the composite type
6893 : : * link to the pg_class entry not the pg_type entry).
6894 : : */
908 6895 : 156 : appendPQExpBufferStr(query,
6896 : : "WHERE c.relkind IN ("
6897 : : CppAsString2(RELKIND_RELATION) ", "
6898 : : CppAsString2(RELKIND_SEQUENCE) ", "
6899 : : CppAsString2(RELKIND_VIEW) ", "
6900 : : CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
6901 : : CppAsString2(RELKIND_MATVIEW) ", "
6902 : : CppAsString2(RELKIND_FOREIGN_TABLE) ", "
6903 : : CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
6904 : : "ORDER BY c.oid");
6905 : :
4450 rhaas@postgresql.org 6906 : 156 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6907 : :
8010 tgl@sss.pgh.pa.us 6908 : 156 : ntups = PQntuples(res);
6909 : :
6910 : 156 : *numTables = ntups;
6911 : :
6912 : : /*
6913 : : * Extract data from result and lock dumpable tables. We do the locking
6914 : : * before anything else, to minimize the window wherein a table could
6915 : : * disappear under us.
6916 : : *
6917 : : * Note that we have to save info about all tables here, even when dumping
6918 : : * only one, because we don't yet know which tables might be inheritance
6919 : : * ancestors of the target table.
6920 : : */
4212 6921 : 156 : tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6922 : :
7435 6923 : 156 : i_reltableoid = PQfnumber(res, "tableoid");
8010 6924 : 156 : i_reloid = PQfnumber(res, "oid");
6925 : 156 : i_relname = PQfnumber(res, "relname");
6926 : 156 : i_relnamespace = PQfnumber(res, "relnamespace");
6927 : 156 : i_relkind = PQfnumber(res, "relkind");
860 6928 : 156 : i_reltype = PQfnumber(res, "reltype");
835 6929 : 156 : i_relowner = PQfnumber(res, "relowner");
8010 6930 : 156 : i_relchecks = PQfnumber(res, "relchecks");
6931 : 156 : i_relhasindex = PQfnumber(res, "relhasindex");
6932 : 156 : i_relhasrules = PQfnumber(res, "relhasrules");
908 6933 : 156 : i_relpages = PQfnumber(res, "relpages");
860 6934 : 156 : i_toastpages = PQfnumber(res, "toastpages");
908 6935 : 156 : i_owning_tab = PQfnumber(res, "owning_tab");
6936 : 156 : i_owning_col = PQfnumber(res, "owning_col");
6937 : 156 : i_reltablespace = PQfnumber(res, "reltablespace");
6938 : 156 : i_relhasoids = PQfnumber(res, "relhasoids");
6939 : 156 : i_relhastriggers = PQfnumber(res, "relhastriggers");
6940 : 156 : i_relpersistence = PQfnumber(res, "relpersistence");
6941 : 156 : i_relispopulated = PQfnumber(res, "relispopulated");
6942 : 156 : i_relreplident = PQfnumber(res, "relreplident");
3490 sfrost@snowman.net 6943 : 156 : i_relrowsec = PQfnumber(res, "relrowsecurity");
3115 6944 : 156 : i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
5534 bruce@momjian.us 6945 : 156 : i_relfrozenxid = PQfnumber(res, "relfrozenxid");
4755 6946 : 156 : i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
908 tgl@sss.pgh.pa.us 6947 : 156 : i_toastoid = PQfnumber(res, "toid");
6948 : 156 : i_relminmxid = PQfnumber(res, "relminmxid");
3574 bruce@momjian.us 6949 : 156 : i_toastminmxid = PQfnumber(res, "tminmxid");
6496 6950 : 156 : i_reloptions = PQfnumber(res, "reloptions");
3923 sfrost@snowman.net 6951 : 156 : i_checkoption = PQfnumber(res, "checkoption");
5550 alvherre@alvh.no-ip. 6952 : 156 : i_toastreloptions = PQfnumber(res, "toast_reloptions");
5190 peter_e@gmx.net 6953 : 156 : i_reloftype = PQfnumber(res, "reloftype");
908 tgl@sss.pgh.pa.us 6954 : 156 : i_foreignserver = PQfnumber(res, "foreignserver");
6955 : 156 : i_amname = PQfnumber(res, "amname");
2565 peter_e@gmx.net 6956 : 156 : i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
908 tgl@sss.pgh.pa.us 6957 : 156 : i_relacl = PQfnumber(res, "relacl");
860 6958 : 156 : i_acldefault = PQfnumber(res, "acldefault");
2537 sfrost@snowman.net 6959 : 156 : i_ispartition = PQfnumber(res, "ispartition");
6960 : :
2741 tgl@sss.pgh.pa.us 6961 [ + + ]: 156 : if (dopt->lockWaitTimeout)
6962 : : {
6963 : : /*
6964 : : * Arrange to fail instead of waiting forever for a table lock.
6965 : : *
6966 : : * NB: this coding assumes that the only queries issued within the
6967 : : * following loop are LOCK TABLEs; else the timeout may be undesirably
6968 : : * applied to other things too.
6969 : : */
5747 6970 : 2 : resetPQExpBuffer(query);
3800 heikki.linnakangas@i 6971 : 2 : appendPQExpBufferStr(query, "SET statement_timeout = ");
3470 alvherre@alvh.no-ip. 6972 : 2 : appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
4450 rhaas@postgresql.org 6973 : 2 : ExecuteSqlStatement(fout, query->data);
6974 : : }
6975 : :
467 tgl@sss.pgh.pa.us 6976 : 156 : resetPQExpBuffer(query);
6977 : :
8010 6978 [ + + ]: 39679 : for (i = 0; i < ntups; i++)
6979 : : {
7435 6980 : 39523 : tblinfo[i].dobj.objType = DO_TABLE;
6981 : 39523 : tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6982 : 39523 : tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6983 : 39523 : AssignDumpId(&tblinfo[i].dobj);
4524 bruce@momjian.us 6984 : 39523 : tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4451 rhaas@postgresql.org 6985 : 79046 : tblinfo[i].dobj.namespace =
1328 peter@eisentraut.org 6986 : 39523 : findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
860 tgl@sss.pgh.pa.us 6987 : 39523 : tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
6988 : 39523 : tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6989 : 39523 : tblinfo[i].dacl.privtype = 0;
6990 : 39523 : tblinfo[i].dacl.initprivs = NULL;
8010 6991 : 39523 : tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
860 6992 : 39523 : tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
835 6993 : 39523 : tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
908 6994 : 39523 : tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
8010 6995 : 39523 : tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6996 : 39523 : tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4039 andrew@dunslane.net 6997 : 39523 : tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
860 tgl@sss.pgh.pa.us 6998 [ + + ]: 39523 : if (PQgetisnull(res, i, i_toastpages))
6999 : 31372 : tblinfo[i].toastpages = 0;
7000 : : else
7001 : 8151 : tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
7909 7002 [ + + ]: 39523 : if (PQgetisnull(res, i, i_owning_tab))
7003 : : {
7435 7004 : 39192 : tblinfo[i].owning_tab = InvalidOid;
7909 7005 : 39192 : tblinfo[i].owning_col = 0;
7006 : : }
7007 : : else
7008 : : {
7435 7009 : 331 : tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
7909 7010 : 331 : tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
7011 : : }
4524 bruce@momjian.us 7012 : 39523 : tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
908 tgl@sss.pgh.pa.us 7013 : 39523 : tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
7014 : 39523 : tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
7015 : 39523 : tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
7016 : 39523 : tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
7017 : 39523 : tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
7018 : 39523 : tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
7019 : 39523 : tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
7020 : 39523 : tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
7021 : 39523 : tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
7022 : 39523 : tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
7023 : 39523 : tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
7024 : 39523 : tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
4524 bruce@momjian.us 7025 : 39523 : tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
908 tgl@sss.pgh.pa.us 7026 [ + + ]: 39523 : if (PQgetisnull(res, i, i_checkoption))
3923 sfrost@snowman.net 7027 : 39476 : tblinfo[i].checkoption = NULL;
7028 : : else
7029 : 47 : tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
4524 bruce@momjian.us 7030 : 39523 : tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
860 tgl@sss.pgh.pa.us 7031 : 39523 : tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
908 7032 : 39523 : tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
1866 andres@anarazel.de 7033 [ + + ]: 39523 : if (PQgetisnull(res, i, i_amname))
7034 : 23809 : tblinfo[i].amname = NULL;
7035 : : else
7036 : 15714 : tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
908 tgl@sss.pgh.pa.us 7037 : 39523 : tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
7038 : 39523 : tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
7039 : :
7040 : : /* other fields were zeroed above */
7041 : :
7042 : : /*
7043 : : * Decide whether we want to dump this table.
7044 : : */
7033 7045 [ + + ]: 39523 : if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
2930 sfrost@snowman.net 7046 : 152 : tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
7047 : : else
7048 : 39371 : selectDumpableTable(&tblinfo[i], fout);
7049 : :
7050 : : /*
7051 : : * Now, consider the table "interesting" if we need to dump its
7052 : : * definition or its data. Later on, we'll skip a lot of data
7053 : : * collection for uninteresting tables.
7054 : : *
7055 : : * Note: the "interesting" flag will also be set by flagInhTables for
7056 : : * parents of interesting tables, so that we collect necessary
7057 : : * inheritance info even when the parents are not themselves being
7058 : : * dumped. This is the main reason why we need an "interesting" flag
7059 : : * that's separate from the components-to-dump bitmask.
7060 : : */
860 tgl@sss.pgh.pa.us 7061 : 39523 : tblinfo[i].interesting = (tblinfo[i].dobj.dump &
7062 : : (DUMP_COMPONENT_DEFINITION |
7063 : 39523 : DUMP_COMPONENT_DATA)) != 0;
7064 : :
908 7065 : 39523 : tblinfo[i].dummy_view = false; /* might get set during sort */
7066 : 39523 : tblinfo[i].postponed_def = false; /* might get set during sort */
7067 : :
7068 : : /* Tables have data */
860 7069 : 39523 : tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
7070 : :
7071 : : /* Mark whether table has an ACL */
7072 [ + + ]: 39523 : if (!PQgetisnull(res, i, i_relacl))
7073 : 32378 : tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
7074 : 39523 : tblinfo[i].hascolumnACLs = false; /* may get set later */
7075 : :
7076 : : /*
7077 : : * Read-lock target tables to make sure they aren't DROPPED or altered
7078 : : * in schema before we get around to dumping them.
7079 : : *
7080 : : * Note that we don't explicitly lock parents of the target tables; we
7081 : : * assume our lock on the child is enough to prevent schema
7082 : : * alterations to parent tables.
7083 : : *
7084 : : * NOTE: it'd be kinda nice to lock other relations too, not only
7085 : : * plain or partitioned tables, but the backend doesn't presently
7086 : : * allow that.
7087 : : *
7088 : : * We only need to lock the table for certain components; see
7089 : : * pg_dump.h
7090 : : */
7091 [ + + ]: 39523 : if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
1255 7092 [ + + ]: 5981 : (tblinfo[i].relkind == RELKIND_RELATION ||
860 7093 [ + + ]: 1698 : tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
7094 : : {
7095 : : /*
7096 : : * Tables are locked in batches. When dumping from a remote
7097 : : * server this can save a significant amount of time by reducing
7098 : : * the number of round trips.
7099 : : */
467 7100 [ + + ]: 4807 : if (query->len == 0)
7101 : 100 : appendPQExpBuffer(query, "LOCK TABLE %s",
7102 : 100 : fmtQualifiedDumpable(&tblinfo[i]));
7103 : : else
7104 : : {
7105 : 4707 : appendPQExpBuffer(query, ", %s",
7106 : 4707 : fmtQualifiedDumpable(&tblinfo[i]));
7107 : :
7108 : : /* Arbitrarily end a batch when query length reaches 100K. */
7109 [ - + ]: 4707 : if (query->len >= 100000)
7110 : : {
7111 : : /* Lock another batch of tables. */
467 tgl@sss.pgh.pa.us 7112 :UBC 0 : appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7113 : 0 : ExecuteSqlStatement(fout, query->data);
7114 : 0 : resetPQExpBuffer(query);
7115 : : }
7116 : : }
7117 : : }
7118 : : }
7119 : :
467 tgl@sss.pgh.pa.us 7120 [ + + ]:CBC 156 : if (query->len != 0)
7121 : : {
7122 : : /* Lock the tables in the last batch. */
7123 : 100 : appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7124 : 100 : ExecuteSqlStatement(fout, query->data);
7125 : : }
7126 : :
2741 7127 [ + + ]: 155 : if (dopt->lockWaitTimeout)
7128 : : {
4450 rhaas@postgresql.org 7129 : 2 : ExecuteSqlStatement(fout, "SET statement_timeout = 0");
7130 : : }
7131 : :
8010 tgl@sss.pgh.pa.us 7132 : 155 : PQclear(res);
7133 : :
4397 7134 : 155 : destroyPQExpBuffer(query);
7135 : :
7136 : 155 : return tblinfo;
7137 : : }
7138 : :
7139 : : /*
7140 : : * getOwnedSeqs
7141 : : * identify owned sequences and mark them as dumpable if owning table is
7142 : : *
7143 : : * We used to do this in getTables(), but it's better to do it after the
7144 : : * index used by findTableByOid() has been set up.
7145 : : */
7146 : : void
7147 : 155 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
7148 : : {
7149 : : int i;
7150 : :
7151 : : /*
7152 : : * Force sequences that are "owned" by table columns to be dumped whenever
7153 : : * their owning table is being dumped.
7154 : : */
7155 [ + + ]: 39419 : for (i = 0; i < numTables; i++)
7156 : : {
6446 7157 : 39264 : TableInfo *seqinfo = &tblinfo[i];
7158 : : TableInfo *owning_tab;
7159 : :
7160 [ + + ]: 39264 : if (!OidIsValid(seqinfo->owning_tab))
7161 : 38936 : continue; /* not an owned sequence */
7162 : :
4397 7163 : 328 : owning_tab = findTableByOid(seqinfo->owning_tab);
2655 sfrost@snowman.net 7164 [ - + ]: 328 : if (owning_tab == NULL)
737 tgl@sss.pgh.pa.us 7165 :UBC 0 : pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
7166 : : seqinfo->owning_tab, seqinfo->dobj.catId.oid);
7167 : :
7168 : : /*
7169 : : * Only dump identity sequences if we're going to dump the table that
7170 : : * it belongs to.
7171 : : */
2062 michael@paquier.xyz 7172 [ + + ]:CBC 328 : if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
7173 [ + + ]: 26 : seqinfo->is_identity_sequence)
7174 : : {
7175 : 7 : seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
7176 : 7 : continue;
7177 : : }
7178 : :
7179 : : /*
7180 : : * Otherwise we need to dump the components that are being dumped for
7181 : : * the table and any components which the sequence is explicitly
7182 : : * marked with.
7183 : : *
7184 : : * We can't simply use the set of components which are being dumped
7185 : : * for the table as the table might be in an extension (and only the
7186 : : * non-extension components, eg: ACLs if changed, security labels, and
7187 : : * policies, are being dumped) while the sequence is not (and
7188 : : * therefore the definition and other components should also be
7189 : : * dumped).
7190 : : *
7191 : : * If the sequence is part of the extension then it should be properly
7192 : : * marked by checkExtensionMembership() and this will be a no-op as
7193 : : * the table will be equivalently marked.
7194 : : */
2814 sfrost@snowman.net 7195 : 321 : seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
7196 : :
7197 [ + + ]: 321 : if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
4397 tgl@sss.pgh.pa.us 7198 : 304 : seqinfo->interesting = true;
7199 : : }
10141 scrappy@hub.org 7200 : 155 : }
7201 : :
7202 : : /*
7203 : : * getInherits
7204 : : * read all the inheritance information
7205 : : * from the system catalogs return them in the InhInfo* structure
7206 : : *
7207 : : * numInherits is set to the number of pairs read in
7208 : : */
7209 : : InhInfo *
4451 rhaas@postgresql.org 7210 : 155 : getInherits(Archive *fout, int *numInherits)
7211 : : {
7212 : : PGresult *res;
7213 : : int ntups;
7214 : : int i;
8768 bruce@momjian.us 7215 : 155 : PQExpBuffer query = createPQExpBuffer();
7216 : : InhInfo *inhinfo;
7217 : :
7218 : : int i_inhrelid;
7219 : : int i_inhparent;
7220 : :
7221 : : /* find all the inheritance information */
2537 sfrost@snowman.net 7222 : 155 : appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
7223 : :
4450 rhaas@postgresql.org 7224 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7225 : :
9716 bruce@momjian.us 7226 : 155 : ntups = PQntuples(res);
7227 : :
7228 : 155 : *numInherits = ntups;
7229 : :
4524 7230 : 155 : inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
7231 : :
8910 7232 : 155 : i_inhrelid = PQfnumber(res, "inhrelid");
9716 7233 : 155 : i_inhparent = PQfnumber(res, "inhparent");
7234 : :
7235 [ + + ]: 2504 : for (i = 0; i < ntups; i++)
7236 : : {
7435 tgl@sss.pgh.pa.us 7237 : 2349 : inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
7238 : 2349 : inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
7239 : : }
7240 : :
9716 bruce@momjian.us 7241 : 155 : PQclear(res);
7242 : :
8290 tgl@sss.pgh.pa.us 7243 : 155 : destroyPQExpBuffer(query);
7244 : :
9716 bruce@momjian.us 7245 : 155 : return inhinfo;
7246 : : }
7247 : :
7248 : : /*
7249 : : * getPartitioningInfo
7250 : : * get information about partitioning
7251 : : *
7252 : : * For the most part, we only collect partitioning info about tables we
7253 : : * intend to dump. However, this function has to consider all partitioned
7254 : : * tables in the database, because we need to know about parents of partitions
7255 : : * we are going to dump even if the parents themselves won't be dumped.
7256 : : *
7257 : : * Specifically, what we need to know is whether each partitioned table
7258 : : * has an "unsafe" partitioning scheme that requires us to force
7259 : : * load-via-partition-root mode for its children. Currently the only case
7260 : : * for which we force that is hash partitioning on enum columns, since the
7261 : : * hash codes depend on enum value OIDs which won't be replicated across
7262 : : * dump-and-reload. There are other cases in which load-via-partition-root
7263 : : * might be necessary, but we expect users to cope with them.
7264 : : */
7265 : : void
394 tgl@sss.pgh.pa.us 7266 : 155 : getPartitioningInfo(Archive *fout)
7267 : : {
7268 : : PQExpBuffer query;
7269 : : PGresult *res;
7270 : : int ntups;
7271 : :
7272 : : /* hash partitioning didn't exist before v11 */
7273 [ - + ]: 155 : if (fout->remoteVersion < 110000)
394 tgl@sss.pgh.pa.us 7274 :UBC 0 : return;
7275 : : /* needn't bother if schema-only dump */
394 tgl@sss.pgh.pa.us 7276 [ + + ]:CBC 155 : if (fout->dopt->schemaOnly)
7277 : 16 : return;
7278 : :
7279 : 139 : query = createPQExpBuffer();
7280 : :
7281 : : /*
7282 : : * Unsafe partitioning schemes are exactly those for which hash enum_ops
7283 : : * appears among the partition opclasses. We needn't check partstrat.
7284 : : *
7285 : : * Note that this query may well retrieve info about tables we aren't
7286 : : * going to dump and hence have no lock on. That's okay since we need not
7287 : : * invoke any unsafe server-side functions.
7288 : : */
7289 : 139 : appendPQExpBufferStr(query,
7290 : : "SELECT partrelid FROM pg_partitioned_table WHERE\n"
7291 : : "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
7292 : : "ON c.opcmethod = a.oid\n"
7293 : : "WHERE opcname = 'enum_ops' "
7294 : : "AND opcnamespace = 'pg_catalog'::regnamespace "
7295 : : "AND amname = 'hash') = ANY(partclass)");
7296 : :
7297 : 139 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7298 : :
7299 : 139 : ntups = PQntuples(res);
7300 : :
7301 [ + + ]: 141 : for (int i = 0; i < ntups; i++)
7302 : : {
7303 : 2 : Oid tabrelid = atooid(PQgetvalue(res, i, 0));
7304 : : TableInfo *tbinfo;
7305 : :
7306 : 2 : tbinfo = findTableByOid(tabrelid);
7307 [ - + ]: 2 : if (tbinfo == NULL)
394 tgl@sss.pgh.pa.us 7308 :UBC 0 : pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
7309 : : tabrelid);
394 tgl@sss.pgh.pa.us 7310 :CBC 2 : tbinfo->unsafe_partitions = true;
7311 : : }
7312 : :
7313 : 139 : PQclear(res);
7314 : :
7315 : 139 : destroyPQExpBuffer(query);
7316 : : }
7317 : :
7318 : : /*
7319 : : * getIndexes
7320 : : * get information about every index on a dumpable table
7321 : : *
7322 : : * Note: index data is not returned directly to the caller, but it
7323 : : * does get entered into the DumpableObject tables.
7324 : : */
7325 : : void
4451 rhaas@postgresql.org 7326 : 155 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
7327 : : {
7435 tgl@sss.pgh.pa.us 7328 : 155 : PQExpBuffer query = createPQExpBuffer();
860 7329 : 155 : PQExpBuffer tbloids = createPQExpBuffer();
7330 : : PGresult *res;
7331 : : int ntups;
7332 : : int curtblindx;
7333 : : IndxInfo *indxinfo;
7334 : : int i_tableoid,
7335 : : i_oid,
7336 : : i_indrelid,
7337 : : i_indexname,
7338 : : i_parentidx,
7339 : : i_indexdef,
7340 : : i_indnkeyatts,
7341 : : i_indnatts,
7342 : : i_indkey,
7343 : : i_indisclustered,
7344 : : i_indisreplident,
7345 : : i_indnullsnotdistinct,
7346 : : i_contype,
7347 : : i_conname,
7348 : : i_condeferrable,
7349 : : i_condeferred,
7350 : : i_conperiod,
7351 : : i_contableoid,
7352 : : i_conoid,
7353 : : i_condef,
7354 : : i_tablespace,
7355 : : i_indreloptions,
7356 : : i_indstatcols,
7357 : : i_indstatvals;
7358 : :
7359 : : /*
7360 : : * We want to perform just one query against pg_index. However, we
7361 : : * mustn't try to select every row of the catalog and then sort it out on
7362 : : * the client side, because some of the server-side functions we need
7363 : : * would be unsafe to apply to tables we don't have lock on. Hence, we
7364 : : * build an array of the OIDs of tables we care about (and now have lock
7365 : : * on!), and use a WHERE clause to constrain which rows are selected.
7366 : : */
7367 : 155 : appendPQExpBufferChar(tbloids, '{');
7368 [ + + ]: 39419 : for (int i = 0; i < numTables; i++)
7369 : : {
7435 7370 : 39264 : TableInfo *tbinfo = &tblinfo[i];
7371 : :
4060 kgrittn@postgresql.o 7372 [ + + ]: 39264 : if (!tbinfo->hasindex)
7435 tgl@sss.pgh.pa.us 7373 : 27592 : continue;
7374 : :
7375 : : /*
7376 : : * We can ignore indexes of uninteresting tables.
7377 : : */
860 7378 [ + + ]: 11672 : if (!tbinfo->interesting)
7435 7379 : 9942 : continue;
7380 : :
7381 : : /* OK, we need info for this table */
860 7382 [ + + ]: 1730 : if (tbloids->len > 1) /* do we have more than the '{'? */
7383 : 1653 : appendPQExpBufferChar(tbloids, ',');
7384 : 1730 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
7385 : : }
7386 : 155 : appendPQExpBufferChar(tbloids, '}');
7387 : :
586 drowley@postgresql.o 7388 : 155 : appendPQExpBufferStr(query,
7389 : : "SELECT t.tableoid, t.oid, i.indrelid, "
7390 : : "t.relname AS indexname, "
7391 : : "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7392 : : "i.indkey, i.indisclustered, "
7393 : : "c.contype, c.conname, "
7394 : : "c.condeferrable, c.condeferred, "
7395 : : "c.tableoid AS contableoid, "
7396 : : "c.oid AS conoid, "
7397 : : "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
7398 : : "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7399 : : "t.reloptions AS indreloptions, ");
7400 : :
7401 : :
846 peter@eisentraut.org 7402 [ + - ]: 155 : if (fout->remoteVersion >= 90400)
586 drowley@postgresql.o 7403 : 155 : appendPQExpBufferStr(query,
7404 : : "i.indisreplident, ");
7405 : : else
586 drowley@postgresql.o 7406 :UBC 0 : appendPQExpBufferStr(query,
7407 : : "false AS indisreplident, ");
7408 : :
846 peter@eisentraut.org 7409 [ + - ]:CBC 155 : if (fout->remoteVersion >= 110000)
586 drowley@postgresql.o 7410 : 155 : appendPQExpBufferStr(query,
7411 : : "inh.inhparent AS parentidx, "
7412 : : "i.indnkeyatts AS indnkeyatts, "
7413 : : "i.indnatts AS indnatts, "
7414 : : "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
7415 : : " FROM pg_catalog.pg_attribute "
7416 : : " WHERE attrelid = i.indexrelid AND "
7417 : : " attstattarget >= 0) AS indstatcols, "
7418 : : "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
7419 : : " FROM pg_catalog.pg_attribute "
7420 : : " WHERE attrelid = i.indexrelid AND "
7421 : : " attstattarget >= 0) AS indstatvals, ");
7422 : : else
586 drowley@postgresql.o 7423 :UBC 0 : appendPQExpBufferStr(query,
7424 : : "0 AS parentidx, "
7425 : : "i.indnatts AS indnkeyatts, "
7426 : : "i.indnatts AS indnatts, "
7427 : : "'' AS indstatcols, "
7428 : : "'' AS indstatvals, ");
7429 : :
801 peter@eisentraut.org 7430 [ + - ]:CBC 155 : if (fout->remoteVersion >= 150000)
586 drowley@postgresql.o 7431 : 155 : appendPQExpBufferStr(query,
7432 : : "i.indnullsnotdistinct, ");
7433 : : else
586 drowley@postgresql.o 7434 :UBC 0 : appendPQExpBufferStr(query,
7435 : : "false AS indnullsnotdistinct, ");
7436 : :
81 peter@eisentraut.org 7437 [ + - ]:GNC 155 : if (fout->remoteVersion >= 170000)
7438 : 155 : appendPQExpBufferStr(query,
7439 : : "c.conperiod ");
7440 : : else
81 peter@eisentraut.org 7441 :UNC 0 : appendPQExpBufferStr(query,
7442 : : "NULL AS conperiod ");
7443 : :
7444 : : /*
7445 : : * The point of the messy-looking outer join is to find a constraint that
7446 : : * is related by an internal dependency link to the index. If we find one,
7447 : : * create a CONSTRAINT entry linked to the INDEX entry. We assume an
7448 : : * index won't have more than one internal dependency.
7449 : : *
7450 : : * Note: the check on conrelid is redundant, but useful because that
7451 : : * column is indexed while conindid is not.
7452 : : */
860 tgl@sss.pgh.pa.us 7453 [ + - ]:CBC 155 : if (fout->remoteVersion >= 110000)
7454 : : {
7455 : 155 : appendPQExpBuffer(query,
7456 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7457 : : "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7458 : : "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7459 : : "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
7460 : : "LEFT JOIN pg_catalog.pg_constraint c "
7461 : : "ON (i.indrelid = c.conrelid AND "
7462 : : "i.indexrelid = c.conindid AND "
7463 : : "c.contype IN ('p','u','x')) "
7464 : : "LEFT JOIN pg_catalog.pg_inherits inh "
7465 : : "ON (inh.inhrelid = indexrelid) "
7466 : : "WHERE (i.indisvalid OR t2.relkind = 'p') "
7467 : : "AND i.indisready "
7468 : : "ORDER BY i.indrelid, indexname",
7469 : : tbloids->data);
7470 : : }
7471 : : else
7472 : : {
7473 : : /*
7474 : : * the test on indisready is necessary in 9.2, and harmless in
7475 : : * earlier/later versions
7476 : : */
860 tgl@sss.pgh.pa.us 7477 :UBC 0 : appendPQExpBuffer(query,
7478 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7479 : : "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7480 : : "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7481 : : "LEFT JOIN pg_catalog.pg_constraint c "
7482 : : "ON (i.indrelid = c.conrelid AND "
7483 : : "i.indexrelid = c.conindid AND "
7484 : : "c.contype IN ('p','u','x')) "
7485 : : "WHERE i.indisvalid AND i.indisready "
7486 : : "ORDER BY i.indrelid, indexname",
7487 : : tbloids->data);
7488 : : }
7489 : :
860 tgl@sss.pgh.pa.us 7490 :CBC 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7491 : :
7492 : 155 : ntups = PQntuples(res);
7493 : :
7494 : 155 : i_tableoid = PQfnumber(res, "tableoid");
7495 : 155 : i_oid = PQfnumber(res, "oid");
7496 : 155 : i_indrelid = PQfnumber(res, "indrelid");
7497 : 155 : i_indexname = PQfnumber(res, "indexname");
7498 : 155 : i_parentidx = PQfnumber(res, "parentidx");
7499 : 155 : i_indexdef = PQfnumber(res, "indexdef");
7500 : 155 : i_indnkeyatts = PQfnumber(res, "indnkeyatts");
7501 : 155 : i_indnatts = PQfnumber(res, "indnatts");
7502 : 155 : i_indkey = PQfnumber(res, "indkey");
7503 : 155 : i_indisclustered = PQfnumber(res, "indisclustered");
7504 : 155 : i_indisreplident = PQfnumber(res, "indisreplident");
801 peter@eisentraut.org 7505 : 155 : i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
860 tgl@sss.pgh.pa.us 7506 : 155 : i_contype = PQfnumber(res, "contype");
7507 : 155 : i_conname = PQfnumber(res, "conname");
7508 : 155 : i_condeferrable = PQfnumber(res, "condeferrable");
7509 : 155 : i_condeferred = PQfnumber(res, "condeferred");
40 peter@eisentraut.org 7510 :GNC 155 : i_conperiod = PQfnumber(res, "conperiod");
860 tgl@sss.pgh.pa.us 7511 :CBC 155 : i_contableoid = PQfnumber(res, "contableoid");
7512 : 155 : i_conoid = PQfnumber(res, "conoid");
7513 : 155 : i_condef = PQfnumber(res, "condef");
7514 : 155 : i_tablespace = PQfnumber(res, "tablespace");
7515 : 155 : i_indreloptions = PQfnumber(res, "indreloptions");
7516 : 155 : i_indstatcols = PQfnumber(res, "indstatcols");
7517 : 155 : i_indstatvals = PQfnumber(res, "indstatvals");
7518 : :
7519 : 155 : indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
7520 : :
7521 : : /*
7522 : : * Outer loop iterates once per table, not once per row. Incrementing of
7523 : : * j is handled by the inner loop.
7524 : : */
7525 : 155 : curtblindx = -1;
7526 [ + + ]: 1881 : for (int j = 0; j < ntups;)
7527 : : {
7528 : 1726 : Oid indrelid = atooid(PQgetvalue(res, j, i_indrelid));
7529 : 1726 : TableInfo *tbinfo = NULL;
7530 : : int numinds;
7531 : :
7532 : : /* Count rows for this table */
7533 [ + + ]: 2222 : for (numinds = 1; numinds < ntups - j; numinds++)
7534 [ + + ]: 2145 : if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
7535 : 1649 : break;
7536 : :
7537 : : /*
7538 : : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
7539 : : * order.
7540 : : */
7541 [ + - ]: 22221 : while (++curtblindx < numTables)
7542 : : {
7543 : 22221 : tbinfo = &tblinfo[curtblindx];
7544 [ + + ]: 22221 : if (tbinfo->dobj.catId.oid == indrelid)
7545 : 1726 : break;
7546 : : }
7547 [ - + ]: 1726 : if (curtblindx >= numTables)
737 tgl@sss.pgh.pa.us 7548 :UBC 0 : pg_fatal("unrecognized table OID %u", indrelid);
7549 : : /* cross-check that we only got requested tables */
860 tgl@sss.pgh.pa.us 7550 [ + - ]:CBC 1726 : if (!tbinfo->hasindex ||
7551 [ - + ]: 1726 : !tbinfo->interesting)
737 tgl@sss.pgh.pa.us 7552 :UBC 0 : pg_fatal("unexpected index data for table \"%s\"",
7553 : : tbinfo->dobj.name);
7554 : :
7555 : : /* Save data for this table */
860 tgl@sss.pgh.pa.us 7556 :CBC 1726 : tbinfo->indexes = indxinfo + j;
7557 : 1726 : tbinfo->numIndexes = numinds;
7558 : :
7559 [ + + ]: 3948 : for (int c = 0; c < numinds; c++, j++)
7560 : : {
7561 : : char contype;
7562 : :
7435 7563 : 2222 : indxinfo[j].dobj.objType = DO_INDEX;
7564 : 2222 : indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7565 : 2222 : indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7566 : 2222 : AssignDumpId(&indxinfo[j].dobj);
2277 alvherre@alvh.no-ip. 7567 : 2222 : indxinfo[j].dobj.dump = tbinfo->dobj.dump;
4524 bruce@momjian.us 7568 : 2222 : indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7347 tgl@sss.pgh.pa.us 7569 : 2222 : indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7435 7570 : 2222 : indxinfo[j].indextable = tbinfo;
4524 bruce@momjian.us 7571 : 2222 : indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
2189 heikki.linnakangas@i 7572 : 2222 : indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
2199 teodor@sigaev.ru 7573 : 2222 : indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
4524 bruce@momjian.us 7574 : 2222 : indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
3025 tgl@sss.pgh.pa.us 7575 : 2222 : indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
1944 michael@paquier.xyz 7576 : 2222 : indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
7577 : 2222 : indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
2199 teodor@sigaev.ru 7578 : 2222 : indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7435 tgl@sss.pgh.pa.us 7579 : 2222 : parseOidArray(PQgetvalue(res, j, i_indkey),
2199 teodor@sigaev.ru 7580 : 2222 : indxinfo[j].indkeys, indxinfo[j].indnattrs);
7435 tgl@sss.pgh.pa.us 7581 : 2222 : indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
3810 rhaas@postgresql.org 7582 : 2222 : indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
801 peter@eisentraut.org 7583 : 2222 : indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
2277 alvherre@alvh.no-ip. 7584 : 2222 : indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
1431 tgl@sss.pgh.pa.us 7585 : 2222 : indxinfo[j].partattaches = (SimplePtrList)
7586 : : {
7587 : : NULL, NULL
7588 : : };
7435 7589 : 2222 : contype = *(PQgetvalue(res, j, i_contype));
7590 : :
5242 7591 [ + + + + : 2222 : if (contype == 'p' || contype == 'u' || contype == 'x')
+ + ]
7435 7592 : 1211 : {
7593 : : /*
7594 : : * If we found a constraint matching the index, create an
7595 : : * entry for it.
7596 : : */
7597 : : ConstraintInfo *constrinfo;
7598 : :
903 7599 : 1211 : constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
7600 : 1211 : constrinfo->dobj.objType = DO_CONSTRAINT;
7601 : 1211 : constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7602 : 1211 : constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7603 : 1211 : AssignDumpId(&constrinfo->dobj);
7604 : 1211 : constrinfo->dobj.dump = tbinfo->dobj.dump;
7605 : 1211 : constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7606 : 1211 : constrinfo->dobj.namespace = tbinfo->dobj.namespace;
7607 : 1211 : constrinfo->contable = tbinfo;
7608 : 1211 : constrinfo->condomain = NULL;
7609 : 1211 : constrinfo->contype = contype;
5242 7610 [ + + ]: 1211 : if (contype == 'x')
903 7611 : 10 : constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
7612 : : else
7613 : 1201 : constrinfo->condef = NULL;
7614 : 1211 : constrinfo->confrelid = InvalidOid;
7615 : 1211 : constrinfo->conindex = indxinfo[j].dobj.dumpId;
7616 : 1211 : constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7617 : 1211 : constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
40 peter@eisentraut.org 7618 :GNC 1211 : constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
903 tgl@sss.pgh.pa.us 7619 :CBC 1211 : constrinfo->conislocal = true;
7620 : 1211 : constrinfo->separate = true;
7621 : :
7622 : 1211 : indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
7623 : : }
7624 : : else
7625 : : {
7626 : : /* Plain secondary index */
7435 7627 : 1011 : indxinfo[j].indexconstraint = 0;
7628 : : }
7629 : : }
7630 : : }
7631 : :
860 7632 : 155 : PQclear(res);
7633 : :
7435 7634 : 155 : destroyPQExpBuffer(query);
860 7635 : 155 : destroyPQExpBuffer(tbloids);
7435 7636 : 155 : }
7637 : :
7638 : : /*
7639 : : * getExtendedStatistics
7640 : : * get information about extended-statistics objects.
7641 : : *
7642 : : * Note: extended statistics data is not returned directly to the caller, but
7643 : : * it does get entered into the DumpableObject tables.
7644 : : */
7645 : : void
2254 7646 : 155 : getExtendedStatistics(Archive *fout)
7647 : : {
7648 : : PQExpBuffer query;
7649 : : PGresult *res;
7650 : : StatsExtInfo *statsextinfo;
7651 : : int ntups;
7652 : : int i_tableoid;
7653 : : int i_oid;
7654 : : int i_stxname;
7655 : : int i_stxnamespace;
7656 : : int i_stxowner;
7657 : : int i_stxrelid;
7658 : : int i_stattarget;
7659 : : int i;
7660 : :
7661 : : /* Extended statistics were new in v10 */
2578 alvherre@alvh.no-ip. 7662 [ - + ]: 155 : if (fout->remoteVersion < 100000)
2578 alvherre@alvh.no-ip. 7663 :UBC 0 : return;
7664 : :
2578 alvherre@alvh.no-ip. 7665 :CBC 155 : query = createPQExpBuffer();
7666 : :
1678 tomas.vondra@postgre 7667 [ - + ]: 155 : if (fout->remoteVersion < 130000)
586 drowley@postgresql.o 7668 :UBC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
7669 : : "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
7670 : : "FROM pg_catalog.pg_statistic_ext");
7671 : : else
586 drowley@postgresql.o 7672 :CBC 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
7673 : : "stxnamespace, stxowner, stxrelid, stxstattarget "
7674 : : "FROM pg_catalog.pg_statistic_ext");
7675 : :
2254 tgl@sss.pgh.pa.us 7676 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7677 : :
7678 : 155 : ntups = PQntuples(res);
7679 : :
7680 : 155 : i_tableoid = PQfnumber(res, "tableoid");
7681 : 155 : i_oid = PQfnumber(res, "oid");
7682 : 155 : i_stxname = PQfnumber(res, "stxname");
7683 : 155 : i_stxnamespace = PQfnumber(res, "stxnamespace");
835 7684 : 155 : i_stxowner = PQfnumber(res, "stxowner");
107 7685 : 155 : i_stxrelid = PQfnumber(res, "stxrelid");
1678 tomas.vondra@postgre 7686 : 155 : i_stattarget = PQfnumber(res, "stxstattarget");
7687 : :
2254 tgl@sss.pgh.pa.us 7688 : 155 : statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7689 : :
7690 [ + + ]: 313 : for (i = 0; i < ntups; i++)
7691 : : {
7692 : 158 : statsextinfo[i].dobj.objType = DO_STATSEXT;
7693 : 158 : statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7694 : 158 : statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7695 : 158 : AssignDumpId(&statsextinfo[i].dobj);
7696 : 158 : statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7697 : 316 : statsextinfo[i].dobj.namespace =
1328 peter@eisentraut.org 7698 : 158 : findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
835 tgl@sss.pgh.pa.us 7699 : 158 : statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
107 7700 : 316 : statsextinfo[i].stattable =
7701 : 158 : findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
28 peter@eisentraut.org 7702 [ + + ]:GNC 158 : if (PQgetisnull(res, i, i_stattarget))
7703 : 112 : statsextinfo[i].stattarget = -1;
7704 : : else
7705 : 46 : statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
7706 : :
7707 : : /* Decide whether we want to dump it */
107 tgl@sss.pgh.pa.us 7708 :CBC 158 : selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
7709 : : }
7710 : :
2254 7711 : 155 : PQclear(res);
2578 alvherre@alvh.no-ip. 7712 : 155 : destroyPQExpBuffer(query);
7713 : : }
7714 : :
7715 : : /*
7716 : : * getConstraints
7717 : : *
7718 : : * Get info about constraints on dumpable tables.
7719 : : *
7720 : : * Currently handles foreign keys only.
7721 : : * Unique and primary key constraints are handled with indexes,
7722 : : * while check constraints are processed in getTableAttrs().
7723 : : */
7724 : : void
4451 rhaas@postgresql.org 7725 : 155 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7726 : : {
860 tgl@sss.pgh.pa.us 7727 : 155 : PQExpBuffer query = createPQExpBuffer();
7728 : 155 : PQExpBuffer tbloids = createPQExpBuffer();
7729 : : PGresult *res;
7730 : : int ntups;
7731 : : int curtblindx;
7732 : 155 : TableInfo *tbinfo = NULL;
7733 : : ConstraintInfo *constrinfo;
7734 : : int i_contableoid,
7735 : : i_conoid,
7736 : : i_conrelid,
7737 : : i_conname,
7738 : : i_confrelid,
7739 : : i_conindid,
7740 : : i_condef;
7741 : :
7742 : : /*
7743 : : * We want to perform just one query against pg_constraint. However, we
7744 : : * mustn't try to select every row of the catalog and then sort it out on
7745 : : * the client side, because some of the server-side functions we need
7746 : : * would be unsafe to apply to tables we don't have lock on. Hence, we
7747 : : * build an array of the OIDs of tables we care about (and now have lock
7748 : : * on!), and use a WHERE clause to constrain which rows are selected.
7749 : : */
7750 : 155 : appendPQExpBufferChar(tbloids, '{');
7751 [ + + ]: 39419 : for (int i = 0; i < numTables; i++)
7752 : : {
603 drowley@postgresql.o 7753 : 39264 : TableInfo *tinfo = &tblinfo[i];
7754 : :
7755 : : /*
7756 : : * For partitioned tables, foreign keys have no triggers so they must
7757 : : * be included anyway in case some foreign keys are defined.
7758 : : */
7759 [ + + ]: 39264 : if ((!tinfo->hastriggers &&
7760 [ + + ]: 38348 : tinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7761 [ + + ]: 1258 : !(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7435 tgl@sss.pgh.pa.us 7762 : 38071 : continue;
7763 : :
7764 : : /* OK, we need info for this table */
860 7765 [ + + ]: 1193 : if (tbloids->len > 1) /* do we have more than the '{'? */
7766 : 1139 : appendPQExpBufferChar(tbloids, ',');
603 drowley@postgresql.o 7767 : 1193 : appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
7768 : : }
860 tgl@sss.pgh.pa.us 7769 : 155 : appendPQExpBufferChar(tbloids, '}');
7770 : :
7771 : 155 : appendPQExpBufferStr(query,
7772 : : "SELECT c.tableoid, c.oid, "
7773 : : "conrelid, conname, confrelid, ");
7774 [ + - ]: 155 : if (fout->remoteVersion >= 110000)
7775 : 155 : appendPQExpBufferStr(query, "conindid, ");
7776 : : else
860 tgl@sss.pgh.pa.us 7777 :UBC 0 : appendPQExpBufferStr(query, "0 AS conindid, ");
860 tgl@sss.pgh.pa.us 7778 :CBC 155 : appendPQExpBuffer(query,
7779 : : "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
7780 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7781 : : "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
7782 : : "WHERE contype = 'f' ",
7783 : : tbloids->data);
7784 [ + - ]: 155 : if (fout->remoteVersion >= 110000)
7785 : 155 : appendPQExpBufferStr(query,
7786 : : "AND conparentid = 0 ");
7787 : 155 : appendPQExpBufferStr(query,
7788 : : "ORDER BY conrelid, conname");
7789 : :
7790 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7791 : :
7792 : 155 : ntups = PQntuples(res);
7793 : :
7794 : 155 : i_contableoid = PQfnumber(res, "tableoid");
7795 : 155 : i_conoid = PQfnumber(res, "oid");
7796 : 155 : i_conrelid = PQfnumber(res, "conrelid");
7797 : 155 : i_conname = PQfnumber(res, "conname");
7798 : 155 : i_confrelid = PQfnumber(res, "confrelid");
7799 : 155 : i_conindid = PQfnumber(res, "conindid");
7800 : 155 : i_condef = PQfnumber(res, "condef");
7801 : :
7802 : 155 : constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7803 : :
7804 : 155 : curtblindx = -1;
7805 [ + + ]: 333 : for (int j = 0; j < ntups; j++)
7806 : : {
7807 : 178 : Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
7808 : : TableInfo *reftable;
7809 : :
7810 : : /*
7811 : : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
7812 : : * order.
7813 : : */
7814 [ + + + + ]: 178 : if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
7815 : : {
7816 [ + - ]: 13252 : while (++curtblindx < numTables)
7817 : : {
7818 : 13252 : tbinfo = &tblinfo[curtblindx];
7819 [ + + ]: 13252 : if (tbinfo->dobj.catId.oid == conrelid)
7820 : 168 : break;
7821 : : }
7822 [ - + ]: 168 : if (curtblindx >= numTables)
737 tgl@sss.pgh.pa.us 7823 :UBC 0 : pg_fatal("unrecognized table OID %u", conrelid);
7824 : : }
7825 : :
860 tgl@sss.pgh.pa.us 7826 :CBC 178 : constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7827 : 178 : constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7828 : 178 : constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7829 : 178 : AssignDumpId(&constrinfo[j].dobj);
7830 : 178 : constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7831 : 178 : constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7832 : 178 : constrinfo[j].contable = tbinfo;
7833 : 178 : constrinfo[j].condomain = NULL;
7834 : 178 : constrinfo[j].contype = 'f';
7835 : 178 : constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7836 : 178 : constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7837 : 178 : constrinfo[j].conindex = 0;
7838 : 178 : constrinfo[j].condeferrable = false;
7839 : 178 : constrinfo[j].condeferred = false;
7840 : 178 : constrinfo[j].conislocal = true;
7841 : 178 : constrinfo[j].separate = true;
7842 : :
7843 : : /*
7844 : : * Restoring an FK that points to a partitioned table requires that
7845 : : * all partition indexes have been attached beforehand. Ensure that
7846 : : * happens by making the constraint depend on each index partition
7847 : : * attach object.
7848 : : */
7849 : 178 : reftable = findTableByOid(constrinfo[j].confrelid);
7850 [ + - + + ]: 178 : if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
7851 : : {
7852 : 20 : Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));
7853 : :
7854 [ + - ]: 20 : if (indexOid != InvalidOid)
7855 : : {
7856 [ + - ]: 20 : for (int k = 0; k < reftable->numIndexes; k++)
7857 : : {
7858 : : IndxInfo *refidx;
7859 : :
7860 : : /* not our index? */
7861 [ - + ]: 20 : if (reftable->indexes[k].dobj.catId.oid != indexOid)
860 tgl@sss.pgh.pa.us 7862 :UBC 0 : continue;
7863 : :
860 tgl@sss.pgh.pa.us 7864 :CBC 20 : refidx = &reftable->indexes[k];
7865 : 20 : addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
7866 : 20 : break;
7867 : : }
7868 : : }
7869 : : }
7870 : : }
7871 : :
7872 : 155 : PQclear(res);
7873 : :
7435 7874 : 155 : destroyPQExpBuffer(query);
860 7875 : 155 : destroyPQExpBuffer(tbloids);
7435 7876 : 155 : }
7877 : :
7878 : : /*
7879 : : * addConstrChildIdxDeps
7880 : : *
7881 : : * Recursive subroutine for getConstraints
7882 : : *
7883 : : * Given an object representing a foreign key constraint and an index on the
7884 : : * partitioned table it references, mark the constraint object as dependent
7885 : : * on the DO_INDEX_ATTACH object of each index partition, recursively
7886 : : * drilling down to their partitions if any. This ensures that the FK is not
7887 : : * restored until the index is fully marked valid.
7888 : : */
7889 : : static void
1159 peter@eisentraut.org 7890 : 45 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
7891 : : {
7892 : : SimplePtrListCell *cell;
7893 : :
1339 alvherre@alvh.no-ip. 7894 [ - + ]: 45 : Assert(dobj->objType == DO_FK_CONSTRAINT);
7895 : :
7896 [ + + ]: 155 : for (cell = refidx->partattaches.head; cell; cell = cell->next)
7897 : : {
7898 : 110 : IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
7899 : :
7900 : 110 : addObjectDependency(dobj, attach->dobj.dumpId);
7901 : :
7902 [ + + ]: 110 : if (attach->partitionIdx->partattaches.head != NULL)
7903 : 25 : addConstrChildIdxDeps(dobj, attach->partitionIdx);
7904 : : }
7905 : 45 : }
7906 : :
7907 : : /*
7908 : : * getDomainConstraints
7909 : : *
7910 : : * Get info about constraints on a domain.
7911 : : */
7912 : : static void
4451 rhaas@postgresql.org 7913 : 134 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7914 : : {
7915 : : int i;
7916 : : ConstraintInfo *constrinfo;
860 tgl@sss.pgh.pa.us 7917 : 134 : PQExpBuffer query = createPQExpBuffer();
7918 : : PGresult *res;
7919 : : int i_tableoid,
7920 : : i_oid,
7921 : : i_conname,
7922 : : i_consrc;
7923 : : int ntups;
7924 : :
7925 [ + + ]: 134 : if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
7926 : : {
7927 : : /* Set up query for constraint-specific details */
7928 : 44 : appendPQExpBufferStr(query,
7929 : : "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
7930 : : "SELECT tableoid, oid, conname, "
7931 : : "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7932 : : "convalidated "
7933 : : "FROM pg_catalog.pg_constraint "
7934 : : "WHERE contypid = $1 AND contype = 'c' "
7935 : : "ORDER BY conname");
7936 : :
7937 : 44 : ExecuteSqlStatement(fout, query->data);
7938 : :
7939 : 44 : fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
7940 : : }
7941 : :
7942 : 134 : printfPQExpBuffer(query,
7943 : : "EXECUTE getDomainConstraints('%u')",
7944 : : tyinfo->dobj.catId.oid);
7945 : :
4450 rhaas@postgresql.org 7946 : 134 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7947 : :
7435 tgl@sss.pgh.pa.us 7948 : 134 : ntups = PQntuples(res);
7949 : :
7950 : 134 : i_tableoid = PQfnumber(res, "tableoid");
7951 : 134 : i_oid = PQfnumber(res, "oid");
7952 : 134 : i_conname = PQfnumber(res, "conname");
7953 : 134 : i_consrc = PQfnumber(res, "consrc");
7954 : :
4524 bruce@momjian.us 7955 : 134 : constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7956 : :
5226 7957 : 134 : tyinfo->nDomChecks = ntups;
7958 : 134 : tyinfo->domChecks = constrinfo;
7959 : :
7435 tgl@sss.pgh.pa.us 7960 [ + + ]: 223 : for (i = 0; i < ntups; i++)
7961 : : {
4326 bruce@momjian.us 7962 : 89 : bool validated = PQgetvalue(res, i, 4)[0] == 't';
7963 : :
7435 tgl@sss.pgh.pa.us 7964 : 89 : constrinfo[i].dobj.objType = DO_CONSTRAINT;
7965 : 89 : constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7966 : 89 : constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7967 : 89 : AssignDumpId(&constrinfo[i].dobj);
4524 bruce@momjian.us 7968 : 89 : constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5226 7969 : 89 : constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7435 tgl@sss.pgh.pa.us 7970 : 89 : constrinfo[i].contable = NULL;
5226 bruce@momjian.us 7971 : 89 : constrinfo[i].condomain = tyinfo;
7435 tgl@sss.pgh.pa.us 7972 : 89 : constrinfo[i].contype = 'c';
4524 bruce@momjian.us 7973 : 89 : constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
5697 tgl@sss.pgh.pa.us 7974 : 89 : constrinfo[i].confrelid = InvalidOid;
7435 7975 : 89 : constrinfo[i].conindex = 0;
5373 7976 : 89 : constrinfo[i].condeferrable = false;
7977 : 89 : constrinfo[i].condeferred = false;
5819 7978 : 89 : constrinfo[i].conislocal = true;
7979 : :
4524 alvherre@alvh.no-ip. 7980 : 89 : constrinfo[i].separate = !validated;
7981 : :
7982 : : /*
7983 : : * Make the domain depend on the constraint, ensuring it won't be
7984 : : * output till any constraint dependencies are OK. If the constraint
7985 : : * has not been validated, it's going to be dumped after the domain
7986 : : * anyway, so this doesn't matter.
7987 : : */
7988 [ + - ]: 89 : if (validated)
7989 : 89 : addObjectDependency(&tyinfo->dobj,
7990 : 89 : constrinfo[i].dobj.dumpId);
7991 : : }
7992 : :
7435 tgl@sss.pgh.pa.us 7993 : 134 : PQclear(res);
7994 : :
7995 : 134 : destroyPQExpBuffer(query);
7996 : 134 : }
7997 : :
7998 : : /*
7999 : : * getRules
8000 : : * get basic information about every rule in the system
8001 : : *
8002 : : * numRules is set to the number of rules read in
8003 : : */
8004 : : RuleInfo *
4451 rhaas@postgresql.org 8005 : 155 : getRules(Archive *fout, int *numRules)
8006 : : {
8007 : : PGresult *res;
8008 : : int ntups;
8009 : : int i;
7435 tgl@sss.pgh.pa.us 8010 : 155 : PQExpBuffer query = createPQExpBuffer();
8011 : : RuleInfo *ruleinfo;
8012 : : int i_tableoid;
8013 : : int i_oid;
8014 : : int i_rulename;
8015 : : int i_ruletable;
8016 : : int i_ev_type;
8017 : : int i_is_instead;
8018 : : int i_ev_enabled;
8019 : :
852 8020 : 155 : appendPQExpBufferStr(query, "SELECT "
8021 : : "tableoid, oid, rulename, "
8022 : : "ev_class AS ruletable, ev_type, is_instead, "
8023 : : "ev_enabled "
8024 : : "FROM pg_rewrite "
8025 : : "ORDER BY oid");
8026 : :
4450 rhaas@postgresql.org 8027 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8028 : :
7435 tgl@sss.pgh.pa.us 8029 : 155 : ntups = PQntuples(res);
8030 : :
8031 : 155 : *numRules = ntups;
8032 : :
4524 bruce@momjian.us 8033 : 155 : ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
8034 : :
7435 tgl@sss.pgh.pa.us 8035 : 155 : i_tableoid = PQfnumber(res, "tableoid");
8036 : 155 : i_oid = PQfnumber(res, "oid");
8037 : 155 : i_rulename = PQfnumber(res, "rulename");
8038 : 155 : i_ruletable = PQfnumber(res, "ruletable");
8039 : 155 : i_ev_type = PQfnumber(res, "ev_type");
8040 : 155 : i_is_instead = PQfnumber(res, "is_instead");
6236 JanWieck@Yahoo.com 8041 : 155 : i_ev_enabled = PQfnumber(res, "ev_enabled");
8042 : :
7435 tgl@sss.pgh.pa.us 8043 [ + + ]: 23560 : for (i = 0; i < ntups; i++)
8044 : : {
8045 : : Oid ruletableoid;
8046 : :
8047 : 23405 : ruleinfo[i].dobj.objType = DO_RULE;
8048 : 23405 : ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8049 : 23405 : ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8050 : 23405 : AssignDumpId(&ruleinfo[i].dobj);
4524 bruce@momjian.us 8051 : 23405 : ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7435 tgl@sss.pgh.pa.us 8052 : 23405 : ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
8053 : 23405 : ruleinfo[i].ruletable = findTableByOid(ruletableoid);
6971 8054 [ - + ]: 23405 : if (ruleinfo[i].ruletable == NULL)
737 tgl@sss.pgh.pa.us 8055 :UBC 0 : pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
8056 : : ruletableoid, ruleinfo[i].dobj.catId.oid);
7347 tgl@sss.pgh.pa.us 8057 :CBC 23405 : ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
6618 8058 : 23405 : ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7435 8059 : 23405 : ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
8060 : 23405 : ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
6236 JanWieck@Yahoo.com 8061 : 23405 : ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7435 tgl@sss.pgh.pa.us 8062 [ + - ]: 23405 : if (ruleinfo[i].ruletable)
8063 : : {
8064 : : /*
8065 : : * If the table is a view or materialized view, force its ON
8066 : : * SELECT rule to be sorted before the view itself --- this
8067 : : * ensures that any dependencies for the rule affect the table's
8068 : : * positioning. Other rules are forced to appear after their
8069 : : * table.
8070 : : */
4060 kgrittn@postgresql.o 8071 [ + + ]: 23405 : if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
4039 andrew@dunslane.net 8072 [ + + ]: 619 : ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7435 tgl@sss.pgh.pa.us 8073 [ + + + - ]: 23240 : ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
8074 : : {
8075 : 22900 : addObjectDependency(&ruleinfo[i].ruletable->dobj,
8076 : 22900 : ruleinfo[i].dobj.dumpId);
8077 : : /* We'll merge the rule into CREATE VIEW, if possible */
7061 8078 : 22900 : ruleinfo[i].separate = false;
8079 : : }
8080 : : else
8081 : : {
7435 8082 : 505 : addObjectDependency(&ruleinfo[i].dobj,
8083 : 505 : ruleinfo[i].ruletable->dobj.dumpId);
7061 8084 : 505 : ruleinfo[i].separate = true;
8085 : : }
8086 : : }
8087 : : else
7061 tgl@sss.pgh.pa.us 8088 :UBC 0 : ruleinfo[i].separate = true;
8089 : : }
8090 : :
7435 tgl@sss.pgh.pa.us 8091 :CBC 155 : PQclear(res);
8092 : :
8093 : 155 : destroyPQExpBuffer(query);
8094 : :
8095 : 155 : return ruleinfo;
8096 : : }
8097 : :
8098 : : /*
8099 : : * getTriggers
8100 : : * get information about every trigger on a dumpable table
8101 : : *
8102 : : * Note: trigger data is not returned directly to the caller, but it
8103 : : * does get entered into the DumpableObject tables.
8104 : : */
8105 : : void
4451 rhaas@postgresql.org 8106 : 155 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
8107 : : {
7435 tgl@sss.pgh.pa.us 8108 : 155 : PQExpBuffer query = createPQExpBuffer();
860 8109 : 155 : PQExpBuffer tbloids = createPQExpBuffer();
8110 : : PGresult *res;
8111 : : int ntups;
8112 : : int curtblindx;
8113 : : TriggerInfo *tginfo;
8114 : : int i_tableoid,
8115 : : i_oid,
8116 : : i_tgrelid,
8117 : : i_tgname,
8118 : : i_tgenabled,
8119 : : i_tgispartition,
8120 : : i_tgdef;
8121 : :
8122 : : /*
8123 : : * We want to perform just one query against pg_trigger. However, we
8124 : : * mustn't try to select every row of the catalog and then sort it out on
8125 : : * the client side, because some of the server-side functions we need
8126 : : * would be unsafe to apply to tables we don't have lock on. Hence, we
8127 : : * build an array of the OIDs of tables we care about (and now have lock
8128 : : * on!), and use a WHERE clause to constrain which rows are selected.
8129 : : */
8130 : 155 : appendPQExpBufferChar(tbloids, '{');
8131 [ + + ]: 39419 : for (int i = 0; i < numTables; i++)
8132 : : {
7435 8133 : 39264 : TableInfo *tbinfo = &tblinfo[i];
8134 : :
2930 sfrost@snowman.net 8135 [ + + ]: 39264 : if (!tbinfo->hastriggers ||
8136 [ + + ]: 916 : !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7435 tgl@sss.pgh.pa.us 8137 : 38406 : continue;
8138 : :
8139 : : /* OK, we need info for this table */
860 8140 [ + + ]: 858 : if (tbloids->len > 1) /* do we have more than the '{'? */
8141 : 806 : appendPQExpBufferChar(tbloids, ',');
8142 : 858 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8143 : : }
8144 : 155 : appendPQExpBufferChar(tbloids, '}');
8145 : :
830 alvherre@alvh.no-ip. 8146 [ + - ]: 155 : if (fout->remoteVersion >= 150000)
8147 : : {
8148 : : /*
8149 : : * NB: think not to use pretty=true in pg_get_triggerdef. It could
8150 : : * result in non-forward-compatible dumps of WHEN clauses due to
8151 : : * under-parenthesization.
8152 : : *
8153 : : * NB: We need to see partition triggers in case the tgenabled flag
8154 : : * has been changed from the parent.
8155 : : */
8156 : 155 : appendPQExpBuffer(query,
8157 : : "SELECT t.tgrelid, t.tgname, "
8158 : : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8159 : : "t.tgenabled, t.tableoid, t.oid, "
8160 : : "t.tgparentid <> 0 AS tgispartition\n"
8161 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8162 : : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8163 : : "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8164 : : "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
8165 : : "OR t.tgenabled != u.tgenabled) "
8166 : : "ORDER BY t.tgrelid, t.tgname",
8167 : : tbloids->data);
8168 : : }
830 alvherre@alvh.no-ip. 8169 [ # # ]:UBC 0 : else if (fout->remoteVersion >= 130000)
8170 : : {
8171 : : /*
8172 : : * NB: think not to use pretty=true in pg_get_triggerdef. It could
8173 : : * result in non-forward-compatible dumps of WHEN clauses due to
8174 : : * under-parenthesization.
8175 : : *
8176 : : * NB: We need to see tgisinternal triggers in partitions, in case the
8177 : : * tgenabled flag has been changed from the parent.
8178 : : */
860 tgl@sss.pgh.pa.us 8179 : 0 : appendPQExpBuffer(query,
8180 : : "SELECT t.tgrelid, t.tgname, "
8181 : : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8182 : : "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
8183 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8184 : : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8185 : : "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8186 : : "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
8187 : : "ORDER BY t.tgrelid, t.tgname",
8188 : : tbloids->data);
8189 : : }
8190 [ # # ]: 0 : else if (fout->remoteVersion >= 110000)
8191 : : {
8192 : : /*
8193 : : * NB: We need to see tgisinternal triggers in partitions, in case the
8194 : : * tgenabled flag has been changed from the parent. No tgparentid in
8195 : : * version 11-12, so we have to match them via pg_depend.
8196 : : *
8197 : : * See above about pretty=true in pg_get_triggerdef.
8198 : : */
8199 : 0 : appendPQExpBuffer(query,
8200 : : "SELECT t.tgrelid, t.tgname, "
8201 : : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8202 : : "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
8203 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8204 : : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8205 : : "LEFT JOIN pg_catalog.pg_depend AS d ON "
8206 : : " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8207 : : " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8208 : : " d.objid = t.oid "
8209 : : "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
8210 : : "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
8211 : : "ORDER BY t.tgrelid, t.tgname",
8212 : : tbloids->data);
8213 : : }
8214 : : else
8215 : : {
8216 : : /* See above about pretty=true in pg_get_triggerdef */
8217 : 0 : appendPQExpBuffer(query,
8218 : : "SELECT t.tgrelid, t.tgname, "
8219 : : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8220 : : "t.tgenabled, false as tgispartition, "
8221 : : "t.tableoid, t.oid "
8222 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8223 : : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8224 : : "WHERE NOT tgisinternal "
8225 : : "ORDER BY t.tgrelid, t.tgname",
8226 : : tbloids->data);
8227 : : }
8228 : :
860 tgl@sss.pgh.pa.us 8229 :CBC 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8230 : :
8231 : 155 : ntups = PQntuples(res);
8232 : :
8233 : 155 : i_tableoid = PQfnumber(res, "tableoid");
8234 : 155 : i_oid = PQfnumber(res, "oid");
8235 : 155 : i_tgrelid = PQfnumber(res, "tgrelid");
8236 : 155 : i_tgname = PQfnumber(res, "tgname");
8237 : 155 : i_tgenabled = PQfnumber(res, "tgenabled");
830 alvherre@alvh.no-ip. 8238 : 155 : i_tgispartition = PQfnumber(res, "tgispartition");
860 tgl@sss.pgh.pa.us 8239 : 155 : i_tgdef = PQfnumber(res, "tgdef");
8240 : :
8241 : 155 : tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
8242 : :
8243 : : /*
8244 : : * Outer loop iterates once per table, not once per row. Incrementing of
8245 : : * j is handled by the inner loop.
8246 : : */
8247 : 155 : curtblindx = -1;
8248 [ + + ]: 461 : for (int j = 0; j < ntups;)
8249 : : {
8250 : 306 : Oid tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
8251 : 306 : TableInfo *tbinfo = NULL;
8252 : : int numtrigs;
8253 : :
8254 : : /* Count rows for this table */
8255 [ + + ]: 508 : for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
8256 [ + + ]: 456 : if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
8257 : 254 : break;
8258 : :
8259 : : /*
8260 : : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8261 : : * order.
8262 : : */
8263 [ + - ]: 15799 : while (++curtblindx < numTables)
8264 : : {
8265 : 15799 : tbinfo = &tblinfo[curtblindx];
8266 [ + + ]: 15799 : if (tbinfo->dobj.catId.oid == tgrelid)
8267 : 306 : break;
8268 : : }
8269 [ - + ]: 306 : if (curtblindx >= numTables)
737 tgl@sss.pgh.pa.us 8270 :UBC 0 : pg_fatal("unrecognized table OID %u", tgrelid);
8271 : :
8272 : : /* Save data for this table */
860 tgl@sss.pgh.pa.us 8273 :CBC 306 : tbinfo->triggers = tginfo + j;
8274 : 306 : tbinfo->numTriggers = numtrigs;
8275 : :
8276 [ + + ]: 814 : for (int c = 0; c < numtrigs; c++, j++)
8277 : : {
7435 8278 : 508 : tginfo[j].dobj.objType = DO_TRIGGER;
8279 : 508 : tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8280 : 508 : tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8281 : 508 : AssignDumpId(&tginfo[j].dobj);
4524 bruce@momjian.us 8282 : 508 : tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7347 tgl@sss.pgh.pa.us 8283 : 508 : tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7435 8284 : 508 : tginfo[j].tgtable = tbinfo;
6236 JanWieck@Yahoo.com 8285 : 508 : tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
830 alvherre@alvh.no-ip. 8286 : 508 : tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
91 peter@eisentraut.org 8287 :GNC 508 : tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
8288 : : }
8289 : : }
8290 : :
860 tgl@sss.pgh.pa.us 8291 :CBC 155 : PQclear(res);
8292 : :
7435 8293 : 155 : destroyPQExpBuffer(query);
860 8294 : 155 : destroyPQExpBuffer(tbloids);
7435 8295 : 155 : }
8296 : :
8297 : : /*
8298 : : * getEventTriggers
8299 : : * get information about event triggers
8300 : : */
8301 : : EventTriggerInfo *
4288 rhaas@postgresql.org 8302 : 155 : getEventTriggers(Archive *fout, int *numEventTriggers)
8303 : : {
8304 : : int i;
8305 : : PQExpBuffer query;
8306 : : PGresult *res;
8307 : : EventTriggerInfo *evtinfo;
8308 : : int i_tableoid,
8309 : : i_oid,
8310 : : i_evtname,
8311 : : i_evtevent,
8312 : : i_evtowner,
8313 : : i_evttags,
8314 : : i_evtfname,
8315 : : i_evtenabled;
8316 : : int ntups;
8317 : :
8318 : : /* Before 9.3, there are no event triggers */
8319 [ - + ]: 155 : if (fout->remoteVersion < 90300)
8320 : : {
4288 rhaas@postgresql.org 8321 :UBC 0 : *numEventTriggers = 0;
8322 : 0 : return NULL;
8323 : : }
8324 : :
3927 sfrost@snowman.net 8325 :CBC 155 : query = createPQExpBuffer();
8326 : :
586 drowley@postgresql.o 8327 : 155 : appendPQExpBufferStr(query,
8328 : : "SELECT e.tableoid, e.oid, evtname, evtenabled, "
8329 : : "evtevent, evtowner, "
8330 : : "array_to_string(array("
8331 : : "select quote_literal(x) "
8332 : : " from unnest(evttags) as t(x)), ', ') as evttags, "
8333 : : "e.evtfoid::regproc as evtfname "
8334 : : "FROM pg_event_trigger e "
8335 : : "ORDER BY e.oid");
8336 : :
4288 rhaas@postgresql.org 8337 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8338 : :
8339 : 155 : ntups = PQntuples(res);
8340 : :
8341 : 155 : *numEventTriggers = ntups;
8342 : :
8343 : 155 : evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
8344 : :
8345 : 155 : i_tableoid = PQfnumber(res, "tableoid");
8346 : 155 : i_oid = PQfnumber(res, "oid");
8347 : 155 : i_evtname = PQfnumber(res, "evtname");
8348 : 155 : i_evtevent = PQfnumber(res, "evtevent");
8349 : 155 : i_evtowner = PQfnumber(res, "evtowner");
8350 : 155 : i_evttags = PQfnumber(res, "evttags");
8351 : 155 : i_evtfname = PQfnumber(res, "evtfname");
8352 : 155 : i_evtenabled = PQfnumber(res, "evtenabled");
8353 : :
8354 [ + + ]: 206 : for (i = 0; i < ntups; i++)
8355 : : {
8356 : 51 : evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
8357 : 51 : evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8358 : 51 : evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8359 : 51 : AssignDumpId(&evtinfo[i].dobj);
8360 : 51 : evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
8361 : 51 : evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
8362 : 51 : evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
835 tgl@sss.pgh.pa.us 8363 : 51 : evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
4288 rhaas@postgresql.org 8364 : 51 : evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
8365 : 51 : evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
8366 : 51 : evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
8367 : :
8368 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 8369 : 51 : selectDumpableObject(&(evtinfo[i].dobj), fout);
8370 : : }
8371 : :
4288 rhaas@postgresql.org 8372 : 155 : PQclear(res);
8373 : :
8374 : 155 : destroyPQExpBuffer(query);
8375 : :
8376 : 155 : return evtinfo;
8377 : : }
8378 : :
8379 : : /*
8380 : : * getProcLangs
8381 : : * get basic information about every procedural language in the system
8382 : : *
8383 : : * numProcLangs is set to the number of langs read in
8384 : : *
8385 : : * NB: this must run after getFuncs() because we assume we can do
8386 : : * findFuncByOid().
8387 : : */
8388 : : ProcLangInfo *
4451 8389 : 155 : getProcLangs(Archive *fout, int *numProcLangs)
8390 : : {
8391 : : PGresult *res;
8392 : : int ntups;
8393 : : int i;
7435 tgl@sss.pgh.pa.us 8394 : 155 : PQExpBuffer query = createPQExpBuffer();
8395 : : ProcLangInfo *planginfo;
8396 : : int i_tableoid;
8397 : : int i_oid;
8398 : : int i_lanname;
8399 : : int i_lanpltrusted;
8400 : : int i_lanplcallfoid;
8401 : : int i_laninline;
8402 : : int i_lanvalidator;
8403 : : int i_lanacl;
8404 : : int i_acldefault;
8405 : : int i_lanowner;
8406 : :
586 drowley@postgresql.o 8407 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8408 : : "lanname, lanpltrusted, lanplcallfoid, "
8409 : : "laninline, lanvalidator, "
8410 : : "lanacl, "
8411 : : "acldefault('l', lanowner) AS acldefault, "
8412 : : "lanowner "
8413 : : "FROM pg_language "
8414 : : "WHERE lanispl "
8415 : : "ORDER BY oid");
8416 : :
4450 rhaas@postgresql.org 8417 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8418 : :
7435 tgl@sss.pgh.pa.us 8419 : 155 : ntups = PQntuples(res);
8420 : :
8421 : 155 : *numProcLangs = ntups;
8422 : :
4524 bruce@momjian.us 8423 : 155 : planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
8424 : :
7435 tgl@sss.pgh.pa.us 8425 : 155 : i_tableoid = PQfnumber(res, "tableoid");
8426 : 155 : i_oid = PQfnumber(res, "oid");
8427 : 155 : i_lanname = PQfnumber(res, "lanname");
8428 : 155 : i_lanpltrusted = PQfnumber(res, "lanpltrusted");
8429 : 155 : i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
5318 8430 : 155 : i_laninline = PQfnumber(res, "laninline");
6707 8431 : 155 : i_lanvalidator = PQfnumber(res, "lanvalidator");
8432 : 155 : i_lanacl = PQfnumber(res, "lanacl");
860 8433 : 155 : i_acldefault = PQfnumber(res, "acldefault");
6707 8434 : 155 : i_lanowner = PQfnumber(res, "lanowner");
8435 : :
7435 8436 [ + + ]: 356 : for (i = 0; i < ntups; i++)
8437 : : {
8438 : 201 : planginfo[i].dobj.objType = DO_PROCLANG;
8439 : 201 : planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8440 : 201 : planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8441 : 201 : AssignDumpId(&planginfo[i].dobj);
8442 : :
4524 bruce@momjian.us 8443 : 201 : planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
860 tgl@sss.pgh.pa.us 8444 : 201 : planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
8445 : 201 : planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
8446 : 201 : planginfo[i].dacl.privtype = 0;
8447 : 201 : planginfo[i].dacl.initprivs = NULL;
7435 8448 : 201 : planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
8449 : 201 : planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
3170 8450 : 201 : planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
8451 : 201 : planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
835 8452 : 201 : planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
8453 : :
8454 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 8455 : 201 : selectDumpableProcLang(&(planginfo[i]), fout);
8456 : :
8457 : : /* Mark whether language has an ACL */
860 tgl@sss.pgh.pa.us 8458 [ + + ]: 201 : if (!PQgetisnull(res, i, i_lanacl))
8459 : 46 : planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
8460 : : }
8461 : :
7435 8462 : 155 : PQclear(res);
8463 : :
8464 : 155 : destroyPQExpBuffer(query);
8465 : :
8466 : 155 : return planginfo;
8467 : : }
8468 : :
8469 : : /*
8470 : : * getCasts
8471 : : * get basic information about most casts in the system
8472 : : *
8473 : : * numCasts is set to the number of casts read in
8474 : : *
8475 : : * Skip casts from a range to its multirange, since we'll create those
8476 : : * automatically.
8477 : : */
8478 : : CastInfo *
3014 8479 : 155 : getCasts(Archive *fout, int *numCasts)
8480 : : {
8481 : : PGresult *res;
8482 : : int ntups;
8483 : : int i;
7435 8484 : 155 : PQExpBuffer query = createPQExpBuffer();
8485 : : CastInfo *castinfo;
8486 : : int i_tableoid;
8487 : : int i_oid;
8488 : : int i_castsource;
8489 : : int i_casttarget;
8490 : : int i_castfunc;
8491 : : int i_castcontext;
8492 : : int i_castmethod;
8493 : :
1211 akorotkov@postgresql 8494 [ + - ]: 155 : if (fout->remoteVersion >= 140000)
8495 : : {
8496 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8497 : : "castsource, casttarget, castfunc, castcontext, "
8498 : : "castmethod "
8499 : : "FROM pg_cast c "
8500 : : "WHERE NOT EXISTS ( "
8501 : : "SELECT 1 FROM pg_range r "
8502 : : "WHERE c.castsource = r.rngtypid "
8503 : : "AND c.casttarget = r.rngmultitypid "
8504 : : ") "
8505 : : "ORDER BY 3,4");
8506 : : }
8507 : : else
8508 : : {
3800 heikki.linnakangas@i 8509 :UBC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8510 : : "castsource, casttarget, castfunc, castcontext, "
8511 : : "castmethod "
8512 : : "FROM pg_cast ORDER BY 3,4");
8513 : : }
8514 : :
4450 rhaas@postgresql.org 8515 :CBC 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8516 : :
7435 tgl@sss.pgh.pa.us 8517 : 155 : ntups = PQntuples(res);
8518 : :
8519 : 155 : *numCasts = ntups;
8520 : :
4524 bruce@momjian.us 8521 : 155 : castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
8522 : :
7435 tgl@sss.pgh.pa.us 8523 : 155 : i_tableoid = PQfnumber(res, "tableoid");
8524 : 155 : i_oid = PQfnumber(res, "oid");
8525 : 155 : i_castsource = PQfnumber(res, "castsource");
8526 : 155 : i_casttarget = PQfnumber(res, "casttarget");
8527 : 155 : i_castfunc = PQfnumber(res, "castfunc");
8528 : 155 : i_castcontext = PQfnumber(res, "castcontext");
5644 heikki.linnakangas@i 8529 : 155 : i_castmethod = PQfnumber(res, "castmethod");
8530 : :
7435 tgl@sss.pgh.pa.us 8531 [ + + ]: 34796 : for (i = 0; i < ntups; i++)
8532 : : {
8533 : : PQExpBufferData namebuf;
8534 : : TypeInfo *sTypeInfo;
8535 : : TypeInfo *tTypeInfo;
8536 : :
8537 : 34641 : castinfo[i].dobj.objType = DO_CAST;
8538 : 34641 : castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8539 : 34641 : castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8540 : 34641 : AssignDumpId(&castinfo[i].dobj);
8541 : 34641 : castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
8542 : 34641 : castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
8543 : 34641 : castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
8544 : 34641 : castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
5644 heikki.linnakangas@i 8545 : 34641 : castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
8546 : :
8547 : : /*
8548 : : * Try to name cast as concatenation of typnames. This is only used
8549 : : * for purposes of sorting. If we fail to find either type, the name
8550 : : * will be an empty string.
8551 : : */
7347 tgl@sss.pgh.pa.us 8552 : 34641 : initPQExpBuffer(&namebuf);
8553 : 34641 : sTypeInfo = findTypeByOid(castinfo[i].castsource);
8554 : 34641 : tTypeInfo = findTypeByOid(castinfo[i].casttarget);
8555 [ + - + - ]: 34641 : if (sTypeInfo && tTypeInfo)
8556 : 34641 : appendPQExpBuffer(&namebuf, "%s %s",
8557 : : sTypeInfo->dobj.name, tTypeInfo->dobj.name);
8558 : 34641 : castinfo[i].dobj.name = namebuf.data;
8559 : :
8560 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 8561 : 34641 : selectDumpableCast(&(castinfo[i]), fout);
8562 : : }
8563 : :
7435 tgl@sss.pgh.pa.us 8564 : 155 : PQclear(res);
8565 : :
8566 : 155 : destroyPQExpBuffer(query);
8567 : :
8568 : 155 : return castinfo;
8569 : : }
8570 : :
8571 : : static char *
3276 peter_e@gmx.net 8572 : 91 : get_language_name(Archive *fout, Oid langid)
8573 : : {
8574 : : PQExpBuffer query;
8575 : : PGresult *res;
8576 : : char *lanname;
8577 : :
8578 : 91 : query = createPQExpBuffer();
8579 : 91 : appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
8580 : 91 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
8581 : 91 : lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
8582 : 91 : destroyPQExpBuffer(query);
8583 : 91 : PQclear(res);
8584 : :
8585 : 91 : return lanname;
8586 : : }
8587 : :
8588 : : /*
8589 : : * getTransforms
8590 : : * get basic information about every transform in the system
8591 : : *
8592 : : * numTransforms is set to the number of transforms read in
8593 : : */
8594 : : TransformInfo *
8595 : 155 : getTransforms(Archive *fout, int *numTransforms)
8596 : : {
8597 : : PGresult *res;
8598 : : int ntups;
8599 : : int i;
8600 : : PQExpBuffer query;
8601 : : TransformInfo *transforminfo;
8602 : : int i_tableoid;
8603 : : int i_oid;
8604 : : int i_trftype;
8605 : : int i_trflang;
8606 : : int i_trffromsql;
8607 : : int i_trftosql;
8608 : :
8609 : : /* Transforms didn't exist pre-9.5 */
8610 [ - + ]: 155 : if (fout->remoteVersion < 90500)
8611 : : {
3276 peter_e@gmx.net 8612 :UBC 0 : *numTransforms = 0;
8613 : 0 : return NULL;
8614 : : }
8615 : :
3265 magnus@hagander.net 8616 :CBC 155 : query = createPQExpBuffer();
8617 : :
1746 drowley@postgresql.o 8618 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8619 : : "trftype, trflang, trffromsql::oid, trftosql::oid "
8620 : : "FROM pg_transform "
8621 : : "ORDER BY 3,4");
8622 : :
3276 peter_e@gmx.net 8623 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8624 : :
8625 : 155 : ntups = PQntuples(res);
8626 : :
8627 : 155 : *numTransforms = ntups;
8628 : :
8629 : 155 : transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8630 : :
8631 : 155 : i_tableoid = PQfnumber(res, "tableoid");
8632 : 155 : i_oid = PQfnumber(res, "oid");
8633 : 155 : i_trftype = PQfnumber(res, "trftype");
8634 : 155 : i_trflang = PQfnumber(res, "trflang");
8635 : 155 : i_trffromsql = PQfnumber(res, "trffromsql");
8636 : 155 : i_trftosql = PQfnumber(res, "trftosql");
8637 : :
8638 [ + + ]: 206 : for (i = 0; i < ntups; i++)
8639 : : {
8640 : : PQExpBufferData namebuf;
8641 : : TypeInfo *typeInfo;
8642 : : char *lanname;
8643 : :
8644 : 51 : transforminfo[i].dobj.objType = DO_TRANSFORM;
8645 : 51 : transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8646 : 51 : transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8647 : 51 : AssignDumpId(&transforminfo[i].dobj);
8648 : 51 : transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8649 : 51 : transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8650 : 51 : transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8651 : 51 : transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8652 : :
8653 : : /*
8654 : : * Try to name transform as concatenation of type and language name.
8655 : : * This is only used for purposes of sorting. If we fail to find
8656 : : * either, the name will be an empty string.
8657 : : */
8658 : 51 : initPQExpBuffer(&namebuf);
8659 : 51 : typeInfo = findTypeByOid(transforminfo[i].trftype);
8660 : 51 : lanname = get_language_name(fout, transforminfo[i].trflang);
8661 [ + - + - ]: 51 : if (typeInfo && lanname)
8662 : 51 : appendPQExpBuffer(&namebuf, "%s %s",
8663 : : typeInfo->dobj.name, lanname);
8664 : 51 : transforminfo[i].dobj.name = namebuf.data;
3199 tgl@sss.pgh.pa.us 8665 : 51 : free(lanname);
8666 : :
8667 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 8668 : 51 : selectDumpableObject(&(transforminfo[i].dobj), fout);
8669 : : }
8670 : :
3276 peter_e@gmx.net 8671 : 155 : PQclear(res);
8672 : :
8673 : 155 : destroyPQExpBuffer(query);
8674 : :
8675 : 155 : return transforminfo;
8676 : : }
8677 : :
8678 : : /*
8679 : : * getTableAttrs -
8680 : : * for each interesting table, read info about its attributes
8681 : : * (names, types, default values, CHECK constraints, etc)
8682 : : *
8683 : : * modifies tblinfo
8684 : : */
8685 : : void
3014 tgl@sss.pgh.pa.us 8686 : 155 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8687 : : {
8688 : 155 : DumpOptions *dopt = fout->dopt;
7435 8689 : 155 : PQExpBuffer q = createPQExpBuffer();
860 8690 : 155 : PQExpBuffer tbloids = createPQExpBuffer();
8691 : 155 : PQExpBuffer checkoids = createPQExpBuffer();
8692 : : PGresult *res;
8693 : : int ntups;
8694 : : int curtblindx;
8695 : : int i_attrelid;
8696 : : int i_attnum;
8697 : : int i_attname;
8698 : : int i_atttypname;
8699 : : int i_attstattarget;
8700 : : int i_attstorage;
8701 : : int i_typstorage;
8702 : : int i_attidentity;
8703 : : int i_attgenerated;
8704 : : int i_attisdropped;
8705 : : int i_attlen;
8706 : : int i_attalign;
8707 : : int i_attislocal;
8708 : : int i_notnull_name;
8709 : : int i_notnull_noinherit;
8710 : : int i_notnull_is_pk;
8711 : : int i_notnull_inh;
8712 : : int i_attoptions;
8713 : : int i_attcollation;
8714 : : int i_attcompression;
8715 : : int i_attfdwoptions;
8716 : : int i_attmissingval;
8717 : : int i_atthasdef;
8718 : :
8719 : : /*
8720 : : * We want to perform just one query against pg_attribute, and then just
8721 : : * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
8722 : : * (for CHECK constraints and for NOT NULL constraints). However, we
8723 : : * mustn't try to select every row of those catalogs and then sort it out
8724 : : * on the client side, because some of the server-side functions we need
8725 : : * would be unsafe to apply to tables we don't have lock on. Hence, we
8726 : : * build an array of the OIDs of tables we care about (and now have lock
8727 : : * on!), and use a WHERE clause to constrain which rows are selected.
8728 : : */
8729 : 155 : appendPQExpBufferChar(tbloids, '{');
8730 : 155 : appendPQExpBufferChar(checkoids, '{');
1375 peter@eisentraut.org 8731 [ + + ]: 39419 : for (int i = 0; i < numTables; i++)
8732 : : {
7893 bruce@momjian.us 8733 : 39264 : TableInfo *tbinfo = &tblinfo[i];
8734 : :
8735 : : /* Don't bother to collect info for sequences */
7909 tgl@sss.pgh.pa.us 8736 [ + + ]: 39264 : if (tbinfo->relkind == RELKIND_SEQUENCE)
9716 bruce@momjian.us 8737 : 515 : continue;
8738 : :
8739 : : /* Don't bother with uninteresting tables, either */
7909 tgl@sss.pgh.pa.us 8740 [ + + ]: 38749 : if (!tbinfo->interesting)
8010 8741 : 33168 : continue;
8742 : :
8743 : : /* OK, we need info for this table */
860 8744 [ + + ]: 5581 : if (tbloids->len > 1) /* do we have more than the '{'? */
8745 : 5478 : appendPQExpBufferChar(tbloids, ',');
8746 : 5581 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8747 : :
8748 [ + + ]: 5581 : if (tbinfo->ncheck > 0)
8749 : : {
8750 : : /* Also make a list of the ones with check constraints */
8751 [ + + ]: 466 : if (checkoids->len > 1) /* do we have more than the '{'? */
8752 : 397 : appendPQExpBufferChar(checkoids, ',');
8753 : 466 : appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
8754 : : }
8755 : : }
8756 : 155 : appendPQExpBufferChar(tbloids, '}');
8757 : 155 : appendPQExpBufferChar(checkoids, '}');
8758 : :
8759 : : /*
8760 : : * Find all the user attributes and their types.
8761 : : *
8762 : : * Since we only want to dump COLLATE clauses for attributes whose
8763 : : * collation is different from their type's default, we use a CASE here to
8764 : : * suppress uninteresting attcollations cheaply.
8765 : : */
8766 : 155 : appendPQExpBufferStr(q,
8767 : : "SELECT\n"
8768 : : "a.attrelid,\n"
8769 : : "a.attnum,\n"
8770 : : "a.attname,\n"
8771 : : "a.attstattarget,\n"
8772 : : "a.attstorage,\n"
8773 : : "t.typstorage,\n"
8774 : : "a.atthasdef,\n"
8775 : : "a.attisdropped,\n"
8776 : : "a.attlen,\n"
8777 : : "a.attalign,\n"
8778 : : "a.attislocal,\n"
8779 : : "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
8780 : : "array_to_string(a.attoptions, ', ') AS attoptions,\n"
8781 : : "CASE WHEN a.attcollation <> t.typcollation "
8782 : : "THEN a.attcollation ELSE 0 END AS attcollation,\n"
8783 : : "pg_catalog.array_to_string(ARRAY("
8784 : : "SELECT pg_catalog.quote_ident(option_name) || "
8785 : : "' ' || pg_catalog.quote_literal(option_value) "
8786 : : "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8787 : : "ORDER BY option_name"
8788 : : "), E',\n ') AS attfdwoptions,\n");
8789 : :
8790 : : /*
8791 : : * Find out any NOT NULL markings for each column. In 17 and up we have
8792 : : * to read pg_constraint, and keep track whether it's NO INHERIT; in older
8793 : : * versions we rely on pg_attribute.attnotnull.
8794 : : *
8795 : : * We also track whether the constraint was defined directly in this table
8796 : : * or via an ancestor, for binary upgrade.
8797 : : *
8798 : : * Lastly, we need to know if the PK for the table involves each column;
8799 : : * for columns that are there we need a NOT NULL marking even if there's
8800 : : * no explicit constraint, to avoid the table having to be scanned for
8801 : : * NULLs after the data is loaded when the PK is created, later in the
8802 : : * dump; for this case we add throwaway constraints that are dropped once
8803 : : * the PK is created.
8804 : : */
233 alvherre@alvh.no-ip. 8805 [ + - ]:GNC 155 : if (fout->remoteVersion >= 170000)
8806 : 155 : appendPQExpBufferStr(q,
8807 : : "co.conname AS notnull_name,\n"
8808 : : "co.connoinherit AS notnull_noinherit,\n"
8809 : : "copk.conname IS NOT NULL as notnull_is_pk,\n"
8810 : : "coalesce(NOT co.conislocal, true) AS notnull_inh,\n");
8811 : : else
233 alvherre@alvh.no-ip. 8812 :UNC 0 : appendPQExpBufferStr(q,
8813 : : "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
8814 : : "false AS notnull_noinherit,\n"
8815 : : "copk.conname IS NOT NULL AS notnull_is_pk,\n"
8816 : : "NOT a.attislocal AS notnull_inh,\n");
8817 : :
860 tgl@sss.pgh.pa.us 8818 [ + - ]:CBC 155 : if (fout->remoteVersion >= 140000)
8819 : 155 : appendPQExpBufferStr(q,
8820 : : "a.attcompression AS attcompression,\n");
8821 : : else
860 tgl@sss.pgh.pa.us 8822 :UBC 0 : appendPQExpBufferStr(q,
8823 : : "'' AS attcompression,\n");
8824 : :
860 tgl@sss.pgh.pa.us 8825 [ + - ]:CBC 155 : if (fout->remoteVersion >= 100000)
8826 : 155 : appendPQExpBufferStr(q,
8827 : : "a.attidentity,\n");
8828 : : else
860 tgl@sss.pgh.pa.us 8829 :UBC 0 : appendPQExpBufferStr(q,
8830 : : "'' AS attidentity,\n");
8831 : :
860 tgl@sss.pgh.pa.us 8832 [ + - ]:CBC 155 : if (fout->remoteVersion >= 110000)
8833 : 155 : appendPQExpBufferStr(q,
8834 : : "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8835 : : "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8836 : : else
860 tgl@sss.pgh.pa.us 8837 :UBC 0 : appendPQExpBufferStr(q,
8838 : : "NULL AS attmissingval,\n");
8839 : :
860 tgl@sss.pgh.pa.us 8840 [ + - ]:CBC 155 : if (fout->remoteVersion >= 120000)
8841 : 155 : appendPQExpBufferStr(q,
8842 : : "a.attgenerated\n");
8843 : : else
860 tgl@sss.pgh.pa.us 8844 :UBC 0 : appendPQExpBufferStr(q,
8845 : : "'' AS attgenerated\n");
8846 : :
8847 : : /* need left join to pg_type to not fail on dropped columns ... */
860 tgl@sss.pgh.pa.us 8848 :CBC 155 : appendPQExpBuffer(q,
8849 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8850 : : "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
8851 : : "LEFT JOIN pg_catalog.pg_type t "
8852 : : "ON (a.atttypid = t.oid)\n",
8853 : : tbloids->data);
8854 : :
8855 : : /*
8856 : : * In versions 16 and up, we need pg_constraint for explicit NOT NULL
8857 : : * entries. Also, we need to know if the NOT NULL for each column is
8858 : : * backing a primary key.
8859 : : */
233 alvherre@alvh.no-ip. 8860 [ + - ]:GNC 155 : if (fout->remoteVersion >= 170000)
8861 : 155 : appendPQExpBufferStr(q,
8862 : : " LEFT JOIN pg_catalog.pg_constraint co ON "
8863 : : "(a.attrelid = co.conrelid\n"
8864 : : " AND co.contype = 'n' AND "
8865 : : "co.conkey = array[a.attnum])\n");
8866 : :
8867 : 155 : appendPQExpBufferStr(q,
8868 : : "LEFT JOIN pg_catalog.pg_constraint copk ON "
8869 : : "(copk.conrelid = src.tbloid\n"
8870 : : " AND copk.contype = 'p' AND "
8871 : : "copk.conkey @> array[a.attnum])\n"
8872 : : "WHERE a.attnum > 0::pg_catalog.int2\n"
8873 : : "ORDER BY a.attrelid, a.attnum");
8874 : :
860 tgl@sss.pgh.pa.us 8875 :CBC 155 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8876 : :
8877 : 155 : ntups = PQntuples(res);
8878 : :
8879 : 155 : i_attrelid = PQfnumber(res, "attrelid");
8880 : 155 : i_attnum = PQfnumber(res, "attnum");
8881 : 155 : i_attname = PQfnumber(res, "attname");
8882 : 155 : i_atttypname = PQfnumber(res, "atttypname");
8883 : 155 : i_attstattarget = PQfnumber(res, "attstattarget");
8884 : 155 : i_attstorage = PQfnumber(res, "attstorage");
8885 : 155 : i_typstorage = PQfnumber(res, "typstorage");
8886 : 155 : i_attidentity = PQfnumber(res, "attidentity");
8887 : 155 : i_attgenerated = PQfnumber(res, "attgenerated");
8888 : 155 : i_attisdropped = PQfnumber(res, "attisdropped");
8889 : 155 : i_attlen = PQfnumber(res, "attlen");
8890 : 155 : i_attalign = PQfnumber(res, "attalign");
8891 : 155 : i_attislocal = PQfnumber(res, "attislocal");
233 alvherre@alvh.no-ip. 8892 :GNC 155 : i_notnull_name = PQfnumber(res, "notnull_name");
8893 : 155 : i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
8894 : 155 : i_notnull_is_pk = PQfnumber(res, "notnull_is_pk");
8895 : 155 : i_notnull_inh = PQfnumber(res, "notnull_inh");
860 tgl@sss.pgh.pa.us 8896 :CBC 155 : i_attoptions = PQfnumber(res, "attoptions");
8897 : 155 : i_attcollation = PQfnumber(res, "attcollation");
8898 : 155 : i_attcompression = PQfnumber(res, "attcompression");
8899 : 155 : i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8900 : 155 : i_attmissingval = PQfnumber(res, "attmissingval");
8901 : 155 : i_atthasdef = PQfnumber(res, "atthasdef");
8902 : :
8903 : : /* Within the next loop, we'll accumulate OIDs of tables with defaults */
368 alvherre@alvh.no-ip. 8904 : 155 : resetPQExpBuffer(tbloids);
8905 : 155 : appendPQExpBufferChar(tbloids, '{');
8906 : :
8907 : : /*
8908 : : * Outer loop iterates once per table, not once per row. Incrementing of
8909 : : * r is handled by the inner loop.
8910 : : */
860 tgl@sss.pgh.pa.us 8911 : 155 : curtblindx = -1;
8912 [ + + ]: 5600 : for (int r = 0; r < ntups;)
8913 : : {
8914 : 5445 : Oid attrelid = atooid(PQgetvalue(res, r, i_attrelid));
8915 : 5445 : TableInfo *tbinfo = NULL;
8916 : : int numatts;
8917 : : bool hasdefaults;
8918 : : int notnullcount;
8919 : :
8920 : : /* Count rows for this table */
8921 [ + + ]: 19859 : for (numatts = 1; numatts < ntups - r; numatts++)
8922 [ + + ]: 19759 : if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
8923 : 5345 : break;
8924 : :
8925 : : /*
8926 : : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8927 : : * order.
8928 : : */
8929 [ + - ]: 27372 : while (++curtblindx < numTables)
8930 : : {
8931 : 27372 : tbinfo = &tblinfo[curtblindx];
8932 [ + + ]: 27372 : if (tbinfo->dobj.catId.oid == attrelid)
8933 : 5445 : break;
8934 : : }
8935 [ - + ]: 5445 : if (curtblindx >= numTables)
737 tgl@sss.pgh.pa.us 8936 :UBC 0 : pg_fatal("unrecognized table OID %u", attrelid);
8937 : : /* cross-check that we only got requested tables */
860 tgl@sss.pgh.pa.us 8938 [ + - ]:CBC 5445 : if (tbinfo->relkind == RELKIND_SEQUENCE ||
8939 [ - + ]: 5445 : !tbinfo->interesting)
737 tgl@sss.pgh.pa.us 8940 :UBC 0 : pg_fatal("unexpected column data for table \"%s\"",
8941 : : tbinfo->dobj.name);
8942 : :
233 alvherre@alvh.no-ip. 8943 :GNC 5445 : notnullcount = 0;
8944 : :
8945 : : /* Save data for this table */
860 tgl@sss.pgh.pa.us 8946 :CBC 5445 : tbinfo->numatts = numatts;
8947 : 5445 : tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
8948 : 5445 : tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
8949 : 5445 : tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
8950 : 5445 : tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
8951 : 5445 : tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
8952 : 5445 : tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
8953 : 5445 : tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
8954 : 5445 : tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
8955 : 5445 : tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
8956 : 5445 : tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
8957 : 5445 : tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
8958 : 5445 : tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
8959 : 5445 : tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
8960 : 5445 : tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
8961 : 5445 : tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
8962 : 5445 : tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
233 alvherre@alvh.no-ip. 8963 :GNC 5445 : tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
8964 : 5445 : tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
8965 : 5445 : tbinfo->notnull_throwaway = (bool *) pg_malloc(numatts * sizeof(bool));
8966 : 5445 : tbinfo->notnull_inh = (bool *) pg_malloc(numatts * sizeof(bool));
860 tgl@sss.pgh.pa.us 8967 :CBC 5445 : tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
8010 8968 : 5445 : hasdefaults = false;
8969 : :
860 8970 [ + + ]: 25304 : for (int j = 0; j < numatts; j++, r++)
8971 : : {
233 alvherre@alvh.no-ip. 8972 :GNC 19859 : bool use_named_notnull = false;
8973 : 19859 : bool use_unnamed_notnull = false;
8974 : 19859 : bool use_throwaway_notnull = false;
8975 : :
860 tgl@sss.pgh.pa.us 8976 [ - + ]:CBC 19859 : if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
737 tgl@sss.pgh.pa.us 8977 :UBC 0 : pg_fatal("invalid column numbering in table \"%s\"",
8978 : : tbinfo->dobj.name);
860 tgl@sss.pgh.pa.us 8979 :CBC 19859 : tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
8980 : 19859 : tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
92 peter@eisentraut.org 8981 [ + + ]:GNC 19859 : if (PQgetisnull(res, r, i_attstattarget))
8982 : 19819 : tbinfo->attstattarget[j] = -1;
8983 : : else
8984 : 40 : tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
860 tgl@sss.pgh.pa.us 8985 :CBC 19859 : tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
8986 : 19859 : tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
8987 : 19859 : tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
8988 : 19859 : tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
2565 peter_e@gmx.net 8989 [ + + + + ]: 19859 : tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
860 tgl@sss.pgh.pa.us 8990 : 19859 : tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
8991 : 19859 : tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
8992 : 19859 : tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
8993 : 19859 : tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
8994 : :
8995 : : /*
8996 : : * Not-null constraints require a jumping through a few hoops.
8997 : : * First, if the user has specified a constraint name that's not
8998 : : * the system-assigned default name, then we need to preserve
8999 : : * that. But if they haven't, then we don't want to use the
9000 : : * verbose syntax in the dump output. (Also, in versions prior to
9001 : : * 17, there was no constraint name at all.)
9002 : : *
9003 : : * (XXX Comparing the name this way to a supposed default name is
9004 : : * a bit of a hack, but it beats having to store a boolean flag in
9005 : : * pg_constraint just for this, or having to compute the knowledge
9006 : : * at pg_dump time from the server.)
9007 : : *
9008 : : * We also need to know if a column is part of the primary key. In
9009 : : * that case, we want to mark the column as not-null at table
9010 : : * creation time, so that the table doesn't have to be scanned to
9011 : : * check for nulls when the PK is created afterwards; this is
9012 : : * especially critical during pg_upgrade (where the data would not
9013 : : * be scanned at all otherwise.) If the column is part of the PK
9014 : : * and does not have any other not-null constraint, then we
9015 : : * fabricate a throwaway constraint name that we later use to
9016 : : * remove the constraint after the PK has been created.
9017 : : *
9018 : : * For inheritance child tables, we don't want to print not-null
9019 : : * when the constraint was defined at the parent level instead of
9020 : : * locally.
9021 : : */
9022 : :
9023 : : /*
9024 : : * We use notnull_inh to suppress unwanted not-null constraints in
9025 : : * inheritance children, when said constraints come from the
9026 : : * parent(s).
9027 : : */
233 alvherre@alvh.no-ip. 9028 :GNC 19859 : tbinfo->notnull_inh[j] = PQgetvalue(res, r, i_notnull_inh)[0] == 't';
9029 : :
9030 [ - + ]: 19859 : if (fout->remoteVersion < 170000)
9031 : : {
233 alvherre@alvh.no-ip. 9032 [ # # ]:UNC 0 : if (!PQgetisnull(res, r, i_notnull_name) &&
9033 [ # # ]: 0 : dopt->binary_upgrade &&
9034 [ # # ]: 0 : !tbinfo->ispartition &&
9035 [ # # ]: 0 : tbinfo->notnull_inh[j])
9036 : : {
9037 : 0 : use_named_notnull = true;
9038 : : /* XXX should match ChooseConstraintName better */
9039 : 0 : tbinfo->notnull_constrs[j] =
9040 : 0 : psprintf("%s_%s_not_null", tbinfo->dobj.name,
9041 : 0 : tbinfo->attnames[j]);
9042 : : }
9043 [ # # ]: 0 : else if (PQgetvalue(res, r, i_notnull_is_pk)[0] == 't')
9044 : 0 : use_throwaway_notnull = true;
9045 [ # # ]: 0 : else if (!PQgetisnull(res, r, i_notnull_name))
9046 : 0 : use_unnamed_notnull = true;
9047 : : }
9048 : : else
9049 : : {
233 alvherre@alvh.no-ip. 9050 [ + + ]:GNC 19859 : if (!PQgetisnull(res, r, i_notnull_name))
9051 : : {
9052 : : /*
9053 : : * In binary upgrade of inheritance child tables, must
9054 : : * have a constraint name that we can UPDATE later.
9055 : : */
9056 [ + + ]: 1211 : if (dopt->binary_upgrade &&
9057 [ + + ]: 132 : !tbinfo->ispartition &&
9058 [ + + ]: 87 : tbinfo->notnull_inh[j])
9059 : : {
9060 : 16 : use_named_notnull = true;
9061 : 16 : tbinfo->notnull_constrs[j] =
9062 : 16 : pstrdup(PQgetvalue(res, r, i_notnull_name));
9063 : :
9064 : : }
9065 : : else
9066 : : {
9067 : : char *default_name;
9068 : :
9069 : : /* XXX should match ChooseConstraintName better */
9070 : 1195 : default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
9071 : 1195 : tbinfo->attnames[j]);
9072 [ + + ]: 1195 : if (strcmp(default_name,
9073 : 1195 : PQgetvalue(res, r, i_notnull_name)) == 0)
9074 : 746 : use_unnamed_notnull = true;
9075 : : else
9076 : : {
9077 : 449 : use_named_notnull = true;
9078 : 449 : tbinfo->notnull_constrs[j] =
9079 : 449 : pstrdup(PQgetvalue(res, r, i_notnull_name));
9080 : : }
9081 : : }
9082 : : }
9083 [ + + ]: 18648 : else if (PQgetvalue(res, r, i_notnull_is_pk)[0] == 't')
9084 : 819 : use_throwaway_notnull = true;
9085 : : }
9086 : :
9087 [ + + ]: 19859 : if (use_unnamed_notnull)
9088 : : {
9089 : 746 : tbinfo->notnull_constrs[j] = "";
9090 : 746 : tbinfo->notnull_throwaway[j] = false;
9091 : : }
9092 [ + + ]: 19113 : else if (use_named_notnull)
9093 : : {
9094 : : /* The name itself has already been determined */
9095 : 465 : tbinfo->notnull_throwaway[j] = false;
9096 : : }
9097 [ + + ]: 18648 : else if (use_throwaway_notnull)
9098 : : {
9099 : 1638 : tbinfo->notnull_constrs[j] =
9100 : 819 : psprintf("pgdump_throwaway_notnull_%d", notnullcount++);
9101 : 819 : tbinfo->notnull_throwaway[j] = true;
9102 : 819 : tbinfo->notnull_inh[j] = false;
9103 : : }
9104 : : else
9105 : : {
9106 : 17829 : tbinfo->notnull_constrs[j] = NULL;
9107 : 17829 : tbinfo->notnull_throwaway[j] = false;
9108 : : }
9109 : :
9110 : : /*
9111 : : * Throwaway constraints must always be NO INHERIT; otherwise do
9112 : : * what the catalog says.
9113 : : */
9114 [ + + ]: 38899 : tbinfo->notnull_noinh[j] = use_throwaway_notnull ||
9115 [ + + ]: 19040 : PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
9116 : :
860 tgl@sss.pgh.pa.us 9117 :CBC 19859 : tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
9118 : 19859 : tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
9119 : 19859 : tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
9120 : 19859 : tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
9121 : 19859 : tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
7168 bruce@momjian.us 9122 : 19859 : tbinfo->attrdefs[j] = NULL; /* fix below */
860 tgl@sss.pgh.pa.us 9123 [ + + ]: 19859 : if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
8010 9124 : 907 : hasdefaults = true;
9125 : : }
9126 : :
860 9127 [ + + ]: 5445 : if (hasdefaults)
9128 : : {
9129 : : /* Collect OIDs of interesting tables that have defaults */
368 alvherre@alvh.no-ip. 9130 [ + + ]: 753 : if (tbloids->len > 1) /* do we have more than the '{'? */
9131 : 702 : appendPQExpBufferChar(tbloids, ',');
9132 : 753 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
9133 : : }
9134 : : }
9135 : :
860 tgl@sss.pgh.pa.us 9136 : 155 : PQclear(res);
9137 : :
9138 : : /*
9139 : : * Now get info about column defaults. This is skipped for a data-only
9140 : : * dump, as it is only needed for table schemas.
9141 : : */
368 alvherre@alvh.no-ip. 9142 [ + + + + ]: 155 : if (!dopt->dataOnly && tbloids->len > 1)
9143 : : {
9144 : : AttrDefInfo *attrdefs;
9145 : : int numDefaults;
860 tgl@sss.pgh.pa.us 9146 : 47 : TableInfo *tbinfo = NULL;
9147 : :
9148 : 47 : pg_log_info("finding table default expressions");
9149 : :
368 alvherre@alvh.no-ip. 9150 : 47 : appendPQExpBufferChar(tbloids, '}');
9151 : :
860 tgl@sss.pgh.pa.us 9152 : 47 : printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
9153 : : "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
9154 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9155 : : "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
9156 : : "ORDER BY a.adrelid, a.adnum",
9157 : : tbloids->data);
9158 : :
9159 : 47 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9160 : :
9161 : 47 : numDefaults = PQntuples(res);
9162 : 47 : attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
9163 : :
9164 : 47 : curtblindx = -1;
9165 [ + + ]: 914 : for (int j = 0; j < numDefaults; j++)
9166 : : {
9167 : 867 : Oid adtableoid = atooid(PQgetvalue(res, j, 0));
9168 : 867 : Oid adoid = atooid(PQgetvalue(res, j, 1));
9169 : 867 : Oid adrelid = atooid(PQgetvalue(res, j, 2));
9170 : 867 : int adnum = atoi(PQgetvalue(res, j, 3));
9171 : 867 : char *adsrc = PQgetvalue(res, j, 4);
9172 : :
9173 : : /*
9174 : : * Locate the associated TableInfo; we rely on tblinfo[] being in
9175 : : * OID order.
9176 : : */
9177 [ + + + + ]: 867 : if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
9178 : : {
9179 [ + - ]: 15529 : while (++curtblindx < numTables)
9180 : : {
9181 : 15529 : tbinfo = &tblinfo[curtblindx];
9182 [ + + ]: 15529 : if (tbinfo->dobj.catId.oid == adrelid)
9183 : 719 : break;
9184 : : }
9185 [ - + ]: 719 : if (curtblindx >= numTables)
737 tgl@sss.pgh.pa.us 9186 :UBC 0 : pg_fatal("unrecognized table OID %u", adrelid);
9187 : : }
9188 : :
860 tgl@sss.pgh.pa.us 9189 [ + - - + ]:CBC 867 : if (adnum <= 0 || adnum > tbinfo->numatts)
737 tgl@sss.pgh.pa.us 9190 :UBC 0 : pg_fatal("invalid adnum value %d for table \"%s\"",
9191 : : adnum, tbinfo->dobj.name);
9192 : :
9193 : : /*
9194 : : * dropped columns shouldn't have defaults, but just in case,
9195 : : * ignore 'em
9196 : : */
860 tgl@sss.pgh.pa.us 9197 [ - + ]:CBC 867 : if (tbinfo->attisdropped[adnum - 1])
860 tgl@sss.pgh.pa.us 9198 :UBC 0 : continue;
9199 : :
860 tgl@sss.pgh.pa.us 9200 :CBC 867 : attrdefs[j].dobj.objType = DO_ATTRDEF;
9201 : 867 : attrdefs[j].dobj.catId.tableoid = adtableoid;
9202 : 867 : attrdefs[j].dobj.catId.oid = adoid;
9203 : 867 : AssignDumpId(&attrdefs[j].dobj);
9204 : 867 : attrdefs[j].adtable = tbinfo;
9205 : 867 : attrdefs[j].adnum = adnum;
9206 : 867 : attrdefs[j].adef_expr = pg_strdup(adsrc);
9207 : :
9208 : 867 : attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
9209 : 867 : attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
9210 : :
9211 : 867 : attrdefs[j].dobj.dump = tbinfo->dobj.dump;
9212 : :
9213 : : /*
9214 : : * Figure out whether the default/generation expression should be
9215 : : * dumped as part of the main CREATE TABLE (or similar) command or
9216 : : * as a separate ALTER TABLE (or similar) command. The preference
9217 : : * is to put it into the CREATE command, but in some cases that's
9218 : : * not possible.
9219 : : */
9220 [ + + ]: 867 : if (tbinfo->attgenerated[adnum - 1])
9221 : : {
9222 : : /*
9223 : : * Column generation expressions cannot be dumped separately,
9224 : : * because there is no syntax for it. By setting separate to
9225 : : * false here we prevent the "default" from being processed as
9226 : : * its own dumpable object. Later, flagInhAttrs() will mark
9227 : : * it as not to be dumped at all, if possible (that is, if it
9228 : : * can be inherited from a parent).
9229 : : */
9230 : 360 : attrdefs[j].separate = false;
9231 : : }
9232 [ + + ]: 507 : else if (tbinfo->relkind == RELKIND_VIEW)
9233 : : {
9234 : : /*
9235 : : * Defaults on a VIEW must always be dumped as separate ALTER
9236 : : * TABLE commands.
9237 : : */
9238 : 36 : attrdefs[j].separate = true;
9239 : : }
9240 [ + + ]: 471 : else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
9241 : : {
9242 : : /* column will be suppressed, print default separately */
9243 : 4 : attrdefs[j].separate = true;
9244 : : }
9245 : : else
9246 : : {
9247 : 467 : attrdefs[j].separate = false;
9248 : : }
9249 : :
9250 [ + + ]: 867 : if (!attrdefs[j].separate)
9251 : : {
9252 : : /*
9253 : : * Mark the default as needing to appear before the table, so
9254 : : * that any dependencies it has must be emitted before the
9255 : : * CREATE TABLE. If this is not possible, we'll change to
9256 : : * "separate" mode while sorting dependencies.
9257 : : */
9258 : 827 : addObjectDependency(&tbinfo->dobj,
9259 : 827 : attrdefs[j].dobj.dumpId);
9260 : : }
9261 : :
9262 : 867 : tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
9263 : : }
9264 : :
9265 : 47 : PQclear(res);
9266 : : }
9267 : :
9268 : : /*
9269 : : * Get info about table CHECK constraints. This is skipped for a
9270 : : * data-only dump, as it is only needed for table schemas.
9271 : : */
9272 [ + + + + ]: 155 : if (!dopt->dataOnly && checkoids->len > 2)
9273 : : {
9274 : : ConstraintInfo *constrs;
9275 : : int numConstrs;
9276 : : int i_tableoid;
9277 : : int i_oid;
9278 : : int i_conrelid;
9279 : : int i_conname;
9280 : : int i_consrc;
9281 : : int i_conislocal;
9282 : : int i_convalidated;
9283 : :
9284 : 64 : pg_log_info("finding table check constraints");
9285 : :
9286 : 64 : resetPQExpBuffer(q);
9287 : 64 : appendPQExpBuffer(q,
9288 : : "SELECT c.tableoid, c.oid, conrelid, conname, "
9289 : : "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9290 : : "conislocal, convalidated "
9291 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9292 : : "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
9293 : : "WHERE contype = 'c' "
9294 : : "ORDER BY c.conrelid, c.conname",
9295 : : checkoids->data);
9296 : :
9297 : 64 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9298 : :
9299 : 64 : numConstrs = PQntuples(res);
9300 : 64 : constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
9301 : :
9302 : 64 : i_tableoid = PQfnumber(res, "tableoid");
9303 : 64 : i_oid = PQfnumber(res, "oid");
9304 : 64 : i_conrelid = PQfnumber(res, "conrelid");
9305 : 64 : i_conname = PQfnumber(res, "conname");
9306 : 64 : i_consrc = PQfnumber(res, "consrc");
9307 : 64 : i_conislocal = PQfnumber(res, "conislocal");
9308 : 64 : i_convalidated = PQfnumber(res, "convalidated");
9309 : :
9310 : : /* As above, this loop iterates once per table, not once per row */
9311 : 64 : curtblindx = -1;
9312 [ + + ]: 504 : for (int j = 0; j < numConstrs;)
9313 : : {
9314 : 440 : Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9315 : 440 : TableInfo *tbinfo = NULL;
9316 : : int numcons;
9317 : :
9318 : : /* Count rows for this table */
9319 [ + + ]: 578 : for (numcons = 1; numcons < numConstrs - j; numcons++)
9320 [ + + ]: 514 : if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9321 : 376 : break;
9322 : :
9323 : : /*
9324 : : * Locate the associated TableInfo; we rely on tblinfo[] being in
9325 : : * OID order.
9326 : : */
9327 [ + - ]: 18295 : while (++curtblindx < numTables)
9328 : : {
9329 : 18295 : tbinfo = &tblinfo[curtblindx];
9330 [ + + ]: 18295 : if (tbinfo->dobj.catId.oid == conrelid)
9331 : 440 : break;
9332 : : }
9333 [ - + ]: 440 : if (curtblindx >= numTables)
737 tgl@sss.pgh.pa.us 9334 :UBC 0 : pg_fatal("unrecognized table OID %u", conrelid);
9335 : :
860 tgl@sss.pgh.pa.us 9336 [ - + ]:CBC 440 : if (numcons != tbinfo->ncheck)
9337 : : {
1840 peter@eisentraut.org 9338 :UBC 0 : pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
9339 : : "expected %d check constraints on table \"%s\" but found %d",
9340 : : tbinfo->ncheck),
9341 : : tbinfo->ncheck, tbinfo->dobj.name, numcons);
737 tgl@sss.pgh.pa.us 9342 : 0 : pg_log_error_hint("The system catalogs might be corrupted.");
4441 rhaas@postgresql.org 9343 : 0 : exit_nicely(1);
9344 : : }
9345 : :
860 tgl@sss.pgh.pa.us 9346 :CBC 440 : tbinfo->checkexprs = constrs + j;
9347 : :
9348 [ + + ]: 1018 : for (int c = 0; c < numcons; c++, j++)
9349 : : {
9350 : 578 : bool validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
9351 : :
7435 9352 : 578 : constrs[j].dobj.objType = DO_CONSTRAINT;
860 9353 : 578 : constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9354 : 578 : constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7435 9355 : 578 : AssignDumpId(&constrs[j].dobj);
860 9356 : 578 : constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7347 9357 : 578 : constrs[j].dobj.namespace = tbinfo->dobj.namespace;
7435 9358 : 578 : constrs[j].contable = tbinfo;
9359 : 578 : constrs[j].condomain = NULL;
9360 : 578 : constrs[j].contype = 'c';
860 9361 : 578 : constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
5697 9362 : 578 : constrs[j].confrelid = InvalidOid;
7435 9363 : 578 : constrs[j].conindex = 0;
5373 9364 : 578 : constrs[j].condeferrable = false;
9365 : 578 : constrs[j].condeferred = false;
860 9366 : 578 : constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9367 : :
9368 : : /*
9369 : : * An unvalidated constraint needs to be dumped separately, so
9370 : : * that potentially-violating existing data is loaded before
9371 : : * the constraint.
9372 : : */
4377 alvherre@alvh.no-ip. 9373 : 578 : constrs[j].separate = !validated;
9374 : :
6618 tgl@sss.pgh.pa.us 9375 : 578 : constrs[j].dobj.dump = tbinfo->dobj.dump;
9376 : :
9377 : : /*
9378 : : * Mark the constraint as needing to appear before the table
9379 : : * --- this is so that any other dependencies of the
9380 : : * constraint will be emitted before we try to create the
9381 : : * table. If the constraint is to be dumped separately, it
9382 : : * will be dumped after data is loaded anyway, so don't do it.
9383 : : * (There's an automatic dependency in the opposite direction
9384 : : * anyway, so don't need to add one manually here.)
9385 : : */
4514 alvherre@alvh.no-ip. 9386 [ + + ]: 578 : if (!constrs[j].separate)
4525 9387 : 543 : addObjectDependency(&tbinfo->dobj,
9388 : 543 : constrs[j].dobj.dumpId);
9389 : :
9390 : : /*
9391 : : * We will detect later whether the constraint must be split
9392 : : * out from the table definition.
9393 : : */
9394 : : }
9395 : : }
9396 : :
860 tgl@sss.pgh.pa.us 9397 : 64 : PQclear(res);
9398 : : }
9399 : :
8290 9400 : 155 : destroyPQExpBuffer(q);
860 9401 : 155 : destroyPQExpBuffer(tbloids);
9402 : 155 : destroyPQExpBuffer(checkoids);
10141 scrappy@hub.org 9403 : 155 : }
9404 : :
9405 : : /*
9406 : : * Test whether a column should be printed as part of table's CREATE TABLE.
9407 : : * Column number is zero-based.
9408 : : *
9409 : : * Normally this is always true, but it's false for dropped columns, as well
9410 : : * as those that were inherited without any local definition. (If we print
9411 : : * such a column it will mistakenly get pg_attribute.attislocal set to true.)
9412 : : * For partitions, it's always true, because we want the partitions to be
9413 : : * created independently and ATTACH PARTITION used afterwards.
9414 : : *
9415 : : * In binary_upgrade mode, we must print all columns and fix the attislocal/
9416 : : * attisdropped state later, so as to keep control of the physical column
9417 : : * order.
9418 : : *
9419 : : * This function exists because there are scattered nonobvious places that
9420 : : * must be kept in sync with this decision.
9421 : : */
9422 : : bool
1159 peter@eisentraut.org 9423 : 35877 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
9424 : : {
3470 alvherre@alvh.no-ip. 9425 [ + + ]: 35877 : if (dopt->binary_upgrade)
4447 tgl@sss.pgh.pa.us 9426 : 5853 : return true;
1770 alvherre@alvh.no-ip. 9427 [ + + ]: 30024 : if (tbinfo->attisdropped[colno])
9428 : 347 : return false;
9429 [ + + + + ]: 29677 : return (tbinfo->attislocal[colno] || tbinfo->ispartition);
9430 : : }
9431 : :
9432 : :
9433 : : /*
9434 : : * getTSParsers:
9435 : : * read all text search parsers in the system catalogs and return them
9436 : : * in the TSParserInfo* structure
9437 : : *
9438 : : * numTSParsers is set to the number of parsers read in
9439 : : */
9440 : : TSParserInfo *
4451 rhaas@postgresql.org 9441 : 155 : getTSParsers(Archive *fout, int *numTSParsers)
9442 : : {
9443 : : PGresult *res;
9444 : : int ntups;
9445 : : int i;
9446 : : PQExpBuffer query;
9447 : : TSParserInfo *prsinfo;
9448 : : int i_tableoid;
9449 : : int i_oid;
9450 : : int i_prsname;
9451 : : int i_prsnamespace;
9452 : : int i_prsstart;
9453 : : int i_prstoken;
9454 : : int i_prsend;
9455 : : int i_prsheadline;
9456 : : int i_prslextype;
9457 : :
4415 peter_e@gmx.net 9458 : 155 : query = createPQExpBuffer();
9459 : :
9460 : : /*
9461 : : * find all text search objects, including builtin ones; we filter out
9462 : : * system-defined objects at dump-out time.
9463 : : */
9464 : :
3800 heikki.linnakangas@i 9465 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
9466 : : "prsstart::oid, prstoken::oid, "
9467 : : "prsend::oid, prsheadline::oid, prslextype::oid "
9468 : : "FROM pg_ts_parser");
9469 : :
4450 rhaas@postgresql.org 9470 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9471 : :
6081 tgl@sss.pgh.pa.us 9472 : 155 : ntups = PQntuples(res);
9473 : 155 : *numTSParsers = ntups;
9474 : :
4524 bruce@momjian.us 9475 : 155 : prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
9476 : :
6081 tgl@sss.pgh.pa.us 9477 : 155 : i_tableoid = PQfnumber(res, "tableoid");
9478 : 155 : i_oid = PQfnumber(res, "oid");
9479 : 155 : i_prsname = PQfnumber(res, "prsname");
9480 : 155 : i_prsnamespace = PQfnumber(res, "prsnamespace");
9481 : 155 : i_prsstart = PQfnumber(res, "prsstart");
9482 : 155 : i_prstoken = PQfnumber(res, "prstoken");
9483 : 155 : i_prsend = PQfnumber(res, "prsend");
9484 : 155 : i_prsheadline = PQfnumber(res, "prsheadline");
9485 : 155 : i_prslextype = PQfnumber(res, "prslextype");
9486 : :
9487 [ + + ]: 356 : for (i = 0; i < ntups; i++)
9488 : : {
9489 : 201 : prsinfo[i].dobj.objType = DO_TSPARSER;
9490 : 201 : prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9491 : 201 : prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9492 : 201 : AssignDumpId(&prsinfo[i].dobj);
4524 bruce@momjian.us 9493 : 201 : prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
4451 rhaas@postgresql.org 9494 : 402 : prsinfo[i].dobj.namespace =
1328 peter@eisentraut.org 9495 : 201 : findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
6081 tgl@sss.pgh.pa.us 9496 : 201 : prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
9497 : 201 : prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
9498 : 201 : prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
9499 : 201 : prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
9500 : 201 : prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
9501 : :
9502 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 9503 : 201 : selectDumpableObject(&(prsinfo[i].dobj), fout);
9504 : : }
9505 : :
6081 tgl@sss.pgh.pa.us 9506 : 155 : PQclear(res);
9507 : :
9508 : 155 : destroyPQExpBuffer(query);
9509 : :
9510 : 155 : return prsinfo;
9511 : : }
9512 : :
9513 : : /*
9514 : : * getTSDictionaries:
9515 : : * read all text search dictionaries in the system catalogs and return them
9516 : : * in the TSDictInfo* structure
9517 : : *
9518 : : * numTSDicts is set to the number of dictionaries read in
9519 : : */
9520 : : TSDictInfo *
4451 rhaas@postgresql.org 9521 : 155 : getTSDictionaries(Archive *fout, int *numTSDicts)
9522 : : {
9523 : : PGresult *res;
9524 : : int ntups;
9525 : : int i;
9526 : : PQExpBuffer query;
9527 : : TSDictInfo *dictinfo;
9528 : : int i_tableoid;
9529 : : int i_oid;
9530 : : int i_dictname;
9531 : : int i_dictnamespace;
9532 : : int i_dictowner;
9533 : : int i_dicttemplate;
9534 : : int i_dictinitoption;
9535 : :
4415 peter_e@gmx.net 9536 : 155 : query = createPQExpBuffer();
9537 : :
586 drowley@postgresql.o 9538 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
9539 : : "dictnamespace, dictowner, "
9540 : : "dicttemplate, dictinitoption "
9541 : : "FROM pg_ts_dict");
9542 : :
4450 rhaas@postgresql.org 9543 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9544 : :
6081 tgl@sss.pgh.pa.us 9545 : 155 : ntups = PQntuples(res);
9546 : 155 : *numTSDicts = ntups;
9547 : :
4524 bruce@momjian.us 9548 : 155 : dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
9549 : :
6081 tgl@sss.pgh.pa.us 9550 : 155 : i_tableoid = PQfnumber(res, "tableoid");
9551 : 155 : i_oid = PQfnumber(res, "oid");
9552 : 155 : i_dictname = PQfnumber(res, "dictname");
9553 : 155 : i_dictnamespace = PQfnumber(res, "dictnamespace");
835 9554 : 155 : i_dictowner = PQfnumber(res, "dictowner");
6081 9555 : 155 : i_dictinitoption = PQfnumber(res, "dictinitoption");
9556 : 155 : i_dicttemplate = PQfnumber(res, "dicttemplate");
9557 : :
9558 [ + + ]: 4741 : for (i = 0; i < ntups; i++)
9559 : : {
9560 : 4586 : dictinfo[i].dobj.objType = DO_TSDICT;
9561 : 4586 : dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9562 : 4586 : dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9563 : 4586 : AssignDumpId(&dictinfo[i].dobj);
4524 bruce@momjian.us 9564 : 4586 : dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
4451 rhaas@postgresql.org 9565 : 9172 : dictinfo[i].dobj.namespace =
1328 peter@eisentraut.org 9566 : 4586 : findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
835 tgl@sss.pgh.pa.us 9567 : 4586 : dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
6081 9568 : 4586 : dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
9569 [ + + ]: 4586 : if (PQgetisnull(res, i, i_dictinitoption))
9570 : 201 : dictinfo[i].dictinitoption = NULL;
9571 : : else
4524 bruce@momjian.us 9572 : 4385 : dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
9573 : :
9574 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 9575 : 4586 : selectDumpableObject(&(dictinfo[i].dobj), fout);
9576 : : }
9577 : :
6081 tgl@sss.pgh.pa.us 9578 : 155 : PQclear(res);
9579 : :
9580 : 155 : destroyPQExpBuffer(query);
9581 : :
9582 : 155 : return dictinfo;
9583 : : }
9584 : :
9585 : : /*
9586 : : * getTSTemplates:
9587 : : * read all text search templates in the system catalogs and return them
9588 : : * in the TSTemplateInfo* structure
9589 : : *
9590 : : * numTSTemplates is set to the number of templates read in
9591 : : */
9592 : : TSTemplateInfo *
4451 rhaas@postgresql.org 9593 : 155 : getTSTemplates(Archive *fout, int *numTSTemplates)
9594 : : {
9595 : : PGresult *res;
9596 : : int ntups;
9597 : : int i;
9598 : : PQExpBuffer query;
9599 : : TSTemplateInfo *tmplinfo;
9600 : : int i_tableoid;
9601 : : int i_oid;
9602 : : int i_tmplname;
9603 : : int i_tmplnamespace;
9604 : : int i_tmplinit;
9605 : : int i_tmpllexize;
9606 : :
4415 peter_e@gmx.net 9607 : 155 : query = createPQExpBuffer();
9608 : :
3800 heikki.linnakangas@i 9609 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
9610 : : "tmplnamespace, tmplinit::oid, tmpllexize::oid "
9611 : : "FROM pg_ts_template");
9612 : :
4450 rhaas@postgresql.org 9613 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9614 : :
6081 tgl@sss.pgh.pa.us 9615 : 155 : ntups = PQntuples(res);
9616 : 155 : *numTSTemplates = ntups;
9617 : :
4524 bruce@momjian.us 9618 : 155 : tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
9619 : :
6081 tgl@sss.pgh.pa.us 9620 : 155 : i_tableoid = PQfnumber(res, "tableoid");
9621 : 155 : i_oid = PQfnumber(res, "oid");
9622 : 155 : i_tmplname = PQfnumber(res, "tmplname");
9623 : 155 : i_tmplnamespace = PQfnumber(res, "tmplnamespace");
9624 : 155 : i_tmplinit = PQfnumber(res, "tmplinit");
9625 : 155 : i_tmpllexize = PQfnumber(res, "tmpllexize");
9626 : :
9627 [ + + ]: 976 : for (i = 0; i < ntups; i++)
9628 : : {
9629 : 821 : tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
9630 : 821 : tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9631 : 821 : tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9632 : 821 : AssignDumpId(&tmplinfo[i].dobj);
4524 bruce@momjian.us 9633 : 821 : tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
4451 rhaas@postgresql.org 9634 : 1642 : tmplinfo[i].dobj.namespace =
1328 peter@eisentraut.org 9635 : 821 : findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
6081 tgl@sss.pgh.pa.us 9636 : 821 : tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
9637 : 821 : tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
9638 : :
9639 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 9640 : 821 : selectDumpableObject(&(tmplinfo[i].dobj), fout);
9641 : : }
9642 : :
6081 tgl@sss.pgh.pa.us 9643 : 155 : PQclear(res);
9644 : :
9645 : 155 : destroyPQExpBuffer(query);
9646 : :
9647 : 155 : return tmplinfo;
9648 : : }
9649 : :
9650 : : /*
9651 : : * getTSConfigurations:
9652 : : * read all text search configurations in the system catalogs and return
9653 : : * them in the TSConfigInfo* structure
9654 : : *
9655 : : * numTSConfigs is set to the number of configurations read in
9656 : : */
9657 : : TSConfigInfo *
4451 rhaas@postgresql.org 9658 : 155 : getTSConfigurations(Archive *fout, int *numTSConfigs)
9659 : : {
9660 : : PGresult *res;
9661 : : int ntups;
9662 : : int i;
9663 : : PQExpBuffer query;
9664 : : TSConfigInfo *cfginfo;
9665 : : int i_tableoid;
9666 : : int i_oid;
9667 : : int i_cfgname;
9668 : : int i_cfgnamespace;
9669 : : int i_cfgowner;
9670 : : int i_cfgparser;
9671 : :
4415 peter_e@gmx.net 9672 : 155 : query = createPQExpBuffer();
9673 : :
586 drowley@postgresql.o 9674 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
9675 : : "cfgnamespace, cfgowner, cfgparser "
9676 : : "FROM pg_ts_config");
9677 : :
4450 rhaas@postgresql.org 9678 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9679 : :
6081 tgl@sss.pgh.pa.us 9680 : 155 : ntups = PQntuples(res);
9681 : 155 : *numTSConfigs = ntups;
9682 : :
4524 bruce@momjian.us 9683 : 155 : cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
9684 : :
6081 tgl@sss.pgh.pa.us 9685 : 155 : i_tableoid = PQfnumber(res, "tableoid");
9686 : 155 : i_oid = PQfnumber(res, "oid");
9687 : 155 : i_cfgname = PQfnumber(res, "cfgname");
9688 : 155 : i_cfgnamespace = PQfnumber(res, "cfgnamespace");
835 9689 : 155 : i_cfgowner = PQfnumber(res, "cfgowner");
6081 9690 : 155 : i_cfgparser = PQfnumber(res, "cfgparser");
9691 : :
9692 [ + + ]: 4716 : for (i = 0; i < ntups; i++)
9693 : : {
9694 : 4561 : cfginfo[i].dobj.objType = DO_TSCONFIG;
9695 : 4561 : cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9696 : 4561 : cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9697 : 4561 : AssignDumpId(&cfginfo[i].dobj);
4524 bruce@momjian.us 9698 : 4561 : cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
4451 rhaas@postgresql.org 9699 : 9122 : cfginfo[i].dobj.namespace =
1328 peter@eisentraut.org 9700 : 4561 : findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
835 tgl@sss.pgh.pa.us 9701 : 4561 : cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
6081 9702 : 4561 : cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
9703 : :
9704 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 9705 : 4561 : selectDumpableObject(&(cfginfo[i].dobj), fout);
9706 : : }
9707 : :
6081 tgl@sss.pgh.pa.us 9708 : 155 : PQclear(res);
9709 : :
9710 : 155 : destroyPQExpBuffer(query);
9711 : :
9712 : 155 : return cfginfo;
9713 : : }
9714 : :
9715 : : /*
9716 : : * getForeignDataWrappers:
9717 : : * read all foreign-data wrappers in the system catalogs and return
9718 : : * them in the FdwInfo* structure
9719 : : *
9720 : : * numForeignDataWrappers is set to the number of fdws read in
9721 : : */
9722 : : FdwInfo *
4451 rhaas@postgresql.org 9723 : 155 : getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
9724 : : {
9725 : : PGresult *res;
9726 : : int ntups;
9727 : : int i;
9728 : : PQExpBuffer query;
9729 : : FdwInfo *fdwinfo;
9730 : : int i_tableoid;
9731 : : int i_oid;
9732 : : int i_fdwname;
9733 : : int i_fdwowner;
9734 : : int i_fdwhandler;
9735 : : int i_fdwvalidator;
9736 : : int i_fdwacl;
9737 : : int i_acldefault;
9738 : : int i_fdwoptions;
9739 : :
3718 sfrost@snowman.net 9740 : 155 : query = createPQExpBuffer();
9741 : :
586 drowley@postgresql.o 9742 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
9743 : : "fdwowner, "
9744 : : "fdwhandler::pg_catalog.regproc, "
9745 : : "fdwvalidator::pg_catalog.regproc, "
9746 : : "fdwacl, "
9747 : : "acldefault('F', fdwowner) AS acldefault, "
9748 : : "array_to_string(ARRAY("
9749 : : "SELECT quote_ident(option_name) || ' ' || "
9750 : : "quote_literal(option_value) "
9751 : : "FROM pg_options_to_table(fdwoptions) "
9752 : : "ORDER BY option_name"
9753 : : "), E',\n ') AS fdwoptions "
9754 : : "FROM pg_foreign_data_wrapper");
9755 : :
4450 rhaas@postgresql.org 9756 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9757 : :
5595 peter_e@gmx.net 9758 : 155 : ntups = PQntuples(res);
9759 : 155 : *numForeignDataWrappers = ntups;
9760 : :
4524 bruce@momjian.us 9761 : 155 : fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
9762 : :
4952 heikki.linnakangas@i 9763 : 155 : i_tableoid = PQfnumber(res, "tableoid");
5595 peter_e@gmx.net 9764 : 155 : i_oid = PQfnumber(res, "oid");
9765 : 155 : i_fdwname = PQfnumber(res, "fdwname");
835 tgl@sss.pgh.pa.us 9766 : 155 : i_fdwowner = PQfnumber(res, "fdwowner");
4803 9767 : 155 : i_fdwhandler = PQfnumber(res, "fdwhandler");
5528 peter_e@gmx.net 9768 : 155 : i_fdwvalidator = PQfnumber(res, "fdwvalidator");
5595 9769 : 155 : i_fdwacl = PQfnumber(res, "fdwacl");
860 tgl@sss.pgh.pa.us 9770 : 155 : i_acldefault = PQfnumber(res, "acldefault");
5595 peter_e@gmx.net 9771 : 155 : i_fdwoptions = PQfnumber(res, "fdwoptions");
9772 : :
9773 [ + + ]: 225 : for (i = 0; i < ntups; i++)
9774 : : {
9775 : 70 : fdwinfo[i].dobj.objType = DO_FDW;
4952 heikki.linnakangas@i 9776 : 70 : fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5595 peter_e@gmx.net 9777 : 70 : fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9778 : 70 : AssignDumpId(&fdwinfo[i].dobj);
4524 bruce@momjian.us 9779 : 70 : fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
5595 peter_e@gmx.net 9780 : 70 : fdwinfo[i].dobj.namespace = NULL;
860 tgl@sss.pgh.pa.us 9781 : 70 : fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
9782 : 70 : fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9783 : 70 : fdwinfo[i].dacl.privtype = 0;
9784 : 70 : fdwinfo[i].dacl.initprivs = NULL;
835 9785 : 70 : fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
4524 bruce@momjian.us 9786 : 70 : fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
9787 : 70 : fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
9788 : 70 : fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
9789 : :
9790 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 9791 : 70 : selectDumpableObject(&(fdwinfo[i].dobj), fout);
9792 : :
9793 : : /* Mark whether FDW has an ACL */
860 tgl@sss.pgh.pa.us 9794 [ + + ]: 70 : if (!PQgetisnull(res, i, i_fdwacl))
9795 : 46 : fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9796 : : }
9797 : :
5595 peter_e@gmx.net 9798 : 155 : PQclear(res);
9799 : :
9800 : 155 : destroyPQExpBuffer(query);
9801 : :
9802 : 155 : return fdwinfo;
9803 : : }
9804 : :
9805 : : /*
9806 : : * getForeignServers:
9807 : : * read all foreign servers in the system catalogs and return
9808 : : * them in the ForeignServerInfo * structure
9809 : : *
9810 : : * numForeignServers is set to the number of servers read in
9811 : : */
9812 : : ForeignServerInfo *
4451 rhaas@postgresql.org 9813 : 155 : getForeignServers(Archive *fout, int *numForeignServers)
9814 : : {
9815 : : PGresult *res;
9816 : : int ntups;
9817 : : int i;
9818 : : PQExpBuffer query;
9819 : : ForeignServerInfo *srvinfo;
9820 : : int i_tableoid;
9821 : : int i_oid;
9822 : : int i_srvname;
9823 : : int i_srvowner;
9824 : : int i_srvfdw;
9825 : : int i_srvtype;
9826 : : int i_srvversion;
9827 : : int i_srvacl;
9828 : : int i_acldefault;
9829 : : int i_srvoptions;
9830 : :
3718 sfrost@snowman.net 9831 : 155 : query = createPQExpBuffer();
9832 : :
586 drowley@postgresql.o 9833 : 155 : appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
9834 : : "srvowner, "
9835 : : "srvfdw, srvtype, srvversion, srvacl, "
9836 : : "acldefault('S', srvowner) AS acldefault, "
9837 : : "array_to_string(ARRAY("
9838 : : "SELECT quote_ident(option_name) || ' ' || "
9839 : : "quote_literal(option_value) "
9840 : : "FROM pg_options_to_table(srvoptions) "
9841 : : "ORDER BY option_name"
9842 : : "), E',\n ') AS srvoptions "
9843 : : "FROM pg_foreign_server");
9844 : :
4450 rhaas@postgresql.org 9845 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9846 : :
5595 peter_e@gmx.net 9847 : 155 : ntups = PQntuples(res);
9848 : 155 : *numForeignServers = ntups;
9849 : :
4524 bruce@momjian.us 9850 : 155 : srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9851 : :
4952 heikki.linnakangas@i 9852 : 155 : i_tableoid = PQfnumber(res, "tableoid");
5595 peter_e@gmx.net 9853 : 155 : i_oid = PQfnumber(res, "oid");
9854 : 155 : i_srvname = PQfnumber(res, "srvname");
835 tgl@sss.pgh.pa.us 9855 : 155 : i_srvowner = PQfnumber(res, "srvowner");
5595 peter_e@gmx.net 9856 : 155 : i_srvfdw = PQfnumber(res, "srvfdw");
9857 : 155 : i_srvtype = PQfnumber(res, "srvtype");
9858 : 155 : i_srvversion = PQfnumber(res, "srvversion");
9859 : 155 : i_srvacl = PQfnumber(res, "srvacl");
860 tgl@sss.pgh.pa.us 9860 : 155 : i_acldefault = PQfnumber(res, "acldefault");
5595 peter_e@gmx.net 9861 : 155 : i_srvoptions = PQfnumber(res, "srvoptions");
9862 : :
9863 [ + + ]: 229 : for (i = 0; i < ntups; i++)
9864 : : {
9865 : 74 : srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
4952 heikki.linnakangas@i 9866 : 74 : srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5595 peter_e@gmx.net 9867 : 74 : srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9868 : 74 : AssignDumpId(&srvinfo[i].dobj);
4524 bruce@momjian.us 9869 : 74 : srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
5595 peter_e@gmx.net 9870 : 74 : srvinfo[i].dobj.namespace = NULL;
860 tgl@sss.pgh.pa.us 9871 : 74 : srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9872 : 74 : srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9873 : 74 : srvinfo[i].dacl.privtype = 0;
9874 : 74 : srvinfo[i].dacl.initprivs = NULL;
835 9875 : 74 : srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
5595 peter_e@gmx.net 9876 : 74 : srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
4524 bruce@momjian.us 9877 : 74 : srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9878 : 74 : srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9879 : 74 : srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9880 : :
9881 : : /* Decide whether we want to dump it */
2930 sfrost@snowman.net 9882 : 74 : selectDumpableObject(&(srvinfo[i].dobj), fout);
9883 : :
9884 : : /* Servers have user mappings */
860 tgl@sss.pgh.pa.us 9885 : 74 : srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
9886 : :
9887 : : /* Mark whether server has an ACL */
9888 [ + + ]: 74 : if (!PQgetisnull(res, i, i_srvacl))
9889 : 46 : srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9890 : : }
9891 : :
5595 peter_e@gmx.net 9892 : 155 : PQclear(res);
9893 : :
9894 : 155 : destroyPQExpBuffer(query);
9895 : :
9896 : 155 : return srvinfo;
9897 : : }
9898 : :
9899 : : /*
9900 : : * getDefaultACLs:
9901 : : * read all default ACL information in the system catalogs and return
9902 : : * them in the DefaultACLInfo structure
9903 : : *
9904 : : * numDefaultACLs is set to the number of ACLs read in
9905 : : */
9906 : : DefaultACLInfo *
3014 tgl@sss.pgh.pa.us 9907 : 155 : getDefaultACLs(Archive *fout, int *numDefaultACLs)
9908 : : {
9909 : 155 : DumpOptions *dopt = fout->dopt;
9910 : : DefaultACLInfo *daclinfo;
9911 : : PQExpBuffer query;
9912 : : PGresult *res;
9913 : : int i_oid;
9914 : : int i_tableoid;
9915 : : int i_defaclrole;
9916 : : int i_defaclnamespace;
9917 : : int i_defaclobjtype;
9918 : : int i_defaclacl;
9919 : : int i_acldefault;
9920 : : int i,
9921 : : ntups;
9922 : :
5305 9923 : 155 : query = createPQExpBuffer();
9924 : :
9925 : : /*
9926 : : * Global entries (with defaclnamespace=0) replace the hard-wired default
9927 : : * ACL for their object type. We should dump them as deltas from the
9928 : : * default ACL, since that will be used as a starting point for
9929 : : * interpreting the ALTER DEFAULT PRIVILEGES commands. On the other hand,
9930 : : * non-global entries can only add privileges not revoke them. We must
9931 : : * dump those as-is (i.e., as deltas from an empty ACL).
9932 : : *
9933 : : * We can use defaclobjtype as the object type for acldefault(), except
9934 : : * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
9935 : : * 's'.
9936 : : */
586 drowley@postgresql.o 9937 : 155 : appendPQExpBufferStr(query,
9938 : : "SELECT oid, tableoid, "
9939 : : "defaclrole, "
9940 : : "defaclnamespace, "
9941 : : "defaclobjtype, "
9942 : : "defaclacl, "
9943 : : "CASE WHEN defaclnamespace = 0 THEN "
9944 : : "acldefault(CASE WHEN defaclobjtype = 'S' "
9945 : : "THEN 's'::\"char\" ELSE defaclobjtype END, "
9946 : : "defaclrole) ELSE '{}' END AS acldefault "
9947 : : "FROM pg_default_acl");
9948 : :
4450 rhaas@postgresql.org 9949 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9950 : :
5305 tgl@sss.pgh.pa.us 9951 : 155 : ntups = PQntuples(res);
9952 : 155 : *numDefaultACLs = ntups;
9953 : :
4524 bruce@momjian.us 9954 : 155 : daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9955 : :
5305 tgl@sss.pgh.pa.us 9956 : 155 : i_oid = PQfnumber(res, "oid");
9957 : 155 : i_tableoid = PQfnumber(res, "tableoid");
9958 : 155 : i_defaclrole = PQfnumber(res, "defaclrole");
9959 : 155 : i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9960 : 155 : i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9961 : 155 : i_defaclacl = PQfnumber(res, "defaclacl");
860 9962 : 155 : i_acldefault = PQfnumber(res, "acldefault");
9963 : :
5305 9964 [ + + ]: 339 : for (i = 0; i < ntups; i++)
9965 : : {
5161 bruce@momjian.us 9966 : 184 : Oid nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9967 : :
5305 tgl@sss.pgh.pa.us 9968 : 184 : daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9969 : 184 : daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9970 : 184 : daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9971 : 184 : AssignDumpId(&daclinfo[i].dobj);
9972 : : /* cheesy ... is it worth coming up with a better object name? */
4524 bruce@momjian.us 9973 : 184 : daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9974 : :
5305 tgl@sss.pgh.pa.us 9975 [ + + ]: 184 : if (nspid != InvalidOid)
1328 peter@eisentraut.org 9976 : 92 : daclinfo[i].dobj.namespace = findNamespace(nspid);
9977 : : else
5305 tgl@sss.pgh.pa.us 9978 : 92 : daclinfo[i].dobj.namespace = NULL;
9979 : :
860 9980 : 184 : daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9981 : 184 : daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9982 : 184 : daclinfo[i].dacl.privtype = 0;
9983 : 184 : daclinfo[i].dacl.initprivs = NULL;
835 9984 : 184 : daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
5305 9985 : 184 : daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9986 : :
9987 : : /* Default ACLs are ACLs, of course */
860 9988 : 184 : daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9989 : :
9990 : : /* Decide whether we want to dump it */
3014 9991 : 184 : selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9992 : : }
9993 : :
5305 9994 : 155 : PQclear(res);
9995 : :
9996 : 155 : destroyPQExpBuffer(query);
9997 : :
9998 : 155 : return daclinfo;
9999 : : }
10000 : :
10001 : : /*
10002 : : * getRoleName -- look up the name of a role, given its OID
10003 : : *
10004 : : * In current usage, we don't expect failures, so error out for a bad OID.
10005 : : */
10006 : : static const char *
835 10007 : 584639 : getRoleName(const char *roleoid_str)
10008 : : {
10009 : 584639 : Oid roleoid = atooid(roleoid_str);
10010 : :
10011 : : /*
10012 : : * Do binary search to find the appropriate item.
10013 : : */
10014 [ + - ]: 584639 : if (nrolenames > 0)
10015 : : {
10016 : 584639 : RoleNameItem *low = &rolenames[0];
10017 : 584639 : RoleNameItem *high = &rolenames[nrolenames - 1];
10018 : :
10019 [ + - ]: 2338626 : while (low <= high)
10020 : : {
10021 : 2338626 : RoleNameItem *middle = low + (high - low) / 2;
10022 : :
10023 [ + + ]: 2338626 : if (roleoid < middle->roleoid)
10024 : 1752766 : high = middle - 1;
10025 [ + + ]: 585860 : else if (roleoid > middle->roleoid)
10026 : 1221 : low = middle + 1;
10027 : : else
10028 : 584639 : return middle->rolename; /* found a match */
10029 : : }
10030 : : }
10031 : :
737 tgl@sss.pgh.pa.us 10032 :UBC 0 : pg_fatal("role with OID %u does not exist", roleoid);
10033 : : return NULL; /* keep compiler quiet */
10034 : : }
10035 : :
10036 : : /*
10037 : : * collectRoleNames --
10038 : : *
10039 : : * Construct a table of all known roles.
10040 : : * The table is sorted by OID for speed in lookup.
10041 : : */
10042 : : static void
835 tgl@sss.pgh.pa.us 10043 :CBC 156 : collectRoleNames(Archive *fout)
10044 : : {
10045 : : PGresult *res;
10046 : : const char *query;
10047 : : int i;
10048 : :
10049 : 156 : query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
10050 : :
10051 : 156 : res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
10052 : :
10053 : 156 : nrolenames = PQntuples(res);
10054 : :
10055 : 156 : rolenames = (RoleNameItem *) pg_malloc(nrolenames * sizeof(RoleNameItem));
10056 : :
10057 [ + + ]: 2858 : for (i = 0; i < nrolenames; i++)
10058 : : {
10059 : 2702 : rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
10060 : 2702 : rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
10061 : : }
10062 : :
10063 : 156 : PQclear(res);
10064 : 156 : }
10065 : :
10066 : : /*
10067 : : * getAdditionalACLs
10068 : : *
10069 : : * We have now created all the DumpableObjects, and collected the ACL data
10070 : : * that appears in the directly-associated catalog entries. However, there's
10071 : : * more ACL-related info to collect. If any of a table's columns have ACLs,
10072 : : * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
10073 : : * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
10074 : : * Also, in versions having the pg_init_privs catalog, read that and load the
10075 : : * information into the relevant DumpableObjects.
10076 : : */
10077 : : static void
860 10078 : 153 : getAdditionalACLs(Archive *fout)
10079 : : {
10080 : 153 : PQExpBuffer query = createPQExpBuffer();
10081 : : PGresult *res;
10082 : : int ntups,
10083 : : i;
10084 : :
10085 : : /* Check for per-column ACLs */
852 10086 : 153 : appendPQExpBufferStr(query,
10087 : : "SELECT DISTINCT attrelid FROM pg_attribute "
10088 : : "WHERE attacl IS NOT NULL");
10089 : :
10090 : 153 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10091 : :
10092 : 153 : ntups = PQntuples(res);
10093 [ + + ]: 475 : for (i = 0; i < ntups; i++)
10094 : : {
10095 : 322 : Oid relid = atooid(PQgetvalue(res, i, 0));
10096 : : TableInfo *tblinfo;
10097 : :
10098 : 322 : tblinfo = findTableByOid(relid);
10099 : : /* OK to ignore tables we haven't got a DumpableObject for */
10100 [ + - ]: 322 : if (tblinfo)
10101 : : {
10102 : 322 : tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
10103 : 322 : tblinfo->hascolumnACLs = true;
10104 : : }
10105 : : }
10106 : 153 : PQclear(res);
10107 : :
10108 : : /* Fetch initial-privileges data */
860 10109 [ + - ]: 153 : if (fout->remoteVersion >= 90600)
10110 : : {
10111 : 153 : printfPQExpBuffer(query,
10112 : : "SELECT objoid, classoid, objsubid, privtype, initprivs "
10113 : : "FROM pg_init_privs");
10114 : :
10115 : 153 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10116 : :
10117 : 153 : ntups = PQntuples(res);
10118 [ + + ]: 34580 : for (i = 0; i < ntups; i++)
10119 : : {
10120 : 34427 : Oid objoid = atooid(PQgetvalue(res, i, 0));
10121 : 34427 : Oid classoid = atooid(PQgetvalue(res, i, 1));
10122 : 34427 : int objsubid = atoi(PQgetvalue(res, i, 2));
10123 : 34427 : char privtype = *(PQgetvalue(res, i, 3));
10124 : 34427 : char *initprivs = PQgetvalue(res, i, 4);
10125 : : CatalogId objId;
10126 : : DumpableObject *dobj;
10127 : :
10128 : 34427 : objId.tableoid = classoid;
10129 : 34427 : objId.oid = objoid;
10130 : 34427 : dobj = findObjectByCatalogId(objId);
10131 : : /* OK to ignore entries we haven't got a DumpableObject for */
10132 [ + + ]: 34427 : if (dobj)
10133 : : {
10134 : : /* Cope with sub-object initprivs */
10135 [ + + ]: 24986 : if (objsubid != 0)
10136 : : {
10137 [ + - ]: 2625 : if (dobj->objType == DO_TABLE)
10138 : : {
10139 : : /* For a column initprivs, set the table's ACL flags */
10140 : 2625 : dobj->components |= DUMP_COMPONENT_ACL;
10141 : 2625 : ((TableInfo *) dobj)->hascolumnACLs = true;
10142 : : }
10143 : : else
860 tgl@sss.pgh.pa.us 10144 :UBC 0 : pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10145 : : classoid, objoid, objsubid);
860 tgl@sss.pgh.pa.us 10146 :CBC 2774 : continue;
10147 : : }
10148 : :
10149 : : /*
10150 : : * We ignore any pg_init_privs.initprivs entry for the public
10151 : : * schema, as explained in getNamespaces().
10152 : : */
10153 [ + + ]: 22361 : if (dobj->objType == DO_NAMESPACE &&
10154 [ + + ]: 302 : strcmp(dobj->name, "public") == 0)
10155 : 149 : continue;
10156 : :
10157 : : /* Else it had better be of a type we think has ACLs */
10158 [ + + ]: 22212 : if (dobj->objType == DO_NAMESPACE ||
10159 [ + + ]: 22059 : dobj->objType == DO_TYPE ||
10160 [ + + ]: 22035 : dobj->objType == DO_FUNC ||
10161 [ + + ]: 21942 : dobj->objType == DO_AGG ||
10162 [ - + ]: 21918 : dobj->objType == DO_TABLE ||
860 tgl@sss.pgh.pa.us 10163 [ # # ]:UBC 0 : dobj->objType == DO_PROCLANG ||
10164 [ # # ]: 0 : dobj->objType == DO_FDW ||
10165 [ # # ]: 0 : dobj->objType == DO_FOREIGN_SERVER)
860 tgl@sss.pgh.pa.us 10166 :CBC 22212 : {
10167 : 22212 : DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
10168 : :
10169 : 22212 : daobj->dacl.privtype = privtype;
10170 : 22212 : daobj->dacl.initprivs = pstrdup(initprivs);
10171 : : }
10172 : : else
860 tgl@sss.pgh.pa.us 10173 :UBC 0 : pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10174 : : classoid, objoid, objsubid);
10175 : : }
10176 : : }
860 tgl@sss.pgh.pa.us 10177 :CBC 153 : PQclear(res);
10178 : : }
10179 : :
10180 : 153 : destroyPQExpBuffer(query);
10181 : 153 : }
10182 : :
10183 : : /*
10184 : : * dumpCommentExtended --
10185 : : *
10186 : : * This routine is used to dump any comments associated with the
10187 : : * object handed to this routine. The routine takes the object type
10188 : : * and object name (ready to print, except for schema decoration), plus
10189 : : * the namespace and owner of the object (for labeling the ArchiveEntry),
10190 : : * plus catalog ID and subid which are the lookup key for pg_description,
10191 : : * plus the dump ID for the object (for setting a dependency).
10192 : : * If a matching pg_description entry is found, it is dumped.
10193 : : *
10194 : : * Note: in some cases, such as comments for triggers and rules, the "type"
10195 : : * string really looks like, e.g., "TRIGGER name ON". This is a bit of a hack
10196 : : * but it doesn't seem worth complicating the API for all callers to make
10197 : : * it cleaner.
10198 : : *
10199 : : * Note: although this routine takes a dumpId for dependency purposes,
10200 : : * that purpose is just to mark the dependency in the emitted dump file
10201 : : * for possible future use by pg_restore. We do NOT use it for determining
10202 : : * ordering of the comment in the dump file, because this routine is called
10203 : : * after dependency sorting occurs. This routine should be called just after
10204 : : * calling ArchiveEntry() for the specified object.
10205 : : */
10206 : : static void
1021 noah@leadboat.com 10207 : 2646 : dumpCommentExtended(Archive *fout, const char *type,
10208 : : const char *name, const char *namespace,
10209 : : const char *owner, CatalogId catalogId,
10210 : : int subid, DumpId dumpId,
10211 : : const char *initdb_comment)
10212 : : {
3014 tgl@sss.pgh.pa.us 10213 : 2646 : DumpOptions *dopt = fout->dopt;
10214 : : CommentItem *comments;
10215 : : int ncomments;
10216 : :
10217 : : /* do nothing, if --no-comments is supplied */
2271 10218 [ - + ]: 2646 : if (dopt->no_comments)
2271 tgl@sss.pgh.pa.us 10219 :UBC 0 : return;
10220 : :
10221 : : /* Comments are schema not data ... except LO comments are data */
2239 tgl@sss.pgh.pa.us 10222 [ + + ]:CBC 2646 : if (strcmp(type, "LARGE OBJECT") != 0)
10223 : : {
3470 alvherre@alvh.no-ip. 10224 [ - + ]: 2594 : if (dopt->dataOnly)
5169 tgl@sss.pgh.pa.us 10225 :UBC 0 : return;
10226 : : }
10227 : : else
10228 : : {
10229 : : /* We do dump LO comments in binary-upgrade mode */
2596 sfrost@snowman.net 10230 [ + + - + ]:CBC 52 : if (dopt->schemaOnly && !dopt->binary_upgrade)
5169 tgl@sss.pgh.pa.us 10231 :UBC 0 : return;
10232 : : }
10233 : :
10234 : : /* Search for comments associated with catalogId, using table */
836 tgl@sss.pgh.pa.us 10235 :CBC 2646 : ncomments = findComments(catalogId.tableoid, catalogId.oid,
10236 : : &comments);
10237 : :
10238 : : /* Is there one matching the subid? */
7330 10239 [ + + ]: 2646 : while (ncomments > 0)
10240 : : {
10241 [ + - ]: 2601 : if (comments->objsubid == subid)
10242 : 2601 : break;
7330 tgl@sss.pgh.pa.us 10243 :UBC 0 : comments++;
10244 : 0 : ncomments--;
10245 : : }
10246 : :
1021 noah@leadboat.com 10247 [ + + ]:CBC 2646 : if (initdb_comment != NULL)
10248 : : {
10249 : : static CommentItem empty_comment = {.descr = ""};
10250 : :
10251 : : /*
10252 : : * initdb creates this object with a comment. Skip dumping the
10253 : : * initdb-provided comment, which would complicate matters for
10254 : : * non-superuser use of pg_dump. When the DBA has removed initdb's
10255 : : * comment, replicate that.
10256 : : */
10257 [ + + ]: 113 : if (ncomments == 0)
10258 : : {
10259 : 4 : comments = &empty_comment;
10260 : 4 : ncomments = 1;
10261 : : }
10262 [ + - ]: 109 : else if (strcmp(comments->descr, initdb_comment) == 0)
10263 : 109 : ncomments = 0;
10264 : : }
10265 : :
10266 : : /* If a comment exists, build COMMENT ON statement */
7330 tgl@sss.pgh.pa.us 10267 [ + + ]: 2646 : if (ncomments > 0)
10268 : : {
10269 : 2496 : PQExpBuffer query = createPQExpBuffer();
2239 10270 : 2496 : PQExpBuffer tag = createPQExpBuffer();
10271 : :
10272 : 2496 : appendPQExpBuffer(query, "COMMENT ON %s ", type);
10273 [ + + + - ]: 2496 : if (namespace && *namespace)
10274 : 2342 : appendPQExpBuffer(query, "%s.", fmtId(namespace));
10275 : 2496 : appendPQExpBuffer(query, "%s IS ", name);
6531 10276 : 2496 : appendStringLiteralAH(query, comments->descr, fout);
3800 heikki.linnakangas@i 10277 : 2496 : appendPQExpBufferStr(query, ";\n");
10278 : :
2239 tgl@sss.pgh.pa.us 10279 : 2496 : appendPQExpBuffer(tag, "%s %s", type, name);
10280 : :
10281 : : /*
10282 : : * We mark comments as SECTION_NONE because they really belong in the
10283 : : * same section as their parent, whether that is pre-data or
10284 : : * post-data.
10285 : : */
7435 10286 : 2496 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 10287 : 2496 : ARCHIVE_OPTS(.tag = tag->data,
10288 : : .namespace = namespace,
10289 : : .owner = owner,
10290 : : .description = "COMMENT",
10291 : : .section = SECTION_NONE,
10292 : : .createStmt = query->data,
10293 : : .deps = &dumpId,
10294 : : .nDeps = 1));
10295 : :
7330 tgl@sss.pgh.pa.us 10296 : 2496 : destroyPQExpBuffer(query);
2239 10297 : 2496 : destroyPQExpBuffer(tag);
10298 : : }
10299 : : }
10300 : :
10301 : : /*
10302 : : * dumpComment --
10303 : : *
10304 : : * Typical simplification of the above function.
10305 : : */
10306 : : static inline void
1021 noah@leadboat.com 10307 : 2518 : dumpComment(Archive *fout, const char *type,
10308 : : const char *name, const char *namespace,
10309 : : const char *owner, CatalogId catalogId,
10310 : : int subid, DumpId dumpId)
10311 : : {
10312 : 2518 : dumpCommentExtended(fout, type, name, namespace, owner,
10313 : : catalogId, subid, dumpId, NULL);
10314 : 2518 : }
10315 : :
10316 : : /*
10317 : : * dumpTableComment --
10318 : : *
10319 : : * As above, but dump comments for both the specified table (or view)
10320 : : * and its columns.
10321 : : */
10322 : : static void
1159 peter@eisentraut.org 10323 : 82 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
10324 : : const char *reltypename)
10325 : : {
3014 tgl@sss.pgh.pa.us 10326 : 82 : DumpOptions *dopt = fout->dopt;
10327 : : CommentItem *comments;
10328 : : int ncomments;
10329 : : PQExpBuffer query;
10330 : : PQExpBuffer tag;
10331 : :
10332 : : /* do nothing, if --no-comments is supplied */
2271 10333 [ - + ]: 82 : if (dopt->no_comments)
2271 tgl@sss.pgh.pa.us 10334 :UBC 0 : return;
10335 : :
10336 : : /* Comments are SCHEMA not data */
3470 alvherre@alvh.no-ip. 10337 [ - + ]:CBC 82 : if (dopt->dataOnly)
8010 tgl@sss.pgh.pa.us 10338 :UBC 0 : return;
10339 : :
10340 : : /* Search for comments associated with relation, using table */
836 tgl@sss.pgh.pa.us 10341 :CBC 82 : ncomments = findComments(tbinfo->dobj.catId.tableoid,
7330 10342 : 82 : tbinfo->dobj.catId.oid,
10343 : : &comments);
10344 : :
10345 : : /* If comments exist, build COMMENT ON statements */
10346 [ - + ]: 82 : if (ncomments <= 0)
7330 tgl@sss.pgh.pa.us 10347 :UBC 0 : return;
10348 : :
8010 tgl@sss.pgh.pa.us 10349 :CBC 82 : query = createPQExpBuffer();
2239 10350 : 82 : tag = createPQExpBuffer();
10351 : :
7330 10352 [ + + ]: 236 : while (ncomments > 0)
10353 : : {
10354 : 154 : const char *descr = comments->descr;
10355 : 154 : int objsubid = comments->objsubid;
10356 : :
8010 10357 [ + + ]: 154 : if (objsubid == 0)
10358 : : {
2239 10359 : 36 : resetPQExpBuffer(tag);
10360 : 36 : appendPQExpBuffer(tag, "%s %s", reltypename,
7347 10361 : 36 : fmtId(tbinfo->dobj.name));
10362 : :
8010 10363 : 36 : resetPQExpBuffer(query);
2239 10364 : 36 : appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
10365 : 36 : fmtQualifiedDumpable(tbinfo));
6531 10366 : 36 : appendStringLiteralAH(query, descr, fout);
3800 heikki.linnakangas@i 10367 : 36 : appendPQExpBufferStr(query, ";\n");
10368 : :
7435 tgl@sss.pgh.pa.us 10369 : 36 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 10370 : 36 : ARCHIVE_OPTS(.tag = tag->data,
10371 : : .namespace = tbinfo->dobj.namespace->dobj.name,
10372 : : .owner = tbinfo->rolname,
10373 : : .description = "COMMENT",
10374 : : .section = SECTION_NONE,
10375 : : .createStmt = query->data,
10376 : : .deps = &(tbinfo->dobj.dumpId),
10377 : : .nDeps = 1));
10378 : : }
8010 tgl@sss.pgh.pa.us 10379 [ + - + - ]: 118 : else if (objsubid > 0 && objsubid <= tbinfo->numatts)
10380 : : {
2239 10381 : 118 : resetPQExpBuffer(tag);
10382 : 118 : appendPQExpBuffer(tag, "COLUMN %s.",
7347 10383 : 118 : fmtId(tbinfo->dobj.name));
2239 10384 : 118 : appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
10385 : :
8010 10386 : 118 : resetPQExpBuffer(query);
2239 10387 : 118 : appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
10388 : 118 : fmtQualifiedDumpable(tbinfo));
10389 : 118 : appendPQExpBuffer(query, "%s IS ",
10390 : 118 : fmtId(tbinfo->attnames[objsubid - 1]));
6531 10391 : 118 : appendStringLiteralAH(query, descr, fout);
3800 heikki.linnakangas@i 10392 : 118 : appendPQExpBufferStr(query, ";\n");
10393 : :
7435 tgl@sss.pgh.pa.us 10394 : 118 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 10395 : 118 : ARCHIVE_OPTS(.tag = tag->data,
10396 : : .namespace = tbinfo->dobj.namespace->dobj.name,
10397 : : .owner = tbinfo->rolname,
10398 : : .description = "COMMENT",
10399 : : .section = SECTION_NONE,
10400 : : .createStmt = query->data,
10401 : : .deps = &(tbinfo->dobj.dumpId),
10402 : : .nDeps = 1));
10403 : : }
10404 : :
7330 tgl@sss.pgh.pa.us 10405 : 154 : comments++;
10406 : 154 : ncomments--;
10407 : : }
10408 : :
8290 10409 : 82 : destroyPQExpBuffer(query);
2239 10410 : 82 : destroyPQExpBuffer(tag);
10411 : : }
10412 : :
10413 : : /*
10414 : : * findComments --
10415 : : *
10416 : : * Find the comment(s), if any, associated with the given object. All the
10417 : : * objsubid values associated with the given classoid/objoid are found with
10418 : : * one search.
10419 : : */
10420 : : static int
836 10421 : 2764 : findComments(Oid classoid, Oid objoid, CommentItem **items)
10422 : : {
7330 10423 : 2764 : CommentItem *middle = NULL;
10424 : : CommentItem *low;
10425 : : CommentItem *high;
10426 : : int nmatch;
10427 : :
10428 : : /*
10429 : : * Do binary search to find some item matching the object.
10430 : : */
10431 : 2764 : low = &comments[0];
7168 bruce@momjian.us 10432 : 2764 : high = &comments[ncomments - 1];
7330 tgl@sss.pgh.pa.us 10433 [ + + ]: 27503 : while (low <= high)
10434 : : {
10435 : 27458 : middle = low + (high - low) / 2;
10436 : :
10437 [ + + ]: 27458 : if (classoid < middle->classoid)
10438 : 4937 : high = middle - 1;
10439 [ + + ]: 22521 : else if (classoid > middle->classoid)
10440 : 3867 : low = middle + 1;
10441 [ + + ]: 18654 : else if (objoid < middle->objoid)
10442 : 7201 : high = middle - 1;
10443 [ + + ]: 11453 : else if (objoid > middle->objoid)
10444 : 8734 : low = middle + 1;
10445 : : else
10446 : 2719 : break; /* found a match */
10447 : : }
10448 : :
10449 [ + + ]: 2764 : if (low > high) /* no matches */
10450 : : {
10451 : 45 : *items = NULL;
10452 : 45 : return 0;
10453 : : }
10454 : :
10455 : : /*
10456 : : * Now determine how many items match the object. The search loop
10457 : : * invariant still holds: only items between low and high inclusive could
10458 : : * match.
10459 : : */
10460 : 2719 : nmatch = 1;
10461 [ + + ]: 2791 : while (middle > low)
10462 : : {
10463 [ + + ]: 1360 : if (classoid != middle[-1].classoid ||
10464 [ + + ]: 1246 : objoid != middle[-1].objoid)
10465 : : break;
7330 tgl@sss.pgh.pa.us 10466 :GBC 72 : middle--;
10467 : 72 : nmatch++;
10468 : : }
10469 : :
7330 tgl@sss.pgh.pa.us 10470 :CBC 2719 : *items = middle;
10471 : :
10472 : 2719 : middle += nmatch;
10473 [ + + ]: 2719 : while (middle <= high)
10474 : : {
10475 [ + + ]: 1557 : if (classoid != middle->classoid ||
10476 [ - + ]: 1194 : objoid != middle->objoid)
10477 : : break;
7330 tgl@sss.pgh.pa.us 10478 :LBC (72) : middle++;
10479 : (72) : nmatch++;
10480 : : }
10481 : :
7330 tgl@sss.pgh.pa.us 10482 :CBC 2719 : return nmatch;
10483 : : }
10484 : :
10485 : : /*
10486 : : * collectComments --
10487 : : *
10488 : : * Construct a table of all comments available for database objects;
10489 : : * also set the has-comment component flag for each relevant object.
10490 : : *
10491 : : * We used to do per-object queries for the comments, but it's much faster
10492 : : * to pull them all over at once, and on most databases the memory cost
10493 : : * isn't high.
10494 : : *
10495 : : * The table is sorted by classoid/objid/objsubid for speed in lookup.
10496 : : */
10497 : : static void
860 10498 : 155 : collectComments(Archive *fout)
10499 : : {
10500 : : PGresult *res;
10501 : : PQExpBuffer query;
10502 : : int i_description;
10503 : : int i_classoid;
10504 : : int i_objoid;
10505 : : int i_objsubid;
10506 : : int ntups;
10507 : : int i;
10508 : : DumpableObject *dobj;
10509 : :
7330 10510 : 155 : query = createPQExpBuffer();
10511 : :
2741 10512 : 155 : appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
10513 : : "FROM pg_catalog.pg_description "
10514 : : "ORDER BY classoid, objoid, objsubid");
10515 : :
4450 rhaas@postgresql.org 10516 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10517 : :
10518 : : /* Construct lookup table containing OIDs in numeric form */
10519 : :
7330 tgl@sss.pgh.pa.us 10520 : 155 : i_description = PQfnumber(res, "description");
10521 : 155 : i_classoid = PQfnumber(res, "classoid");
10522 : 155 : i_objoid = PQfnumber(res, "objoid");
10523 : 155 : i_objsubid = PQfnumber(res, "objsubid");
10524 : :
10525 : 155 : ntups = PQntuples(res);
10526 : :
4524 bruce@momjian.us 10527 : 155 : comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
860 tgl@sss.pgh.pa.us 10528 : 155 : ncomments = 0;
10529 : 155 : dobj = NULL;
10530 : :
7330 10531 [ + + ]: 811341 : for (i = 0; i < ntups; i++)
10532 : : {
10533 : : CatalogId objId;
10534 : : int subid;
10535 : :
860 10536 : 811186 : objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
10537 : 811186 : objId.oid = atooid(PQgetvalue(res, i, i_objoid));
10538 : 811186 : subid = atoi(PQgetvalue(res, i, i_objsubid));
10539 : :
10540 : : /* We needn't remember comments that don't match any dumpable object */
10541 [ + + ]: 811186 : if (dobj == NULL ||
10542 [ + + ]: 296953 : dobj->catId.tableoid != objId.tableoid ||
10543 [ + + ]: 295012 : dobj->catId.oid != objId.oid)
10544 : 811094 : dobj = findObjectByCatalogId(objId);
10545 [ + + ]: 811186 : if (dobj == NULL)
10546 : 514082 : continue;
10547 : :
10548 : : /*
10549 : : * Comments on columns of composite types are linked to the type's
10550 : : * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
10551 : : * in the type's own DumpableObject.
10552 : : */
10553 [ + + + - ]: 297104 : if (subid != 0 && dobj->objType == DO_TABLE &&
10554 [ + + ]: 194 : ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
10555 : 46 : {
10556 : : TypeInfo *cTypeInfo;
10557 : :
10558 : 46 : cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
10559 [ + - ]: 46 : if (cTypeInfo)
10560 : 46 : cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
10561 : : }
10562 : : else
10563 : 297058 : dobj->components |= DUMP_COMPONENT_COMMENT;
10564 : :
10565 : 297104 : comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
10566 : 297104 : comments[ncomments].classoid = objId.tableoid;
10567 : 297104 : comments[ncomments].objoid = objId.oid;
10568 : 297104 : comments[ncomments].objsubid = subid;
10569 : 297104 : ncomments++;
10570 : : }
10571 : :
10572 : 155 : PQclear(res);
7330 10573 : 155 : destroyPQExpBuffer(query);
10574 : 155 : }
10575 : :
10576 : : /*
10577 : : * dumpDumpableObject
10578 : : *
10579 : : * This routine and its subsidiaries are responsible for creating
10580 : : * ArchiveEntries (TOC objects) for each object to be dumped.
10581 : : */
10582 : : static void
860 10583 : 664248 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
10584 : : {
10585 : : /*
10586 : : * Clear any dump-request bits for components that don't exist for this
10587 : : * object. (This makes it safe to initially use DUMP_COMPONENT_ALL as the
10588 : : * request for every kind of object.)
10589 : : */
10590 : 664248 : dobj->dump &= dobj->components;
10591 : :
10592 : : /* Now, short-circuit if there's nothing to be done here. */
10593 [ + + ]: 664248 : if (dobj->dump == 0)
10594 : 605568 : return;
10595 : :
7435 10596 [ + + + + : 58680 : switch (dobj->objType)
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + - ]
10597 : : {
10598 : 397 : case DO_NAMESPACE:
1159 peter@eisentraut.org 10599 : 397 : dumpNamespace(fout, (const NamespaceInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10600 : 397 : break;
4814 10601 : 19 : case DO_EXTENSION:
1159 peter@eisentraut.org 10602 : 19 : dumpExtension(fout, (const ExtensionInfo *) dobj);
4814 tgl@sss.pgh.pa.us 10603 : 19 : break;
7435 10604 : 650 : case DO_TYPE:
1159 peter@eisentraut.org 10605 : 650 : dumpType(fout, (const TypeInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10606 : 650 : break;
6618 10607 : 74 : case DO_SHELL_TYPE:
1159 peter@eisentraut.org 10608 : 74 : dumpShellType(fout, (const ShellTypeInfo *) dobj);
6618 tgl@sss.pgh.pa.us 10609 : 74 : break;
7435 10610 : 1789 : case DO_FUNC:
1159 peter@eisentraut.org 10611 : 1789 : dumpFunc(fout, (const FuncInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10612 : 1789 : break;
10613 : 293 : case DO_AGG:
1159 peter@eisentraut.org 10614 : 293 : dumpAgg(fout, (const AggInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10615 : 293 : break;
10616 : 907 : case DO_OPERATOR:
1159 peter@eisentraut.org 10617 : 907 : dumpOpr(fout, (const OprInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10618 : 907 : break;
2944 alvherre@alvh.no-ip. 10619 : 82 : case DO_ACCESS_METHOD:
1159 peter@eisentraut.org 10620 : 82 : dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
2944 alvherre@alvh.no-ip. 10621 : 82 : break;
7435 tgl@sss.pgh.pa.us 10622 : 309 : case DO_OPCLASS:
1159 peter@eisentraut.org 10623 : 309 : dumpOpclass(fout, (const OpclassInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10624 : 309 : break;
6291 10625 : 259 : case DO_OPFAMILY:
1159 peter@eisentraut.org 10626 : 259 : dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
6291 tgl@sss.pgh.pa.us 10627 : 259 : break;
4810 peter_e@gmx.net 10628 : 1547 : case DO_COLLATION:
1159 peter@eisentraut.org 10629 : 1547 : dumpCollation(fout, (const CollInfo *) dobj);
4810 peter_e@gmx.net 10630 : 1547 : break;
7435 tgl@sss.pgh.pa.us 10631 : 167 : case DO_CONVERSION:
1159 peter@eisentraut.org 10632 : 167 : dumpConversion(fout, (const ConvInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10633 : 167 : break;
10634 : 25269 : case DO_TABLE:
1159 peter@eisentraut.org 10635 : 25269 : dumpTable(fout, (const TableInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10636 : 25269 : break;
1189 10637 : 1259 : case DO_TABLE_ATTACH:
1159 peter@eisentraut.org 10638 : 1259 : dumpTableAttach(fout, (const TableAttachInfo *) dobj);
1189 tgl@sss.pgh.pa.us 10639 : 1259 : break;
7435 10640 : 818 : case DO_ATTRDEF:
1159 peter@eisentraut.org 10641 : 818 : dumpAttrDef(fout, (const AttrDefInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10642 : 818 : break;
10643 : 2216 : case DO_INDEX:
1159 peter@eisentraut.org 10644 : 2216 : dumpIndex(fout, (const IndxInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10645 : 2216 : break;
2277 alvherre@alvh.no-ip. 10646 : 567 : case DO_INDEX_ATTACH:
1159 peter@eisentraut.org 10647 : 567 : dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
2277 alvherre@alvh.no-ip. 10648 : 567 : break;
2578 10649 : 136 : case DO_STATSEXT:
1159 peter@eisentraut.org 10650 : 136 : dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
2578 alvherre@alvh.no-ip. 10651 : 136 : break;
4060 kgrittn@postgresql.o 10652 : 365 : case DO_REFRESH_MATVIEW:
1159 peter@eisentraut.org 10653 : 365 : refreshMatViewData(fout, (const TableDataInfo *) dobj);
4060 kgrittn@postgresql.o 10654 : 365 : break;
7435 tgl@sss.pgh.pa.us 10655 : 940 : case DO_RULE:
1159 peter@eisentraut.org 10656 : 940 : dumpRule(fout, (const RuleInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10657 : 940 : break;
10658 : 508 : case DO_TRIGGER:
1159 peter@eisentraut.org 10659 : 508 : dumpTrigger(fout, (const TriggerInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10660 : 508 : break;
4288 rhaas@postgresql.org 10661 : 43 : case DO_EVENT_TRIGGER:
1159 peter@eisentraut.org 10662 : 43 : dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
4288 rhaas@postgresql.org 10663 : 43 : break;
7435 tgl@sss.pgh.pa.us 10664 : 1855 : case DO_CONSTRAINT:
1159 peter@eisentraut.org 10665 : 1855 : dumpConstraint(fout, (const ConstraintInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10666 : 1855 : break;
10667 : 178 : case DO_FK_CONSTRAINT:
1159 peter@eisentraut.org 10668 : 178 : dumpConstraint(fout, (const ConstraintInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10669 : 178 : break;
10670 : 84 : case DO_PROCLANG:
1159 peter@eisentraut.org 10671 : 84 : dumpProcLang(fout, (const ProcLangInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10672 : 84 : break;
10673 : 68 : case DO_CAST:
1159 peter@eisentraut.org 10674 : 68 : dumpCast(fout, (const CastInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10675 : 68 : break;
3276 peter_e@gmx.net 10676 : 43 : case DO_TRANSFORM:
1159 peter@eisentraut.org 10677 : 43 : dumpTransform(fout, (const TransformInfo *) dobj);
3276 peter_e@gmx.net 10678 : 43 : break;
2791 10679 : 385 : case DO_SEQUENCE_SET:
1159 peter@eisentraut.org 10680 : 385 : dumpSequenceData(fout, (const TableDataInfo *) dobj);
2791 peter_e@gmx.net 10681 : 385 : break;
7435 tgl@sss.pgh.pa.us 10682 : 3616 : case DO_TABLE_DATA:
1159 peter@eisentraut.org 10683 : 3616 : dumpTableData(fout, (const TableDataInfo *) dobj);
7435 tgl@sss.pgh.pa.us 10684 : 3616 : break;
5565 10685 : 11878 : case DO_DUMMY_TYPE:
10686 : : /* table rowtypes and array types are never dumped separately */
7347 10687 : 11878 : break;
6081 10688 : 40 : case DO_TSPARSER:
1159 peter@eisentraut.org 10689 : 40 : dumpTSParser(fout, (const TSParserInfo *) dobj);
6081 tgl@sss.pgh.pa.us 10690 : 40 : break;
10691 : 113 : case DO_TSDICT:
1159 peter@eisentraut.org 10692 : 113 : dumpTSDictionary(fout, (const TSDictInfo *) dobj);
6081 tgl@sss.pgh.pa.us 10693 : 113 : break;
10694 : 44 : case DO_TSTEMPLATE:
1159 peter@eisentraut.org 10695 : 44 : dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
6081 tgl@sss.pgh.pa.us 10696 : 44 : break;
10697 : 88 : case DO_TSCONFIG:
1159 peter@eisentraut.org 10698 : 88 : dumpTSConfig(fout, (const TSConfigInfo *) dobj);
6081 tgl@sss.pgh.pa.us 10699 : 88 : break;
5595 peter_e@gmx.net 10700 : 53 : case DO_FDW:
1159 peter@eisentraut.org 10701 : 53 : dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
5595 peter_e@gmx.net 10702 : 53 : break;
10703 : 57 : case DO_FOREIGN_SERVER:
1159 peter@eisentraut.org 10704 : 57 : dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
5595 peter_e@gmx.net 10705 : 57 : break;
5305 tgl@sss.pgh.pa.us 10706 : 154 : case DO_DEFAULT_ACL:
1159 peter@eisentraut.org 10707 : 154 : dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
5305 tgl@sss.pgh.pa.us 10708 : 154 : break;
496 peter@eisentraut.org 10709 : 79 : case DO_LARGE_OBJECT:
10710 : 79 : dumpLO(fout, (const LoInfo *) dobj);
5169 tgl@sss.pgh.pa.us 10711 : 79 : break;
496 peter@eisentraut.org 10712 : 79 : case DO_LARGE_OBJECT_DATA:
2930 sfrost@snowman.net 10713 [ + - ]: 79 : if (dobj->dump & DUMP_COMPONENT_DATA)
10714 : : {
10715 : : LoInfo *loinfo;
10716 : : TocEntry *te;
10717 : :
13 tgl@sss.pgh.pa.us 10718 :GNC 79 : loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
10719 [ - + ]: 79 : if (loinfo == NULL)
13 tgl@sss.pgh.pa.us 10720 :UNC 0 : pg_fatal("missing metadata for large objects \"%s\"",
10721 : : dobj->name);
10722 : :
2039 tgl@sss.pgh.pa.us 10723 :CBC 79 : te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
1899 alvherre@alvh.no-ip. 10724 : 79 : ARCHIVE_OPTS(.tag = dobj->name,
10725 : : .owner = loinfo->rolname,
10726 : : .description = "BLOBS",
10727 : : .section = SECTION_DATA,
10728 : : .deps = dobj->dependencies,
10729 : : .nDeps = dobj->nDeps,
10730 : : .dumpFn = dumpLOs,
10731 : : .dumpArg = loinfo));
10732 : :
10733 : : /*
10734 : : * Set the TocEntry's dataLength in case we are doing a
10735 : : * parallel dump and want to order dump jobs by table size.
10736 : : * (We need some size estimate for every TocEntry with a
10737 : : * DataDumper function.) We don't currently have any cheap
10738 : : * way to estimate the size of LOs, but fortunately it doesn't
10739 : : * matter too much as long as we get large batches of LOs
10740 : : * processed reasonably early. Assume 8K per blob.
10741 : : */
13 tgl@sss.pgh.pa.us 10742 :GNC 79 : te->dataLength = loinfo->numlos * (pgoff_t) 8192;
10743 : : }
7347 tgl@sss.pgh.pa.us 10744 :CBC 79 : break;
3426 sfrost@snowman.net 10745 : 340 : case DO_POLICY:
1159 peter@eisentraut.org 10746 : 340 : dumpPolicy(fout, (const PolicyInfo *) dobj);
3495 sfrost@snowman.net 10747 : 340 : break;
2642 peter_e@gmx.net 10748 : 153 : case DO_PUBLICATION:
1159 peter@eisentraut.org 10749 : 153 : dumpPublication(fout, (const PublicationInfo *) dobj);
2642 peter_e@gmx.net 10750 : 153 : break;
10751 : 256 : case DO_PUBLICATION_REL:
1159 peter@eisentraut.org 10752 : 256 : dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
2642 peter_e@gmx.net 10753 : 256 : break;
887 akapila@postgresql.o 10754 : 75 : case DO_PUBLICATION_TABLE_IN_SCHEMA:
900 10755 : 75 : dumpPublicationNamespace(fout,
10756 : : (const PublicationSchemaInfo *) dobj);
10757 : 75 : break;
2642 peter_e@gmx.net 10758 : 116 : case DO_SUBSCRIPTION:
1159 peter@eisentraut.org 10759 : 116 : dumpSubscription(fout, (const SubscriptionInfo *) dobj);
2642 peter_e@gmx.net 10760 : 116 : break;
103 akapila@postgresql.o 10761 :GNC 2 : case DO_SUBSCRIPTION_REL:
10762 : 2 : dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
10763 : 2 : break;
4311 tgl@sss.pgh.pa.us 10764 :CBC 310 : case DO_PRE_DATA_BOUNDARY:
10765 : : case DO_POST_DATA_BOUNDARY:
10766 : : /* never dumped, nothing to do */
10767 : 310 : break;
10768 : : }
10769 : : }
10770 : :
10771 : : /*
10772 : : * dumpNamespace
10773 : : * writes out to fout the queries to recreate a user-defined namespace
10774 : : */
10775 : : static void
1159 peter@eisentraut.org 10776 : 397 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
10777 : : {
3014 tgl@sss.pgh.pa.us 10778 : 397 : DumpOptions *dopt = fout->dopt;
10779 : : PQExpBuffer q;
10780 : : PQExpBuffer delq;
10781 : : char *qnspname;
10782 : :
10783 : : /* Do nothing in data-only dump */
860 10784 [ + + ]: 397 : if (dopt->dataOnly)
7435 10785 : 16 : return;
10786 : :
10787 : 381 : q = createPQExpBuffer();
10788 : 381 : delq = createPQExpBuffer();
10789 : :
4524 bruce@momjian.us 10790 : 381 : qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
10791 : :
1021 noah@leadboat.com 10792 [ + + ]: 381 : if (nspinfo->create)
10793 : : {
10794 : 256 : appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
10795 : 256 : appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
10796 : : }
10797 : : else
10798 : : {
10799 : : /* see selectDumpableNamespace() */
10800 : 125 : appendPQExpBufferStr(delq,
10801 : : "-- *not* dropping schema, since initdb creates it\n");
10802 : 125 : appendPQExpBufferStr(q,
10803 : : "-- *not* creating schema, since initdb creates it\n");
10804 : : }
10805 : :
3470 alvherre@alvh.no-ip. 10806 [ + + ]: 381 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 10807 : 40 : binary_upgrade_extension_member(q, &nspinfo->dobj,
10808 : : "SCHEMA", qnspname, NULL);
10809 : :
2930 sfrost@snowman.net 10810 [ + + ]: 381 : if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10811 : 165 : ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 10812 : 165 : ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
10813 : : .owner = nspinfo->rolname,
10814 : : .description = "SCHEMA",
10815 : : .section = SECTION_PRE_DATA,
10816 : : .createStmt = q->data,
10817 : : .dropStmt = delq->data));
10818 : :
10819 : : /* Dump Schema Comments and Security Labels */
2930 sfrost@snowman.net 10820 [ + + ]: 381 : if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10821 : : {
1021 noah@leadboat.com 10822 : 128 : const char *initdb_comment = NULL;
10823 : :
10824 [ + + + + ]: 128 : if (!nspinfo->create && strcmp(qnspname, "public") == 0)
852 tgl@sss.pgh.pa.us 10825 : 113 : initdb_comment = "standard public schema";
1021 noah@leadboat.com 10826 : 128 : dumpCommentExtended(fout, "SCHEMA", qnspname,
10827 : 128 : NULL, nspinfo->rolname,
10828 : 128 : nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
10829 : : initdb_comment);
10830 : : }
10831 : :
2930 sfrost@snowman.net 10832 [ - + ]: 381 : if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 10833 :UBC 0 : dumpSecLabel(fout, "SCHEMA", qnspname,
2930 sfrost@snowman.net 10834 : 0 : NULL, nspinfo->rolname,
10835 : 0 : nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
10836 : :
2930 sfrost@snowman.net 10837 [ + + ]:CBC 381 : if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
1373 tgl@sss.pgh.pa.us 10838 : 295 : dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
10839 : : qnspname, NULL, NULL,
13 tgl@sss.pgh.pa.us 10840 :GNC 295 : NULL, nspinfo->rolname, &nspinfo->dacl);
10841 : :
7435 tgl@sss.pgh.pa.us 10842 :CBC 381 : free(qnspname);
10843 : :
8010 10844 : 381 : destroyPQExpBuffer(q);
10845 : 381 : destroyPQExpBuffer(delq);
10846 : : }
10847 : :
10848 : : /*
10849 : : * dumpExtension
10850 : : * writes out to fout the queries to recreate an extension
10851 : : */
10852 : : static void
1159 peter@eisentraut.org 10853 : 19 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
10854 : : {
3014 tgl@sss.pgh.pa.us 10855 : 19 : DumpOptions *dopt = fout->dopt;
10856 : : PQExpBuffer q;
10857 : : PQExpBuffer delq;
10858 : : char *qextname;
10859 : :
10860 : : /* Do nothing in data-only dump */
860 10861 [ + + ]: 19 : if (dopt->dataOnly)
4814 10862 : 1 : return;
10863 : :
10864 : 18 : q = createPQExpBuffer();
10865 : 18 : delq = createPQExpBuffer();
10866 : :
4524 bruce@momjian.us 10867 : 18 : qextname = pg_strdup(fmtId(extinfo->dobj.name));
10868 : :
4814 tgl@sss.pgh.pa.us 10869 : 18 : appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
10870 : :
3470 alvherre@alvh.no-ip. 10871 [ + + ]: 18 : if (!dopt->binary_upgrade)
10872 : : {
10873 : : /*
10874 : : * In a regular dump, we simply create the extension, intentionally
10875 : : * not specifying a version, so that the destination installation's
10876 : : * default version is used.
10877 : : *
10878 : : * Use of IF NOT EXISTS here is unlike our behavior for other object
10879 : : * types; but there are various scenarios in which it's convenient to
10880 : : * manually create the desired extension before restoring, so we
10881 : : * prefer to allow it to exist already.
10882 : : */
4790 tgl@sss.pgh.pa.us 10883 : 17 : appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
4813 10884 : 17 : qextname, fmtId(extinfo->namespace));
10885 : : }
10886 : : else
10887 : : {
10888 : : /*
10889 : : * In binary-upgrade mode, it's critical to reproduce the state of the
10890 : : * database exactly, so our procedure is to create an empty extension,
10891 : : * restore all the contained objects normally, and add them to the
10892 : : * extension one by one. This function performs just the first of
10893 : : * those steps. binary_upgrade_extension_member() takes care of
10894 : : * adding member objects as they're created.
10895 : : */
10896 : : int i;
10897 : : int n;
10898 : :
3800 heikki.linnakangas@i 10899 : 1 : appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
10900 : :
10901 : : /*
10902 : : * We unconditionally create the extension, so we must drop it if it
10903 : : * exists. This could happen if the user deleted 'plpgsql' and then
10904 : : * readded it, causing its oid to be greater than g_last_builtin_oid.
10905 : : */
4302 bruce@momjian.us 10906 : 1 : appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
10907 : :
3800 heikki.linnakangas@i 10908 : 1 : appendPQExpBufferStr(q,
10909 : : "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
4813 tgl@sss.pgh.pa.us 10910 : 1 : appendStringLiteralAH(q, extinfo->dobj.name, fout);
3800 heikki.linnakangas@i 10911 : 1 : appendPQExpBufferStr(q, ", ");
4813 tgl@sss.pgh.pa.us 10912 : 1 : appendStringLiteralAH(q, extinfo->namespace, fout);
3800 heikki.linnakangas@i 10913 : 1 : appendPQExpBufferStr(q, ", ");
4813 tgl@sss.pgh.pa.us 10914 [ + - ]: 1 : appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
4811 10915 : 1 : appendStringLiteralAH(q, extinfo->extversion, fout);
3800 heikki.linnakangas@i 10916 : 1 : appendPQExpBufferStr(q, ", ");
10917 : :
10918 : : /*
10919 : : * Note that we're pushing extconfig (an OID array) back into
10920 : : * pg_extension exactly as-is. This is OK because pg_class OIDs are
10921 : : * preserved in binary upgrade.
10922 : : */
4813 tgl@sss.pgh.pa.us 10923 [ + - ]: 1 : if (strlen(extinfo->extconfig) > 2)
10924 : 1 : appendStringLiteralAH(q, extinfo->extconfig, fout);
10925 : : else
3800 heikki.linnakangas@i 10926 :UBC 0 : appendPQExpBufferStr(q, "NULL");
3800 heikki.linnakangas@i 10927 :CBC 1 : appendPQExpBufferStr(q, ", ");
4813 tgl@sss.pgh.pa.us 10928 [ + - ]: 1 : if (strlen(extinfo->extcondition) > 2)
10929 : 1 : appendStringLiteralAH(q, extinfo->extcondition, fout);
10930 : : else
3800 heikki.linnakangas@i 10931 :UBC 0 : appendPQExpBufferStr(q, "NULL");
3800 heikki.linnakangas@i 10932 :CBC 1 : appendPQExpBufferStr(q, ", ");
10933 : 1 : appendPQExpBufferStr(q, "ARRAY[");
4813 tgl@sss.pgh.pa.us 10934 : 1 : n = 0;
10935 [ + + ]: 2 : for (i = 0; i < extinfo->dobj.nDeps; i++)
10936 : : {
10937 : : DumpableObject *extobj;
10938 : :
10939 : 1 : extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
10940 [ + - - + ]: 1 : if (extobj && extobj->objType == DO_EXTENSION)
10941 : : {
4813 tgl@sss.pgh.pa.us 10942 [ # # ]:UBC 0 : if (n++ > 0)
3800 heikki.linnakangas@i 10943 : 0 : appendPQExpBufferChar(q, ',');
4813 tgl@sss.pgh.pa.us 10944 : 0 : appendStringLiteralAH(q, extobj->name, fout);
10945 : : }
10946 : : }
3800 heikki.linnakangas@i 10947 :CBC 1 : appendPQExpBufferStr(q, "]::pg_catalog.text[]");
10948 : 1 : appendPQExpBufferStr(q, ");\n");
10949 : : }
10950 : :
2930 sfrost@snowman.net 10951 [ + - ]: 18 : if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10952 : 18 : ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 10953 : 18 : ARCHIVE_OPTS(.tag = extinfo->dobj.name,
10954 : : .description = "EXTENSION",
10955 : : .section = SECTION_PRE_DATA,
10956 : : .createStmt = q->data,
10957 : : .dropStmt = delq->data));
10958 : :
10959 : : /* Dump Extension Comments and Security Labels */
2930 sfrost@snowman.net 10960 [ + - ]: 18 : if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 10961 : 18 : dumpComment(fout, "EXTENSION", qextname,
10962 : : NULL, "",
2930 sfrost@snowman.net 10963 : 18 : extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10964 : :
10965 [ - + ]: 18 : if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 10966 :UBC 0 : dumpSecLabel(fout, "EXTENSION", qextname,
10967 : : NULL, "",
2930 sfrost@snowman.net 10968 : 0 : extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10969 : :
4814 tgl@sss.pgh.pa.us 10970 :CBC 18 : free(qextname);
10971 : :
10972 : 18 : destroyPQExpBuffer(q);
10973 : 18 : destroyPQExpBuffer(delq);
10974 : : }
10975 : :
10976 : : /*
10977 : : * dumpType
10978 : : * writes out to fout the queries to recreate a user-defined type
10979 : : */
10980 : : static void
1159 peter@eisentraut.org 10981 : 650 : dumpType(Archive *fout, const TypeInfo *tyinfo)
10982 : : {
3014 tgl@sss.pgh.pa.us 10983 : 650 : DumpOptions *dopt = fout->dopt;
10984 : :
10985 : : /* Do nothing in data-only dump */
860 10986 [ + + ]: 650 : if (dopt->dataOnly)
7435 10987 : 22 : return;
10988 : :
10989 : : /* Dump out in proper style */
5226 bruce@momjian.us 10990 [ + + ]: 628 : if (tyinfo->typtype == TYPTYPE_BASE)
3014 tgl@sss.pgh.pa.us 10991 : 141 : dumpBaseType(fout, tyinfo);
5226 bruce@momjian.us 10992 [ + + ]: 487 : else if (tyinfo->typtype == TYPTYPE_DOMAIN)
3014 tgl@sss.pgh.pa.us 10993 : 131 : dumpDomain(fout, tyinfo);
5226 bruce@momjian.us 10994 [ + + ]: 356 : else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
3014 tgl@sss.pgh.pa.us 10995 : 134 : dumpCompositeType(fout, tyinfo);
5226 bruce@momjian.us 10996 [ + + ]: 222 : else if (tyinfo->typtype == TYPTYPE_ENUM)
3014 tgl@sss.pgh.pa.us 10997 : 58 : dumpEnumType(fout, tyinfo);
4546 heikki.linnakangas@i 10998 [ + + ]: 164 : else if (tyinfo->typtype == TYPTYPE_RANGE)
3014 tgl@sss.pgh.pa.us 10999 : 98 : dumpRangeType(fout, tyinfo);
3176 11000 [ + - + + ]: 66 : else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
3014 11001 : 41 : dumpUndefinedType(fout, tyinfo);
11002 : : else
1840 peter@eisentraut.org 11003 : 25 : pg_log_warning("typtype of data type \"%s\" appears to be invalid",
11004 : : tyinfo->dobj.name);
11005 : : }
11006 : :
11007 : : /*
11008 : : * dumpEnumType
11009 : : * writes out to fout the queries to recreate a user-defined enum type
11010 : : */
11011 : : static void
1159 11012 : 58 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
11013 : : {
3014 tgl@sss.pgh.pa.us 11014 : 58 : DumpOptions *dopt = fout->dopt;
6222 11015 : 58 : PQExpBuffer q = createPQExpBuffer();
11016 : 58 : PQExpBuffer delq = createPQExpBuffer();
11017 : 58 : PQExpBuffer query = createPQExpBuffer();
11018 : : PGresult *res;
11019 : : int num,
11020 : : i;
11021 : : Oid enum_oid;
11022 : : char *qtypname;
11023 : : char *qualtypname;
11024 : : char *label;
11025 : : int i_enumlabel;
11026 : : int i_oid;
11027 : :
860 11028 [ + + ]: 58 : if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
11029 : : {
11030 : : /* Set up query for enum-specific details */
11031 : 43 : appendPQExpBufferStr(query,
11032 : : "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
11033 : : "SELECT oid, enumlabel "
11034 : : "FROM pg_catalog.pg_enum "
11035 : : "WHERE enumtypid = $1 "
11036 : : "ORDER BY enumsortorder");
11037 : :
11038 : 43 : ExecuteSqlStatement(fout, query->data);
11039 : :
11040 : 43 : fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
11041 : : }
11042 : :
11043 : 58 : printfPQExpBuffer(query,
11044 : : "EXECUTE dumpEnumType('%u')",
11045 : 58 : tyinfo->dobj.catId.oid);
11046 : :
4450 rhaas@postgresql.org 11047 : 58 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11048 : :
6222 tgl@sss.pgh.pa.us 11049 : 58 : num = PQntuples(res);
11050 : :
4144 11051 : 58 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2239 11052 : 58 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11053 : :
11054 : : /*
11055 : : * CASCADE shouldn't be required here as for normal types since the I/O
11056 : : * functions are generic and do not get dropped.
11057 : : */
11058 : 58 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11059 : :
3470 alvherre@alvh.no-ip. 11060 [ + + ]: 58 : if (dopt->binary_upgrade)
4450 rhaas@postgresql.org 11061 : 5 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2388 tgl@sss.pgh.pa.us 11062 : 5 : tyinfo->dobj.catId.oid,
11063 : : false, false);
11064 : :
5222 bruce@momjian.us 11065 : 58 : appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
11066 : : qualtypname);
11067 : :
3470 alvherre@alvh.no-ip. 11068 [ + + ]: 58 : if (!dopt->binary_upgrade)
11069 : : {
961 dgustafsson@postgres 11070 : 53 : i_enumlabel = PQfnumber(res, "enumlabel");
11071 : :
11072 : : /* Labels with server-assigned oids */
5222 bruce@momjian.us 11073 [ + + ]: 378 : for (i = 0; i < num; i++)
11074 : : {
961 dgustafsson@postgres 11075 : 325 : label = PQgetvalue(res, i, i_enumlabel);
5222 bruce@momjian.us 11076 [ + + ]: 325 : if (i > 0)
3800 heikki.linnakangas@i 11077 : 272 : appendPQExpBufferChar(q, ',');
11078 : 325 : appendPQExpBufferStr(q, "\n ");
5222 bruce@momjian.us 11079 : 325 : appendStringLiteralAH(q, label, fout);
11080 : : }
11081 : : }
11082 : :
3800 heikki.linnakangas@i 11083 : 58 : appendPQExpBufferStr(q, "\n);\n");
11084 : :
3470 alvherre@alvh.no-ip. 11085 [ + + ]: 58 : if (dopt->binary_upgrade)
11086 : : {
961 dgustafsson@postgres 11087 : 5 : i_oid = PQfnumber(res, "oid");
11088 : 5 : i_enumlabel = PQfnumber(res, "enumlabel");
11089 : :
11090 : : /* Labels with dump-assigned (preserved) oids */
5222 bruce@momjian.us 11091 [ + + ]: 58 : for (i = 0; i < num; i++)
11092 : : {
961 dgustafsson@postgres 11093 : 53 : enum_oid = atooid(PQgetvalue(res, i, i_oid));
11094 : 53 : label = PQgetvalue(res, i, i_enumlabel);
11095 : :
5222 bruce@momjian.us 11096 [ + + ]: 53 : if (i == 0)
3800 heikki.linnakangas@i 11097 : 5 : appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
5222 bruce@momjian.us 11098 : 53 : appendPQExpBuffer(q,
11099 : : "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
11100 : : enum_oid);
2239 tgl@sss.pgh.pa.us 11101 : 53 : appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
5222 bruce@momjian.us 11102 : 53 : appendStringLiteralAH(q, label, fout);
3800 heikki.linnakangas@i 11103 : 53 : appendPQExpBufferStr(q, ";\n\n");
11104 : : }
11105 : : }
11106 : :
3470 alvherre@alvh.no-ip. 11107 [ + + ]: 58 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 11108 : 5 : binary_upgrade_extension_member(q, &tyinfo->dobj,
11109 : : "TYPE", qtypname,
11110 : 5 : tyinfo->dobj.namespace->dobj.name);
11111 : :
2930 sfrost@snowman.net 11112 [ + - ]: 58 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11113 : 58 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 11114 : 58 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11115 : : .namespace = tyinfo->dobj.namespace->dobj.name,
11116 : : .owner = tyinfo->rolname,
11117 : : .description = "TYPE",
11118 : : .section = SECTION_PRE_DATA,
11119 : : .createStmt = q->data,
11120 : : .dropStmt = delq->data));
11121 : :
11122 : : /* Dump Type Comments and Security Labels */
2930 sfrost@snowman.net 11123 [ + + ]: 58 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 11124 : 36 : dumpComment(fout, "TYPE", qtypname,
2930 sfrost@snowman.net 11125 : 36 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11126 : 36 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11127 : :
11128 [ - + ]: 58 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 11129 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
2930 sfrost@snowman.net 11130 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11131 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11132 : :
2930 sfrost@snowman.net 11133 [ + + ]:CBC 58 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1373 tgl@sss.pgh.pa.us 11134 : 36 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11135 : : qtypname, NULL,
2930 sfrost@snowman.net 11136 : 36 : tyinfo->dobj.namespace->dobj.name,
13 tgl@sss.pgh.pa.us 11137 :GNC 36 : NULL, tyinfo->rolname, &tyinfo->dacl);
11138 : :
4546 heikki.linnakangas@i 11139 :CBC 58 : PQclear(res);
11140 : 58 : destroyPQExpBuffer(q);
11141 : 58 : destroyPQExpBuffer(delq);
11142 : 58 : destroyPQExpBuffer(query);
2239 tgl@sss.pgh.pa.us 11143 : 58 : free(qtypname);
11144 : 58 : free(qualtypname);
4546 heikki.linnakangas@i 11145 : 58 : }
11146 : :
11147 : : /*
11148 : : * dumpRangeType
11149 : : * writes out to fout the queries to recreate a user-defined range type
11150 : : */
11151 : : static void
1159 peter@eisentraut.org 11152 : 98 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
11153 : : {
3014 tgl@sss.pgh.pa.us 11154 : 98 : DumpOptions *dopt = fout->dopt;
4546 heikki.linnakangas@i 11155 : 98 : PQExpBuffer q = createPQExpBuffer();
11156 : 98 : PQExpBuffer delq = createPQExpBuffer();
11157 : 98 : PQExpBuffer query = createPQExpBuffer();
11158 : : PGresult *res;
11159 : : Oid collationOid;
11160 : : char *qtypname;
11161 : : char *qualtypname;
11162 : : char *procname;
11163 : :
860 tgl@sss.pgh.pa.us 11164 [ + + ]: 98 : if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
11165 : : {
11166 : : /* Set up query for range-specific details */
11167 : 42 : appendPQExpBufferStr(query,
11168 : : "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
11169 : :
11170 : 42 : appendPQExpBufferStr(query,
11171 : : "SELECT ");
11172 : :
11173 [ + - ]: 42 : if (fout->remoteVersion >= 140000)
11174 : 42 : appendPQExpBufferStr(query,
11175 : : "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
11176 : : else
860 tgl@sss.pgh.pa.us 11177 :UBC 0 : appendPQExpBufferStr(query,
11178 : : "NULL AS rngmultitype, ");
11179 : :
860 tgl@sss.pgh.pa.us 11180 :CBC 42 : appendPQExpBufferStr(query,
11181 : : "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
11182 : : "opc.opcname AS opcname, "
11183 : : "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
11184 : : " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
11185 : : "opc.opcdefault, "
11186 : : "CASE WHEN rngcollation = st.typcollation THEN 0 "
11187 : : " ELSE rngcollation END AS collation, "
11188 : : "rngcanonical, rngsubdiff "
11189 : : "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
11190 : : " pg_catalog.pg_opclass opc "
11191 : : "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
11192 : : "rngtypid = $1");
11193 : :
11194 : 42 : ExecuteSqlStatement(fout, query->data);
11195 : :
11196 : 42 : fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
11197 : : }
11198 : :
11199 : 98 : printfPQExpBuffer(query,
11200 : : "EXECUTE dumpRangeType('%u')",
4546 heikki.linnakangas@i 11201 : 98 : tyinfo->dobj.catId.oid);
11202 : :
4441 rhaas@postgresql.org 11203 : 98 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
11204 : :
4144 tgl@sss.pgh.pa.us 11205 : 98 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2239 11206 : 98 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11207 : :
11208 : : /*
11209 : : * CASCADE shouldn't be required here as for normal types since the I/O
11210 : : * functions are generic and do not get dropped.
11211 : : */
11212 : 98 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11213 : :
3470 alvherre@alvh.no-ip. 11214 [ + + ]: 98 : if (dopt->binary_upgrade)
2388 tgl@sss.pgh.pa.us 11215 : 6 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
11216 : 6 : tyinfo->dobj.catId.oid,
11217 : : false, true);
11218 : :
4546 heikki.linnakangas@i 11219 : 98 : appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
11220 : : qualtypname);
11221 : :
4529 tgl@sss.pgh.pa.us 11222 : 98 : appendPQExpBuffer(q, "\n subtype = %s",
11223 : : PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
11224 : :
1211 akorotkov@postgresql 11225 [ + - ]: 98 : if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
11226 : 98 : appendPQExpBuffer(q, ",\n multirange_type_name = %s",
11227 : : PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
11228 : :
11229 : : /* print subtype_opclass only if not default for subtype */
4529 tgl@sss.pgh.pa.us 11230 [ + + ]: 98 : if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
11231 : : {
4326 bruce@momjian.us 11232 : 36 : char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
11233 : 36 : char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
11234 : :
4529 tgl@sss.pgh.pa.us 11235 : 36 : appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
11236 : : fmtId(nspname));
3800 heikki.linnakangas@i 11237 : 36 : appendPQExpBufferStr(q, fmtId(opcname));
11238 : : }
11239 : :
4529 tgl@sss.pgh.pa.us 11240 : 98 : collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
4546 heikki.linnakangas@i 11241 [ + + ]: 98 : if (OidIsValid(collationOid))
11242 : : {
4529 tgl@sss.pgh.pa.us 11243 : 41 : CollInfo *coll = findCollationByOid(collationOid);
11244 : :
4546 heikki.linnakangas@i 11245 [ + - ]: 41 : if (coll)
2239 tgl@sss.pgh.pa.us 11246 : 41 : appendPQExpBuffer(q, ",\n collation = %s",
11247 : 41 : fmtQualifiedDumpable(coll));
11248 : : }
11249 : :
4529 11250 : 98 : procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
11251 [ + + ]: 98 : if (strcmp(procname, "-") != 0)
11252 : 3 : appendPQExpBuffer(q, ",\n canonical = %s", procname);
11253 : :
11254 : 98 : procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
11255 [ + + ]: 98 : if (strcmp(procname, "-") != 0)
11256 : 11 : appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
11257 : :
3800 heikki.linnakangas@i 11258 : 98 : appendPQExpBufferStr(q, "\n);\n");
11259 : :
3470 alvherre@alvh.no-ip. 11260 [ + + ]: 98 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 11261 : 6 : binary_upgrade_extension_member(q, &tyinfo->dobj,
11262 : : "TYPE", qtypname,
11263 : 6 : tyinfo->dobj.namespace->dobj.name);
11264 : :
2930 sfrost@snowman.net 11265 [ + - ]: 98 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11266 : 98 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 11267 : 98 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11268 : : .namespace = tyinfo->dobj.namespace->dobj.name,
11269 : : .owner = tyinfo->rolname,
11270 : : .description = "TYPE",
11271 : : .section = SECTION_PRE_DATA,
11272 : : .createStmt = q->data,
11273 : : .dropStmt = delq->data));
11274 : :
11275 : : /* Dump Type Comments and Security Labels */
2930 sfrost@snowman.net 11276 [ + + ]: 98 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 11277 : 42 : dumpComment(fout, "TYPE", qtypname,
2930 sfrost@snowman.net 11278 : 42 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11279 : 42 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11280 : :
11281 [ - + ]: 98 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 11282 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
2930 sfrost@snowman.net 11283 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11284 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11285 : :
2930 sfrost@snowman.net 11286 [ + + ]:CBC 98 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1373 tgl@sss.pgh.pa.us 11287 : 36 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11288 : : qtypname, NULL,
2930 sfrost@snowman.net 11289 : 36 : tyinfo->dobj.namespace->dobj.name,
13 tgl@sss.pgh.pa.us 11290 :GNC 36 : NULL, tyinfo->rolname, &tyinfo->dacl);
11291 : :
6222 tgl@sss.pgh.pa.us 11292 :CBC 98 : PQclear(res);
11293 : 98 : destroyPQExpBuffer(q);
11294 : 98 : destroyPQExpBuffer(delq);
11295 : 98 : destroyPQExpBuffer(query);
2239 11296 : 98 : free(qtypname);
11297 : 98 : free(qualtypname);
7435 11298 : 98 : }
11299 : :
11300 : : /*
11301 : : * dumpUndefinedType
11302 : : * writes out to fout the queries to recreate a !typisdefined type
11303 : : *
11304 : : * This is a shell type, but we use different terminology to distinguish
11305 : : * this case from where we have to emit a shell type definition to break
11306 : : * circular dependencies. An undefined type shouldn't ever have anything
11307 : : * depending on it.
11308 : : */
11309 : : static void
1159 peter@eisentraut.org 11310 : 41 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
11311 : : {
3014 tgl@sss.pgh.pa.us 11312 : 41 : DumpOptions *dopt = fout->dopt;
3176 11313 : 41 : PQExpBuffer q = createPQExpBuffer();
11314 : 41 : PQExpBuffer delq = createPQExpBuffer();
11315 : : char *qtypname;
11316 : : char *qualtypname;
11317 : :
11318 : 41 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2239 11319 : 41 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11320 : :
11321 : 41 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11322 : :
3176 11323 [ + + ]: 41 : if (dopt->binary_upgrade)
2388 11324 : 2 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
11325 : 2 : tyinfo->dobj.catId.oid,
11326 : : false, false);
11327 : :
3176 11328 : 41 : appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11329 : : qualtypname);
11330 : :
11331 [ + + ]: 41 : if (dopt->binary_upgrade)
2239 11332 : 2 : binary_upgrade_extension_member(q, &tyinfo->dobj,
11333 : : "TYPE", qtypname,
11334 : 2 : tyinfo->dobj.namespace->dobj.name);
11335 : :
2930 sfrost@snowman.net 11336 [ + - ]: 41 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11337 : 41 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 11338 : 41 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11339 : : .namespace = tyinfo->dobj.namespace->dobj.name,
11340 : : .owner = tyinfo->rolname,
11341 : : .description = "TYPE",
11342 : : .section = SECTION_PRE_DATA,
11343 : : .createStmt = q->data,
11344 : : .dropStmt = delq->data));
11345 : :
11346 : : /* Dump Type Comments and Security Labels */
2930 sfrost@snowman.net 11347 [ + + ]: 41 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 11348 : 36 : dumpComment(fout, "TYPE", qtypname,
2930 sfrost@snowman.net 11349 : 36 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11350 : 36 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11351 : :
11352 [ - + ]: 41 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 11353 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
2930 sfrost@snowman.net 11354 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11355 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11356 : :
2930 sfrost@snowman.net 11357 [ - + ]:CBC 41 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1373 tgl@sss.pgh.pa.us 11358 :UBC 0 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11359 : : qtypname, NULL,
2930 sfrost@snowman.net 11360 : 0 : tyinfo->dobj.namespace->dobj.name,
13 tgl@sss.pgh.pa.us 11361 :UNC 0 : NULL, tyinfo->rolname, &tyinfo->dacl);
11362 : :
3176 tgl@sss.pgh.pa.us 11363 :CBC 41 : destroyPQExpBuffer(q);
11364 : 41 : destroyPQExpBuffer(delq);
2239 11365 : 41 : free(qtypname);
11366 : 41 : free(qualtypname);
3176 11367 : 41 : }
11368 : :
11369 : : /*
11370 : : * dumpBaseType
11371 : : * writes out to fout the queries to recreate a user-defined base type
11372 : : */
11373 : : static void
1159 peter@eisentraut.org 11374 : 141 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
11375 : : {
3014 tgl@sss.pgh.pa.us 11376 : 141 : DumpOptions *dopt = fout->dopt;
8010 11377 : 141 : PQExpBuffer q = createPQExpBuffer();
11378 : 141 : PQExpBuffer delq = createPQExpBuffer();
11379 : 141 : PQExpBuffer query = createPQExpBuffer();
11380 : : PGresult *res;
11381 : : char *qtypname;
11382 : : char *qualtypname;
11383 : : char *typlen;
11384 : : char *typinput;
11385 : : char *typoutput;
11386 : : char *typreceive;
11387 : : char *typsend;
11388 : : char *typmodin;
11389 : : char *typmodout;
11390 : : char *typanalyze;
11391 : : char *typsubscript;
11392 : : Oid typreceiveoid;
11393 : : Oid typsendoid;
11394 : : Oid typmodinoid;
11395 : : Oid typmodoutoid;
11396 : : Oid typanalyzeoid;
11397 : : Oid typsubscriptoid;
11398 : : char *typcategory;
11399 : : char *typispreferred;
11400 : : char *typdelim;
11401 : : char *typbyval;
11402 : : char *typalign;
11403 : : char *typstorage;
11404 : : char *typcollatable;
11405 : : char *typdefault;
6627 11406 : 141 : bool typdefault_is_literal = false;
11407 : :
860 11408 [ + + ]: 141 : if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
11409 : : {
11410 : : /* Set up query for type-specific details */
1225 11411 : 42 : appendPQExpBufferStr(query,
11412 : : "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
11413 : : "SELECT typlen, "
11414 : : "typinput, typoutput, typreceive, typsend, "
11415 : : "typreceive::pg_catalog.oid AS typreceiveoid, "
11416 : : "typsend::pg_catalog.oid AS typsendoid, "
11417 : : "typanalyze, "
11418 : : "typanalyze::pg_catalog.oid AS typanalyzeoid, "
11419 : : "typdelim, typbyval, typalign, typstorage, "
11420 : : "typmodin, typmodout, "
11421 : : "typmodin::pg_catalog.oid AS typmodinoid, "
11422 : : "typmodout::pg_catalog.oid AS typmodoutoid, "
11423 : : "typcategory, typispreferred, "
11424 : : "(typcollation <> 0) AS typcollatable, "
11425 : : "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
11426 : :
860 11427 [ + - ]: 42 : if (fout->remoteVersion >= 140000)
11428 : 42 : appendPQExpBufferStr(query,
11429 : : "typsubscript, "
11430 : : "typsubscript::pg_catalog.oid AS typsubscriptoid ");
11431 : : else
860 tgl@sss.pgh.pa.us 11432 :UBC 0 : appendPQExpBufferStr(query,
11433 : : "'-' AS typsubscript, 0 AS typsubscriptoid ");
11434 : :
860 tgl@sss.pgh.pa.us 11435 :CBC 42 : appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
11436 : : "WHERE oid = $1");
11437 : :
11438 : 42 : ExecuteSqlStatement(fout, query->data);
11439 : :
11440 : 42 : fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
11441 : : }
11442 : :
11443 : 141 : printfPQExpBuffer(query,
11444 : : "EXECUTE dumpBaseType('%u')",
1225 11445 : 141 : tyinfo->dobj.catId.oid);
11446 : :
4441 rhaas@postgresql.org 11447 : 141 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
11448 : :
8010 tgl@sss.pgh.pa.us 11449 : 141 : typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
11450 : 141 : typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
11451 : 141 : typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
7647 11452 : 141 : typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
11453 : 141 : typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
6315 11454 : 141 : typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
11455 : 141 : typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
7367 11456 : 141 : typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
1222 11457 : 141 : typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
7435 11458 : 141 : typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
11459 : 141 : typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
6315 11460 : 141 : typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
11461 : 141 : typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
7367 11462 : 141 : typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
1222 11463 : 141 : typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
5737 11464 : 141 : typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
11465 : 141 : typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
8010 11466 : 141 : typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
11467 : 141 : typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
11468 : 141 : typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
11469 : 141 : typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
4793 peter_e@gmx.net 11470 : 141 : typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
6627 tgl@sss.pgh.pa.us 11471 [ - + ]: 141 : if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6627 tgl@sss.pgh.pa.us 11472 :UBC 0 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6627 tgl@sss.pgh.pa.us 11473 [ + + ]:CBC 141 : else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
11474 : : {
11475 : 46 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6402 bruce@momjian.us 11476 : 46 : typdefault_is_literal = true; /* it needs quotes */
11477 : : }
11478 : : else
6627 tgl@sss.pgh.pa.us 11479 : 95 : typdefault = NULL;
11480 : :
4144 11481 : 141 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2239 11482 : 141 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11483 : :
11484 : : /*
11485 : : * The reason we include CASCADE is that the circular dependency between
11486 : : * the type and its I/O functions makes it impossible to drop the type any
11487 : : * other way.
11488 : : */
11489 : 141 : appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
11490 : :
11491 : : /*
11492 : : * We might already have a shell type, but setting pg_type_oid is
11493 : : * harmless, and in any case we'd better set the array type OID.
11494 : : */
3470 alvherre@alvh.no-ip. 11495 [ + + ]: 141 : if (dopt->binary_upgrade)
4450 rhaas@postgresql.org 11496 : 8 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2388 tgl@sss.pgh.pa.us 11497 : 8 : tyinfo->dobj.catId.oid,
11498 : : false, false);
11499 : :
8010 11500 : 141 : appendPQExpBuffer(q,
11501 : : "CREATE TYPE %s (\n"
11502 : : " INTERNALLENGTH = %s",
11503 : : qualtypname,
7935 peter_e@gmx.net 11504 [ + + ]: 141 : (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
11505 : :
11506 : : /* regproc result is sufficiently quoted already */
2741 tgl@sss.pgh.pa.us 11507 : 141 : appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
11508 : 141 : appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
11509 [ + + ]: 141 : if (OidIsValid(typreceiveoid))
11510 : 68 : appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
11511 [ + + ]: 141 : if (OidIsValid(typsendoid))
11512 : 68 : appendPQExpBuffer(q, ",\n SEND = %s", typsend);
11513 [ + + ]: 141 : if (OidIsValid(typmodinoid))
11514 : 15 : appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
11515 [ + + ]: 141 : if (OidIsValid(typmodoutoid))
11516 : 15 : appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
11517 [ + + ]: 141 : if (OidIsValid(typanalyzeoid))
11518 : 1 : appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
11519 : :
4793 peter_e@gmx.net 11520 [ + + ]: 141 : if (strcmp(typcollatable, "t") == 0)
3800 heikki.linnakangas@i 11521 : 10 : appendPQExpBufferStr(q, ",\n COLLATABLE = true");
11522 : :
8010 tgl@sss.pgh.pa.us 11523 [ + + ]: 141 : if (typdefault != NULL)
11524 : : {
3800 heikki.linnakangas@i 11525 : 46 : appendPQExpBufferStr(q, ",\n DEFAULT = ");
6627 tgl@sss.pgh.pa.us 11526 [ + - ]: 46 : if (typdefault_is_literal)
6531 11527 : 46 : appendStringLiteralAH(q, typdefault, fout);
11528 : : else
6627 tgl@sss.pgh.pa.us 11529 :UBC 0 : appendPQExpBufferStr(q, typdefault);
11530 : : }
11531 : :
1222 tgl@sss.pgh.pa.us 11532 [ + + ]:CBC 141 : if (OidIsValid(typsubscriptoid))
11533 : 13 : appendPQExpBuffer(q, ",\n SUBSCRIPT = %s", typsubscript);
11534 : :
5226 bruce@momjian.us 11535 [ + + ]: 141 : if (OidIsValid(tyinfo->typelem))
949 tgl@sss.pgh.pa.us 11536 : 12 : appendPQExpBuffer(q, ",\n ELEMENT = %s",
11537 : 12 : getFormattedTypeName(fout, tyinfo->typelem,
11538 : : zeroIsError));
11539 : :
5737 11540 [ + + ]: 141 : if (strcmp(typcategory, "U") != 0)
11541 : : {
3800 heikki.linnakangas@i 11542 : 55 : appendPQExpBufferStr(q, ",\n CATEGORY = ");
5737 tgl@sss.pgh.pa.us 11543 : 55 : appendStringLiteralAH(q, typcategory, fout);
11544 : : }
11545 : :
11546 [ + + ]: 141 : if (strcmp(typispreferred, "t") == 0)
3800 heikki.linnakangas@i 11547 : 13 : appendPQExpBufferStr(q, ",\n PREFERRED = true");
11548 : :
7647 tgl@sss.pgh.pa.us 11549 [ + - + + ]: 141 : if (typdelim && strcmp(typdelim, ",") != 0)
11550 : : {
3800 heikki.linnakangas@i 11551 : 1 : appendPQExpBufferStr(q, ",\n DELIMITER = ");
6531 tgl@sss.pgh.pa.us 11552 : 1 : appendStringLiteralAH(q, typdelim, fout);
11553 : : }
11554 : :
1502 11555 [ + + ]: 141 : if (*typalign == TYPALIGN_CHAR)
3800 heikki.linnakangas@i 11556 : 4 : appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
1502 tgl@sss.pgh.pa.us 11557 [ + + ]: 137 : else if (*typalign == TYPALIGN_SHORT)
3800 heikki.linnakangas@i 11558 : 2 : appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
1502 tgl@sss.pgh.pa.us 11559 [ + + ]: 135 : else if (*typalign == TYPALIGN_INT)
3800 heikki.linnakangas@i 11560 : 100 : appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
1502 tgl@sss.pgh.pa.us 11561 [ + - ]: 35 : else if (*typalign == TYPALIGN_DOUBLE)
3800 heikki.linnakangas@i 11562 : 35 : appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
11563 : :
1502 tgl@sss.pgh.pa.us 11564 [ + + ]: 141 : if (*typstorage == TYPSTORAGE_PLAIN)
3800 heikki.linnakangas@i 11565 : 116 : appendPQExpBufferStr(q, ",\n STORAGE = plain");
1502 tgl@sss.pgh.pa.us 11566 [ - + ]: 25 : else if (*typstorage == TYPSTORAGE_EXTERNAL)
3800 heikki.linnakangas@i 11567 :UBC 0 : appendPQExpBufferStr(q, ",\n STORAGE = external");
1502 tgl@sss.pgh.pa.us 11568 [ + + ]:CBC 25 : else if (*typstorage == TYPSTORAGE_EXTENDED)
3800 heikki.linnakangas@i 11569 : 22 : appendPQExpBufferStr(q, ",\n STORAGE = extended");
1502 tgl@sss.pgh.pa.us 11570 [ + - ]: 3 : else if (*typstorage == TYPSTORAGE_MAIN)
3800 heikki.linnakangas@i 11571 : 3 : appendPQExpBufferStr(q, ",\n STORAGE = main");
11572 : :
8010 tgl@sss.pgh.pa.us 11573 [ + + ]: 141 : if (strcmp(typbyval, "t") == 0)
3800 heikki.linnakangas@i 11574 : 79 : appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
11575 : :
11576 : 141 : appendPQExpBufferStr(q, "\n);\n");
11577 : :
3470 alvherre@alvh.no-ip. 11578 [ + + ]: 141 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 11579 : 8 : binary_upgrade_extension_member(q, &tyinfo->dobj,
11580 : : "TYPE", qtypname,
11581 : 8 : tyinfo->dobj.namespace->dobj.name);
11582 : :
2930 sfrost@snowman.net 11583 [ + - ]: 141 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11584 : 141 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 11585 : 141 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11586 : : .namespace = tyinfo->dobj.namespace->dobj.name,
11587 : : .owner = tyinfo->rolname,
11588 : : .description = "TYPE",
11589 : : .section = SECTION_PRE_DATA,
11590 : : .createStmt = q->data,
11591 : : .dropStmt = delq->data));
11592 : :
11593 : : /* Dump Type Comments and Security Labels */
2930 sfrost@snowman.net 11594 [ + + ]: 141 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 11595 : 106 : dumpComment(fout, "TYPE", qtypname,
2930 sfrost@snowman.net 11596 : 106 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11597 : 106 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11598 : :
11599 [ - + ]: 141 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 11600 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
2930 sfrost@snowman.net 11601 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11602 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11603 : :
2930 sfrost@snowman.net 11604 [ + + ]:CBC 141 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1373 tgl@sss.pgh.pa.us 11605 : 36 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11606 : : qtypname, NULL,
2930 sfrost@snowman.net 11607 : 36 : tyinfo->dobj.namespace->dobj.name,
13 tgl@sss.pgh.pa.us 11608 :GNC 36 : NULL, tyinfo->rolname, &tyinfo->dacl);
11609 : :
8853 bruce@momjian.us 11610 :CBC 141 : PQclear(res);
8010 tgl@sss.pgh.pa.us 11611 : 141 : destroyPQExpBuffer(q);
11612 : 141 : destroyPQExpBuffer(delq);
8290 11613 : 141 : destroyPQExpBuffer(query);
2239 11614 : 141 : free(qtypname);
11615 : 141 : free(qualtypname);
8853 bruce@momjian.us 11616 : 141 : }
11617 : :
11618 : : /*
11619 : : * dumpDomain
11620 : : * writes out to fout the queries to recreate a user-defined domain
11621 : : */
11622 : : static void
1159 peter@eisentraut.org 11623 : 131 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
11624 : : {
3014 tgl@sss.pgh.pa.us 11625 : 131 : DumpOptions *dopt = fout->dopt;
8045 bruce@momjian.us 11626 : 131 : PQExpBuffer q = createPQExpBuffer();
11627 : 131 : PQExpBuffer delq = createPQExpBuffer();
11628 : 131 : PQExpBuffer query = createPQExpBuffer();
11629 : : PGresult *res;
11630 : : int i;
11631 : : char *qtypname;
11632 : : char *qualtypname;
11633 : : char *typnotnull;
11634 : : char *typdefn;
11635 : : char *typdefault;
11636 : : Oid typcollation;
6627 tgl@sss.pgh.pa.us 11637 : 131 : bool typdefault_is_literal = false;
11638 : :
860 11639 [ + + ]: 131 : if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
11640 : : {
11641 : : /* Set up query for domain-specific details */
11642 : 41 : appendPQExpBufferStr(query,
11643 : : "PREPARE dumpDomain(pg_catalog.oid) AS\n");
11644 : :
852 11645 : 41 : appendPQExpBufferStr(query, "SELECT t.typnotnull, "
11646 : : "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
11647 : : "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
11648 : : "t.typdefault, "
11649 : : "CASE WHEN t.typcollation <> u.typcollation "
11650 : : "THEN t.typcollation ELSE 0 END AS typcollation "
11651 : : "FROM pg_catalog.pg_type t "
11652 : : "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
11653 : : "WHERE t.oid = $1");
11654 : :
860 11655 : 41 : ExecuteSqlStatement(fout, query->data);
11656 : :
11657 : 41 : fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
11658 : : }
11659 : :
11660 : 131 : printfPQExpBuffer(query,
11661 : : "EXECUTE dumpDomain('%u')",
11662 : 131 : tyinfo->dobj.catId.oid);
11663 : :
4441 rhaas@postgresql.org 11664 : 131 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
11665 : :
8010 tgl@sss.pgh.pa.us 11666 : 131 : typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
11667 : 131 : typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
6627 11668 [ + + ]: 131 : if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
11669 : 41 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
11670 [ - + ]: 90 : else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
11671 : : {
7992 tgl@sss.pgh.pa.us 11672 :UBC 0 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6402 bruce@momjian.us 11673 : 0 : typdefault_is_literal = true; /* it needs quotes */
11674 : : }
11675 : : else
6627 tgl@sss.pgh.pa.us 11676 :CBC 90 : typdefault = NULL;
4784 11677 : 131 : typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
11678 : :
3470 alvherre@alvh.no-ip. 11679 [ + + ]: 131 : if (dopt->binary_upgrade)
4450 rhaas@postgresql.org 11680 : 20 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2388 tgl@sss.pgh.pa.us 11681 : 20 : tyinfo->dobj.catId.oid,
11682 : : true, /* force array type */
11683 : : false); /* force multirange type */
11684 : :
4144 11685 : 131 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2239 11686 : 131 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11687 : :
8045 bruce@momjian.us 11688 : 131 : appendPQExpBuffer(q,
11689 : : "CREATE DOMAIN %s AS %s",
11690 : : qualtypname,
11691 : : typdefn);
11692 : :
11693 : : /* Print collation only if different from base type's collation */
4784 tgl@sss.pgh.pa.us 11694 [ + + ]: 131 : if (OidIsValid(typcollation))
11695 : : {
11696 : : CollInfo *coll;
11697 : :
11698 : 36 : coll = findCollationByOid(typcollation);
11699 [ + - ]: 36 : if (coll)
2239 11700 : 36 : appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
11701 : : }
11702 : :
8010 11703 [ + + ]: 131 : if (typnotnull[0] == 't')
3800 heikki.linnakangas@i 11704 : 15 : appendPQExpBufferStr(q, " NOT NULL");
11705 : :
6627 tgl@sss.pgh.pa.us 11706 [ + + ]: 131 : if (typdefault != NULL)
11707 : : {
3800 heikki.linnakangas@i 11708 : 41 : appendPQExpBufferStr(q, " DEFAULT ");
6627 tgl@sss.pgh.pa.us 11709 [ - + ]: 41 : if (typdefault_is_literal)
6531 tgl@sss.pgh.pa.us 11710 :UBC 0 : appendStringLiteralAH(q, typdefault, fout);
11711 : : else
6627 tgl@sss.pgh.pa.us 11712 :CBC 41 : appendPQExpBufferStr(q, typdefault);
11713 : : }
11714 : :
7794 11715 : 131 : PQclear(res);
11716 : :
11717 : : /*
11718 : : * Add any CHECK constraints for the domain
11719 : : */
5226 bruce@momjian.us 11720 [ + + ]: 217 : for (i = 0; i < tyinfo->nDomChecks; i++)
11721 : : {
11722 : 86 : ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
11723 : :
7435 tgl@sss.pgh.pa.us 11724 [ + - ]: 86 : if (!domcheck->separate)
11725 : 86 : appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
6756 bruce@momjian.us 11726 : 86 : fmtId(domcheck->dobj.name), domcheck->condef);
11727 : : }
11728 : :
3800 heikki.linnakangas@i 11729 : 131 : appendPQExpBufferStr(q, ";\n");
11730 : :
2239 tgl@sss.pgh.pa.us 11731 : 131 : appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
11732 : :
3470 alvherre@alvh.no-ip. 11733 [ + + ]: 131 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 11734 : 20 : binary_upgrade_extension_member(q, &tyinfo->dobj,
11735 : : "DOMAIN", qtypname,
11736 : 20 : tyinfo->dobj.namespace->dobj.name);
11737 : :
2930 sfrost@snowman.net 11738 [ + - ]: 131 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11739 : 131 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 11740 : 131 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11741 : : .namespace = tyinfo->dobj.namespace->dobj.name,
11742 : : .owner = tyinfo->rolname,
11743 : : .description = "DOMAIN",
11744 : : .section = SECTION_PRE_DATA,
11745 : : .createStmt = q->data,
11746 : : .dropStmt = delq->data));
11747 : :
11748 : : /* Dump Domain Comments and Security Labels */
2930 sfrost@snowman.net 11749 [ - + ]: 131 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 11750 :UBC 0 : dumpComment(fout, "DOMAIN", qtypname,
2930 sfrost@snowman.net 11751 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11752 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11753 : :
2930 sfrost@snowman.net 11754 [ - + ]:CBC 131 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 11755 :UBC 0 : dumpSecLabel(fout, "DOMAIN", qtypname,
2930 sfrost@snowman.net 11756 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11757 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11758 : :
2930 sfrost@snowman.net 11759 [ + + ]:CBC 131 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1373 tgl@sss.pgh.pa.us 11760 : 36 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11761 : : qtypname, NULL,
2930 sfrost@snowman.net 11762 : 36 : tyinfo->dobj.namespace->dobj.name,
13 tgl@sss.pgh.pa.us 11763 :GNC 36 : NULL, tyinfo->rolname, &tyinfo->dacl);
11764 : :
11765 : : /* Dump any per-constraint comments */
3400 alvherre@alvh.no-ip. 11766 [ + + ]:CBC 217 : for (i = 0; i < tyinfo->nDomChecks; i++)
11767 : : {
11768 : 86 : ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
2239 tgl@sss.pgh.pa.us 11769 : 86 : PQExpBuffer conprefix = createPQExpBuffer();
11770 : :
11771 : 86 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
3400 alvherre@alvh.no-ip. 11772 : 86 : fmtId(domcheck->dobj.name));
11773 : :
529 tgl@sss.pgh.pa.us 11774 [ + + ]: 86 : if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 11775 : 36 : dumpComment(fout, conprefix->data, qtypname,
2930 sfrost@snowman.net 11776 : 36 : tyinfo->dobj.namespace->dobj.name,
11777 : 36 : tyinfo->rolname,
11778 : 36 : domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
11779 : :
2239 tgl@sss.pgh.pa.us 11780 : 86 : destroyPQExpBuffer(conprefix);
11781 : : }
11782 : :
8010 11783 : 131 : destroyPQExpBuffer(q);
11784 : 131 : destroyPQExpBuffer(delq);
11785 : 131 : destroyPQExpBuffer(query);
2239 11786 : 131 : free(qtypname);
11787 : 131 : free(qualtypname);
8045 bruce@momjian.us 11788 : 131 : }
11789 : :
11790 : : /*
11791 : : * dumpCompositeType
11792 : : * writes out to fout the queries to recreate a user-defined stand-alone
11793 : : * composite type
11794 : : */
11795 : : static void
1159 peter@eisentraut.org 11796 : 134 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
11797 : : {
3014 tgl@sss.pgh.pa.us 11798 : 134 : DumpOptions *dopt = fout->dopt;
7913 bruce@momjian.us 11799 : 134 : PQExpBuffer q = createPQExpBuffer();
4712 heikki.linnakangas@i 11800 : 134 : PQExpBuffer dropped = createPQExpBuffer();
7913 bruce@momjian.us 11801 : 134 : PQExpBuffer delq = createPQExpBuffer();
11802 : 134 : PQExpBuffer query = createPQExpBuffer();
11803 : : PGresult *res;
11804 : : char *qtypname;
11805 : : char *qualtypname;
11806 : : int ntups;
11807 : : int i_attname;
11808 : : int i_atttypdefn;
11809 : : int i_attlen;
11810 : : int i_attalign;
11811 : : int i_attisdropped;
11812 : : int i_attcollation;
11813 : : int i;
11814 : : int actual_atts;
11815 : :
860 tgl@sss.pgh.pa.us 11816 [ + + ]: 134 : if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
11817 : : {
11818 : : /*
11819 : : * Set up query for type-specific details.
11820 : : *
11821 : : * Since we only want to dump COLLATE clauses for attributes whose
11822 : : * collation is different from their type's default, we use a CASE
11823 : : * here to suppress uninteresting attcollations cheaply. atttypid
11824 : : * will be 0 for dropped columns; collation does not matter for those.
11825 : : */
11826 : 59 : appendPQExpBufferStr(query,
11827 : : "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
11828 : : "SELECT a.attname, a.attnum, "
11829 : : "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
11830 : : "a.attlen, a.attalign, a.attisdropped, "
11831 : : "CASE WHEN a.attcollation <> at.typcollation "
11832 : : "THEN a.attcollation ELSE 0 END AS attcollation "
11833 : : "FROM pg_catalog.pg_type ct "
11834 : : "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
11835 : : "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
11836 : : "WHERE ct.oid = $1 "
11837 : : "ORDER BY a.attnum");
11838 : :
11839 : 59 : ExecuteSqlStatement(fout, query->data);
11840 : :
11841 : 59 : fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
11842 : : }
11843 : :
11844 : 134 : printfPQExpBuffer(query,
11845 : : "EXECUTE dumpCompositeType('%u')",
11846 : 134 : tyinfo->dobj.catId.oid);
11847 : :
4450 rhaas@postgresql.org 11848 : 134 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11849 : :
7913 bruce@momjian.us 11850 : 134 : ntups = PQntuples(res);
11851 : :
7899 tgl@sss.pgh.pa.us 11852 : 134 : i_attname = PQfnumber(res, "attname");
11853 : 134 : i_atttypdefn = PQfnumber(res, "atttypdefn");
4712 heikki.linnakangas@i 11854 : 134 : i_attlen = PQfnumber(res, "attlen");
11855 : 134 : i_attalign = PQfnumber(res, "attalign");
11856 : 134 : i_attisdropped = PQfnumber(res, "attisdropped");
4746 tgl@sss.pgh.pa.us 11857 : 134 : i_attcollation = PQfnumber(res, "attcollation");
11858 : :
3470 alvherre@alvh.no-ip. 11859 [ + + ]: 134 : if (dopt->binary_upgrade)
11860 : : {
4450 rhaas@postgresql.org 11861 : 18 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2388 tgl@sss.pgh.pa.us 11862 : 18 : tyinfo->dobj.catId.oid,
11863 : : false, false);
3467 11864 : 18 : binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
11865 : : }
11866 : :
4144 11867 : 134 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2239 11868 : 134 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11869 : :
7899 11870 : 134 : appendPQExpBuffer(q, "CREATE TYPE %s AS (",
11871 : : qualtypname);
11872 : :
4712 heikki.linnakangas@i 11873 : 134 : actual_atts = 0;
7913 bruce@momjian.us 11874 [ + + ]: 424 : for (i = 0; i < ntups; i++)
11875 : : {
11876 : : char *attname;
11877 : : char *atttypdefn;
11878 : : char *attlen;
11879 : : char *attalign;
11880 : : bool attisdropped;
11881 : : Oid attcollation;
11882 : :
7899 tgl@sss.pgh.pa.us 11883 : 290 : attname = PQgetvalue(res, i, i_attname);
11884 : 290 : atttypdefn = PQgetvalue(res, i, i_atttypdefn);
4712 heikki.linnakangas@i 11885 : 290 : attlen = PQgetvalue(res, i, i_attlen);
11886 : 290 : attalign = PQgetvalue(res, i, i_attalign);
11887 : 290 : attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
4746 tgl@sss.pgh.pa.us 11888 : 290 : attcollation = atooid(PQgetvalue(res, i, i_attcollation));
11889 : :
3470 alvherre@alvh.no-ip. 11890 [ + + + + ]: 290 : if (attisdropped && !dopt->binary_upgrade)
4712 heikki.linnakangas@i 11891 : 8 : continue;
11892 : :
11893 : : /* Format properly if not first attr */
11894 [ + + ]: 282 : if (actual_atts++ > 0)
3800 11895 : 148 : appendPQExpBufferChar(q, ',');
11896 : 282 : appendPQExpBufferStr(q, "\n\t");
11897 : :
4712 11898 [ + + ]: 282 : if (!attisdropped)
11899 : : {
11900 : 280 : appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
11901 : :
11902 : : /* Add collation if not default for the column type */
11903 [ - + ]: 280 : if (OidIsValid(attcollation))
11904 : : {
11905 : : CollInfo *coll;
11906 : :
4712 heikki.linnakangas@i 11907 :UBC 0 : coll = findCollationByOid(attcollation);
11908 [ # # ]: 0 : if (coll)
2239 tgl@sss.pgh.pa.us 11909 : 0 : appendPQExpBuffer(q, " COLLATE %s",
11910 : 0 : fmtQualifiedDumpable(coll));
11911 : : }
11912 : : }
11913 : : else
11914 : : {
11915 : : /*
11916 : : * This is a dropped attribute and we're in binary_upgrade mode.
11917 : : * Insert a placeholder for it in the CREATE TYPE command, and set
11918 : : * length and alignment with direct UPDATE to the catalogs
11919 : : * afterwards. See similar code in dumpTableSchema().
11920 : : */
4712 heikki.linnakangas@i 11921 :CBC 2 : appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
11922 : :
11923 : : /* stash separately for insertion after the CREATE TYPE */
3800 11924 : 2 : appendPQExpBufferStr(dropped,
11925 : : "\n-- For binary upgrade, recreate dropped column.\n");
4712 11926 : 2 : appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
11927 : : "SET attlen = %s, "
11928 : : "attalign = '%s', attbyval = false\n"
11929 : : "WHERE attname = ", attlen, attalign);
11930 : 2 : appendStringLiteralAH(dropped, attname, fout);
3800 11931 : 2 : appendPQExpBufferStr(dropped, "\n AND attrelid = ");
2239 tgl@sss.pgh.pa.us 11932 : 2 : appendStringLiteralAH(dropped, qualtypname, fout);
3800 heikki.linnakangas@i 11933 : 2 : appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
11934 : :
4712 11935 : 2 : appendPQExpBuffer(dropped, "ALTER TYPE %s ",
11936 : : qualtypname);
11937 : 2 : appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
11938 : : fmtId(attname));
11939 : : }
11940 : : }
3800 11941 : 134 : appendPQExpBufferStr(q, "\n);\n");
4712 11942 : 134 : appendPQExpBufferStr(q, dropped->data);
11943 : :
2239 tgl@sss.pgh.pa.us 11944 : 134 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11945 : :
3470 alvherre@alvh.no-ip. 11946 [ + + ]: 134 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 11947 : 18 : binary_upgrade_extension_member(q, &tyinfo->dobj,
11948 : : "TYPE", qtypname,
11949 : 18 : tyinfo->dobj.namespace->dobj.name);
11950 : :
2930 sfrost@snowman.net 11951 [ + + ]: 134 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11952 : 117 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 11953 : 117 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11954 : : .namespace = tyinfo->dobj.namespace->dobj.name,
11955 : : .owner = tyinfo->rolname,
11956 : : .description = "TYPE",
11957 : : .section = SECTION_PRE_DATA,
11958 : : .createStmt = q->data,
11959 : : .dropStmt = delq->data));
11960 : :
11961 : :
11962 : : /* Dump Type Comments and Security Labels */
2930 sfrost@snowman.net 11963 [ + + ]: 134 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 11964 : 36 : dumpComment(fout, "TYPE", qtypname,
2930 sfrost@snowman.net 11965 : 36 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11966 : 36 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11967 : :
11968 [ - + ]: 134 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 11969 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
2930 sfrost@snowman.net 11970 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11971 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11972 : :
2930 sfrost@snowman.net 11973 [ + + ]:CBC 134 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1373 tgl@sss.pgh.pa.us 11974 : 18 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11975 : : qtypname, NULL,
2930 sfrost@snowman.net 11976 : 18 : tyinfo->dobj.namespace->dobj.name,
13 tgl@sss.pgh.pa.us 11977 :GNC 18 : NULL, tyinfo->rolname, &tyinfo->dacl);
11978 : :
11979 : : /* Dump any per-column comments */
836 tgl@sss.pgh.pa.us 11980 [ + + ]:CBC 134 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11981 : 36 : dumpCompositeTypeColComments(fout, tyinfo, res);
11982 : :
7435 11983 : 134 : PQclear(res);
11984 : 134 : destroyPQExpBuffer(q);
4712 heikki.linnakangas@i 11985 : 134 : destroyPQExpBuffer(dropped);
7435 tgl@sss.pgh.pa.us 11986 : 134 : destroyPQExpBuffer(delq);
11987 : 134 : destroyPQExpBuffer(query);
2239 11988 : 134 : free(qtypname);
11989 : 134 : free(qualtypname);
5379 11990 : 134 : }
11991 : :
11992 : : /*
11993 : : * dumpCompositeTypeColComments
11994 : : * writes out to fout the queries to recreate comments on the columns of
11995 : : * a user-defined stand-alone composite type.
11996 : : *
11997 : : * The caller has already made a query to collect the names and attnums
11998 : : * of the type's columns, so we just pass that result into here rather
11999 : : * than reading them again.
12000 : : */
12001 : : static void
836 12002 : 36 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
12003 : : PGresult *res)
12004 : : {
12005 : : CommentItem *comments;
12006 : : int ncomments;
12007 : : PQExpBuffer query;
12008 : : PQExpBuffer target;
12009 : : int i;
12010 : : int ntups;
12011 : : int i_attname;
12012 : : int i_attnum;
12013 : : int i_attisdropped;
12014 : :
12015 : : /* do nothing, if --no-comments is supplied */
2271 12016 [ - + ]: 36 : if (fout->dopt->no_comments)
2271 tgl@sss.pgh.pa.us 12017 :UBC 0 : return;
12018 : :
12019 : : /* Search for comments associated with type's pg_class OID */
836 tgl@sss.pgh.pa.us 12020 :CBC 36 : ncomments = findComments(RelationRelationId, tyinfo->typrelid,
12021 : : &comments);
12022 : :
12023 : : /* If no comments exist, we're done */
5379 12024 [ - + ]: 36 : if (ncomments <= 0)
5379 tgl@sss.pgh.pa.us 12025 :UBC 0 : return;
12026 : :
12027 : : /* Build COMMENT ON statements */
836 tgl@sss.pgh.pa.us 12028 :CBC 36 : query = createPQExpBuffer();
5379 12029 : 36 : target = createPQExpBuffer();
12030 : :
836 12031 : 36 : ntups = PQntuples(res);
5379 12032 : 36 : i_attnum = PQfnumber(res, "attnum");
12033 : 36 : i_attname = PQfnumber(res, "attname");
836 12034 : 36 : i_attisdropped = PQfnumber(res, "attisdropped");
5379 12035 [ + + ]: 72 : while (ncomments > 0)
12036 : : {
12037 : : const char *attname;
12038 : :
12039 : 36 : attname = NULL;
12040 [ + - ]: 36 : for (i = 0; i < ntups; i++)
12041 : : {
836 12042 [ + - ]: 36 : if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
12043 [ + - ]: 36 : PQgetvalue(res, i, i_attisdropped)[0] != 't')
12044 : : {
5379 12045 : 36 : attname = PQgetvalue(res, i, i_attname);
12046 : 36 : break;
12047 : : }
12048 : : }
12049 [ + - ]: 36 : if (attname) /* just in case we don't find it */
12050 : : {
12051 : 36 : const char *descr = comments->descr;
12052 : :
12053 : 36 : resetPQExpBuffer(target);
12054 : 36 : appendPQExpBuffer(target, "COLUMN %s.",
5226 bruce@momjian.us 12055 : 36 : fmtId(tyinfo->dobj.name));
3800 heikki.linnakangas@i 12056 : 36 : appendPQExpBufferStr(target, fmtId(attname));
12057 : :
5379 tgl@sss.pgh.pa.us 12058 : 36 : resetPQExpBuffer(query);
2239 12059 : 36 : appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
12060 : 36 : fmtQualifiedDumpable(tyinfo));
12061 : 36 : appendPQExpBuffer(query, "%s IS ", fmtId(attname));
5379 12062 : 36 : appendStringLiteralAH(query, descr, fout);
3800 heikki.linnakangas@i 12063 : 36 : appendPQExpBufferStr(query, ";\n");
12064 : :
5379 tgl@sss.pgh.pa.us 12065 : 36 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 12066 : 36 : ARCHIVE_OPTS(.tag = target->data,
12067 : : .namespace = tyinfo->dobj.namespace->dobj.name,
12068 : : .owner = tyinfo->rolname,
12069 : : .description = "COMMENT",
12070 : : .section = SECTION_NONE,
12071 : : .createStmt = query->data,
12072 : : .deps = &(tyinfo->dobj.dumpId),
12073 : : .nDeps = 1));
12074 : : }
12075 : :
5379 tgl@sss.pgh.pa.us 12076 : 36 : comments++;
12077 : 36 : ncomments--;
12078 : : }
12079 : :
12080 : 36 : destroyPQExpBuffer(query);
12081 : 36 : destroyPQExpBuffer(target);
12082 : : }
12083 : :
12084 : : /*
12085 : : * dumpShellType
12086 : : * writes out to fout the queries to create a shell type
12087 : : *
12088 : : * We dump a shell definition in advance of the I/O functions for the type.
12089 : : */
12090 : : static void
1159 peter@eisentraut.org 12091 : 74 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
12092 : : {
3014 tgl@sss.pgh.pa.us 12093 : 74 : DumpOptions *dopt = fout->dopt;
12094 : : PQExpBuffer q;
12095 : :
12096 : : /* Do nothing in data-only dump */
860 12097 [ + + ]: 74 : if (dopt->dataOnly)
6618 12098 : 3 : return;
12099 : :
12100 : 71 : q = createPQExpBuffer();
12101 : :
12102 : : /*
12103 : : * Note the lack of a DROP command for the shell type; any required DROP
12104 : : * is driven off the base type entry, instead. This interacts with
12105 : : * _printTocEntry()'s use of the presence of a DROP command to decide
12106 : : * whether an entry needs an ALTER OWNER command. We don't want to alter
12107 : : * the shell type's owner immediately on creation; that should happen only
12108 : : * after it's filled in, otherwise the backend complains.
12109 : : */
12110 : :
3470 alvherre@alvh.no-ip. 12111 [ + + ]: 71 : if (dopt->binary_upgrade)
4450 rhaas@postgresql.org 12112 : 8 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2388 tgl@sss.pgh.pa.us 12113 : 8 : stinfo->baseType->dobj.catId.oid,
12114 : : false, false);
12115 : :
6618 12116 : 71 : appendPQExpBuffer(q, "CREATE TYPE %s;\n",
2239 12117 : 71 : fmtQualifiedDumpable(stinfo));
12118 : :
2930 sfrost@snowman.net 12119 [ + - ]: 71 : if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12120 : 71 : ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 12121 : 71 : ARCHIVE_OPTS(.tag = stinfo->dobj.name,
12122 : : .namespace = stinfo->dobj.namespace->dobj.name,
12123 : : .owner = stinfo->baseType->rolname,
12124 : : .description = "SHELL TYPE",
12125 : : .section = SECTION_PRE_DATA,
12126 : : .createStmt = q->data));
12127 : :
6618 tgl@sss.pgh.pa.us 12128 : 71 : destroyPQExpBuffer(q);
12129 : : }
12130 : :
12131 : : /*
12132 : : * dumpProcLang
12133 : : * writes out to fout the queries to recreate a user-defined
12134 : : * procedural language
12135 : : */
12136 : : static void
1159 peter@eisentraut.org 12137 : 84 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
12138 : : {
3014 tgl@sss.pgh.pa.us 12139 : 84 : DumpOptions *dopt = fout->dopt;
12140 : : PQExpBuffer defqry;
12141 : : PQExpBuffer delqry;
12142 : : bool useParams;
12143 : : char *qlanname;
12144 : : FuncInfo *funcInfo;
5318 12145 : 84 : FuncInfo *inlineInfo = NULL;
7435 12146 : 84 : FuncInfo *validatorInfo = NULL;
12147 : :
12148 : : /* Do nothing in data-only dump */
860 12149 [ + + ]: 84 : if (dopt->dataOnly)
7435 12150 : 7 : return;
12151 : :
12152 : : /*
12153 : : * Try to find the support function(s). It is not an error if we don't
12154 : : * find them --- if the functions are in the pg_catalog schema, as is
12155 : : * standard in 8.1 and up, then we won't have loaded them. (In this case
12156 : : * we will emit a parameterless CREATE LANGUAGE command, which will
12157 : : * require PL template knowledge in the backend to reload.)
12158 : : */
12159 : :
12160 : 77 : funcInfo = findFuncByOid(plang->lanplcallfoid);
6618 12161 [ + + + + ]: 77 : if (funcInfo != NULL && !funcInfo->dobj.dump)
6796 12162 : 2 : funcInfo = NULL; /* treat not-dumped same as not-found */
12163 : :
5318 12164 [ + + ]: 77 : if (OidIsValid(plang->laninline))
12165 : : {
12166 : 42 : inlineInfo = findFuncByOid(plang->laninline);
12167 [ + + + - ]: 42 : if (inlineInfo != NULL && !inlineInfo->dobj.dump)
12168 : 1 : inlineInfo = NULL;
12169 : : }
12170 : :
7435 12171 [ + + ]: 77 : if (OidIsValid(plang->lanvalidator))
12172 : : {
12173 : 42 : validatorInfo = findFuncByOid(plang->lanvalidator);
6618 12174 [ + + + - ]: 42 : if (validatorInfo != NULL && !validatorInfo->dobj.dump)
6796 12175 : 1 : validatorInfo = NULL;
12176 : : }
12177 : :
12178 : : /*
12179 : : * If the functions are dumpable then emit a complete CREATE LANGUAGE with
12180 : : * parameters. Otherwise, we'll write a parameterless command, which will
12181 : : * be interpreted as CREATE EXTENSION.
12182 : : */
12183 [ + - ]: 34 : useParams = (funcInfo != NULL &&
5318 12184 [ + + + - : 145 : (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
+ - ]
6796 12185 [ + - ]: 34 : (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
12186 : :
7435 12187 : 77 : defqry = createPQExpBuffer();
12188 : 77 : delqry = createPQExpBuffer();
12189 : :
4524 bruce@momjian.us 12190 : 77 : qlanname = pg_strdup(fmtId(plang->dobj.name));
12191 : :
7435 tgl@sss.pgh.pa.us 12192 : 77 : appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
12193 : : qlanname);
12194 : :
6796 12195 [ + + ]: 77 : if (useParams)
12196 : : {
5163 tgl@sss.pgh.pa.us 12197 :UBC 0 : appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
5163 tgl@sss.pgh.pa.us 12198 [ - + ]:CBC 34 : plang->lanpltrusted ? "TRUSTED " : "",
12199 : : qlanname);
6796 12200 : 34 : appendPQExpBuffer(defqry, " HANDLER %s",
2239 12201 : 34 : fmtQualifiedDumpable(funcInfo));
5318 12202 [ - + ]: 34 : if (OidIsValid(plang->laninline))
2239 tgl@sss.pgh.pa.us 12203 :UBC 0 : appendPQExpBuffer(defqry, " INLINE %s",
12204 : 0 : fmtQualifiedDumpable(inlineInfo));
6796 tgl@sss.pgh.pa.us 12205 [ - + ]:CBC 34 : if (OidIsValid(plang->lanvalidator))
2239 tgl@sss.pgh.pa.us 12206 :UBC 0 : appendPQExpBuffer(defqry, " VALIDATOR %s",
12207 : 0 : fmtQualifiedDumpable(validatorInfo));
12208 : : }
12209 : : else
12210 : : {
12211 : : /*
12212 : : * If not dumping parameters, then use CREATE OR REPLACE so that the
12213 : : * command will not fail if the language is preinstalled in the target
12214 : : * database.
12215 : : *
12216 : : * Modern servers will interpret this as CREATE EXTENSION IF NOT
12217 : : * EXISTS; perhaps we should emit that instead? But it might just add
12218 : : * confusion.
12219 : : */
5163 tgl@sss.pgh.pa.us 12220 :CBC 43 : appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
12221 : : qlanname);
12222 : : }
3800 heikki.linnakangas@i 12223 : 77 : appendPQExpBufferStr(defqry, ";\n");
12224 : :
3470 alvherre@alvh.no-ip. 12225 [ + + ]: 77 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 12226 : 2 : binary_upgrade_extension_member(defqry, &plang->dobj,
12227 : : "LANGUAGE", qlanname, NULL);
12228 : :
2930 sfrost@snowman.net 12229 [ + + ]: 77 : if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
12230 : 35 : ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
1899 alvherre@alvh.no-ip. 12231 : 35 : ARCHIVE_OPTS(.tag = plang->dobj.name,
12232 : : .owner = plang->lanowner,
12233 : : .description = "PROCEDURAL LANGUAGE",
12234 : : .section = SECTION_PRE_DATA,
12235 : : .createStmt = defqry->data,
12236 : : .dropStmt = delqry->data,
12237 : : ));
12238 : :
12239 : : /* Dump Proc Lang Comments and Security Labels */
2930 sfrost@snowman.net 12240 [ - + ]: 77 : if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 12241 :UBC 0 : dumpComment(fout, "LANGUAGE", qlanname,
12242 : 0 : NULL, plang->lanowner,
2930 sfrost@snowman.net 12243 : 0 : plang->dobj.catId, 0, plang->dobj.dumpId);
12244 : :
2930 sfrost@snowman.net 12245 [ - + ]:CBC 77 : if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 12246 :UBC 0 : dumpSecLabel(fout, "LANGUAGE", qlanname,
12247 : 0 : NULL, plang->lanowner,
2930 sfrost@snowman.net 12248 : 0 : plang->dobj.catId, 0, plang->dobj.dumpId);
12249 : :
2930 sfrost@snowman.net 12250 [ + + + - ]:CBC 77 : if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
1373 tgl@sss.pgh.pa.us 12251 : 42 : dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
12252 : : qlanname, NULL, NULL,
13 tgl@sss.pgh.pa.us 12253 :GNC 42 : NULL, plang->lanowner, &plang->dacl);
12254 : :
7435 tgl@sss.pgh.pa.us 12255 :CBC 77 : free(qlanname);
12256 : :
12257 : 77 : destroyPQExpBuffer(defqry);
12258 : 77 : destroyPQExpBuffer(delqry);
12259 : : }
12260 : :
12261 : : /*
12262 : : * format_function_arguments: generate function name and argument list
12263 : : *
12264 : : * This is used when we can rely on pg_get_function_arguments to format
12265 : : * the argument list. Note, however, that pg_get_function_arguments
12266 : : * does not special-case zero-argument aggregates.
12267 : : */
12268 : : static char *
1159 peter@eisentraut.org 12269 : 4092 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
12270 : : {
12271 : : PQExpBufferData fn;
12272 : :
5749 tgl@sss.pgh.pa.us 12273 : 4092 : initPQExpBuffer(&fn);
3800 heikki.linnakangas@i 12274 : 4092 : appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
3876 tgl@sss.pgh.pa.us 12275 [ + + + + ]: 4092 : if (is_agg && finfo->nargs == 0)
3800 heikki.linnakangas@i 12276 : 80 : appendPQExpBufferStr(&fn, "(*)");
12277 : : else
3876 tgl@sss.pgh.pa.us 12278 : 4012 : appendPQExpBuffer(&fn, "(%s)", funcargs);
5749 12279 : 4092 : return fn.data;
12280 : : }
12281 : :
12282 : : /*
12283 : : * format_function_signature: generate function name and argument list
12284 : : *
12285 : : * Only a minimal list of input argument types is generated; this is
12286 : : * sufficient to reference the function, but not to define it.
12287 : : *
12288 : : * If honor_quotes is false then the function name is never quoted.
12289 : : * This is appropriate for use in TOC tags, but not in SQL commands.
12290 : : */
12291 : : static char *
1159 peter@eisentraut.org 12292 : 2166 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
12293 : : {
12294 : : PQExpBufferData fn;
12295 : : int j;
12296 : :
6953 tgl@sss.pgh.pa.us 12297 : 2166 : initPQExpBuffer(&fn);
12298 [ + + ]: 2166 : if (honor_quotes)
12299 : 409 : appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
12300 : : else
12301 : 1757 : appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
12302 [ + + ]: 3970 : for (j = 0; j < finfo->nargs; j++)
12303 : : {
3800 heikki.linnakangas@i 12304 [ + + ]: 1804 : if (j > 0)
12305 : 417 : appendPQExpBufferStr(&fn, ", ");
12306 : :
949 tgl@sss.pgh.pa.us 12307 : 1804 : appendPQExpBufferStr(&fn,
12308 : 1804 : getFormattedTypeName(fout, finfo->argtypes[j],
12309 : : zeroIsError));
12310 : : }
3800 heikki.linnakangas@i 12311 : 2166 : appendPQExpBufferChar(&fn, ')');
6953 tgl@sss.pgh.pa.us 12312 : 2166 : return fn.data;
12313 : : }
12314 : :
12315 : :
12316 : : /*
12317 : : * dumpFunc:
12318 : : * dump out one function
12319 : : */
12320 : : static void
1159 peter@eisentraut.org 12321 : 1789 : dumpFunc(Archive *fout, const FuncInfo *finfo)
12322 : : {
3014 tgl@sss.pgh.pa.us 12323 : 1789 : DumpOptions *dopt = fout->dopt;
12324 : : PQExpBuffer query;
12325 : : PQExpBuffer q;
12326 : : PQExpBuffer delqry;
12327 : : PQExpBuffer asPart;
12328 : : PGresult *res;
12329 : : char *funcsig; /* identity signature */
2489 12330 : 1789 : char *funcfullsig = NULL; /* full signature */
12331 : : char *funcsig_tag;
12332 : : char *qual_funcsig;
12333 : : char *proretset;
12334 : : char *prosrc;
12335 : : char *probin;
12336 : : char *prosqlbody;
12337 : : char *funcargs;
12338 : : char *funciargs;
12339 : : char *funcresult;
12340 : : char *protrftypes;
12341 : : char *prokind;
12342 : : char *provolatile;
12343 : : char *proisstrict;
12344 : : char *prosecdef;
12345 : : char *proleakproof;
12346 : : char *proconfig;
12347 : : char *procost;
12348 : : char *prorows;
12349 : : char *prosupport;
12350 : : char *proparallel;
12351 : : char *lanname;
6068 12352 : 1789 : char **configitems = NULL;
12353 : 1789 : int nconfigitems = 0;
12354 : : const char *keyword;
12355 : :
12356 : : /* Do nothing in data-only dump */
860 12357 [ + + ]: 1789 : if (dopt->dataOnly)
6817 12358 : 32 : return;
12359 : :
7435 12360 : 1757 : query = createPQExpBuffer();
12361 : 1757 : q = createPQExpBuffer();
12362 : 1757 : delqry = createPQExpBuffer();
12363 : 1757 : asPart = createPQExpBuffer();
12364 : :
860 12365 [ + + ]: 1757 : if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
12366 : : {
12367 : : /* Set up query for function-specific details */
1277 drowley@postgresql.o 12368 : 63 : appendPQExpBufferStr(query,
12369 : : "PREPARE dumpFunc(pg_catalog.oid) AS\n");
12370 : :
12371 : 63 : appendPQExpBufferStr(query,
12372 : : "SELECT\n"
12373 : : "proretset,\n"
12374 : : "prosrc,\n"
12375 : : "probin,\n"
12376 : : "provolatile,\n"
12377 : : "proisstrict,\n"
12378 : : "prosecdef,\n"
12379 : : "lanname,\n"
12380 : : "proconfig,\n"
12381 : : "procost,\n"
12382 : : "prorows,\n"
12383 : : "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
12384 : : "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
12385 : : "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
12386 : : "proleakproof,\n");
12387 : :
860 tgl@sss.pgh.pa.us 12388 [ + - ]: 63 : if (fout->remoteVersion >= 90500)
12389 : 63 : appendPQExpBufferStr(query,
12390 : : "array_to_string(protrftypes, ' ') AS protrftypes,\n");
12391 : : else
847 tgl@sss.pgh.pa.us 12392 :UBC 0 : appendPQExpBufferStr(query,
12393 : : "NULL AS protrftypes,\n");
12394 : :
860 tgl@sss.pgh.pa.us 12395 [ + - ]:CBC 63 : if (fout->remoteVersion >= 90600)
12396 : 63 : appendPQExpBufferStr(query,
12397 : : "proparallel,\n");
12398 : : else
860 tgl@sss.pgh.pa.us 12399 :UBC 0 : appendPQExpBufferStr(query,
12400 : : "'u' AS proparallel,\n");
12401 : :
860 tgl@sss.pgh.pa.us 12402 [ + - ]:CBC 63 : if (fout->remoteVersion >= 110000)
12403 : 63 : appendPQExpBufferStr(query,
12404 : : "prokind,\n");
12405 : : else
860 tgl@sss.pgh.pa.us 12406 :UBC 0 : appendPQExpBufferStr(query,
12407 : : "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
12408 : :
860 tgl@sss.pgh.pa.us 12409 [ + - ]:CBC 63 : if (fout->remoteVersion >= 120000)
12410 : 63 : appendPQExpBufferStr(query,
12411 : : "prosupport,\n");
12412 : : else
860 tgl@sss.pgh.pa.us 12413 :UBC 0 : appendPQExpBufferStr(query,
12414 : : "'-' AS prosupport,\n");
12415 : :
860 tgl@sss.pgh.pa.us 12416 [ + - ]:CBC 63 : if (fout->remoteVersion >= 140000)
12417 : 63 : appendPQExpBufferStr(query,
12418 : : "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
12419 : : else
860 tgl@sss.pgh.pa.us 12420 :UBC 0 : appendPQExpBufferStr(query,
12421 : : "NULL AS prosqlbody\n");
12422 : :
1103 peter@eisentraut.org 12423 :CBC 63 : appendPQExpBufferStr(query,
12424 : : "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
12425 : : "WHERE p.oid = $1 "
12426 : : "AND l.oid = p.prolang");
12427 : :
860 tgl@sss.pgh.pa.us 12428 : 63 : ExecuteSqlStatement(fout, query->data);
12429 : :
12430 : 63 : fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
12431 : : }
12432 : :
12433 : 1757 : printfPQExpBuffer(query,
12434 : : "EXECUTE dumpFunc('%u')",
1369 peter@eisentraut.org 12435 : 1757 : finfo->dobj.catId.oid);
12436 : :
4441 rhaas@postgresql.org 12437 : 1757 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
12438 : :
8010 tgl@sss.pgh.pa.us 12439 : 1757 : proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
1103 peter@eisentraut.org 12440 [ + + ]: 1757 : if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
12441 : : {
12442 : 1705 : prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
12443 : 1705 : probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
12444 : 1705 : prosqlbody = NULL;
12445 : : }
12446 : : else
12447 : : {
12448 : 52 : prosrc = NULL;
12449 : 52 : probin = NULL;
12450 : 52 : prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
12451 : : }
852 tgl@sss.pgh.pa.us 12452 : 1757 : funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
12453 : 1757 : funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
12454 : 1757 : funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
847 12455 : 1757 : protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
2235 peter_e@gmx.net 12456 : 1757 : prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
8010 tgl@sss.pgh.pa.us 12457 : 1757 : provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
12458 : 1757 : proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
8002 peter_e@gmx.net 12459 : 1757 : prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
4444 rhaas@postgresql.org 12460 : 1757 : proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
6068 tgl@sss.pgh.pa.us 12461 : 1757 : proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
6292 12462 : 1757 : procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
12463 : 1757 : prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
1891 12464 : 1757 : prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
1369 peter@eisentraut.org 12465 : 1757 : proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
8010 tgl@sss.pgh.pa.us 12466 : 1757 : lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
12467 : :
12468 : : /*
12469 : : * See backend/commands/functioncmds.c for details of how the 'AS' clause
12470 : : * is used.
12471 : : */
1103 peter@eisentraut.org 12472 [ + + ]: 1757 : if (prosqlbody)
12473 : : {
12474 : 52 : appendPQExpBufferStr(asPart, prosqlbody);
12475 : : }
850 tgl@sss.pgh.pa.us 12476 [ + + ]: 1705 : else if (probin[0] != '\0')
12477 : : {
3800 heikki.linnakangas@i 12478 : 146 : appendPQExpBufferStr(asPart, "AS ");
6531 tgl@sss.pgh.pa.us 12479 : 146 : appendStringLiteralAH(asPart, probin, fout);
850 12480 [ + - ]: 146 : if (prosrc[0] != '\0')
12481 : : {
3800 heikki.linnakangas@i 12482 : 146 : appendPQExpBufferStr(asPart, ", ");
12483 : :
12484 : : /*
12485 : : * where we have bin, use dollar quoting if allowed and src
12486 : : * contains quote or backslash; else use regular quoting.
12487 : : */
3470 alvherre@alvh.no-ip. 12488 [ + - ]: 146 : if (dopt->disable_dollar_quoting ||
2489 tgl@sss.pgh.pa.us 12489 [ + - + - ]: 146 : (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
6531 12490 : 146 : appendStringLiteralAH(asPart, prosrc, fout);
12491 : : else
6531 tgl@sss.pgh.pa.us 12492 :UBC 0 : appendStringLiteralDQ(asPart, prosrc, NULL);
12493 : : }
12494 : : }
12495 : : else
12496 : : {
850 tgl@sss.pgh.pa.us 12497 :CBC 1559 : appendPQExpBufferStr(asPart, "AS ");
12498 : : /* with no bin, dollar quote src unconditionally if allowed */
12499 [ - + ]: 1559 : if (dopt->disable_dollar_quoting)
850 tgl@sss.pgh.pa.us 12500 :UBC 0 : appendStringLiteralAH(asPart, prosrc, fout);
12501 : : else
850 tgl@sss.pgh.pa.us 12502 :CBC 1559 : appendStringLiteralDQ(asPart, prosrc, NULL);
12503 : : }
12504 : :
847 12505 [ + + ]: 1757 : if (*proconfig)
12506 : : {
6068 12507 [ - + ]: 15 : if (!parsePGArray(proconfig, &configitems, &nconfigitems))
737 tgl@sss.pgh.pa.us 12508 :UBC 0 : pg_fatal("could not parse %s array", "proconfig");
12509 : : }
12510 : : else
12511 : : {
1242 michael@paquier.xyz 12512 :CBC 1742 : configitems = NULL;
12513 : 1742 : nconfigitems = 0;
12514 : : }
12515 : :
852 tgl@sss.pgh.pa.us 12516 : 1757 : funcfullsig = format_function_arguments(finfo, funcargs, false);
12517 : 1757 : funcsig = format_function_arguments(finfo, funciargs, false);
12518 : :
4451 rhaas@postgresql.org 12519 : 1757 : funcsig_tag = format_function_signature(fout, finfo, false);
12520 : :
903 tgl@sss.pgh.pa.us 12521 : 1757 : qual_funcsig = psprintf("%s.%s",
12522 : 1757 : fmtId(finfo->dobj.namespace->dobj.name),
12523 : : funcsig);
12524 : :
2235 peter_e@gmx.net 12525 [ + + ]: 1757 : if (prokind[0] == PROKIND_PROCEDURE)
12526 : 81 : keyword = "PROCEDURE";
12527 : : else
12528 : 1676 : keyword = "FUNCTION"; /* works for window functions too */
12529 : :
903 tgl@sss.pgh.pa.us 12530 : 1757 : appendPQExpBuffer(delqry, "DROP %s %s;\n",
12531 : : keyword, qual_funcsig);
12532 : :
2239 12533 [ + - ]: 3514 : appendPQExpBuffer(q, "CREATE %s %s.%s",
12534 : : keyword,
12535 : 1757 : fmtId(finfo->dobj.namespace->dobj.name),
12536 : : funcfullsig ? funcfullsig :
12537 : : funcsig);
12538 : :
2235 peter_e@gmx.net 12539 [ + + ]: 1757 : if (prokind[0] == PROKIND_PROCEDURE)
12540 : : /* no result type to output */ ;
2327 12541 [ + - ]: 1676 : else if (funcresult)
12542 : 1676 : appendPQExpBuffer(q, " RETURNS %s", funcresult);
12543 : : else
2327 peter_e@gmx.net 12544 :UBC 0 : appendPQExpBuffer(q, " RETURNS %s%s",
5749 tgl@sss.pgh.pa.us 12545 [ # # ]: 0 : (proretset[0] == 't') ? "SETOF " : "",
949 12546 : 0 : getFormattedTypeName(fout, finfo->prorettype,
12547 : : zeroIsError));
12548 : :
5766 heikki.linnakangas@i 12549 :CBC 1757 : appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
12550 : :
847 tgl@sss.pgh.pa.us 12551 [ - + ]: 1757 : if (*protrftypes)
12552 : : {
3249 bruce@momjian.us 12553 :UBC 0 : Oid *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
12554 : : int i;
12555 : :
3276 peter_e@gmx.net 12556 : 0 : appendPQExpBufferStr(q, " TRANSFORM ");
12557 : 0 : parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
12558 [ # # ]: 0 : for (i = 0; typeids[i]; i++)
12559 : : {
12560 [ # # ]: 0 : if (i != 0)
12561 : 0 : appendPQExpBufferStr(q, ", ");
12562 : 0 : appendPQExpBuffer(q, "FOR TYPE %s",
2489 tgl@sss.pgh.pa.us 12563 : 0 : getFormattedTypeName(fout, typeids[i], zeroAsNone));
12564 : : }
12565 : : }
12566 : :
2235 peter_e@gmx.net 12567 [ + + ]:CBC 1757 : if (prokind[0] == PROKIND_WINDOW)
3800 heikki.linnakangas@i 12568 : 5 : appendPQExpBufferStr(q, " WINDOW");
12569 : :
8003 peter_e@gmx.net 12570 [ + + ]: 1757 : if (provolatile[0] != PROVOLATILE_VOLATILE)
12571 : : {
8010 tgl@sss.pgh.pa.us 12572 [ + + ]: 350 : if (provolatile[0] == PROVOLATILE_IMMUTABLE)
3800 heikki.linnakangas@i 12573 : 334 : appendPQExpBufferStr(q, " IMMUTABLE");
8010 tgl@sss.pgh.pa.us 12574 [ + - ]: 16 : else if (provolatile[0] == PROVOLATILE_STABLE)
3800 heikki.linnakangas@i 12575 : 16 : appendPQExpBufferStr(q, " STABLE");
8010 tgl@sss.pgh.pa.us 12576 [ # # ]:UBC 0 : else if (provolatile[0] != PROVOLATILE_VOLATILE)
737 12577 : 0 : pg_fatal("unrecognized provolatile value for function \"%s\"",
12578 : : finfo->dobj.name);
12579 : : }
12580 : :
8003 peter_e@gmx.net 12581 [ + + ]:CBC 1757 : if (proisstrict[0] == 't')
3800 heikki.linnakangas@i 12582 : 356 : appendPQExpBufferStr(q, " STRICT");
12583 : :
8002 peter_e@gmx.net 12584 [ - + ]: 1757 : if (prosecdef[0] == 't')
3800 heikki.linnakangas@i 12585 :UBC 0 : appendPQExpBufferStr(q, " SECURITY DEFINER");
12586 : :
4444 rhaas@postgresql.org 12587 [ + + ]:CBC 1757 : if (proleakproof[0] == 't')
3800 heikki.linnakangas@i 12588 : 10 : appendPQExpBufferStr(q, " LEAKPROOF");
12589 : :
12590 : : /*
12591 : : * COST and ROWS are emitted only if present and not default, so as not to
12592 : : * break backwards-compatibility of the dump without need. Keep this code
12593 : : * in sync with the defaults in functioncmds.c.
12594 : : */
6292 tgl@sss.pgh.pa.us 12595 [ + - ]: 1757 : if (strcmp(procost, "0") != 0)
12596 : : {
12597 [ + + + + ]: 1757 : if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
12598 : : {
12599 : : /* default cost is 1 */
12600 [ - + ]: 387 : if (strcmp(procost, "1") != 0)
6292 tgl@sss.pgh.pa.us 12601 :UBC 0 : appendPQExpBuffer(q, " COST %s", procost);
12602 : : }
12603 : : else
12604 : : {
12605 : : /* default cost is 100 */
6292 tgl@sss.pgh.pa.us 12606 [ + + ]:CBC 1370 : if (strcmp(procost, "100") != 0)
12607 : 6 : appendPQExpBuffer(q, " COST %s", procost);
12608 : : }
12609 : : }
12610 [ + + ]: 1757 : if (proretset[0] == 't' &&
12611 [ + - - + ]: 191 : strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
6292 tgl@sss.pgh.pa.us 12612 :UBC 0 : appendPQExpBuffer(q, " ROWS %s", prorows);
12613 : :
1891 tgl@sss.pgh.pa.us 12614 [ + + ]:CBC 1757 : if (strcmp(prosupport, "-") != 0)
12615 : : {
12616 : : /* We rely on regprocout to provide quoting and qualification */
12617 : 46 : appendPQExpBuffer(q, " SUPPORT %s", prosupport);
12618 : : }
12619 : :
1369 peter@eisentraut.org 12620 [ + + ]: 1757 : if (proparallel[0] != PROPARALLEL_UNSAFE)
12621 : : {
3133 rhaas@postgresql.org 12622 [ + + ]: 120 : if (proparallel[0] == PROPARALLEL_SAFE)
12623 : 115 : appendPQExpBufferStr(q, " PARALLEL SAFE");
12624 [ + - ]: 5 : else if (proparallel[0] == PROPARALLEL_RESTRICTED)
12625 : 5 : appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
3133 rhaas@postgresql.org 12626 [ # # ]:UBC 0 : else if (proparallel[0] != PROPARALLEL_UNSAFE)
737 tgl@sss.pgh.pa.us 12627 : 0 : pg_fatal("unrecognized proparallel value for function \"%s\"",
12628 : : finfo->dobj.name);
12629 : : }
12630 : :
599 drowley@postgresql.o 12631 [ + + ]:CBC 1792 : for (int i = 0; i < nconfigitems; i++)
12632 : : {
12633 : : /* we feel free to scribble on configitems[] here */
6068 tgl@sss.pgh.pa.us 12634 : 35 : char *configitem = configitems[i];
12635 : : char *pos;
12636 : :
12637 : 35 : pos = strchr(configitem, '=');
12638 [ - + ]: 35 : if (pos == NULL)
6068 tgl@sss.pgh.pa.us 12639 :UBC 0 : continue;
6068 tgl@sss.pgh.pa.us 12640 :CBC 35 : *pos++ = '\0';
12641 : 35 : appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
12642 : :
12643 : : /*
12644 : : * Variables that are marked GUC_LIST_QUOTE were already fully quoted
12645 : : * by flatten_set_variable_args() before they were put into the
12646 : : * proconfig array. However, because the quoting rules used there
12647 : : * aren't exactly like SQL's, we have to break the list value apart
12648 : : * and then quote the elements as string literals. (The elements may
12649 : : * be double-quoted as-is, but we can't just feed them to the SQL
12650 : : * parser; it would do the wrong thing with elements that are
12651 : : * zero-length or longer than NAMEDATALEN.)
12652 : : *
12653 : : * Variables that are not so marked should just be emitted as simple
12654 : : * string literals. If the variable is not known to
12655 : : * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
12656 : : * to use GUC_LIST_QUOTE for extension variables.
12657 : : */
2216 12658 [ + + ]: 35 : if (variable_is_guc_list_quote(configitem))
12659 : : {
12660 : : char **namelist;
12661 : : char **nameptr;
12662 : :
12663 : : /* Parse string into list of identifiers */
12664 : : /* this shouldn't fail really */
2084 12665 [ + - ]: 10 : if (SplitGUCList(pos, ',', &namelist))
12666 : : {
12667 [ + + ]: 35 : for (nameptr = namelist; *nameptr; nameptr++)
12668 : : {
12669 [ + + ]: 25 : if (nameptr != namelist)
12670 : 15 : appendPQExpBufferStr(q, ", ");
12671 : 25 : appendStringLiteralAH(q, *nameptr, fout);
12672 : : }
12673 : : }
12674 : 10 : pg_free(namelist);
12675 : : }
12676 : : else
6068 12677 : 25 : appendStringLiteralAH(q, pos, fout);
12678 : : }
12679 : :
5766 heikki.linnakangas@i 12680 : 1757 : appendPQExpBuffer(q, "\n %s;\n", asPart->data);
12681 : :
1495 alvherre@alvh.no-ip. 12682 : 1757 : append_depends_on_extension(fout, q, &finfo->dobj,
12683 : : "pg_catalog.pg_proc", keyword,
12684 : : qual_funcsig);
12685 : :
3470 12686 [ + + ]: 1757 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 12687 : 282 : binary_upgrade_extension_member(q, &finfo->dobj,
12688 : : keyword, funcsig,
12689 : 282 : finfo->dobj.namespace->dobj.name);
12690 : :
2930 sfrost@snowman.net 12691 [ + + ]: 1757 : if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12692 : 1653 : ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 12693 [ + + ]: 1653 : ARCHIVE_OPTS(.tag = funcsig_tag,
12694 : : .namespace = finfo->dobj.namespace->dobj.name,
12695 : : .owner = finfo->rolname,
12696 : : .description = keyword,
12697 : : .section = finfo->postponed_def ?
12698 : : SECTION_POST_DATA : SECTION_PRE_DATA,
12699 : : .createStmt = q->data,
12700 : : .dropStmt = delqry->data));
12701 : :
12702 : : /* Dump Function Comments and Security Labels */
2930 sfrost@snowman.net 12703 [ + + ]: 1757 : if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 12704 : 5 : dumpComment(fout, keyword, funcsig,
2930 sfrost@snowman.net 12705 : 5 : finfo->dobj.namespace->dobj.name, finfo->rolname,
12706 : 5 : finfo->dobj.catId, 0, finfo->dobj.dumpId);
12707 : :
12708 [ - + ]: 1757 : if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 12709 :UBC 0 : dumpSecLabel(fout, keyword, funcsig,
2930 sfrost@snowman.net 12710 : 0 : finfo->dobj.namespace->dobj.name, finfo->rolname,
12711 : 0 : finfo->dobj.catId, 0, finfo->dobj.dumpId);
12712 : :
2930 sfrost@snowman.net 12713 [ + + ]:CBC 1757 : if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
1373 tgl@sss.pgh.pa.us 12714 : 108 : dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
12715 : : funcsig, NULL,
2930 sfrost@snowman.net 12716 : 108 : finfo->dobj.namespace->dobj.name,
13 tgl@sss.pgh.pa.us 12717 :GNC 108 : NULL, finfo->rolname, &finfo->dacl);
12718 : :
8010 tgl@sss.pgh.pa.us 12719 :CBC 1757 : PQclear(res);
12720 : :
12721 : 1757 : destroyPQExpBuffer(query);
8290 12722 : 1757 : destroyPQExpBuffer(q);
12723 : 1757 : destroyPQExpBuffer(delqry);
12724 : 1757 : destroyPQExpBuffer(asPart);
8001 peter_e@gmx.net 12725 : 1757 : free(funcsig);
668 peter@eisentraut.org 12726 : 1757 : free(funcfullsig);
7955 bruce@momjian.us 12727 : 1757 : free(funcsig_tag);
903 tgl@sss.pgh.pa.us 12728 : 1757 : free(qual_funcsig);
668 peter@eisentraut.org 12729 : 1757 : free(configitems);
12730 : : }
12731 : :
12732 : :
12733 : : /*
12734 : : * Dump a user-defined cast
12735 : : */
12736 : : static void
1159 12737 : 68 : dumpCast(Archive *fout, const CastInfo *cast)
12738 : : {
3014 tgl@sss.pgh.pa.us 12739 : 68 : DumpOptions *dopt = fout->dopt;
12740 : : PQExpBuffer defqry;
12741 : : PQExpBuffer delqry;
12742 : : PQExpBuffer labelq;
12743 : : PQExpBuffer castargs;
7435 12744 : 68 : FuncInfo *funcInfo = NULL;
12745 : : const char *sourceType;
12746 : : const char *targetType;
12747 : :
12748 : : /* Do nothing in data-only dump */
860 12749 [ + + ]: 68 : if (dopt->dataOnly)
7435 12750 : 3 : return;
12751 : :
12752 : : /* Cannot dump if we don't have the cast function's info */
12753 [ + + ]: 65 : if (OidIsValid(cast->castfunc))
12754 : : {
12755 : 40 : funcInfo = findFuncByOid(cast->castfunc);
12756 [ - + ]: 40 : if (funcInfo == NULL)
737 tgl@sss.pgh.pa.us 12757 :UBC 0 : pg_fatal("could not find function definition for function with OID %u",
12758 : : cast->castfunc);
12759 : : }
12760 : :
7435 tgl@sss.pgh.pa.us 12761 :CBC 65 : defqry = createPQExpBuffer();
12762 : 65 : delqry = createPQExpBuffer();
4813 12763 : 65 : labelq = createPQExpBuffer();
2239 12764 : 65 : castargs = createPQExpBuffer();
12765 : :
3209 heikki.linnakangas@i 12766 : 65 : sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12767 : 65 : targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
7435 tgl@sss.pgh.pa.us 12768 : 65 : appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12769 : : sourceType, targetType);
12770 : :
12771 : 65 : appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12772 : : sourceType, targetType);
12773 : :
5421 bruce@momjian.us 12774 [ + - + - ]: 65 : switch (cast->castmethod)
12775 : : {
5644 heikki.linnakangas@i 12776 : 25 : case COERCION_METHOD_BINARY:
3800 12777 : 25 : appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
5644 12778 : 25 : break;
5644 heikki.linnakangas@i 12779 :UBC 0 : case COERCION_METHOD_INOUT:
3800 12780 : 0 : appendPQExpBufferStr(defqry, "WITH INOUT");
5644 12781 : 0 : break;
5644 heikki.linnakangas@i 12782 :CBC 40 : case COERCION_METHOD_FUNCTION:
4412 peter_e@gmx.net 12783 [ + - ]: 40 : if (funcInfo)
12784 : : {
4326 bruce@momjian.us 12785 : 40 : char *fsig = format_function_signature(fout, funcInfo, true);
12786 : :
12787 : : /*
12788 : : * Always qualify the function name (format_function_signature
12789 : : * won't qualify it).
12790 : : */
4412 peter_e@gmx.net 12791 : 40 : appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
2489 tgl@sss.pgh.pa.us 12792 : 40 : fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
4412 peter_e@gmx.net 12793 : 40 : free(fsig);
12794 : : }
12795 : : else
1840 peter@eisentraut.org 12796 :UBC 0 : pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
5644 heikki.linnakangas@i 12797 :CBC 40 : break;
5644 heikki.linnakangas@i 12798 :UBC 0 : default:
1840 peter@eisentraut.org 12799 : 0 : pg_log_warning("bogus value in pg_cast.castmethod field");
12800 : : }
12801 : :
7435 tgl@sss.pgh.pa.us 12802 [ + + ]:CBC 65 : if (cast->castcontext == 'a')
3800 heikki.linnakangas@i 12803 : 35 : appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
7435 tgl@sss.pgh.pa.us 12804 [ + + ]: 30 : else if (cast->castcontext == 'i')
3800 heikki.linnakangas@i 12805 : 10 : appendPQExpBufferStr(defqry, " AS IMPLICIT");
12806 : 65 : appendPQExpBufferStr(defqry, ";\n");
12807 : :
4813 tgl@sss.pgh.pa.us 12808 : 65 : appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12809 : : sourceType, targetType);
12810 : :
2239 12811 : 65 : appendPQExpBuffer(castargs, "(%s AS %s)",
12812 : : sourceType, targetType);
12813 : :
3470 alvherre@alvh.no-ip. 12814 [ + + ]: 65 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 12815 : 7 : binary_upgrade_extension_member(defqry, &cast->dobj,
12816 : 7 : "CAST", castargs->data, NULL);
12817 : :
2930 sfrost@snowman.net 12818 [ + - ]: 65 : if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12819 : 65 : ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
1899 alvherre@alvh.no-ip. 12820 : 65 : ARCHIVE_OPTS(.tag = labelq->data,
12821 : : .description = "CAST",
12822 : : .section = SECTION_PRE_DATA,
12823 : : .createStmt = defqry->data,
12824 : : .dropStmt = delqry->data));
12825 : :
12826 : : /* Dump Cast Comments */
2930 sfrost@snowman.net 12827 [ - + ]: 65 : if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 12828 :UBC 0 : dumpComment(fout, "CAST", castargs->data,
12829 : : NULL, "",
2930 sfrost@snowman.net 12830 : 0 : cast->dobj.catId, 0, cast->dobj.dumpId);
12831 : :
7941 peter_e@gmx.net 12832 :CBC 65 : destroyPQExpBuffer(defqry);
12833 : 65 : destroyPQExpBuffer(delqry);
4813 tgl@sss.pgh.pa.us 12834 : 65 : destroyPQExpBuffer(labelq);
2239 12835 : 65 : destroyPQExpBuffer(castargs);
12836 : : }
12837 : :
12838 : : /*
12839 : : * Dump a transform
12840 : : */
12841 : : static void
1159 peter@eisentraut.org 12842 : 43 : dumpTransform(Archive *fout, const TransformInfo *transform)
12843 : : {
3014 tgl@sss.pgh.pa.us 12844 : 43 : DumpOptions *dopt = fout->dopt;
12845 : : PQExpBuffer defqry;
12846 : : PQExpBuffer delqry;
12847 : : PQExpBuffer labelq;
12848 : : PQExpBuffer transformargs;
3276 peter_e@gmx.net 12849 : 43 : FuncInfo *fromsqlFuncInfo = NULL;
12850 : 43 : FuncInfo *tosqlFuncInfo = NULL;
12851 : : char *lanname;
12852 : : const char *transformType;
12853 : :
12854 : : /* Do nothing in data-only dump */
860 tgl@sss.pgh.pa.us 12855 [ + + ]: 43 : if (dopt->dataOnly)
3276 peter_e@gmx.net 12856 : 3 : return;
12857 : :
12858 : : /* Cannot dump if we don't have the transform functions' info */
12859 [ + - ]: 40 : if (OidIsValid(transform->trffromsql))
12860 : : {
12861 : 40 : fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12862 [ - + ]: 40 : if (fromsqlFuncInfo == NULL)
737 tgl@sss.pgh.pa.us 12863 :UBC 0 : pg_fatal("could not find function definition for function with OID %u",
12864 : : transform->trffromsql);
12865 : : }
3276 peter_e@gmx.net 12866 [ + - ]:CBC 40 : if (OidIsValid(transform->trftosql))
12867 : : {
12868 : 40 : tosqlFuncInfo = findFuncByOid(transform->trftosql);
12869 [ - + ]: 40 : if (tosqlFuncInfo == NULL)
737 tgl@sss.pgh.pa.us 12870 :UBC 0 : pg_fatal("could not find function definition for function with OID %u",
12871 : : transform->trftosql);
12872 : : }
12873 : :
3276 peter_e@gmx.net 12874 :CBC 40 : defqry = createPQExpBuffer();
12875 : 40 : delqry = createPQExpBuffer();
12876 : 40 : labelq = createPQExpBuffer();
2239 tgl@sss.pgh.pa.us 12877 : 40 : transformargs = createPQExpBuffer();
12878 : :
3276 peter_e@gmx.net 12879 : 40 : lanname = get_language_name(fout, transform->trflang);
3209 heikki.linnakangas@i 12880 : 40 : transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12881 : :
3276 peter_e@gmx.net 12882 : 40 : appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12883 : : transformType, lanname);
12884 : :
12885 : 40 : appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12886 : : transformType, lanname);
12887 : :
12888 [ - + - - ]: 40 : if (!transform->trffromsql && !transform->trftosql)
1840 peter@eisentraut.org 12889 :UBC 0 : pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
12890 : :
3276 peter_e@gmx.net 12891 [ + - ]:CBC 40 : if (transform->trffromsql)
12892 : : {
12893 [ + - ]: 40 : if (fromsqlFuncInfo)
12894 : : {
12895 : 40 : char *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12896 : :
12897 : : /*
12898 : : * Always qualify the function name (format_function_signature
12899 : : * won't qualify it).
12900 : : */
12901 : 40 : appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
2489 tgl@sss.pgh.pa.us 12902 : 40 : fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
3276 peter_e@gmx.net 12903 : 40 : free(fsig);
12904 : : }
12905 : : else
1840 peter@eisentraut.org 12906 :UBC 0 : pg_log_warning("bogus value in pg_transform.trffromsql field");
12907 : : }
12908 : :
3276 peter_e@gmx.net 12909 [ + - ]:CBC 40 : if (transform->trftosql)
12910 : : {
12911 [ + - ]: 40 : if (transform->trffromsql)
1746 drowley@postgresql.o 12912 : 40 : appendPQExpBufferStr(defqry, ", ");
12913 : :
3276 peter_e@gmx.net 12914 [ + - ]: 40 : if (tosqlFuncInfo)
12915 : : {
12916 : 40 : char *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12917 : :
12918 : : /*
12919 : : * Always qualify the function name (format_function_signature
12920 : : * won't qualify it).
12921 : : */
12922 : 40 : appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
2489 tgl@sss.pgh.pa.us 12923 : 40 : fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
3276 peter_e@gmx.net 12924 : 40 : free(fsig);
12925 : : }
12926 : : else
1840 peter@eisentraut.org 12927 :UBC 0 : pg_log_warning("bogus value in pg_transform.trftosql field");
12928 : : }
12929 : :
1746 drowley@postgresql.o 12930 :CBC 40 : appendPQExpBufferStr(defqry, ");\n");
12931 : :
3276 peter_e@gmx.net 12932 : 40 : appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12933 : : transformType, lanname);
12934 : :
2239 tgl@sss.pgh.pa.us 12935 : 40 : appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12936 : : transformType, lanname);
12937 : :
3276 peter_e@gmx.net 12938 [ + + ]: 40 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 12939 : 2 : binary_upgrade_extension_member(defqry, &transform->dobj,
12940 : 2 : "TRANSFORM", transformargs->data, NULL);
12941 : :
2930 sfrost@snowman.net 12942 [ + - ]: 40 : if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12943 : 40 : ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
1899 alvherre@alvh.no-ip. 12944 : 40 : ARCHIVE_OPTS(.tag = labelq->data,
12945 : : .description = "TRANSFORM",
12946 : : .section = SECTION_PRE_DATA,
12947 : : .createStmt = defqry->data,
12948 : : .dropStmt = delqry->data,
12949 : : .deps = transform->dobj.dependencies,
12950 : : .nDeps = transform->dobj.nDeps));
12951 : :
12952 : : /* Dump Transform Comments */
2930 sfrost@snowman.net 12953 [ - + ]: 40 : if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 12954 :UBC 0 : dumpComment(fout, "TRANSFORM", transformargs->data,
12955 : : NULL, "",
2930 sfrost@snowman.net 12956 : 0 : transform->dobj.catId, 0, transform->dobj.dumpId);
12957 : :
3276 peter_e@gmx.net 12958 :CBC 40 : free(lanname);
12959 : 40 : destroyPQExpBuffer(defqry);
12960 : 40 : destroyPQExpBuffer(delqry);
12961 : 40 : destroyPQExpBuffer(labelq);
2239 tgl@sss.pgh.pa.us 12962 : 40 : destroyPQExpBuffer(transformargs);
12963 : : }
12964 : :
12965 : :
12966 : : /*
12967 : : * dumpOpr
12968 : : * write out a single operator definition
12969 : : */
12970 : : static void
1159 peter@eisentraut.org 12971 : 907 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
12972 : : {
3014 tgl@sss.pgh.pa.us 12973 : 907 : DumpOptions *dopt = fout->dopt;
12974 : : PQExpBuffer query;
12975 : : PQExpBuffer q;
12976 : : PQExpBuffer delq;
12977 : : PQExpBuffer oprid;
12978 : : PQExpBuffer details;
12979 : : PGresult *res;
12980 : : int i_oprkind;
12981 : : int i_oprcode;
12982 : : int i_oprleft;
12983 : : int i_oprright;
12984 : : int i_oprcom;
12985 : : int i_oprnegate;
12986 : : int i_oprrest;
12987 : : int i_oprjoin;
12988 : : int i_oprcanmerge;
12989 : : int i_oprcanhash;
12990 : : char *oprkind;
12991 : : char *oprcode;
12992 : : char *oprleft;
12993 : : char *oprright;
12994 : : char *oprcom;
12995 : : char *oprnegate;
12996 : : char *oprrest;
12997 : : char *oprjoin;
12998 : : char *oprcanmerge;
12999 : : char *oprcanhash;
13000 : : char *oprregproc;
13001 : : char *oprref;
13002 : :
13003 : : /* Do nothing in data-only dump */
860 13004 [ + + ]: 907 : if (dopt->dataOnly)
7435 13005 : 3 : return;
13006 : :
13007 : : /*
13008 : : * some operators are invalid because they were the result of user
13009 : : * defining operators before commutators exist
13010 : : */
13011 [ + + ]: 904 : if (!OidIsValid(oprinfo->oprcode))
13012 : 14 : return;
13013 : :
13014 : 890 : query = createPQExpBuffer();
13015 : 890 : q = createPQExpBuffer();
13016 : 890 : delq = createPQExpBuffer();
13017 : 890 : oprid = createPQExpBuffer();
13018 : 890 : details = createPQExpBuffer();
13019 : :
860 13020 [ + + ]: 890 : if (!fout->is_prepared[PREPQUERY_DUMPOPR])
13021 : : {
13022 : : /* Set up query for operator-specific details */
13023 : 42 : appendPQExpBufferStr(query,
13024 : : "PREPARE dumpOpr(pg_catalog.oid) AS\n"
13025 : : "SELECT oprkind, "
13026 : : "oprcode::pg_catalog.regprocedure, "
13027 : : "oprleft::pg_catalog.regtype, "
13028 : : "oprright::pg_catalog.regtype, "
13029 : : "oprcom, "
13030 : : "oprnegate, "
13031 : : "oprrest::pg_catalog.regprocedure, "
13032 : : "oprjoin::pg_catalog.regprocedure, "
13033 : : "oprcanmerge, oprcanhash "
13034 : : "FROM pg_catalog.pg_operator "
13035 : : "WHERE oid = $1");
13036 : :
13037 : 42 : ExecuteSqlStatement(fout, query->data);
13038 : :
13039 : 42 : fout->is_prepared[PREPQUERY_DUMPOPR] = true;
13040 : : }
13041 : :
13042 : 890 : printfPQExpBuffer(query,
13043 : : "EXECUTE dumpOpr('%u')",
13044 : 890 : oprinfo->dobj.catId.oid);
13045 : :
4441 rhaas@postgresql.org 13046 : 890 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13047 : :
8010 tgl@sss.pgh.pa.us 13048 : 890 : i_oprkind = PQfnumber(res, "oprkind");
13049 : 890 : i_oprcode = PQfnumber(res, "oprcode");
13050 : 890 : i_oprleft = PQfnumber(res, "oprleft");
13051 : 890 : i_oprright = PQfnumber(res, "oprright");
13052 : 890 : i_oprcom = PQfnumber(res, "oprcom");
13053 : 890 : i_oprnegate = PQfnumber(res, "oprnegate");
13054 : 890 : i_oprrest = PQfnumber(res, "oprrest");
13055 : 890 : i_oprjoin = PQfnumber(res, "oprjoin");
6322 13056 : 890 : i_oprcanmerge = PQfnumber(res, "oprcanmerge");
8010 13057 : 890 : i_oprcanhash = PQfnumber(res, "oprcanhash");
13058 : :
13059 : 890 : oprkind = PQgetvalue(res, 0, i_oprkind);
13060 : 890 : oprcode = PQgetvalue(res, 0, i_oprcode);
13061 : 890 : oprleft = PQgetvalue(res, 0, i_oprleft);
13062 : 890 : oprright = PQgetvalue(res, 0, i_oprright);
13063 : 890 : oprcom = PQgetvalue(res, 0, i_oprcom);
13064 : 890 : oprnegate = PQgetvalue(res, 0, i_oprnegate);
13065 : 890 : oprrest = PQgetvalue(res, 0, i_oprrest);
13066 : 890 : oprjoin = PQgetvalue(res, 0, i_oprjoin);
6322 13067 : 890 : oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
8010 13068 : 890 : oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
13069 : :
13070 : : /* In PG14 upwards postfix operator support does not exist anymore. */
1305 13071 [ - + ]: 890 : if (strcmp(oprkind, "r") == 0)
1305 tgl@sss.pgh.pa.us 13072 :UBC 0 : pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
13073 : : oprcode);
13074 : :
1328 peter@eisentraut.org 13075 :CBC 890 : oprregproc = convertRegProcReference(oprcode);
3697 sfrost@snowman.net 13076 [ + - ]: 890 : if (oprregproc)
13077 : : {
2069 peter_e@gmx.net 13078 : 890 : appendPQExpBuffer(details, " FUNCTION = %s", oprregproc);
3697 sfrost@snowman.net 13079 : 890 : free(oprregproc);
13080 : : }
13081 : :
8010 tgl@sss.pgh.pa.us 13082 : 890 : appendPQExpBuffer(oprid, "%s (",
7347 13083 : 890 : oprinfo->dobj.name);
13084 : :
13085 : : /*
13086 : : * right unary means there's a left arg and left unary means there's a
13087 : : * right arg. (Although the "r" case is dead code for PG14 and later,
13088 : : * continue to support it in case we're dumping from an old server.)
13089 : : */
8010 13090 [ + - ]: 890 : if (strcmp(oprkind, "r") == 0 ||
13091 [ + + ]: 890 : strcmp(oprkind, "b") == 0)
13092 : : {
2741 13093 : 829 : appendPQExpBuffer(details, ",\n LEFTARG = %s", oprleft);
13094 : 829 : appendPQExpBufferStr(oprid, oprleft);
13095 : : }
13096 : : else
3800 heikki.linnakangas@i 13097 : 61 : appendPQExpBufferStr(oprid, "NONE");
13098 : :
8010 tgl@sss.pgh.pa.us 13099 [ + + ]: 890 : if (strcmp(oprkind, "l") == 0 ||
13100 [ + - ]: 829 : strcmp(oprkind, "b") == 0)
13101 : : {
2741 13102 : 890 : appendPQExpBuffer(details, ",\n RIGHTARG = %s", oprright);
13103 : 890 : appendPQExpBuffer(oprid, ", %s)", oprright);
13104 : : }
13105 : : else
3800 heikki.linnakangas@i 13106 :UBC 0 : appendPQExpBufferStr(oprid, ", NONE)");
13107 : :
1328 peter@eisentraut.org 13108 :CBC 890 : oprref = getFormattedOperatorName(oprcom);
3697 sfrost@snowman.net 13109 [ + + ]: 890 : if (oprref)
13110 : : {
13111 : 567 : appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
13112 : 567 : free(oprref);
13113 : : }
13114 : :
1328 peter@eisentraut.org 13115 : 890 : oprref = getFormattedOperatorName(oprnegate);
3697 sfrost@snowman.net 13116 [ + + ]: 890 : if (oprref)
13117 : : {
13118 : 391 : appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
13119 : 391 : free(oprref);
13120 : : }
13121 : :
6322 tgl@sss.pgh.pa.us 13122 [ + + ]: 890 : if (strcmp(oprcanmerge, "t") == 0)
3800 heikki.linnakangas@i 13123 : 75 : appendPQExpBufferStr(details, ",\n MERGES");
13124 : :
8010 tgl@sss.pgh.pa.us 13125 [ + + ]: 890 : if (strcmp(oprcanhash, "t") == 0)
3800 heikki.linnakangas@i 13126 : 46 : appendPQExpBufferStr(details, ",\n HASHES");
13127 : :
1328 peter@eisentraut.org 13128 : 890 : oprregproc = convertRegProcReference(oprrest);
3697 sfrost@snowman.net 13129 [ + + ]: 890 : if (oprregproc)
13130 : : {
13131 : 518 : appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
13132 : 518 : free(oprregproc);
13133 : : }
13134 : :
1328 peter@eisentraut.org 13135 : 890 : oprregproc = convertRegProcReference(oprjoin);
3697 sfrost@snowman.net 13136 [ + + ]: 890 : if (oprregproc)
13137 : : {
13138 : 518 : appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
13139 : 518 : free(oprregproc);
13140 : : }
13141 : :
7992 tgl@sss.pgh.pa.us 13142 : 890 : appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
7347 13143 : 890 : fmtId(oprinfo->dobj.namespace->dobj.name),
13144 : : oprid->data);
13145 : :
2239 13146 : 890 : appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
13147 : 890 : fmtId(oprinfo->dobj.namespace->dobj.name),
7347 13148 : 890 : oprinfo->dobj.name, details->data);
13149 : :
3470 alvherre@alvh.no-ip. 13150 [ + + ]: 890 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 13151 : 12 : binary_upgrade_extension_member(q, &oprinfo->dobj,
13152 : 12 : "OPERATOR", oprid->data,
13153 : 12 : oprinfo->dobj.namespace->dobj.name);
13154 : :
2930 sfrost@snowman.net 13155 [ + - ]: 890 : if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13156 : 890 : ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 13157 : 890 : ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
13158 : : .namespace = oprinfo->dobj.namespace->dobj.name,
13159 : : .owner = oprinfo->rolname,
13160 : : .description = "OPERATOR",
13161 : : .section = SECTION_PRE_DATA,
13162 : : .createStmt = q->data,
13163 : : .dropStmt = delq->data));
13164 : :
13165 : : /* Dump Operator Comments */
2930 sfrost@snowman.net 13166 [ + + ]: 890 : if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 13167 : 799 : dumpComment(fout, "OPERATOR", oprid->data,
2930 sfrost@snowman.net 13168 : 799 : oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
13169 : 799 : oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
13170 : :
8010 tgl@sss.pgh.pa.us 13171 : 890 : PQclear(res);
13172 : :
13173 : 890 : destroyPQExpBuffer(query);
13174 : 890 : destroyPQExpBuffer(q);
13175 : 890 : destroyPQExpBuffer(delq);
13176 : 890 : destroyPQExpBuffer(oprid);
13177 : 890 : destroyPQExpBuffer(details);
13178 : : }
13179 : :
13180 : : /*
13181 : : * Convert a function reference obtained from pg_operator
13182 : : *
13183 : : * Returns allocated string of what to print, or NULL if function references
13184 : : * is InvalidOid. Returned string is expected to be free'd by the caller.
13185 : : *
13186 : : * The input is a REGPROCEDURE display; we have to strip the argument-types
13187 : : * part.
13188 : : */
13189 : : static char *
1328 peter@eisentraut.org 13190 : 2670 : convertRegProcReference(const char *proc)
13191 : : {
13192 : : char *name;
13193 : : char *paren;
13194 : : bool inquote;
13195 : :
13196 : : /* In all cases "-" means a null reference */
8010 tgl@sss.pgh.pa.us 13197 [ + + ]: 2670 : if (strcmp(proc, "-") == 0)
13198 : 744 : return NULL;
13199 : :
2741 13200 : 1926 : name = pg_strdup(proc);
13201 : : /* find non-double-quoted left paren */
13202 : 1926 : inquote = false;
13203 [ + - ]: 23128 : for (paren = name; *paren; paren++)
13204 : : {
13205 [ + + + - ]: 23128 : if (*paren == '(' && !inquote)
13206 : : {
13207 : 1926 : *paren = '\0';
13208 : 1926 : break;
13209 : : }
13210 [ + + ]: 21202 : if (*paren == '"')
13211 : 50 : inquote = !inquote;
13212 : : }
13213 : 1926 : return name;
13214 : : }
13215 : :
13216 : : /*
13217 : : * getFormattedOperatorName - retrieve the operator name for the
13218 : : * given operator OID (presented in string form).
13219 : : *
13220 : : * Returns an allocated string, or NULL if the given OID is invalid.
13221 : : * Caller is responsible for free'ing result string.
13222 : : *
13223 : : * What we produce has the format "OPERATOR(schema.oprname)". This is only
13224 : : * useful in commands where the operator's argument types can be inferred from
13225 : : * context. We always schema-qualify the name, though. The predecessor to
13226 : : * this code tried to skip the schema qualification if possible, but that led
13227 : : * to wrong results in corner cases, such as if an operator and its negator
13228 : : * are in different schemas.
13229 : : */
13230 : : static char *
1328 peter@eisentraut.org 13231 : 2069 : getFormattedOperatorName(const char *oproid)
13232 : : {
13233 : : OprInfo *oprInfo;
13234 : :
13235 : : /* In all cases "0" means a null reference */
2239 tgl@sss.pgh.pa.us 13236 [ + + ]: 2069 : if (strcmp(oproid, "0") == 0)
8010 13237 : 1111 : return NULL;
13238 : :
2239 13239 : 958 : oprInfo = findOprByOid(atooid(oproid));
13240 [ - + ]: 958 : if (oprInfo == NULL)
13241 : : {
1840 peter@eisentraut.org 13242 :UBC 0 : pg_log_warning("could not find operator with OID %s",
13243 : : oproid);
2239 tgl@sss.pgh.pa.us 13244 : 0 : return NULL;
13245 : : }
13246 : :
2239 tgl@sss.pgh.pa.us 13247 :CBC 958 : return psprintf("OPERATOR(%s.%s)",
13248 : 958 : fmtId(oprInfo->dobj.namespace->dobj.name),
13249 : : oprInfo->dobj.name);
13250 : : }
13251 : :
13252 : : /*
13253 : : * Convert a function OID obtained from pg_ts_parser or pg_ts_template
13254 : : *
13255 : : * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
13256 : : * argument lists of these functions are predetermined. Note that the
13257 : : * caller should ensure we are in the proper schema, because the results
13258 : : * are search path dependent!
13259 : : */
13260 : : static char *
4450 rhaas@postgresql.org 13261 : 195 : convertTSFunction(Archive *fout, Oid funcOid)
13262 : : {
13263 : : char *result;
13264 : : char query[128];
13265 : : PGresult *res;
13266 : :
6081 tgl@sss.pgh.pa.us 13267 : 195 : snprintf(query, sizeof(query),
13268 : : "SELECT '%u'::pg_catalog.regproc", funcOid);
4441 rhaas@postgresql.org 13269 : 195 : res = ExecuteSqlQueryForSingleRow(fout, query);
13270 : :
4524 bruce@momjian.us 13271 : 195 : result = pg_strdup(PQgetvalue(res, 0, 0));
13272 : :
6081 tgl@sss.pgh.pa.us 13273 : 195 : PQclear(res);
13274 : :
13275 : 195 : return result;
13276 : : }
13277 : :
13278 : : /*
13279 : : * dumpAccessMethod
13280 : : * write out a single access method definition
13281 : : */
13282 : : static void
1159 peter@eisentraut.org 13283 : 82 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
13284 : : {
2944 alvherre@alvh.no-ip. 13285 : 82 : DumpOptions *dopt = fout->dopt;
13286 : : PQExpBuffer q;
13287 : : PQExpBuffer delq;
13288 : : char *qamname;
13289 : :
13290 : : /* Do nothing in data-only dump */
860 tgl@sss.pgh.pa.us 13291 [ + + ]: 82 : if (dopt->dataOnly)
2944 alvherre@alvh.no-ip. 13292 : 6 : return;
13293 : :
13294 : 76 : q = createPQExpBuffer();
13295 : 76 : delq = createPQExpBuffer();
13296 : :
13297 : 76 : qamname = pg_strdup(fmtId(aminfo->dobj.name));
13298 : :
13299 : 76 : appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
13300 : :
13301 [ + + - ]: 76 : switch (aminfo->amtype)
13302 : : {
13303 : 36 : case AMTYPE_INDEX:
1746 drowley@postgresql.o 13304 : 36 : appendPQExpBufferStr(q, "TYPE INDEX ");
2944 alvherre@alvh.no-ip. 13305 : 36 : break;
1866 andres@anarazel.de 13306 : 40 : case AMTYPE_TABLE:
1746 drowley@postgresql.o 13307 : 40 : appendPQExpBufferStr(q, "TYPE TABLE ");
1866 andres@anarazel.de 13308 : 40 : break;
2944 alvherre@alvh.no-ip. 13309 :UBC 0 : default:
1840 peter@eisentraut.org 13310 : 0 : pg_log_warning("invalid type \"%c\" of access method \"%s\"",
13311 : : aminfo->amtype, qamname);
2944 alvherre@alvh.no-ip. 13312 : 0 : destroyPQExpBuffer(q);
13313 : 0 : destroyPQExpBuffer(delq);
2239 tgl@sss.pgh.pa.us 13314 : 0 : free(qamname);
2944 alvherre@alvh.no-ip. 13315 : 0 : return;
13316 : : }
13317 : :
2944 alvherre@alvh.no-ip. 13318 :CBC 76 : appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
13319 : :
13320 : 76 : appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
13321 : : qamname);
13322 : :
2751 tgl@sss.pgh.pa.us 13323 [ + + ]: 76 : if (dopt->binary_upgrade)
2239 13324 : 4 : binary_upgrade_extension_member(q, &aminfo->dobj,
13325 : : "ACCESS METHOD", qamname, NULL);
13326 : :
2868 sfrost@snowman.net 13327 [ + - ]: 76 : if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13328 : 76 : ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 13329 : 76 : ARCHIVE_OPTS(.tag = aminfo->dobj.name,
13330 : : .description = "ACCESS METHOD",
13331 : : .section = SECTION_PRE_DATA,
13332 : : .createStmt = q->data,
13333 : : .dropStmt = delq->data));
13334 : :
13335 : : /* Dump Access Method Comments */
2868 sfrost@snowman.net 13336 [ - + ]: 76 : if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 13337 :UBC 0 : dumpComment(fout, "ACCESS METHOD", qamname,
13338 : : NULL, "",
2868 sfrost@snowman.net 13339 : 0 : aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
13340 : :
2944 alvherre@alvh.no-ip. 13341 :CBC 76 : destroyPQExpBuffer(q);
13342 : 76 : destroyPQExpBuffer(delq);
2239 tgl@sss.pgh.pa.us 13343 : 76 : free(qamname);
13344 : : }
13345 : :
13346 : : /*
13347 : : * dumpOpclass
13348 : : * write out a single operator class definition
13349 : : */
13350 : : static void
1159 peter@eisentraut.org 13351 : 309 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
13352 : : {
3014 tgl@sss.pgh.pa.us 13353 : 309 : DumpOptions *dopt = fout->dopt;
13354 : : PQExpBuffer query;
13355 : : PQExpBuffer q;
13356 : : PQExpBuffer delq;
13357 : : PQExpBuffer nameusing;
13358 : : PGresult *res;
13359 : : int ntups;
13360 : : int i_opcintype;
13361 : : int i_opckeytype;
13362 : : int i_opcdefault;
13363 : : int i_opcfamily;
13364 : : int i_opcfamilyname;
13365 : : int i_opcfamilynsp;
13366 : : int i_amname;
13367 : : int i_amopstrategy;
13368 : : int i_amopopr;
13369 : : int i_sortfamily;
13370 : : int i_sortfamilynsp;
13371 : : int i_amprocnum;
13372 : : int i_amproc;
13373 : : int i_amproclefttype;
13374 : : int i_amprocrighttype;
13375 : : char *opcintype;
13376 : : char *opckeytype;
13377 : : char *opcdefault;
13378 : : char *opcfamily;
13379 : : char *opcfamilyname;
13380 : : char *opcfamilynsp;
13381 : : char *amname;
13382 : : char *amopstrategy;
13383 : : char *amopopr;
13384 : : char *sortfamily;
13385 : : char *sortfamilynsp;
13386 : : char *amprocnum;
13387 : : char *amproc;
13388 : : char *amproclefttype;
13389 : : char *amprocrighttype;
13390 : : bool needComma;
13391 : : int i;
13392 : :
13393 : : /* Do nothing in data-only dump */
860 13394 [ + + ]: 309 : if (dopt->dataOnly)
7435 13395 : 9 : return;
13396 : :
13397 : 300 : query = createPQExpBuffer();
13398 : 300 : q = createPQExpBuffer();
13399 : 300 : delq = createPQExpBuffer();
2239 13400 : 300 : nameusing = createPQExpBuffer();
13401 : :
13402 : : /* Get additional fields from the pg_opclass row */
852 13403 : 300 : appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
13404 : : "opckeytype::pg_catalog.regtype, "
13405 : : "opcdefault, opcfamily, "
13406 : : "opfname AS opcfamilyname, "
13407 : : "nspname AS opcfamilynsp, "
13408 : : "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
13409 : : "FROM pg_catalog.pg_opclass c "
13410 : : "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
13411 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13412 : : "WHERE c.oid = '%u'::pg_catalog.oid",
13413 : 300 : opcinfo->dobj.catId.oid);
13414 : :
4441 rhaas@postgresql.org 13415 : 300 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13416 : :
7929 tgl@sss.pgh.pa.us 13417 : 300 : i_opcintype = PQfnumber(res, "opcintype");
13418 : 300 : i_opckeytype = PQfnumber(res, "opckeytype");
13419 : 300 : i_opcdefault = PQfnumber(res, "opcdefault");
6291 13420 : 300 : i_opcfamily = PQfnumber(res, "opcfamily");
4890 13421 : 300 : i_opcfamilyname = PQfnumber(res, "opcfamilyname");
6291 13422 : 300 : i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
7929 13423 : 300 : i_amname = PQfnumber(res, "amname");
13424 : :
13425 : : /* opcintype may still be needed after we PQclear res */
2515 13426 : 300 : opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
7929 13427 : 300 : opckeytype = PQgetvalue(res, 0, i_opckeytype);
13428 : 300 : opcdefault = PQgetvalue(res, 0, i_opcdefault);
13429 : : /* opcfamily will still be needed after we PQclear res */
4524 bruce@momjian.us 13430 : 300 : opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
4890 tgl@sss.pgh.pa.us 13431 : 300 : opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
6291 13432 : 300 : opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
13433 : : /* amname will still be needed after we PQclear res */
4524 bruce@momjian.us 13434 : 300 : amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13435 : :
7929 tgl@sss.pgh.pa.us 13436 : 300 : appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
2239 13437 : 300 : fmtQualifiedDumpable(opcinfo));
7929 13438 : 300 : appendPQExpBuffer(delq, " USING %s;\n",
13439 : : fmtId(amname));
13440 : :
13441 : : /* Build the fixed portion of the CREATE command */
7910 peter_e@gmx.net 13442 : 300 : appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
2239 tgl@sss.pgh.pa.us 13443 : 300 : fmtQualifiedDumpable(opcinfo));
7929 13444 [ + + ]: 300 : if (strcmp(opcdefault, "t") == 0)
3800 heikki.linnakangas@i 13445 : 119 : appendPQExpBufferStr(q, "DEFAULT ");
6291 tgl@sss.pgh.pa.us 13446 : 300 : appendPQExpBuffer(q, "FOR TYPE %s USING %s",
13447 : : opcintype,
13448 : : fmtId(amname));
2923 13449 [ + - ]: 300 : if (strlen(opcfamilyname) > 0)
13450 : : {
3800 heikki.linnakangas@i 13451 : 300 : appendPQExpBufferStr(q, " FAMILY ");
2239 tgl@sss.pgh.pa.us 13452 : 300 : appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
3209 heikki.linnakangas@i 13453 : 300 : appendPQExpBufferStr(q, fmtId(opcfamilyname));
13454 : : }
3800 13455 : 300 : appendPQExpBufferStr(q, " AS\n ");
13456 : :
7929 tgl@sss.pgh.pa.us 13457 : 300 : needComma = false;
13458 : :
13459 [ + + ]: 300 : if (strcmp(opckeytype, "-") != 0)
13460 : : {
7910 peter_e@gmx.net 13461 : 84 : appendPQExpBuffer(q, "STORAGE %s",
13462 : : opckeytype);
7929 tgl@sss.pgh.pa.us 13463 : 84 : needComma = true;
13464 : : }
13465 : :
13466 : 300 : PQclear(res);
13467 : :
13468 : : /*
13469 : : * Now fetch and print the OPERATOR entries (pg_amop rows).
13470 : : *
13471 : : * Print only those opfamily members that are tied to the opclass by
13472 : : * pg_depend entries.
13473 : : */
13474 : 300 : resetPQExpBuffer(query);
852 13475 : 300 : appendPQExpBuffer(query, "SELECT amopstrategy, "
13476 : : "amopopr::pg_catalog.regoperator, "
13477 : : "opfname AS sortfamily, "
13478 : : "nspname AS sortfamilynsp "
13479 : : "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13480 : : "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13481 : : "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13482 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13483 : : "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13484 : : "AND refobjid = '%u'::pg_catalog.oid "
13485 : : "AND amopfamily = '%s'::pg_catalog.oid "
13486 : : "ORDER BY amopstrategy",
13487 : 300 : opcinfo->dobj.catId.oid,
13488 : : opcfamily);
13489 : :
4450 rhaas@postgresql.org 13490 : 300 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13491 : :
7929 tgl@sss.pgh.pa.us 13492 : 300 : ntups = PQntuples(res);
13493 : :
13494 : 300 : i_amopstrategy = PQfnumber(res, "amopstrategy");
13495 : 300 : i_amopopr = PQfnumber(res, "amopopr");
4890 13496 : 300 : i_sortfamily = PQfnumber(res, "sortfamily");
13497 : 300 : i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
13498 : :
7929 13499 [ + + ]: 526 : for (i = 0; i < ntups; i++)
13500 : : {
13501 : 226 : amopstrategy = PQgetvalue(res, i, i_amopstrategy);
13502 : 226 : amopopr = PQgetvalue(res, i, i_amopopr);
4890 13503 : 226 : sortfamily = PQgetvalue(res, i, i_sortfamily);
13504 : 226 : sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
13505 : :
7929 13506 [ + + ]: 226 : if (needComma)
3800 heikki.linnakangas@i 13507 : 144 : appendPQExpBufferStr(q, " ,\n ");
13508 : :
7910 peter_e@gmx.net 13509 : 226 : appendPQExpBuffer(q, "OPERATOR %s %s",
13510 : : amopstrategy, amopopr);
13511 : :
4890 tgl@sss.pgh.pa.us 13512 [ - + ]: 226 : if (strlen(sortfamily) > 0)
13513 : : {
3800 heikki.linnakangas@i 13514 :UBC 0 : appendPQExpBufferStr(q, " FOR ORDER BY ");
2239 tgl@sss.pgh.pa.us 13515 : 0 : appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
3800 heikki.linnakangas@i 13516 : 0 : appendPQExpBufferStr(q, fmtId(sortfamily));
13517 : : }
13518 : :
7929 tgl@sss.pgh.pa.us 13519 :CBC 226 : needComma = true;
13520 : : }
13521 : :
13522 : 300 : PQclear(res);
13523 : :
13524 : : /*
13525 : : * Now fetch and print the FUNCTION entries (pg_amproc rows).
13526 : : *
13527 : : * Print only those opfamily members that are tied to the opclass by
13528 : : * pg_depend entries.
13529 : : *
13530 : : * We print the amproclefttype/amprocrighttype even though in most cases
13531 : : * the backend could deduce the right values, because of the corner case
13532 : : * of a btree sort support function for a cross-type comparison.
13533 : : */
13534 : 300 : resetPQExpBuffer(query);
13535 : :
852 13536 : 300 : appendPQExpBuffer(query, "SELECT amprocnum, "
13537 : : "amproc::pg_catalog.regprocedure, "
13538 : : "amproclefttype::pg_catalog.regtype, "
13539 : : "amprocrighttype::pg_catalog.regtype "
13540 : : "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13541 : : "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13542 : : "AND refobjid = '%u'::pg_catalog.oid "
13543 : : "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13544 : : "AND objid = ap.oid "
13545 : : "ORDER BY amprocnum",
13546 : 300 : opcinfo->dobj.catId.oid);
13547 : :
4450 rhaas@postgresql.org 13548 : 300 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13549 : :
7929 tgl@sss.pgh.pa.us 13550 : 300 : ntups = PQntuples(res);
13551 : :
13552 : 300 : i_amprocnum = PQfnumber(res, "amprocnum");
13553 : 300 : i_amproc = PQfnumber(res, "amproc");
4512 13554 : 300 : i_amproclefttype = PQfnumber(res, "amproclefttype");
13555 : 300 : i_amprocrighttype = PQfnumber(res, "amprocrighttype");
13556 : :
7929 13557 [ + + ]: 336 : for (i = 0; i < ntups; i++)
13558 : : {
13559 : 36 : amprocnum = PQgetvalue(res, i, i_amprocnum);
13560 : 36 : amproc = PQgetvalue(res, i, i_amproc);
4512 13561 : 36 : amproclefttype = PQgetvalue(res, i, i_amproclefttype);
13562 : 36 : amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
13563 : :
7929 13564 [ + - ]: 36 : if (needComma)
3800 heikki.linnakangas@i 13565 : 36 : appendPQExpBufferStr(q, " ,\n ");
13566 : :
4512 tgl@sss.pgh.pa.us 13567 : 36 : appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
13568 : :
13569 [ + - + - ]: 36 : if (*amproclefttype && *amprocrighttype)
13570 : 36 : appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
13571 : :
13572 : 36 : appendPQExpBuffer(q, " %s", amproc);
13573 : :
7929 13574 : 36 : needComma = true;
13575 : : }
13576 : :
13577 : 300 : PQclear(res);
13578 : :
13579 : : /*
13580 : : * If needComma is still false it means we haven't added anything after
13581 : : * the AS keyword. To avoid printing broken SQL, append a dummy STORAGE
13582 : : * clause with the same datatype. This isn't sanctioned by the
13583 : : * documentation, but actually DefineOpClass will treat it as a no-op.
13584 : : */
2515 13585 [ + + ]: 300 : if (!needComma)
13586 : 134 : appendPQExpBuffer(q, "STORAGE %s", opcintype);
13587 : :
3800 heikki.linnakangas@i 13588 : 300 : appendPQExpBufferStr(q, ";\n");
13589 : :
2239 tgl@sss.pgh.pa.us 13590 : 300 : appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
13591 : 300 : appendPQExpBuffer(nameusing, " USING %s",
13592 : : fmtId(amname));
13593 : :
3470 alvherre@alvh.no-ip. 13594 [ + + ]: 300 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 13595 : 6 : binary_upgrade_extension_member(q, &opcinfo->dobj,
13596 : 6 : "OPERATOR CLASS", nameusing->data,
13597 : 6 : opcinfo->dobj.namespace->dobj.name);
13598 : :
2930 sfrost@snowman.net 13599 [ + - ]: 300 : if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13600 : 300 : ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 13601 : 300 : ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
13602 : : .namespace = opcinfo->dobj.namespace->dobj.name,
13603 : : .owner = opcinfo->rolname,
13604 : : .description = "OPERATOR CLASS",
13605 : : .section = SECTION_PRE_DATA,
13606 : : .createStmt = q->data,
13607 : : .dropStmt = delq->data));
13608 : :
13609 : : /* Dump Operator Class Comments */
2930 sfrost@snowman.net 13610 [ - + ]: 300 : if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 13611 :UBC 0 : dumpComment(fout, "OPERATOR CLASS", nameusing->data,
2596 13612 : 0 : opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
2930 sfrost@snowman.net 13613 : 0 : opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13614 : :
2515 tgl@sss.pgh.pa.us 13615 :CBC 300 : free(opcintype);
13616 : 300 : free(opcfamily);
7450 13617 : 300 : free(amname);
7929 13618 : 300 : destroyPQExpBuffer(query);
13619 : 300 : destroyPQExpBuffer(q);
13620 : 300 : destroyPQExpBuffer(delq);
2239 13621 : 300 : destroyPQExpBuffer(nameusing);
13622 : : }
13623 : :
13624 : : /*
13625 : : * dumpOpfamily
13626 : : * write out a single operator family definition
13627 : : *
13628 : : * Note: this also dumps any "loose" operator members that aren't bound to a
13629 : : * specific opclass within the opfamily.
13630 : : */
13631 : : static void
1159 peter@eisentraut.org 13632 : 259 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
13633 : : {
3014 tgl@sss.pgh.pa.us 13634 : 259 : DumpOptions *dopt = fout->dopt;
13635 : : PQExpBuffer query;
13636 : : PQExpBuffer q;
13637 : : PQExpBuffer delq;
13638 : : PQExpBuffer nameusing;
13639 : : PGresult *res;
13640 : : PGresult *res_ops;
13641 : : PGresult *res_procs;
13642 : : int ntups;
13643 : : int i_amname;
13644 : : int i_amopstrategy;
13645 : : int i_amopopr;
13646 : : int i_sortfamily;
13647 : : int i_sortfamilynsp;
13648 : : int i_amprocnum;
13649 : : int i_amproc;
13650 : : int i_amproclefttype;
13651 : : int i_amprocrighttype;
13652 : : char *amname;
13653 : : char *amopstrategy;
13654 : : char *amopopr;
13655 : : char *sortfamily;
13656 : : char *sortfamilynsp;
13657 : : char *amprocnum;
13658 : : char *amproc;
13659 : : char *amproclefttype;
13660 : : char *amprocrighttype;
13661 : : bool needComma;
13662 : : int i;
13663 : :
13664 : : /* Do nothing in data-only dump */
860 13665 [ + + ]: 259 : if (dopt->dataOnly)
6291 13666 : 6 : return;
13667 : :
13668 : 253 : query = createPQExpBuffer();
13669 : 253 : q = createPQExpBuffer();
13670 : 253 : delq = createPQExpBuffer();
2239 13671 : 253 : nameusing = createPQExpBuffer();
13672 : :
13673 : : /*
13674 : : * Fetch only those opfamily members that are tied directly to the
13675 : : * opfamily by pg_depend entries.
13676 : : */
852 13677 : 253 : appendPQExpBuffer(query, "SELECT amopstrategy, "
13678 : : "amopopr::pg_catalog.regoperator, "
13679 : : "opfname AS sortfamily, "
13680 : : "nspname AS sortfamilynsp "
13681 : : "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13682 : : "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13683 : : "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13684 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13685 : : "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13686 : : "AND refobjid = '%u'::pg_catalog.oid "
13687 : : "AND amopfamily = '%u'::pg_catalog.oid "
13688 : : "ORDER BY amopstrategy",
13689 : 253 : opfinfo->dobj.catId.oid,
13690 : 253 : opfinfo->dobj.catId.oid);
13691 : :
4450 rhaas@postgresql.org 13692 : 253 : res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13693 : :
6291 tgl@sss.pgh.pa.us 13694 : 253 : resetPQExpBuffer(query);
13695 : :
13696 : 253 : appendPQExpBuffer(query, "SELECT amprocnum, "
13697 : : "amproc::pg_catalog.regprocedure, "
13698 : : "amproclefttype::pg_catalog.regtype, "
13699 : : "amprocrighttype::pg_catalog.regtype "
13700 : : "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13701 : : "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13702 : : "AND refobjid = '%u'::pg_catalog.oid "
13703 : : "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13704 : : "AND objid = ap.oid "
13705 : : "ORDER BY amprocnum",
13706 : 253 : opfinfo->dobj.catId.oid);
13707 : :
4450 rhaas@postgresql.org 13708 : 253 : res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13709 : :
13710 : : /* Get additional fields from the pg_opfamily row */
6291 tgl@sss.pgh.pa.us 13711 : 253 : resetPQExpBuffer(query);
13712 : :
13713 : 253 : appendPQExpBuffer(query, "SELECT "
13714 : : "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13715 : : "FROM pg_catalog.pg_opfamily "
13716 : : "WHERE oid = '%u'::pg_catalog.oid",
13717 : 253 : opfinfo->dobj.catId.oid);
13718 : :
4441 rhaas@postgresql.org 13719 : 253 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13720 : :
6291 tgl@sss.pgh.pa.us 13721 : 253 : i_amname = PQfnumber(res, "amname");
13722 : :
13723 : : /* amname will still be needed after we PQclear res */
4524 bruce@momjian.us 13724 : 253 : amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13725 : :
6291 tgl@sss.pgh.pa.us 13726 : 253 : appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
2239 13727 : 253 : fmtQualifiedDumpable(opfinfo));
6291 13728 : 253 : appendPQExpBuffer(delq, " USING %s;\n",
13729 : : fmtId(amname));
13730 : :
13731 : : /* Build the fixed portion of the CREATE command */
13732 : 253 : appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
2239 13733 : 253 : fmtQualifiedDumpable(opfinfo));
6291 13734 : 253 : appendPQExpBuffer(q, " USING %s;\n",
13735 : : fmtId(amname));
13736 : :
13737 : 253 : PQclear(res);
13738 : :
13739 : : /* Do we need an ALTER to add loose members? */
13740 [ + + + + ]: 253 : if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13741 : : {
13742 : 51 : appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
2239 13743 : 51 : fmtQualifiedDumpable(opfinfo));
6291 13744 : 51 : appendPQExpBuffer(q, " USING %s ADD\n ",
13745 : : fmtId(amname));
13746 : :
13747 : 51 : needComma = false;
13748 : :
13749 : : /*
13750 : : * Now fetch and print the OPERATOR entries (pg_amop rows).
13751 : : */
13752 : 51 : ntups = PQntuples(res_ops);
13753 : :
13754 : 51 : i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13755 : 51 : i_amopopr = PQfnumber(res_ops, "amopopr");
4890 13756 : 51 : i_sortfamily = PQfnumber(res_ops, "sortfamily");
13757 : 51 : i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13758 : :
6291 13759 [ + + ]: 231 : for (i = 0; i < ntups; i++)
13760 : : {
13761 : 180 : amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13762 : 180 : amopopr = PQgetvalue(res_ops, i, i_amopopr);
4890 13763 : 180 : sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13764 : 180 : sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13765 : :
6291 13766 [ + + ]: 180 : if (needComma)
3800 heikki.linnakangas@i 13767 : 144 : appendPQExpBufferStr(q, " ,\n ");
13768 : :
6291 tgl@sss.pgh.pa.us 13769 : 180 : appendPQExpBuffer(q, "OPERATOR %s %s",
13770 : : amopstrategy, amopopr);
13771 : :
4890 13772 [ - + ]: 180 : if (strlen(sortfamily) > 0)
13773 : : {
3800 heikki.linnakangas@i 13774 :UBC 0 : appendPQExpBufferStr(q, " FOR ORDER BY ");
2239 tgl@sss.pgh.pa.us 13775 : 0 : appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
3800 heikki.linnakangas@i 13776 : 0 : appendPQExpBufferStr(q, fmtId(sortfamily));
13777 : : }
13778 : :
6291 tgl@sss.pgh.pa.us 13779 :CBC 180 : needComma = true;
13780 : : }
13781 : :
13782 : : /*
13783 : : * Now fetch and print the FUNCTION entries (pg_amproc rows).
13784 : : */
13785 : 51 : ntups = PQntuples(res_procs);
13786 : :
13787 : 51 : i_amprocnum = PQfnumber(res_procs, "amprocnum");
13788 : 51 : i_amproc = PQfnumber(res_procs, "amproc");
13789 : 51 : i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13790 : 51 : i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13791 : :
13792 [ + + ]: 246 : for (i = 0; i < ntups; i++)
13793 : : {
13794 : 195 : amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13795 : 195 : amproc = PQgetvalue(res_procs, i, i_amproc);
13796 : 195 : amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13797 : 195 : amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13798 : :
13799 [ + + ]: 195 : if (needComma)
3800 heikki.linnakangas@i 13800 : 180 : appendPQExpBufferStr(q, " ,\n ");
13801 : :
6291 tgl@sss.pgh.pa.us 13802 : 195 : appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13803 : : amprocnum, amproclefttype, amprocrighttype,
13804 : : amproc);
13805 : :
13806 : 195 : needComma = true;
13807 : : }
13808 : :
3800 heikki.linnakangas@i 13809 : 51 : appendPQExpBufferStr(q, ";\n");
13810 : : }
13811 : :
2239 tgl@sss.pgh.pa.us 13812 : 253 : appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13813 : 253 : appendPQExpBuffer(nameusing, " USING %s",
13814 : : fmtId(amname));
13815 : :
3470 alvherre@alvh.no-ip. 13816 [ + + ]: 253 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 13817 : 9 : binary_upgrade_extension_member(q, &opfinfo->dobj,
13818 : 9 : "OPERATOR FAMILY", nameusing->data,
13819 : 9 : opfinfo->dobj.namespace->dobj.name);
13820 : :
2930 sfrost@snowman.net 13821 [ + - ]: 253 : if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13822 : 253 : ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 13823 : 253 : ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
13824 : : .namespace = opfinfo->dobj.namespace->dobj.name,
13825 : : .owner = opfinfo->rolname,
13826 : : .description = "OPERATOR FAMILY",
13827 : : .section = SECTION_PRE_DATA,
13828 : : .createStmt = q->data,
13829 : : .dropStmt = delq->data));
13830 : :
13831 : : /* Dump Operator Family Comments */
2930 sfrost@snowman.net 13832 [ - + ]: 253 : if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 13833 :UBC 0 : dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
2596 13834 : 0 : opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
2930 sfrost@snowman.net 13835 : 0 : opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13836 : :
6291 tgl@sss.pgh.pa.us 13837 :CBC 253 : free(amname);
13838 : 253 : PQclear(res_ops);
13839 : 253 : PQclear(res_procs);
13840 : 253 : destroyPQExpBuffer(query);
13841 : 253 : destroyPQExpBuffer(q);
13842 : 253 : destroyPQExpBuffer(delq);
2239 13843 : 253 : destroyPQExpBuffer(nameusing);
13844 : : }
13845 : :
13846 : : /*
13847 : : * dumpCollation
13848 : : * write out a single collation definition
13849 : : */
13850 : : static void
1159 peter@eisentraut.org 13851 : 1547 : dumpCollation(Archive *fout, const CollInfo *collinfo)
13852 : : {
3014 tgl@sss.pgh.pa.us 13853 : 1547 : DumpOptions *dopt = fout->dopt;
13854 : : PQExpBuffer query;
13855 : : PQExpBuffer q;
13856 : : PQExpBuffer delq;
13857 : : char *qcollname;
13858 : : PGresult *res;
13859 : : int i_collprovider;
13860 : : int i_collisdeterministic;
13861 : : int i_collcollate;
13862 : : int i_collctype;
13863 : : int i_colllocale;
13864 : : int i_collicurules;
13865 : : const char *collprovider;
13866 : : const char *collcollate;
13867 : : const char *collctype;
13868 : : const char *colllocale;
13869 : : const char *collicurules;
13870 : :
13871 : : /* Do nothing in data-only dump */
860 13872 [ + + ]: 1547 : if (dopt->dataOnly)
4810 peter_e@gmx.net 13873 : 6 : return;
13874 : :
13875 : 1541 : query = createPQExpBuffer();
13876 : 1541 : q = createPQExpBuffer();
13877 : 1541 : delq = createPQExpBuffer();
13878 : :
2239 tgl@sss.pgh.pa.us 13879 : 1541 : qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13880 : :
13881 : : /* Get collation-specific details */
1746 drowley@postgresql.o 13882 : 1541 : appendPQExpBufferStr(query, "SELECT ");
13883 : :
2579 peter_e@gmx.net 13884 [ + - ]: 1541 : if (fout->remoteVersion >= 100000)
1746 drowley@postgresql.o 13885 : 1541 : appendPQExpBufferStr(query,
13886 : : "collprovider, "
13887 : : "collversion, ");
13888 : : else
1746 drowley@postgresql.o 13889 :UBC 0 : appendPQExpBufferStr(query,
13890 : : "'c' AS collprovider, "
13891 : : "NULL AS collversion, ");
13892 : :
1850 peter@eisentraut.org 13893 [ + - ]:CBC 1541 : if (fout->remoteVersion >= 120000)
1746 drowley@postgresql.o 13894 : 1541 : appendPQExpBufferStr(query,
13895 : : "collisdeterministic, ");
13896 : : else
1746 drowley@postgresql.o 13897 :UBC 0 : appendPQExpBufferStr(query,
13898 : : "true AS collisdeterministic, ");
13899 : :
36 jdavis@postgresql.or 13900 [ + - ]:GNC 1541 : if (fout->remoteVersion >= 170000)
36 jdavis@postgresql.or 13901 :CBC 1541 : appendPQExpBufferStr(query,
13902 : : "colllocale, ");
36 jdavis@postgresql.or 13903 [ # # ]:UNC 0 : else if (fout->remoteVersion >= 150000)
599 peter@eisentraut.org 13904 : 0 : appendPQExpBufferStr(query,
13905 : : "colliculocale AS colllocale, ");
13906 : : else
599 peter@eisentraut.org 13907 :UBC 0 : appendPQExpBufferStr(query,
13908 : : "NULL AS colllocale, ");
13909 : :
403 peter@eisentraut.org 13910 [ + - ]:CBC 1541 : if (fout->remoteVersion >= 160000)
13911 : 1541 : appendPQExpBufferStr(query,
13912 : : "collicurules, ");
13913 : : else
403 peter@eisentraut.org 13914 :UBC 0 : appendPQExpBufferStr(query,
13915 : : "NULL AS collicurules, ");
13916 : :
1850 peter@eisentraut.org 13917 :CBC 1541 : appendPQExpBuffer(query,
13918 : : "collcollate, "
13919 : : "collctype "
13920 : : "FROM pg_catalog.pg_collation c "
13921 : : "WHERE c.oid = '%u'::pg_catalog.oid",
13922 : 1541 : collinfo->dobj.catId.oid);
13923 : :
4441 rhaas@postgresql.org 13924 : 1541 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13925 : :
2579 peter_e@gmx.net 13926 : 1541 : i_collprovider = PQfnumber(res, "collprovider");
1850 peter@eisentraut.org 13927 : 1541 : i_collisdeterministic = PQfnumber(res, "collisdeterministic");
4810 peter_e@gmx.net 13928 : 1541 : i_collcollate = PQfnumber(res, "collcollate");
13929 : 1541 : i_collctype = PQfnumber(res, "collctype");
36 jdavis@postgresql.or 13930 :GNC 1541 : i_colllocale = PQfnumber(res, "colllocale");
403 peter@eisentraut.org 13931 :CBC 1541 : i_collicurules = PQfnumber(res, "collicurules");
13932 : :
2579 peter_e@gmx.net 13933 : 1541 : collprovider = PQgetvalue(res, 0, i_collprovider);
13934 : :
599 peter@eisentraut.org 13935 [ + + ]: 1541 : if (!PQgetisnull(res, 0, i_collcollate))
13936 : 686 : collcollate = PQgetvalue(res, 0, i_collcollate);
13937 : : else
13938 : 855 : collcollate = NULL;
13939 : :
13940 [ + + ]: 1541 : if (!PQgetisnull(res, 0, i_collctype))
13941 : 686 : collctype = PQgetvalue(res, 0, i_collctype);
13942 : : else
13943 : 855 : collctype = NULL;
13944 : :
13945 : : /*
13946 : : * Before version 15, collcollate and collctype were of type NAME and
13947 : : * non-nullable. Treat empty strings as NULL for consistency.
13948 : : */
236 jdavis@postgresql.or 13949 [ - + ]: 1541 : if (fout->remoteVersion < 150000)
13950 : : {
236 jdavis@postgresql.or 13951 [ # # ]:UBC 0 : if (collcollate[0] == '\0')
13952 : 0 : collcollate = NULL;
13953 [ # # ]: 0 : if (collctype[0] == '\0')
13954 : 0 : collctype = NULL;
13955 : : }
13956 : :
36 jdavis@postgresql.or 13957 [ + + ]:GNC 1541 : if (!PQgetisnull(res, 0, i_colllocale))
13958 : 854 : colllocale = PQgetvalue(res, 0, i_colllocale);
13959 : : else
13960 : 687 : colllocale = NULL;
13961 : :
403 peter@eisentraut.org 13962 [ - + ]:CBC 1541 : if (!PQgetisnull(res, 0, i_collicurules))
403 peter@eisentraut.org 13963 :UBC 0 : collicurules = PQgetvalue(res, 0, i_collicurules);
13964 : : else
403 peter@eisentraut.org 13965 :CBC 1541 : collicurules = NULL;
13966 : :
2239 tgl@sss.pgh.pa.us 13967 : 1541 : appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13968 : 1541 : fmtQualifiedDumpable(collinfo));
13969 : :
2579 peter_e@gmx.net 13970 : 1541 : appendPQExpBuffer(q, "CREATE COLLATION %s (",
2239 tgl@sss.pgh.pa.us 13971 : 1541 : fmtQualifiedDumpable(collinfo));
13972 : :
2579 peter_e@gmx.net 13973 : 1541 : appendPQExpBufferStr(q, "provider = ");
32 jdavis@postgresql.or 13974 [ + + ]:GNC 1541 : if (collprovider[0] == 'b')
13975 : 7 : appendPQExpBufferStr(q, "builtin");
13976 [ + + ]: 1534 : else if (collprovider[0] == 'c')
2579 peter_e@gmx.net 13977 :CBC 686 : appendPQExpBufferStr(q, "libc");
13978 [ + + ]: 848 : else if (collprovider[0] == 'i')
13979 : 847 : appendPQExpBufferStr(q, "icu");
2497 13980 [ + - ]: 1 : else if (collprovider[0] == 'd')
13981 : : /* to allow dumping pg_catalog; not accepted on input */
13982 : 1 : appendPQExpBufferStr(q, "default");
13983 : : else
737 tgl@sss.pgh.pa.us 13984 :UBC 0 : pg_fatal("unrecognized collation provider: %s",
13985 : : collprovider);
13986 : :
1850 peter@eisentraut.org 13987 [ - + ]:CBC 1541 : if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
1850 peter@eisentraut.org 13988 :UBC 0 : appendPQExpBufferStr(q, ", deterministic = false");
13989 : :
236 jdavis@postgresql.or 13990 [ + + ]:CBC 1541 : if (collprovider[0] == 'd')
13991 : : {
36 jdavis@postgresql.or 13992 [ + - + - :GNC 1 : if (collcollate || collctype || colllocale || collicurules)
+ - - + ]
236 jdavis@postgresql.or 13993 :UBC 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
13994 : :
13995 : : /* no locale -- the default collation cannot be reloaded anyway */
13996 : : }
32 jdavis@postgresql.or 13997 [ + + ]:GNC 1540 : else if (collprovider[0] == 'b')
13998 : : {
13999 [ + - + - : 7 : if (collcollate || collctype || !colllocale || collicurules)
+ - - + ]
32 jdavis@postgresql.or 14000 :UNC 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
14001 : :
32 jdavis@postgresql.or 14002 :GNC 7 : appendPQExpBufferStr(q, ", locale = ");
14003 [ + - ]: 7 : appendStringLiteralAH(q, colllocale ? colllocale : "",
14004 : : fout);
14005 : : }
236 jdavis@postgresql.or 14006 [ + + ]:CBC 1533 : else if (collprovider[0] == 'i')
14007 : : {
14008 [ + - ]: 847 : if (fout->remoteVersion >= 150000)
14009 : : {
36 jdavis@postgresql.or 14010 [ + - + - :GNC 847 : if (collcollate || collctype || !colllocale)
- + ]
236 jdavis@postgresql.or 14011 :UBC 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
14012 : :
236 jdavis@postgresql.or 14013 :CBC 847 : appendPQExpBufferStr(q, ", locale = ");
36 jdavis@postgresql.or 14014 [ + - ]:GNC 847 : appendStringLiteralAH(q, colllocale ? colllocale : "",
14015 : : fout);
14016 : : }
14017 : : else
14018 : : {
36 jdavis@postgresql.or 14019 [ # # # # :UNC 0 : if (!collcollate || !collctype || colllocale ||
# # ]
236 jdavis@postgresql.or 14020 [ # # ]:UBC 0 : strcmp(collcollate, collctype) != 0)
14021 : 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
14022 : :
599 peter@eisentraut.org 14023 : 0 : appendPQExpBufferStr(q, ", locale = ");
236 jdavis@postgresql.or 14024 [ # # ]: 0 : appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
14025 : : }
14026 : :
236 jdavis@postgresql.or 14027 [ - + ]:CBC 847 : if (collicurules)
14028 : : {
236 jdavis@postgresql.or 14029 :UBC 0 : appendPQExpBufferStr(q, ", rules = ");
14030 [ # # ]: 0 : appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
14031 : : }
14032 : : }
236 jdavis@postgresql.or 14033 [ + - ]:CBC 686 : else if (collprovider[0] == 'c')
14034 : : {
36 jdavis@postgresql.or 14035 [ + - + - :GNC 686 : if (colllocale || collicurules || !collcollate || !collctype)
+ - - + ]
236 jdavis@postgresql.or 14036 :UBC 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
14037 : :
236 jdavis@postgresql.or 14038 [ + - + - :CBC 686 : if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
+ - ]
14039 : : {
14040 : 686 : appendPQExpBufferStr(q, ", locale = ");
14041 [ + - ]: 686 : appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
14042 : : }
14043 : : else
14044 : : {
599 peter@eisentraut.org 14045 :UBC 0 : appendPQExpBufferStr(q, ", lc_collate = ");
236 jdavis@postgresql.or 14046 [ # # ]: 0 : appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
599 peter@eisentraut.org 14047 : 0 : appendPQExpBufferStr(q, ", lc_ctype = ");
236 jdavis@postgresql.or 14048 [ # # ]: 0 : appendStringLiteralAH(q, collctype ? collctype : "", fout);
14049 : : }
14050 : : }
14051 : : else
222 peter@eisentraut.org 14052 : 0 : pg_fatal("unrecognized collation provider: %s", collprovider);
14053 : :
14054 : : /*
14055 : : * For binary upgrade, carry over the collation version. For normal
14056 : : * dump/restore, omit the version, so that it is computed upon restore.
14057 : : */
1073 tmunro@postgresql.or 14058 [ + + ]:CBC 1541 : if (dopt->binary_upgrade)
14059 : : {
14060 : : int i_collversion;
14061 : :
14062 : 4 : i_collversion = PQfnumber(res, "collversion");
14063 [ + + ]: 4 : if (!PQgetisnull(res, 0, i_collversion))
14064 : : {
14065 : 3 : appendPQExpBufferStr(q, ", version = ");
14066 : 3 : appendStringLiteralAH(q,
14067 : : PQgetvalue(res, 0, i_collversion),
14068 : : fout);
14069 : : }
14070 : : }
14071 : :
3800 heikki.linnakangas@i 14072 : 1541 : appendPQExpBufferStr(q, ");\n");
14073 : :
3470 alvherre@alvh.no-ip. 14074 [ + + ]: 1541 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 14075 : 4 : binary_upgrade_extension_member(q, &collinfo->dobj,
14076 : : "COLLATION", qcollname,
14077 : 4 : collinfo->dobj.namespace->dobj.name);
14078 : :
2930 sfrost@snowman.net 14079 [ + - ]: 1541 : if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14080 : 1541 : ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 14081 : 1541 : ARCHIVE_OPTS(.tag = collinfo->dobj.name,
14082 : : .namespace = collinfo->dobj.namespace->dobj.name,
14083 : : .owner = collinfo->rolname,
14084 : : .description = "COLLATION",
14085 : : .section = SECTION_PRE_DATA,
14086 : : .createStmt = q->data,
14087 : : .dropStmt = delq->data));
14088 : :
14089 : : /* Dump Collation Comments */
2930 sfrost@snowman.net 14090 [ + + ]: 1541 : if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 14091 : 834 : dumpComment(fout, "COLLATION", qcollname,
2930 sfrost@snowman.net 14092 : 834 : collinfo->dobj.namespace->dobj.name, collinfo->rolname,
14093 : 834 : collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
14094 : :
4810 peter_e@gmx.net 14095 : 1541 : PQclear(res);
14096 : :
14097 : 1541 : destroyPQExpBuffer(query);
14098 : 1541 : destroyPQExpBuffer(q);
14099 : 1541 : destroyPQExpBuffer(delq);
2239 tgl@sss.pgh.pa.us 14100 : 1541 : free(qcollname);
14101 : : }
14102 : :
14103 : : /*
14104 : : * dumpConversion
14105 : : * write out a single conversion definition
14106 : : */
14107 : : static void
1159 peter@eisentraut.org 14108 : 167 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
14109 : : {
3014 tgl@sss.pgh.pa.us 14110 : 167 : DumpOptions *dopt = fout->dopt;
14111 : : PQExpBuffer query;
14112 : : PQExpBuffer q;
14113 : : PQExpBuffer delq;
14114 : : char *qconvname;
14115 : : PGresult *res;
14116 : : int i_conforencoding;
14117 : : int i_contoencoding;
14118 : : int i_conproc;
14119 : : int i_condefault;
14120 : : const char *conforencoding;
14121 : : const char *contoencoding;
14122 : : const char *conproc;
14123 : : bool condefault;
14124 : :
14125 : : /* Do nothing in data-only dump */
860 14126 [ + + ]: 167 : if (dopt->dataOnly)
7435 14127 : 3 : return;
14128 : :
14129 : 164 : query = createPQExpBuffer();
14130 : 164 : q = createPQExpBuffer();
14131 : 164 : delq = createPQExpBuffer();
14132 : :
2239 14133 : 164 : qconvname = pg_strdup(fmtId(convinfo->dobj.name));
14134 : :
14135 : : /* Get conversion-specific details */
4752 peter_e@gmx.net 14136 : 164 : appendPQExpBuffer(query, "SELECT "
14137 : : "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
14138 : : "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
14139 : : "conproc, condefault "
14140 : : "FROM pg_catalog.pg_conversion c "
14141 : : "WHERE c.oid = '%u'::pg_catalog.oid",
7435 tgl@sss.pgh.pa.us 14142 : 164 : convinfo->dobj.catId.oid);
14143 : :
4441 rhaas@postgresql.org 14144 : 164 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
14145 : :
7450 tgl@sss.pgh.pa.us 14146 : 164 : i_conforencoding = PQfnumber(res, "conforencoding");
14147 : 164 : i_contoencoding = PQfnumber(res, "contoencoding");
14148 : 164 : i_conproc = PQfnumber(res, "conproc");
14149 : 164 : i_condefault = PQfnumber(res, "condefault");
14150 : :
14151 : 164 : conforencoding = PQgetvalue(res, 0, i_conforencoding);
14152 : 164 : contoencoding = PQgetvalue(res, 0, i_contoencoding);
14153 : 164 : conproc = PQgetvalue(res, 0, i_conproc);
14154 : 164 : condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
14155 : :
2239 14156 : 164 : appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
14157 : 164 : fmtQualifiedDumpable(convinfo));
14158 : :
7450 14159 [ + - ]: 164 : appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
14160 : : (condefault) ? "DEFAULT " : "",
2239 14161 : 164 : fmtQualifiedDumpable(convinfo));
6531 14162 : 164 : appendStringLiteralAH(q, conforencoding, fout);
3800 heikki.linnakangas@i 14163 : 164 : appendPQExpBufferStr(q, " TO ");
6531 tgl@sss.pgh.pa.us 14164 : 164 : appendStringLiteralAH(q, contoencoding, fout);
14165 : : /* regproc output is already sufficiently quoted */
7450 14166 : 164 : appendPQExpBuffer(q, " FROM %s;\n", conproc);
14167 : :
3470 alvherre@alvh.no-ip. 14168 [ + + ]: 164 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 14169 : 1 : binary_upgrade_extension_member(q, &convinfo->dobj,
14170 : : "CONVERSION", qconvname,
14171 : 1 : convinfo->dobj.namespace->dobj.name);
14172 : :
2930 sfrost@snowman.net 14173 [ + - ]: 164 : if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14174 : 164 : ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 14175 : 164 : ARCHIVE_OPTS(.tag = convinfo->dobj.name,
14176 : : .namespace = convinfo->dobj.namespace->dobj.name,
14177 : : .owner = convinfo->rolname,
14178 : : .description = "CONVERSION",
14179 : : .section = SECTION_PRE_DATA,
14180 : : .createStmt = q->data,
14181 : : .dropStmt = delq->data));
14182 : :
14183 : : /* Dump Conversion Comments */
2930 sfrost@snowman.net 14184 [ + - ]: 164 : if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 14185 : 164 : dumpComment(fout, "CONVERSION", qconvname,
2930 sfrost@snowman.net 14186 : 164 : convinfo->dobj.namespace->dobj.name, convinfo->rolname,
14187 : 164 : convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
14188 : :
7435 tgl@sss.pgh.pa.us 14189 : 164 : PQclear(res);
14190 : :
14191 : 164 : destroyPQExpBuffer(query);
14192 : 164 : destroyPQExpBuffer(q);
14193 : 164 : destroyPQExpBuffer(delq);
2239 14194 : 164 : free(qconvname);
14195 : : }
14196 : :
14197 : : /*
14198 : : * format_aggregate_signature: generate aggregate name and argument list
14199 : : *
14200 : : * The argument type names are qualified if needed. The aggregate name
14201 : : * is never qualified.
14202 : : */
14203 : : static char *
1159 peter@eisentraut.org 14204 : 289 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
14205 : : {
14206 : : PQExpBufferData buf;
14207 : : int j;
14208 : :
8001 peter_e@gmx.net 14209 : 289 : initPQExpBuffer(&buf);
7955 bruce@momjian.us 14210 [ - + ]: 289 : if (honor_quotes)
3800 heikki.linnakangas@i 14211 :UBC 0 : appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
14212 : : else
3800 heikki.linnakangas@i 14213 :CBC 289 : appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
14214 : :
6471 tgl@sss.pgh.pa.us 14215 [ + + ]: 289 : if (agginfo->aggfn.nargs == 0)
1746 drowley@postgresql.o 14216 : 40 : appendPQExpBufferStr(&buf, "(*)");
14217 : : else
14218 : : {
3800 heikki.linnakangas@i 14219 : 249 : appendPQExpBufferChar(&buf, '(');
6471 tgl@sss.pgh.pa.us 14220 [ + + ]: 543 : for (j = 0; j < agginfo->aggfn.nargs; j++)
14221 [ + + ]: 294 : appendPQExpBuffer(&buf, "%s%s",
14222 : : (j > 0) ? ", " : "",
14223 : : getFormattedTypeName(fout,
949 14224 : 294 : agginfo->aggfn.argtypes[j],
14225 : : zeroIsError));
3800 heikki.linnakangas@i 14226 : 249 : appendPQExpBufferChar(&buf, ')');
14227 : : }
8001 peter_e@gmx.net 14228 : 289 : return buf.data;
14229 : : }
14230 : :
14231 : : /*
14232 : : * dumpAgg
14233 : : * write out a single aggregate definition
14234 : : */
14235 : : static void
1159 peter@eisentraut.org 14236 : 293 : dumpAgg(Archive *fout, const AggInfo *agginfo)
14237 : : {
3014 tgl@sss.pgh.pa.us 14238 : 293 : DumpOptions *dopt = fout->dopt;
14239 : : PQExpBuffer query;
14240 : : PQExpBuffer q;
14241 : : PQExpBuffer delq;
14242 : : PQExpBuffer details;
14243 : : char *aggsig; /* identity signature */
2489 14244 : 293 : char *aggfullsig = NULL; /* full signature */
14245 : : char *aggsig_tag;
14246 : : PGresult *res;
14247 : : int i_agginitval;
14248 : : int i_aggminitval;
14249 : : const char *aggtransfn;
14250 : : const char *aggfinalfn;
14251 : : const char *aggcombinefn;
14252 : : const char *aggserialfn;
14253 : : const char *aggdeserialfn;
14254 : : const char *aggmtransfn;
14255 : : const char *aggminvtransfn;
14256 : : const char *aggmfinalfn;
14257 : : bool aggfinalextra;
14258 : : bool aggmfinalextra;
14259 : : char aggfinalmodify;
14260 : : char aggmfinalmodify;
14261 : : const char *aggsortop;
14262 : : char *aggsortconvop;
14263 : : char aggkind;
14264 : : const char *aggtranstype;
14265 : : const char *aggtransspace;
14266 : : const char *aggmtranstype;
14267 : : const char *aggmtransspace;
14268 : : const char *agginitval;
14269 : : const char *aggminitval;
14270 : : const char *proparallel;
14271 : : char defaultfinalmodify;
14272 : :
14273 : : /* Do nothing in data-only dump */
860 14274 [ + + ]: 293 : if (dopt->dataOnly)
7435 14275 : 4 : return;
14276 : :
14277 : 289 : query = createPQExpBuffer();
14278 : 289 : q = createPQExpBuffer();
14279 : 289 : delq = createPQExpBuffer();
14280 : 289 : details = createPQExpBuffer();
14281 : :
860 14282 [ + + ]: 289 : if (!fout->is_prepared[PREPQUERY_DUMPAGG])
14283 : : {
14284 : : /* Set up query for aggregate-specific details */
1277 drowley@postgresql.o 14285 : 59 : appendPQExpBufferStr(query,
14286 : : "PREPARE dumpAgg(pg_catalog.oid) AS\n");
14287 : :
14288 : 59 : appendPQExpBufferStr(query,
14289 : : "SELECT "
14290 : : "aggtransfn,\n"
14291 : : "aggfinalfn,\n"
14292 : : "aggtranstype::pg_catalog.regtype,\n"
14293 : : "agginitval,\n"
14294 : : "aggsortop,\n"
14295 : : "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
14296 : : "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
14297 : :
860 tgl@sss.pgh.pa.us 14298 [ + - ]: 59 : if (fout->remoteVersion >= 90400)
14299 : 59 : appendPQExpBufferStr(query,
14300 : : "aggkind,\n"
14301 : : "aggmtransfn,\n"
14302 : : "aggminvtransfn,\n"
14303 : : "aggmfinalfn,\n"
14304 : : "aggmtranstype::pg_catalog.regtype,\n"
14305 : : "aggfinalextra,\n"
14306 : : "aggmfinalextra,\n"
14307 : : "aggtransspace,\n"
14308 : : "aggmtransspace,\n"
14309 : : "aggminitval,\n");
14310 : : else
860 tgl@sss.pgh.pa.us 14311 :UBC 0 : appendPQExpBufferStr(query,
14312 : : "'n' AS aggkind,\n"
14313 : : "'-' AS aggmtransfn,\n"
14314 : : "'-' AS aggminvtransfn,\n"
14315 : : "'-' AS aggmfinalfn,\n"
14316 : : "0 AS aggmtranstype,\n"
14317 : : "false AS aggfinalextra,\n"
14318 : : "false AS aggmfinalextra,\n"
14319 : : "0 AS aggtransspace,\n"
14320 : : "0 AS aggmtransspace,\n"
14321 : : "NULL AS aggminitval,\n");
14322 : :
860 tgl@sss.pgh.pa.us 14323 [ + - ]:CBC 59 : if (fout->remoteVersion >= 90600)
14324 : 59 : appendPQExpBufferStr(query,
14325 : : "aggcombinefn,\n"
14326 : : "aggserialfn,\n"
14327 : : "aggdeserialfn,\n"
14328 : : "proparallel,\n");
14329 : : else
860 tgl@sss.pgh.pa.us 14330 :UBC 0 : appendPQExpBufferStr(query,
14331 : : "'-' AS aggcombinefn,\n"
14332 : : "'-' AS aggserialfn,\n"
14333 : : "'-' AS aggdeserialfn,\n"
14334 : : "'u' AS proparallel,\n");
14335 : :
860 tgl@sss.pgh.pa.us 14336 [ + - ]:CBC 59 : if (fout->remoteVersion >= 110000)
14337 : 59 : appendPQExpBufferStr(query,
14338 : : "aggfinalmodify,\n"
14339 : : "aggmfinalmodify\n");
14340 : : else
860 tgl@sss.pgh.pa.us 14341 :UBC 0 : appendPQExpBufferStr(query,
14342 : : "'0' AS aggfinalmodify,\n"
14343 : : "'0' AS aggmfinalmodify\n");
14344 : :
1277 drowley@postgresql.o 14345 :CBC 59 : appendPQExpBufferStr(query,
14346 : : "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
14347 : : "WHERE a.aggfnoid = p.oid "
14348 : : "AND p.oid = $1");
14349 : :
860 tgl@sss.pgh.pa.us 14350 : 59 : ExecuteSqlStatement(fout, query->data);
14351 : :
14352 : 59 : fout->is_prepared[PREPQUERY_DUMPAGG] = true;
14353 : : }
14354 : :
14355 : 289 : printfPQExpBuffer(query,
14356 : : "EXECUTE dumpAgg('%u')",
1369 peter@eisentraut.org 14357 : 289 : agginfo->aggfn.dobj.catId.oid);
14358 : :
4441 rhaas@postgresql.org 14359 : 289 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
14360 : :
8010 tgl@sss.pgh.pa.us 14361 : 289 : i_agginitval = PQfnumber(res, "agginitval");
3655 14362 : 289 : i_aggminitval = PQfnumber(res, "aggminitval");
14363 : :
1369 peter@eisentraut.org 14364 : 289 : aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
14365 : 289 : aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
14366 : 289 : aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
14367 : 289 : aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
14368 : 289 : aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
14369 : 289 : aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
14370 : 289 : aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
14371 : 289 : aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
14372 : 289 : aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
14373 : 289 : aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
14374 : 289 : aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
14375 : 289 : aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
14376 : 289 : aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
14377 : 289 : aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
14378 : 289 : aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
14379 : 289 : aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
14380 : 289 : aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
14381 : 289 : aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
8010 tgl@sss.pgh.pa.us 14382 : 289 : agginitval = PQgetvalue(res, 0, i_agginitval);
3655 14383 : 289 : aggminitval = PQgetvalue(res, 0, i_aggminitval);
1369 peter@eisentraut.org 14384 : 289 : proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
14385 : :
14386 : : {
14387 : : char *funcargs;
14388 : : char *funciargs;
14389 : :
3876 tgl@sss.pgh.pa.us 14390 : 289 : funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
14391 : 289 : funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
14392 : 289 : aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
14393 : 289 : aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
14394 : : }
14395 : :
7435 14396 : 289 : aggsig_tag = format_aggregate_signature(agginfo, fout, false);
14397 : :
14398 : : /* identify default modify flag for aggkind (must match DefineAggregate) */
2374 14399 [ + + ]: 289 : defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
14400 : : /* replace omitted flags for old versions */
14401 [ - + ]: 289 : if (aggfinalmodify == '0')
2374 tgl@sss.pgh.pa.us 14402 :UBC 0 : aggfinalmodify = defaultfinalmodify;
2374 tgl@sss.pgh.pa.us 14403 [ - + ]:CBC 289 : if (aggmfinalmodify == '0')
2374 tgl@sss.pgh.pa.us 14404 :UBC 0 : aggmfinalmodify = defaultfinalmodify;
14405 : :
14406 : : /* regproc and regtype output is already sufficiently quoted */
2741 tgl@sss.pgh.pa.us 14407 :CBC 289 : appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
14408 : : aggtransfn, aggtranstype);
14409 : :
3802 14410 [ + + ]: 289 : if (strcmp(aggtransspace, "0") != 0)
14411 : : {
14412 : 5 : appendPQExpBuffer(details, ",\n SSPACE = %s",
14413 : : aggtransspace);
14414 : : }
14415 : :
8010 14416 [ + + ]: 289 : if (!PQgetisnull(res, 0, i_agginitval))
14417 : : {
3800 heikki.linnakangas@i 14418 : 211 : appendPQExpBufferStr(details, ",\n INITCOND = ");
6531 tgl@sss.pgh.pa.us 14419 : 211 : appendStringLiteralAH(details, agginitval, fout);
14420 : : }
14421 : :
8010 14422 [ + + ]: 289 : if (strcmp(aggfinalfn, "-") != 0)
14423 : : {
7910 peter_e@gmx.net 14424 : 136 : appendPQExpBuffer(details, ",\n FINALFUNC = %s",
14425 : : aggfinalfn);
3644 tgl@sss.pgh.pa.us 14426 [ + + ]: 136 : if (aggfinalextra)
14427 : 10 : appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
2374 14428 [ + + ]: 136 : if (aggfinalmodify != defaultfinalmodify)
14429 : : {
14430 [ - + - - ]: 36 : switch (aggfinalmodify)
14431 : : {
2374 tgl@sss.pgh.pa.us 14432 :UBC 0 : case AGGMODIFY_READ_ONLY:
14433 : 0 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_ONLY");
14434 : 0 : break;
2155 tgl@sss.pgh.pa.us 14435 :CBC 36 : case AGGMODIFY_SHAREABLE:
14436 : 36 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = SHAREABLE");
2374 14437 : 36 : break;
2374 tgl@sss.pgh.pa.us 14438 :UBC 0 : case AGGMODIFY_READ_WRITE:
14439 : 0 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_WRITE");
14440 : 0 : break;
14441 : 0 : default:
737 14442 : 0 : pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
14443 : : agginfo->aggfn.dobj.name);
14444 : : break;
14445 : : }
14446 : : }
14447 : : }
14448 : :
3007 rhaas@postgresql.org 14449 [ - + ]:CBC 289 : if (strcmp(aggcombinefn, "-") != 0)
2866 rhaas@postgresql.org 14450 :UBC 0 : appendPQExpBuffer(details, ",\n COMBINEFUNC = %s", aggcombinefn);
14451 : :
2938 rhaas@postgresql.org 14452 [ - + ]:CBC 289 : if (strcmp(aggserialfn, "-") != 0)
2866 rhaas@postgresql.org 14453 :UBC 0 : appendPQExpBuffer(details, ",\n SERIALFUNC = %s", aggserialfn);
14454 : :
2853 tgl@sss.pgh.pa.us 14455 [ - + ]:CBC 289 : if (strcmp(aggdeserialfn, "-") != 0)
2866 rhaas@postgresql.org 14456 :UBC 0 : appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
14457 : :
3655 tgl@sss.pgh.pa.us 14458 [ + + ]:CBC 289 : if (strcmp(aggmtransfn, "-") != 0)
14459 : : {
14460 : 30 : appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
14461 : : aggmtransfn,
14462 : : aggminvtransfn,
14463 : : aggmtranstype);
14464 : : }
14465 : :
14466 [ - + ]: 289 : if (strcmp(aggmtransspace, "0") != 0)
14467 : : {
3655 tgl@sss.pgh.pa.us 14468 :UBC 0 : appendPQExpBuffer(details, ",\n MSSPACE = %s",
14469 : : aggmtransspace);
14470 : : }
14471 : :
3655 tgl@sss.pgh.pa.us 14472 [ + + ]:CBC 289 : if (!PQgetisnull(res, 0, i_aggminitval))
14473 : : {
14474 : 10 : appendPQExpBufferStr(details, ",\n MINITCOND = ");
14475 : 10 : appendStringLiteralAH(details, aggminitval, fout);
14476 : : }
14477 : :
14478 [ - + ]: 289 : if (strcmp(aggmfinalfn, "-") != 0)
14479 : : {
3655 tgl@sss.pgh.pa.us 14480 :UBC 0 : appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
14481 : : aggmfinalfn);
3644 14482 [ # # ]: 0 : if (aggmfinalextra)
14483 : 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
2374 14484 [ # # ]: 0 : if (aggmfinalmodify != defaultfinalmodify)
14485 : : {
14486 [ # # # # ]: 0 : switch (aggmfinalmodify)
14487 : : {
14488 : 0 : case AGGMODIFY_READ_ONLY:
14489 : 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_ONLY");
14490 : 0 : break;
2155 14491 : 0 : case AGGMODIFY_SHAREABLE:
14492 : 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = SHAREABLE");
2374 14493 : 0 : break;
14494 : 0 : case AGGMODIFY_READ_WRITE:
14495 : 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_WRITE");
14496 : 0 : break;
14497 : 0 : default:
737 14498 : 0 : pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
14499 : : agginfo->aggfn.dobj.name);
14500 : : break;
14501 : : }
14502 : : }
14503 : : }
14504 : :
1328 peter@eisentraut.org 14505 :CBC 289 : aggsortconvop = getFormattedOperatorName(aggsortop);
3697 sfrost@snowman.net 14506 [ - + ]: 289 : if (aggsortconvop)
14507 : : {
6942 tgl@sss.pgh.pa.us 14508 :UBC 0 : appendPQExpBuffer(details, ",\n SORTOP = %s",
14509 : : aggsortconvop);
3697 sfrost@snowman.net 14510 : 0 : free(aggsortconvop);
14511 : : }
14512 : :
2374 tgl@sss.pgh.pa.us 14513 [ + + ]:CBC 289 : if (aggkind == AGGKIND_HYPOTHETICAL)
3765 14514 : 5 : appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
14515 : :
1369 peter@eisentraut.org 14516 [ + + ]: 289 : if (proparallel[0] != PROPARALLEL_UNSAFE)
14517 : : {
2916 rhaas@postgresql.org 14518 [ + - ]: 5 : if (proparallel[0] == PROPARALLEL_SAFE)
14519 : 5 : appendPQExpBufferStr(details, ",\n PARALLEL = safe");
2916 rhaas@postgresql.org 14520 [ # # ]:UBC 0 : else if (proparallel[0] == PROPARALLEL_RESTRICTED)
14521 : 0 : appendPQExpBufferStr(details, ",\n PARALLEL = restricted");
14522 [ # # ]: 0 : else if (proparallel[0] != PROPARALLEL_UNSAFE)
737 tgl@sss.pgh.pa.us 14523 : 0 : pg_fatal("unrecognized proparallel value for function \"%s\"",
14524 : : agginfo->aggfn.dobj.name);
14525 : : }
14526 : :
7992 tgl@sss.pgh.pa.us 14527 :CBC 289 : appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
7347 14528 : 289 : fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14529 : : aggsig);
14530 : :
2239 14531 [ + - ]: 578 : appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
14532 : 289 : fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14533 : : aggfullsig ? aggfullsig : aggsig, details->data);
14534 : :
3470 alvherre@alvh.no-ip. 14535 [ + + ]: 289 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 14536 : 49 : binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
14537 : : "AGGREGATE", aggsig,
14538 : 49 : agginfo->aggfn.dobj.namespace->dobj.name);
14539 : :
2930 sfrost@snowman.net 14540 [ + + ]: 289 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
14541 : 272 : ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
14542 : 272 : agginfo->aggfn.dobj.dumpId,
1899 alvherre@alvh.no-ip. 14543 : 272 : ARCHIVE_OPTS(.tag = aggsig_tag,
14544 : : .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
14545 : : .owner = agginfo->aggfn.rolname,
14546 : : .description = "AGGREGATE",
14547 : : .section = SECTION_PRE_DATA,
14548 : : .createStmt = q->data,
14549 : : .dropStmt = delq->data));
14550 : :
14551 : : /* Dump Aggregate Comments */
2930 sfrost@snowman.net 14552 [ + + ]: 289 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 14553 : 10 : dumpComment(fout, "AGGREGATE", aggsig,
2930 sfrost@snowman.net 14554 : 10 : agginfo->aggfn.dobj.namespace->dobj.name,
14555 : 10 : agginfo->aggfn.rolname,
14556 : 10 : agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14557 : :
14558 [ - + ]: 289 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 14559 :UBC 0 : dumpSecLabel(fout, "AGGREGATE", aggsig,
2930 sfrost@snowman.net 14560 : 0 : agginfo->aggfn.dobj.namespace->dobj.name,
14561 : 0 : agginfo->aggfn.rolname,
2489 tgl@sss.pgh.pa.us 14562 : 0 : agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14563 : :
14564 : : /*
14565 : : * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
14566 : : * command look like a function's GRANT; in particular this affects the
14567 : : * syntax for zero-argument aggregates and ordered-set aggregates.
14568 : : */
7435 tgl@sss.pgh.pa.us 14569 :CBC 289 : free(aggsig);
14570 : :
4451 rhaas@postgresql.org 14571 : 289 : aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14572 : :
2930 sfrost@snowman.net 14573 [ + + ]: 289 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
1373 tgl@sss.pgh.pa.us 14574 : 18 : dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
14575 : : "FUNCTION", aggsig, NULL,
2930 sfrost@snowman.net 14576 : 18 : agginfo->aggfn.dobj.namespace->dobj.name,
13 tgl@sss.pgh.pa.us 14577 :GNC 18 : NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
14578 : :
7435 tgl@sss.pgh.pa.us 14579 :CBC 289 : free(aggsig);
668 peter@eisentraut.org 14580 : 289 : free(aggfullsig);
7435 tgl@sss.pgh.pa.us 14581 : 289 : free(aggsig_tag);
14582 : :
8010 14583 : 289 : PQclear(res);
14584 : :
14585 : 289 : destroyPQExpBuffer(query);
8290 14586 : 289 : destroyPQExpBuffer(q);
14587 : 289 : destroyPQExpBuffer(delq);
14588 : 289 : destroyPQExpBuffer(details);
14589 : : }
14590 : :
14591 : : /*
14592 : : * dumpTSParser
14593 : : * write out a single text search parser
14594 : : */
14595 : : static void
1159 peter@eisentraut.org 14596 : 40 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
14597 : : {
3014 tgl@sss.pgh.pa.us 14598 : 40 : DumpOptions *dopt = fout->dopt;
14599 : : PQExpBuffer q;
14600 : : PQExpBuffer delq;
14601 : : char *qprsname;
14602 : :
14603 : : /* Do nothing in data-only dump */
860 14604 [ + + ]: 40 : if (dopt->dataOnly)
6081 14605 : 3 : return;
14606 : :
14607 : 37 : q = createPQExpBuffer();
14608 : 37 : delq = createPQExpBuffer();
14609 : :
2239 14610 : 37 : qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14611 : :
6081 14612 : 37 : appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
2239 14613 : 37 : fmtQualifiedDumpable(prsinfo));
14614 : :
6081 14615 : 37 : appendPQExpBuffer(q, " START = %s,\n",
4450 rhaas@postgresql.org 14616 : 37 : convertTSFunction(fout, prsinfo->prsstart));
6081 tgl@sss.pgh.pa.us 14617 : 37 : appendPQExpBuffer(q, " GETTOKEN = %s,\n",
4450 rhaas@postgresql.org 14618 : 37 : convertTSFunction(fout, prsinfo->prstoken));
6081 tgl@sss.pgh.pa.us 14619 : 37 : appendPQExpBuffer(q, " END = %s,\n",
4450 rhaas@postgresql.org 14620 : 37 : convertTSFunction(fout, prsinfo->prsend));
6081 tgl@sss.pgh.pa.us 14621 [ + + ]: 37 : if (prsinfo->prsheadline != InvalidOid)
14622 : 1 : appendPQExpBuffer(q, " HEADLINE = %s,\n",
4450 rhaas@postgresql.org 14623 : 1 : convertTSFunction(fout, prsinfo->prsheadline));
6081 tgl@sss.pgh.pa.us 14624 : 37 : appendPQExpBuffer(q, " LEXTYPES = %s );\n",
4450 rhaas@postgresql.org 14625 : 37 : convertTSFunction(fout, prsinfo->prslextype));
14626 : :
2239 tgl@sss.pgh.pa.us 14627 : 37 : appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14628 : 37 : fmtQualifiedDumpable(prsinfo));
14629 : :
3470 alvherre@alvh.no-ip. 14630 [ + + ]: 37 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 14631 : 1 : binary_upgrade_extension_member(q, &prsinfo->dobj,
14632 : : "TEXT SEARCH PARSER", qprsname,
14633 : 1 : prsinfo->dobj.namespace->dobj.name);
14634 : :
2930 sfrost@snowman.net 14635 [ + - ]: 37 : if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14636 : 37 : ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 14637 : 37 : ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
14638 : : .namespace = prsinfo->dobj.namespace->dobj.name,
14639 : : .description = "TEXT SEARCH PARSER",
14640 : : .section = SECTION_PRE_DATA,
14641 : : .createStmt = q->data,
14642 : : .dropStmt = delq->data));
14643 : :
14644 : : /* Dump Parser Comments */
2930 sfrost@snowman.net 14645 [ + - ]: 37 : if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 14646 : 37 : dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
2596 14647 : 37 : prsinfo->dobj.namespace->dobj.name, "",
2930 sfrost@snowman.net 14648 : 37 : prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14649 : :
6081 tgl@sss.pgh.pa.us 14650 : 37 : destroyPQExpBuffer(q);
14651 : 37 : destroyPQExpBuffer(delq);
2239 14652 : 37 : free(qprsname);
14653 : : }
14654 : :
14655 : : /*
14656 : : * dumpTSDictionary
14657 : : * write out a single text search dictionary
14658 : : */
14659 : : static void
1159 peter@eisentraut.org 14660 : 113 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
14661 : : {
3014 tgl@sss.pgh.pa.us 14662 : 113 : DumpOptions *dopt = fout->dopt;
14663 : : PQExpBuffer q;
14664 : : PQExpBuffer delq;
14665 : : PQExpBuffer query;
14666 : : char *qdictname;
14667 : : PGresult *res;
14668 : : char *nspname;
14669 : : char *tmplname;
14670 : :
14671 : : /* Do nothing in data-only dump */
860 14672 [ + + ]: 113 : if (dopt->dataOnly)
6081 14673 : 3 : return;
14674 : :
14675 : 110 : q = createPQExpBuffer();
14676 : 110 : delq = createPQExpBuffer();
14677 : 110 : query = createPQExpBuffer();
14678 : :
2239 14679 : 110 : qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14680 : :
14681 : : /* Fetch name and namespace of the dictionary's template */
6081 14682 : 110 : appendPQExpBuffer(query, "SELECT nspname, tmplname "
14683 : : "FROM pg_ts_template p, pg_namespace n "
14684 : : "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14685 : 110 : dictinfo->dicttemplate);
4441 rhaas@postgresql.org 14686 : 110 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
6081 tgl@sss.pgh.pa.us 14687 : 110 : nspname = PQgetvalue(res, 0, 0);
14688 : 110 : tmplname = PQgetvalue(res, 0, 1);
14689 : :
14690 : 110 : appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
2239 14691 : 110 : fmtQualifiedDumpable(dictinfo));
14692 : :
3800 heikki.linnakangas@i 14693 : 110 : appendPQExpBufferStr(q, " TEMPLATE = ");
2239 tgl@sss.pgh.pa.us 14694 : 110 : appendPQExpBuffer(q, "%s.", fmtId(nspname));
3800 heikki.linnakangas@i 14695 : 110 : appendPQExpBufferStr(q, fmtId(tmplname));
14696 : :
6081 tgl@sss.pgh.pa.us 14697 : 110 : PQclear(res);
14698 : :
14699 : : /* the dictinitoption can be dumped straight into the command */
14700 [ + + ]: 110 : if (dictinfo->dictinitoption)
6080 14701 : 73 : appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
14702 : :
3800 heikki.linnakangas@i 14703 : 110 : appendPQExpBufferStr(q, " );\n");
14704 : :
2239 tgl@sss.pgh.pa.us 14705 : 110 : appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14706 : 110 : fmtQualifiedDumpable(dictinfo));
14707 : :
3470 alvherre@alvh.no-ip. 14708 [ + + ]: 110 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 14709 : 10 : binary_upgrade_extension_member(q, &dictinfo->dobj,
14710 : : "TEXT SEARCH DICTIONARY", qdictname,
14711 : 10 : dictinfo->dobj.namespace->dobj.name);
14712 : :
2930 sfrost@snowman.net 14713 [ + - ]: 110 : if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14714 : 110 : ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 14715 : 110 : ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
14716 : : .namespace = dictinfo->dobj.namespace->dobj.name,
14717 : : .owner = dictinfo->rolname,
14718 : : .description = "TEXT SEARCH DICTIONARY",
14719 : : .section = SECTION_PRE_DATA,
14720 : : .createStmt = q->data,
14721 : : .dropStmt = delq->data));
14722 : :
14723 : : /* Dump Dictionary Comments */
2930 sfrost@snowman.net 14724 [ + + ]: 110 : if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 14725 : 65 : dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
2596 14726 : 65 : dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
2930 sfrost@snowman.net 14727 : 65 : dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14728 : :
6081 tgl@sss.pgh.pa.us 14729 : 110 : destroyPQExpBuffer(q);
14730 : 110 : destroyPQExpBuffer(delq);
14731 : 110 : destroyPQExpBuffer(query);
2239 14732 : 110 : free(qdictname);
14733 : : }
14734 : :
14735 : : /*
14736 : : * dumpTSTemplate
14737 : : * write out a single text search template
14738 : : */
14739 : : static void
1159 peter@eisentraut.org 14740 : 44 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
14741 : : {
3014 tgl@sss.pgh.pa.us 14742 : 44 : DumpOptions *dopt = fout->dopt;
14743 : : PQExpBuffer q;
14744 : : PQExpBuffer delq;
14745 : : char *qtmplname;
14746 : :
14747 : : /* Do nothing in data-only dump */
860 14748 [ + + ]: 44 : if (dopt->dataOnly)
6081 14749 : 3 : return;
14750 : :
14751 : 41 : q = createPQExpBuffer();
14752 : 41 : delq = createPQExpBuffer();
14753 : :
2239 14754 : 41 : qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14755 : :
6081 14756 : 41 : appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
2239 14757 : 41 : fmtQualifiedDumpable(tmplinfo));
14758 : :
6081 14759 [ + + ]: 41 : if (tmplinfo->tmplinit != InvalidOid)
14760 : 5 : appendPQExpBuffer(q, " INIT = %s,\n",
4450 rhaas@postgresql.org 14761 : 5 : convertTSFunction(fout, tmplinfo->tmplinit));
6081 tgl@sss.pgh.pa.us 14762 : 41 : appendPQExpBuffer(q, " LEXIZE = %s );\n",
4450 rhaas@postgresql.org 14763 : 41 : convertTSFunction(fout, tmplinfo->tmpllexize));
14764 : :
2239 tgl@sss.pgh.pa.us 14765 : 41 : appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14766 : 41 : fmtQualifiedDumpable(tmplinfo));
14767 : :
3470 alvherre@alvh.no-ip. 14768 [ + + ]: 41 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 14769 : 1 : binary_upgrade_extension_member(q, &tmplinfo->dobj,
14770 : : "TEXT SEARCH TEMPLATE", qtmplname,
14771 : 1 : tmplinfo->dobj.namespace->dobj.name);
14772 : :
2930 sfrost@snowman.net 14773 [ + - ]: 41 : if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14774 : 41 : ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 14775 : 41 : ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
14776 : : .namespace = tmplinfo->dobj.namespace->dobj.name,
14777 : : .description = "TEXT SEARCH TEMPLATE",
14778 : : .section = SECTION_PRE_DATA,
14779 : : .createStmt = q->data,
14780 : : .dropStmt = delq->data));
14781 : :
14782 : : /* Dump Template Comments */
2930 sfrost@snowman.net 14783 [ + - ]: 41 : if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 14784 : 41 : dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
2596 14785 : 41 : tmplinfo->dobj.namespace->dobj.name, "",
2930 sfrost@snowman.net 14786 : 41 : tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14787 : :
6081 tgl@sss.pgh.pa.us 14788 : 41 : destroyPQExpBuffer(q);
14789 : 41 : destroyPQExpBuffer(delq);
2239 14790 : 41 : free(qtmplname);
14791 : : }
14792 : :
14793 : : /*
14794 : : * dumpTSConfig
14795 : : * write out a single text search configuration
14796 : : */
14797 : : static void
1159 peter@eisentraut.org 14798 : 88 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
14799 : : {
3014 tgl@sss.pgh.pa.us 14800 : 88 : DumpOptions *dopt = fout->dopt;
14801 : : PQExpBuffer q;
14802 : : PQExpBuffer delq;
14803 : : PQExpBuffer query;
14804 : : char *qcfgname;
14805 : : PGresult *res;
14806 : : char *nspname;
14807 : : char *prsname;
14808 : : int ntups,
14809 : : i;
14810 : : int i_tokenname;
14811 : : int i_dictname;
14812 : :
14813 : : /* Do nothing in data-only dump */
860 14814 [ + + ]: 88 : if (dopt->dataOnly)
6081 14815 : 3 : return;
14816 : :
14817 : 85 : q = createPQExpBuffer();
14818 : 85 : delq = createPQExpBuffer();
14819 : 85 : query = createPQExpBuffer();
14820 : :
2239 14821 : 85 : qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14822 : :
14823 : : /* Fetch name and namespace of the config's parser */
6081 14824 : 85 : appendPQExpBuffer(query, "SELECT nspname, prsname "
14825 : : "FROM pg_ts_parser p, pg_namespace n "
14826 : : "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14827 : 85 : cfginfo->cfgparser);
4441 rhaas@postgresql.org 14828 : 85 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
6081 tgl@sss.pgh.pa.us 14829 : 85 : nspname = PQgetvalue(res, 0, 0);
14830 : 85 : prsname = PQgetvalue(res, 0, 1);
14831 : :
14832 : 85 : appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
2239 14833 : 85 : fmtQualifiedDumpable(cfginfo));
14834 : :
14835 : 85 : appendPQExpBuffer(q, " PARSER = %s.", fmtId(nspname));
6081 14836 : 85 : appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14837 : :
14838 : 85 : PQclear(res);
14839 : :
14840 : 85 : resetPQExpBuffer(query);
14841 : 85 : appendPQExpBuffer(query,
14842 : : "SELECT\n"
14843 : : " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14844 : : " WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14845 : : " m.mapdict::pg_catalog.regdictionary AS dictname\n"
14846 : : "FROM pg_catalog.pg_ts_config_map AS m\n"
14847 : : "WHERE m.mapcfg = '%u'\n"
14848 : : "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14849 : 85 : cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14850 : :
4450 rhaas@postgresql.org 14851 : 85 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6081 tgl@sss.pgh.pa.us 14852 : 85 : ntups = PQntuples(res);
14853 : :
14854 : 85 : i_tokenname = PQfnumber(res, "tokenname");
14855 : 85 : i_dictname = PQfnumber(res, "dictname");
14856 : :
14857 [ + + ]: 1835 : for (i = 0; i < ntups; i++)
14858 : : {
5995 bruce@momjian.us 14859 : 1750 : char *tokenname = PQgetvalue(res, i, i_tokenname);
14860 : 1750 : char *dictname = PQgetvalue(res, i, i_dictname);
14861 : :
6081 tgl@sss.pgh.pa.us 14862 [ + + ]: 1750 : if (i == 0 ||
5995 bruce@momjian.us 14863 [ + + ]: 1665 : strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14864 : : {
14865 : : /* starting a new token type, so start a new command */
6081 tgl@sss.pgh.pa.us 14866 [ + + ]: 1615 : if (i > 0)
3800 heikki.linnakangas@i 14867 : 1530 : appendPQExpBufferStr(q, ";\n");
6081 tgl@sss.pgh.pa.us 14868 : 1615 : appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
2239 14869 : 1615 : fmtQualifiedDumpable(cfginfo));
14870 : : /* tokenname needs quoting, dictname does NOT */
6081 14871 : 1615 : appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
14872 : : fmtId(tokenname), dictname);
14873 : : }
14874 : : else
14875 : 135 : appendPQExpBuffer(q, ", %s", dictname);
14876 : : }
14877 : :
14878 [ + - ]: 85 : if (ntups > 0)
3800 heikki.linnakangas@i 14879 : 85 : appendPQExpBufferStr(q, ";\n");
14880 : :
6081 tgl@sss.pgh.pa.us 14881 : 85 : PQclear(res);
14882 : :
2239 14883 : 85 : appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14884 : 85 : fmtQualifiedDumpable(cfginfo));
14885 : :
3470 alvherre@alvh.no-ip. 14886 [ + + ]: 85 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 14887 : 5 : binary_upgrade_extension_member(q, &cfginfo->dobj,
14888 : : "TEXT SEARCH CONFIGURATION", qcfgname,
14889 : 5 : cfginfo->dobj.namespace->dobj.name);
14890 : :
2930 sfrost@snowman.net 14891 [ + - ]: 85 : if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14892 : 85 : ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 14893 : 85 : ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
14894 : : .namespace = cfginfo->dobj.namespace->dobj.name,
14895 : : .owner = cfginfo->rolname,
14896 : : .description = "TEXT SEARCH CONFIGURATION",
14897 : : .section = SECTION_PRE_DATA,
14898 : : .createStmt = q->data,
14899 : : .dropStmt = delq->data));
14900 : :
14901 : : /* Dump Configuration Comments */
2930 sfrost@snowman.net 14902 [ + + ]: 85 : if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 14903 : 65 : dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
2596 14904 : 65 : cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
2930 sfrost@snowman.net 14905 : 65 : cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14906 : :
6081 tgl@sss.pgh.pa.us 14907 : 85 : destroyPQExpBuffer(q);
14908 : 85 : destroyPQExpBuffer(delq);
14909 : 85 : destroyPQExpBuffer(query);
2239 14910 : 85 : free(qcfgname);
14911 : : }
14912 : :
14913 : : /*
14914 : : * dumpForeignDataWrapper
14915 : : * write out a single foreign-data wrapper definition
14916 : : */
14917 : : static void
1159 peter@eisentraut.org 14918 : 53 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
14919 : : {
3014 tgl@sss.pgh.pa.us 14920 : 53 : DumpOptions *dopt = fout->dopt;
14921 : : PQExpBuffer q;
14922 : : PQExpBuffer delq;
14923 : : char *qfdwname;
14924 : :
14925 : : /* Do nothing in data-only dump */
860 14926 [ + + ]: 53 : if (dopt->dataOnly)
5595 peter_e@gmx.net 14927 : 4 : return;
14928 : :
14929 : 49 : q = createPQExpBuffer();
14930 : 49 : delq = createPQExpBuffer();
14931 : :
4524 bruce@momjian.us 14932 : 49 : qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14933 : :
5528 peter_e@gmx.net 14934 : 49 : appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14935 : : qfdwname);
14936 : :
4803 tgl@sss.pgh.pa.us 14937 [ - + ]: 49 : if (strcmp(fdwinfo->fdwhandler, "-") != 0)
4803 tgl@sss.pgh.pa.us 14938 :UBC 0 : appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14939 : :
4803 tgl@sss.pgh.pa.us 14940 [ - + ]:CBC 49 : if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
4803 tgl@sss.pgh.pa.us 14941 :UBC 0 : appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14942 : :
4803 tgl@sss.pgh.pa.us 14943 [ - + ]:CBC 49 : if (strlen(fdwinfo->fdwoptions) > 0)
4483 peter_e@gmx.net 14944 :UBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
14945 : :
3800 heikki.linnakangas@i 14946 :CBC 49 : appendPQExpBufferStr(q, ";\n");
14947 : :
5595 peter_e@gmx.net 14948 : 49 : appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14949 : : qfdwname);
14950 : :
3470 alvherre@alvh.no-ip. 14951 [ + + ]: 49 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 14952 : 2 : binary_upgrade_extension_member(q, &fdwinfo->dobj,
14953 : : "FOREIGN DATA WRAPPER", qfdwname,
14954 : : NULL);
14955 : :
2930 sfrost@snowman.net 14956 [ + - ]: 49 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14957 : 49 : ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 14958 : 49 : ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
14959 : : .owner = fdwinfo->rolname,
14960 : : .description = "FOREIGN DATA WRAPPER",
14961 : : .section = SECTION_PRE_DATA,
14962 : : .createStmt = q->data,
14963 : : .dropStmt = delq->data));
14964 : :
14965 : : /* Dump Foreign Data Wrapper Comments */
2274 tgl@sss.pgh.pa.us 14966 [ - + ]: 49 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 14967 :UBC 0 : dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
2274 14968 : 0 : NULL, fdwinfo->rolname,
14969 : 0 : fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14970 : :
14971 : : /* Handle the ACL */
2930 sfrost@snowman.net 14972 [ + + ]:CBC 49 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
1373 tgl@sss.pgh.pa.us 14973 : 35 : dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
14974 : : "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
860 14975 : 35 : NULL, fdwinfo->rolname, &fdwinfo->dacl);
14976 : :
4813 14977 : 49 : free(qfdwname);
14978 : :
5595 peter_e@gmx.net 14979 : 49 : destroyPQExpBuffer(q);
14980 : 49 : destroyPQExpBuffer(delq);
14981 : : }
14982 : :
14983 : : /*
14984 : : * dumpForeignServer
14985 : : * write out a foreign server definition
14986 : : */
14987 : : static void
1159 peter@eisentraut.org 14988 : 57 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
14989 : : {
3014 tgl@sss.pgh.pa.us 14990 : 57 : DumpOptions *dopt = fout->dopt;
14991 : : PQExpBuffer q;
14992 : : PQExpBuffer delq;
14993 : : PQExpBuffer query;
14994 : : PGresult *res;
14995 : : char *qsrvname;
14996 : : char *fdwname;
14997 : :
14998 : : /* Do nothing in data-only dump */
860 14999 [ + + ]: 57 : if (dopt->dataOnly)
5595 peter_e@gmx.net 15000 : 6 : return;
15001 : :
15002 : 51 : q = createPQExpBuffer();
15003 : 51 : delq = createPQExpBuffer();
15004 : 51 : query = createPQExpBuffer();
15005 : :
4524 bruce@momjian.us 15006 : 51 : qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
15007 : :
15008 : : /* look up the foreign-data wrapper */
5595 peter_e@gmx.net 15009 : 51 : appendPQExpBuffer(query, "SELECT fdwname "
15010 : : "FROM pg_foreign_data_wrapper w "
15011 : : "WHERE w.oid = '%u'",
15012 : 51 : srvinfo->srvfdw);
4441 rhaas@postgresql.org 15013 : 51 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
5595 peter_e@gmx.net 15014 : 51 : fdwname = PQgetvalue(res, 0, 0);
15015 : :
4813 tgl@sss.pgh.pa.us 15016 : 51 : appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
5595 peter_e@gmx.net 15017 [ + - - + ]: 51 : if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
15018 : : {
3800 heikki.linnakangas@i 15019 :UBC 0 : appendPQExpBufferStr(q, " TYPE ");
5485 15020 : 0 : appendStringLiteralAH(q, srvinfo->srvtype, fout);
15021 : : }
5595 peter_e@gmx.net 15022 [ + - - + ]:CBC 51 : if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
15023 : : {
3800 heikki.linnakangas@i 15024 :UBC 0 : appendPQExpBufferStr(q, " VERSION ");
5485 15025 : 0 : appendStringLiteralAH(q, srvinfo->srvversion, fout);
15026 : : }
15027 : :
3800 heikki.linnakangas@i 15028 :CBC 51 : appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
15029 : 51 : appendPQExpBufferStr(q, fmtId(fdwname));
15030 : :
5595 peter_e@gmx.net 15031 [ + - - + ]: 51 : if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
4483 peter_e@gmx.net 15032 :UBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
15033 : :
3800 heikki.linnakangas@i 15034 :CBC 51 : appendPQExpBufferStr(q, ";\n");
15035 : :
5595 peter_e@gmx.net 15036 : 51 : appendPQExpBuffer(delq, "DROP SERVER %s;\n",
15037 : : qsrvname);
15038 : :
3470 alvherre@alvh.no-ip. 15039 [ + + ]: 51 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 15040 : 2 : binary_upgrade_extension_member(q, &srvinfo->dobj,
15041 : : "SERVER", qsrvname, NULL);
15042 : :
2930 sfrost@snowman.net 15043 [ + - ]: 51 : if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15044 : 51 : ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 15045 : 51 : ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
15046 : : .owner = srvinfo->rolname,
15047 : : .description = "SERVER",
15048 : : .section = SECTION_PRE_DATA,
15049 : : .createStmt = q->data,
15050 : : .dropStmt = delq->data));
15051 : :
15052 : : /* Dump Foreign Server Comments */
2274 tgl@sss.pgh.pa.us 15053 [ - + ]: 51 : if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 15054 :UBC 0 : dumpComment(fout, "SERVER", qsrvname,
2274 15055 : 0 : NULL, srvinfo->rolname,
15056 : 0 : srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
15057 : :
15058 : : /* Handle the ACL */
2930 sfrost@snowman.net 15059 [ + + ]:CBC 51 : if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
1373 tgl@sss.pgh.pa.us 15060 : 35 : dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
15061 : : "FOREIGN SERVER", qsrvname, NULL, NULL,
860 15062 : 35 : NULL, srvinfo->rolname, &srvinfo->dacl);
15063 : :
15064 : : /* Dump user mappings */
2930 sfrost@snowman.net 15065 [ + - ]: 51 : if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
15066 : 51 : dumpUserMappings(fout,
15067 : 51 : srvinfo->dobj.name, NULL,
15068 : 51 : srvinfo->rolname,
15069 : 51 : srvinfo->dobj.catId, srvinfo->dobj.dumpId);
15070 : :
903 tgl@sss.pgh.pa.us 15071 : 51 : PQclear(res);
15072 : :
4813 15073 : 51 : free(qsrvname);
15074 : :
5595 peter_e@gmx.net 15075 : 51 : destroyPQExpBuffer(q);
15076 : 51 : destroyPQExpBuffer(delq);
2925 tgl@sss.pgh.pa.us 15077 : 51 : destroyPQExpBuffer(query);
15078 : : }
15079 : :
15080 : : /*
15081 : : * dumpUserMappings
15082 : : *
15083 : : * This routine is used to dump any user mappings associated with the
15084 : : * server handed to this routine. Should be called after ArchiveEntry()
15085 : : * for the server.
15086 : : */
15087 : : static void
5023 15088 : 51 : dumpUserMappings(Archive *fout,
15089 : : const char *servername, const char *namespace,
15090 : : const char *owner,
15091 : : CatalogId catalogId, DumpId dumpId)
15092 : : {
15093 : : PQExpBuffer q;
15094 : : PQExpBuffer delq;
15095 : : PQExpBuffer query;
15096 : : PQExpBuffer tag;
15097 : : PGresult *res;
15098 : : int ntups;
15099 : : int i_usename;
15100 : : int i_umoptions;
15101 : : int i;
15102 : :
5595 peter_e@gmx.net 15103 : 51 : q = createPQExpBuffer();
15104 : 51 : tag = createPQExpBuffer();
15105 : 51 : delq = createPQExpBuffer();
15106 : 51 : query = createPQExpBuffer();
15107 : :
15108 : : /*
15109 : : * We read from the publicly accessible view pg_user_mappings, so as not
15110 : : * to fail if run by a non-superuser. Note that the view will show
15111 : : * umoptions as null if the user hasn't got privileges for the associated
15112 : : * server; this means that pg_dump will dump such a mapping, but with no
15113 : : * OPTIONS clause. A possible alternative is to skip such mappings
15114 : : * altogether, but it's not clear that that's an improvement.
15115 : : */
15116 : 51 : appendPQExpBuffer(query,
15117 : : "SELECT usename, "
15118 : : "array_to_string(ARRAY("
15119 : : "SELECT quote_ident(option_name) || ' ' || "
15120 : : "quote_literal(option_value) "
15121 : : "FROM pg_options_to_table(umoptions) "
15122 : : "ORDER BY option_name"
15123 : : "), E',\n ') AS umoptions "
15124 : : "FROM pg_user_mappings "
15125 : : "WHERE srvid = '%u' "
15126 : : "ORDER BY usename",
15127 : : catalogId.oid);
15128 : :
4450 rhaas@postgresql.org 15129 : 51 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15130 : :
5595 peter_e@gmx.net 15131 : 51 : ntups = PQntuples(res);
5023 tgl@sss.pgh.pa.us 15132 : 51 : i_usename = PQfnumber(res, "usename");
5595 peter_e@gmx.net 15133 : 51 : i_umoptions = PQfnumber(res, "umoptions");
15134 : :
15135 [ + + ]: 86 : for (i = 0; i < ntups; i++)
15136 : : {
15137 : : char *usename;
15138 : : char *umoptions;
15139 : :
5023 tgl@sss.pgh.pa.us 15140 : 35 : usename = PQgetvalue(res, i, i_usename);
5595 peter_e@gmx.net 15141 : 35 : umoptions = PQgetvalue(res, i, i_umoptions);
15142 : :
15143 : 35 : resetPQExpBuffer(q);
5023 tgl@sss.pgh.pa.us 15144 : 35 : appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
5595 peter_e@gmx.net 15145 : 35 : appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
15146 : :
15147 [ + - - + ]: 35 : if (umoptions && strlen(umoptions) > 0)
4483 peter_e@gmx.net 15148 :UBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
15149 : :
3800 heikki.linnakangas@i 15150 :CBC 35 : appendPQExpBufferStr(q, ";\n");
15151 : :
5595 peter_e@gmx.net 15152 : 35 : resetPQExpBuffer(delq);
5023 tgl@sss.pgh.pa.us 15153 : 35 : appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
15154 : 35 : appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
15155 : :
5595 peter_e@gmx.net 15156 : 35 : resetPQExpBuffer(tag);
5023 tgl@sss.pgh.pa.us 15157 : 35 : appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
15158 : : usename, servername);
15159 : :
5595 peter_e@gmx.net 15160 : 35 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 15161 : 35 : ARCHIVE_OPTS(.tag = tag->data,
15162 : : .namespace = namespace,
15163 : : .owner = owner,
15164 : : .description = "USER MAPPING",
15165 : : .section = SECTION_PRE_DATA,
15166 : : .createStmt = q->data,
15167 : : .dropStmt = delq->data));
15168 : : }
15169 : :
5595 peter_e@gmx.net 15170 : 51 : PQclear(res);
15171 : :
15172 : 51 : destroyPQExpBuffer(query);
15173 : 51 : destroyPQExpBuffer(delq);
3697 sfrost@snowman.net 15174 : 51 : destroyPQExpBuffer(tag);
5595 peter_e@gmx.net 15175 : 51 : destroyPQExpBuffer(q);
15176 : 51 : }
15177 : :
15178 : : /*
15179 : : * Write out default privileges information
15180 : : */
15181 : : static void
1159 peter@eisentraut.org 15182 : 154 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
15183 : : {
3014 tgl@sss.pgh.pa.us 15184 : 154 : DumpOptions *dopt = fout->dopt;
15185 : : PQExpBuffer q;
15186 : : PQExpBuffer tag;
15187 : : const char *type;
15188 : :
15189 : : /* Do nothing in data-only dump, or if we're skipping ACLs */
860 15190 [ + + + + ]: 154 : if (dopt->dataOnly || dopt->aclsSkip)
5305 15191 : 16 : return;
15192 : :
15193 : 138 : q = createPQExpBuffer();
15194 : 138 : tag = createPQExpBuffer();
15195 : :
15196 [ + - + - : 138 : switch (daclinfo->defaclobjtype)
- - ]
15197 : : {
15198 : 69 : case DEFACLOBJ_RELATION:
5298 15199 : 69 : type = "TABLES";
5305 15200 : 69 : break;
5305 tgl@sss.pgh.pa.us 15201 :UBC 0 : case DEFACLOBJ_SEQUENCE:
5298 15202 : 0 : type = "SEQUENCES";
5305 15203 : 0 : break;
5305 tgl@sss.pgh.pa.us 15204 :CBC 69 : case DEFACLOBJ_FUNCTION:
5298 15205 : 69 : type = "FUNCTIONS";
5305 15206 : 69 : break;
4144 tgl@sss.pgh.pa.us 15207 :UBC 0 : case DEFACLOBJ_TYPE:
15208 : 0 : type = "TYPES";
15209 : 0 : break;
2574 teodor@sigaev.ru 15210 : 0 : case DEFACLOBJ_NAMESPACE:
15211 : 0 : type = "SCHEMAS";
15212 : 0 : break;
5305 tgl@sss.pgh.pa.us 15213 : 0 : default:
15214 : : /* shouldn't get here */
737 15215 : 0 : pg_fatal("unrecognized object type in default privileges: %d",
15216 : : (int) daclinfo->defaclobjtype);
15217 : : type = ""; /* keep compiler quiet */
15218 : : }
15219 : :
5298 tgl@sss.pgh.pa.us 15220 :CBC 138 : appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
15221 : :
15222 : : /* build the actual command(s) for this tuple */
5305 15223 [ - + ]: 138 : if (!buildDefaultACLCommands(type,
15224 : 138 : daclinfo->dobj.namespace != NULL ?
15225 : 70 : daclinfo->dobj.namespace->dobj.name : NULL,
860 15226 : 138 : daclinfo->dacl.acl,
15227 : 138 : daclinfo->dacl.acldefault,
5305 15228 [ + + ]: 138 : daclinfo->defaclrole,
15229 : : fout->remoteVersion,
15230 : : q))
737 tgl@sss.pgh.pa.us 15231 :UBC 0 : pg_fatal("could not parse default ACL list (%s)",
15232 : : daclinfo->dacl.acl);
15233 : :
2930 sfrost@snowman.net 15234 [ + - ]:CBC 138 : if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
15235 : 138 : ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 15236 [ + + ]: 138 : ARCHIVE_OPTS(.tag = tag->data,
15237 : : .namespace = daclinfo->dobj.namespace ?
15238 : : daclinfo->dobj.namespace->dobj.name : NULL,
15239 : : .owner = daclinfo->defaclrole,
15240 : : .description = "DEFAULT ACL",
15241 : : .section = SECTION_POST_DATA,
15242 : : .createStmt = q->data));
15243 : :
5305 tgl@sss.pgh.pa.us 15244 : 138 : destroyPQExpBuffer(tag);
15245 : 138 : destroyPQExpBuffer(q);
15246 : : }
15247 : :
15248 : : /*----------
15249 : : * Write out grant/revoke information
15250 : : *
15251 : : * 'objDumpId' is the dump ID of the underlying object.
15252 : : * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
15253 : : * or InvalidDumpId if there is no need for a second dependency.
15254 : : * 'type' must be one of
15255 : : * TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
15256 : : * FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
15257 : : * 'name' is the formatted name of the object. Must be quoted etc. already.
15258 : : * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
15259 : : * (Currently we assume that subname is only provided for table columns.)
15260 : : * 'nspname' is the namespace the object is in (NULL if none).
15261 : : * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
15262 : : * to use the default for the object type.
15263 : : * 'owner' is the owner, NULL if there is no owner (for languages).
15264 : : * 'dacl' is the DumpableAcl struct for the object.
15265 : : *
15266 : : * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
15267 : : * no ACL entry was created.
15268 : : *----------
15269 : : */
15270 : : static DumpId
1373 15271 : 23222 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
15272 : : const char *type, const char *name, const char *subname,
15273 : : const char *nspname, const char *tag, const char *owner,
15274 : : const DumpableAcl *dacl)
15275 : : {
15276 : 23222 : DumpId aclDumpId = InvalidDumpId;
3014 15277 : 23222 : DumpOptions *dopt = fout->dopt;
860 15278 : 23222 : const char *acls = dacl->acl;
15279 : 23222 : const char *acldefault = dacl->acldefault;
15280 : 23222 : char privtype = dacl->privtype;
15281 : 23222 : const char *initprivs = dacl->initprivs;
15282 : : const char *baseacls;
15283 : : PQExpBuffer sql;
15284 : :
15285 : : /* Do nothing if ACL dump is not enabled */
3470 alvherre@alvh.no-ip. 15286 [ + + ]: 23222 : if (dopt->aclsSkip)
1373 tgl@sss.pgh.pa.us 15287 : 318 : return InvalidDumpId;
15288 : :
15289 : : /* --data-only skips ACLs *except* large object ACLs */
3470 alvherre@alvh.no-ip. 15290 [ + + - + ]: 22904 : if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
1373 tgl@sss.pgh.pa.us 15291 :UBC 0 : return InvalidDumpId;
15292 : :
8014 tgl@sss.pgh.pa.us 15293 :CBC 22904 : sql = createPQExpBuffer();
15294 : :
15295 : : /*
15296 : : * In binary upgrade mode, we don't run an extension's script but instead
15297 : : * dump out the objects independently and then recreate them. To preserve
15298 : : * any initial privileges which were set on extension objects, we need to
15299 : : * compute the set of GRANT and REVOKE commands necessary to get from the
15300 : : * default privileges of an object to its initial privileges as recorded
15301 : : * in pg_init_privs.
15302 : : *
15303 : : * At restore time, we apply these commands after having called
15304 : : * binary_upgrade_set_record_init_privs(true). That tells the backend to
15305 : : * copy the results into pg_init_privs. This is how we preserve the
15306 : : * contents of that catalog across binary upgrades.
15307 : : */
860 15308 [ + + + + : 22904 : if (dopt->binary_upgrade && privtype == 'e' &&
+ - ]
15309 [ + - ]: 13 : initprivs && *initprivs != '\0')
15310 : : {
1746 drowley@postgresql.o 15311 : 13 : appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
2239 tgl@sss.pgh.pa.us 15312 [ - + ]: 13 : if (!buildACLCommands(name, subname, nspname, type,
15313 : : initprivs, acldefault, owner,
15314 : : "", fout->remoteVersion, sql))
737 tgl@sss.pgh.pa.us 15315 :UBC 0 : pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
15316 : : initprivs, acldefault, name, type);
1746 drowley@postgresql.o 15317 :CBC 13 : appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
15318 : : }
15319 : :
15320 : : /*
15321 : : * Now figure the GRANT and REVOKE commands needed to get to the object's
15322 : : * actual current ACL, starting from the initprivs if given, else from the
15323 : : * object-type-specific default. Also, while buildACLCommands will assume
15324 : : * that a NULL/empty acls string means it needn't do anything, what that
15325 : : * actually represents is the object-type-specific default; so we need to
15326 : : * substitute the acldefault string to get the right results in that case.
15327 : : */
860 tgl@sss.pgh.pa.us 15328 [ + + + + ]: 22904 : if (initprivs && *initprivs != '\0')
15329 : : {
15330 : 21021 : baseacls = initprivs;
15331 [ + - + + ]: 21021 : if (acls == NULL || *acls == '\0')
15332 : 17 : acls = acldefault;
15333 : : }
15334 : : else
15335 : 1883 : baseacls = acldefault;
15336 : :
2239 15337 [ - + ]: 22904 : if (!buildACLCommands(name, subname, nspname, type,
15338 : : acls, baseacls, owner,
15339 : : "", fout->remoteVersion, sql))
737 tgl@sss.pgh.pa.us 15340 :UBC 0 : pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
15341 : : acls, baseacls, name, type);
15342 : :
7625 tgl@sss.pgh.pa.us 15343 [ + + ]:CBC 22904 : if (sql->len > 0)
15344 : : {
13 tgl@sss.pgh.pa.us 15345 :GNC 1971 : PQExpBuffer tagbuf = createPQExpBuffer();
15346 : : DumpId aclDeps[2];
1373 tgl@sss.pgh.pa.us 15347 :CBC 1971 : int nDeps = 0;
15348 : :
13 tgl@sss.pgh.pa.us 15349 [ - + ]:GNC 1971 : if (tag)
13 tgl@sss.pgh.pa.us 15350 :UNC 0 : appendPQExpBufferStr(tagbuf, tag);
13 tgl@sss.pgh.pa.us 15351 [ + + ]:GNC 1971 : else if (subname)
15352 : 1169 : appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
15353 : : else
15354 : 802 : appendPQExpBuffer(tagbuf, "%s %s", type, name);
15355 : :
1373 tgl@sss.pgh.pa.us 15356 :CBC 1971 : aclDeps[nDeps++] = objDumpId;
15357 [ + + ]: 1971 : if (altDumpId != InvalidDumpId)
15358 : 1092 : aclDeps[nDeps++] = altDumpId;
15359 : :
15360 : 1971 : aclDumpId = createDumpId();
15361 : :
15362 : 1971 : ArchiveEntry(fout, nilCatalogId, aclDumpId,
13 tgl@sss.pgh.pa.us 15363 :GNC 1971 : ARCHIVE_OPTS(.tag = tagbuf->data,
15364 : : .namespace = nspname,
15365 : : .owner = owner,
15366 : : .description = "ACL",
15367 : : .section = SECTION_NONE,
15368 : : .createStmt = sql->data,
15369 : : .deps = aclDeps,
15370 : : .nDeps = nDeps));
15371 : :
15372 : 1971 : destroyPQExpBuffer(tagbuf);
15373 : : }
15374 : :
8014 tgl@sss.pgh.pa.us 15375 :CBC 22904 : destroyPQExpBuffer(sql);
15376 : :
1373 15377 : 22904 : return aclDumpId;
15378 : : }
15379 : :
15380 : : /*
15381 : : * dumpSecLabel
15382 : : *
15383 : : * This routine is used to dump any security labels associated with the
15384 : : * object handed to this routine. The routine takes the object type
15385 : : * and object name (ready to print, except for schema decoration), plus
15386 : : * the namespace and owner of the object (for labeling the ArchiveEntry),
15387 : : * plus catalog ID and subid which are the lookup key for pg_seclabel,
15388 : : * plus the dump ID for the object (for setting a dependency).
15389 : : * If a matching pg_seclabel entry is found, it is dumped.
15390 : : *
15391 : : * Note: although this routine takes a dumpId for dependency purposes,
15392 : : * that purpose is just to mark the dependency in the emitted dump file
15393 : : * for possible future use by pg_restore. We do NOT use it for determining
15394 : : * ordering of the label in the dump file, because this routine is called
15395 : : * after dependency sorting occurs. This routine should be called just after
15396 : : * calling ArchiveEntry() for the specified object.
15397 : : */
15398 : : static void
2239 tgl@sss.pgh.pa.us 15399 :UBC 0 : dumpSecLabel(Archive *fout, const char *type, const char *name,
15400 : : const char *namespace, const char *owner,
15401 : : CatalogId catalogId, int subid, DumpId dumpId)
15402 : : {
3014 15403 : 0 : DumpOptions *dopt = fout->dopt;
15404 : : SecLabelItem *labels;
15405 : : int nlabels;
15406 : : int i;
15407 : : PQExpBuffer query;
15408 : :
15409 : : /* do nothing, if --no-security-labels is supplied */
3470 alvherre@alvh.no-ip. 15410 [ # # ]: 0 : if (dopt->no_security_labels)
4948 rhaas@postgresql.org 15411 : 0 : return;
15412 : :
15413 : : /*
15414 : : * Security labels are schema not data ... except large object labels are
15415 : : * data
15416 : : */
2239 tgl@sss.pgh.pa.us 15417 [ # # ]: 0 : if (strcmp(type, "LARGE OBJECT") != 0)
15418 : : {
3470 alvherre@alvh.no-ip. 15419 [ # # ]: 0 : if (dopt->dataOnly)
4948 rhaas@postgresql.org 15420 : 0 : return;
15421 : : }
15422 : : else
15423 : : {
15424 : : /* We do dump large object security labels in binary-upgrade mode */
2596 sfrost@snowman.net 15425 [ # # # # ]: 0 : if (dopt->schemaOnly && !dopt->binary_upgrade)
4948 rhaas@postgresql.org 15426 : 0 : return;
15427 : : }
15428 : :
15429 : : /* Search for security labels associated with catalogId, using table */
836 tgl@sss.pgh.pa.us 15430 : 0 : nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
15431 : :
4948 rhaas@postgresql.org 15432 : 0 : query = createPQExpBuffer();
15433 : :
15434 [ # # ]: 0 : for (i = 0; i < nlabels; i++)
15435 : : {
15436 : : /*
15437 : : * Ignore label entries for which the subid doesn't match.
15438 : : */
15439 [ # # ]: 0 : if (labels[i].objsubid != subid)
15440 : 0 : continue;
15441 : :
15442 : 0 : appendPQExpBuffer(query,
15443 : : "SECURITY LABEL FOR %s ON %s ",
2239 tgl@sss.pgh.pa.us 15444 : 0 : fmtId(labels[i].provider), type);
15445 [ # # # # ]: 0 : if (namespace && *namespace)
15446 : 0 : appendPQExpBuffer(query, "%s.", fmtId(namespace));
15447 : 0 : appendPQExpBuffer(query, "%s IS ", name);
4948 rhaas@postgresql.org 15448 : 0 : appendStringLiteralAH(query, labels[i].label, fout);
3800 heikki.linnakangas@i 15449 : 0 : appendPQExpBufferStr(query, ";\n");
15450 : : }
15451 : :
4948 rhaas@postgresql.org 15452 [ # # ]: 0 : if (query->len > 0)
15453 : : {
2239 tgl@sss.pgh.pa.us 15454 : 0 : PQExpBuffer tag = createPQExpBuffer();
15455 : :
15456 : 0 : appendPQExpBuffer(tag, "%s %s", type, name);
4948 rhaas@postgresql.org 15457 : 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 15458 : 0 : ARCHIVE_OPTS(.tag = tag->data,
15459 : : .namespace = namespace,
15460 : : .owner = owner,
15461 : : .description = "SECURITY LABEL",
15462 : : .section = SECTION_NONE,
15463 : : .createStmt = query->data,
15464 : : .deps = &dumpId,
15465 : : .nDeps = 1));
2239 tgl@sss.pgh.pa.us 15466 : 0 : destroyPQExpBuffer(tag);
15467 : : }
15468 : :
4948 rhaas@postgresql.org 15469 : 0 : destroyPQExpBuffer(query);
15470 : : }
15471 : :
15472 : : /*
15473 : : * dumpTableSecLabel
15474 : : *
15475 : : * As above, but dump security label for both the specified table (or view)
15476 : : * and its columns.
15477 : : */
15478 : : static void
1159 peter@eisentraut.org 15479 : 0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
15480 : : {
3014 tgl@sss.pgh.pa.us 15481 : 0 : DumpOptions *dopt = fout->dopt;
15482 : : SecLabelItem *labels;
15483 : : int nlabels;
15484 : : int i;
15485 : : PQExpBuffer query;
15486 : : PQExpBuffer target;
15487 : :
15488 : : /* do nothing, if --no-security-labels is supplied */
3470 alvherre@alvh.no-ip. 15489 [ # # ]: 0 : if (dopt->no_security_labels)
4948 rhaas@postgresql.org 15490 : 0 : return;
15491 : :
15492 : : /* SecLabel are SCHEMA not data */
3470 alvherre@alvh.no-ip. 15493 [ # # ]: 0 : if (dopt->dataOnly)
4948 rhaas@postgresql.org 15494 : 0 : return;
15495 : :
15496 : : /* Search for comments associated with relation, using table */
836 tgl@sss.pgh.pa.us 15497 : 0 : nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
4948 rhaas@postgresql.org 15498 : 0 : tbinfo->dobj.catId.oid,
15499 : : &labels);
15500 : :
15501 : : /* If security labels exist, build SECURITY LABEL statements */
15502 [ # # ]: 0 : if (nlabels <= 0)
15503 : 0 : return;
15504 : :
15505 : 0 : query = createPQExpBuffer();
15506 : 0 : target = createPQExpBuffer();
15507 : :
15508 [ # # ]: 0 : for (i = 0; i < nlabels; i++)
15509 : : {
15510 : : const char *colname;
4753 bruce@momjian.us 15511 : 0 : const char *provider = labels[i].provider;
15512 : 0 : const char *label = labels[i].label;
15513 : 0 : int objsubid = labels[i].objsubid;
15514 : :
4948 rhaas@postgresql.org 15515 : 0 : resetPQExpBuffer(target);
15516 [ # # ]: 0 : if (objsubid == 0)
15517 : : {
15518 : 0 : appendPQExpBuffer(target, "%s %s", reltypename,
2239 tgl@sss.pgh.pa.us 15519 : 0 : fmtQualifiedDumpable(tbinfo));
15520 : : }
15521 : : else
15522 : : {
4948 rhaas@postgresql.org 15523 : 0 : colname = getAttrName(objsubid, tbinfo);
15524 : : /* first fmtXXX result must be consumed before calling again */
2239 tgl@sss.pgh.pa.us 15525 : 0 : appendPQExpBuffer(target, "COLUMN %s",
15526 : 0 : fmtQualifiedDumpable(tbinfo));
4852 rhaas@postgresql.org 15527 : 0 : appendPQExpBuffer(target, ".%s", fmtId(colname));
15528 : : }
4948 15529 : 0 : appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
15530 : : fmtId(provider), target->data);
15531 : 0 : appendStringLiteralAH(query, label, fout);
3800 heikki.linnakangas@i 15532 : 0 : appendPQExpBufferStr(query, ";\n");
15533 : : }
4948 rhaas@postgresql.org 15534 [ # # ]: 0 : if (query->len > 0)
15535 : : {
15536 : 0 : resetPQExpBuffer(target);
15537 : 0 : appendPQExpBuffer(target, "%s %s", reltypename,
15538 : 0 : fmtId(tbinfo->dobj.name));
15539 : 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 15540 : 0 : ARCHIVE_OPTS(.tag = target->data,
15541 : : .namespace = tbinfo->dobj.namespace->dobj.name,
15542 : : .owner = tbinfo->rolname,
15543 : : .description = "SECURITY LABEL",
15544 : : .section = SECTION_NONE,
15545 : : .createStmt = query->data,
15546 : : .deps = &(tbinfo->dobj.dumpId),
15547 : : .nDeps = 1));
15548 : : }
4948 rhaas@postgresql.org 15549 : 0 : destroyPQExpBuffer(query);
15550 : 0 : destroyPQExpBuffer(target);
15551 : : }
15552 : :
15553 : : /*
15554 : : * findSecLabels
15555 : : *
15556 : : * Find the security label(s), if any, associated with the given object.
15557 : : * All the objsubid values associated with the given classoid/objoid are
15558 : : * found with one search.
15559 : : */
15560 : : static int
836 tgl@sss.pgh.pa.us 15561 : 0 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
15562 : : {
4753 bruce@momjian.us 15563 : 0 : SecLabelItem *middle = NULL;
15564 : : SecLabelItem *low;
15565 : : SecLabelItem *high;
15566 : : int nmatch;
15567 : :
860 tgl@sss.pgh.pa.us 15568 [ # # ]: 0 : if (nseclabels <= 0) /* no labels, so no match is possible */
15569 : : {
4539 15570 : 0 : *items = NULL;
15571 : 0 : return 0;
15572 : : }
15573 : :
15574 : : /*
15575 : : * Do binary search to find some item matching the object.
15576 : : */
860 15577 : 0 : low = &seclabels[0];
15578 : 0 : high = &seclabels[nseclabels - 1];
4948 rhaas@postgresql.org 15579 [ # # ]: 0 : while (low <= high)
15580 : : {
15581 : 0 : middle = low + (high - low) / 2;
15582 : :
15583 [ # # ]: 0 : if (classoid < middle->classoid)
15584 : 0 : high = middle - 1;
15585 [ # # ]: 0 : else if (classoid > middle->classoid)
15586 : 0 : low = middle + 1;
15587 [ # # ]: 0 : else if (objoid < middle->objoid)
15588 : 0 : high = middle - 1;
15589 [ # # ]: 0 : else if (objoid > middle->objoid)
15590 : 0 : low = middle + 1;
15591 : : else
4753 bruce@momjian.us 15592 : 0 : break; /* found a match */
15593 : : }
15594 : :
15595 [ # # ]: 0 : if (low > high) /* no matches */
15596 : : {
4948 rhaas@postgresql.org 15597 : 0 : *items = NULL;
15598 : 0 : return 0;
15599 : : }
15600 : :
15601 : : /*
15602 : : * Now determine how many items match the object. The search loop
15603 : : * invariant still holds: only items between low and high inclusive could
15604 : : * match.
15605 : : */
15606 : 0 : nmatch = 1;
15607 [ # # ]: 0 : while (middle > low)
15608 : : {
15609 [ # # ]: 0 : if (classoid != middle[-1].classoid ||
15610 [ # # ]: 0 : objoid != middle[-1].objoid)
15611 : : break;
15612 : 0 : middle--;
15613 : 0 : nmatch++;
15614 : : }
15615 : :
15616 : 0 : *items = middle;
15617 : :
15618 : 0 : middle += nmatch;
15619 [ # # ]: 0 : while (middle <= high)
15620 : : {
15621 [ # # ]: 0 : if (classoid != middle->classoid ||
15622 [ # # ]: 0 : objoid != middle->objoid)
15623 : : break;
15624 : 0 : middle++;
15625 : 0 : nmatch++;
15626 : : }
15627 : :
15628 : 0 : return nmatch;
15629 : : }
15630 : :
15631 : : /*
15632 : : * collectSecLabels
15633 : : *
15634 : : * Construct a table of all security labels available for database objects;
15635 : : * also set the has-seclabel component flag for each relevant object.
15636 : : *
15637 : : * The table is sorted by classoid/objid/objsubid for speed in lookup.
15638 : : */
15639 : : static void
860 tgl@sss.pgh.pa.us 15640 :CBC 155 : collectSecLabels(Archive *fout)
15641 : : {
15642 : : PGresult *res;
15643 : : PQExpBuffer query;
15644 : : int i_label;
15645 : : int i_provider;
15646 : : int i_classoid;
15647 : : int i_objoid;
15648 : : int i_objsubid;
15649 : : int ntups;
15650 : : int i;
15651 : : DumpableObject *dobj;
15652 : :
4948 rhaas@postgresql.org 15653 : 155 : query = createPQExpBuffer();
15654 : :
3800 heikki.linnakangas@i 15655 : 155 : appendPQExpBufferStr(query,
15656 : : "SELECT label, provider, classoid, objoid, objsubid "
15657 : : "FROM pg_catalog.pg_seclabel "
15658 : : "ORDER BY classoid, objoid, objsubid");
15659 : :
4450 rhaas@postgresql.org 15660 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15661 : :
15662 : : /* Construct lookup table containing OIDs in numeric form */
4753 bruce@momjian.us 15663 : 155 : i_label = PQfnumber(res, "label");
15664 : 155 : i_provider = PQfnumber(res, "provider");
15665 : 155 : i_classoid = PQfnumber(res, "classoid");
15666 : 155 : i_objoid = PQfnumber(res, "objoid");
15667 : 155 : i_objsubid = PQfnumber(res, "objsubid");
15668 : :
4948 rhaas@postgresql.org 15669 : 155 : ntups = PQntuples(res);
15670 : :
860 tgl@sss.pgh.pa.us 15671 : 155 : seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15672 : 155 : nseclabels = 0;
15673 : 155 : dobj = NULL;
15674 : :
4948 rhaas@postgresql.org 15675 [ - + ]: 155 : for (i = 0; i < ntups; i++)
15676 : : {
15677 : : CatalogId objId;
15678 : : int subid;
15679 : :
860 tgl@sss.pgh.pa.us 15680 :UBC 0 : objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
15681 : 0 : objId.oid = atooid(PQgetvalue(res, i, i_objoid));
15682 : 0 : subid = atoi(PQgetvalue(res, i, i_objsubid));
15683 : :
15684 : : /* We needn't remember labels that don't match any dumpable object */
15685 [ # # ]: 0 : if (dobj == NULL ||
15686 [ # # ]: 0 : dobj->catId.tableoid != objId.tableoid ||
15687 [ # # ]: 0 : dobj->catId.oid != objId.oid)
15688 : 0 : dobj = findObjectByCatalogId(objId);
15689 [ # # ]: 0 : if (dobj == NULL)
15690 : 0 : continue;
15691 : :
15692 : : /*
15693 : : * Labels on columns of composite types are linked to the type's
15694 : : * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
15695 : : * in the type's own DumpableObject.
15696 : : */
15697 [ # # # # ]: 0 : if (subid != 0 && dobj->objType == DO_TABLE &&
15698 [ # # ]: 0 : ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
15699 : 0 : {
15700 : : TypeInfo *cTypeInfo;
15701 : :
15702 : 0 : cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
15703 [ # # ]: 0 : if (cTypeInfo)
15704 : 0 : cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
15705 : : }
15706 : : else
15707 : 0 : dobj->components |= DUMP_COMPONENT_SECLABEL;
15708 : :
15709 : 0 : seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
15710 : 0 : seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
15711 : 0 : seclabels[nseclabels].classoid = objId.tableoid;
15712 : 0 : seclabels[nseclabels].objoid = objId.oid;
15713 : 0 : seclabels[nseclabels].objsubid = subid;
15714 : 0 : nseclabels++;
15715 : : }
15716 : :
860 tgl@sss.pgh.pa.us 15717 :CBC 155 : PQclear(res);
4753 bruce@momjian.us 15718 : 155 : destroyPQExpBuffer(query);
4948 rhaas@postgresql.org 15719 : 155 : }
15720 : :
15721 : : /*
15722 : : * dumpTable
15723 : : * write out to fout the declarations (not data) of a user-defined table
15724 : : */
15725 : : static void
1159 peter@eisentraut.org 15726 : 25269 : dumpTable(Archive *fout, const TableInfo *tbinfo)
15727 : : {
2930 sfrost@snowman.net 15728 : 25269 : DumpOptions *dopt = fout->dopt;
1373 tgl@sss.pgh.pa.us 15729 : 25269 : DumpId tableAclDumpId = InvalidDumpId;
15730 : : char *namecopy;
15731 : :
15732 : : /* Do nothing in data-only dump */
860 15733 [ + + ]: 25269 : if (dopt->dataOnly)
2928 sfrost@snowman.net 15734 : 867 : return;
15735 : :
860 tgl@sss.pgh.pa.us 15736 [ + + ]: 24402 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15737 : : {
15738 [ + + ]: 5789 : if (tbinfo->relkind == RELKIND_SEQUENCE)
15739 : 367 : dumpSequence(fout, tbinfo);
15740 : : else
15741 : 5422 : dumpTableSchema(fout, tbinfo);
15742 : : }
15743 : :
15744 : : /* Handle the ACL here */
2930 sfrost@snowman.net 15745 : 24402 : namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15746 [ + + ]: 24402 : if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15747 : : {
2274 tgl@sss.pgh.pa.us 15748 : 19066 : const char *objtype =
331 15749 [ + + ]: 19066 : (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15750 : :
15751 : : tableAclDumpId =
1373 15752 : 19066 : dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
15753 : : objtype, namecopy, NULL,
13 tgl@sss.pgh.pa.us 15754 :GNC 19066 : tbinfo->dobj.namespace->dobj.name,
15755 : 19066 : NULL, tbinfo->rolname, &tbinfo->dacl);
15756 : : }
15757 : :
15758 : : /*
15759 : : * Handle column ACLs, if any. Note: we pull these with a separate query
15760 : : * rather than trying to fetch them during getTableAttrs, so that we won't
15761 : : * miss ACLs on system columns. Doing it this way also allows us to dump
15762 : : * ACLs for catalogs that we didn't mark "interesting" back in getTables.
15763 : : */
860 tgl@sss.pgh.pa.us 15764 [ + + + + ]:CBC 24402 : if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
15765 : : {
2930 sfrost@snowman.net 15766 : 261 : PQExpBuffer query = createPQExpBuffer();
15767 : : PGresult *res;
15768 : : int i;
15769 : :
860 tgl@sss.pgh.pa.us 15770 [ + + ]: 261 : if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
15771 : : {
15772 : : /* Set up query for column ACLs */
15773 : 132 : appendPQExpBufferStr(query,
15774 : : "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
15775 : :
15776 [ + - ]: 132 : if (fout->remoteVersion >= 90600)
15777 : : {
15778 : : /*
15779 : : * In principle we should call acldefault('c', relowner) to
15780 : : * get the default ACL for a column. However, we don't
15781 : : * currently store the numeric OID of the relowner in
15782 : : * TableInfo. We could convert the owner name using regrole,
15783 : : * but that creates a risk of failure due to concurrent role
15784 : : * renames. Given that the default ACL for columns is empty
15785 : : * and is likely to stay that way, it's not worth extra cycles
15786 : : * and risk to avoid hard-wiring that knowledge here.
15787 : : */
15788 : 132 : appendPQExpBufferStr(query,
15789 : : "SELECT at.attname, "
15790 : : "at.attacl, "
15791 : : "'{}' AS acldefault, "
15792 : : "pip.privtype, pip.initprivs "
15793 : : "FROM pg_catalog.pg_attribute at "
15794 : : "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15795 : : "(at.attrelid = pip.objoid "
15796 : : "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15797 : : "AND at.attnum = pip.objsubid) "
15798 : : "WHERE at.attrelid = $1 AND "
15799 : : "NOT at.attisdropped "
15800 : : "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
15801 : : "ORDER BY at.attnum");
15802 : : }
15803 : : else
15804 : : {
860 tgl@sss.pgh.pa.us 15805 :UBC 0 : appendPQExpBufferStr(query,
15806 : : "SELECT attname, attacl, '{}' AS acldefault, "
15807 : : "NULL AS privtype, NULL AS initprivs "
15808 : : "FROM pg_catalog.pg_attribute "
15809 : : "WHERE attrelid = $1 AND NOT attisdropped "
15810 : : "AND attacl IS NOT NULL "
15811 : : "ORDER BY attnum");
15812 : : }
15813 : :
860 tgl@sss.pgh.pa.us 15814 :CBC 132 : ExecuteSqlStatement(fout, query->data);
15815 : :
15816 : 132 : fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
15817 : : }
15818 : :
15819 : 261 : printfPQExpBuffer(query,
15820 : : "EXECUTE getColumnACLs('%u')",
15821 : 261 : tbinfo->dobj.catId.oid);
15822 : :
2930 sfrost@snowman.net 15823 : 261 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15824 : :
15825 [ + + ]: 3623 : for (i = 0; i < PQntuples(res); i++)
15826 : : {
15827 : 3362 : char *attname = PQgetvalue(res, i, 0);
15828 : 3362 : char *attacl = PQgetvalue(res, i, 1);
860 tgl@sss.pgh.pa.us 15829 : 3362 : char *acldefault = PQgetvalue(res, i, 2);
15830 : 3362 : char privtype = *(PQgetvalue(res, i, 3));
15831 : 3362 : char *initprivs = PQgetvalue(res, i, 4);
15832 : : DumpableAcl coldacl;
15833 : : char *attnamecopy;
15834 : :
15835 : 3362 : coldacl.acl = attacl;
15836 : 3362 : coldacl.acldefault = acldefault;
15837 : 3362 : coldacl.privtype = privtype;
15838 : 3362 : coldacl.initprivs = initprivs;
2930 sfrost@snowman.net 15839 : 3362 : attnamecopy = pg_strdup(fmtId(attname));
15840 : :
15841 : : /*
15842 : : * Column's GRANT type is always TABLE. Each column ACL depends
15843 : : * on the table-level ACL, since we can restore column ACLs in
15844 : : * parallel but the table-level ACL has to be done first.
15845 : : */
1373 tgl@sss.pgh.pa.us 15846 : 3362 : dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
15847 : : "TABLE", namecopy, attnamecopy,
13 tgl@sss.pgh.pa.us 15848 :GNC 3362 : tbinfo->dobj.namespace->dobj.name,
15849 : 3362 : NULL, tbinfo->rolname, &coldacl);
2930 sfrost@snowman.net 15850 :CBC 3362 : free(attnamecopy);
15851 : : }
15852 : 261 : PQclear(res);
15853 : 261 : destroyPQExpBuffer(query);
15854 : : }
15855 : :
15856 : 24402 : free(namecopy);
15857 : : }
15858 : :
15859 : : /*
15860 : : * Create the AS clause for a view or materialized view. The semicolon is
15861 : : * stripped because a materialized view must add a WITH NO DATA clause.
15862 : : *
15863 : : * This returns a new buffer which must be freed by the caller.
15864 : : */
15865 : : static PQExpBuffer
1159 peter@eisentraut.org 15866 : 713 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
15867 : : {
4060 kgrittn@postgresql.o 15868 : 713 : PQExpBuffer query = createPQExpBuffer();
15869 : 713 : PQExpBuffer result = createPQExpBuffer();
15870 : : PGresult *res;
15871 : : int len;
15872 : :
15873 : : /* Fetch the view definition */
2741 tgl@sss.pgh.pa.us 15874 : 713 : appendPQExpBuffer(query,
15875 : : "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15876 : 713 : tbinfo->dobj.catId.oid);
15877 : :
4060 kgrittn@postgresql.o 15878 : 713 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15879 : :
15880 [ - + ]: 713 : if (PQntuples(res) != 1)
15881 : : {
4060 kgrittn@postgresql.o 15882 [ # # ]:UBC 0 : if (PQntuples(res) < 1)
737 tgl@sss.pgh.pa.us 15883 : 0 : pg_fatal("query to obtain definition of view \"%s\" returned no data",
15884 : : tbinfo->dobj.name);
15885 : : else
15886 : 0 : pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
15887 : : tbinfo->dobj.name);
15888 : : }
15889 : :
4060 kgrittn@postgresql.o 15890 :CBC 713 : len = PQgetlength(res, 0, 0);
15891 : :
15892 [ - + ]: 713 : if (len == 0)
737 tgl@sss.pgh.pa.us 15893 :UBC 0 : pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
15894 : : tbinfo->dobj.name);
15895 : :
15896 : : /* Strip off the trailing semicolon so that other things may follow. */
4039 andrew@dunslane.net 15897 [ - + ]:CBC 713 : Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
4060 kgrittn@postgresql.o 15898 : 713 : appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15899 : :
15900 : 713 : PQclear(res);
15901 : 713 : destroyPQExpBuffer(query);
15902 : :
15903 : 713 : return result;
15904 : : }
15905 : :
15906 : : /*
15907 : : * Create a dummy AS clause for a view. This is used when the real view
15908 : : * definition has to be postponed because of circular dependencies.
15909 : : * We must duplicate the view's external properties -- column names and types
15910 : : * (including collation) -- so that it works for subsequent references.
15911 : : *
15912 : : * This returns a new buffer which must be freed by the caller.
15913 : : */
15914 : : static PQExpBuffer
1159 peter@eisentraut.org 15915 : 20 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
15916 : : {
2705 tgl@sss.pgh.pa.us 15917 : 20 : PQExpBuffer result = createPQExpBuffer();
15918 : : int j;
15919 : :
15920 : 20 : appendPQExpBufferStr(result, "SELECT");
15921 : :
15922 [ + + ]: 40 : for (j = 0; j < tbinfo->numatts; j++)
15923 : : {
15924 [ + + ]: 20 : if (j > 0)
15925 : 10 : appendPQExpBufferChar(result, ',');
15926 : 20 : appendPQExpBufferStr(result, "\n ");
15927 : :
15928 : 20 : appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15929 : :
15930 : : /*
15931 : : * Must add collation if not default for the type, because CREATE OR
15932 : : * REPLACE VIEW won't change it
15933 : : */
15934 [ - + ]: 20 : if (OidIsValid(tbinfo->attcollation[j]))
15935 : : {
15936 : : CollInfo *coll;
15937 : :
2705 tgl@sss.pgh.pa.us 15938 :UBC 0 : coll = findCollationByOid(tbinfo->attcollation[j]);
15939 [ # # ]: 0 : if (coll)
2239 15940 : 0 : appendPQExpBuffer(result, " COLLATE %s",
15941 : 0 : fmtQualifiedDumpable(coll));
15942 : : }
15943 : :
2705 tgl@sss.pgh.pa.us 15944 :CBC 20 : appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15945 : : }
15946 : :
15947 : 20 : return result;
15948 : : }
15949 : :
15950 : : /*
15951 : : * dumpTableSchema
15952 : : * write the declaration (not data) of one user-defined table or view
15953 : : */
15954 : : static void
1159 peter@eisentraut.org 15955 : 5422 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
15956 : : {
3014 tgl@sss.pgh.pa.us 15957 : 5422 : DumpOptions *dopt = fout->dopt;
8768 bruce@momjian.us 15958 : 5422 : PQExpBuffer q = createPQExpBuffer();
8685 15959 : 5422 : PQExpBuffer delq = createPQExpBuffer();
15960 : : char *qrelname;
15961 : : char *qualrelname;
15962 : : int numParents;
15963 : : TableInfo **parents;
15964 : : int actual_atts; /* number of attrs in this CREATE statement */
15965 : : const char *reltypename;
15966 : : char *storage;
15967 : : int j,
15968 : : k;
15969 : :
15970 : : /* We had better have loaded per-column details about this table */
1285 tgl@sss.pgh.pa.us 15971 [ - + ]: 5422 : Assert(tbinfo->interesting);
15972 : :
2239 15973 : 5422 : qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15974 : 5422 : qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15975 : :
1972 andres@anarazel.de 15976 [ - + ]: 5422 : if (tbinfo->hasoids)
1840 peter@eisentraut.org 15977 :UBC 0 : pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
15978 : : qrelname);
15979 : :
3470 alvherre@alvh.no-ip. 15980 [ + + ]:CBC 5422 : if (dopt->binary_upgrade)
860 tgl@sss.pgh.pa.us 15981 : 760 : binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
15982 : :
15983 : : /* Is it a table or a view? */
8010 15984 [ + + ]: 5422 : if (tbinfo->relkind == RELKIND_VIEW)
15985 : : {
15986 : : PQExpBuffer result;
15987 : :
15988 : : /*
15989 : : * Note: keep this code in sync with the is_view case in dumpRule()
15990 : : */
15991 : :
15992 : 349 : reltypename = "VIEW";
15993 : :
2239 15994 : 349 : appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15995 : :
3470 alvherre@alvh.no-ip. 15996 [ + + ]: 349 : if (dopt->binary_upgrade)
4450 rhaas@postgresql.org 15997 : 48 : binary_upgrade_set_pg_class_oids(fout, q,
15998 : 48 : tbinfo->dobj.catId.oid, false);
15999 : :
2239 tgl@sss.pgh.pa.us 16000 : 349 : appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
16001 : :
2705 16002 [ + + ]: 349 : if (tbinfo->dummy_view)
16003 : 10 : result = createDummyViewAsClause(fout, tbinfo);
16004 : : else
16005 : : {
16006 [ + + ]: 339 : if (nonemptyReloptions(tbinfo->reloptions))
16007 : : {
16008 : 59 : appendPQExpBufferStr(q, " WITH (");
16009 : 59 : appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
16010 : 59 : appendPQExpBufferChar(q, ')');
16011 : : }
16012 : 339 : result = createViewAsClause(fout, tbinfo);
16013 : : }
3923 sfrost@snowman.net 16014 : 349 : appendPQExpBuffer(q, " AS\n%s", result->data);
4060 kgrittn@postgresql.o 16015 : 349 : destroyPQExpBuffer(result);
16016 : :
2705 tgl@sss.pgh.pa.us 16017 [ + + + - ]: 349 : if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
3923 sfrost@snowman.net 16018 : 36 : appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
3800 heikki.linnakangas@i 16019 : 349 : appendPQExpBufferStr(q, ";\n");
16020 : : }
16021 : : else
16022 : : {
860 tgl@sss.pgh.pa.us 16023 : 5073 : char *partkeydef = NULL;
1956 sfrost@snowman.net 16024 : 5073 : char *ftoptions = NULL;
16025 : 5073 : char *srvname = NULL;
1486 alvherre@alvh.no-ip. 16026 : 5073 : char *foreign = "";
16027 : :
16028 : : /*
16029 : : * Set reltypename, and collect any relkind-specific data that we
16030 : : * didn't fetch during getTables().
16031 : : */
4060 kgrittn@postgresql.o 16032 [ + + + + ]: 5073 : switch (tbinfo->relkind)
16033 : : {
860 tgl@sss.pgh.pa.us 16034 : 512 : case RELKIND_PARTITIONED_TABLE:
16035 : : {
16036 : 512 : PQExpBuffer query = createPQExpBuffer();
16037 : : PGresult *res;
16038 : :
16039 : 512 : reltypename = "TABLE";
16040 : :
16041 : : /* retrieve partition key definition */
16042 : 512 : appendPQExpBuffer(query,
16043 : : "SELECT pg_get_partkeydef('%u')",
16044 : 512 : tbinfo->dobj.catId.oid);
16045 : 512 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
16046 : 512 : partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
16047 : 512 : PQclear(res);
16048 : 512 : destroyPQExpBuffer(query);
16049 : 512 : break;
16050 : : }
2593 16051 : 38 : case RELKIND_FOREIGN_TABLE:
16052 : : {
4039 andrew@dunslane.net 16053 : 38 : PQExpBuffer query = createPQExpBuffer();
16054 : : PGresult *res;
16055 : : int i_srvname;
16056 : : int i_ftoptions;
16057 : :
16058 : 38 : reltypename = "FOREIGN TABLE";
16059 : :
16060 : : /* retrieve name of foreign server and generic options */
16061 : 38 : appendPQExpBuffer(query,
16062 : : "SELECT fs.srvname, "
16063 : : "pg_catalog.array_to_string(ARRAY("
16064 : : "SELECT pg_catalog.quote_ident(option_name) || "
16065 : : "' ' || pg_catalog.quote_literal(option_value) "
16066 : : "FROM pg_catalog.pg_options_to_table(ftoptions) "
16067 : : "ORDER BY option_name"
16068 : : "), E',\n ') AS ftoptions "
16069 : : "FROM pg_catalog.pg_foreign_table ft "
16070 : : "JOIN pg_catalog.pg_foreign_server fs "
16071 : : "ON (fs.oid = ft.ftserver) "
16072 : : "WHERE ft.ftrelid = '%u'",
16073 : 38 : tbinfo->dobj.catId.oid);
16074 : 38 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
16075 : 38 : i_srvname = PQfnumber(res, "srvname");
16076 : 38 : i_ftoptions = PQfnumber(res, "ftoptions");
16077 : 38 : srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
16078 : 38 : ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
16079 : 38 : PQclear(res);
16080 : 38 : destroyPQExpBuffer(query);
16081 : :
1486 alvherre@alvh.no-ip. 16082 : 38 : foreign = "FOREIGN ";
4039 andrew@dunslane.net 16083 : 38 : break;
16084 : : }
2593 tgl@sss.pgh.pa.us 16085 : 364 : case RELKIND_MATVIEW:
4060 kgrittn@postgresql.o 16086 : 364 : reltypename = "MATERIALIZED VIEW";
16087 : 364 : break;
16088 : 4159 : default:
16089 : 4159 : reltypename = "TABLE";
860 tgl@sss.pgh.pa.us 16090 : 4159 : break;
16091 : : }
16092 : :
8010 16093 : 5073 : numParents = tbinfo->numParents;
7435 16094 : 5073 : parents = tbinfo->parents;
16095 : :
2239 16096 : 5073 : appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
16097 : :
3470 alvherre@alvh.no-ip. 16098 [ + + ]: 5073 : if (dopt->binary_upgrade)
4450 rhaas@postgresql.org 16099 : 712 : binary_upgrade_set_pg_class_oids(fout, q,
16100 : 712 : tbinfo->dobj.catId.oid, false);
16101 : :
4852 16102 : 5073 : appendPQExpBuffer(q, "CREATE %s%s %s",
16103 [ + + ]: 5073 : tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
16104 : : "UNLOGGED " : "",
16105 : : reltypename,
16106 : : qualrelname);
16107 : :
16108 : : /*
16109 : : * Attach to type, if reloftype; except in case of a binary upgrade,
16110 : : * we dump the table normally and attach it to the type afterward.
16111 : : */
860 tgl@sss.pgh.pa.us 16112 [ + + + + ]: 5073 : if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
16113 : 24 : appendPQExpBuffer(q, " OF %s",
16114 : 24 : getFormattedTypeName(fout, tbinfo->reloftype,
16115 : : zeroIsError));
16116 : :
4060 kgrittn@postgresql.o 16117 [ + + ]: 5073 : if (tbinfo->relkind != RELKIND_MATVIEW)
16118 : : {
16119 : : /* Dump the attributes */
4039 andrew@dunslane.net 16120 : 4709 : actual_atts = 0;
16121 [ + + ]: 22400 : for (j = 0; j < tbinfo->numatts; j++)
16122 : : {
16123 : : /*
16124 : : * Normally, dump if it's locally defined in this table, and
16125 : : * not dropped. But for binary upgrade, we'll dump all the
16126 : : * columns, and then fix up the dropped and nonlocal cases
16127 : : * below.
16128 : : */
3470 alvherre@alvh.no-ip. 16129 [ + + ]: 17691 : if (shouldPrintColumn(dopt, tbinfo, j))
16130 : : {
16131 : : bool print_default;
16132 : : bool print_notnull;
16133 : :
16134 : : /*
16135 : : * Default value --- suppress if to be printed separately
16136 : : * or not at all.
16137 : : */
1770 16138 : 34565 : print_default = (tbinfo->attrdefs[j] != NULL &&
411 tgl@sss.pgh.pa.us 16139 [ + + + + ]: 17650 : tbinfo->attrdefs[j]->dobj.dump &&
1770 alvherre@alvh.no-ip. 16140 [ + + ]: 778 : !tbinfo->attrdefs[j]->separate);
16141 : :
16142 : : /*
16143 : : * Not Null constraint --- suppress unless it is locally
16144 : : * defined, except if partition, or in binary-upgrade case
16145 : : * where that won't work.
16146 : : */
233 alvherre@alvh.no-ip. 16147 :GNC 16872 : print_notnull =
16148 [ + + ]: 18728 : (tbinfo->notnull_constrs[j] != NULL &&
16149 [ + + + + ]: 1856 : (!tbinfo->notnull_inh[j] || tbinfo->ispartition ||
16150 [ + + ]: 51 : dopt->binary_upgrade));
16151 : :
16152 : : /*
16153 : : * Skip column if fully defined by reloftype, except in
16154 : : * binary upgrade
16155 : : */
860 tgl@sss.pgh.pa.us 16156 [ + + ]:CBC 16872 : if (OidIsValid(tbinfo->reloftype) &&
16157 [ + + + + ]: 50 : !print_default && !print_notnull &&
1770 alvherre@alvh.no-ip. 16158 [ + + ]: 30 : !dopt->binary_upgrade)
4039 andrew@dunslane.net 16159 : 24 : continue;
16160 : :
16161 : : /* Format properly if not first attr */
16162 [ + + ]: 16848 : if (actual_atts == 0)
3800 heikki.linnakangas@i 16163 : 4454 : appendPQExpBufferStr(q, " (");
16164 : : else
3209 16165 : 12394 : appendPQExpBufferChar(q, ',');
3800 16166 : 16848 : appendPQExpBufferStr(q, "\n ");
4039 andrew@dunslane.net 16167 : 16848 : actual_atts++;
16168 : :
16169 : : /* Attribute name */
3800 heikki.linnakangas@i 16170 : 16848 : appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
16171 : :
4039 andrew@dunslane.net 16172 [ + + ]: 16848 : if (tbinfo->attisdropped[j])
16173 : : {
16174 : : /*
16175 : : * ALTER TABLE DROP COLUMN clears
16176 : : * pg_attribute.atttypid, so we will not have gotten a
16177 : : * valid type name; insert INTEGER as a stopgap. We'll
16178 : : * clean things up later.
16179 : : */
3800 heikki.linnakangas@i 16180 : 79 : appendPQExpBufferStr(q, " INTEGER /* dummy */");
16181 : : /* and skip to the next column */
4039 andrew@dunslane.net 16182 : 79 : continue;
16183 : : }
16184 : :
16185 : : /*
16186 : : * Attribute type; print it except when creating a typed
16187 : : * table ('OF type_name'), but in binary-upgrade mode,
16188 : : * print it in that case too.
16189 : : */
860 tgl@sss.pgh.pa.us 16190 [ + + + + ]: 16769 : if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
16191 : : {
4039 andrew@dunslane.net 16192 : 16753 : appendPQExpBuffer(q, " %s",
2741 tgl@sss.pgh.pa.us 16193 : 16753 : tbinfo->atttypnames[j]);
16194 : : }
16195 : :
1770 alvherre@alvh.no-ip. 16196 [ + + ]: 16769 : if (print_default)
16197 : : {
1842 peter@eisentraut.org 16198 [ + + ]: 640 : if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
16199 : 274 : appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
16200 : 274 : tbinfo->attrdefs[j]->adef_expr);
16201 : : else
16202 : 366 : appendPQExpBuffer(q, " DEFAULT %s",
16203 : 366 : tbinfo->attrdefs[j]->adef_expr);
16204 : : }
16205 : :
16206 : :
1770 alvherre@alvh.no-ip. 16207 [ + + ]: 16769 : if (print_notnull)
16208 : : {
233 alvherre@alvh.no-ip. 16209 [ + + ]:GNC 1821 : if (tbinfo->notnull_constrs[j][0] == '\0')
16210 : 605 : appendPQExpBufferStr(q, " NOT NULL");
16211 : : else
16212 : 1216 : appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
16213 : 1216 : fmtId(tbinfo->notnull_constrs[j]));
16214 : :
16215 [ + + ]: 1821 : if (tbinfo->notnull_noinh[j])
16216 : 804 : appendPQExpBufferStr(q, " NO INHERIT");
16217 : : }
16218 : :
16219 : : /* Add collation if not default for the type */
4039 andrew@dunslane.net 16220 [ + + ]:CBC 16769 : if (OidIsValid(tbinfo->attcollation[j]))
16221 : : {
16222 : : CollInfo *coll;
16223 : :
16224 : 69 : coll = findCollationByOid(tbinfo->attcollation[j]);
16225 [ + - ]: 69 : if (coll)
2239 tgl@sss.pgh.pa.us 16226 : 69 : appendPQExpBuffer(q, " COLLATE %s",
16227 : 69 : fmtQualifiedDumpable(coll));
16228 : : }
16229 : : }
16230 : : }
16231 : :
16232 : : /*
16233 : : * Add non-inherited CHECK constraints, if any.
16234 : : *
16235 : : * For partitions, we need to include check constraints even if
16236 : : * they're not defined locally, because the ALTER TABLE ATTACH
16237 : : * PARTITION that we'll emit later expects the constraint to be
16238 : : * there. (No need to fix conislocal: ATTACH PARTITION does that)
16239 : : */
4039 andrew@dunslane.net 16240 [ + + ]: 5267 : for (j = 0; j < tbinfo->ncheck; j++)
16241 : : {
16242 : 558 : ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16243 : :
1770 alvherre@alvh.no-ip. 16244 [ + + ]: 558 : if (constr->separate ||
16245 [ + + + + ]: 518 : (!constr->conislocal && !tbinfo->ispartition))
4039 andrew@dunslane.net 16246 : 81 : continue;
16247 : :
16248 [ + + ]: 477 : if (actual_atts == 0)
3800 heikki.linnakangas@i 16249 : 16 : appendPQExpBufferStr(q, " (\n ");
16250 : : else
16251 : 461 : appendPQExpBufferStr(q, ",\n ");
16252 : :
4039 andrew@dunslane.net 16253 : 477 : appendPQExpBuffer(q, "CONSTRAINT %s ",
16254 : 477 : fmtId(constr->dobj.name));
3800 heikki.linnakangas@i 16255 : 477 : appendPQExpBufferStr(q, constr->condef);
16256 : :
4039 andrew@dunslane.net 16257 : 477 : actual_atts++;
16258 : : }
16259 : :
16260 [ + + ]: 4709 : if (actual_atts)
3800 heikki.linnakangas@i 16261 : 4470 : appendPQExpBufferStr(q, "\n)");
860 tgl@sss.pgh.pa.us 16262 [ + + - + ]: 239 : else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
16263 : : {
16264 : : /*
16265 : : * No attributes? we must have a parenthesized attribute list,
16266 : : * even though empty, when not using the OF TYPE syntax.
16267 : : */
3800 heikki.linnakangas@i 16268 : 227 : appendPQExpBufferStr(q, " (\n)");
16269 : : }
16270 : :
16271 : : /*
16272 : : * Emit the INHERITS clause (not for partitions), except in
16273 : : * binary-upgrade mode.
16274 : : */
1770 alvherre@alvh.no-ip. 16275 [ + + + + ]: 4709 : if (numParents > 0 && !tbinfo->ispartition &&
2537 sfrost@snowman.net 16276 [ + + ]: 355 : !dopt->binary_upgrade)
16277 : : {
3800 heikki.linnakangas@i 16278 : 304 : appendPQExpBufferStr(q, "\nINHERITS (");
4039 andrew@dunslane.net 16279 [ + + ]: 636 : for (k = 0; k < numParents; k++)
16280 : : {
16281 : 332 : TableInfo *parentRel = parents[k];
16282 : :
16283 [ + + ]: 332 : if (k > 0)
3800 heikki.linnakangas@i 16284 : 28 : appendPQExpBufferStr(q, ", ");
2239 tgl@sss.pgh.pa.us 16285 : 332 : appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
16286 : : }
3800 heikki.linnakangas@i 16287 : 304 : appendPQExpBufferChar(q, ')');
16288 : : }
16289 : :
2685 rhaas@postgresql.org 16290 [ + + ]: 4709 : if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
860 tgl@sss.pgh.pa.us 16291 : 512 : appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
16292 : :
4039 andrew@dunslane.net 16293 [ + + ]: 4709 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
16294 : 38 : appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
16295 : : }
16296 : :
3025 tgl@sss.pgh.pa.us 16297 [ + + - + ]: 10000 : if (nonemptyReloptions(tbinfo->reloptions) ||
16298 : 4927 : nonemptyReloptions(tbinfo->toast_reloptions))
16299 : : {
5421 bruce@momjian.us 16300 : 146 : bool addcomma = false;
16301 : :
3800 heikki.linnakangas@i 16302 : 146 : appendPQExpBufferStr(q, "\nWITH (");
3025 tgl@sss.pgh.pa.us 16303 [ + - ]: 146 : if (nonemptyReloptions(tbinfo->reloptions))
16304 : : {
5550 alvherre@alvh.no-ip. 16305 : 146 : addcomma = true;
2900 dean.a.rasheed@gmail 16306 : 146 : appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
16307 : : }
3025 tgl@sss.pgh.pa.us 16308 [ + + ]: 146 : if (nonemptyReloptions(tbinfo->toast_reloptions))
16309 : : {
16310 [ + - ]: 5 : if (addcomma)
16311 : 5 : appendPQExpBufferStr(q, ", ");
2900 dean.a.rasheed@gmail 16312 : 5 : appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
16313 : : fout);
16314 : : }
3800 heikki.linnakangas@i 16315 : 146 : appendPQExpBufferChar(q, ')');
16316 : : }
16317 : :
16318 : : /* Dump generic options if any */
4852 rhaas@postgresql.org 16319 [ + + + + ]: 5073 : if (ftoptions && ftoptions[0])
4483 peter_e@gmx.net 16320 : 36 : appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
16321 : :
16322 : : /*
16323 : : * For materialized views, create the AS clause just like a view. At
16324 : : * this point, we always mark the view as not populated.
16325 : : */
4060 kgrittn@postgresql.o 16326 [ + + ]: 5073 : if (tbinfo->relkind == RELKIND_MATVIEW)
16327 : : {
16328 : : PQExpBuffer result;
16329 : :
16330 : 364 : result = createViewAsClause(fout, tbinfo);
16331 : 364 : appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
16332 : : result->data);
16333 : 364 : destroyPQExpBuffer(result);
16334 : : }
16335 : : else
3800 heikki.linnakangas@i 16336 : 4709 : appendPQExpBufferStr(q, ";\n");
16337 : :
16338 : : /* Materialized views can depend on extensions */
1495 alvherre@alvh.no-ip. 16339 [ + + ]: 5073 : if (tbinfo->relkind == RELKIND_MATVIEW)
16340 : 364 : append_depends_on_extension(fout, q, &tbinfo->dobj,
16341 : : "pg_catalog.pg_class",
16342 : : "MATERIALIZED VIEW",
16343 : : qualrelname);
16344 : :
16345 : : /*
16346 : : * in binary upgrade mode, update the catalog with any missing values
16347 : : * that might be present.
16348 : : */
2123 andrew@dunslane.net 16349 [ + + ]: 5073 : if (dopt->binary_upgrade)
16350 : : {
16351 [ + + ]: 3659 : for (j = 0; j < tbinfo->numatts; j++)
16352 : : {
16353 [ + + ]: 2947 : if (tbinfo->attmissingval[j][0] != '\0')
16354 : : {
16355 : 2 : appendPQExpBufferStr(q, "\n-- set missing value.\n");
16356 : 2 : appendPQExpBufferStr(q,
16357 : : "SELECT pg_catalog.binary_upgrade_set_missing_value(");
16358 : 2 : appendStringLiteralAH(q, qualrelname, fout);
16359 : 2 : appendPQExpBufferStr(q, "::pg_catalog.regclass,");
16360 : 2 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
586 drowley@postgresql.o 16361 : 2 : appendPQExpBufferChar(q, ',');
2123 andrew@dunslane.net 16362 : 2 : appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
16363 : 2 : appendPQExpBufferStr(q, ");\n\n");
16364 : : }
16365 : : }
16366 : : }
16367 : :
16368 : : /*
16369 : : * To create binary-compatible heap files, we have to ensure the same
16370 : : * physical column order, including dropped columns, as in the
16371 : : * original. Therefore, we create dropped columns above and drop them
16372 : : * here, also updating their attlen/attalign values so that the
16373 : : * dropped column can be skipped properly. (We do not bother with
16374 : : * restoring the original attbyval setting.) Also, inheritance
16375 : : * relationships are set up by doing ALTER TABLE INHERIT rather than
16376 : : * using an INHERITS clause --- the latter would possibly mess up the
16377 : : * column order. That also means we have to take care about setting
16378 : : * attislocal correctly, plus fix up any inherited CHECK constraints.
16379 : : * Analogously, we set up typed tables using ALTER TABLE / OF here.
16380 : : *
16381 : : * We process foreign and partitioned tables here, even though they
16382 : : * lack heap storage, because they can participate in inheritance
16383 : : * relationships and we want this stuff to be consistent across the
16384 : : * inheritance tree. We can exclude indexes, toast tables, sequences
16385 : : * and matviews, even though they have storage, because we don't
16386 : : * support altering or dropping columns in them, nor can they be part
16387 : : * of inheritance trees.
16388 : : */
3311 tgl@sss.pgh.pa.us 16389 [ + + ]: 5073 : if (dopt->binary_upgrade &&
16390 [ + + ]: 712 : (tbinfo->relkind == RELKIND_RELATION ||
2685 rhaas@postgresql.org 16391 [ + + ]: 101 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
16392 [ + + ]: 100 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
16393 : : {
5535 bruce@momjian.us 16394 [ + + ]: 3622 : for (j = 0; j < tbinfo->numatts; j++)
16395 : : {
16396 [ + + ]: 2927 : if (tbinfo->attisdropped[j])
16397 : : {
3800 heikki.linnakangas@i 16398 : 79 : appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
5400 tgl@sss.pgh.pa.us 16399 : 79 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
16400 : : "SET attlen = %d, "
16401 : : "attalign = '%c', attbyval = false\n"
16402 : : "WHERE attname = ",
16403 : 79 : tbinfo->attlen[j],
16404 : 79 : tbinfo->attalign[j]);
16405 : 79 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
3800 heikki.linnakangas@i 16406 : 79 : appendPQExpBufferStr(q, "\n AND attrelid = ");
2239 tgl@sss.pgh.pa.us 16407 : 79 : appendStringLiteralAH(q, qualrelname, fout);
3800 heikki.linnakangas@i 16408 : 79 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16409 : :
2685 rhaas@postgresql.org 16410 [ + + ]: 79 : if (tbinfo->relkind == RELKIND_RELATION ||
16411 [ + - ]: 16 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
3946 andrew@dunslane.net 16412 : 79 : appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16413 : : qualrelname);
16414 : : else
3311 tgl@sss.pgh.pa.us 16415 :UBC 0 : appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
16416 : : qualrelname);
5535 bruce@momjian.us 16417 :CBC 79 : appendPQExpBuffer(q, "DROP COLUMN %s;\n",
16418 : 79 : fmtId(tbinfo->attnames[j]));
16419 : : }
5400 tgl@sss.pgh.pa.us 16420 [ + + ]: 2848 : else if (!tbinfo->attislocal[j])
16421 : : {
3800 heikki.linnakangas@i 16422 : 561 : appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
16423 : 561 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
16424 : : "SET attislocal = false\n"
16425 : : "WHERE attname = ");
5400 tgl@sss.pgh.pa.us 16426 : 561 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
3800 heikki.linnakangas@i 16427 : 561 : appendPQExpBufferStr(q, "\n AND attrelid = ");
2239 tgl@sss.pgh.pa.us 16428 : 561 : appendStringLiteralAH(q, qualrelname, fout);
3800 heikki.linnakangas@i 16429 : 561 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16430 : :
16431 : : /*
16432 : : * If a not-null constraint comes from inheritance, reset
16433 : : * conislocal. The inhcount is fixed later.
16434 : : */
233 alvherre@alvh.no-ip. 16435 [ + + ]:GNC 561 : if (tbinfo->notnull_constrs[j] != NULL &&
16436 [ + + ]: 83 : !tbinfo->notnull_throwaway[j] &&
16437 [ + + ]: 63 : tbinfo->notnull_inh[j] &&
16438 [ + + ]: 48 : !tbinfo->ispartition)
16439 : : {
16440 : 15 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
16441 : : "SET conislocal = false\n"
16442 : : "WHERE contype = 'n' AND conrelid = ");
16443 : 15 : appendStringLiteralAH(q, qualrelname, fout);
16444 : 15 : appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
16445 : : "conname = ");
16446 : 15 : appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
16447 : 15 : appendPQExpBufferStr(q, ";\n");
16448 : : }
16449 : : }
16450 : : }
16451 : :
16452 : : /*
16453 : : * Add inherited CHECK constraints, if any.
16454 : : *
16455 : : * For partitions, they were already dumped, and conislocal
16456 : : * doesn't need fixing.
16457 : : */
5400 tgl@sss.pgh.pa.us 16458 [ + + ]:CBC 746 : for (k = 0; k < tbinfo->ncheck; k++)
16459 : : {
16460 : 51 : ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
16461 : :
1770 alvherre@alvh.no-ip. 16462 [ + + + + : 51 : if (constr->separate || constr->conislocal || tbinfo->ispartition)
+ + ]
5400 tgl@sss.pgh.pa.us 16463 : 49 : continue;
16464 : :
3800 heikki.linnakangas@i 16465 : 2 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
1486 alvherre@alvh.no-ip. 16466 : 2 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
16467 : : foreign, qualrelname,
16468 : 2 : fmtId(constr->dobj.name),
16469 : : constr->condef);
3800 heikki.linnakangas@i 16470 : 2 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
16471 : : "SET conislocal = false\n"
16472 : : "WHERE contype = 'c' AND conname = ");
5400 tgl@sss.pgh.pa.us 16473 : 2 : appendStringLiteralAH(q, constr->dobj.name, fout);
3800 heikki.linnakangas@i 16474 : 2 : appendPQExpBufferStr(q, "\n AND conrelid = ");
2239 tgl@sss.pgh.pa.us 16475 : 2 : appendStringLiteralAH(q, qualrelname, fout);
3800 heikki.linnakangas@i 16476 : 2 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16477 : : }
16478 : :
1770 alvherre@alvh.no-ip. 16479 [ + + + + ]: 695 : if (numParents > 0 && !tbinfo->ispartition)
16480 : : {
16481 : 51 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
5400 tgl@sss.pgh.pa.us 16482 [ + + ]: 109 : for (k = 0; k < numParents; k++)
16483 : : {
16484 : 58 : TableInfo *parentRel = parents[k];
16485 : :
1486 alvherre@alvh.no-ip. 16486 : 58 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
16487 : : qualrelname,
1770 16488 : 58 : fmtQualifiedDumpable(parentRel));
16489 : : }
16490 : : }
16491 : :
860 tgl@sss.pgh.pa.us 16492 [ + + ]: 695 : if (OidIsValid(tbinfo->reloftype))
16493 : : {
3800 heikki.linnakangas@i 16494 : 6 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
4736 peter_e@gmx.net 16495 : 6 : appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
16496 : : qualrelname,
860 tgl@sss.pgh.pa.us 16497 : 6 : getFormattedTypeName(fout, tbinfo->reloftype,
16498 : : zeroIsError));
16499 : : }
16500 : : }
16501 : :
16502 : : /*
16503 : : * In binary_upgrade mode, arrange to restore the old relfrozenxid and
16504 : : * relminmxid of all vacuumable relations. (While vacuum.c processes
16505 : : * TOAST tables semi-independently, here we see them only as children
16506 : : * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
16507 : : * child toast table is handled below.)
16508 : : */
2244 16509 [ + + ]: 5073 : if (dopt->binary_upgrade &&
16510 [ + + ]: 712 : (tbinfo->relkind == RELKIND_RELATION ||
16511 [ + + ]: 101 : tbinfo->relkind == RELKIND_MATVIEW))
16512 : : {
3574 bruce@momjian.us 16513 : 628 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
5400 tgl@sss.pgh.pa.us 16514 : 628 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16515 : : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16516 : : "WHERE oid = ",
3574 bruce@momjian.us 16517 : 628 : tbinfo->frozenxid, tbinfo->minmxid);
2239 tgl@sss.pgh.pa.us 16518 : 628 : appendStringLiteralAH(q, qualrelname, fout);
3800 heikki.linnakangas@i 16519 : 628 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16520 : :
4755 bruce@momjian.us 16521 [ + + ]: 628 : if (tbinfo->toast_oid)
16522 : : {
16523 : : /*
16524 : : * The toast table will have the same OID at restore, so we
16525 : : * can safely target it by OID.
16526 : : */
3574 16527 : 272 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
4755 16528 : 272 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16529 : : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16530 : : "WHERE oid = '%u';\n",
3574 16531 : 272 : tbinfo->toast_frozenxid,
16532 : 272 : tbinfo->toast_minmxid, tbinfo->toast_oid);
16533 : : }
16534 : : }
16535 : :
16536 : : /*
16537 : : * In binary_upgrade mode, restore matviews' populated status by
16538 : : * poking pg_class directly. This is pretty ugly, but we can't use
16539 : : * REFRESH MATERIALIZED VIEW since it's possible that some underlying
16540 : : * matview is not populated even though this matview is; in any case,
16541 : : * we want to transfer the matview's heap storage, not run REFRESH.
16542 : : */
3470 alvherre@alvh.no-ip. 16543 [ + + + + ]: 5073 : if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
3996 tgl@sss.pgh.pa.us 16544 [ + + ]: 17 : tbinfo->relispopulated)
16545 : : {
3800 heikki.linnakangas@i 16546 : 15 : appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
16547 : 15 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
16548 : : "SET relispopulated = 't'\n"
16549 : : "WHERE oid = ");
2239 tgl@sss.pgh.pa.us 16550 : 15 : appendStringLiteralAH(q, qualrelname, fout);
3800 heikki.linnakangas@i 16551 : 15 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16552 : : }
16553 : :
16554 : : /*
16555 : : * Dump additional per-column properties that we can't handle in the
16556 : : * main CREATE TABLE command.
16557 : : */
7893 bruce@momjian.us 16558 [ + + ]: 23174 : for (j = 0; j < tbinfo->numatts; j++)
16559 : : {
16560 : : /* None of this applies to dropped columns */
4447 tgl@sss.pgh.pa.us 16561 [ + + ]: 18101 : if (tbinfo->attisdropped[j])
16562 : 426 : continue;
16563 : :
16564 : : /*
16565 : : * If we didn't dump the column definition explicitly above, and
16566 : : * it is not-null and did not inherit that property from a parent,
16567 : : * we have to mark it separately.
16568 : : */
3470 alvherre@alvh.no-ip. 16569 [ + + ]: 17675 : if (!shouldPrintColumn(dopt, tbinfo, j) &&
233 alvherre@alvh.no-ip. 16570 [ + + ]:GNC 472 : tbinfo->notnull_constrs[j] != NULL &&
16571 [ + + + - : 103 : (!tbinfo->notnull_inh[j] && !tbinfo->ispartition && !dopt->binary_upgrade))
+ - ]
16572 : : {
16573 : : /* No constraint name desired? */
16574 [ + + ]: 12 : if (tbinfo->notnull_constrs[j][0] == '\0')
16575 : 8 : appendPQExpBuffer(q,
16576 : : "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET NOT NULL;\n",
16577 : : foreign, qualrelname,
16578 : 8 : fmtId(tbinfo->attnames[j]));
16579 : : else
16580 : 8 : appendPQExpBuffer(q,
16581 : : "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s NOT NULL %s;\n",
16582 : : foreign, qualrelname,
16583 : 4 : tbinfo->notnull_constrs[j],
16584 : 4 : fmtId(tbinfo->attnames[j]));
16585 : : }
16586 : :
16587 : : /*
16588 : : * Dump per-column statistics information. We only issue an ALTER
16589 : : * TABLE statement if the attstattarget entry for this column is
16590 : : * not the default value.
16591 : : */
4447 tgl@sss.pgh.pa.us 16592 [ + + ]:CBC 17675 : if (tbinfo->attstattarget[j] >= 0)
1486 alvherre@alvh.no-ip. 16593 : 36 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
16594 : : foreign, qualrelname,
16595 : 36 : fmtId(tbinfo->attnames[j]),
7928 tgl@sss.pgh.pa.us 16596 : 36 : tbinfo->attstattarget[j]);
16597 : :
16598 : : /*
16599 : : * Dump per-column storage information. The statement is only
16600 : : * dumped if the storage has been changed from the type's default.
16601 : : */
4447 16602 [ + + ]: 17675 : if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
16603 : : {
7559 bruce@momjian.us 16604 [ + + - + : 87 : switch (tbinfo->attstorage[j])
- ]
16605 : : {
1502 tgl@sss.pgh.pa.us 16606 : 10 : case TYPSTORAGE_PLAIN:
7696 bruce@momjian.us 16607 : 10 : storage = "PLAIN";
16608 : 10 : break;
1502 tgl@sss.pgh.pa.us 16609 : 41 : case TYPSTORAGE_EXTERNAL:
7696 bruce@momjian.us 16610 : 41 : storage = "EXTERNAL";
16611 : 41 : break;
1502 tgl@sss.pgh.pa.us 16612 :UBC 0 : case TYPSTORAGE_EXTENDED:
7696 bruce@momjian.us 16613 : 0 : storage = "EXTENDED";
16614 : 0 : break;
1502 tgl@sss.pgh.pa.us 16615 :CBC 36 : case TYPSTORAGE_MAIN:
16616 : 36 : storage = "MAIN";
16617 : 36 : break;
7696 bruce@momjian.us 16618 :UBC 0 : default:
16619 : 0 : storage = NULL;
16620 : : }
16621 : :
16622 : : /*
16623 : : * Only dump the statement if it's a storage type we recognize
16624 : : */
7559 bruce@momjian.us 16625 [ + - ]:CBC 87 : if (storage != NULL)
1486 alvherre@alvh.no-ip. 16626 : 87 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
16627 : : foreign, qualrelname,
16628 : 87 : fmtId(tbinfo->attnames[j]),
16629 : : storage);
16630 : : }
16631 : :
16632 : : /*
16633 : : * Dump per-column compression, if it's been set.
16634 : : */
1121 tgl@sss.pgh.pa.us 16635 [ + + ]: 17675 : if (!dopt->no_toast_compression)
16636 : : {
16637 : : const char *cmname;
16638 : :
16639 [ + + + ]: 17592 : switch (tbinfo->attcompression[j])
16640 : : {
16641 : 55 : case 'p':
16642 : 55 : cmname = "pglz";
16643 : 55 : break;
16644 : 100 : case 'l':
16645 : 100 : cmname = "lz4";
16646 : 100 : break;
16647 : 17437 : default:
16648 : 17437 : cmname = NULL;
16649 : 17437 : break;
16650 : : }
16651 : :
1053 16652 [ + + ]: 17592 : if (cmname != NULL)
1121 16653 : 155 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
16654 : : foreign, qualrelname,
16655 : 155 : fmtId(tbinfo->attnames[j]),
16656 : : cmname);
16657 : : }
16658 : :
16659 : : /*
16660 : : * Dump per-column attributes.
16661 : : */
1053 16662 [ + + ]: 17675 : if (tbinfo->attoptions[j][0] != '\0')
16663 : 36 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
16664 : : foreign, qualrelname,
16665 : 36 : fmtId(tbinfo->attnames[j]),
16666 : 36 : tbinfo->attoptions[j]);
16667 : :
16668 : : /*
16669 : : * Dump per-column fdw options.
16670 : : */
16671 [ + + ]: 17675 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16672 [ + + ]: 38 : tbinfo->attfdwoptions[j][0] != '\0')
16673 : 36 : appendPQExpBuffer(q,
16674 : : "ALTER FOREIGN TABLE %s ALTER COLUMN %s OPTIONS (\n"
16675 : : " %s\n"
16676 : : ");\n",
16677 : : qualrelname,
16678 : 36 : fmtId(tbinfo->attnames[j]),
16679 : 36 : tbinfo->attfdwoptions[j]);
16680 : : } /* end loop over columns */
16681 : :
668 peter@eisentraut.org 16682 : 5073 : free(partkeydef);
16683 : 5073 : free(ftoptions);
16684 : 5073 : free(srvname);
16685 : : }
16686 : :
16687 : : /*
16688 : : * dump properties we only have ALTER TABLE syntax for
16689 : : */
3311 tgl@sss.pgh.pa.us 16690 [ + + ]: 5422 : if ((tbinfo->relkind == RELKIND_RELATION ||
2685 rhaas@postgresql.org 16691 [ + + ]: 1263 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
3311 tgl@sss.pgh.pa.us 16692 [ + + ]: 751 : tbinfo->relkind == RELKIND_MATVIEW) &&
3808 peter_e@gmx.net 16693 [ + + ]: 5035 : tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
16694 : : {
3810 rhaas@postgresql.org 16695 [ + - ]: 64 : if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
16696 : : {
16697 : : /* nothing to do, will be set when the index is dumped */
16698 : : }
16699 [ + - ]: 64 : else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
16700 : : {
16701 : 64 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
16702 : : qualrelname);
16703 : : }
3810 rhaas@postgresql.org 16704 [ # # ]:UBC 0 : else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16705 : : {
16706 : 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16707 : : qualrelname);
16708 : : }
16709 : : }
16710 : :
3115 sfrost@snowman.net 16711 [ + + ]:CBC 5422 : if (tbinfo->forcerowsec)
16712 : 5 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16713 : : qualrelname);
16714 : :
3470 alvherre@alvh.no-ip. 16715 [ + + ]: 5422 : if (dopt->binary_upgrade)
2239 tgl@sss.pgh.pa.us 16716 : 760 : binary_upgrade_extension_member(q, &tbinfo->dobj,
16717 : : reltypename, qrelname,
16718 : 760 : tbinfo->dobj.namespace->dobj.name);
16719 : :
2930 sfrost@snowman.net 16720 [ + - ]: 5422 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16721 : : {
863 peter@eisentraut.org 16722 : 5422 : char *tablespace = NULL;
1789 tgl@sss.pgh.pa.us 16723 : 5422 : char *tableam = NULL;
16724 : :
16725 : : /*
16726 : : * _selectTablespace() relies on tablespace-enabled objects in the
16727 : : * default tablespace to have a tablespace of "" (empty string) versus
16728 : : * non-tablespace-enabled objects to have a tablespace of NULL.
16729 : : * getTables() sets tbinfo->reltablespace to "" for the default
16730 : : * tablespace (not NULL).
16731 : : */
863 peter@eisentraut.org 16732 [ + + + - : 5422 : if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
+ - + - +
+ + + - +
+ - ]
16733 : 5035 : tablespace = tbinfo->reltablespace;
16734 : :
20 alvherre@alvh.no-ip. 16735 [ + + + - :GNC 5422 : if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
+ + ]
16736 [ + + ]: 899 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
1866 andres@anarazel.de 16737 :CBC 5035 : tableam = tbinfo->amname;
16738 : :
2930 sfrost@snowman.net 16739 : 5422 : ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 16740 [ + + ]: 5422 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16741 : : .namespace = tbinfo->dobj.namespace->dobj.name,
16742 : : .tablespace = tablespace,
16743 : : .tableam = tableam,
16744 : : .owner = tbinfo->rolname,
16745 : : .description = reltypename,
16746 : : .section = tbinfo->postponed_def ?
16747 : : SECTION_POST_DATA : SECTION_PRE_DATA,
16748 : : .createStmt = q->data,
16749 : : .dropStmt = delq->data));
16750 : : }
16751 : :
16752 : : /* Dump Table Comments */
2930 sfrost@snowman.net 16753 [ + + ]: 5422 : if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16754 : 82 : dumpTableComment(fout, tbinfo, reltypename);
16755 : :
16756 : : /* Dump Table Security Labels */
16757 [ - + ]: 5422 : if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2930 sfrost@snowman.net 16758 :UBC 0 : dumpTableSecLabel(fout, tbinfo, reltypename);
16759 : :
16760 : : /* Dump comments on inlined table constraints */
7061 tgl@sss.pgh.pa.us 16761 [ + + ]:CBC 5980 : for (j = 0; j < tbinfo->ncheck; j++)
16762 : : {
16763 : 558 : ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16764 : :
5819 16765 [ + + + + ]: 558 : if (constr->separate || !constr->conislocal)
7061 16766 : 229 : continue;
16767 : :
529 16768 [ + + ]: 329 : if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
2930 sfrost@snowman.net 16769 : 41 : dumpTableConstraintComment(fout, constr);
16770 : : }
16771 : :
8010 tgl@sss.pgh.pa.us 16772 : 5422 : destroyPQExpBuffer(q);
16773 : 5422 : destroyPQExpBuffer(delq);
2239 16774 : 5422 : free(qrelname);
16775 : 5422 : free(qualrelname);
8493 pjw@rhyme.com.au 16776 : 5422 : }
16777 : :
16778 : : /*
16779 : : * dumpTableAttach
16780 : : * write to fout the commands to attach a child partition
16781 : : *
16782 : : * Child partitions are always made by creating them separately
16783 : : * and then using ATTACH PARTITION, rather than using
16784 : : * CREATE TABLE ... PARTITION OF. This is important for preserving
16785 : : * any possible discrepancy in column layout, to allow assigning the
16786 : : * correct tablespace if different, and so that it's possible to restore
16787 : : * a partition without restoring its parent. (You'll get an error from
16788 : : * the ATTACH PARTITION command, but that can be ignored, or skipped
16789 : : * using "pg_restore -L" if you prefer.) The last point motivates
16790 : : * treating ATTACH PARTITION as a completely separate ArchiveEntry
16791 : : * rather than emitting it within the child partition's ArchiveEntry.
16792 : : */
16793 : : static void
1159 peter@eisentraut.org 16794 : 1259 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
16795 : : {
1189 tgl@sss.pgh.pa.us 16796 : 1259 : DumpOptions *dopt = fout->dopt;
16797 : : PQExpBuffer q;
16798 : : PGresult *res;
16799 : : char *partbound;
16800 : :
16801 : : /* Do nothing in data-only dump */
16802 [ + + ]: 1259 : if (dopt->dataOnly)
16803 : 21 : return;
16804 : :
16805 : 1238 : q = createPQExpBuffer();
16806 : :
860 16807 [ + + ]: 1238 : if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
16808 : : {
16809 : : /* Set up query for partbound details */
16810 : 47 : appendPQExpBufferStr(q,
16811 : : "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
16812 : :
16813 : 47 : appendPQExpBufferStr(q,
16814 : : "SELECT pg_get_expr(c.relpartbound, c.oid) "
16815 : : "FROM pg_class c "
16816 : : "WHERE c.oid = $1");
16817 : :
16818 : 47 : ExecuteSqlStatement(fout, q->data);
16819 : :
16820 : 47 : fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
16821 : : }
16822 : :
16823 : 1238 : printfPQExpBuffer(q,
16824 : : "EXECUTE dumpTableAttach('%u')",
16825 : 1238 : attachinfo->partitionTbl->dobj.catId.oid);
16826 : :
16827 : 1238 : res = ExecuteSqlQueryForSingleRow(fout, q->data);
16828 : 1238 : partbound = PQgetvalue(res, 0, 0);
16829 : :
16830 : : /* Perform ALTER TABLE on the parent */
16831 : 1238 : printfPQExpBuffer(q,
16832 : : "ALTER TABLE ONLY %s ",
1189 16833 : 1238 : fmtQualifiedDumpable(attachinfo->parentTbl));
16834 : 1238 : appendPQExpBuffer(q,
16835 : : "ATTACH PARTITION %s %s;\n",
16836 : 1238 : fmtQualifiedDumpable(attachinfo->partitionTbl),
16837 : : partbound);
16838 : :
16839 : : /*
16840 : : * There is no point in creating a drop query as the drop is done by table
16841 : : * drop. (If you think to change this, see also _printTocEntry().)
16842 : : * Although this object doesn't really have ownership as such, set the
16843 : : * owner field anyway to ensure that the command is run by the correct
16844 : : * role at restore time.
16845 : : */
16846 : 1238 : ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16847 : 1238 : ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16848 : : .namespace = attachinfo->dobj.namespace->dobj.name,
16849 : : .owner = attachinfo->partitionTbl->rolname,
16850 : : .description = "TABLE ATTACH",
16851 : : .section = SECTION_PRE_DATA,
16852 : : .createStmt = q->data));
16853 : :
860 16854 : 1238 : PQclear(res);
1189 16855 : 1238 : destroyPQExpBuffer(q);
16856 : : }
16857 : :
16858 : : /*
16859 : : * dumpAttrDef --- dump an attribute's default-value declaration
16860 : : */
16861 : : static void
1159 peter@eisentraut.org 16862 : 818 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
16863 : : {
3014 tgl@sss.pgh.pa.us 16864 : 818 : DumpOptions *dopt = fout->dopt;
7435 16865 : 818 : TableInfo *tbinfo = adinfo->adtable;
16866 : 818 : int adnum = adinfo->adnum;
16867 : : PQExpBuffer q;
16868 : : PQExpBuffer delq;
16869 : : char *qualrelname;
16870 : : char *tag;
16871 : : char *foreign;
16872 : :
16873 : : /* Do nothing in data-only dump */
860 16874 [ - + ]: 818 : if (dopt->dataOnly)
7435 tgl@sss.pgh.pa.us 16875 :UBC 0 : return;
16876 : :
16877 : : /* Skip if not "separate"; it was dumped in the table's definition */
4447 tgl@sss.pgh.pa.us 16878 [ + + ]:CBC 818 : if (!adinfo->separate)
7435 16879 : 640 : return;
16880 : :
16881 : 178 : q = createPQExpBuffer();
16882 : 178 : delq = createPQExpBuffer();
16883 : :
2239 16884 : 178 : qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16885 : :
1486 alvherre@alvh.no-ip. 16886 [ - + ]: 178 : foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
16887 : :
16888 : 178 : appendPQExpBuffer(q,
16889 : : "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
16890 : 178 : foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
7435 tgl@sss.pgh.pa.us 16891 : 178 : adinfo->adef_expr);
16892 : :
1486 alvherre@alvh.no-ip. 16893 : 178 : appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
16894 : : foreign, qualrelname,
7435 tgl@sss.pgh.pa.us 16895 : 178 : fmtId(tbinfo->attnames[adnum - 1]));
16896 : :
2971 peter_e@gmx.net 16897 : 178 : tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16898 : :
2930 sfrost@snowman.net 16899 [ + - ]: 178 : if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16900 : 178 : ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 16901 : 178 : ARCHIVE_OPTS(.tag = tag,
16902 : : .namespace = tbinfo->dobj.namespace->dobj.name,
16903 : : .owner = tbinfo->rolname,
16904 : : .description = "DEFAULT",
16905 : : .section = SECTION_PRE_DATA,
16906 : : .createStmt = q->data,
16907 : : .dropStmt = delq->data));
16908 : :
2971 peter_e@gmx.net 16909 : 178 : free(tag);
7435 tgl@sss.pgh.pa.us 16910 : 178 : destroyPQExpBuffer(q);
16911 : 178 : destroyPQExpBuffer(delq);
2239 16912 : 178 : free(qualrelname);
16913 : : }
16914 : :
16915 : : /*
16916 : : * getAttrName: extract the correct name for an attribute
16917 : : *
16918 : : * The array tblInfo->attnames[] only provides names of user attributes;
16919 : : * if a system attribute number is supplied, we have to fake it.
16920 : : * We also do a little bit of bounds checking for safety's sake.
16921 : : */
16922 : : static const char *
1159 peter@eisentraut.org 16923 : 1678 : getAttrName(int attrnum, const TableInfo *tblInfo)
16924 : : {
8393 tgl@sss.pgh.pa.us 16925 [ + - + - ]: 1678 : if (attrnum > 0 && attrnum <= tblInfo->numatts)
8207 bruce@momjian.us 16926 : 1678 : return tblInfo->attnames[attrnum - 1];
8393 tgl@sss.pgh.pa.us 16927 [ # # # # :UBC 0 : switch (attrnum)
# # # ]
16928 : : {
16929 : 0 : case SelfItemPointerAttributeNumber:
16930 : 0 : return "ctid";
16931 : 0 : case MinTransactionIdAttributeNumber:
16932 : 0 : return "xmin";
16933 : 0 : case MinCommandIdAttributeNumber:
16934 : 0 : return "cmin";
16935 : 0 : case MaxTransactionIdAttributeNumber:
16936 : 0 : return "xmax";
16937 : 0 : case MaxCommandIdAttributeNumber:
16938 : 0 : return "cmax";
16939 : 0 : case TableOidAttributeNumber:
16940 : 0 : return "tableoid";
16941 : : }
737 16942 : 0 : pg_fatal("invalid column number %d for table \"%s\"",
16943 : : attrnum, tblInfo->dobj.name);
16944 : : return NULL; /* keep compiler quiet */
16945 : : }
16946 : :
16947 : : /*
16948 : : * dumpIndex
16949 : : * write out to fout a user-defined index
16950 : : */
16951 : : static void
1159 peter@eisentraut.org 16952 :CBC 2216 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
16953 : : {
3014 tgl@sss.pgh.pa.us 16954 : 2216 : DumpOptions *dopt = fout->dopt;
7435 16955 : 2216 : TableInfo *tbinfo = indxinfo->indextable;
3944 16956 : 2216 : bool is_constraint = (indxinfo->indexconstraint != 0);
16957 : : PQExpBuffer q;
16958 : : PQExpBuffer delq;
16959 : : char *qindxname;
16960 : : char *qqindxname;
16961 : :
16962 : : /* Do nothing in data-only dump */
3470 alvherre@alvh.no-ip. 16963 [ + + ]: 2216 : if (dopt->dataOnly)
7435 tgl@sss.pgh.pa.us 16964 : 57 : return;
16965 : :
16966 : 2159 : q = createPQExpBuffer();
16967 : 2159 : delq = createPQExpBuffer();
16968 : :
2239 16969 : 2159 : qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
1495 alvherre@alvh.no-ip. 16970 : 2159 : qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
16971 : :
16972 : : /*
16973 : : * If there's an associated constraint, don't dump the index per se, but
16974 : : * do dump any comment for it. (This is safe because dependency ordering
16975 : : * will have ensured the constraint is emitted first.) Note that the
16976 : : * emitted comment has to be shown as depending on the constraint, not the
16977 : : * index, in such cases.
16978 : : */
3944 tgl@sss.pgh.pa.us 16979 [ + + ]: 2159 : if (!is_constraint)
16980 : : {
1944 michael@paquier.xyz 16981 : 989 : char *indstatcols = indxinfo->indstatcols;
16982 : 989 : char *indstatvals = indxinfo->indstatvals;
16983 : 989 : char **indstatcolsarray = NULL;
16984 : 989 : char **indstatvalsarray = NULL;
1242 16985 : 989 : int nstatcols = 0;
16986 : 989 : int nstatvals = 0;
16987 : :
3470 alvherre@alvh.no-ip. 16988 [ + + ]: 989 : if (dopt->binary_upgrade)
4450 rhaas@postgresql.org 16989 : 153 : binary_upgrade_set_pg_class_oids(fout, q,
16990 : 153 : indxinfo->dobj.catId.oid, true);
16991 : :
16992 : : /* Plain secondary index */
7435 tgl@sss.pgh.pa.us 16993 : 989 : appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16994 : :
16995 : : /*
16996 : : * Append ALTER TABLE commands as needed to set properties that we
16997 : : * only have ALTER TABLE syntax for. Keep this in sync with the
16998 : : * similar code in dumpConstraint!
16999 : : */
17000 : :
17001 : : /* If the index is clustered, we need to record that. */
17002 [ - + ]: 989 : if (indxinfo->indisclustered)
17003 : : {
7435 tgl@sss.pgh.pa.us 17004 :UBC 0 : appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
2239 17005 : 0 : fmtQualifiedDumpable(tbinfo));
17006 : : /* index name is not qualified in this syntax */
7435 17007 : 0 : appendPQExpBuffer(q, " ON %s;\n",
17008 : : qindxname);
17009 : : }
17010 : :
17011 : : /*
17012 : : * If the index has any statistics on some of its columns, generate
17013 : : * the associated ALTER INDEX queries.
17014 : : */
1242 michael@paquier.xyz 17015 [ + + - + ]:CBC 989 : if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
17016 : : {
17017 : : int j;
17018 : :
17019 [ - + ]: 36 : if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
737 tgl@sss.pgh.pa.us 17020 :UBC 0 : pg_fatal("could not parse index statistic columns");
1242 michael@paquier.xyz 17021 [ - + ]:CBC 36 : if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
737 tgl@sss.pgh.pa.us 17022 :UBC 0 : pg_fatal("could not parse index statistic values");
1242 michael@paquier.xyz 17023 [ - + ]:CBC 36 : if (nstatcols != nstatvals)
737 tgl@sss.pgh.pa.us 17024 :UBC 0 : pg_fatal("mismatched number of columns and values for index statistics");
17025 : :
1944 michael@paquier.xyz 17026 [ + + ]:CBC 108 : for (j = 0; j < nstatcols; j++)
17027 : : {
1495 alvherre@alvh.no-ip. 17028 : 72 : appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
17029 : :
17030 : : /*
17031 : : * Note that this is a column number, so no quotes should be
17032 : : * used.
17033 : : */
1944 michael@paquier.xyz 17034 : 72 : appendPQExpBuffer(q, "ALTER COLUMN %s ",
17035 : 72 : indstatcolsarray[j]);
17036 : 72 : appendPQExpBuffer(q, "SET STATISTICS %s;\n",
17037 : 72 : indstatvalsarray[j]);
17038 : : }
17039 : : }
17040 : :
17041 : : /* Indexes can depend on extensions */
1495 alvherre@alvh.no-ip. 17042 : 989 : append_depends_on_extension(fout, q, &indxinfo->dobj,
17043 : : "pg_catalog.pg_class",
17044 : : "INDEX", qqindxname);
17045 : :
17046 : : /* If the index defines identity, we need to record that. */
3810 rhaas@postgresql.org 17047 [ - + ]: 989 : if (indxinfo->indisreplident)
17048 : : {
3810 rhaas@postgresql.org 17049 :UBC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
2239 tgl@sss.pgh.pa.us 17050 : 0 : fmtQualifiedDumpable(tbinfo));
17051 : : /* index name is not qualified in this syntax */
3810 rhaas@postgresql.org 17052 : 0 : appendPQExpBuffer(q, " INDEX %s;\n",
17053 : : qindxname);
17054 : : }
17055 : :
1495 alvherre@alvh.no-ip. 17056 :CBC 989 : appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
17057 : :
2930 sfrost@snowman.net 17058 [ + - ]: 989 : if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17059 : 989 : ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 17060 : 989 : ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
17061 : : .namespace = tbinfo->dobj.namespace->dobj.name,
17062 : : .tablespace = indxinfo->tablespace,
17063 : : .owner = tbinfo->rolname,
17064 : : .description = "INDEX",
17065 : : .section = SECTION_POST_DATA,
17066 : : .createStmt = q->data,
17067 : : .dropStmt = delq->data));
17068 : :
668 peter@eisentraut.org 17069 : 989 : free(indstatcolsarray);
17070 : 989 : free(indstatvalsarray);
17071 : : }
17072 : :
17073 : : /* Dump Index Comments */
2930 sfrost@snowman.net 17074 [ + + ]: 2159 : if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 17075 [ + + ]: 15 : dumpComment(fout, "INDEX", qindxname,
2930 sfrost@snowman.net 17076 : 15 : tbinfo->dobj.namespace->dobj.name,
17077 : : tbinfo->rolname,
17078 : : indxinfo->dobj.catId, 0,
17079 : : is_constraint ? indxinfo->indexconstraint :
17080 : : indxinfo->dobj.dumpId);
17081 : :
7435 tgl@sss.pgh.pa.us 17082 : 2159 : destroyPQExpBuffer(q);
17083 : 2159 : destroyPQExpBuffer(delq);
2239 17084 : 2159 : free(qindxname);
1495 alvherre@alvh.no-ip. 17085 : 2159 : free(qqindxname);
17086 : : }
17087 : :
17088 : : /*
17089 : : * dumpIndexAttach
17090 : : * write out to fout a partitioned-index attachment clause
17091 : : */
17092 : : static void
1159 peter@eisentraut.org 17093 : 567 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
17094 : : {
17095 : : /* Do nothing in data-only dump */
2277 alvherre@alvh.no-ip. 17096 [ + + ]: 567 : if (fout->dopt->dataOnly)
17097 : 24 : return;
17098 : :
17099 [ + - ]: 543 : if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
17100 : : {
2274 tgl@sss.pgh.pa.us 17101 : 543 : PQExpBuffer q = createPQExpBuffer();
17102 : :
2056 17103 : 543 : appendPQExpBuffer(q, "ALTER INDEX %s ",
2239 17104 : 543 : fmtQualifiedDumpable(attachinfo->parentIdx));
2277 alvherre@alvh.no-ip. 17105 : 543 : appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
2239 tgl@sss.pgh.pa.us 17106 : 543 : fmtQualifiedDumpable(attachinfo->partitionIdx));
17107 : :
17108 : : /*
17109 : : * There is no point in creating a drop query as the drop is done by
17110 : : * index drop. (If you think to change this, see also
17111 : : * _printTocEntry().) Although this object doesn't really have
17112 : : * ownership as such, set the owner field anyway to ensure that the
17113 : : * command is run by the correct role at restore time.
17114 : : */
2277 alvherre@alvh.no-ip. 17115 : 543 : ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
1899 17116 : 543 : ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
17117 : : .namespace = attachinfo->dobj.namespace->dobj.name,
17118 : : .owner = attachinfo->parentIdx->indextable->rolname,
17119 : : .description = "INDEX ATTACH",
17120 : : .section = SECTION_POST_DATA,
17121 : : .createStmt = q->data));
17122 : :
2277 17123 : 543 : destroyPQExpBuffer(q);
17124 : : }
17125 : : }
17126 : :
17127 : : /*
17128 : : * dumpStatisticsExt
17129 : : * write out to fout an extended statistics object
17130 : : */
17131 : : static void
1159 peter@eisentraut.org 17132 : 136 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
17133 : : {
2578 alvherre@alvh.no-ip. 17134 : 136 : DumpOptions *dopt = fout->dopt;
17135 : : PQExpBuffer q;
17136 : : PQExpBuffer delq;
17137 : : PQExpBuffer query;
17138 : : char *qstatsextname;
17139 : : PGresult *res;
17140 : : char *stxdef;
17141 : :
17142 : : /* Do nothing in data-only dump */
860 tgl@sss.pgh.pa.us 17143 [ + + ]: 136 : if (dopt->dataOnly)
2578 alvherre@alvh.no-ip. 17144 : 9 : return;
17145 : :
17146 : 127 : q = createPQExpBuffer();
17147 : 127 : delq = createPQExpBuffer();
2254 tgl@sss.pgh.pa.us 17148 : 127 : query = createPQExpBuffer();
17149 : :
2239 17150 : 127 : qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
17151 : :
2254 17152 : 127 : appendPQExpBuffer(query, "SELECT "
17153 : : "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
17154 : 127 : statsextinfo->dobj.catId.oid);
17155 : :
17156 : 127 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
17157 : :
17158 : 127 : stxdef = PQgetvalue(res, 0, 0);
17159 : :
17160 : : /* Result of pg_get_statisticsobjdef is complete except for semicolon */
17161 : 127 : appendPQExpBuffer(q, "%s;\n", stxdef);
17162 : :
17163 : : /*
17164 : : * We only issue an ALTER STATISTICS statement if the stxstattarget entry
17165 : : * for this statistics object is not the default value.
17166 : : */
1678 tomas.vondra@postgre 17167 [ + + ]: 127 : if (statsextinfo->stattarget >= 0)
17168 : : {
17169 : 36 : appendPQExpBuffer(q, "ALTER STATISTICS %s ",
17170 : 36 : fmtQualifiedDumpable(statsextinfo));
17171 : 36 : appendPQExpBuffer(q, "SET STATISTICS %d;\n",
17172 : 36 : statsextinfo->stattarget);
17173 : : }
17174 : :
2239 tgl@sss.pgh.pa.us 17175 : 127 : appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
17176 : 127 : fmtQualifiedDumpable(statsextinfo));
17177 : :
2578 alvherre@alvh.no-ip. 17178 [ + - ]: 127 : if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2524 bruce@momjian.us 17179 : 127 : ArchiveEntry(fout, statsextinfo->dobj.catId,
17180 : 127 : statsextinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 17181 : 127 : ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
17182 : : .namespace = statsextinfo->dobj.namespace->dobj.name,
17183 : : .owner = statsextinfo->rolname,
17184 : : .description = "STATISTICS",
17185 : : .section = SECTION_POST_DATA,
17186 : : .createStmt = q->data,
17187 : : .dropStmt = delq->data));
17188 : :
17189 : : /* Dump Statistics Comments */
2578 17190 [ - + ]: 127 : if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 17191 :UBC 0 : dumpComment(fout, "STATISTICS", qstatsextname,
2254 17192 : 0 : statsextinfo->dobj.namespace->dobj.name,
17193 : 0 : statsextinfo->rolname,
17194 : : statsextinfo->dobj.catId, 0,
2578 alvherre@alvh.no-ip. 17195 : 0 : statsextinfo->dobj.dumpId);
17196 : :
2254 tgl@sss.pgh.pa.us 17197 :CBC 127 : PQclear(res);
2578 alvherre@alvh.no-ip. 17198 : 127 : destroyPQExpBuffer(q);
17199 : 127 : destroyPQExpBuffer(delq);
2254 tgl@sss.pgh.pa.us 17200 : 127 : destroyPQExpBuffer(query);
2239 17201 : 127 : free(qstatsextname);
17202 : : }
17203 : :
17204 : : /*
17205 : : * dumpConstraint
17206 : : * write out to fout a user-defined constraint
17207 : : */
17208 : : static void
1159 peter@eisentraut.org 17209 : 2033 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
17210 : : {
3014 tgl@sss.pgh.pa.us 17211 : 2033 : DumpOptions *dopt = fout->dopt;
7435 17212 : 2033 : TableInfo *tbinfo = coninfo->contable;
17213 : : PQExpBuffer q;
17214 : : PQExpBuffer delq;
2971 peter_e@gmx.net 17215 : 2033 : char *tag = NULL;
17216 : : char *foreign;
17217 : :
17218 : : /* Do nothing in data-only dump */
860 tgl@sss.pgh.pa.us 17219 [ + + ]: 2033 : if (dopt->dataOnly)
7435 17220 : 47 : return;
17221 : :
17222 : 1986 : q = createPQExpBuffer();
17223 : 1986 : delq = createPQExpBuffer();
17224 : :
1486 alvherre@alvh.no-ip. 17225 : 3886 : foreign = tbinfo &&
1431 tgl@sss.pgh.pa.us 17226 [ + + - + ]: 1986 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
17227 : :
5242 17228 [ + + ]: 1986 : if (coninfo->contype == 'p' ||
17229 [ + + ]: 958 : coninfo->contype == 'u' ||
17230 [ + + ]: 826 : coninfo->contype == 'x')
7435 17231 : 1170 : {
17232 : : /* Index-related constraint */
17233 : : IndxInfo *indxinfo;
17234 : : int k;
17235 : :
17236 : 1170 : indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
17237 : :
17238 [ - + ]: 1170 : if (indxinfo == NULL)
737 tgl@sss.pgh.pa.us 17239 :UBC 0 : pg_fatal("missing index for constraint \"%s\"",
17240 : : coninfo->dobj.name);
17241 : :
3470 alvherre@alvh.no-ip. 17242 [ + + ]:CBC 1170 : if (dopt->binary_upgrade)
4450 rhaas@postgresql.org 17243 : 130 : binary_upgrade_set_pg_class_oids(fout, q,
17244 : : indxinfo->dobj.catId.oid, true);
17245 : :
1486 alvherre@alvh.no-ip. 17246 : 1170 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
2239 tgl@sss.pgh.pa.us 17247 : 1170 : fmtQualifiedDumpable(tbinfo));
5242 17248 : 1170 : appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
17249 : 1170 : fmtId(coninfo->dobj.name));
17250 : :
17251 [ + + ]: 1170 : if (coninfo->condef)
17252 : : {
17253 : : /* pg_get_constraintdef should have provided everything */
17254 : 10 : appendPQExpBuffer(q, "%s;\n", coninfo->condef);
17255 : : }
17256 : : else
17257 : : {
586 drowley@postgresql.o 17258 : 1160 : appendPQExpBufferStr(q,
17259 [ + + ]: 1160 : coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
17260 : :
17261 : : /*
17262 : : * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
17263 : : * indexes. Being able to create this was fixed, but we need to
17264 : : * make the index distinct in order to be able to restore the
17265 : : * dump.
17266 : : */
415 dgustafsson@postgres 17267 [ - + - - ]: 1160 : if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
586 drowley@postgresql.o 17268 :UBC 0 : appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
586 drowley@postgresql.o 17269 :CBC 1160 : appendPQExpBufferStr(q, " (");
2199 teodor@sigaev.ru 17270 [ + + ]: 2798 : for (k = 0; k < indxinfo->indnkeyattrs; k++)
17271 : : {
5242 tgl@sss.pgh.pa.us 17272 : 1638 : int indkey = (int) indxinfo->indkeys[k];
17273 : : const char *attname;
17274 : :
17275 [ - + ]: 1638 : if (indkey == InvalidAttrNumber)
5242 tgl@sss.pgh.pa.us 17276 :UBC 0 : break;
5242 tgl@sss.pgh.pa.us 17277 :CBC 1638 : attname = getAttrName(indkey, tbinfo);
17278 : :
17279 [ + + ]: 1638 : appendPQExpBuffer(q, "%s%s",
17280 : : (k == 0) ? "" : ", ",
17281 : : fmtId(attname));
17282 : : }
40 peter@eisentraut.org 17283 [ + + ]:GNC 1160 : if (coninfo->conperiod)
81 17284 : 117 : appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
17285 : :
2199 teodor@sigaev.ru 17286 [ + + ]:CBC 1160 : if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
1746 drowley@postgresql.o 17287 : 20 : appendPQExpBufferStr(q, ") INCLUDE (");
17288 : :
2199 teodor@sigaev.ru 17289 [ + + ]: 1200 : for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
17290 : : {
17291 : 40 : int indkey = (int) indxinfo->indkeys[k];
17292 : : const char *attname;
17293 : :
17294 [ - + ]: 40 : if (indkey == InvalidAttrNumber)
2199 teodor@sigaev.ru 17295 :UBC 0 : break;
2199 teodor@sigaev.ru 17296 :CBC 40 : attname = getAttrName(indkey, tbinfo);
17297 : :
17298 : 80 : appendPQExpBuffer(q, "%s%s",
17299 [ + + ]: 40 : (k == indxinfo->indnkeyattrs) ? "" : ", ",
17300 : : fmtId(attname));
17301 : : }
17302 : :
3800 heikki.linnakangas@i 17303 : 1160 : appendPQExpBufferChar(q, ')');
17304 : :
3025 tgl@sss.pgh.pa.us 17305 [ - + ]: 1160 : if (nonemptyReloptions(indxinfo->indreloptions))
17306 : : {
3025 tgl@sss.pgh.pa.us 17307 :UBC 0 : appendPQExpBufferStr(q, " WITH (");
2900 dean.a.rasheed@gmail 17308 : 0 : appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
3025 tgl@sss.pgh.pa.us 17309 : 0 : appendPQExpBufferChar(q, ')');
17310 : : }
17311 : :
5242 tgl@sss.pgh.pa.us 17312 [ + + ]:CBC 1160 : if (coninfo->condeferrable)
17313 : : {
3800 heikki.linnakangas@i 17314 :GBC 25 : appendPQExpBufferStr(q, " DEFERRABLE");
5242 tgl@sss.pgh.pa.us 17315 [ + + ]: 25 : if (coninfo->condeferred)
3800 heikki.linnakangas@i 17316 : 15 : appendPQExpBufferStr(q, " INITIALLY DEFERRED");
17317 : : }
17318 : :
3800 heikki.linnakangas@i 17319 :CBC 1160 : appendPQExpBufferStr(q, ";\n");
17320 : : }
17321 : :
17322 : : /*
17323 : : * Append ALTER TABLE commands as needed to set properties that we
17324 : : * only have ALTER TABLE syntax for. Keep this in sync with the
17325 : : * similar code in dumpIndex!
17326 : : */
17327 : :
17328 : : /* Drop any not-null constraints that were added to support the PK */
233 alvherre@alvh.no-ip. 17329 [ + + ]:GNC 1170 : if (coninfo->contype == 'p')
17330 [ + + ]: 3909 : for (int i = 0; i < tbinfo->numatts; i++)
17331 [ + + ]: 2881 : if (tbinfo->notnull_throwaway[i])
17332 : 803 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s DROP CONSTRAINT %s;",
17333 : 803 : fmtQualifiedDumpable(tbinfo),
17334 : 803 : tbinfo->notnull_constrs[i]);
17335 : :
17336 : : /* If the index is clustered, we need to record that. */
7435 tgl@sss.pgh.pa.us 17337 [ + + ]:CBC 1170 : if (indxinfo->indisclustered)
17338 : : {
17339 : 36 : appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
2239 17340 : 36 : fmtQualifiedDumpable(tbinfo));
17341 : : /* index name is not qualified in this syntax */
7435 17342 : 36 : appendPQExpBuffer(q, " ON %s;\n",
7347 17343 : 36 : fmtId(indxinfo->dobj.name));
17344 : : }
17345 : :
17346 : : /* If the index defines identity, we need to record that. */
2085 17347 [ - + ]: 1170 : if (indxinfo->indisreplident)
17348 : : {
2085 tgl@sss.pgh.pa.us 17349 :UBC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
17350 : 0 : fmtQualifiedDumpable(tbinfo));
17351 : : /* index name is not qualified in this syntax */
17352 : 0 : appendPQExpBuffer(q, " INDEX %s;\n",
17353 : 0 : fmtId(indxinfo->dobj.name));
17354 : : }
17355 : :
17356 : : /* Indexes can depend on extensions */
1495 alvherre@alvh.no-ip. 17357 :CBC 1170 : append_depends_on_extension(fout, q, &indxinfo->dobj,
17358 : : "pg_catalog.pg_class", "INDEX",
17359 : 1170 : fmtQualifiedDumpable(indxinfo));
17360 : :
1486 17361 : 1170 : appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
2239 tgl@sss.pgh.pa.us 17362 : 1170 : fmtQualifiedDumpable(tbinfo));
7435 17363 : 1170 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
7347 17364 : 1170 : fmtId(coninfo->dobj.name));
17365 : :
2971 peter_e@gmx.net 17366 : 1170 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
17367 : :
2930 sfrost@snowman.net 17368 [ + - ]: 1170 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17369 : 1170 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 17370 : 1170 : ARCHIVE_OPTS(.tag = tag,
17371 : : .namespace = tbinfo->dobj.namespace->dobj.name,
17372 : : .tablespace = indxinfo->tablespace,
17373 : : .owner = tbinfo->rolname,
17374 : : .description = "CONSTRAINT",
17375 : : .section = SECTION_POST_DATA,
17376 : : .createStmt = q->data,
17377 : : .dropStmt = delq->data));
17378 : : }
7435 tgl@sss.pgh.pa.us 17379 [ + + ]: 816 : else if (coninfo->contype == 'f')
17380 : : {
17381 : : char *only;
17382 : :
17383 : : /*
17384 : : * Foreign keys on partitioned tables are always declared as
17385 : : * inheriting to partitions; for all other cases, emit them as
17386 : : * applying ONLY directly to the named table, because that's how they
17387 : : * work for regular inherited tables.
17388 : : */
2202 alvherre@alvh.no-ip. 17389 [ + + ]: 172 : only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
17390 : :
17391 : : /*
17392 : : * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
17393 : : * current table data is not processed
17394 : : */
1486 17395 : 172 : appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
2202 17396 : 172 : only, fmtQualifiedDumpable(tbinfo));
7435 tgl@sss.pgh.pa.us 17397 : 172 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
7347 17398 : 172 : fmtId(coninfo->dobj.name),
7435 17399 : 172 : coninfo->condef);
17400 : :
1486 alvherre@alvh.no-ip. 17401 : 172 : appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
2202 17402 : 172 : only, fmtQualifiedDumpable(tbinfo));
7435 tgl@sss.pgh.pa.us 17403 : 172 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
7347 17404 : 172 : fmtId(coninfo->dobj.name));
17405 : :
2971 peter_e@gmx.net 17406 : 172 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
17407 : :
2930 sfrost@snowman.net 17408 [ + - ]: 172 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17409 : 172 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 17410 : 172 : ARCHIVE_OPTS(.tag = tag,
17411 : : .namespace = tbinfo->dobj.namespace->dobj.name,
17412 : : .owner = tbinfo->rolname,
17413 : : .description = "FK CONSTRAINT",
17414 : : .section = SECTION_POST_DATA,
17415 : : .createStmt = q->data,
17416 : : .dropStmt = delq->data));
17417 : : }
7435 tgl@sss.pgh.pa.us 17418 [ + - + + ]: 644 : else if (coninfo->contype == 'c' && tbinfo)
17419 : : {
17420 : : /* CHECK constraint on a table */
17421 : :
17422 : : /* Ignore if not to be dumped separately, or if it was inherited */
3118 17423 [ + + + + ]: 558 : if (coninfo->separate && coninfo->conislocal)
17424 : : {
17425 : : /* not ONLY since we want it to propagate to children */
1486 alvherre@alvh.no-ip. 17426 : 25 : appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
2239 tgl@sss.pgh.pa.us 17427 : 25 : fmtQualifiedDumpable(tbinfo));
7435 17428 : 25 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
7347 17429 : 25 : fmtId(coninfo->dobj.name),
7435 17430 : 25 : coninfo->condef);
17431 : :
1486 alvherre@alvh.no-ip. 17432 : 25 : appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
2239 tgl@sss.pgh.pa.us 17433 : 25 : fmtQualifiedDumpable(tbinfo));
7435 17434 : 25 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
7347 17435 : 25 : fmtId(coninfo->dobj.name));
17436 : :
2971 peter_e@gmx.net 17437 : 25 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
17438 : :
2930 sfrost@snowman.net 17439 [ + - ]: 25 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17440 : 25 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 17441 : 25 : ARCHIVE_OPTS(.tag = tag,
17442 : : .namespace = tbinfo->dobj.namespace->dobj.name,
17443 : : .owner = tbinfo->rolname,
17444 : : .description = "CHECK CONSTRAINT",
17445 : : .section = SECTION_POST_DATA,
17446 : : .createStmt = q->data,
17447 : : .dropStmt = delq->data));
17448 : : }
17449 : : }
7435 tgl@sss.pgh.pa.us 17450 [ + - + - ]: 86 : else if (coninfo->contype == 'c' && tbinfo == NULL)
17451 : 86 : {
17452 : : /* CHECK constraint on a domain */
5226 bruce@momjian.us 17453 : 86 : TypeInfo *tyinfo = coninfo->condomain;
17454 : :
17455 : : /* Ignore if not to be dumped separately */
6618 tgl@sss.pgh.pa.us 17456 [ - + ]: 86 : if (coninfo->separate)
17457 : : {
7435 tgl@sss.pgh.pa.us 17458 :UBC 0 : appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
2239 17459 : 0 : fmtQualifiedDumpable(tyinfo));
7435 17460 : 0 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
7347 17461 : 0 : fmtId(coninfo->dobj.name),
7435 17462 : 0 : coninfo->condef);
17463 : :
2239 17464 : 0 : appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
17465 : 0 : fmtQualifiedDumpable(tyinfo));
7435 17466 : 0 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
7347 17467 : 0 : fmtId(coninfo->dobj.name));
17468 : :
2971 peter_e@gmx.net 17469 : 0 : tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
17470 : :
2930 sfrost@snowman.net 17471 [ # # ]: 0 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17472 : 0 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 17473 : 0 : ARCHIVE_OPTS(.tag = tag,
17474 : : .namespace = tyinfo->dobj.namespace->dobj.name,
17475 : : .owner = tyinfo->rolname,
17476 : : .description = "CHECK CONSTRAINT",
17477 : : .section = SECTION_POST_DATA,
17478 : : .createStmt = q->data,
17479 : : .dropStmt = delq->data));
17480 : : }
17481 : : }
17482 : : else
17483 : : {
737 tgl@sss.pgh.pa.us 17484 : 0 : pg_fatal("unrecognized constraint type: %c",
17485 : : coninfo->contype);
17486 : : }
17487 : :
17488 : : /* Dump Constraint Comments --- only works for table constraints */
2930 sfrost@snowman.net 17489 [ + + + + ]:CBC 1986 : if (tbinfo && coninfo->separate &&
17490 [ + + ]: 1382 : coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3014 tgl@sss.pgh.pa.us 17491 : 10 : dumpTableConstraintComment(fout, coninfo);
17492 : :
2971 peter_e@gmx.net 17493 : 1986 : free(tag);
8010 tgl@sss.pgh.pa.us 17494 : 1986 : destroyPQExpBuffer(q);
17495 : 1986 : destroyPQExpBuffer(delq);
17496 : : }
17497 : :
17498 : : /*
17499 : : * dumpTableConstraintComment --- dump a constraint's comment if any
17500 : : *
17501 : : * This is split out because we need the function in two different places
17502 : : * depending on whether the constraint is dumped as part of CREATE TABLE
17503 : : * or as a separate ALTER command.
17504 : : */
17505 : : static void
1159 peter@eisentraut.org 17506 : 51 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
17507 : : {
7061 tgl@sss.pgh.pa.us 17508 : 51 : TableInfo *tbinfo = coninfo->contable;
2239 17509 : 51 : PQExpBuffer conprefix = createPQExpBuffer();
17510 : : char *qtabname;
17511 : :
17512 : 51 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17513 : :
17514 : 51 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
7061 17515 : 51 : fmtId(coninfo->dobj.name));
17516 : :
2930 sfrost@snowman.net 17517 [ + - ]: 51 : if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 17518 : 51 : dumpComment(fout, conprefix->data, qtabname,
2930 sfrost@snowman.net 17519 : 51 : tbinfo->dobj.namespace->dobj.name,
17520 : : tbinfo->rolname,
17521 : : coninfo->dobj.catId, 0,
2489 tgl@sss.pgh.pa.us 17522 [ + + ]: 51 : coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
17523 : :
2239 17524 : 51 : destroyPQExpBuffer(conprefix);
17525 : 51 : free(qtabname);
7061 17526 : 51 : }
17527 : :
17528 : : /*
17529 : : * dumpSequence
17530 : : * write the declaration (not data) of one user-defined sequence
17531 : : */
17532 : : static void
1159 peter@eisentraut.org 17533 : 367 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
17534 : : {
3014 tgl@sss.pgh.pa.us 17535 : 367 : DumpOptions *dopt = fout->dopt;
17536 : : PGresult *res;
17537 : : char *startv,
17538 : : *incby,
17539 : : *maxv,
17540 : : *minv,
17541 : : *cache,
17542 : : *seqtype;
17543 : : bool cycled;
17544 : : bool is_ascending;
17545 : : int64 default_minv,
17546 : : default_maxv;
17547 : : char bufm[32],
17548 : : bufx[32];
8768 bruce@momjian.us 17549 : 367 : PQExpBuffer query = createPQExpBuffer();
8685 17550 : 367 : PQExpBuffer delqry = createPQExpBuffer();
17551 : : char *qseqname;
738 peter@eisentraut.org 17552 : 367 : TableInfo *owning_tab = NULL;
17553 : :
2239 tgl@sss.pgh.pa.us 17554 : 367 : qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
17555 : :
2672 peter_e@gmx.net 17556 [ + - ]: 367 : if (fout->remoteVersion >= 100000)
17557 : : {
17558 : 367 : appendPQExpBuffer(query,
17559 : : "SELECT format_type(seqtypid, NULL), "
17560 : : "seqstart, seqincrement, "
17561 : : "seqmax, seqmin, "
17562 : : "seqcache, seqcycle "
17563 : : "FROM pg_catalog.pg_sequence "
17564 : : "WHERE seqrelid = '%u'::oid",
2637 17565 : 367 : tbinfo->dobj.catId.oid);
17566 : : }
17567 : : else
17568 : : {
17569 : : /*
17570 : : * Before PostgreSQL 10, sequence metadata is in the sequence itself.
17571 : : *
17572 : : * Note: it might seem that 'bigint' potentially needs to be
17573 : : * schema-qualified, but actually that's a keyword.
17574 : : */
5812 tgl@sss.pgh.pa.us 17575 :UBC 0 : appendPQExpBuffer(query,
17576 : : "SELECT 'bigint' AS sequence_type, "
17577 : : "start_value, increment_by, max_value, min_value, "
17578 : : "cache_value, is_cycled FROM %s",
2239 17579 : 0 : fmtQualifiedDumpable(tbinfo));
17580 : : }
17581 : :
4450 rhaas@postgresql.org 17582 :CBC 367 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17583 : :
9716 bruce@momjian.us 17584 [ - + ]: 367 : if (PQntuples(res) != 1)
737 tgl@sss.pgh.pa.us 17585 :UBC 0 : pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
17586 : : "query to get data of sequence \"%s\" returned %d rows (expected 1)",
17587 : : PQntuples(res)),
17588 : : tbinfo->dobj.name, PQntuples(res));
17589 : :
2620 peter_e@gmx.net 17590 :CBC 367 : seqtype = PQgetvalue(res, 0, 0);
17591 : 367 : startv = PQgetvalue(res, 0, 1);
17592 : 367 : incby = PQgetvalue(res, 0, 2);
17593 : 367 : maxv = PQgetvalue(res, 0, 3);
17594 : 367 : minv = PQgetvalue(res, 0, 4);
17595 : 367 : cache = PQgetvalue(res, 0, 5);
17596 : 367 : cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
17597 : :
17598 : : /* Calculate default limits for a sequence of this type */
2245 tgl@sss.pgh.pa.us 17599 : 367 : is_ascending = (incby[0] != '-');
2620 peter_e@gmx.net 17600 [ + + ]: 367 : if (strcmp(seqtype, "smallint") == 0)
17601 : : {
2245 tgl@sss.pgh.pa.us 17602 [ + + ]: 25 : default_minv = is_ascending ? 1 : PG_INT16_MIN;
17603 [ + + ]: 25 : default_maxv = is_ascending ? PG_INT16_MAX : -1;
17604 : : }
2620 peter_e@gmx.net 17605 [ + + ]: 342 : else if (strcmp(seqtype, "integer") == 0)
17606 : : {
2245 tgl@sss.pgh.pa.us 17607 [ + + ]: 286 : default_minv = is_ascending ? 1 : PG_INT32_MIN;
17608 [ + + ]: 286 : default_maxv = is_ascending ? PG_INT32_MAX : -1;
17609 : : }
2620 peter_e@gmx.net 17610 [ + - ]: 56 : else if (strcmp(seqtype, "bigint") == 0)
17611 : : {
2245 tgl@sss.pgh.pa.us 17612 [ + + ]: 56 : default_minv = is_ascending ? 1 : PG_INT64_MIN;
17613 [ + + ]: 56 : default_maxv = is_ascending ? PG_INT64_MAX : -1;
17614 : : }
17615 : : else
17616 : : {
737 tgl@sss.pgh.pa.us 17617 :UBC 0 : pg_fatal("unrecognized sequence type: %s", seqtype);
17618 : : default_minv = default_maxv = 0; /* keep compiler quiet */
17619 : : }
17620 : :
17621 : : /*
17622 : : * 64-bit strtol() isn't very portable, so convert the limits to strings
17623 : : * and compare that way.
17624 : : */
2245 tgl@sss.pgh.pa.us 17625 :CBC 367 : snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
17626 : 367 : snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
17627 : :
17628 : : /* Don't print minv/maxv if they match the respective default limit */
17629 [ + + ]: 367 : if (strcmp(minv, bufm) == 0)
17630 : 352 : minv = NULL;
17631 [ + + ]: 367 : if (strcmp(maxv, bufx) == 0)
17632 : 352 : maxv = NULL;
17633 : :
17634 : : /*
17635 : : * Identity sequences are not to be dropped separately.
17636 : : */
2565 peter_e@gmx.net 17637 [ + + ]: 367 : if (!tbinfo->is_identity_sequence)
17638 : : {
2239 tgl@sss.pgh.pa.us 17639 : 236 : appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
17640 : 236 : fmtQualifiedDumpable(tbinfo));
17641 : : }
17642 : :
4188 17643 : 367 : resetPQExpBuffer(query);
17644 : :
3470 alvherre@alvh.no-ip. 17645 [ + + ]: 367 : if (dopt->binary_upgrade)
17646 : : {
4188 tgl@sss.pgh.pa.us 17647 : 58 : binary_upgrade_set_pg_class_oids(fout, query,
17648 : 58 : tbinfo->dobj.catId.oid, false);
17649 : :
17650 : : /*
17651 : : * In older PG versions a sequence will have a pg_type entry, but v14
17652 : : * and up don't use that, so don't attempt to preserve the type OID.
17653 : : */
17654 : : }
17655 : :
2565 peter_e@gmx.net 17656 [ + + ]: 367 : if (tbinfo->is_identity_sequence)
17657 : : {
738 peter@eisentraut.org 17658 : 131 : owning_tab = findTableByOid(tbinfo->owning_tab);
17659 : :
2565 peter_e@gmx.net 17660 : 131 : appendPQExpBuffer(query,
17661 : : "ALTER TABLE %s ",
2239 tgl@sss.pgh.pa.us 17662 : 131 : fmtQualifiedDumpable(owning_tab));
2565 peter_e@gmx.net 17663 : 131 : appendPQExpBuffer(query,
17664 : : "ALTER COLUMN %s ADD GENERATED ",
2489 tgl@sss.pgh.pa.us 17665 : 131 : fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
2565 peter_e@gmx.net 17666 [ + + ]: 131 : if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
1746 drowley@postgresql.o 17667 : 91 : appendPQExpBufferStr(query, "ALWAYS");
2565 peter_e@gmx.net 17668 [ + - ]: 40 : else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
1746 drowley@postgresql.o 17669 : 40 : appendPQExpBufferStr(query, "BY DEFAULT");
2565 peter_e@gmx.net 17670 : 131 : appendPQExpBuffer(query, " AS IDENTITY (\n SEQUENCE NAME %s\n",
2239 tgl@sss.pgh.pa.us 17671 : 131 : fmtQualifiedDumpable(tbinfo));
17672 : : }
17673 : : else
17674 : : {
2565 peter_e@gmx.net 17675 : 236 : appendPQExpBuffer(query,
17676 : : "CREATE %sSEQUENCE %s\n",
738 peter@eisentraut.org 17677 [ + + ]: 236 : tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
17678 : : "UNLOGGED " : "",
2239 tgl@sss.pgh.pa.us 17679 : 236 : fmtQualifiedDumpable(tbinfo));
17680 : :
2565 peter_e@gmx.net 17681 [ + + ]: 236 : if (strcmp(seqtype, "bigint") != 0)
17682 : 190 : appendPQExpBuffer(query, " AS %s\n", seqtype);
17683 : : }
17684 : :
852 tgl@sss.pgh.pa.us 17685 : 367 : appendPQExpBuffer(query, " START WITH %s\n", startv);
17686 : :
4188 17687 : 367 : appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
17688 : :
17689 [ + + ]: 367 : if (minv)
17690 : 15 : appendPQExpBuffer(query, " MINVALUE %s\n", minv);
17691 : : else
3800 heikki.linnakangas@i 17692 : 352 : appendPQExpBufferStr(query, " NO MINVALUE\n");
17693 : :
4188 tgl@sss.pgh.pa.us 17694 [ + + ]: 367 : if (maxv)
17695 : 15 : appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
17696 : : else
3800 heikki.linnakangas@i 17697 : 352 : appendPQExpBufferStr(query, " NO MAXVALUE\n");
17698 : :
4188 tgl@sss.pgh.pa.us 17699 [ + + ]: 367 : appendPQExpBuffer(query,
17700 : : " CACHE %s%s",
17701 : : cache, (cycled ? "\n CYCLE" : ""));
17702 : :
2565 peter_e@gmx.net 17703 [ + + ]: 367 : if (tbinfo->is_identity_sequence)
17704 : : {
17705 : 131 : appendPQExpBufferStr(query, "\n);\n");
738 peter@eisentraut.org 17706 [ - + ]: 131 : if (tbinfo->relpersistence != owning_tab->relpersistence)
738 peter@eisentraut.org 17707 :UBC 0 : appendPQExpBuffer(query,
17708 : : "ALTER SEQUENCE %s SET %s;\n",
17709 : 0 : fmtQualifiedDumpable(tbinfo),
17710 [ # # ]: 0 : tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
17711 : : "UNLOGGED" : "LOGGED");
17712 : : }
17713 : : else
2565 peter_e@gmx.net 17714 :CBC 236 : appendPQExpBufferStr(query, ";\n");
17715 : :
17716 : : /* binary_upgrade: no need to clear TOAST table oid */
17717 : :
3470 alvherre@alvh.no-ip. 17718 [ + + ]: 367 : if (dopt->binary_upgrade)
4188 tgl@sss.pgh.pa.us 17719 : 58 : binary_upgrade_extension_member(query, &tbinfo->dobj,
17720 : : "SEQUENCE", qseqname,
2239 17721 : 58 : tbinfo->dobj.namespace->dobj.name);
17722 : :
2930 sfrost@snowman.net 17723 [ + - ]: 367 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17724 : 367 : ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 17725 : 367 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17726 : : .namespace = tbinfo->dobj.namespace->dobj.name,
17727 : : .owner = tbinfo->rolname,
17728 : : .description = "SEQUENCE",
17729 : : .section = SECTION_PRE_DATA,
17730 : : .createStmt = query->data,
17731 : : .dropStmt = delqry->data));
17732 : :
17733 : : /*
17734 : : * If the sequence is owned by a table column, emit the ALTER for it as a
17735 : : * separate TOC entry immediately following the sequence's own entry. It's
17736 : : * OK to do this rather than using full sorting logic, because the
17737 : : * dependency that tells us it's owned will have forced the table to be
17738 : : * created first. We can't just include the ALTER in the TOC entry
17739 : : * because it will fail if we haven't reassigned the sequence owner to
17740 : : * match the table's owner.
17741 : : *
17742 : : * We need not schema-qualify the table reference because both sequence
17743 : : * and table must be in the same schema.
17744 : : */
2565 peter_e@gmx.net 17745 [ + + + + ]: 367 : if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
17746 : : {
603 drowley@postgresql.o 17747 : 145 : owning_tab = findTableByOid(tbinfo->owning_tab);
17748 : :
2655 sfrost@snowman.net 17749 [ - + ]: 145 : if (owning_tab == NULL)
737 tgl@sss.pgh.pa.us 17750 :UBC 0 : pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
17751 : : tbinfo->owning_tab, tbinfo->dobj.catId.oid);
17752 : :
2655 sfrost@snowman.net 17753 [ + + ]:CBC 145 : if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
17754 : : {
4188 tgl@sss.pgh.pa.us 17755 : 143 : resetPQExpBuffer(query);
17756 : 143 : appendPQExpBuffer(query, "ALTER SEQUENCE %s",
2239 17757 : 143 : fmtQualifiedDumpable(tbinfo));
4188 17758 : 143 : appendPQExpBuffer(query, " OWNED BY %s",
2239 17759 : 143 : fmtQualifiedDumpable(owning_tab));
4188 17760 : 143 : appendPQExpBuffer(query, ".%s;\n",
2489 17761 : 143 : fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17762 : :
2930 sfrost@snowman.net 17763 [ + - ]: 143 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17764 : 143 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 17765 : 143 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17766 : : .namespace = tbinfo->dobj.namespace->dobj.name,
17767 : : .owner = tbinfo->rolname,
17768 : : .description = "SEQUENCE OWNED BY",
17769 : : .section = SECTION_PRE_DATA,
17770 : : .createStmt = query->data,
17771 : : .deps = &(tbinfo->dobj.dumpId),
17772 : : .nDeps = 1));
17773 : : }
17774 : : }
17775 : :
17776 : : /* Dump Sequence Comments and Security Labels */
2930 sfrost@snowman.net 17777 [ - + ]: 367 : if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 17778 :UBC 0 : dumpComment(fout, "SEQUENCE", qseqname,
2930 sfrost@snowman.net 17779 : 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17780 : 0 : tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17781 : :
2930 sfrost@snowman.net 17782 [ - + ]:CBC 367 : if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2239 tgl@sss.pgh.pa.us 17783 :UBC 0 : dumpSecLabel(fout, "SEQUENCE", qseqname,
2930 sfrost@snowman.net 17784 : 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17785 : 0 : tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17786 : :
8277 tgl@sss.pgh.pa.us 17787 :CBC 367 : PQclear(res);
17788 : :
8290 17789 : 367 : destroyPQExpBuffer(query);
17790 : 367 : destroyPQExpBuffer(delqry);
2239 17791 : 367 : free(qseqname);
9874 vadim4o@yahoo.com 17792 : 367 : }
17793 : :
17794 : : /*
17795 : : * dumpSequenceData
17796 : : * write the data of one user-defined sequence
17797 : : */
17798 : : static void
1159 peter@eisentraut.org 17799 : 385 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
17800 : : {
4188 tgl@sss.pgh.pa.us 17801 : 385 : TableInfo *tbinfo = tdinfo->tdtable;
17802 : : PGresult *res;
17803 : : char *last;
17804 : : bool called;
17805 : 385 : PQExpBuffer query = createPQExpBuffer();
17806 : :
17807 : 385 : appendPQExpBuffer(query,
17808 : : "SELECT last_value, is_called FROM %s",
2239 17809 : 385 : fmtQualifiedDumpable(tbinfo));
17810 : :
4188 17811 : 385 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17812 : :
17813 [ - + ]: 385 : if (PQntuples(res) != 1)
737 tgl@sss.pgh.pa.us 17814 :UBC 0 : pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
17815 : : "query to get data of sequence \"%s\" returned %d rows (expected 1)",
17816 : : PQntuples(res)),
17817 : : tbinfo->dobj.name, PQntuples(res));
17818 : :
4188 tgl@sss.pgh.pa.us 17819 :CBC 385 : last = PQgetvalue(res, 0, 0);
17820 : 385 : called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
17821 : :
17822 : 385 : resetPQExpBuffer(query);
3800 heikki.linnakangas@i 17823 : 385 : appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
2239 tgl@sss.pgh.pa.us 17824 : 385 : appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
4188 17825 [ + + ]: 385 : appendPQExpBuffer(query, ", %s, %s);\n",
17826 : : last, (called ? "true" : "false"));
17827 : :
2642 sfrost@snowman.net 17828 [ + - ]: 385 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2930 17829 : 385 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
1899 alvherre@alvh.no-ip. 17830 : 385 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17831 : : .namespace = tbinfo->dobj.namespace->dobj.name,
17832 : : .owner = tbinfo->rolname,
17833 : : .description = "SEQUENCE SET",
17834 : : .section = SECTION_DATA,
17835 : : .createStmt = query->data,
17836 : : .deps = &(tbinfo->dobj.dumpId),
17837 : : .nDeps = 1));
17838 : :
4188 tgl@sss.pgh.pa.us 17839 : 385 : PQclear(res);
17840 : :
17841 : 385 : destroyPQExpBuffer(query);
17842 : 385 : }
17843 : :
17844 : : /*
17845 : : * dumpTrigger
17846 : : * write the declaration of one user-defined table trigger
17847 : : */
17848 : : static void
1159 peter@eisentraut.org 17849 : 508 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
17850 : : {
3014 tgl@sss.pgh.pa.us 17851 : 508 : DumpOptions *dopt = fout->dopt;
7435 17852 : 508 : TableInfo *tbinfo = tginfo->tgtable;
17853 : : PQExpBuffer query;
17854 : : PQExpBuffer delqry;
17855 : : PQExpBuffer trigprefix;
17856 : : PQExpBuffer trigidentity;
17857 : : char *qtabname;
17858 : : char *tag;
17859 : :
17860 : : /* Do nothing in data-only dump */
3470 alvherre@alvh.no-ip. 17861 [ + + ]: 508 : if (dopt->dataOnly)
7912 tgl@sss.pgh.pa.us 17862 : 16 : return;
17863 : :
7435 17864 : 492 : query = createPQExpBuffer();
17865 : 492 : delqry = createPQExpBuffer();
2239 17866 : 492 : trigprefix = createPQExpBuffer();
1495 alvherre@alvh.no-ip. 17867 : 492 : trigidentity = createPQExpBuffer();
17868 : :
2239 tgl@sss.pgh.pa.us 17869 : 492 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17870 : :
1495 alvherre@alvh.no-ip. 17871 : 492 : appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
17872 : 492 : appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
17873 : :
91 peter@eisentraut.org 17874 :GNC 492 : appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
1495 alvherre@alvh.no-ip. 17875 :CBC 492 : appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
17876 : :
17877 : : /* Triggers can depend on extensions */
17878 : 492 : append_depends_on_extension(fout, query, &tginfo->dobj,
17879 : : "pg_catalog.pg_trigger", "TRIGGER",
17880 : 492 : trigidentity->data);
17881 : :
830 17882 [ + + ]: 492 : if (tginfo->tgispartition)
17883 : : {
17884 [ - + ]: 121 : Assert(tbinfo->ispartition);
17885 : :
17886 : : /*
17887 : : * Partition triggers only appear here because their 'tgenabled' flag
17888 : : * differs from its parent's. The trigger is created already, so
17889 : : * remove the CREATE and replace it with an ALTER. (Clear out the
17890 : : * DROP query too, so that pg_dump --create does not cause errors.)
17891 : : */
1003 17892 : 121 : resetPQExpBuffer(query);
17893 : 121 : resetPQExpBuffer(delqry);
1003 alvherre@alvh.no-ip. 17894 :UBC 0 : appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
1003 alvherre@alvh.no-ip. 17895 [ - + ]:CBC 121 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
17896 : 121 : fmtQualifiedDumpable(tbinfo));
17897 [ + - + + : 121 : switch (tginfo->tgenabled)
- ]
17898 : : {
17899 : 42 : case 'f':
17900 : : case 'D':
17901 : 42 : appendPQExpBufferStr(query, "DISABLE");
17902 : 42 : break;
1003 alvherre@alvh.no-ip. 17903 :UBC 0 : case 't':
17904 : : case 'O':
17905 : 0 : appendPQExpBufferStr(query, "ENABLE");
17906 : 0 : break;
1003 alvherre@alvh.no-ip. 17907 :CBC 37 : case 'R':
17908 : 37 : appendPQExpBufferStr(query, "ENABLE REPLICA");
17909 : 37 : break;
17910 : 42 : case 'A':
17911 : 42 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
17912 : 42 : break;
17913 : : }
17914 : 121 : appendPQExpBuffer(query, " TRIGGER %s;\n",
17915 : 121 : fmtId(tginfo->dobj.name));
17916 : : }
17917 [ + - - + ]: 371 : else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17918 : : {
1486 alvherre@alvh.no-ip. 17919 :UBC 0 : appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
17920 [ # # ]: 0 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
2239 tgl@sss.pgh.pa.us 17921 : 0 : fmtQualifiedDumpable(tbinfo));
6236 JanWieck@Yahoo.com 17922 [ # # # # ]: 0 : switch (tginfo->tgenabled)
17923 : : {
17924 : 0 : case 'D':
17925 : : case 'f':
3800 heikki.linnakangas@i 17926 : 0 : appendPQExpBufferStr(query, "DISABLE");
6236 JanWieck@Yahoo.com 17927 : 0 : break;
17928 : 0 : case 'A':
3800 heikki.linnakangas@i 17929 : 0 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
6236 JanWieck@Yahoo.com 17930 : 0 : break;
17931 : 0 : case 'R':
3800 heikki.linnakangas@i 17932 : 0 : appendPQExpBufferStr(query, "ENABLE REPLICA");
6236 JanWieck@Yahoo.com 17933 : 0 : break;
17934 : 0 : default:
3800 heikki.linnakangas@i 17935 : 0 : appendPQExpBufferStr(query, "ENABLE");
6236 JanWieck@Yahoo.com 17936 : 0 : break;
17937 : : }
17938 : 0 : appendPQExpBuffer(query, " TRIGGER %s;\n",
6809 tgl@sss.pgh.pa.us 17939 : 0 : fmtId(tginfo->dobj.name));
17940 : : }
17941 : :
2239 tgl@sss.pgh.pa.us 17942 :CBC 492 : appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
4813 17943 : 492 : fmtId(tginfo->dobj.name));
17944 : :
2971 peter_e@gmx.net 17945 : 492 : tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17946 : :
2930 sfrost@snowman.net 17947 [ + - ]: 492 : if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17948 : 492 : ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 17949 : 492 : ARCHIVE_OPTS(.tag = tag,
17950 : : .namespace = tbinfo->dobj.namespace->dobj.name,
17951 : : .owner = tbinfo->rolname,
17952 : : .description = "TRIGGER",
17953 : : .section = SECTION_POST_DATA,
17954 : : .createStmt = query->data,
17955 : : .dropStmt = delqry->data));
17956 : :
2930 sfrost@snowman.net 17957 [ - + ]: 492 : if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 17958 :UBC 0 : dumpComment(fout, trigprefix->data, qtabname,
2930 sfrost@snowman.net 17959 : 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17960 : 0 : tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17961 : :
2971 peter_e@gmx.net 17962 :CBC 492 : free(tag);
7435 tgl@sss.pgh.pa.us 17963 : 492 : destroyPQExpBuffer(query);
17964 : 492 : destroyPQExpBuffer(delqry);
2239 17965 : 492 : destroyPQExpBuffer(trigprefix);
1495 alvherre@alvh.no-ip. 17966 : 492 : destroyPQExpBuffer(trigidentity);
2239 tgl@sss.pgh.pa.us 17967 : 492 : free(qtabname);
17968 : : }
17969 : :
17970 : : /*
17971 : : * dumpEventTrigger
17972 : : * write the declaration of one user-defined event trigger
17973 : : */
17974 : : static void
1159 peter@eisentraut.org 17975 : 43 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
17976 : : {
3014 tgl@sss.pgh.pa.us 17977 : 43 : DumpOptions *dopt = fout->dopt;
17978 : : PQExpBuffer query;
17979 : : PQExpBuffer delqry;
17980 : : char *qevtname;
17981 : :
17982 : : /* Do nothing in data-only dump */
860 17983 [ + + ]: 43 : if (dopt->dataOnly)
3758 17984 : 3 : return;
17985 : :
4288 rhaas@postgresql.org 17986 : 40 : query = createPQExpBuffer();
2458 tgl@sss.pgh.pa.us 17987 : 40 : delqry = createPQExpBuffer();
17988 : :
2239 17989 : 40 : qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17990 : :
3800 heikki.linnakangas@i 17991 : 40 : appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
2239 tgl@sss.pgh.pa.us 17992 : 40 : appendPQExpBufferStr(query, qevtname);
3800 heikki.linnakangas@i 17993 : 40 : appendPQExpBufferStr(query, " ON ");
4288 rhaas@postgresql.org 17994 : 40 : appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17995 : :
17996 [ + + ]: 40 : if (strcmp("", evtinfo->evttags) != 0)
17997 : : {
4288 rhaas@postgresql.org 17998 :GBC 5 : appendPQExpBufferStr(query, "\n WHEN TAG IN (");
17999 : 5 : appendPQExpBufferStr(query, evtinfo->evttags);
3209 heikki.linnakangas@i 18000 : 5 : appendPQExpBufferChar(query, ')');
18001 : : }
18002 : :
1893 peter@eisentraut.org 18003 :CBC 40 : appendPQExpBufferStr(query, "\n EXECUTE FUNCTION ");
4288 rhaas@postgresql.org 18004 : 40 : appendPQExpBufferStr(query, evtinfo->evtfname);
3800 heikki.linnakangas@i 18005 : 40 : appendPQExpBufferStr(query, "();\n");
18006 : :
4288 rhaas@postgresql.org 18007 [ - + ]: 40 : if (evtinfo->evtenabled != 'O')
18008 : : {
4288 rhaas@postgresql.org 18009 :UBC 0 : appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
18010 : : qevtname);
18011 [ # # # # ]: 0 : switch (evtinfo->evtenabled)
18012 : : {
18013 : 0 : case 'D':
3800 heikki.linnakangas@i 18014 : 0 : appendPQExpBufferStr(query, "DISABLE");
4288 rhaas@postgresql.org 18015 : 0 : break;
18016 : 0 : case 'A':
3800 heikki.linnakangas@i 18017 : 0 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
4288 rhaas@postgresql.org 18018 : 0 : break;
18019 : 0 : case 'R':
3800 heikki.linnakangas@i 18020 : 0 : appendPQExpBufferStr(query, "ENABLE REPLICA");
4288 rhaas@postgresql.org 18021 : 0 : break;
18022 : 0 : default:
3800 heikki.linnakangas@i 18023 : 0 : appendPQExpBufferStr(query, "ENABLE");
4288 rhaas@postgresql.org 18024 : 0 : break;
18025 : : }
3800 heikki.linnakangas@i 18026 : 0 : appendPQExpBufferStr(query, ";\n");
18027 : : }
18028 : :
2458 tgl@sss.pgh.pa.us 18029 :CBC 40 : appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
18030 : : qevtname);
18031 : :
2077 18032 [ + + ]: 40 : if (dopt->binary_upgrade)
18033 : 2 : binary_upgrade_extension_member(query, &evtinfo->dobj,
18034 : : "EVENT TRIGGER", qevtname, NULL);
18035 : :
2930 sfrost@snowman.net 18036 [ + - ]: 40 : if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18037 : 40 : ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 18038 : 40 : ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
18039 : : .owner = evtinfo->evtowner,
18040 : : .description = "EVENT TRIGGER",
18041 : : .section = SECTION_POST_DATA,
18042 : : .createStmt = query->data,
18043 : : .dropStmt = delqry->data));
18044 : :
2930 sfrost@snowman.net 18045 [ - + ]: 40 : if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 18046 :UBC 0 : dumpComment(fout, "EVENT TRIGGER", qevtname,
2930 sfrost@snowman.net 18047 : 0 : NULL, evtinfo->evtowner,
18048 : 0 : evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
18049 : :
4288 rhaas@postgresql.org 18050 :CBC 40 : destroyPQExpBuffer(query);
2458 tgl@sss.pgh.pa.us 18051 : 40 : destroyPQExpBuffer(delqry);
2239 18052 : 40 : free(qevtname);
18053 : : }
18054 : :
18055 : : /*
18056 : : * dumpRule
18057 : : * Dump a rule
18058 : : */
18059 : : static void
1159 peter@eisentraut.org 18060 : 940 : dumpRule(Archive *fout, const RuleInfo *rinfo)
18061 : : {
3014 tgl@sss.pgh.pa.us 18062 : 940 : DumpOptions *dopt = fout->dopt;
7435 18063 : 940 : TableInfo *tbinfo = rinfo->ruletable;
18064 : : bool is_view;
18065 : : PQExpBuffer query;
18066 : : PQExpBuffer cmd;
18067 : : PQExpBuffer delcmd;
18068 : : PQExpBuffer ruleprefix;
18069 : : char *qtabname;
18070 : : PGresult *res;
18071 : : char *tag;
18072 : :
18073 : : /* Do nothing in data-only dump */
860 18074 [ + + ]: 940 : if (dopt->dataOnly)
7435 18075 : 30 : return;
18076 : :
18077 : : /*
18078 : : * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
18079 : : * we do not want to dump it as a separate object.
18080 : : */
7061 18081 [ + + ]: 910 : if (!rinfo->separate)
7435 18082 : 703 : return;
18083 : :
18084 : : /*
18085 : : * If it's an ON SELECT rule, we want to print it as a view definition,
18086 : : * instead of a rule.
18087 : : */
2705 18088 [ + + + - ]: 207 : is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
18089 : :
7435 18090 : 207 : query = createPQExpBuffer();
18091 : 207 : cmd = createPQExpBuffer();
18092 : 207 : delcmd = createPQExpBuffer();
2239 18093 : 207 : ruleprefix = createPQExpBuffer();
18094 : :
18095 : 207 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
18096 : :
2705 18097 [ + + ]: 207 : if (is_view)
18098 : : {
18099 : : PQExpBuffer result;
18100 : :
18101 : : /*
18102 : : * We need OR REPLACE here because we'll be replacing a dummy view.
18103 : : * Otherwise this should look largely like the regular view dump code.
18104 : : */
18105 : 10 : appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
2239 18106 : 10 : fmtQualifiedDumpable(tbinfo));
2705 18107 [ - + ]: 10 : if (nonemptyReloptions(tbinfo->reloptions))
18108 : : {
2705 tgl@sss.pgh.pa.us 18109 :UBC 0 : appendPQExpBufferStr(cmd, " WITH (");
18110 : 0 : appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
18111 : 0 : appendPQExpBufferChar(cmd, ')');
18112 : : }
2705 tgl@sss.pgh.pa.us 18113 :CBC 10 : result = createViewAsClause(fout, tbinfo);
18114 : 10 : appendPQExpBuffer(cmd, " AS\n%s", result->data);
18115 : 10 : destroyPQExpBuffer(result);
18116 [ - + ]: 10 : if (tbinfo->checkoption != NULL)
2705 tgl@sss.pgh.pa.us 18117 :UBC 0 : appendPQExpBuffer(cmd, "\n WITH %s CHECK OPTION",
18118 : : tbinfo->checkoption);
2705 tgl@sss.pgh.pa.us 18119 :CBC 10 : appendPQExpBufferStr(cmd, ";\n");
18120 : : }
18121 : : else
18122 : : {
18123 : : /* In the rule case, just print pg_get_ruledef's result verbatim */
18124 : 197 : appendPQExpBuffer(query,
18125 : : "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
18126 : 197 : rinfo->dobj.catId.oid);
18127 : :
18128 : 197 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18129 : :
18130 [ - + ]: 197 : if (PQntuples(res) != 1)
737 tgl@sss.pgh.pa.us 18131 :UBC 0 : pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
18132 : : rinfo->dobj.name, tbinfo->dobj.name);
18133 : :
2705 tgl@sss.pgh.pa.us 18134 :CBC 197 : printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
18135 : :
18136 : 197 : PQclear(res);
18137 : : }
18138 : :
18139 : : /*
18140 : : * Add the command to alter the rules replication firing semantics if it
18141 : : * differs from the default.
18142 : : */
6236 JanWieck@Yahoo.com 18143 [ + + ]: 207 : if (rinfo->ev_enabled != 'O')
18144 : : {
2239 tgl@sss.pgh.pa.us 18145 :GBC 15 : appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
6236 JanWieck@Yahoo.com 18146 [ - - + - ]: 15 : switch (rinfo->ev_enabled)
18147 : : {
6236 JanWieck@Yahoo.com 18148 :UBC 0 : case 'A':
18149 : 0 : appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
5995 bruce@momjian.us 18150 : 0 : fmtId(rinfo->dobj.name));
6236 JanWieck@Yahoo.com 18151 : 0 : break;
18152 : 0 : case 'R':
18153 : 0 : appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
5995 bruce@momjian.us 18154 : 0 : fmtId(rinfo->dobj.name));
6236 JanWieck@Yahoo.com 18155 : 0 : break;
6236 JanWieck@Yahoo.com 18156 :GBC 15 : case 'D':
18157 : 15 : appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
5995 bruce@momjian.us 18158 : 15 : fmtId(rinfo->dobj.name));
6236 JanWieck@Yahoo.com 18159 : 15 : break;
18160 : : }
18161 : : }
18162 : :
2705 tgl@sss.pgh.pa.us 18163 [ + + ]:CBC 207 : if (is_view)
18164 : : {
18165 : : /*
18166 : : * We can't DROP a view's ON SELECT rule. Instead, use CREATE OR
18167 : : * REPLACE VIEW to replace the rule with something with minimal
18168 : : * dependencies.
18169 : : */
18170 : : PQExpBuffer result;
18171 : :
2239 18172 : 10 : appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
18173 : 10 : fmtQualifiedDumpable(tbinfo));
2705 18174 : 10 : result = createDummyViewAsClause(fout, tbinfo);
18175 : 10 : appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
18176 : 10 : destroyPQExpBuffer(result);
18177 : : }
18178 : : else
18179 : : {
18180 : 197 : appendPQExpBuffer(delcmd, "DROP RULE %s ",
18181 : 197 : fmtId(rinfo->dobj.name));
2239 18182 : 197 : appendPQExpBuffer(delcmd, "ON %s;\n",
18183 : 197 : fmtQualifiedDumpable(tbinfo));
18184 : : }
18185 : :
18186 : 207 : appendPQExpBuffer(ruleprefix, "RULE %s ON",
4813 18187 : 207 : fmtId(rinfo->dobj.name));
18188 : :
2971 peter_e@gmx.net 18189 : 207 : tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
18190 : :
2930 sfrost@snowman.net 18191 [ + - ]: 207 : if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18192 : 207 : ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
1899 alvherre@alvh.no-ip. 18193 : 207 : ARCHIVE_OPTS(.tag = tag,
18194 : : .namespace = tbinfo->dobj.namespace->dobj.name,
18195 : : .owner = tbinfo->rolname,
18196 : : .description = "RULE",
18197 : : .section = SECTION_POST_DATA,
18198 : : .createStmt = cmd->data,
18199 : : .dropStmt = delcmd->data));
18200 : :
18201 : : /* Dump rule comments */
2930 sfrost@snowman.net 18202 [ - + ]: 207 : if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2239 tgl@sss.pgh.pa.us 18203 :UBC 0 : dumpComment(fout, ruleprefix->data, qtabname,
2930 sfrost@snowman.net 18204 : 0 : tbinfo->dobj.namespace->dobj.name,
18205 : : tbinfo->rolname,
18206 : 0 : rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
18207 : :
2971 peter_e@gmx.net 18208 :CBC 207 : free(tag);
8010 tgl@sss.pgh.pa.us 18209 : 207 : destroyPQExpBuffer(query);
7435 18210 : 207 : destroyPQExpBuffer(cmd);
18211 : 207 : destroyPQExpBuffer(delcmd);
2239 18212 : 207 : destroyPQExpBuffer(ruleprefix);
18213 : 207 : free(qtabname);
18214 : : }
18215 : :
18216 : : /*
18217 : : * getExtensionMembership --- obtain extension membership data
18218 : : *
18219 : : * We need to identify objects that are extension members as soon as they're
18220 : : * loaded, so that we can correctly determine whether they need to be dumped.
18221 : : * Generally speaking, extension member objects will get marked as *not* to
18222 : : * be dumped, as they will be recreated by the single CREATE EXTENSION
18223 : : * command. However, in binary upgrade mode we still need to dump the members
18224 : : * individually.
18225 : : */
18226 : : void
3014 18227 : 156 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
18228 : : int numExtensions)
18229 : : {
18230 : : PQExpBuffer query;
18231 : : PGresult *res;
18232 : : int ntups,
18233 : : i;
18234 : : int i_classid,
18235 : : i_objid,
18236 : : i_refobjid;
18237 : : ExtensionInfo *ext;
18238 : :
18239 : : /* Nothing to do if no extensions */
4813 18240 [ - + ]: 156 : if (numExtensions == 0)
4813 tgl@sss.pgh.pa.us 18241 :UBC 0 : return;
18242 : :
4813 tgl@sss.pgh.pa.us 18243 :CBC 156 : query = createPQExpBuffer();
18244 : :
18245 : : /* refclassid constraint is redundant but may speed the search */
3800 heikki.linnakangas@i 18246 : 156 : appendPQExpBufferStr(query, "SELECT "
18247 : : "classid, objid, refobjid "
18248 : : "FROM pg_depend "
18249 : : "WHERE refclassid = 'pg_extension'::regclass "
18250 : : "AND deptype = 'e' "
18251 : : "ORDER BY 3");
18252 : :
4450 rhaas@postgresql.org 18253 : 156 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18254 : :
4813 tgl@sss.pgh.pa.us 18255 : 156 : ntups = PQntuples(res);
18256 : :
18257 : 156 : i_classid = PQfnumber(res, "classid");
18258 : 156 : i_objid = PQfnumber(res, "objid");
18259 : 156 : i_refobjid = PQfnumber(res, "refobjid");
18260 : :
18261 : : /*
18262 : : * Since we ordered the SELECT by referenced ID, we can expect that
18263 : : * multiple entries for the same extension will appear together; this
18264 : : * saves on searches.
18265 : : */
3014 18266 : 156 : ext = NULL;
18267 : :
4813 18268 [ + + ]: 1380 : for (i = 0; i < ntups; i++)
18269 : : {
18270 : : CatalogId objId;
18271 : : Oid extId;
18272 : :
18273 : 1224 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
18274 : 1224 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
3014 18275 : 1224 : extId = atooid(PQgetvalue(res, i, i_refobjid));
18276 : :
18277 [ + + ]: 1224 : if (ext == NULL ||
18278 [ + + ]: 1068 : ext->dobj.catId.oid != extId)
18279 : 181 : ext = findExtensionByOid(extId);
18280 : :
18281 [ - + ]: 1224 : if (ext == NULL)
18282 : : {
18283 : : /* shouldn't happen */
1840 peter@eisentraut.org 18284 :UBC 0 : pg_log_warning("could not find referenced extension %u", extId);
4813 tgl@sss.pgh.pa.us 18285 : 0 : continue;
18286 : : }
18287 : :
905 tgl@sss.pgh.pa.us 18288 :CBC 1224 : recordExtensionMembership(objId, ext);
18289 : : }
18290 : :
3014 18291 : 156 : PQclear(res);
18292 : :
18293 : 156 : destroyPQExpBuffer(query);
18294 : : }
18295 : :
18296 : : /*
18297 : : * processExtensionTables --- deal with extension configuration tables
18298 : : *
18299 : : * There are two parts to this process:
18300 : : *
18301 : : * 1. Identify and create dump records for extension configuration tables.
18302 : : *
18303 : : * Extensions can mark tables as "configuration", which means that the user
18304 : : * is able and expected to modify those tables after the extension has been
18305 : : * loaded. For these tables, we dump out only the data- the structure is
18306 : : * expected to be handled at CREATE EXTENSION time, including any indexes or
18307 : : * foreign keys, which brings us to-
18308 : : *
18309 : : * 2. Record FK dependencies between configuration tables.
18310 : : *
18311 : : * Due to the FKs being created at CREATE EXTENSION time and therefore before
18312 : : * the data is loaded, we have to work out what the best order for reloading
18313 : : * the data is, to avoid FK violations when the tables are restored. This is
18314 : : * not perfect- we can't handle circular dependencies and if any exist they
18315 : : * will cause an invalid dump to be produced (though at least all of the data
18316 : : * is included for a user to manually restore). This is currently documented
18317 : : * but perhaps we can provide a better solution in the future.
18318 : : */
18319 : : void
18320 : 155 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
18321 : : int numExtensions)
18322 : : {
18323 : 155 : DumpOptions *dopt = fout->dopt;
18324 : : PQExpBuffer query;
18325 : : PGresult *res;
18326 : : int ntups,
18327 : : i;
18328 : : int i_conrelid,
18329 : : i_confrelid;
18330 : :
18331 : : /* Nothing to do if no extensions */
18332 [ - + ]: 155 : if (numExtensions == 0)
3014 tgl@sss.pgh.pa.us 18333 :UBC 0 : return;
18334 : :
18335 : : /*
18336 : : * Identify extension configuration tables and create TableDataInfo
18337 : : * objects for them, ensuring their data will be dumped even though the
18338 : : * tables themselves won't be.
18339 : : *
18340 : : * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
18341 : : * user data in a configuration table is treated like schema data. This
18342 : : * seems appropriate since system data in a config table would get
18343 : : * reloaded by CREATE EXTENSION. If the extension is not listed in the
18344 : : * list of extensions to be included, none of its data is dumped.
18345 : : */
4813 tgl@sss.pgh.pa.us 18346 [ + + ]:CBC 335 : for (i = 0; i < numExtensions; i++)
18347 : : {
4447 18348 : 180 : ExtensionInfo *curext = &(extinfo[i]);
18349 : 180 : char *extconfig = curext->extconfig;
18350 : 180 : char *extcondition = curext->extcondition;
4753 bruce@momjian.us 18351 : 180 : char **extconfigarray = NULL;
18352 : 180 : char **extconditionarray = NULL;
1242 michael@paquier.xyz 18353 : 180 : int nconfigitems = 0;
18354 : 180 : int nconditionitems = 0;
18355 : :
18356 : : /*
18357 : : * Check if this extension is listed as to include in the dump. If
18358 : : * not, any table data associated with it is discarded.
18359 : : */
1095 18360 [ + + ]: 180 : if (extension_include_oids.head != NULL &&
18361 [ + + ]: 8 : !simple_oid_list_member(&extension_include_oids,
18362 : : curext->dobj.catId.oid))
18363 : 6 : continue;
18364 : :
18365 : : /*
18366 : : * Check if this extension is listed as to exclude in the dump. If
18367 : : * yes, any table data associated with it is discarded.
18368 : : */
25 dean.a.rasheed@gmail 18369 [ + + + + ]:GNC 180 : if (extension_exclude_oids.head != NULL &&
18370 : 4 : simple_oid_list_member(&extension_exclude_oids,
18371 : : curext->dobj.catId.oid))
18372 : 2 : continue;
18373 : :
1242 michael@paquier.xyz 18374 [ + + - + ]:CBC 174 : if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
18375 : : {
18376 : : int j;
18377 : :
18378 [ - + ]: 20 : if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
737 tgl@sss.pgh.pa.us 18379 :UBC 0 : pg_fatal("could not parse %s array", "extconfig");
1242 michael@paquier.xyz 18380 [ - + ]:CBC 20 : if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
737 tgl@sss.pgh.pa.us 18381 :UBC 0 : pg_fatal("could not parse %s array", "extcondition");
1242 michael@paquier.xyz 18382 [ - + ]:CBC 20 : if (nconfigitems != nconditionitems)
737 tgl@sss.pgh.pa.us 18383 :UBC 0 : pg_fatal("mismatched number of configurations and conditions for extension");
18384 : :
4813 tgl@sss.pgh.pa.us 18385 [ + + ]:CBC 60 : for (j = 0; j < nconfigitems; j++)
18386 : : {
18387 : : TableInfo *configtbl;
4006 mail@joeconway.com 18388 : 40 : Oid configtbloid = atooid(extconfigarray[j]);
2930 sfrost@snowman.net 18389 : 40 : bool dumpobj =
331 tgl@sss.pgh.pa.us 18390 : 40 : curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
18391 : :
4006 mail@joeconway.com 18392 : 40 : configtbl = findTableByOid(configtbloid);
4449 tgl@sss.pgh.pa.us 18393 [ - + ]: 40 : if (configtbl == NULL)
4449 tgl@sss.pgh.pa.us 18394 :UBC 0 : continue;
18395 : :
18396 : : /*
18397 : : * Tables of not-to-be-dumped extensions shouldn't be dumped
18398 : : * unless the table or its schema is explicitly included
18399 : : */
2930 sfrost@snowman.net 18400 [ + + ]:CBC 40 : if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
18401 : : {
18402 : : /* check table explicitly requested */
4006 mail@joeconway.com 18403 [ - + - - ]: 2 : if (table_include_oids.head != NULL &&
4006 mail@joeconway.com 18404 :UBC 0 : simple_oid_list_member(&table_include_oids,
18405 : : configtbloid))
18406 : 0 : dumpobj = true;
18407 : :
18408 : : /* check table's schema explicitly requested */
2930 sfrost@snowman.net 18409 [ + - ]:CBC 2 : if (configtbl->dobj.namespace->dobj.dump &
18410 : : DUMP_COMPONENT_DATA)
4006 mail@joeconway.com 18411 : 2 : dumpobj = true;
18412 : : }
18413 : :
18414 : : /* check table excluded by an exclusion switch */
18415 [ + + + + ]: 44 : if (table_exclude_oids.head != NULL &&
18416 : 4 : simple_oid_list_member(&table_exclude_oids,
18417 : : configtbloid))
18418 : 1 : dumpobj = false;
18419 : :
18420 : : /* check schema excluded by an exclusion switch */
18421 [ - + ]: 40 : if (simple_oid_list_member(&schema_exclude_oids,
2489 tgl@sss.pgh.pa.us 18422 : 40 : configtbl->dobj.namespace->dobj.catId.oid))
4006 mail@joeconway.com 18423 :UBC 0 : dumpobj = false;
18424 : :
4006 mail@joeconway.com 18425 [ + + ]:CBC 40 : if (dumpobj)
18426 : : {
1972 andres@anarazel.de 18427 : 39 : makeTableDataInfo(dopt, configtbl);
4006 mail@joeconway.com 18428 [ + - ]: 39 : if (configtbl->dataObj != NULL)
18429 : : {
18430 [ - + ]: 39 : if (strlen(extconditionarray[j]) > 0)
4006 mail@joeconway.com 18431 :UBC 0 : configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
18432 : : }
18433 : : }
18434 : : }
18435 : : }
4813 tgl@sss.pgh.pa.us 18436 [ + + ]:CBC 174 : if (extconfigarray)
18437 : 20 : free(extconfigarray);
18438 [ + + ]: 174 : if (extconditionarray)
18439 : 20 : free(extconditionarray);
18440 : : }
18441 : :
18442 : : /*
18443 : : * Now that all the TableDataInfo objects have been created for all the
18444 : : * extensions, check their FK dependencies and register them to try and
18445 : : * dump the data out in an order that they can be restored in.
18446 : : *
18447 : : * Note that this is not a problem for user tables as their FKs are
18448 : : * recreated after the data has been loaded.
18449 : : */
18450 : :
3014 18451 : 155 : query = createPQExpBuffer();
18452 : :
3331 sfrost@snowman.net 18453 : 155 : printfPQExpBuffer(query,
18454 : : "SELECT conrelid, confrelid "
18455 : : "FROM pg_constraint "
18456 : : "JOIN pg_depend ON (objid = confrelid) "
18457 : : "WHERE contype = 'f' "
18458 : : "AND refclassid = 'pg_extension'::regclass "
18459 : : "AND classid = 'pg_class'::regclass;");
18460 : :
18461 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18462 : 155 : ntups = PQntuples(res);
18463 : :
18464 : 155 : i_conrelid = PQfnumber(res, "conrelid");
18465 : 155 : i_confrelid = PQfnumber(res, "confrelid");
18466 : :
18467 : : /* Now get the dependencies and register them */
18468 [ - + ]: 155 : for (i = 0; i < ntups; i++)
18469 : : {
18470 : : Oid conrelid,
18471 : : confrelid;
18472 : : TableInfo *reftable,
18473 : : *contable;
18474 : :
3331 sfrost@snowman.net 18475 :UBC 0 : conrelid = atooid(PQgetvalue(res, i, i_conrelid));
18476 : 0 : confrelid = atooid(PQgetvalue(res, i, i_confrelid));
18477 : 0 : contable = findTableByOid(conrelid);
18478 : 0 : reftable = findTableByOid(confrelid);
18479 : :
18480 [ # # ]: 0 : if (reftable == NULL ||
18481 [ # # # # ]: 0 : reftable->dataObj == NULL ||
18482 : 0 : contable == NULL ||
18483 [ # # ]: 0 : contable->dataObj == NULL)
18484 : 0 : continue;
18485 : :
18486 : : /*
18487 : : * Make referencing TABLE_DATA object depend on the referenced table's
18488 : : * TABLE_DATA object.
18489 : : */
18490 : 0 : addObjectDependency(&contable->dataObj->dobj,
18491 : 0 : reftable->dataObj->dobj.dumpId);
18492 : : }
3199 tgl@sss.pgh.pa.us 18493 :CBC 155 : PQclear(res);
4813 18494 : 155 : destroyPQExpBuffer(query);
18495 : : }
18496 : :
18497 : : /*
18498 : : * getDependencies --- obtain available dependency data
18499 : : */
18500 : : static void
4451 rhaas@postgresql.org 18501 : 155 : getDependencies(Archive *fout)
18502 : : {
18503 : : PQExpBuffer query;
18504 : : PGresult *res;
18505 : : int ntups,
18506 : : i;
18507 : : int i_classid,
18508 : : i_objid,
18509 : : i_refclassid,
18510 : : i_refobjid,
18511 : : i_deptype;
18512 : : DumpableObject *dobj,
18513 : : *refdobj;
18514 : :
1840 peter@eisentraut.org 18515 : 155 : pg_log_info("reading dependency data");
18516 : :
7435 tgl@sss.pgh.pa.us 18517 : 155 : query = createPQExpBuffer();
18518 : :
18519 : : /*
18520 : : * Messy query to collect the dependency data we need. Note that we
18521 : : * ignore the sub-object column, so that dependencies of or on a column
18522 : : * look the same as dependencies of or on a whole table.
18523 : : *
18524 : : * PIN dependencies aren't interesting, and EXTENSION dependencies were
18525 : : * already processed by getExtensionMembership.
18526 : : */
3800 heikki.linnakangas@i 18527 : 155 : appendPQExpBufferStr(query, "SELECT "
18528 : : "classid, objid, refclassid, refobjid, deptype "
18529 : : "FROM pg_depend "
18530 : : "WHERE deptype != 'p' AND deptype != 'e'\n");
18531 : :
18532 : : /*
18533 : : * Since we don't treat pg_amop entries as separate DumpableObjects, we
18534 : : * have to translate their dependencies into dependencies of their parent
18535 : : * opfamily. Ignore internal dependencies though, as those will point to
18536 : : * their parent opclass, which we needn't consider here (and if we did,
18537 : : * it'd just result in circular dependencies). Also, "loose" opfamily
18538 : : * entries will have dependencies on their parent opfamily, which we
18539 : : * should drop since they'd likewise become useless self-dependencies.
18540 : : * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
18541 : : */
852 tgl@sss.pgh.pa.us 18542 : 155 : appendPQExpBufferStr(query, "UNION ALL\n"
18543 : : "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
18544 : : "FROM pg_depend d, pg_amop o "
18545 : : "WHERE deptype NOT IN ('p', 'e', 'i') AND "
18546 : : "classid = 'pg_amop'::regclass AND objid = o.oid "
18547 : : "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
18548 : :
18549 : : /* Likewise for pg_amproc entries */
18550 : 155 : appendPQExpBufferStr(query, "UNION ALL\n"
18551 : : "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
18552 : : "FROM pg_depend d, pg_amproc p "
18553 : : "WHERE deptype NOT IN ('p', 'e', 'i') AND "
18554 : : "classid = 'pg_amproc'::regclass AND objid = p.oid "
18555 : : "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
18556 : :
18557 : : /* Sort the output for efficiency below */
1719 18558 : 155 : appendPQExpBufferStr(query, "ORDER BY 1,2");
18559 : :
4450 rhaas@postgresql.org 18560 : 155 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18561 : :
7435 tgl@sss.pgh.pa.us 18562 : 155 : ntups = PQntuples(res);
18563 : :
18564 : 155 : i_classid = PQfnumber(res, "classid");
18565 : 155 : i_objid = PQfnumber(res, "objid");
18566 : 155 : i_refclassid = PQfnumber(res, "refclassid");
18567 : 155 : i_refobjid = PQfnumber(res, "refobjid");
18568 : 155 : i_deptype = PQfnumber(res, "deptype");
18569 : :
18570 : : /*
18571 : : * Since we ordered the SELECT by referencing ID, we can expect that
18572 : : * multiple entries for the same object will appear together; this saves
18573 : : * on searches.
18574 : : */
18575 : 155 : dobj = NULL;
18576 : :
18577 [ + + ]: 323734 : for (i = 0; i < ntups; i++)
18578 : : {
18579 : : CatalogId objId;
18580 : : CatalogId refobjId;
18581 : : char deptype;
18582 : :
18583 : 323579 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
18584 : 323579 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
18585 : 323579 : refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
18586 : 323579 : refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
18587 : 323579 : deptype = *(PQgetvalue(res, i, i_deptype));
18588 : :
18589 [ + + ]: 323579 : if (dobj == NULL ||
18590 [ + + ]: 306712 : dobj->catId.tableoid != objId.tableoid ||
18591 [ + + ]: 304854 : dobj->catId.oid != objId.oid)
18592 : 137772 : dobj = findObjectByCatalogId(objId);
18593 : :
18594 : : /*
18595 : : * Failure to find objects mentioned in pg_depend is not unexpected,
18596 : : * since for example we don't collect info about TOAST tables.
18597 : : */
18598 [ + + ]: 323579 : if (dobj == NULL)
18599 : : {
18600 : : #ifdef NOT_USED
18601 : : pg_log_warning("no referencing object %u %u",
18602 : : objId.tableoid, objId.oid);
18603 : : #endif
18604 : 17478 : continue;
18605 : : }
18606 : :
18607 : 306859 : refdobj = findObjectByCatalogId(refobjId);
18608 : :
18609 [ + + ]: 306859 : if (refdobj == NULL)
18610 : : {
18611 : : #ifdef NOT_USED
18612 : : pg_log_warning("no referenced object %u %u",
18613 : : refobjId.tableoid, refobjId.oid);
18614 : : #endif
18615 : 758 : continue;
18616 : : }
18617 : :
18618 : : /*
18619 : : * For 'x' dependencies, mark the object for later; we still add the
18620 : : * normal dependency, for possible ordering purposes. Currently
18621 : : * pg_dump_sort.c knows to put extensions ahead of all object types
18622 : : * that could possibly depend on them, but this is safer.
18623 : : */
1495 alvherre@alvh.no-ip. 18624 [ + + ]: 306101 : if (deptype == 'x')
18625 : 44 : dobj->depends_on_ext = true;
18626 : :
18627 : : /*
18628 : : * Ordinarily, table rowtypes have implicit dependencies on their
18629 : : * tables. However, for a composite type the implicit dependency goes
18630 : : * the other way in pg_depend; which is the right thing for DROP but
18631 : : * it doesn't produce the dependency ordering we need. So in that one
18632 : : * case, we reverse the direction of the dependency.
18633 : : */
7033 tgl@sss.pgh.pa.us 18634 [ + + ]: 306101 : if (deptype == 'i' &&
18635 [ + + ]: 84153 : dobj->objType == DO_TABLE &&
18636 [ + + ]: 884 : refdobj->objType == DO_TYPE)
18637 : 151 : addObjectDependency(refdobj, dobj->dumpId);
18638 : : else
18639 : : /* normal case */
18640 : 305950 : addObjectDependency(dobj, refdobj->dumpId);
18641 : : }
18642 : :
7435 18643 : 155 : PQclear(res);
18644 : :
8290 18645 : 155 : destroyPQExpBuffer(query);
9322 bruce@momjian.us 18646 : 155 : }
18647 : :
18648 : :
18649 : : /*
18650 : : * createBoundaryObjects - create dummy DumpableObjects to represent
18651 : : * dump section boundaries.
18652 : : */
18653 : : static DumpableObject *
4311 tgl@sss.pgh.pa.us 18654 : 155 : createBoundaryObjects(void)
18655 : : {
18656 : : DumpableObject *dobjs;
18657 : :
18658 : 155 : dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
18659 : :
18660 : 155 : dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
18661 : 155 : dobjs[0].catId = nilCatalogId;
18662 : 155 : AssignDumpId(dobjs + 0);
18663 : 155 : dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
18664 : :
18665 : 155 : dobjs[1].objType = DO_POST_DATA_BOUNDARY;
18666 : 155 : dobjs[1].catId = nilCatalogId;
18667 : 155 : AssignDumpId(dobjs + 1);
18668 : 155 : dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
18669 : :
18670 : 155 : return dobjs;
18671 : : }
18672 : :
18673 : : /*
18674 : : * addBoundaryDependencies - add dependencies as needed to enforce the dump
18675 : : * section boundaries.
18676 : : */
18677 : : static void
18678 : 155 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
18679 : : DumpableObject *boundaryObjs)
18680 : : {
18681 : 155 : DumpableObject *preDataBound = boundaryObjs + 0;
18682 : 155 : DumpableObject *postDataBound = boundaryObjs + 1;
18683 : : int i;
18684 : :
18685 [ + + ]: 664403 : for (i = 0; i < numObjs; i++)
18686 : : {
18687 : 664248 : DumpableObject *dobj = dobjs[i];
18688 : :
18689 : : /*
18690 : : * The classification of object types here must match the SECTION_xxx
18691 : : * values assigned during subsequent ArchiveEntry calls!
18692 : : */
18693 [ + + + + : 664248 : switch (dobj->objType)
+ + + - ]
18694 : : {
18695 : 629249 : case DO_NAMESPACE:
18696 : : case DO_EXTENSION:
18697 : : case DO_TYPE:
18698 : : case DO_SHELL_TYPE:
18699 : : case DO_FUNC:
18700 : : case DO_AGG:
18701 : : case DO_OPERATOR:
18702 : : case DO_ACCESS_METHOD:
18703 : : case DO_OPCLASS:
18704 : : case DO_OPFAMILY:
18705 : : case DO_COLLATION:
18706 : : case DO_CONVERSION:
18707 : : case DO_TABLE:
18708 : : case DO_TABLE_ATTACH:
18709 : : case DO_ATTRDEF:
18710 : : case DO_PROCLANG:
18711 : : case DO_CAST:
18712 : : case DO_DUMMY_TYPE:
18713 : : case DO_TSPARSER:
18714 : : case DO_TSDICT:
18715 : : case DO_TSTEMPLATE:
18716 : : case DO_TSCONFIG:
18717 : : case DO_FDW:
18718 : : case DO_FOREIGN_SERVER:
18719 : : case DO_TRANSFORM:
18720 : : /* Pre-data objects: must come before the pre-data boundary */
18721 : 629249 : addObjectDependency(preDataBound, dobj->dumpId);
18722 : 629249 : break;
18723 : 4159 : case DO_TABLE_DATA:
18724 : : case DO_SEQUENCE_SET:
18725 : : case DO_LARGE_OBJECT:
18726 : : case DO_LARGE_OBJECT_DATA:
18727 : : /* Data objects: must come between the boundaries */
18728 : 4159 : addObjectDependency(dobj, preDataBound->dumpId);
18729 : 4159 : addObjectDependency(postDataBound, dobj->dumpId);
18730 : 4159 : break;
18731 : 5069 : case DO_INDEX:
18732 : : case DO_INDEX_ATTACH:
18733 : : case DO_STATSEXT:
18734 : : case DO_REFRESH_MATVIEW:
18735 : : case DO_TRIGGER:
18736 : : case DO_EVENT_TRIGGER:
18737 : : case DO_DEFAULT_ACL:
18738 : : case DO_POLICY:
18739 : : case DO_PUBLICATION:
18740 : : case DO_PUBLICATION_REL:
18741 : : case DO_PUBLICATION_TABLE_IN_SCHEMA:
18742 : : case DO_SUBSCRIPTION:
18743 : : case DO_SUBSCRIPTION_REL:
18744 : : /* Post-data objects: must come after the post-data boundary */
18745 : 5069 : addObjectDependency(dobj, postDataBound->dumpId);
18746 : 5069 : break;
18747 : 23405 : case DO_RULE:
18748 : : /* Rules are post-data, but only if dumped separately */
18749 [ + + ]: 23405 : if (((RuleInfo *) dobj)->separate)
18750 : 505 : addObjectDependency(dobj, postDataBound->dumpId);
18751 : 23405 : break;
18752 : 2056 : case DO_CONSTRAINT:
18753 : : case DO_FK_CONSTRAINT:
18754 : : /* Constraints are post-data, but only if dumped separately */
18755 [ + + ]: 2056 : if (((ConstraintInfo *) dobj)->separate)
18756 : 1424 : addObjectDependency(dobj, postDataBound->dumpId);
18757 : 2056 : break;
18758 : 155 : case DO_PRE_DATA_BOUNDARY:
18759 : : /* nothing to do */
18760 : 155 : break;
18761 : 155 : case DO_POST_DATA_BOUNDARY:
18762 : : /* must come after the pre-data boundary */
18763 : 155 : addObjectDependency(dobj, preDataBound->dumpId);
18764 : 155 : break;
18765 : : }
18766 : : }
18767 : 155 : }
18768 : :
18769 : :
18770 : : /*
18771 : : * BuildArchiveDependencies - create dependency data for archive TOC entries
18772 : : *
18773 : : * The raw dependency data obtained by getDependencies() is not terribly
18774 : : * useful in an archive dump, because in many cases there are dependency
18775 : : * chains linking through objects that don't appear explicitly in the dump.
18776 : : * For example, a view will depend on its _RETURN rule while the _RETURN rule
18777 : : * will depend on other objects --- but the rule will not appear as a separate
18778 : : * object in the dump. We need to adjust the view's dependencies to include
18779 : : * whatever the rule depends on that is included in the dump.
18780 : : *
18781 : : * Just to make things more complicated, there are also "special" dependencies
18782 : : * such as the dependency of a TABLE DATA item on its TABLE, which we must
18783 : : * not rearrange because pg_restore knows that TABLE DATA only depends on
18784 : : * its table. In these cases we must leave the dependencies strictly as-is
18785 : : * even if they refer to not-to-be-dumped objects.
18786 : : *
18787 : : * To handle this, the convention is that "special" dependencies are created
18788 : : * during ArchiveEntry calls, and an archive TOC item that has any such
18789 : : * entries will not be touched here. Otherwise, we recursively search the
18790 : : * DumpableObject data structures to build the correct dependencies for each
18791 : : * archive TOC item.
18792 : : */
18793 : : static void
18794 : 33 : BuildArchiveDependencies(Archive *fout)
18795 : : {
18796 : 33 : ArchiveHandle *AH = (ArchiveHandle *) fout;
18797 : : TocEntry *te;
18798 : :
18799 : : /* Scan all TOC entries in the archive */
18800 [ + + ]: 5428 : for (te = AH->toc->next; te != AH->toc; te = te->next)
18801 : : {
18802 : : DumpableObject *dobj;
18803 : : DumpId *dependencies;
18804 : : int nDeps;
18805 : : int allocDeps;
18806 : :
18807 : : /* No need to process entries that will not be dumped */
18808 [ + + ]: 5395 : if (te->reqs == 0)
18809 : 1745 : continue;
18810 : : /* Ignore entries that already have "special" dependencies */
18811 [ + + ]: 5392 : if (te->nDeps > 0)
18812 : 1451 : continue;
18813 : : /* Otherwise, look up the item's original DumpableObject, if any */
18814 : 3941 : dobj = findObjectByDumpId(te->dumpId);
18815 [ + + ]: 3941 : if (dobj == NULL)
18816 : 169 : continue;
18817 : : /* No work if it has no dependencies */
18818 [ + + ]: 3772 : if (dobj->nDeps <= 0)
18819 : 122 : continue;
18820 : : /* Set up work array */
18821 : 3650 : allocDeps = 64;
18822 : 3650 : dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18823 : 3650 : nDeps = 0;
18824 : : /* Recursively find all dumpable dependencies */
18825 : 3650 : findDumpableDependencies(AH, dobj,
18826 : : &dependencies, &nDeps, &allocDeps);
18827 : : /* And save 'em ... */
18828 [ + + ]: 3650 : if (nDeps > 0)
18829 : : {
18830 : 2812 : dependencies = (DumpId *) pg_realloc(dependencies,
18831 : : nDeps * sizeof(DumpId));
18832 : 2812 : te->dependencies = dependencies;
18833 : 2812 : te->nDeps = nDeps;
18834 : : }
18835 : : else
18836 : 838 : free(dependencies);
18837 : : }
18838 : 33 : }
18839 : :
18840 : : /* Recursive search subroutine for BuildArchiveDependencies */
18841 : : static void
1159 peter@eisentraut.org 18842 : 8803 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
18843 : : DumpId **dependencies, int *nDeps, int *allocDeps)
18844 : : {
18845 : : int i;
18846 : :
18847 : : /*
18848 : : * Ignore section boundary objects: if we search through them, we'll
18849 : : * report lots of bogus dependencies.
18850 : : */
4311 tgl@sss.pgh.pa.us 18851 [ + + ]: 8803 : if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18852 [ + + ]: 8780 : dobj->objType == DO_POST_DATA_BOUNDARY)
18853 : 1614 : return;
18854 : :
18855 [ + + ]: 18407 : for (i = 0; i < dobj->nDeps; i++)
18856 : : {
18857 : 11218 : DumpId depid = dobj->dependencies[i];
18858 : :
18859 [ + + ]: 11218 : if (TocIDRequired(AH, depid) != 0)
18860 : : {
18861 : : /* Object will be dumped, so just reference it as a dependency */
18862 [ - + ]: 6065 : if (*nDeps >= *allocDeps)
18863 : : {
4311 tgl@sss.pgh.pa.us 18864 :UBC 0 : *allocDeps *= 2;
18865 : 0 : *dependencies = (DumpId *) pg_realloc(*dependencies,
2489 18866 : 0 : *allocDeps * sizeof(DumpId));
18867 : : }
4311 tgl@sss.pgh.pa.us 18868 :CBC 6065 : (*dependencies)[*nDeps] = depid;
18869 : 6065 : (*nDeps)++;
18870 : : }
18871 : : else
18872 : : {
18873 : : /*
18874 : : * Object will not be dumped, so recursively consider its deps. We
18875 : : * rely on the assumption that sortDumpableObjects already broke
18876 : : * any dependency loops, else we might recurse infinitely.
18877 : : */
18878 : 5153 : DumpableObject *otherdobj = findObjectByDumpId(depid);
18879 : :
18880 [ + - ]: 5153 : if (otherdobj)
18881 : 5153 : findDumpableDependencies(AH, otherdobj,
18882 : : dependencies, nDeps, allocDeps);
18883 : : }
18884 : : }
18885 : : }
18886 : :
18887 : :
18888 : : /*
18889 : : * getFormattedTypeName - retrieve a nicely-formatted type name for the
18890 : : * given type OID.
18891 : : *
18892 : : * This does not guarantee to schema-qualify the output, so it should not
18893 : : * be used to create the target object name for CREATE or ALTER commands.
18894 : : *
18895 : : * Note that the result is cached and must not be freed by the caller.
18896 : : */
18897 : : static const char *
4451 rhaas@postgresql.org 18898 : 2310 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18899 : : {
18900 : : TypeInfo *typeInfo;
18901 : : char *result;
18902 : : PQExpBuffer query;
18903 : : PGresult *res;
18904 : :
7435 tgl@sss.pgh.pa.us 18905 [ - + ]: 2310 : if (oid == 0)
18906 : : {
1501 tgl@sss.pgh.pa.us 18907 [ # # ]:UBC 0 : if ((opts & zeroAsStar) != 0)
949 18908 : 0 : return "*";
8010 18909 [ # # ]: 0 : else if ((opts & zeroAsNone) != 0)
949 18910 : 0 : return "NONE";
18911 : : }
18912 : :
18913 : : /* see if we have the result cached in the type's TypeInfo record */
957 tgl@sss.pgh.pa.us 18914 :CBC 2310 : typeInfo = findTypeByOid(oid);
18915 [ + - + + ]: 2310 : if (typeInfo && typeInfo->ftypname)
949 18916 : 1827 : return typeInfo->ftypname;
18917 : :
8010 18918 : 483 : query = createPQExpBuffer();
2741 18919 : 483 : appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18920 : : oid);
18921 : :
4441 rhaas@postgresql.org 18922 : 483 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
18923 : :
18924 : : /* result of format_type is already quoted */
2741 tgl@sss.pgh.pa.us 18925 : 483 : result = pg_strdup(PQgetvalue(res, 0, 0));
18926 : :
8010 18927 : 483 : PQclear(res);
18928 : 483 : destroyPQExpBuffer(query);
18929 : :
18930 : : /*
18931 : : * Cache the result for re-use in later requests, if possible. If we
18932 : : * don't have a TypeInfo for the type, the string will be leaked once the
18933 : : * caller is done with it ... but that case really should not happen, so
18934 : : * leaking if it does seems acceptable.
18935 : : */
957 18936 [ + - ]: 483 : if (typeInfo)
949 18937 : 483 : typeInfo->ftypname = result;
18938 : :
8010 18939 : 483 : return result;
18940 : : }
18941 : :
18942 : : /*
18943 : : * Return a column list clause for the given relation.
18944 : : *
18945 : : * Special case: if there are no undropped columns in the relation, return
18946 : : * "", not an invalid "()" column list.
18947 : : */
18948 : : static const char *
4039 andrew@dunslane.net 18949 : 7026 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18950 : : {
7941 bruce@momjian.us 18951 : 7026 : int numatts = ti->numatts;
7893 18952 : 7026 : char **attnames = ti->attnames;
18953 : 7026 : bool *attisdropped = ti->attisdropped;
1842 peter@eisentraut.org 18954 : 7026 : char *attgenerated = ti->attgenerated;
18955 : : bool needComma;
18956 : : int i;
18957 : :
3800 heikki.linnakangas@i 18958 : 7026 : appendPQExpBufferChar(buffer, '(');
7926 tgl@sss.pgh.pa.us 18959 : 7026 : needComma = false;
7941 bruce@momjian.us 18960 [ + + ]: 34286 : for (i = 0; i < numatts; i++)
18961 : : {
7926 tgl@sss.pgh.pa.us 18962 [ + + ]: 27260 : if (attisdropped[i])
18963 : 564 : continue;
1842 peter@eisentraut.org 18964 [ + + ]: 26696 : if (attgenerated[i])
18965 : 620 : continue;
7926 tgl@sss.pgh.pa.us 18966 [ + + ]: 26076 : if (needComma)
3800 heikki.linnakangas@i 18967 : 19284 : appendPQExpBufferStr(buffer, ", ");
18968 : 26076 : appendPQExpBufferStr(buffer, fmtId(attnames[i]));
7926 tgl@sss.pgh.pa.us 18969 : 26076 : needComma = true;
18970 : : }
18971 : :
7794 18972 [ + + ]: 7026 : if (!needComma)
7660 18973 : 234 : return ""; /* no undropped columns */
18974 : :
3800 heikki.linnakangas@i 18975 : 6792 : appendPQExpBufferChar(buffer, ')');
4039 andrew@dunslane.net 18976 : 6792 : return buffer->data;
18977 : : }
18978 : :
18979 : : /*
18980 : : * Check if a reloptions array is nonempty.
18981 : : */
18982 : : static bool
3025 tgl@sss.pgh.pa.us 18983 : 11801 : nonemptyReloptions(const char *reloptions)
18984 : : {
18985 : : /* Don't want to print it if it's just "{}" */
18986 [ + - + + ]: 11801 : return (reloptions != NULL && strlen(reloptions) > 2);
18987 : : }
18988 : :
18989 : : /*
18990 : : * Format a reloptions array and append it to the given buffer.
18991 : : *
18992 : : * "prefix" is prepended to the option names; typically it's "" or "toast.".
18993 : : */
18994 : : static void
2900 dean.a.rasheed@gmail 18995 : 210 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18996 : : const char *prefix, Archive *fout)
18997 : : {
18998 : : bool res;
18999 : :
19000 : 210 : res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
19001 : 210 : fout->std_strings);
19002 [ - + ]: 210 : if (!res)
897 peter@eisentraut.org 19003 :UBC 0 : pg_log_warning("could not parse %s array", "reloptions");
3025 tgl@sss.pgh.pa.us 19004 :CBC 210 : }
19005 : :
19006 : : /*
19007 : : * read_dump_filters - retrieve object identifier patterns from file
19008 : : *
19009 : : * Parse the specified filter file for include and exclude patterns, and add
19010 : : * them to the relevant lists. If the filename is "-" then filters will be
19011 : : * read from STDIN rather than a file.
19012 : : */
19013 : : static void
137 dgustafsson@postgres 19014 :GNC 26 : read_dump_filters(const char *filename, DumpOptions *dopt)
19015 : : {
19016 : : FilterStateData fstate;
19017 : : char *objname;
19018 : : FilterCommandType comtype;
19019 : : FilterObjectType objtype;
19020 : :
19021 : 26 : filter_init(&fstate, filename, exit_nicely);
19022 : :
19023 [ + + ]: 84 : while (filter_read_item(&fstate, &objname, &comtype, &objtype))
19024 : : {
19025 [ + + ]: 33 : if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
19026 : : {
19027 [ - - + + : 17 : switch (objtype)
+ + + - ]
19028 : : {
137 dgustafsson@postgres 19029 :UNC 0 : case FILTER_OBJECT_TYPE_NONE:
19030 : 0 : break;
19031 : 0 : case FILTER_OBJECT_TYPE_DATABASE:
19032 : : case FILTER_OBJECT_TYPE_FUNCTION:
19033 : : case FILTER_OBJECT_TYPE_INDEX:
19034 : : case FILTER_OBJECT_TYPE_TABLE_DATA:
19035 : : case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
19036 : : case FILTER_OBJECT_TYPE_TRIGGER:
136 19037 : 0 : pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
19038 : : "include",
19039 : : filter_object_type_name(objtype));
137 19040 : 0 : exit_nicely(1);
19041 : : break; /* unreachable */
19042 : :
137 dgustafsson@postgres 19043 :GNC 1 : case FILTER_OBJECT_TYPE_EXTENSION:
19044 : 1 : simple_string_list_append(&extension_include_patterns, objname);
19045 : 1 : break;
19046 : 1 : case FILTER_OBJECT_TYPE_FOREIGN_DATA:
19047 : 1 : simple_string_list_append(&foreign_servers_include_patterns, objname);
19048 : 1 : break;
19049 : 1 : case FILTER_OBJECT_TYPE_SCHEMA:
19050 : 1 : simple_string_list_append(&schema_include_patterns, objname);
19051 : 1 : dopt->include_everything = false;
19052 : 1 : break;
19053 : 13 : case FILTER_OBJECT_TYPE_TABLE:
19054 : 13 : simple_string_list_append(&table_include_patterns, objname);
19055 : 13 : dopt->include_everything = false;
19056 : 13 : break;
19057 : 1 : case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
19058 : 1 : simple_string_list_append(&table_include_patterns_and_children,
19059 : : objname);
19060 : 1 : dopt->include_everything = false;
19061 : 1 : break;
19062 : : }
19063 : : }
19064 [ + + ]: 16 : else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
19065 : : {
19066 [ - + + + : 9 : switch (objtype)
+ + + +
- ]
19067 : : {
137 dgustafsson@postgres 19068 :UNC 0 : case FILTER_OBJECT_TYPE_NONE:
19069 : 0 : break;
137 dgustafsson@postgres 19070 :GNC 1 : case FILTER_OBJECT_TYPE_DATABASE:
19071 : : case FILTER_OBJECT_TYPE_FUNCTION:
19072 : : case FILTER_OBJECT_TYPE_INDEX:
19073 : : case FILTER_OBJECT_TYPE_TRIGGER:
19074 : : case FILTER_OBJECT_TYPE_FOREIGN_DATA:
136 19075 : 1 : pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
19076 : : "exclude",
19077 : : filter_object_type_name(objtype));
137 19078 : 1 : exit_nicely(1);
19079 : : break;
19080 : :
25 dean.a.rasheed@gmail 19081 : 1 : case FILTER_OBJECT_TYPE_EXTENSION:
19082 : 1 : simple_string_list_append(&extension_exclude_patterns, objname);
19083 : 1 : break;
137 dgustafsson@postgres 19084 : 1 : case FILTER_OBJECT_TYPE_TABLE_DATA:
19085 : 1 : simple_string_list_append(&tabledata_exclude_patterns,
19086 : : objname);
19087 : 1 : break;
19088 : 1 : case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
19089 : 1 : simple_string_list_append(&tabledata_exclude_patterns_and_children,
19090 : : objname);
19091 : 1 : break;
19092 : 2 : case FILTER_OBJECT_TYPE_SCHEMA:
19093 : 2 : simple_string_list_append(&schema_exclude_patterns, objname);
19094 : 2 : break;
19095 : 2 : case FILTER_OBJECT_TYPE_TABLE:
19096 : 2 : simple_string_list_append(&table_exclude_patterns, objname);
19097 : 2 : break;
19098 : 1 : case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
19099 : 1 : simple_string_list_append(&table_exclude_patterns_and_children,
19100 : : objname);
19101 : 1 : break;
19102 : : }
19103 : : }
19104 : : else
19105 : : {
19106 [ - + ]: 7 : Assert(comtype == FILTER_COMMAND_TYPE_NONE);
19107 [ - + ]: 7 : Assert(objtype == FILTER_OBJECT_TYPE_NONE);
19108 : : }
19109 : :
19110 [ + + ]: 32 : if (objname)
19111 : 25 : free(objname);
19112 : : }
19113 : :
19114 : 22 : filter_free(&fstate);
19115 : 22 : }
|