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-2025, 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_constraint_d.h"
51 : : #include "catalog/pg_default_acl_d.h"
52 : : #include "catalog/pg_largeobject_d.h"
53 : : #include "catalog/pg_largeobject_metadata_d.h"
54 : : #include "catalog/pg_proc_d.h"
55 : : #include "catalog/pg_publication_d.h"
56 : : #include "catalog/pg_shdepend_d.h"
57 : : #include "catalog/pg_subscription_d.h"
58 : : #include "catalog/pg_type_d.h"
59 : : #include "common/connect.h"
60 : : #include "common/int.h"
61 : : #include "common/relpath.h"
62 : : #include "common/shortest_dec.h"
63 : : #include "compress_io.h"
64 : : #include "dumputils.h"
65 : : #include "fe_utils/option_utils.h"
66 : : #include "fe_utils/string_utils.h"
67 : : #include "filter.h"
68 : : #include "getopt_long.h"
69 : : #include "libpq/libpq-fs.h"
70 : : #include "parallel.h"
71 : : #include "pg_backup_db.h"
72 : : #include "pg_backup_utils.h"
73 : : #include "pg_dump.h"
74 : : #include "storage/block.h"
75 : :
76 : : typedef struct
77 : : {
78 : : Oid roleoid; /* role's OID */
79 : : const char *rolename; /* role's name */
80 : : } RoleNameItem;
81 : :
82 : : typedef struct
83 : : {
84 : : const char *descr; /* comment for an object */
85 : : Oid classoid; /* object class (catalog OID) */
86 : : Oid objoid; /* object OID */
87 : : int objsubid; /* subobject (table column #) */
88 : : } CommentItem;
89 : :
90 : : typedef struct
91 : : {
92 : : const char *provider; /* label provider of this security label */
93 : : const char *label; /* security label for an object */
94 : : Oid classoid; /* object class (catalog OID) */
95 : : Oid objoid; /* object OID */
96 : : int objsubid; /* subobject (table column #) */
97 : : } SecLabelItem;
98 : :
99 : : typedef struct
100 : : {
101 : : Oid oid; /* object OID */
102 : : char relkind; /* object kind */
103 : : RelFileNumber relfilenumber; /* object filenode */
104 : : Oid toast_oid; /* toast table OID */
105 : : RelFileNumber toast_relfilenumber; /* toast table filenode */
106 : : Oid toast_index_oid; /* toast table index OID */
107 : : RelFileNumber toast_index_relfilenumber; /* toast table index filenode */
108 : : } BinaryUpgradeClassOidItem;
109 : :
110 : : /* sequence types */
111 : : typedef enum SeqType
112 : : {
113 : : SEQTYPE_SMALLINT,
114 : : SEQTYPE_INTEGER,
115 : : SEQTYPE_BIGINT,
116 : : } SeqType;
117 : :
118 : : static const char *const SeqTypeNames[] =
119 : : {
120 : : [SEQTYPE_SMALLINT] = "smallint",
121 : : [SEQTYPE_INTEGER] = "integer",
122 : : [SEQTYPE_BIGINT] = "bigint",
123 : : };
124 : :
125 : : StaticAssertDecl(lengthof(SeqTypeNames) == (SEQTYPE_BIGINT + 1),
126 : : "array length mismatch");
127 : :
128 : : typedef struct
129 : : {
130 : : Oid oid; /* sequence OID */
131 : : SeqType seqtype; /* data type of sequence */
132 : : bool cycled; /* whether sequence cycles */
133 : : int64 minv; /* minimum value */
134 : : int64 maxv; /* maximum value */
135 : : int64 startv; /* start value */
136 : : int64 incby; /* increment value */
137 : : int64 cache; /* cache size */
138 : : int64 last_value; /* last value of sequence */
139 : : bool is_called; /* whether nextval advances before returning */
140 : : } SequenceItem;
141 : :
142 : : typedef enum OidOptions
143 : : {
144 : : zeroIsError = 1,
145 : : zeroAsStar = 2,
146 : : zeroAsNone = 4,
147 : : } OidOptions;
148 : :
149 : : /* global decls */
150 : : static bool dosync = true; /* Issue fsync() to make dump durable on disk. */
151 : :
152 : : static Oid g_last_builtin_oid; /* value of the last builtin oid */
153 : :
154 : : /* The specified names/patterns should to match at least one entity */
155 : : static int strict_names = 0;
156 : :
157 : : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
158 : :
159 : : /*
160 : : * Object inclusion/exclusion lists
161 : : *
162 : : * The string lists record the patterns given by command-line switches,
163 : : * which we then convert to lists of OIDs of matching objects.
164 : : */
165 : : static SimpleStringList schema_include_patterns = {NULL, NULL};
166 : : static SimpleOidList schema_include_oids = {NULL, NULL};
167 : : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
168 : : static SimpleOidList schema_exclude_oids = {NULL, NULL};
169 : :
170 : : static SimpleStringList table_include_patterns = {NULL, NULL};
171 : : static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
172 : : static SimpleOidList table_include_oids = {NULL, NULL};
173 : : static SimpleStringList table_exclude_patterns = {NULL, NULL};
174 : : static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
175 : : static SimpleOidList table_exclude_oids = {NULL, NULL};
176 : : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
177 : : static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
178 : : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
179 : :
180 : : static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
181 : : static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
182 : :
183 : : static SimpleStringList extension_include_patterns = {NULL, NULL};
184 : : static SimpleOidList extension_include_oids = {NULL, NULL};
185 : :
186 : : static SimpleStringList extension_exclude_patterns = {NULL, NULL};
187 : : static SimpleOidList extension_exclude_oids = {NULL, NULL};
188 : :
189 : : static const CatalogId nilCatalogId = {0, 0};
190 : :
191 : : /* override for standard extra_float_digits setting */
192 : : static bool have_extra_float_digits = false;
193 : : static int extra_float_digits;
194 : :
195 : : /* sorted table of role names */
196 : : static RoleNameItem *rolenames = NULL;
197 : : static int nrolenames = 0;
198 : :
199 : : /* sorted table of comments */
200 : : static CommentItem *comments = NULL;
201 : : static int ncomments = 0;
202 : :
203 : : /* sorted table of security labels */
204 : : static SecLabelItem *seclabels = NULL;
205 : : static int nseclabels = 0;
206 : :
207 : : /* sorted table of pg_class information for binary upgrade */
208 : : static BinaryUpgradeClassOidItem *binaryUpgradeClassOids = NULL;
209 : : static int nbinaryUpgradeClassOids = 0;
210 : :
211 : : /* sorted table of sequences */
212 : : static SequenceItem *sequences = NULL;
213 : : static int nsequences = 0;
214 : :
215 : : /*
216 : : * For binary upgrade, the dump ID of pg_largeobject_metadata is saved for use
217 : : * as a dependency for pg_shdepend and any large object comments/seclabels.
218 : : */
219 : : static DumpId lo_metadata_dumpId;
220 : :
221 : : /* Maximum number of relations to fetch in a fetchAttributeStats() call. */
222 : : #define MAX_ATTR_STATS_RELS 64
223 : :
224 : : /*
225 : : * The default number of rows per INSERT when
226 : : * --inserts is specified without --rows-per-insert
227 : : */
228 : : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
229 : :
230 : : /*
231 : : * Maximum number of large objects to group into a single ArchiveEntry.
232 : : * At some point we might want to make this user-controllable, but for now
233 : : * a hard-wired setting will suffice.
234 : : */
235 : : #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
236 : :
237 : : /*
238 : : * Macro for producing quoted, schema-qualified name of a dumpable object.
239 : : */
240 : : #define fmtQualifiedDumpable(obj) \
241 : : fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
242 : : (obj)->dobj.name)
243 : :
244 : : static void help(const char *progname);
245 : : static void setup_connection(Archive *AH,
246 : : const char *dumpencoding, const char *dumpsnapshot,
247 : : char *use_role);
248 : : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
249 : : static void expand_schema_name_patterns(Archive *fout,
250 : : SimpleStringList *patterns,
251 : : SimpleOidList *oids,
252 : : bool strict_names);
253 : : static void expand_extension_name_patterns(Archive *fout,
254 : : SimpleStringList *patterns,
255 : : SimpleOidList *oids,
256 : : bool strict_names);
257 : : static void expand_foreign_server_name_patterns(Archive *fout,
258 : : SimpleStringList *patterns,
259 : : SimpleOidList *oids);
260 : : static void expand_table_name_patterns(Archive *fout,
261 : : SimpleStringList *patterns,
262 : : SimpleOidList *oids,
263 : : bool strict_names,
264 : : bool with_child_tables);
265 : : static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
266 : : const char *pattern);
267 : :
268 : : static NamespaceInfo *findNamespace(Oid nsoid);
269 : : static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
270 : : static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
271 : : static const char *getRoleName(const char *roleoid_str);
272 : : static void collectRoleNames(Archive *fout);
273 : : static void getAdditionalACLs(Archive *fout);
274 : : static void dumpCommentExtended(Archive *fout, const char *type,
275 : : const char *name, const char *namespace,
276 : : const char *owner, CatalogId catalogId,
277 : : int subid, DumpId dumpId,
278 : : const char *initdb_comment);
279 : : static inline void dumpComment(Archive *fout, const char *type,
280 : : const char *name, const char *namespace,
281 : : const char *owner, CatalogId catalogId,
282 : : int subid, DumpId dumpId);
283 : : static int findComments(Oid classoid, Oid objoid, CommentItem **items);
284 : : static void collectComments(Archive *fout);
285 : : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
286 : : const char *namespace, const char *owner,
287 : : CatalogId catalogId, int subid, DumpId dumpId);
288 : : static int findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
289 : : static void collectSecLabels(Archive *fout);
290 : : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
291 : : static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
292 : : static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
293 : : static void dumpType(Archive *fout, const TypeInfo *tyinfo);
294 : : static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
295 : : static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
296 : : static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
297 : : static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
298 : : static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
299 : : static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
300 : : static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
301 : : PGresult *res);
302 : : static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
303 : : static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
304 : : static void dumpFunc(Archive *fout, const FuncInfo *finfo);
305 : : static void dumpCast(Archive *fout, const CastInfo *cast);
306 : : static void dumpTransform(Archive *fout, const TransformInfo *transform);
307 : : static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
308 : : static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
309 : : static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
310 : : static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
311 : : static void dumpCollation(Archive *fout, const CollInfo *collinfo);
312 : : static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
313 : : static void dumpRule(Archive *fout, const RuleInfo *rinfo);
314 : : static void dumpAgg(Archive *fout, const AggInfo *agginfo);
315 : : static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
316 : : static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
317 : : static void dumpTable(Archive *fout, const TableInfo *tbinfo);
318 : : static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
319 : : static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
320 : : static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
321 : : static void collectSequences(Archive *fout);
322 : : static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
323 : : static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
324 : : static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
325 : : static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
326 : : static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
327 : : static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
328 : : static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
329 : : static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
330 : : static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
331 : : static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
332 : : static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
333 : : static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
334 : : static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
335 : : static void dumpUserMappings(Archive *fout,
336 : : const char *servername, const char *namespace,
337 : : const char *owner, CatalogId catalogId, DumpId dumpId);
338 : : static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
339 : :
340 : : static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
341 : : const char *type, const char *name, const char *subname,
342 : : const char *nspname, const char *tag, const char *owner,
343 : : const DumpableAcl *dacl);
344 : :
345 : : static void getDependencies(Archive *fout);
346 : : static void BuildArchiveDependencies(Archive *fout);
347 : : static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
348 : : DumpId **dependencies, int *nDeps, int *allocDeps);
349 : :
350 : : static DumpableObject *createBoundaryObjects(void);
351 : : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
352 : : DumpableObject *boundaryObjs);
353 : :
354 : : static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
355 : : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
356 : : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
357 : : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
358 : : static void buildMatViewRefreshDependencies(Archive *fout);
359 : : static void getTableDataFKConstraints(void);
360 : : static void determineNotNullFlags(Archive *fout, PGresult *res, int r,
361 : : TableInfo *tbinfo, int j,
362 : : int i_notnull_name,
363 : : int i_notnull_comment,
364 : : int i_notnull_invalidoid,
365 : : int i_notnull_noinherit,
366 : : int i_notnull_islocal,
367 : : PQExpBuffer *invalidnotnulloids);
368 : : static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
369 : : bool is_agg);
370 : : static char *format_function_signature(Archive *fout,
371 : : const FuncInfo *finfo, bool honor_quotes);
372 : : static char *convertRegProcReference(const char *proc);
373 : : static char *getFormattedOperatorName(const char *oproid);
374 : : static char *convertTSFunction(Archive *fout, Oid funcOid);
375 : : static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
376 : : static void getLOs(Archive *fout);
377 : : static void dumpLO(Archive *fout, const LoInfo *loinfo);
378 : : static int dumpLOs(Archive *fout, const void *arg);
379 : : static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
380 : : static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
381 : : static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
382 : : static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
383 : : static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
384 : : static void dumpDatabase(Archive *fout);
385 : : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
386 : : const char *dbname, Oid dboid);
387 : : static void dumpEncoding(Archive *AH);
388 : : static void dumpStdStrings(Archive *AH);
389 : : static void dumpSearchPath(Archive *AH);
390 : : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
391 : : PQExpBuffer upgrade_buffer,
392 : : Oid pg_type_oid,
393 : : bool force_array_type,
394 : : bool include_multirange_type);
395 : : static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
396 : : PQExpBuffer upgrade_buffer,
397 : : const TableInfo *tbinfo);
398 : : static void collectBinaryUpgradeClassOids(Archive *fout);
399 : : static void binary_upgrade_set_pg_class_oids(Archive *fout,
400 : : PQExpBuffer upgrade_buffer,
401 : : Oid pg_class_oid);
402 : : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
403 : : const DumpableObject *dobj,
404 : : const char *objtype,
405 : : const char *objname,
406 : : const char *objnamespace);
407 : : static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
408 : : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
409 : : static bool nonemptyReloptions(const char *reloptions);
410 : : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
411 : : const char *prefix, Archive *fout);
412 : : static char *get_synchronized_snapshot(Archive *fout);
413 : : static void set_restrict_relation_kind(Archive *AH, const char *value);
414 : : static void setupDumpWorker(Archive *AH);
415 : : static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
416 : : static bool forcePartitionRootLoad(const TableInfo *tbinfo);
417 : : static void read_dump_filters(const char *filename, DumpOptions *dopt);
418 : :
419 : :
420 : : int
8520 tgl@sss.pgh.pa.us 421 :CBC 293 : main(int argc, char **argv)
422 : : {
423 : : int c;
424 : 293 : const char *filename = NULL;
425 : 293 : const char *format = "p";
426 : : TableInfo *tblinfo;
427 : : int numTables;
428 : : DumpableObject **dobjs;
429 : : int numObjs;
430 : : DumpableObject *boundaryObjs;
431 : : int i;
432 : : int optindex;
433 : : RestoreOptions *ropt;
434 : : Archive *fout; /* the script file */
2350 peter@eisentraut.org 435 : 293 : bool g_verbose = false;
3980 alvherre@alvh.no-ip. 436 : 293 : const char *dumpencoding = NULL;
3946 simon@2ndQuadrant.co 437 : 293 : const char *dumpsnapshot = NULL;
3980 alvherre@alvh.no-ip. 438 : 293 : char *use_role = NULL;
4549 andrew@dunslane.net 439 : 293 : int numWorkers = 1;
8520 tgl@sss.pgh.pa.us 440 : 293 : int plainText = 0;
5340 heikki.linnakangas@i 441 : 293 : ArchiveFormat archiveFormat = archUnknown;
442 : : ArchiveMode archiveMode;
1009 michael@paquier.xyz 443 : 293 : pg_compress_specification compression_spec = {0};
444 : 293 : char *compression_detail = NULL;
445 : 293 : char *compression_algorithm_str = "none";
446 : 293 : char *error_detail = NULL;
447 : 293 : bool user_compression_defined = false;
731 nathan@postgresql.or 448 : 293 : DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
285 449 : 293 : bool data_only = false;
450 : 293 : bool schema_only = false;
198 jdavis@postgresql.or 451 : 293 : bool statistics_only = false;
165 452 : 293 : bool with_statistics = false;
198 453 : 293 : bool no_data = false;
454 : 293 : bool no_schema = false;
455 : 293 : bool no_statistics = false;
456 : :
457 : : static DumpOptions dopt;
458 : :
459 : : static struct option long_options[] = {
460 : : {"data-only", no_argument, NULL, 'a'},
461 : : {"blobs", no_argument, NULL, 'b'},
462 : : {"large-objects", no_argument, NULL, 'b'},
463 : : {"no-blobs", no_argument, NULL, 'B'},
464 : : {"no-large-objects", no_argument, NULL, 'B'},
465 : : {"clean", no_argument, NULL, 'c'},
466 : : {"create", no_argument, NULL, 'C'},
467 : : {"dbname", required_argument, NULL, 'd'},
468 : : {"extension", required_argument, NULL, 'e'},
469 : : {"file", required_argument, NULL, 'f'},
470 : : {"format", required_argument, NULL, 'F'},
471 : : {"host", required_argument, NULL, 'h'},
472 : : {"jobs", 1, NULL, 'j'},
473 : : {"no-reconnect", no_argument, NULL, 'R'},
474 : : {"no-owner", no_argument, NULL, 'O'},
475 : : {"port", required_argument, NULL, 'p'},
476 : : {"schema", required_argument, NULL, 'n'},
477 : : {"exclude-schema", required_argument, NULL, 'N'},
478 : : {"schema-only", no_argument, NULL, 's'},
479 : : {"superuser", required_argument, NULL, 'S'},
480 : : {"table", required_argument, NULL, 't'},
481 : : {"exclude-table", required_argument, NULL, 'T'},
482 : : {"no-password", no_argument, NULL, 'w'},
483 : : {"password", no_argument, NULL, 'W'},
484 : : {"username", required_argument, NULL, 'U'},
485 : : {"verbose", no_argument, NULL, 'v'},
486 : : {"no-privileges", no_argument, NULL, 'x'},
487 : : {"no-acl", no_argument, NULL, 'x'},
488 : : {"compress", required_argument, NULL, 'Z'},
489 : : {"encoding", required_argument, NULL, 'E'},
490 : : {"help", no_argument, NULL, '?'},
491 : : {"version", no_argument, NULL, 'V'},
492 : :
493 : : /*
494 : : * the following options don't have an equivalent short option letter
495 : : */
496 : : {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
497 : : {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
498 : : {"column-inserts", no_argument, &dopt.column_inserts, 1},
499 : : {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
500 : : {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
501 : : {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
502 : : {"exclude-table-data", required_argument, NULL, 4},
503 : : {"extra-float-digits", required_argument, NULL, 8},
504 : : {"if-exists", no_argument, &dopt.if_exists, 1},
505 : : {"inserts", no_argument, NULL, 9},
506 : : {"lock-wait-timeout", required_argument, NULL, 2},
507 : : {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
508 : : {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
509 : : {"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
510 : : {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
511 : : {"role", required_argument, NULL, 3},
512 : : {"section", required_argument, NULL, 5},
513 : : {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
514 : : {"snapshot", required_argument, NULL, 6},
515 : : {"statistics", no_argument, NULL, 22},
516 : : {"statistics-only", no_argument, NULL, 18},
517 : : {"strict-names", no_argument, &strict_names, 1},
518 : : {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
519 : : {"no-comments", no_argument, &dopt.no_comments, 1},
520 : : {"no-data", no_argument, NULL, 19},
521 : : {"no-policies", no_argument, &dopt.no_policies, 1},
522 : : {"no-publications", no_argument, &dopt.no_publications, 1},
523 : : {"no-schema", no_argument, NULL, 20},
524 : : {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
525 : : {"no-statistics", no_argument, NULL, 21},
526 : : {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
527 : : {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
528 : : {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
529 : : {"no-sync", no_argument, NULL, 7},
530 : : {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
531 : : {"rows-per-insert", required_argument, NULL, 10},
532 : : {"include-foreign-data", required_argument, NULL, 11},
533 : : {"table-and-children", required_argument, NULL, 12},
534 : : {"exclude-table-and-children", required_argument, NULL, 13},
535 : : {"exclude-table-data-and-children", required_argument, NULL, 14},
536 : : {"sync-method", required_argument, NULL, 15},
537 : : {"filter", required_argument, NULL, 16},
538 : : {"exclude-extension", required_argument, NULL, 17},
539 : : {"sequence-data", no_argument, &dopt.sequence_data, 1},
540 : : {"restrict-key", required_argument, NULL, 25},
541 : :
542 : : {NULL, 0, NULL, 0}
543 : : };
544 : :
2350 peter@eisentraut.org 545 : 293 : pg_logging_init(argv[0]);
546 : 293 : pg_logging_set_level(PG_LOG_WARNING);
6113 peter_e@gmx.net 547 : 293 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
548 : :
549 : : /*
550 : : * Initialize what we need for parallel execution, especially for thread
551 : : * support on Windows.
552 : : */
4549 andrew@dunslane.net 553 : 293 : init_parallel_dump_utils();
554 : :
8191 bruce@momjian.us 555 : 293 : progname = get_progname(argv[0]);
556 : :
8520 tgl@sss.pgh.pa.us 557 [ + - ]: 293 : if (argc > 1)
558 : : {
559 [ + + - + ]: 293 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
560 : : {
561 : 1 : help(progname);
4951 rhaas@postgresql.org 562 : 1 : exit_nicely(0);
563 : : }
8520 tgl@sss.pgh.pa.us 564 [ + + + + ]: 292 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
565 : : {
566 : 62 : puts("pg_dump (PostgreSQL) " PG_VERSION);
4951 rhaas@postgresql.org 567 : 62 : exit_nicely(0);
568 : : }
569 : : }
570 : :
3891 tgl@sss.pgh.pa.us 571 : 230 : InitDumpOptions(&dopt);
572 : :
198 jdavis@postgresql.or 573 : 1276 : while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
8279 peter_e@gmx.net 574 [ + + ]: 1276 : long_options, &optindex)) != -1)
575 : : {
8520 tgl@sss.pgh.pa.us 576 [ + + + + : 1054 : switch (c)
+ + + + +
+ + + + +
+ + + + +
+ + + + +
- + + + +
+ + + - +
+ + + + +
+ + - + +
+ + + + +
+ + ]
577 : : {
578 : 9 : case 'a': /* Dump data only */
285 nathan@postgresql.or 579 : 9 : data_only = true;
8520 tgl@sss.pgh.pa.us 580 : 9 : break;
581 : :
1006 peter@eisentraut.org 582 : 1 : case 'b': /* Dump LOs */
583 : 1 : dopt.outputLOs = true;
8520 tgl@sss.pgh.pa.us 584 : 1 : break;
585 : :
1006 peter@eisentraut.org 586 : 2 : case 'B': /* Don't dump LOs */
587 : 2 : dopt.dontOutputLOs = true;
3203 sfrost@snowman.net 588 : 2 : break;
589 : :
7266 bruce@momjian.us 590 : 6 : case 'c': /* clean (i.e., drop) schema prior to create */
3891 tgl@sss.pgh.pa.us 591 : 6 : dopt.outputClean = 1;
8520 592 : 6 : break;
593 : :
594 : 29 : case 'C': /* Create DB */
3891 595 : 29 : dopt.outputCreateDB = 1;
8520 596 : 29 : break;
597 : :
4576 heikki.linnakangas@i 598 : 5 : case 'd': /* database name */
1808 tgl@sss.pgh.pa.us 599 : 5 : dopt.cparams.dbname = pg_strdup(optarg);
4576 heikki.linnakangas@i 600 : 5 : break;
601 : :
1620 michael@paquier.xyz 602 : 4 : case 'e': /* include extension(s) */
603 : 4 : simple_string_list_append(&extension_include_patterns, optarg);
604 : 4 : dopt.include_everything = false;
605 : 4 : break;
606 : :
7363 bruce@momjian.us 607 : 2 : case 'E': /* Dump encoding */
4712 608 : 2 : dumpencoding = pg_strdup(optarg);
7363 609 : 2 : break;
610 : :
8520 tgl@sss.pgh.pa.us 611 : 183 : case 'f':
4712 bruce@momjian.us 612 : 183 : filename = pg_strdup(optarg);
8520 tgl@sss.pgh.pa.us 613 : 183 : break;
614 : :
615 : 111 : case 'F':
4712 bruce@momjian.us 616 : 111 : format = pg_strdup(optarg);
8520 tgl@sss.pgh.pa.us 617 : 111 : break;
618 : :
619 : 34 : case 'h': /* server host */
1808 620 : 34 : dopt.cparams.pghost = pg_strdup(optarg);
8520 621 : 34 : break;
622 : :
4549 andrew@dunslane.net 623 : 12 : case 'j': /* number of dump jobs */
1505 michael@paquier.xyz 624 [ + + ]: 12 : if (!option_parse_int(optarg, "-j/--jobs", 1,
625 : : PG_MAX_JOBS,
626 : : &numWorkers))
627 : 1 : exit_nicely(1);
4549 andrew@dunslane.net 628 : 11 : break;
629 : :
6907 tgl@sss.pgh.pa.us 630 : 17 : case 'n': /* include schema(s) */
631 : 17 : simple_string_list_append(&schema_include_patterns, optarg);
3891 632 : 17 : dopt.include_everything = false;
6907 633 : 17 : break;
634 : :
635 : 1 : case 'N': /* exclude schema(s) */
636 : 1 : simple_string_list_append(&schema_exclude_patterns, optarg);
8241 bruce@momjian.us 637 : 1 : break;
638 : :
8520 tgl@sss.pgh.pa.us 639 : 2 : case 'O': /* Don't reconnect to match owner */
3891 640 : 2 : dopt.outputNoOwner = 1;
8520 641 : 2 : break;
642 : :
643 : 73 : case 'p': /* server port */
1808 644 : 73 : dopt.cparams.pgport = pg_strdup(optarg);
8520 645 : 73 : break;
646 : :
8019 647 : 2 : case 'R':
648 : : /* no-op, still accepted for backwards compatibility */
8520 649 : 2 : break;
650 : :
651 : 7 : case 's': /* dump schema only */
285 nathan@postgresql.or 652 : 7 : schema_only = true;
8520 tgl@sss.pgh.pa.us 653 : 7 : break;
654 : :
7266 bruce@momjian.us 655 : 1 : case 'S': /* Username for superuser in plain text output */
3891 tgl@sss.pgh.pa.us 656 : 1 : dopt.outputSuperuser = pg_strdup(optarg);
8520 657 : 1 : break;
658 : :
6907 659 : 8 : case 't': /* include table(s) */
660 : 8 : simple_string_list_append(&table_include_patterns, optarg);
3891 661 : 8 : dopt.include_everything = false;
6907 662 : 8 : break;
663 : :
664 : 4 : case 'T': /* exclude table(s) */
665 : 4 : simple_string_list_append(&table_exclude_patterns, optarg);
666 : 4 : break;
667 : :
8520 668 : 36 : case 'U':
1808 669 : 36 : dopt.cparams.username = pg_strdup(optarg);
8520 670 : 36 : break;
671 : :
672 : 6 : case 'v': /* verbose */
673 : 6 : g_verbose = true;
1815 674 : 6 : pg_logging_increase_verbosity();
8520 675 : 6 : break;
676 : :
6036 peter_e@gmx.net 677 : 1 : case 'w':
1808 tgl@sss.pgh.pa.us 678 : 1 : dopt.cparams.promptPassword = TRI_NO;
6036 peter_e@gmx.net 679 : 1 : break;
680 : :
8520 tgl@sss.pgh.pa.us 681 :UBC 0 : case 'W':
1808 682 : 0 : dopt.cparams.promptPassword = TRI_YES;
8520 683 : 0 : break;
684 : :
8520 tgl@sss.pgh.pa.us 685 :CBC 2 : case 'x': /* skip ACL dump */
3891 686 : 2 : dopt.aclsSkip = true;
8520 687 : 2 : break;
688 : :
1009 michael@paquier.xyz 689 : 15 : case 'Z': /* Compression */
690 : 15 : parse_compress_options(optarg, &compression_algorithm_str,
691 : : &compression_detail);
692 : 15 : user_compression_defined = true;
8520 tgl@sss.pgh.pa.us 693 : 15 : break;
694 : :
695 : 128 : case 0:
696 : : /* This covers the long options. */
697 : 128 : break;
698 : :
6088 699 : 2 : case 2: /* lock-wait-timeout */
3891 700 : 2 : dopt.lockWaitTimeout = pg_strdup(optarg);
6257 701 : 2 : break;
702 : :
6088 703 : 3 : case 3: /* SET ROLE */
4712 bruce@momjian.us 704 : 3 : use_role = pg_strdup(optarg);
6088 tgl@sss.pgh.pa.us 705 : 3 : break;
706 : :
4836 bruce@momjian.us 707 : 1 : case 4: /* exclude table(s) data */
5015 andrew@dunslane.net 708 : 1 : simple_string_list_append(&tabledata_exclude_patterns, optarg);
709 : 1 : break;
710 : :
5013 711 : 6 : case 5: /* section */
3891 tgl@sss.pgh.pa.us 712 : 6 : set_dump_section(optarg, &dopt.dumpSections);
5013 andrew@dunslane.net 713 : 6 : break;
714 : :
3946 simon@2ndQuadrant.co 715 :UBC 0 : case 6: /* snapshot */
716 : 0 : dumpsnapshot = pg_strdup(optarg);
717 : 0 : break;
718 : :
3090 andrew@dunslane.net 719 :CBC 138 : case 7: /* no-sync */
720 : 138 : dosync = false;
721 : 138 : break;
722 : :
2392 723 : 1 : case 8:
724 : 1 : have_extra_float_digits = true;
1505 michael@paquier.xyz 725 [ + - ]: 1 : if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
726 : : &extra_float_digits))
2392 andrew@dunslane.net 727 : 1 : exit_nicely(1);
2392 andrew@dunslane.net 728 :UBC 0 : break;
729 : :
2375 alvherre@alvh.no-ip. 730 :CBC 2 : case 9: /* inserts */
731 : :
732 : : /*
733 : : * dump_inserts also stores --rows-per-insert, careful not to
734 : : * overwrite that.
735 : : */
736 [ + - ]: 2 : if (dopt.dump_inserts == 0)
737 : 2 : dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
738 : 2 : break;
739 : :
740 : 2 : case 10: /* rows per insert */
1505 michael@paquier.xyz 741 [ + + ]: 2 : if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
742 : : &dopt.dump_inserts))
2375 alvherre@alvh.no-ip. 743 : 1 : exit_nicely(1);
744 : 1 : break;
745 : :
1991 746 : 4 : case 11: /* include foreign data */
747 : 4 : simple_string_list_append(&foreign_servers_include_patterns,
748 : : optarg);
749 : 4 : break;
750 : :
907 tgl@sss.pgh.pa.us 751 : 1 : case 12: /* include table(s) and their children */
752 : 1 : simple_string_list_append(&table_include_patterns_and_children,
753 : : optarg);
754 : 1 : dopt.include_everything = false;
755 : 1 : break;
756 : :
757 : 1 : case 13: /* exclude table(s) and their children */
758 : 1 : simple_string_list_append(&table_exclude_patterns_and_children,
759 : : optarg);
760 : 1 : break;
761 : :
762 : 1 : case 14: /* exclude data of table(s) and children */
763 : 1 : simple_string_list_append(&tabledata_exclude_patterns_and_children,
764 : : optarg);
765 : 1 : break;
766 : :
731 nathan@postgresql.or 767 :UBC 0 : case 15:
768 [ # # ]: 0 : if (!parse_sync_method(optarg, &sync_method))
769 : 0 : exit_nicely(1);
770 : 0 : break;
771 : :
647 dgustafsson@postgres 772 :CBC 26 : case 16: /* read object filters from file */
773 : 26 : read_dump_filters(optarg, &dopt);
774 : 22 : break;
775 : :
535 dean.a.rasheed@gmail 776 : 1 : case 17: /* exclude extension(s) */
777 : 1 : simple_string_list_append(&extension_exclude_patterns,
778 : : optarg);
779 : 1 : break;
780 : :
198 jdavis@postgresql.or 781 : 4 : case 18:
782 : 4 : statistics_only = true;
783 : 4 : break;
784 : :
785 : 36 : case 19:
786 : 36 : no_data = true;
787 : 36 : break;
788 : :
789 : 2 : case 20:
790 : 2 : no_schema = true;
791 : 2 : break;
792 : :
793 : 8 : case 21:
794 : 8 : no_statistics = true;
795 : 8 : break;
796 : :
165 797 : 87 : case 22:
798 : 87 : with_statistics = true;
799 : 87 : break;
800 : :
26 nathan@postgresql.or 801 : 26 : case 25:
802 : 26 : dopt.restrict_key = pg_strdup(optarg);
803 : 26 : break;
804 : :
8520 tgl@sss.pgh.pa.us 805 : 1 : default:
806 : : /* getopt_long already emitted a complaint */
1247 807 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4951 rhaas@postgresql.org 808 : 1 : exit_nicely(1);
809 : : }
810 : : }
811 : :
812 : : /*
813 : : * Non-option argument specifies database name as long as it wasn't
814 : : * already specified with -d / --dbname
815 : : */
1808 tgl@sss.pgh.pa.us 816 [ + + + - ]: 222 : if (optind < argc && dopt.cparams.dbname == NULL)
817 : 186 : dopt.cparams.dbname = argv[optind++];
818 : :
819 : : /* Complain if any arguments remain */
5503 820 [ + + ]: 222 : if (optind < argc)
821 : : {
2350 peter@eisentraut.org 822 : 1 : pg_log_error("too many command-line arguments (first is \"%s\")",
823 : : argv[optind]);
1247 tgl@sss.pgh.pa.us 824 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4951 rhaas@postgresql.org 825 : 1 : exit_nicely(1);
826 : : }
827 : :
828 : : /* --column-inserts implies --inserts */
2375 alvherre@alvh.no-ip. 829 [ + + + - ]: 221 : if (dopt.column_inserts && dopt.dump_inserts == 0)
830 : 1 : dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
831 : :
832 : : /* reject conflicting "-only" options */
285 nathan@postgresql.or 833 [ + + + + ]: 221 : if (data_only && schema_only)
1247 tgl@sss.pgh.pa.us 834 : 1 : pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
198 jdavis@postgresql.or 835 [ + + + + ]: 220 : if (schema_only && statistics_only)
836 : 1 : pg_fatal("options -s/--schema-only and --statistics-only cannot be used together");
837 [ + + + + ]: 219 : if (data_only && statistics_only)
838 : 1 : pg_fatal("options -a/--data-only and --statistics-only cannot be used together");
839 : :
840 : : /* reject conflicting "-only" and "no-" options */
841 [ + + - + ]: 218 : if (data_only && no_data)
198 jdavis@postgresql.or 842 :UBC 0 : pg_fatal("options -a/--data-only and --no-data cannot be used together");
198 jdavis@postgresql.or 843 [ + + - + ]:CBC 218 : if (schema_only && no_schema)
198 jdavis@postgresql.or 844 :UBC 0 : pg_fatal("options -s/--schema-only and --no-schema cannot be used together");
198 jdavis@postgresql.or 845 [ + + + + ]:CBC 218 : if (statistics_only && no_statistics)
846 : 1 : pg_fatal("options --statistics-only and --no-statistics cannot be used together");
847 : :
848 : : /* reject conflicting "no-" options */
165 849 [ + + - + ]: 217 : if (with_statistics && no_statistics)
35 jdavis@postgresql.or 850 :UBC 0 : pg_fatal("options --statistics and --no-statistics cannot be used together");
851 : :
852 : : /* reject conflicting "-only" options */
35 jdavis@postgresql.or 853 [ + + - + ]:CBC 217 : if (data_only && with_statistics)
36 jdavis@postgresql.or 854 :UBC 0 : pg_fatal("options %s and %s cannot be used together",
855 : : "-a/--data-only", "--statistics");
35 jdavis@postgresql.or 856 [ + + + + ]:CBC 217 : if (schema_only && with_statistics)
36 857 : 1 : pg_fatal("options %s and %s cannot be used together",
858 : : "-s/--schema-only", "--statistics");
859 : :
285 nathan@postgresql.or 860 [ + + + + ]: 216 : if (schema_only && foreign_servers_include_patterns.head != NULL)
1247 tgl@sss.pgh.pa.us 861 : 1 : pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
862 : :
1991 alvherre@alvh.no-ip. 863 [ + + + + ]: 215 : if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
1247 tgl@sss.pgh.pa.us 864 : 1 : pg_fatal("option --include-foreign-data is not supported with parallel backup");
865 : :
285 nathan@postgresql.or 866 [ + + + + ]: 214 : if (data_only && dopt.outputClean)
1247 tgl@sss.pgh.pa.us 867 : 1 : pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
868 : :
3891 869 [ + + + + ]: 213 : if (dopt.if_exists && !dopt.outputClean)
1247 870 : 1 : pg_fatal("option --if-exists requires option -c/--clean");
871 : :
872 : : /*
873 : : * Set derivative flags. Ambiguous or nonsensical combinations, e.g.
874 : : * "--schema-only --no-schema", will have already caused an error in one
875 : : * of the checks above.
876 : : */
165 jdavis@postgresql.or 877 [ + + + + : 212 : dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
- + ]
35 878 [ + - + + ]: 424 : data_only) && !no_data;
165 879 [ + + + + : 212 : dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
- + ]
35 880 [ + - + + ]: 424 : schema_only) && !no_schema;
165 881 [ - - - - : 212 : dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
+ + ]
882 [ - + + + : 424 : (statistics_only || with_statistics)) && !no_statistics;
+ - ]
883 : :
884 : :
885 : : /*
886 : : * --inserts are already implied above if --column-inserts or
887 : : * --rows-per-insert were specified.
888 : : */
2375 alvherre@alvh.no-ip. 889 [ + + + - ]: 212 : if (dopt.do_nothing && dopt.dump_inserts == 0)
1247 tgl@sss.pgh.pa.us 890 : 1 : pg_fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
891 : :
892 : : /* Identify archive format to emit */
5340 heikki.linnakangas@i 893 : 211 : archiveFormat = parseArchiveFormat(format, &archiveMode);
894 : :
895 : : /* archiveFormat specific setup */
896 [ + + ]: 210 : if (archiveFormat == archNull)
897 : : {
6743 bruce@momjian.us 898 : 154 : plainText = 1;
899 : :
900 : : /*
901 : : * If you don't provide a restrict key, one will be appointed for you.
902 : : */
26 nathan@postgresql.or 903 [ + + ]: 154 : if (!dopt.restrict_key)
904 : 128 : dopt.restrict_key = generate_restrict_key();
905 [ - + ]: 154 : if (!dopt.restrict_key)
26 nathan@postgresql.or 906 :UBC 0 : pg_fatal("could not generate restrict key");
26 nathan@postgresql.or 907 [ - + ]:CBC 154 : if (!valid_restrict_key(dopt.restrict_key))
26 nathan@postgresql.or 908 :UBC 0 : pg_fatal("invalid restrict key");
909 : : }
26 nathan@postgresql.or 910 [ - + ]:CBC 56 : else if (dopt.restrict_key)
26 nathan@postgresql.or 911 :UBC 0 : pg_fatal("option --restrict-key can only be used with --format=plain");
912 : :
913 : : /*
914 : : * Custom and directory formats are compressed by default with gzip when
915 : : * available, not the others. If gzip is not available, no compression is
916 : : * done by default.
917 : : */
863 michael@paquier.xyz 918 [ + + + + ]:CBC 210 : if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
919 [ + + ]: 53 : !user_compression_defined)
920 : : {
921 : : #ifdef HAVE_LIBZ
922 : 46 : compression_algorithm_str = "gzip";
923 : : #else
924 : : compression_algorithm_str = "none";
925 : : #endif
926 : : }
927 : :
928 : : /*
929 : : * Compression options
930 : : */
1009 931 [ + + ]: 210 : if (!parse_compress_algorithm(compression_algorithm_str,
932 : : &compression_algorithm))
933 : 1 : pg_fatal("unrecognized compression algorithm: \"%s\"",
934 : : compression_algorithm_str);
935 : :
936 : 209 : parse_compress_specification(compression_algorithm, compression_detail,
937 : : &compression_spec);
938 : 209 : error_detail = validate_compress_specification(&compression_spec);
939 [ + + ]: 209 : if (error_detail != NULL)
940 : 3 : pg_fatal("invalid compression specification: %s",
941 : : error_detail);
942 : :
885 tomas.vondra@postgre 943 : 206 : error_detail = supports_compression(compression_spec);
944 [ - + ]: 206 : if (error_detail != NULL)
885 tomas.vondra@postgre 945 :UBC 0 : pg_fatal("%s", error_detail);
946 : :
947 : : /*
948 : : * Disable support for zstd workers for now - these are based on
949 : : * threading, and it's unclear how it interacts with parallel dumps on
950 : : * platforms where that relies on threads too (e.g. Windows).
951 : : */
885 tomas.vondra@postgre 952 [ - + ]:CBC 206 : if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
885 tomas.vondra@postgre 953 :UBC 0 : pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
954 : : "workers");
955 : :
956 : : /*
957 : : * If emitting an archive format, we always want to emit a DATABASE item,
958 : : * in case --create is specified at pg_restore time.
959 : : */
2781 tgl@sss.pgh.pa.us 960 [ + + ]:CBC 206 : if (!plainText)
961 : 56 : dopt.outputCreateDB = 1;
962 : :
963 : : /* Parallel backup only in the directory archive format so far */
4549 andrew@dunslane.net 964 [ + + + + ]: 206 : if (archiveFormat != archDirectory && numWorkers > 1)
1247 tgl@sss.pgh.pa.us 965 : 1 : pg_fatal("parallel backup only supported by the directory format");
966 : :
967 : : /* Open the output file */
1009 michael@paquier.xyz 968 : 205 : fout = CreateArchive(filename, archiveFormat, compression_spec,
969 : : dosync, archiveMode, setupDumpWorker, sync_method);
970 : :
971 : : /* Make dump options accessible right away */
3524 tgl@sss.pgh.pa.us 972 : 204 : SetArchiveOptions(fout, &dopt, NULL);
973 : :
974 : : /* Register the cleanup hook */
4918 alvherre@alvh.no-ip. 975 : 204 : on_exit_close_archive(fout);
976 : :
977 : : /* Let the archiver know how noisy to be */
4961 rhaas@postgresql.org 978 : 204 : fout->verbose = g_verbose;
979 : :
980 : :
981 : : /*
982 : : * We allow the server to be back to 9.2, and up to any minor release of
983 : : * our own major version. (See also version check in pg_dumpall.c.)
984 : : */
1362 tgl@sss.pgh.pa.us 985 : 204 : fout->minRemoteVersion = 90200;
4547 heikki.linnakangas@i 986 : 204 : fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
987 : :
4549 andrew@dunslane.net 988 : 204 : fout->numWorkers = numWorkers;
989 : :
990 : : /*
991 : : * Open the database using the Archiver, so it knows about it. Errors mean
992 : : * death.
993 : : */
155 994 : 204 : ConnectDatabaseAhx(fout, &dopt.cparams, false);
3524 tgl@sss.pgh.pa.us 995 : 202 : setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
996 : :
997 : : /*
998 : : * On hot standbys, never try to dump unlogged table data, since it will
999 : : * just throw an error.
1000 : : */
3390 magnus@hagander.net 1001 [ + + ]: 202 : if (fout->isStandby)
1002 : 4 : dopt.no_unlogged_table_data = true;
1003 : :
1004 : : /*
1005 : : * Find the last built-in OID, if needed (prior to 8.1)
1006 : : *
1007 : : * With 8.1 and above, we can just use FirstNormalObjectId - 1.
1008 : : */
1362 tgl@sss.pgh.pa.us 1009 : 202 : g_last_builtin_oid = FirstNormalObjectId - 1;
1010 : :
2350 peter@eisentraut.org 1011 : 202 : pg_log_info("last built-in OID is %u", g_last_builtin_oid);
1012 : :
1013 : : /* Expand schema selection patterns into OID lists */
6907 tgl@sss.pgh.pa.us 1014 [ + + ]: 202 : if (schema_include_patterns.head != NULL)
1015 : : {
4961 rhaas@postgresql.org 1016 : 18 : expand_schema_name_patterns(fout, &schema_include_patterns,
1017 : : &schema_include_oids,
1018 : : strict_names);
6907 tgl@sss.pgh.pa.us 1019 [ + + ]: 12 : if (schema_include_oids.head == NULL)
1247 1020 : 1 : pg_fatal("no matching schemas were found");
1021 : : }
4961 rhaas@postgresql.org 1022 : 195 : expand_schema_name_patterns(fout, &schema_exclude_patterns,
1023 : : &schema_exclude_oids,
1024 : : false);
1025 : : /* non-matching exclusion patterns aren't an error */
1026 : :
1027 : : /* Expand table selection patterns into OID lists */
907 tgl@sss.pgh.pa.us 1028 : 195 : expand_table_name_patterns(fout, &table_include_patterns,
1029 : : &table_include_oids,
1030 : : strict_names, false);
1031 : 190 : expand_table_name_patterns(fout, &table_include_patterns_and_children,
1032 : : &table_include_oids,
1033 : : strict_names, true);
1034 [ + + ]: 190 : if ((table_include_patterns.head != NULL ||
1035 [ + + ]: 179 : table_include_patterns_and_children.head != NULL) &&
1036 [ + + ]: 13 : table_include_oids.head == NULL)
1037 : 2 : pg_fatal("no matching tables were found");
1038 : :
4960 rhaas@postgresql.org 1039 : 188 : expand_table_name_patterns(fout, &table_exclude_patterns,
1040 : : &table_exclude_oids,
1041 : : false, false);
907 tgl@sss.pgh.pa.us 1042 : 188 : expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
1043 : : &table_exclude_oids,
1044 : : false, true);
1045 : :
4960 rhaas@postgresql.org 1046 : 188 : expand_table_name_patterns(fout, &tabledata_exclude_patterns,
1047 : : &tabledata_exclude_oids,
1048 : : false, false);
907 tgl@sss.pgh.pa.us 1049 : 188 : expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
1050 : : &tabledata_exclude_oids,
1051 : : false, true);
1052 : :
1991 alvherre@alvh.no-ip. 1053 : 188 : expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
1054 : : &foreign_servers_include_oids);
1055 : :
1056 : : /* non-matching exclusion patterns aren't an error */
1057 : :
1058 : : /* Expand extension selection patterns into OID lists */
1620 michael@paquier.xyz 1059 [ + + ]: 187 : if (extension_include_patterns.head != NULL)
1060 : : {
1061 : 5 : expand_extension_name_patterns(fout, &extension_include_patterns,
1062 : : &extension_include_oids,
1063 : : strict_names);
1064 [ + + ]: 5 : if (extension_include_oids.head == NULL)
1247 tgl@sss.pgh.pa.us 1065 : 1 : pg_fatal("no matching extensions were found");
1066 : : }
535 dean.a.rasheed@gmail 1067 : 186 : expand_extension_name_patterns(fout, &extension_exclude_patterns,
1068 : : &extension_exclude_oids,
1069 : : false);
1070 : : /* non-matching exclusion patterns aren't an error */
1071 : :
1072 : : /*
1073 : : * Dumping LOs is the default for dumps where an inclusion switch is not
1074 : : * used (an "include everything" dump). -B can be used to exclude LOs
1075 : : * from those dumps. -b can be used to include LOs even when an inclusion
1076 : : * switch is used.
1077 : : *
1078 : : * -s means "schema only" and LOs are data, not schema, so we never
1079 : : * include LOs when -s is used.
1080 : : */
285 nathan@postgresql.or 1081 [ + + + + : 186 : if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
+ + ]
1006 peter@eisentraut.org 1082 : 121 : dopt.outputLOs = true;
1083 : :
1084 : : /*
1085 : : * Collect role names so we can map object owner OIDs to names.
1086 : : */
1345 tgl@sss.pgh.pa.us 1087 : 186 : collectRoleNames(fout);
1088 : :
1089 : : /*
1090 : : * Now scan the database and create DumpableObject structs for all the
1091 : : * objects we intend to dump.
1092 : : */
3524 1093 : 186 : tblinfo = getSchemaData(fout, &numTables);
1094 : :
285 nathan@postgresql.or 1095 [ + + ]: 185 : if (dopt.dumpData)
1096 : : {
2482 andres@anarazel.de 1097 : 145 : getTableData(&dopt, tblinfo, numTables, 0);
4570 kgrittn@postgresql.o 1098 : 145 : buildMatViewRefreshDependencies(fout);
285 nathan@postgresql.or 1099 [ + + ]: 145 : if (!dopt.dumpSchema)
6207 tgl@sss.pgh.pa.us 1100 : 7 : getTableDataFKConstraints();
1101 : : }
1102 : :
285 nathan@postgresql.or 1103 [ + + + + ]: 185 : if (!dopt.dumpData && dopt.sequence_data)
2482 andres@anarazel.de 1104 : 32 : getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
1105 : :
1106 : : /*
1107 : : * For binary upgrade mode, dump pg_largeobject_metadata and the
1108 : : * associated pg_shdepend rows. This is faster to restore than the
1109 : : * equivalent set of large object commands. We can only do this for
1110 : : * upgrades from v12 and newer; in older versions, pg_largeobject_metadata
1111 : : * was created WITH OIDS, so the OID column is hidden and won't be dumped.
1112 : : */
50 nathan@postgresql.or 1113 [ + + + - ]:GNC 185 : if (dopt.binary_upgrade && fout->remoteVersion >= 120000)
1114 : : {
1115 : 36 : TableInfo *lo_metadata = findTableByOid(LargeObjectMetadataRelationId);
1116 : 36 : TableInfo *shdepend = findTableByOid(SharedDependRelationId);
1117 : :
1118 : 36 : makeTableDataInfo(&dopt, lo_metadata);
1119 : 36 : makeTableDataInfo(&dopt, shdepend);
1120 : :
1121 : : /*
1122 : : * Save pg_largeobject_metadata's dump ID for use as a dependency for
1123 : : * pg_shdepend and any large object comments/seclabels.
1124 : : */
1125 : 36 : lo_metadata_dumpId = lo_metadata->dataObj->dobj.dumpId;
1126 : 36 : addObjectDependency(&shdepend->dataObj->dobj, lo_metadata_dumpId);
1127 : :
1128 : : /*
1129 : : * Only dump large object shdepend rows for this database.
1130 : : */
1131 : 36 : shdepend->dataObj->filtercond = "WHERE classid = 'pg_largeobject'::regclass "
1132 : : "AND dbid = (SELECT oid FROM pg_database "
1133 : : " WHERE datname = current_database())";
1134 : : }
1135 : :
1136 : : /*
1137 : : * In binary-upgrade mode, we do not have to worry about the actual LO
1138 : : * data or the associated metadata that resides in the pg_largeobject and
1139 : : * pg_largeobject_metadata tables, respectively.
1140 : : *
1141 : : * However, we do need to collect LO information as there may be comments
1142 : : * or other information on LOs that we do need to dump out.
1143 : : */
1006 peter@eisentraut.org 1144 [ + + + + ]:CBC 185 : if (dopt.outputLOs || dopt.binary_upgrade)
1145 : 157 : getLOs(fout);
1146 : :
1147 : : /*
1148 : : * Collect dependency data to assist in ordering the objects.
1149 : : */
4961 rhaas@postgresql.org 1150 : 185 : getDependencies(fout);
1151 : :
1152 : : /*
1153 : : * Collect ACLs, comments, and security labels, if wanted.
1154 : : */
1370 tgl@sss.pgh.pa.us 1155 [ + + ]: 185 : if (!dopt.aclsSkip)
1156 : 183 : getAdditionalACLs(fout);
1157 [ + - ]: 185 : if (!dopt.no_comments)
1158 : 185 : collectComments(fout);
1159 [ + - ]: 185 : if (!dopt.no_security_labels)
1160 : 185 : collectSecLabels(fout);
1161 : :
1162 : : /* For binary upgrade mode, collect required pg_class information. */
430 nathan@postgresql.or 1163 [ + + ]: 185 : if (dopt.binary_upgrade)
1164 : 36 : collectBinaryUpgradeClassOids(fout);
1165 : :
1166 : : /* Collect sequence information. */
402 1167 : 185 : collectSequences(fout);
1168 : :
1169 : : /* Lastly, create dummy objects to represent the section boundaries */
4821 tgl@sss.pgh.pa.us 1170 : 185 : boundaryObjs = createBoundaryObjects();
1171 : :
1172 : : /* Get pointers to all the known DumpableObjects */
1173 : 185 : getDumpableObjects(&dobjs, &numObjs);
1174 : :
1175 : : /*
1176 : : * Add dummy dependencies to enforce the dump section ordering.
1177 : : */
1178 : 185 : addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
1179 : :
1180 : : /*
1181 : : * Sort the objects into a safe dump order (no forward references).
1182 : : *
1183 : : * We rely on dependency information to help us determine a safe order, so
1184 : : * the initial sort is mostly for cosmetic purposes: we sort by name to
1185 : : * ensure that logically identical schemas will dump identically.
1186 : : */
3251 1187 : 185 : sortDumpableObjectsByTypeName(dobjs, numObjs);
1188 : :
4821 1189 : 185 : sortDumpableObjects(dobjs, numObjs,
1190 : 185 : boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
1191 : :
1192 : : /*
1193 : : * Create archive TOC entries for all the objects to be dumped, in a safe
1194 : : * order.
1195 : : */
1196 : :
1197 : : /*
1198 : : * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
1199 : : */
4961 rhaas@postgresql.org 1200 : 185 : dumpEncoding(fout);
1201 : 185 : dumpStdStrings(fout);
2749 tgl@sss.pgh.pa.us 1202 : 185 : dumpSearchPath(fout);
1203 : :
1204 : : /* The database items are always next, unless we don't want them at all */
2781 1205 [ + + ]: 185 : if (dopt.outputCreateDB)
3524 1206 : 84 : dumpDatabase(fout);
1207 : :
1208 : : /* Now the rearrangeable objects. */
7945 1209 [ + + ]: 819380 : for (i = 0; i < numObjs; i++)
3524 1210 : 819195 : dumpDumpableObject(fout, dobjs[i]);
1211 : :
1212 : : /*
1213 : : * Set up options info to ensure we dump what we want.
1214 : : */
4848 1215 : 185 : ropt = NewRestoreOptions();
1216 : 185 : ropt->filename = filename;
1217 : :
1218 : : /* if you change this list, see dumpOptionsFromRestoreOptions */
1808 1219 [ + + ]: 185 : ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
1220 [ + + ]: 185 : ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
1221 [ + + ]: 185 : ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
1222 [ + + ]: 185 : ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
1223 : 185 : ropt->cparams.promptPassword = dopt.cparams.promptPassword;
3891 1224 : 185 : ropt->dropSchema = dopt.outputClean;
285 nathan@postgresql.or 1225 : 185 : ropt->dumpData = dopt.dumpData;
1226 : 185 : ropt->dumpSchema = dopt.dumpSchema;
198 jdavis@postgresql.or 1227 : 185 : ropt->dumpStatistics = dopt.dumpStatistics;
3891 tgl@sss.pgh.pa.us 1228 : 185 : ropt->if_exists = dopt.if_exists;
1229 : 185 : ropt->column_inserts = dopt.column_inserts;
1230 : 185 : ropt->dumpSections = dopt.dumpSections;
1231 : 185 : ropt->aclsSkip = dopt.aclsSkip;
1232 : 185 : ropt->superuser = dopt.outputSuperuser;
1233 : 185 : ropt->createDB = dopt.outputCreateDB;
1234 : 185 : ropt->noOwner = dopt.outputNoOwner;
1328 michael@paquier.xyz 1235 : 185 : ropt->noTableAm = dopt.outputNoTableAm;
3891 tgl@sss.pgh.pa.us 1236 : 185 : ropt->noTablespace = dopt.outputNoTablespaces;
1237 : 185 : ropt->disable_triggers = dopt.disable_triggers;
1238 : 185 : ropt->use_setsessauth = dopt.use_setsessauth;
1239 : 185 : ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
1240 : 185 : ropt->dump_inserts = dopt.dump_inserts;
2781 1241 : 185 : ropt->no_comments = dopt.no_comments;
174 1242 : 185 : ropt->no_policies = dopt.no_policies;
3039 peter_e@gmx.net 1243 : 185 : ropt->no_publications = dopt.no_publications;
3891 tgl@sss.pgh.pa.us 1244 : 185 : ropt->no_security_labels = dopt.no_security_labels;
3042 peter_e@gmx.net 1245 : 185 : ropt->no_subscriptions = dopt.no_subscriptions;
3891 tgl@sss.pgh.pa.us 1246 : 185 : ropt->lockWaitTimeout = dopt.lockWaitTimeout;
1247 : 185 : ropt->include_everything = dopt.include_everything;
1248 : 185 : ropt->enable_row_security = dopt.enable_row_security;
3301 peter_e@gmx.net 1249 : 185 : ropt->sequence_data = dopt.sequence_data;
3106 sfrost@snowman.net 1250 : 185 : ropt->binary_upgrade = dopt.binary_upgrade;
26 nathan@postgresql.or 1251 [ + + ]: 185 : ropt->restrict_key = dopt.restrict_key ? pg_strdup(dopt.restrict_key) : NULL;
1252 : :
1009 michael@paquier.xyz 1253 : 185 : ropt->compression_spec = compression_spec;
1254 : :
4836 bruce@momjian.us 1255 : 185 : ropt->suppressDumpWarnings = true; /* We've already shown them */
1256 : :
3524 tgl@sss.pgh.pa.us 1257 : 185 : SetArchiveOptions(fout, &dopt, ropt);
1258 : :
1259 : : /* Mark which entries should be output */
1260 : 185 : ProcessArchiveRestoreOptions(fout);
1261 : :
1262 : : /*
1263 : : * The archive's TOC entries are now marked as to which ones will actually
1264 : : * be output, so we can set up their dependency lists properly. This isn't
1265 : : * necessary for plain-text output, though.
1266 : : */
4821 1267 [ + + ]: 185 : if (!plainText)
1268 : 55 : BuildArchiveDependencies(fout);
1269 : :
1270 : : /*
1271 : : * And finally we can do the actual output.
1272 : : *
1273 : : * Note: for non-plain-text output formats, the output file is written
1274 : : * inside CloseArchive(). This is, um, bizarre; but not worth changing
1275 : : * right now.
1276 : : */
4848 1277 [ + + ]: 185 : if (plainText)
38 andrew@dunslane.net 1278 : 130 : RestoreArchive(fout);
1279 : :
3524 tgl@sss.pgh.pa.us 1280 : 184 : CloseArchive(fout);
1281 : :
4951 rhaas@postgresql.org 1282 : 184 : exit_nicely(0);
1283 : : }
1284 : :
1285 : :
1286 : : static void
8520 tgl@sss.pgh.pa.us 1287 : 1 : help(const char *progname)
1288 : : {
79 peter@eisentraut.org 1289 : 1 : printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
8410 peter_e@gmx.net 1290 : 1 : printf(_("Usage:\n"));
8359 1291 : 1 : printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
1292 : :
1293 : 1 : printf(_("\nGeneral options:\n"));
4859 1294 : 1 : printf(_(" -f, --file=FILENAME output file or directory name\n"));
1295 : 1 : printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
1296 : : " plain text (default))\n"));
4549 andrew@dunslane.net 1297 : 1 : printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
4859 peter_e@gmx.net 1298 : 1 : printf(_(" -v, --verbose verbose mode\n"));
4828 1299 : 1 : printf(_(" -V, --version output version information, then exit\n"));
841 peter@eisentraut.org 1300 : 1 : printf(_(" -Z, --compress=METHOD[:DETAIL]\n"
1301 : : " compress as specified\n"));
4859 peter_e@gmx.net 1302 : 1 : printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
3090 andrew@dunslane.net 1303 : 1 : printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
731 nathan@postgresql.or 1304 : 1 : printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
4828 peter_e@gmx.net 1305 : 1 : printf(_(" -?, --help show this help, then exit\n"));
1306 : :
8359 1307 : 1 : printf(_("\nOptions controlling the output content:\n"));
198 jdavis@postgresql.or 1308 : 1 : printf(_(" -a, --data-only dump only the data, not the schema or statistics\n"));
841 peter@eisentraut.org 1309 : 1 : printf(_(" -b, --large-objects include large objects in dump\n"));
1310 : 1 : printf(_(" --blobs (same as --large-objects, deprecated)\n"));
1311 : 1 : printf(_(" -B, --no-large-objects exclude large objects in dump\n"));
1312 : 1 : printf(_(" --no-blobs (same as --no-large-objects, deprecated)\n"));
4859 peter_e@gmx.net 1313 : 1 : printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
1314 : 1 : printf(_(" -C, --create include commands to create database in dump\n"));
1620 michael@paquier.xyz 1315 : 1 : printf(_(" -e, --extension=PATTERN dump the specified extension(s) only\n"));
4859 peter_e@gmx.net 1316 : 1 : printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
2195 peter@eisentraut.org 1317 : 1 : printf(_(" -n, --schema=PATTERN dump the specified schema(s) only\n"));
1318 : 1 : printf(_(" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
4859 peter_e@gmx.net 1319 : 1 : printf(_(" -O, --no-owner skip restoration of object ownership in\n"
1320 : : " plain-text format\n"));
198 jdavis@postgresql.or 1321 : 1 : printf(_(" -s, --schema-only dump only the schema, no data or statistics\n"));
4859 peter_e@gmx.net 1322 : 1 : printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
907 tgl@sss.pgh.pa.us 1323 : 1 : printf(_(" -t, --table=PATTERN dump only the specified table(s)\n"));
2195 peter@eisentraut.org 1324 : 1 : printf(_(" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n"));
4859 peter_e@gmx.net 1325 : 1 : printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
1326 : 1 : printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
1327 : 1 : printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
1328 : 1 : printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
1329 : 1 : printf(_(" --disable-triggers disable triggers during data-only restore\n"));
3643 1330 : 1 : printf(_(" --enable-row-security enable row security (dump only content user has\n"
1331 : : " access to)\n"));
500 peter@eisentraut.org 1332 : 1 : printf(_(" --exclude-extension=PATTERN do NOT dump the specified extension(s)\n"));
907 tgl@sss.pgh.pa.us 1333 : 1 : printf(_(" --exclude-table-and-children=PATTERN\n"
1334 : : " do NOT dump the specified table(s), including\n"
1335 : : " child and partition tables\n"));
2195 peter@eisentraut.org 1336 : 1 : printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
907 tgl@sss.pgh.pa.us 1337 : 1 : printf(_(" --exclude-table-data-and-children=PATTERN\n"
1338 : : " do NOT dump data for the specified table(s),\n"
1339 : : " including child and partition tables\n"));
2392 andrew@dunslane.net 1340 : 1 : printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
647 dgustafsson@postgres 1341 : 1 : printf(_(" --filter=FILENAME include or exclude objects and data from dump\n"
1342 : : " based on expressions in FILENAME\n"));
4205 alvherre@alvh.no-ip. 1343 : 1 : printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
1991 1344 : 1 : printf(_(" --include-foreign-data=PATTERN\n"
1345 : : " include data of foreign tables on foreign\n"
1346 : : " servers matching PATTERN\n"));
4859 peter_e@gmx.net 1347 : 1 : printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
2651 1348 : 1 : printf(_(" --load-via-partition-root load partitions via the root table\n"));
290 bruce@momjian.us 1349 : 1 : printf(_(" --no-comments do not dump comment commands\n"));
198 jdavis@postgresql.or 1350 : 1 : printf(_(" --no-data do not dump data\n"));
174 tgl@sss.pgh.pa.us 1351 : 1 : printf(_(" --no-policies do not dump row security policies\n"));
3039 peter_e@gmx.net 1352 : 1 : printf(_(" --no-publications do not dump publications\n"));
198 jdavis@postgresql.or 1353 : 1 : printf(_(" --no-schema do not dump schema\n"));
4859 peter_e@gmx.net 1354 : 1 : printf(_(" --no-security-labels do not dump security label assignments\n"));
198 jdavis@postgresql.or 1355 : 1 : printf(_(" --no-statistics do not dump statistics\n"));
3042 peter_e@gmx.net 1356 : 1 : printf(_(" --no-subscriptions do not dump subscriptions\n"));
1328 michael@paquier.xyz 1357 : 1 : printf(_(" --no-table-access-method do not dump table access methods\n"));
4859 peter_e@gmx.net 1358 : 1 : printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
1576 peter@eisentraut.org 1359 : 1 : printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
4859 peter_e@gmx.net 1360 : 1 : printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
2612 tmunro@postgresql.or 1361 : 1 : printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
4859 peter_e@gmx.net 1362 : 1 : printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
26 nathan@postgresql.or 1363 : 1 : printf(_(" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n"));
2375 alvherre@alvh.no-ip. 1364 : 1 : printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
4859 peter_e@gmx.net 1365 : 1 : printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
165 nathan@postgresql.or 1366 : 1 : printf(_(" --sequence-data include sequence data in dump\n"));
4859 peter_e@gmx.net 1367 : 1 : printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
3632 1368 : 1 : printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
35 jdavis@postgresql.or 1369 : 1 : printf(_(" --statistics dump the statistics\n"));
198 1370 : 1 : printf(_(" --statistics-only dump only the statistics, not schema or data\n"));
3645 teodor@sigaev.ru 1371 : 1 : printf(_(" --strict-names require table and/or schema include patterns to\n"
1372 : : " match at least one entity each\n"));
841 peter@eisentraut.org 1373 : 1 : printf(_(" --table-and-children=PATTERN dump only the specified table(s), including\n"
1374 : : " child and partition tables\n"));
6909 peter_e@gmx.net 1375 : 1 : printf(_(" --use-set-session-authorization\n"
1376 : : " use SET SESSION AUTHORIZATION commands instead of\n"
1377 : : " ALTER OWNER commands to set ownership\n"));
1378 : :
8359 1379 : 1 : printf(_("\nConnection options:\n"));
4576 heikki.linnakangas@i 1380 : 1 : printf(_(" -d, --dbname=DBNAME database to dump\n"));
8123 bruce@momjian.us 1381 : 1 : printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
8359 peter_e@gmx.net 1382 : 1 : printf(_(" -p, --port=PORT database server port number\n"));
1383 : 1 : printf(_(" -U, --username=NAME connect as specified database user\n"));
6017 1384 : 1 : printf(_(" -w, --no-password never prompt for password\n"));
8359 1385 : 1 : printf(_(" -W, --password force password prompt (should happen automatically)\n"));
5218 1386 : 1 : printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
1387 : :
8081 1388 : 1 : printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1389 : : "variable value is used.\n\n"));
2017 peter@eisentraut.org 1390 : 1 : printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1391 : 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
8520 tgl@sss.pgh.pa.us 1392 : 1 : }
1393 : :
1394 : : static void
3524 1395 : 220 : setup_connection(Archive *AH, const char *dumpencoding,
1396 : : const char *dumpsnapshot, char *use_role)
1397 : : {
1398 : 220 : DumpOptions *dopt = AH->dopt;
4951 rhaas@postgresql.org 1399 : 220 : PGconn *conn = GetConnection(AH);
1400 : : const char *std_strings;
1401 : :
2749 noah@leadboat.com 1402 : 220 : PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1403 : :
1404 : : /*
1405 : : * Set the client encoding if requested.
1406 : : */
4971 rhaas@postgresql.org 1407 [ + + ]: 220 : if (dumpencoding)
1408 : : {
4951 1409 [ - + ]: 20 : if (PQsetClientEncoding(conn, dumpencoding) < 0)
1247 tgl@sss.pgh.pa.us 1410 :UBC 0 : pg_fatal("invalid client encoding \"%s\" specified",
1411 : : dumpencoding);
1412 : : }
1413 : :
1414 : : /*
1415 : : * Get the active encoding and the standard_conforming_strings setting, so
1416 : : * we know how to escape strings.
1417 : : */
4951 rhaas@postgresql.org 1418 :CBC 220 : AH->encoding = PQclientEncoding(conn);
208 andres@anarazel.de 1419 : 220 : setFmtEncoding(AH->encoding);
1420 : :
4951 rhaas@postgresql.org 1421 : 220 : std_strings = PQparameterStatus(conn, "standard_conforming_strings");
4971 1422 [ + - + - ]: 220 : AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1423 : :
1424 : : /*
1425 : : * Set the role if requested. In a parallel dump worker, we'll be passed
1426 : : * use_role == NULL, but AH->use_role is already set (if user specified it
1427 : : * originally) and we should use that.
1428 : : */
4549 andrew@dunslane.net 1429 [ + + + + ]: 220 : if (!use_role && AH->use_role)
1430 : 2 : use_role = AH->use_role;
1431 : :
1432 : : /* Set the role if requested */
1362 tgl@sss.pgh.pa.us 1433 [ + + ]: 220 : if (use_role)
1434 : : {
4971 rhaas@postgresql.org 1435 : 5 : PQExpBuffer query = createPQExpBuffer();
1436 : :
1437 : 5 : appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
4960 1438 : 5 : ExecuteSqlStatement(AH, query->data);
4971 1439 : 5 : destroyPQExpBuffer(query);
1440 : :
1441 : : /* save it for possible later use by parallel workers */
4549 andrew@dunslane.net 1442 [ + + ]: 5 : if (!AH->use_role)
3384 tgl@sss.pgh.pa.us 1443 : 3 : AH->use_role = pg_strdup(use_role);
1444 : : }
1445 : :
1446 : : /* Set the datestyle to ISO to ensure the dump's portability */
4960 rhaas@postgresql.org 1447 : 220 : ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1448 : :
1449 : : /* Likewise, avoid using sql_standard intervalstyle */
1362 tgl@sss.pgh.pa.us 1450 : 220 : ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1451 : :
1452 : : /*
1453 : : * Use an explicitly specified extra_float_digits if it has been provided.
1454 : : * Otherwise, set extra_float_digits so that we can dump float data
1455 : : * exactly (given correctly implemented float I/O code, anyway).
1456 : : */
2392 andrew@dunslane.net 1457 [ - + ]: 220 : if (have_extra_float_digits)
1458 : : {
2392 andrew@dunslane.net 1459 :UBC 0 : PQExpBuffer q = createPQExpBuffer();
1460 : :
1461 : 0 : appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1462 : : extra_float_digits);
1463 : 0 : ExecuteSqlStatement(AH, q->data);
1464 : 0 : destroyPQExpBuffer(q);
1465 : : }
1466 : : else
1362 tgl@sss.pgh.pa.us 1467 :CBC 220 : ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1468 : :
1469 : : /*
1470 : : * Disable synchronized scanning, to prevent unpredictable changes in row
1471 : : * ordering across a dump and reload.
1472 : : */
1473 : 220 : ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1474 : :
1475 : : /*
1476 : : * Disable timeouts if supported.
1477 : : */
3251 1478 : 220 : ExecuteSqlStatement(AH, "SET statement_timeout = 0");
4557 1479 [ + - ]: 220 : if (AH->remoteVersion >= 90300)
1480 : 220 : ExecuteSqlStatement(AH, "SET lock_timeout = 0");
3370 1481 [ + - ]: 220 : if (AH->remoteVersion >= 90600)
1482 : 220 : ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
569 akorotkov@postgresql 1483 [ + - ]: 220 : if (AH->remoteVersion >= 170000)
1484 : 220 : ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
1485 : :
1486 : : /*
1487 : : * Quote all identifiers, if requested.
1488 : : */
1362 tgl@sss.pgh.pa.us 1489 [ + + ]: 220 : if (quote_all_identifiers)
4960 rhaas@postgresql.org 1490 : 34 : ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1491 : :
1492 : : /*
1493 : : * Adjust row-security mode, if supported.
1494 : : */
3853 tgl@sss.pgh.pa.us 1495 [ + - ]: 220 : if (AH->remoteVersion >= 90500)
1496 : : {
1497 [ - + ]: 220 : if (dopt->enable_row_security)
3853 tgl@sss.pgh.pa.us 1498 :UBC 0 : ExecuteSqlStatement(AH, "SET row_security = on");
1499 : : else
3853 tgl@sss.pgh.pa.us 1500 :CBC 220 : ExecuteSqlStatement(AH, "SET row_security = off");
1501 : : }
1502 : :
1503 : : /*
1504 : : * For security reasons, we restrict the expansion of non-system views and
1505 : : * access to foreign tables during the pg_dump process. This restriction
1506 : : * is adjusted when dumping foreign table data.
1507 : : */
397 msawada@postgresql.o 1508 : 220 : set_restrict_relation_kind(AH, "view, foreign-table");
1509 : :
1510 : : /*
1511 : : * Initialize prepared-query state to "nothing prepared". We do this here
1512 : : * so that a parallel dump worker will have its own state.
1513 : : */
1370 tgl@sss.pgh.pa.us 1514 : 220 : AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
1515 : :
1516 : : /*
1517 : : * Start transaction-snapshot mode transaction to dump consistent data.
1518 : : */
4549 andrew@dunslane.net 1519 : 220 : ExecuteSqlStatement(AH, "BEGIN");
1520 : :
1521 : : /*
1522 : : * To support the combination of serializable_deferrable with the jobs
1523 : : * option we use REPEATABLE READ for the worker connections that are
1524 : : * passed a snapshot. As long as the snapshot is acquired in a
1525 : : * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1526 : : * REPEATABLE READ transaction provides the appropriate integrity
1527 : : * guarantees. This is a kluge, but safe for back-patching.
1528 : : */
1362 tgl@sss.pgh.pa.us 1529 [ - + - - ]: 220 : if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1362 tgl@sss.pgh.pa.us 1530 :UBC 0 : ExecuteSqlStatement(AH,
1531 : : "SET TRANSACTION ISOLATION LEVEL "
1532 : : "SERIALIZABLE, READ ONLY, DEFERRABLE");
1533 : : else
4549 andrew@dunslane.net 1534 :CBC 220 : ExecuteSqlStatement(AH,
1535 : : "SET TRANSACTION ISOLATION LEVEL "
1536 : : "REPEATABLE READ, READ ONLY");
1537 : :
1538 : : /*
1539 : : * If user specified a snapshot to use, select that. In a parallel dump
1540 : : * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1541 : : * is already set (if the server can handle it) and we should use that.
1542 : : */
3946 simon@2ndQuadrant.co 1543 [ - + ]: 220 : if (dumpsnapshot)
3384 tgl@sss.pgh.pa.us 1544 :UBC 0 : AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1545 : :
3946 simon@2ndQuadrant.co 1546 [ + + ]:CBC 220 : if (AH->sync_snapshot_id)
1547 : : {
1548 : 18 : PQExpBuffer query = createPQExpBuffer();
1549 : :
2256 drowley@postgresql.o 1550 : 18 : appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
3946 simon@2ndQuadrant.co 1551 : 18 : appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1552 : 18 : ExecuteSqlStatement(AH, query->data);
1553 : 18 : destroyPQExpBuffer(query);
1554 : : }
1361 tgl@sss.pgh.pa.us 1555 [ + + ]: 202 : else if (AH->numWorkers > 1)
1556 : : {
2943 peter_e@gmx.net 1557 [ - + - - ]: 9 : if (AH->isStandby && AH->remoteVersion < 100000)
1247 tgl@sss.pgh.pa.us 1558 :UBC 0 : pg_fatal("parallel dumps from standby servers are not supported by this server version");
3946 simon@2ndQuadrant.co 1559 :CBC 9 : AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1560 : : }
4549 andrew@dunslane.net 1561 : 220 : }
1562 : :
1563 : : /* Set up connection for a parallel worker process */
1564 : : static void
3384 tgl@sss.pgh.pa.us 1565 : 18 : setupDumpWorker(Archive *AH)
1566 : : {
1567 : : /*
1568 : : * We want to re-select all the same values the leader connection is
1569 : : * using. We'll have inherited directly-usable values in
1570 : : * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1571 : : * inherited encoding value back to a string to pass to setup_connection.
1572 : : */
1573 : 18 : setup_connection(AH,
1574 : : pg_encoding_to_char(AH->encoding),
1575 : : NULL,
1576 : : NULL);
4549 andrew@dunslane.net 1577 : 18 : }
1578 : :
1579 : : static char *
1580 : 9 : get_synchronized_snapshot(Archive *fout)
1581 : : {
3384 tgl@sss.pgh.pa.us 1582 : 9 : char *query = "SELECT pg_catalog.pg_export_snapshot()";
1583 : : char *result;
1584 : : PGresult *res;
1585 : :
4549 andrew@dunslane.net 1586 : 9 : res = ExecuteSqlQueryForSingleRow(fout, query);
3384 tgl@sss.pgh.pa.us 1587 : 9 : result = pg_strdup(PQgetvalue(res, 0, 0));
4549 andrew@dunslane.net 1588 : 9 : PQclear(res);
1589 : :
1590 : 9 : return result;
1591 : : }
1592 : :
1593 : : static ArchiveFormat
5340 heikki.linnakangas@i 1594 : 211 : parseArchiveFormat(const char *format, ArchiveMode *mode)
1595 : : {
1596 : : ArchiveFormat archiveFormat;
1597 : :
1598 : 211 : *mode = archModeWrite;
1599 : :
1600 [ + + - + ]: 211 : if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1601 : : {
1602 : : /* This is used by pg_dumpall, and is not documented */
1603 : 43 : archiveFormat = archNull;
1604 : 43 : *mode = archModeAppend;
1605 : : }
1606 [ - + ]: 168 : else if (pg_strcasecmp(format, "c") == 0)
5340 heikki.linnakangas@i 1607 :UBC 0 : archiveFormat = archCustom;
5340 heikki.linnakangas@i 1608 [ + + ]:CBC 168 : else if (pg_strcasecmp(format, "custom") == 0)
1609 : 42 : archiveFormat = archCustom;
1610 [ - + ]: 126 : else if (pg_strcasecmp(format, "d") == 0)
5340 heikki.linnakangas@i 1611 :UBC 0 : archiveFormat = archDirectory;
5340 heikki.linnakangas@i 1612 [ + + ]:CBC 126 : else if (pg_strcasecmp(format, "directory") == 0)
1613 : 11 : archiveFormat = archDirectory;
1614 [ + + ]: 115 : else if (pg_strcasecmp(format, "p") == 0)
1615 : 107 : archiveFormat = archNull;
1616 [ + + ]: 8 : else if (pg_strcasecmp(format, "plain") == 0)
1617 : 4 : archiveFormat = archNull;
1618 [ - + ]: 4 : else if (pg_strcasecmp(format, "t") == 0)
5340 heikki.linnakangas@i 1619 :UBC 0 : archiveFormat = archTar;
5340 heikki.linnakangas@i 1620 [ + + ]:CBC 4 : else if (pg_strcasecmp(format, "tar") == 0)
1621 : 3 : archiveFormat = archTar;
1622 : : else
1247 tgl@sss.pgh.pa.us 1623 : 1 : pg_fatal("invalid output format \"%s\" specified", format);
5340 heikki.linnakangas@i 1624 : 210 : return archiveFormat;
1625 : : }
1626 : :
1627 : : /*
1628 : : * Find the OIDs of all schemas matching the given list of patterns,
1629 : : * and append them to the given OID list.
1630 : : */
1631 : : static void
4961 rhaas@postgresql.org 1632 : 213 : expand_schema_name_patterns(Archive *fout,
1633 : : SimpleStringList *patterns,
1634 : : SimpleOidList *oids,
1635 : : bool strict_names)
1636 : : {
1637 : : PQExpBuffer query;
1638 : : PGresult *res;
1639 : : SimpleStringListCell *cell;
1640 : : int i;
1641 : :
6907 tgl@sss.pgh.pa.us 1642 [ + + ]: 213 : if (patterns->head == NULL)
1643 : 192 : return; /* nothing to do */
1644 : :
1645 : 21 : query = createPQExpBuffer();
1646 : :
1647 : : /*
1648 : : * The loop below runs multiple SELECTs might sometimes result in
1649 : : * duplicate entries in the OID list, but we don't care.
1650 : : */
1651 : :
1652 [ + + ]: 36 : for (cell = patterns->head; cell; cell = cell->next)
1653 : : {
1654 : : PQExpBufferData dbbuf;
1655 : : int dotcnt;
1656 : :
2256 drowley@postgresql.o 1657 : 21 : appendPQExpBufferStr(query,
1658 : : "SELECT oid FROM pg_catalog.pg_namespace n\n");
1235 rhaas@postgresql.org 1659 : 21 : initPQExpBuffer(&dbbuf);
4951 1660 : 21 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1661 : : false, NULL, "n.nspname", NULL, NULL, &dbbuf,
1662 : : &dotcnt);
1235 1663 [ + + ]: 21 : if (dotcnt > 1)
1664 : 2 : pg_fatal("improper qualified name (too many dotted names): %s",
1665 : : cell->val);
1666 [ + + ]: 19 : else if (dotcnt == 1)
1667 : 3 : prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
1668 : 16 : termPQExpBuffer(&dbbuf);
1669 : :
3645 teodor@sigaev.ru 1670 : 16 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1671 [ + + + - ]: 16 : if (strict_names && PQntuples(res) == 0)
1247 tgl@sss.pgh.pa.us 1672 : 1 : pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
1673 : :
3645 teodor@sigaev.ru 1674 [ + + ]: 29 : for (i = 0; i < PQntuples(res); i++)
1675 : : {
1676 : 14 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1677 : : }
1678 : :
1679 : 15 : PQclear(res);
1680 : 15 : resetPQExpBuffer(query);
1681 : : }
1682 : :
6907 tgl@sss.pgh.pa.us 1683 : 15 : destroyPQExpBuffer(query);
1684 : : }
1685 : :
1686 : : /*
1687 : : * Find the OIDs of all extensions matching the given list of patterns,
1688 : : * and append them to the given OID list.
1689 : : */
1690 : : static void
1620 michael@paquier.xyz 1691 : 191 : expand_extension_name_patterns(Archive *fout,
1692 : : SimpleStringList *patterns,
1693 : : SimpleOidList *oids,
1694 : : bool strict_names)
1695 : : {
1696 : : PQExpBuffer query;
1697 : : PGresult *res;
1698 : : SimpleStringListCell *cell;
1699 : : int i;
1700 : :
1701 [ + + ]: 191 : if (patterns->head == NULL)
1702 : 184 : return; /* nothing to do */
1703 : :
1704 : 7 : query = createPQExpBuffer();
1705 : :
1706 : : /*
1707 : : * The loop below runs multiple SELECTs might sometimes result in
1708 : : * duplicate entries in the OID list, but we don't care.
1709 : : */
1710 [ + + ]: 14 : for (cell = patterns->head; cell; cell = cell->next)
1711 : : {
1712 : : int dotcnt;
1713 : :
1714 : 7 : appendPQExpBufferStr(query,
1715 : : "SELECT oid FROM pg_catalog.pg_extension e\n");
1716 : 7 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1717 : : false, NULL, "e.extname", NULL, NULL, NULL,
1718 : : &dotcnt);
1235 rhaas@postgresql.org 1719 [ - + ]: 7 : if (dotcnt > 0)
1235 rhaas@postgresql.org 1720 :UBC 0 : pg_fatal("improper qualified name (too many dotted names): %s",
1721 : : cell->val);
1722 : :
1620 michael@paquier.xyz 1723 :CBC 7 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1724 [ - + - - ]: 7 : if (strict_names && PQntuples(res) == 0)
1247 tgl@sss.pgh.pa.us 1725 :UBC 0 : pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
1726 : :
1620 michael@paquier.xyz 1727 [ + + ]:CBC 13 : for (i = 0; i < PQntuples(res); i++)
1728 : : {
1729 : 6 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1730 : : }
1731 : :
1732 : 7 : PQclear(res);
1733 : 7 : resetPQExpBuffer(query);
1734 : : }
1735 : :
1736 : 7 : destroyPQExpBuffer(query);
1737 : : }
1738 : :
1739 : : /*
1740 : : * Find the OIDs of all foreign servers matching the given list of patterns,
1741 : : * and append them to the given OID list.
1742 : : */
1743 : : static void
1991 alvherre@alvh.no-ip. 1744 : 188 : expand_foreign_server_name_patterns(Archive *fout,
1745 : : SimpleStringList *patterns,
1746 : : SimpleOidList *oids)
1747 : : {
1748 : : PQExpBuffer query;
1749 : : PGresult *res;
1750 : : SimpleStringListCell *cell;
1751 : : int i;
1752 : :
1753 [ + + ]: 188 : if (patterns->head == NULL)
1754 : 185 : return; /* nothing to do */
1755 : :
1756 : 3 : query = createPQExpBuffer();
1757 : :
1758 : : /*
1759 : : * The loop below runs multiple SELECTs might sometimes result in
1760 : : * duplicate entries in the OID list, but we don't care.
1761 : : */
1762 : :
1763 [ + + ]: 5 : for (cell = patterns->head; cell; cell = cell->next)
1764 : : {
1765 : : int dotcnt;
1766 : :
1787 drowley@postgresql.o 1767 : 3 : appendPQExpBufferStr(query,
1768 : : "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
1991 alvherre@alvh.no-ip. 1769 : 3 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1770 : : false, NULL, "s.srvname", NULL, NULL, NULL,
1771 : : &dotcnt);
1235 rhaas@postgresql.org 1772 [ - + ]: 3 : if (dotcnt > 0)
1235 rhaas@postgresql.org 1773 :UBC 0 : pg_fatal("improper qualified name (too many dotted names): %s",
1774 : : cell->val);
1775 : :
1991 alvherre@alvh.no-ip. 1776 :CBC 3 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1777 [ + + ]: 3 : if (PQntuples(res) == 0)
1247 tgl@sss.pgh.pa.us 1778 : 1 : pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
1779 : :
1991 alvherre@alvh.no-ip. 1780 [ + + ]: 4 : for (i = 0; i < PQntuples(res); i++)
1781 : 2 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1782 : :
1783 : 2 : PQclear(res);
1784 : 2 : resetPQExpBuffer(query);
1785 : : }
1786 : :
1787 : 2 : destroyPQExpBuffer(query);
1788 : : }
1789 : :
1790 : : /*
1791 : : * Find the OIDs of all tables matching the given list of patterns,
1792 : : * and append them to the given OID list. See also expand_dbname_patterns()
1793 : : * in pg_dumpall.c
1794 : : */
1795 : : static void
4960 rhaas@postgresql.org 1796 : 1137 : expand_table_name_patterns(Archive *fout,
1797 : : SimpleStringList *patterns, SimpleOidList *oids,
1798 : : bool strict_names, bool with_child_tables)
1799 : : {
1800 : : PQExpBuffer query;
1801 : : PGresult *res;
1802 : : SimpleStringListCell *cell;
1803 : : int i;
1804 : :
6907 tgl@sss.pgh.pa.us 1805 [ + + ]: 1137 : if (patterns->head == NULL)
1806 : 1108 : return; /* nothing to do */
1807 : :
1808 : 29 : query = createPQExpBuffer();
1809 : :
1810 : : /*
1811 : : * this might sometimes result in duplicate entries in the OID list, but
1812 : : * we don't care.
1813 : : */
1814 : :
1815 [ + + ]: 59 : for (cell = patterns->head; cell; cell = cell->next)
1816 : : {
1817 : : PQExpBufferData dbbuf;
1818 : : int dotcnt;
1819 : :
1820 : : /*
1821 : : * Query must remain ABSOLUTELY devoid of unqualified names. This
1822 : : * would be unnecessary given a pg_table_is_visible() variant taking a
1823 : : * search_path argument.
1824 : : *
1825 : : * For with_child_tables, we start with the basic query's results and
1826 : : * recursively search the inheritance tree to add child tables.
1827 : : */
907 1828 [ + + ]: 35 : if (with_child_tables)
1829 : : {
141 drowley@postgresql.o 1830 : 6 : appendPQExpBufferStr(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
1831 : : }
1832 : :
6907 tgl@sss.pgh.pa.us 1833 : 35 : appendPQExpBuffer(query,
1834 : : "SELECT c.oid"
1835 : : "\nFROM pg_catalog.pg_class c"
1836 : : "\n LEFT JOIN pg_catalog.pg_namespace n"
1837 : : "\n ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1838 : : "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1839 : : "\n (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1840 : : RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1841 : : RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1842 : : RELKIND_PARTITIONED_TABLE);
1235 rhaas@postgresql.org 1843 : 35 : initPQExpBuffer(&dbbuf);
4951 1844 : 35 : processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1845 : : false, "n.nspname", "c.relname", NULL,
1846 : : "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
1847 : : &dotcnt);
1235 1848 [ + + ]: 35 : if (dotcnt > 2)
1849 : 1 : pg_fatal("improper relation name (too many dotted names): %s",
1850 : : cell->val);
1851 [ + + ]: 34 : else if (dotcnt == 2)
1852 : 2 : prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
1853 : 32 : termPQExpBuffer(&dbbuf);
1854 : :
907 tgl@sss.pgh.pa.us 1855 [ + + ]: 32 : if (with_child_tables)
1856 : : {
141 drowley@postgresql.o 1857 : 6 : appendPQExpBufferStr(query, "UNION"
1858 : : "\nSELECT i.inhrelid"
1859 : : "\nFROM partition_tree p"
1860 : : "\n JOIN pg_catalog.pg_inherits i"
1861 : : "\n ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
1862 : : "\n)"
1863 : : "\nSELECT relid FROM partition_tree");
1864 : : }
1865 : :
2749 noah@leadboat.com 1866 : 32 : ExecuteSqlStatement(fout, "RESET search_path");
3645 teodor@sigaev.ru 1867 : 32 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2749 noah@leadboat.com 1868 : 32 : PQclear(ExecuteSqlQueryForSingleRow(fout,
1869 : : ALWAYS_SECURE_SEARCH_PATH_SQL));
3645 teodor@sigaev.ru 1870 [ + + + + ]: 32 : if (strict_names && PQntuples(res) == 0)
1247 tgl@sss.pgh.pa.us 1871 : 2 : pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
1872 : :
3645 teodor@sigaev.ru 1873 [ + + ]: 74 : for (i = 0; i < PQntuples(res); i++)
1874 : : {
1875 : 44 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1876 : : }
1877 : :
1878 : 30 : PQclear(res);
1879 : 30 : resetPQExpBuffer(query);
1880 : : }
1881 : :
6907 tgl@sss.pgh.pa.us 1882 : 24 : destroyPQExpBuffer(query);
1883 : : }
1884 : :
1885 : : /*
1886 : : * Verifies that the connected database name matches the given database name,
1887 : : * and if not, dies with an error about the given pattern.
1888 : : *
1889 : : * The 'dbname' argument should be a literal name parsed from 'pattern'.
1890 : : */
1891 : : static void
1235 rhaas@postgresql.org 1892 : 5 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
1893 : : {
1894 : : const char *db;
1895 : :
1896 : 5 : db = PQdb(conn);
1897 [ - + ]: 5 : if (db == NULL)
1235 rhaas@postgresql.org 1898 :UBC 0 : pg_fatal("You are currently not connected to a database.");
1899 : :
1235 rhaas@postgresql.org 1900 [ + - ]:CBC 5 : if (strcmp(db, dbname) != 0)
1901 : 5 : pg_fatal("cross-database references are not implemented: %s",
1902 : : pattern);
1235 rhaas@postgresql.org 1903 :UBC 0 : }
1904 : :
1905 : : /*
1906 : : * checkExtensionMembership
1907 : : * Determine whether object is an extension member, and if so,
1908 : : * record an appropriate dependency and set the object's dump flag.
1909 : : *
1910 : : * It's important to call this for each object that could be an extension
1911 : : * member. Generally, we integrate this with determining the object's
1912 : : * to-be-dumped-ness, since extension membership overrides other rules for that.
1913 : : *
1914 : : * Returns true if object is an extension member, else false.
1915 : : */
1916 : : static bool
3440 sfrost@snowman.net 1917 :CBC 714407 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1918 : : {
3524 tgl@sss.pgh.pa.us 1919 : 714407 : ExtensionInfo *ext = findOwningExtension(dobj->catId);
1920 : :
1921 [ + + ]: 714407 : if (ext == NULL)
1922 : 713614 : return false;
1923 : :
1924 : 793 : dobj->ext_member = true;
1925 : :
1926 : : /* Record dependency so that getDependencies needn't deal with that */
1927 : 793 : addObjectDependency(dobj, ext->dobj.dumpId);
1928 : :
1929 : : /*
1930 : : * In 9.6 and above, mark the member object to have any non-initial ACLs
1931 : : * dumped. (Any initial ACLs will be removed later, using data from
1932 : : * pg_init_privs, so that we'll dump only the delta from the extension's
1933 : : * initial setup.)
1934 : : *
1935 : : * Prior to 9.6, we do not include any extension member components.
1936 : : *
1937 : : * In binary upgrades, we still dump all components of the members
1938 : : * individually, since the idea is to exactly reproduce the database
1939 : : * contents rather than replace the extension contents with something
1940 : : * different.
1941 : : *
1942 : : * Note: it might be interesting someday to implement storage and delta
1943 : : * dumping of extension members' RLS policies and/or security labels.
1944 : : * However there is a pitfall for RLS policies: trying to dump them
1945 : : * requires getting a lock on their tables, and the calling user might not
1946 : : * have privileges for that. We need no lock to examine a table's ACLs,
1947 : : * so the current feature doesn't have a problem of that sort.
1948 : : */
3410 sfrost@snowman.net 1949 [ + + ]: 793 : if (fout->dopt->binary_upgrade)
3524 tgl@sss.pgh.pa.us 1950 : 164 : dobj->dump = ext->dobj.dump;
1951 : : else
1952 : : {
3410 sfrost@snowman.net 1953 [ - + ]: 629 : if (fout->remoteVersion < 90600)
3410 sfrost@snowman.net 1954 :UBC 0 : dobj->dump = DUMP_COMPONENT_NONE;
1955 : : else
663 tgl@sss.pgh.pa.us 1956 :CBC 629 : dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
1957 : : }
1958 : :
3524 1959 : 793 : return true;
1960 : : }
1961 : :
1962 : : /*
1963 : : * selectDumpableNamespace: policy-setting subroutine
1964 : : * Mark a namespace as to be dumped or not
1965 : : */
1966 : : static void
3440 sfrost@snowman.net 1967 : 1434 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1968 : : {
1969 : : /*
1970 : : * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
1971 : : * and (for --clean) a DROP SCHEMA statement. (In the absence of
1972 : : * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
1973 : : */
1531 noah@leadboat.com 1974 : 1434 : nsinfo->create = true;
1975 : :
1976 : : /*
1977 : : * If specific tables are being dumped, do not dump any complete
1978 : : * namespaces. If specific namespaces are being dumped, dump just those
1979 : : * namespaces. Otherwise, dump all non-system namespaces.
1980 : : */
6907 tgl@sss.pgh.pa.us 1981 [ + + ]: 1434 : if (table_include_oids.head != NULL)
3440 sfrost@snowman.net 1982 : 50 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
6907 tgl@sss.pgh.pa.us 1983 [ + + ]: 1384 : else if (schema_include_oids.head != NULL)
3440 sfrost@snowman.net 1984 : 179 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1985 : 179 : simple_oid_list_member(&schema_include_oids,
1986 : : nsinfo->dobj.catId.oid) ?
1987 [ + + ]: 179 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1988 [ + - ]: 1205 : else if (fout->remoteVersion >= 90600 &&
3285 tgl@sss.pgh.pa.us 1989 [ + + ]: 1205 : strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1990 : : {
1991 : : /*
1992 : : * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1993 : : * they are interesting (and not the original ACLs which were set at
1994 : : * initdb time, see pg_init_privs).
1995 : : */
3440 sfrost@snowman.net 1996 : 164 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1997 : : }
6907 tgl@sss.pgh.pa.us 1998 [ + + ]: 1041 : else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1999 [ + + ]: 513 : strcmp(nsinfo->dobj.name, "information_schema") == 0)
2000 : : {
2001 : : /* Other system schemas don't get dumped */
3440 sfrost@snowman.net 2002 : 692 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
2003 : : }
2781 tgl@sss.pgh.pa.us 2004 [ + + ]: 349 : else if (strcmp(nsinfo->dobj.name, "public") == 0)
2005 : : {
2006 : : /*
2007 : : * The public schema is a strange beast that sits in a sort of
2008 : : * no-mans-land between being a system object and a user object.
2009 : : * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
2010 : : * a comment and an indication of ownership. If the owner is the
2011 : : * default, omit that superfluous DUMP_COMPONENT_DEFINITION. Before
2012 : : * v15, the default owner was BOOTSTRAP_SUPERUSERID.
2013 : : */
1531 noah@leadboat.com 2014 : 160 : nsinfo->create = false;
2015 : 160 : nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1458 2016 [ + + ]: 160 : if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
1531 2017 : 112 : nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
2781 tgl@sss.pgh.pa.us 2018 : 160 : nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
2019 : :
2020 : : /*
2021 : : * Also, make like it has a comment even if it doesn't; this is so
2022 : : * that we'll emit a command to drop the comment, if appropriate.
2023 : : * (Without this, we'd not call dumpCommentExtended for it.)
2024 : : */
1370 2025 : 160 : nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
2026 : : }
2027 : : else
3440 sfrost@snowman.net 2028 : 189 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
2029 : :
2030 : : /*
2031 : : * In any case, a namespace can be excluded by an exclusion switch
2032 : : */
2033 [ + + + + ]: 1958 : if (nsinfo->dobj.dump_contains &&
6907 tgl@sss.pgh.pa.us 2034 : 524 : simple_oid_list_member(&schema_exclude_oids,
2035 : : nsinfo->dobj.catId.oid))
3440 sfrost@snowman.net 2036 : 3 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
2037 : :
2038 : : /*
2039 : : * If the schema belongs to an extension, allow extension membership to
2040 : : * override the dump decision for the schema itself. However, this does
2041 : : * not change dump_contains, so this won't change what we do with objects
2042 : : * within the schema. (If they belong to the extension, they'll get
2043 : : * suppressed by it, otherwise not.)
2044 : : */
3285 tgl@sss.pgh.pa.us 2045 : 1434 : (void) checkExtensionMembership(&nsinfo->dobj, fout);
6907 2046 : 1434 : }
2047 : :
2048 : : /*
2049 : : * selectDumpableTable: policy-setting subroutine
2050 : : * Mark a table as to be dumped or not
2051 : : */
2052 : : static void
3440 sfrost@snowman.net 2053 : 49126 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
2054 : : {
2055 [ + + ]: 49126 : if (checkExtensionMembership(&tbinfo->dobj, fout))
3524 tgl@sss.pgh.pa.us 2056 : 225 : return; /* extension membership overrides all else */
2057 : :
2058 : : /*
2059 : : * If specific tables are being dumped, dump just those tables; else, dump
2060 : : * according to the parent namespace's dump flag.
2061 : : */
6907 2062 [ + + ]: 48901 : if (table_include_oids.head != NULL)
2063 : 5178 : tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
2064 : : tbinfo->dobj.catId.oid) ?
3440 sfrost@snowman.net 2065 [ + + ]: 2589 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2066 : : else
2067 : 46312 : tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
2068 : :
2069 : : /*
2070 : : * In any case, a table can be excluded by an exclusion switch
2071 : : */
6907 tgl@sss.pgh.pa.us 2072 [ + + + + ]: 80076 : if (tbinfo->dobj.dump &&
2073 : 31175 : simple_oid_list_member(&table_exclude_oids,
2074 : : tbinfo->dobj.catId.oid))
3440 sfrost@snowman.net 2075 : 12 : tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
2076 : : }
2077 : :
2078 : : /*
2079 : : * selectDumpableType: policy-setting subroutine
2080 : : * Mark a type as to be dumped or not
2081 : : *
2082 : : * If it's a table's rowtype or an autogenerated array type, we also apply a
2083 : : * special type code to facilitate sorting into the desired order. (We don't
2084 : : * want to consider those to be ordinary types because that would bring tables
2085 : : * up into the datatype part of the dump order.) We still set the object's
2086 : : * dump flag; that's not going to cause the dummy type to be dumped, but we
2087 : : * need it so that casts involving such types will be dumped correctly -- see
2088 : : * dumpCast. This means the flag should be set the same as for the underlying
2089 : : * object (the table or base type).
2090 : : */
2091 : : static void
2092 : 134755 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
2093 : : {
2094 : : /* skip complex types, except for standalone composite types */
5736 bruce@momjian.us 2095 [ + + ]: 134755 : if (OidIsValid(tyinfo->typrelid) &&
2096 [ + + ]: 48387 : tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
2097 : : {
5072 tgl@sss.pgh.pa.us 2098 : 48199 : TableInfo *tytable = findTableByOid(tyinfo->typrelid);
2099 : :
5736 bruce@momjian.us 2100 : 48199 : tyinfo->dobj.objType = DO_DUMMY_TYPE;
5072 tgl@sss.pgh.pa.us 2101 [ + - ]: 48199 : if (tytable != NULL)
2102 : 48199 : tyinfo->dobj.dump = tytable->dobj.dump;
2103 : : else
3440 sfrost@snowman.net 2104 :UBC 0 : tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
5072 tgl@sss.pgh.pa.us 2105 :CBC 48199 : return;
2106 : : }
2107 : :
2108 : : /* skip auto-generated array and multirange types */
1721 akorotkov@postgresql 2109 [ + + + + ]: 86556 : if (tyinfo->isArray || tyinfo->isMultirange)
2110 : : {
5736 bruce@momjian.us 2111 : 65920 : tyinfo->dobj.objType = DO_DUMMY_TYPE;
2112 : :
2113 : : /*
2114 : : * Fall through to set the dump flag; we assume that the subsequent
2115 : : * rules will do the same thing as they would for the array's base
2116 : : * type or multirange's range type. (We cannot reliably look up the
2117 : : * base type here, since getTypes may not have processed it yet.)
2118 : : */
2119 : : }
2120 : :
3440 sfrost@snowman.net 2121 [ + + ]: 86556 : if (checkExtensionMembership(&tyinfo->dobj, fout))
3524 tgl@sss.pgh.pa.us 2122 : 150 : return; /* extension membership overrides all else */
2123 : :
2124 : : /* Dump based on if the contents of the namespace are being dumped */
3440 sfrost@snowman.net 2125 : 86406 : tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
2126 : : }
2127 : :
2128 : : /*
2129 : : * selectDumpableDefaultACL: policy-setting subroutine
2130 : : * Mark a default ACL as to be dumped or not
2131 : : *
2132 : : * For per-schema default ACLs, dump if the schema is to be dumped.
2133 : : * Otherwise dump if we are dumping "everything". Note that dumpSchema
2134 : : * and aclsSkip are checked separately.
2135 : : */
2136 : : static void
3524 tgl@sss.pgh.pa.us 2137 : 218 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
2138 : : {
2139 : : /* Default ACLs can't be extension members */
2140 : :
5815 2141 [ + + ]: 218 : if (dinfo->dobj.namespace)
2142 : : /* default ACLs are considered part of the namespace */
3410 sfrost@snowman.net 2143 : 102 : dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
2144 : : else
3440 2145 : 116 : dinfo->dobj.dump = dopt->include_everything ?
2146 [ + + ]: 116 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
5815 tgl@sss.pgh.pa.us 2147 : 218 : }
2148 : :
2149 : : /*
2150 : : * selectDumpableCast: policy-setting subroutine
2151 : : * Mark a cast as to be dumped or not
2152 : : *
2153 : : * Casts do not belong to any particular namespace (since they haven't got
2154 : : * names), nor do they have identifiable owners. To distinguish user-defined
2155 : : * casts from built-in ones, we must resort to checking whether the cast's
2156 : : * OID is in the range reserved for initdb.
2157 : : */
2158 : : static void
3440 sfrost@snowman.net 2159 : 43753 : selectDumpableCast(CastInfo *cast, Archive *fout)
2160 : : {
2161 [ - + ]: 43753 : if (checkExtensionMembership(&cast->dobj, fout))
3524 tgl@sss.pgh.pa.us 2162 :UBC 0 : return; /* extension membership overrides all else */
2163 : :
2164 : : /*
2165 : : * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
2166 : : * support ACLs currently.
2167 : : */
3181 sfrost@snowman.net 2168 [ + + ]:CBC 43753 : if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
3440 2169 : 43660 : cast->dobj.dump = DUMP_COMPONENT_NONE;
2170 : : else
2171 : 93 : cast->dobj.dump = fout->dopt->include_everything ?
2172 [ + + ]: 93 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2173 : : }
2174 : :
2175 : : /*
2176 : : * selectDumpableProcLang: policy-setting subroutine
2177 : : * Mark a procedural language as to be dumped or not
2178 : : *
2179 : : * Procedural languages do not belong to any particular namespace. To
2180 : : * identify built-in languages, we must resort to checking whether the
2181 : : * language's OID is in the range reserved for initdb.
2182 : : */
2183 : : static void
2184 : 236 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
2185 : : {
2186 [ + + ]: 236 : if (checkExtensionMembership(&plang->dobj, fout))
3524 tgl@sss.pgh.pa.us 2187 : 185 : return; /* extension membership overrides all else */
2188 : :
2189 : : /*
2190 : : * Only include procedural languages when we are dumping everything.
2191 : : *
2192 : : * For from-initdb procedural languages, only include ACLs, as we do for
2193 : : * the pg_catalog namespace. We need this because procedural languages do
2194 : : * not live in any namespace.
2195 : : */
3410 sfrost@snowman.net 2196 [ + + ]: 51 : if (!fout->dopt->include_everything)
3440 2197 : 8 : plang->dobj.dump = DUMP_COMPONENT_NONE;
2198 : : else
2199 : : {
3181 2200 [ - + ]: 43 : if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
3410 sfrost@snowman.net 2201 :UBC 0 : plang->dobj.dump = fout->remoteVersion < 90600 ?
2202 [ # # ]: 0 : DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
2203 : : else
3410 sfrost@snowman.net 2204 :CBC 43 : plang->dobj.dump = DUMP_COMPONENT_ALL;
2205 : : }
2206 : : }
2207 : :
2208 : : /*
2209 : : * selectDumpableAccessMethod: policy-setting subroutine
2210 : : * Mark an access method as to be dumped or not
2211 : : *
2212 : : * Access methods do not belong to any particular namespace. To identify
2213 : : * built-in access methods, we must resort to checking whether the
2214 : : * method's OID is in the range reserved for initdb.
2215 : : */
2216 : : static void
3440 2217 : 1429 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
2218 : : {
2219 : : /* see getAccessMethods() comment about v9.6. */
37 noah@leadboat.com 2220 [ - + ]: 1429 : if (fout->remoteVersion < 90600)
2221 : : {
37 noah@leadboat.com 2222 :UBC 0 : method->dobj.dump = DUMP_COMPONENT_NONE;
2223 : 0 : return;
2224 : : }
2225 : :
3440 sfrost@snowman.net 2226 [ + + ]:CBC 1429 : if (checkExtensionMembership(&method->dobj, fout))
3454 alvherre@alvh.no-ip. 2227 : 25 : return; /* extension membership overrides all else */
2228 : :
2229 : : /*
2230 : : * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
2231 : : * they do not support ACLs currently.
2232 : : */
3181 sfrost@snowman.net 2233 [ + + ]: 1404 : if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
3440 2234 : 1295 : method->dobj.dump = DUMP_COMPONENT_NONE;
2235 : : else
2236 : 109 : method->dobj.dump = fout->dopt->include_everything ?
2237 [ + + ]: 109 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2238 : : }
2239 : :
2240 : : /*
2241 : : * selectDumpableExtension: policy-setting subroutine
2242 : : * Mark an extension as to be dumped or not
2243 : : *
2244 : : * Built-in extensions should be skipped except for checking ACLs, since we
2245 : : * assume those will already be installed in the target database. We identify
2246 : : * such extensions by their having OIDs in the range reserved for initdb.
2247 : : * We dump all user-added extensions by default. No extensions are dumped
2248 : : * if include_everything is false (i.e., a --schema or --table switch was
2249 : : * given), except if --extension specifies a list of extensions to dump.
2250 : : */
2251 : : static void
3524 tgl@sss.pgh.pa.us 2252 : 211 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
2253 : : {
2254 : : /*
2255 : : * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
2256 : : * change permissions on their member objects, if they wish to, and have
2257 : : * those changes preserved.
2258 : : */
2781 2259 [ + + ]: 211 : if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
3410 sfrost@snowman.net 2260 : 186 : extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
2261 : : else
2262 : : {
2263 : : /* check if there is a list of extensions to dump */
1620 michael@paquier.xyz 2264 [ + + ]: 25 : if (extension_include_oids.head != NULL)
2265 : 4 : extinfo->dobj.dump = extinfo->dobj.dump_contains =
2266 : 4 : simple_oid_list_member(&extension_include_oids,
2267 : : extinfo->dobj.catId.oid) ?
2268 [ + + ]: 4 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2269 : : else
2270 : 21 : extinfo->dobj.dump = extinfo->dobj.dump_contains =
2271 : 21 : dopt->include_everything ?
2272 [ + + ]: 21 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2273 : :
2274 : : /* check that the extension is not explicitly excluded */
535 dean.a.rasheed@gmail 2275 [ + + + + ]: 46 : if (extinfo->dobj.dump &&
2276 : 21 : simple_oid_list_member(&extension_exclude_oids,
2277 : : extinfo->dobj.catId.oid))
2278 : 2 : extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
2279 : : }
5300 tgl@sss.pgh.pa.us 2280 : 211 : }
2281 : :
2282 : : /*
2283 : : * selectDumpablePublicationObject: policy-setting subroutine
2284 : : * Mark a publication object as to be dumped or not
2285 : : *
2286 : : * A publication can have schemas and tables which have schemas, but those are
2287 : : * ignored in decision making, because publications are only dumped when we are
2288 : : * dumping everything.
2289 : : */
2290 : : static void
1410 akapila@postgresql.o 2291 : 529 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
2292 : : {
3091 peter_e@gmx.net 2293 [ - + ]: 529 : if (checkExtensionMembership(dobj, fout))
3091 peter_e@gmx.net 2294 :UBC 0 : return; /* extension membership overrides all else */
2295 : :
3091 peter_e@gmx.net 2296 :CBC 529 : dobj->dump = fout->dopt->include_everything ?
2297 [ + + ]: 529 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2298 : : }
2299 : :
2300 : : /*
2301 : : * selectDumpableStatisticsObject: policy-setting subroutine
2302 : : * Mark an extended statistics object as to be dumped or not
2303 : : *
2304 : : * We dump an extended statistics object if the schema it's in and the table
2305 : : * it's for are being dumped. (This'll need more thought if statistics
2306 : : * objects ever support cross-table stats.)
2307 : : */
2308 : : static void
617 tgl@sss.pgh.pa.us 2309 : 181 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
2310 : : {
2311 [ - + ]: 181 : if (checkExtensionMembership(&sobj->dobj, fout))
617 tgl@sss.pgh.pa.us 2312 :UBC 0 : return; /* extension membership overrides all else */
2313 : :
617 tgl@sss.pgh.pa.us 2314 :CBC 181 : sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
2315 [ + - ]: 181 : if (sobj->stattable == NULL ||
2316 [ + + ]: 181 : !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
2317 : 28 : sobj->dobj.dump = DUMP_COMPONENT_NONE;
2318 : : }
2319 : :
2320 : : /*
2321 : : * selectDumpableObject: policy-setting subroutine
2322 : : * Mark a generic dumpable object as to be dumped or not
2323 : : *
2324 : : * Use this only for object types without a special-case routine above.
2325 : : */
2326 : : static void
3440 sfrost@snowman.net 2327 : 531163 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
2328 : : {
2329 [ + + ]: 531163 : if (checkExtensionMembership(dobj, fout))
3524 tgl@sss.pgh.pa.us 2330 : 183 : return; /* extension membership overrides all else */
2331 : :
2332 : : /*
2333 : : * Default policy is to dump if parent namespace is dumpable, or for
2334 : : * non-namespace-associated items, dump if we're dumping "everything".
2335 : : */
7128 2336 [ + + ]: 530980 : if (dobj->namespace)
3440 sfrost@snowman.net 2337 : 530264 : dobj->dump = dobj->namespace->dobj.dump_contains;
2338 : : else
2339 : 716 : dobj->dump = fout->dopt->include_everything ?
2340 [ + + ]: 716 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2341 : : }
2342 : :
2343 : : /*
2344 : : * Dump a table's contents for loading using the COPY command
2345 : : * - this routine is called by the Archiver when it wants the table
2346 : : * to be dumped.
2347 : : */
2348 : : static int
1669 peter@eisentraut.org 2349 : 4327 : dumpTableData_copy(Archive *fout, const void *dcontext)
2350 : : {
7945 tgl@sss.pgh.pa.us 2351 : 4327 : TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2352 : 4327 : TableInfo *tbinfo = tdinfo->tdtable;
7857 2353 : 4327 : const char *classname = tbinfo->dobj.name;
8520 2354 : 4327 : PQExpBuffer q = createPQExpBuffer();
2355 : :
2356 : : /*
2357 : : * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
2358 : : * which uses it already.
2359 : : */
4549 andrew@dunslane.net 2360 : 4327 : PQExpBuffer clistBuf = createPQExpBuffer();
4951 rhaas@postgresql.org 2361 : 4327 : PGconn *conn = GetConnection(fout);
2362 : : PGresult *res;
2363 : : int ret;
2364 : : char *copybuf;
2365 : : const char *column_list;
2366 : :
2350 peter@eisentraut.org 2367 : 4327 : pg_log_info("dumping contents of table \"%s.%s\"",
2368 : : tbinfo->dobj.namespace->dobj.name, classname);
2369 : :
2370 : : /*
2371 : : * Specify the column list explicitly so that we have no possibility of
2372 : : * retrieving data in the wrong column order. (The default column
2373 : : * ordering of COPY will not be what we want in certain corner cases
2374 : : * involving ADD COLUMN and inheritance.)
2375 : : */
3251 tgl@sss.pgh.pa.us 2376 : 4327 : column_list = fmtCopyColumnList(tbinfo, clistBuf);
2377 : :
2378 : : /*
2379 : : * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
2380 : : * a filter condition was specified. For other cases a simple COPY
2381 : : * suffices.
2382 : : */
1991 alvherre@alvh.no-ip. 2383 [ + + + + ]: 4327 : if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2384 : : {
2385 : : /* Temporary allows to access to foreign tables to dump data */
397 msawada@postgresql.o 2386 [ + + ]: 37 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2387 : 1 : set_restrict_relation_kind(fout, "view");
2388 : :
5324 tgl@sss.pgh.pa.us 2389 : 37 : appendPQExpBufferStr(q, "COPY (SELECT ");
2390 : : /* klugery to get rid of parens in column list */
2391 [ + - ]: 37 : if (strlen(column_list) > 2)
2392 : : {
2393 : 37 : appendPQExpBufferStr(q, column_list + 1);
2394 : 37 : q->data[q->len - 1] = ' ';
2395 : : }
2396 : : else
5324 tgl@sss.pgh.pa.us 2397 :UBC 0 : appendPQExpBufferStr(q, "* ");
2398 : :
5324 tgl@sss.pgh.pa.us 2399 :CBC 74 : appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
2749 2400 : 37 : fmtQualifiedDumpable(tbinfo),
1991 alvherre@alvh.no-ip. 2401 [ + + ]: 37 : tdinfo->filtercond ? tdinfo->filtercond : "");
2402 : : }
2403 : : else
2404 : : {
8451 bruce@momjian.us 2405 : 4290 : appendPQExpBuffer(q, "COPY %s %s TO stdout;",
2749 tgl@sss.pgh.pa.us 2406 : 4290 : fmtQualifiedDumpable(tbinfo),
2407 : : column_list);
2408 : : }
4960 rhaas@postgresql.org 2409 : 4327 : res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
7127 tgl@sss.pgh.pa.us 2410 : 4326 : PQclear(res);
4549 andrew@dunslane.net 2411 : 4326 : destroyPQExpBuffer(clistBuf);
2412 : :
2413 : : for (;;)
2414 : : {
4951 rhaas@postgresql.org 2415 : 1813263 : ret = PQgetCopyData(conn, ©buf, 0);
2416 : :
7127 tgl@sss.pgh.pa.us 2417 [ + + ]: 1813263 : if (ret < 0)
2418 : 4326 : break; /* done or error */
2419 : :
2420 [ + - ]: 1808937 : if (copybuf)
2421 : : {
2422 : 1808937 : WriteData(fout, copybuf, ret);
2423 : 1808937 : PQfreemem(copybuf);
2424 : : }
2425 : :
2426 : : /* ----------
2427 : : * THROTTLE:
2428 : : *
2429 : : * There was considerable discussion in late July, 2000 regarding
2430 : : * slowing down pg_dump when backing up large tables. Users with both
2431 : : * slow & fast (multi-processor) machines experienced performance
2432 : : * degradation when doing a backup.
2433 : : *
2434 : : * Initial attempts based on sleeping for a number of ms for each ms
2435 : : * of work were deemed too complex, then a simple 'sleep in each loop'
2436 : : * implementation was suggested. The latter failed because the loop
2437 : : * was too tight. Finally, the following was implemented:
2438 : : *
2439 : : * If throttle is non-zero, then
2440 : : * See how long since the last sleep.
2441 : : * Work out how long to sleep (based on ratio).
2442 : : * If sleep is more than 100ms, then
2443 : : * sleep
2444 : : * reset timer
2445 : : * EndIf
2446 : : * EndIf
2447 : : *
2448 : : * where the throttle value was the number of ms to sleep per ms of
2449 : : * work. The calculation was done in each loop.
2450 : : *
2451 : : * Most of the hard work is done in the backend, and this solution
2452 : : * still did not work particularly well: on slow machines, the ratio
2453 : : * was 50:1, and on medium paced machines, 1:1, and on fast
2454 : : * multi-processor machines, it had little or no effect, for reasons
2455 : : * that were unclear.
2456 : : *
2457 : : * Further discussion ensued, and the proposal was dropped.
2458 : : *
2459 : : * For those people who want this feature, it can be implemented using
2460 : : * gettimeofday in each loop, calculating the time since last sleep,
2461 : : * multiplying that by the sleep ratio, then if the result is more
2462 : : * than a preset 'minimum sleep time' (say 100ms), call the 'select'
2463 : : * function to sleep for a subsecond period ie.
2464 : : *
2465 : : * select(0, NULL, NULL, NULL, &tvi);
2466 : : *
2467 : : * This will return after the interval specified in the structure tvi.
2468 : : * Finally, call gettimeofday again to save the 'last sleep time'.
2469 : : * ----------
2470 : : */
2471 : : }
8420 peter_e@gmx.net 2472 : 4326 : archprintf(fout, "\\.\n\n\n");
2473 : :
7127 tgl@sss.pgh.pa.us 2474 [ - + ]: 4326 : if (ret == -2)
2475 : : {
2476 : : /* copy data transfer failed */
2350 peter@eisentraut.org 2477 :UBC 0 : pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
1247 tgl@sss.pgh.pa.us 2478 : 0 : pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2479 : 0 : pg_log_error_detail("Command was: %s", q->data);
4951 rhaas@postgresql.org 2480 : 0 : exit_nicely(1);
2481 : : }
2482 : :
2483 : : /* Check command status and return to normal libpq state */
4951 rhaas@postgresql.org 2484 :CBC 4326 : res = PQgetResult(conn);
4960 2485 [ - + ]: 4326 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
2486 : : {
2350 peter@eisentraut.org 2487 :UBC 0 : pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
1247 tgl@sss.pgh.pa.us 2488 : 0 : pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2489 : 0 : pg_log_error_detail("Command was: %s", q->data);
4951 rhaas@postgresql.org 2490 : 0 : exit_nicely(1);
2491 : : }
8467 bruce@momjian.us 2492 :CBC 4326 : PQclear(res);
2493 : :
2494 : : /* Do this to ensure we've pumped libpq back to idle state */
3383 tgl@sss.pgh.pa.us 2495 [ - + ]: 4326 : if (PQgetResult(conn) != NULL)
2350 peter@eisentraut.org 2496 :UBC 0 : pg_log_warning("unexpected extra results during COPY of table \"%s\"",
2497 : : classname);
2498 : :
8520 tgl@sss.pgh.pa.us 2499 :CBC 4326 : destroyPQExpBuffer(q);
2500 : :
2501 : : /* Revert back the setting */
397 msawada@postgresql.o 2502 [ - + ]: 4326 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
397 msawada@postgresql.o 2503 :UBC 0 : set_restrict_relation_kind(fout, "view, foreign-table");
2504 : :
8520 tgl@sss.pgh.pa.us 2505 :CBC 4326 : return 1;
2506 : : }
2507 : :
2508 : : /*
2509 : : * Dump table data using INSERT commands.
2510 : : *
2511 : : * Caution: when we restore from an archive file direct to database, the
2512 : : * INSERT commands emitted by this function have to be parsed by
2513 : : * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
2514 : : * E'' strings, or dollar-quoted strings. So don't emit anything like that.
2515 : : */
2516 : : static int
1669 peter@eisentraut.org 2517 : 85 : dumpTableData_insert(Archive *fout, const void *dcontext)
2518 : : {
7945 tgl@sss.pgh.pa.us 2519 : 85 : TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2520 : 85 : TableInfo *tbinfo = tdinfo->tdtable;
3524 2521 : 85 : DumpOptions *dopt = fout->dopt;
8520 2522 : 85 : PQExpBuffer q = createPQExpBuffer();
4313 2523 : 85 : PQExpBuffer insertStmt = NULL;
2524 : : char *attgenerated;
2525 : : PGresult *res;
2526 : : int nfields,
2527 : : i;
2375 alvherre@alvh.no-ip. 2528 : 85 : int rows_per_statement = dopt->dump_inserts;
2529 : 85 : int rows_this_statement = 0;
2530 : :
2531 : : /* Temporary allows to access to foreign tables to dump data */
397 msawada@postgresql.o 2532 [ - + ]: 85 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
397 msawada@postgresql.o 2533 :UBC 0 : set_restrict_relation_kind(fout, "view");
2534 : :
2535 : : /*
2536 : : * If we're going to emit INSERTs with column names, the most efficient
2537 : : * way to deal with generated columns is to exclude them entirely. For
2538 : : * INSERTs without column names, we have to emit DEFAULT rather than the
2539 : : * actual column value --- but we can save a few cycles by fetching nulls
2540 : : * rather than the uninteresting-to-us value.
2541 : : */
1384 tgl@sss.pgh.pa.us 2542 :CBC 85 : attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
2543 : 85 : appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
2544 : 85 : nfields = 0;
2545 [ + + ]: 261 : for (i = 0; i < tbinfo->numatts; i++)
2546 : : {
2547 [ + + ]: 176 : if (tbinfo->attisdropped[i])
2548 : 2 : continue;
2549 [ + + + + ]: 174 : if (tbinfo->attgenerated[i] && dopt->column_inserts)
2550 : 8 : continue;
2551 [ + + ]: 166 : if (nfields > 0)
2552 : 88 : appendPQExpBufferStr(q, ", ");
2553 [ + + ]: 166 : if (tbinfo->attgenerated[i])
2554 : 8 : appendPQExpBufferStr(q, "NULL");
2555 : : else
2556 : 158 : appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
2557 : 166 : attgenerated[nfields] = tbinfo->attgenerated[i];
2558 : 166 : nfields++;
2559 : : }
2560 : : /* Servers before 9.4 will complain about zero-column SELECT */
2561 [ + + ]: 85 : if (nfields == 0)
2562 : 7 : appendPQExpBufferStr(q, "NULL");
2563 : 85 : appendPQExpBuffer(q, " FROM ONLY %s",
2749 2564 : 85 : fmtQualifiedDumpable(tbinfo));
5324 2565 [ - + ]: 85 : if (tdinfo->filtercond)
5324 tgl@sss.pgh.pa.us 2566 :UBC 0 : appendPQExpBuffer(q, " %s", tdinfo->filtercond);
2567 : :
4960 rhaas@postgresql.org 2568 :CBC 85 : ExecuteSqlStatement(fout, q->data);
2569 : :
2570 : : while (1)
2571 : : {
2572 : 137 : res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
2573 : : PGRES_TUPLES_OK);
2574 : :
2575 : : /* cross-check field count, allowing for dummy NULL if any */
1384 tgl@sss.pgh.pa.us 2576 [ + + + - ]: 137 : if (nfields != PQnfields(res) &&
2577 [ - + ]: 10 : !(nfields == 0 && PQnfields(res) == 1))
1247 tgl@sss.pgh.pa.us 2578 :UBC 0 : pg_fatal("wrong number of fields retrieved from table \"%s\"",
2579 : : tbinfo->dobj.name);
2580 : :
2581 : : /*
2582 : : * First time through, we build as much of the INSERT statement as
2583 : : * possible in "insertStmt", which we can then just print for each
2584 : : * statement. If the table happens to have zero dumpable columns then
2585 : : * this will be a complete statement, otherwise it will end in
2586 : : * "VALUES" and be ready to have the row's column values printed.
2587 : : */
2375 alvherre@alvh.no-ip. 2588 [ + + ]:CBC 137 : if (insertStmt == NULL)
2589 : : {
2590 : : TableInfo *targettab;
2591 : :
2592 : 85 : insertStmt = createPQExpBuffer();
2593 : :
2594 : : /*
2595 : : * When load-via-partition-root is set or forced, get the root
2596 : : * table name for the partition table, so that we can reload data
2597 : : * through the root table.
2598 : : */
904 tgl@sss.pgh.pa.us 2599 [ + + ]: 85 : if (tbinfo->ispartition &&
2600 [ + - + + ]: 48 : (dopt->load_via_partition_root ||
2601 : 24 : forcePartitionRootLoad(tbinfo)))
2375 alvherre@alvh.no-ip. 2602 : 7 : targettab = getRootTableInfo(tbinfo);
2603 : : else
2604 : 78 : targettab = tbinfo;
2605 : :
2606 : 85 : appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
2607 : 85 : fmtQualifiedDumpable(targettab));
2608 : :
2609 : : /* corner case for zero-column table */
2610 [ + + ]: 85 : if (nfields == 0)
2611 : : {
2612 : 7 : appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
2613 : : }
2614 : : else
2615 : : {
2616 : : /* append the list of column names if required */
2617 [ + + ]: 78 : if (dopt->column_inserts)
2618 : : {
2619 : 35 : appendPQExpBufferChar(insertStmt, '(');
2620 [ + + ]: 105 : for (int field = 0; field < nfields; field++)
2621 : : {
2622 [ + + ]: 70 : if (field > 0)
2623 : 35 : appendPQExpBufferStr(insertStmt, ", ");
2624 : 70 : appendPQExpBufferStr(insertStmt,
2625 : 70 : fmtId(PQfname(res, field)));
2626 : : }
2627 : 35 : appendPQExpBufferStr(insertStmt, ") ");
2628 : : }
2629 : :
2630 [ + + ]: 78 : if (tbinfo->needs_override)
2631 : 2 : appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
2632 : :
2633 : 78 : appendPQExpBufferStr(insertStmt, "VALUES");
2634 : : }
2635 : : }
2636 : :
2637 [ + + ]: 3408 : for (int tuple = 0; tuple < PQntuples(res); tuple++)
2638 : : {
2639 : : /* Write the INSERT if not in the middle of a multi-row INSERT. */
2640 [ + + ]: 3271 : if (rows_this_statement == 0)
2641 : 3265 : archputs(insertStmt->data, fout);
2642 : :
2643 : : /*
2644 : : * If it is zero-column table then we've already written the
2645 : : * complete statement, which will mean we've disobeyed
2646 : : * --rows-per-insert when it's set greater than 1. We do support
2647 : : * a way to make this multi-row with: SELECT UNION ALL SELECT
2648 : : * UNION ALL ... but that's non-standard so we should avoid it
2649 : : * given that using INSERTs is mostly only ever needed for
2650 : : * cross-database exports.
2651 : : */
4313 tgl@sss.pgh.pa.us 2652 [ + + ]: 3271 : if (nfields == 0)
2653 : 6 : continue;
2654 : :
2655 : : /* Emit a row heading */
2375 alvherre@alvh.no-ip. 2656 [ + + ]: 3265 : if (rows_per_statement == 1)
2657 : 3256 : archputs(" (", fout);
2658 [ + + ]: 9 : else if (rows_this_statement > 0)
2659 : 6 : archputs(",\n\t(", fout);
2660 : : else
2661 : 3 : archputs("\n\t(", fout);
2662 : :
2663 [ + + ]: 9849 : for (int field = 0; field < nfields; field++)
2664 : : {
8520 tgl@sss.pgh.pa.us 2665 [ + + ]: 6584 : if (field > 0)
4313 2666 : 3319 : archputs(", ", fout);
1384 2667 [ + + ]: 6584 : if (attgenerated[field])
2668 : : {
2352 peter@eisentraut.org 2669 : 2 : archputs("DEFAULT", fout);
2670 : 2 : continue;
2671 : : }
8520 tgl@sss.pgh.pa.us 2672 [ + + ]: 6582 : if (PQgetisnull(res, tuple, field))
2673 : : {
4313 2674 : 83 : archputs("NULL", fout);
8520 2675 : 83 : continue;
2676 : : }
2677 : :
2678 : : /* XXX This code is partially duplicated in ruleutils.c */
2679 [ + + + + ]: 6499 : switch (PQftype(res, field))
2680 : : {
2681 : 4469 : case INT2OID:
2682 : : case INT4OID:
2683 : : case INT8OID:
2684 : : case OIDOID:
2685 : : case FLOAT4OID:
2686 : : case FLOAT8OID:
2687 : : case NUMERICOID:
2688 : : {
2689 : : /*
2690 : : * These types are printed without quotes unless
2691 : : * they contain values that aren't accepted by the
2692 : : * scanner unquoted (e.g., 'NaN'). Note that
2693 : : * strtod() and friends might accept NaN, so we
2694 : : * can't use that to test.
2695 : : *
2696 : : * In reality we only need to defend against
2697 : : * infinity and NaN, so we need not get too crazy
2698 : : * about pattern matching here.
2699 : : */
8403 bruce@momjian.us 2700 : 4469 : const char *s = PQgetvalue(res, tuple, field);
2701 : :
2702 [ + + ]: 4469 : if (strspn(s, "0123456789 +-eE.") == strlen(s))
4313 tgl@sss.pgh.pa.us 2703 : 4467 : archputs(s, fout);
2704 : : else
8403 bruce@momjian.us 2705 : 2 : archprintf(fout, "'%s'", s);
2706 : : }
2707 : 4469 : break;
2708 : :
8520 tgl@sss.pgh.pa.us 2709 : 2 : case BITOID:
2710 : : case VARBITOID:
2711 : 2 : archprintf(fout, "B'%s'",
2712 : : PQgetvalue(res, tuple, field));
2713 : 2 : break;
2714 : :
8420 peter_e@gmx.net 2715 : 4 : case BOOLOID:
8403 bruce@momjian.us 2716 [ + + ]: 4 : if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
4313 tgl@sss.pgh.pa.us 2717 : 2 : archputs("true", fout);
2718 : : else
2719 : 2 : archputs("false", fout);
8420 peter_e@gmx.net 2720 : 4 : break;
2721 : :
2722 : 2024 : default:
2723 : : /* All other types are printed as string literals. */
8520 tgl@sss.pgh.pa.us 2724 : 2024 : resetPQExpBuffer(q);
7041 2725 : 2024 : appendStringLiteralAH(q,
2726 : : PQgetvalue(res, tuple, field),
2727 : : fout);
7528 2728 : 2024 : archputs(q->data, fout);
8520 2729 : 2024 : break;
2730 : : }
2731 : : }
2732 : :
2733 : : /* Terminate the row ... */
2375 alvherre@alvh.no-ip. 2734 : 3265 : archputs(")", fout);
2735 : :
2736 : : /* ... and the statement, if the target no. of rows is reached */
2737 [ + + ]: 3265 : if (++rows_this_statement >= rows_per_statement)
2738 : : {
2739 [ - + ]: 3258 : if (dopt->do_nothing)
2375 alvherre@alvh.no-ip. 2740 :UBC 0 : archputs(" ON CONFLICT DO NOTHING;\n", fout);
2741 : : else
2375 alvherre@alvh.no-ip. 2742 :CBC 3258 : archputs(";\n", fout);
2743 : : /* Reset the row counter */
2744 : 3258 : rows_this_statement = 0;
2745 : : }
2746 : : }
2747 : :
4960 rhaas@postgresql.org 2748 [ + + ]: 137 : if (PQntuples(res) <= 0)
2749 : : {
2750 : 85 : PQclear(res);
2751 : 85 : break;
2752 : : }
2753 : 52 : PQclear(res);
2754 : : }
2755 : :
2756 : : /* Terminate any statements that didn't make the row count. */
2375 alvherre@alvh.no-ip. 2757 [ + + ]: 85 : if (rows_this_statement > 0)
2758 : : {
2759 [ - + ]: 1 : if (dopt->do_nothing)
2375 alvherre@alvh.no-ip. 2760 :UBC 0 : archputs(" ON CONFLICT DO NOTHING;\n", fout);
2761 : : else
2375 alvherre@alvh.no-ip. 2762 :CBC 1 : archputs(";\n", fout);
2763 : : }
2764 : :
4313 tgl@sss.pgh.pa.us 2765 : 85 : archputs("\n\n", fout);
2766 : :
4960 rhaas@postgresql.org 2767 : 85 : ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2768 : :
8520 tgl@sss.pgh.pa.us 2769 : 85 : destroyPQExpBuffer(q);
4313 2770 [ + - ]: 85 : if (insertStmt != NULL)
2771 : 85 : destroyPQExpBuffer(insertStmt);
1384 2772 : 85 : free(attgenerated);
2773 : :
2774 : : /* Revert back the setting */
397 msawada@postgresql.o 2775 [ - + ]: 85 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
397 msawada@postgresql.o 2776 :UBC 0 : set_restrict_relation_kind(fout, "view, foreign-table");
2777 : :
8520 tgl@sss.pgh.pa.us 2778 :CBC 85 : return 1;
2779 : : }
2780 : :
2781 : : /*
2782 : : * getRootTableInfo:
2783 : : * get the root TableInfo for the given partition table.
2784 : : */
2785 : : static TableInfo *
1669 peter@eisentraut.org 2786 : 91 : getRootTableInfo(const TableInfo *tbinfo)
2787 : : {
2788 : : TableInfo *parentTbinfo;
2789 : :
2945 rhaas@postgresql.org 2790 [ - + ]: 91 : Assert(tbinfo->ispartition);
2791 [ - + ]: 91 : Assert(tbinfo->numParents == 1);
2792 : :
2793 : 91 : parentTbinfo = tbinfo->parents[0];
2794 [ - + ]: 91 : while (parentTbinfo->ispartition)
2795 : : {
2945 rhaas@postgresql.org 2796 [ # # ]:UBC 0 : Assert(parentTbinfo->numParents == 1);
2797 : 0 : parentTbinfo = parentTbinfo->parents[0];
2798 : : }
2799 : :
2945 rhaas@postgresql.org 2800 :CBC 91 : return parentTbinfo;
2801 : : }
2802 : :
2803 : : /*
2804 : : * forcePartitionRootLoad
2805 : : * Check if we must force load_via_partition_root for this partition.
2806 : : *
2807 : : * This is required if any level of ancestral partitioned table has an
2808 : : * unsafe partitioning scheme.
2809 : : */
2810 : : static bool
904 tgl@sss.pgh.pa.us 2811 : 1102 : forcePartitionRootLoad(const TableInfo *tbinfo)
2812 : : {
2813 : : TableInfo *parentTbinfo;
2814 : :
2815 [ - + ]: 1102 : Assert(tbinfo->ispartition);
2816 [ - + ]: 1102 : Assert(tbinfo->numParents == 1);
2817 : :
2818 : 1102 : parentTbinfo = tbinfo->parents[0];
2819 [ + + ]: 1102 : if (parentTbinfo->unsafe_partitions)
2820 : 91 : return true;
2821 [ + + ]: 1227 : while (parentTbinfo->ispartition)
2822 : : {
2823 [ - + ]: 216 : Assert(parentTbinfo->numParents == 1);
2824 : 216 : parentTbinfo = parentTbinfo->parents[0];
2825 [ - + ]: 216 : if (parentTbinfo->unsafe_partitions)
904 tgl@sss.pgh.pa.us 2826 :UBC 0 : return true;
2827 : : }
2828 : :
904 tgl@sss.pgh.pa.us 2829 :CBC 1011 : return false;
2830 : : }
2831 : :
2832 : : /*
2833 : : * dumpTableData -
2834 : : * dump the contents of a single table
2835 : : *
2836 : : * Actually, this just makes an ArchiveEntry for the table contents.
2837 : : */
2838 : : static void
1669 peter@eisentraut.org 2839 : 4496 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
2840 : : {
3524 tgl@sss.pgh.pa.us 2841 : 4496 : DumpOptions *dopt = fout->dopt;
7945 2842 : 4496 : TableInfo *tbinfo = tdinfo->tdtable;
5323 2843 : 4496 : PQExpBuffer copyBuf = createPQExpBuffer();
4549 andrew@dunslane.net 2844 : 4496 : PQExpBuffer clistBuf = createPQExpBuffer();
2845 : : DataDumperPtr dumpFn;
904 tgl@sss.pgh.pa.us 2846 : 4496 : char *tdDefn = NULL;
2847 : : char *copyStmt;
2848 : : const char *copyFrom;
2849 : :
2850 : : /* We had better have loaded per-column details about this table */
1795 2851 [ - + ]: 4496 : Assert(tbinfo->interesting);
2852 : :
2853 : : /*
2854 : : * When load-via-partition-root is set or forced, get the root table name
2855 : : * for the partition table, so that we can reload data through the root
2856 : : * table. Then construct a comment to be inserted into the TOC entry's
2857 : : * defn field, so that such cases can be identified reliably.
2858 : : */
904 2859 [ + + ]: 4496 : if (tbinfo->ispartition &&
2860 [ + - + + ]: 2156 : (dopt->load_via_partition_root ||
2861 : 1078 : forcePartitionRootLoad(tbinfo)))
2862 : 84 : {
2863 : : TableInfo *parentTbinfo;
2864 : : char *sanitized;
2865 : :
2866 : 84 : parentTbinfo = getRootTableInfo(tbinfo);
2867 : 84 : copyFrom = fmtQualifiedDumpable(parentTbinfo);
26 noah@leadboat.com 2868 : 84 : sanitized = sanitize_line(copyFrom, true);
904 tgl@sss.pgh.pa.us 2869 : 84 : printfPQExpBuffer(copyBuf, "-- load via partition root %s",
2870 : : sanitized);
26 noah@leadboat.com 2871 : 84 : free(sanitized);
904 tgl@sss.pgh.pa.us 2872 : 84 : tdDefn = pg_strdup(copyBuf->data);
2873 : : }
2874 : : else
2875 : 4412 : copyFrom = fmtQualifiedDumpable(tbinfo);
2876 : :
1886 alvherre@alvh.no-ip. 2877 [ + + ]: 4496 : if (dopt->dump_inserts == 0)
2878 : : {
2879 : : /* Dump/restore using COPY */
7945 tgl@sss.pgh.pa.us 2880 : 4411 : dumpFn = dumpTableData_copy;
2881 : : /* must use 2 steps here 'cause fmtId is nonreentrant */
904 2882 : 4411 : printfPQExpBuffer(copyBuf, "COPY %s ",
2883 : : copyFrom);
2482 andres@anarazel.de 2884 : 4411 : appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2885 : : fmtCopyColumnList(tbinfo, clistBuf));
7945 tgl@sss.pgh.pa.us 2886 : 4411 : copyStmt = copyBuf->data;
2887 : : }
2888 : : else
2889 : : {
2890 : : /* Restore using INSERT */
2891 : 85 : dumpFn = dumpTableData_insert;
2892 : 85 : copyStmt = NULL;
2893 : : }
2894 : :
2895 : : /*
2896 : : * Note: although the TableDataInfo is a full DumpableObject, we treat its
2897 : : * dependency on its table as "special" and pass it to ArchiveEntry now.
2898 : : * See comments for BuildArchiveDependencies.
2899 : : */
3440 sfrost@snowman.net 2900 [ + - ]: 4496 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2901 : : {
2902 : : TocEntry *te;
2903 : :
2549 tgl@sss.pgh.pa.us 2904 : 4496 : te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 2905 : 4496 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2906 : : .namespace = tbinfo->dobj.namespace->dobj.name,
2907 : : .owner = tbinfo->rolname,
2908 : : .description = "TABLE DATA",
2909 : : .section = SECTION_DATA,
2910 : : .createStmt = tdDefn,
2911 : : .copyStmt = copyStmt,
2912 : : .deps = &(tbinfo->dobj.dumpId),
2913 : : .nDeps = 1,
2914 : : .dumpFn = dumpFn,
2915 : : .dumpArg = tdinfo));
2916 : :
2917 : : /*
2918 : : * Set the TocEntry's dataLength in case we are doing a parallel dump
2919 : : * and want to order dump jobs by table size. We choose to measure
2920 : : * dataLength in table pages (including TOAST pages) during dump, so
2921 : : * no scaling is needed.
2922 : : *
2923 : : * However, relpages is declared as "integer" in pg_class, and hence
2924 : : * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2925 : : * Cast so that we get the right interpretation of table sizes
2926 : : * exceeding INT_MAX pages.
2927 : : */
2549 tgl@sss.pgh.pa.us 2928 : 4496 : te->dataLength = (BlockNumber) tbinfo->relpages;
1370 2929 : 4496 : te->dataLength += (BlockNumber) tbinfo->toastpages;
2930 : :
2931 : : /*
2932 : : * If pgoff_t is only 32 bits wide, the above refinement is useless,
2933 : : * and instead we'd better worry about integer overflow. Clamp to
2934 : : * INT_MAX if the correct result exceeds that.
2935 : : */
2936 : : if (sizeof(te->dataLength) == 4 &&
2937 : : (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
2938 : : te->dataLength < 0))
2939 : : te->dataLength = INT_MAX;
2940 : : }
2941 : :
7945 2942 : 4496 : destroyPQExpBuffer(copyBuf);
4549 andrew@dunslane.net 2943 : 4496 : destroyPQExpBuffer(clistBuf);
7945 tgl@sss.pgh.pa.us 2944 : 4496 : }
2945 : :
2946 : : /*
2947 : : * refreshMatViewData -
2948 : : * load or refresh the contents of a single materialized view
2949 : : *
2950 : : * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2951 : : * statement.
2952 : : */
2953 : : static void
1669 peter@eisentraut.org 2954 : 432 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
2955 : : {
4570 kgrittn@postgresql.o 2956 : 432 : TableInfo *tbinfo = tdinfo->tdtable;
2957 : : PQExpBuffer q;
2958 : :
2959 : : /* If the materialized view is not flagged as populated, skip this. */
4506 tgl@sss.pgh.pa.us 2960 [ + + ]: 432 : if (!tbinfo->relispopulated)
4570 kgrittn@postgresql.o 2961 : 80 : return;
2962 : :
2963 : 352 : q = createPQExpBuffer();
2964 : :
2965 : 352 : appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2749 tgl@sss.pgh.pa.us 2966 : 352 : fmtQualifiedDumpable(tbinfo));
2967 : :
3440 sfrost@snowman.net 2968 [ + - ]: 352 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2969 : 352 : ArchiveEntry(fout,
2970 : : tdinfo->dobj.catId, /* catalog ID */
2999 tgl@sss.pgh.pa.us 2971 : 352 : tdinfo->dobj.dumpId, /* dump ID */
2409 alvherre@alvh.no-ip. 2972 : 352 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2973 : : .namespace = tbinfo->dobj.namespace->dobj.name,
2974 : : .owner = tbinfo->rolname,
2975 : : .description = "MATERIALIZED VIEW DATA",
2976 : : .section = SECTION_POST_DATA,
2977 : : .createStmt = q->data,
2978 : : .deps = tdinfo->dobj.dependencies,
2979 : : .nDeps = tdinfo->dobj.nDeps));
2980 : :
4570 kgrittn@postgresql.o 2981 : 352 : destroyPQExpBuffer(q);
2982 : : }
2983 : :
2984 : : /*
2985 : : * getTableData -
2986 : : * set up dumpable objects representing the contents of tables
2987 : : */
2988 : : static void
2482 andres@anarazel.de 2989 : 177 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2990 : : {
2991 : : int i;
2992 : :
8520 tgl@sss.pgh.pa.us 2993 [ + + ]: 47317 : for (i = 0; i < numTables; i++)
2994 : : {
3301 peter_e@gmx.net 2995 [ + + + + ]: 47140 : if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2996 [ + + ]: 929 : (!relkind || tblinfo[i].relkind == relkind))
2482 andres@anarazel.de 2997 : 6296 : makeTableDataInfo(dopt, &(tblinfo[i]));
2998 : : }
5324 tgl@sss.pgh.pa.us 2999 : 177 : }
3000 : :
3001 : : /*
3002 : : * Make a dumpable object for the data of this specific table
3003 : : *
3004 : : * Note: we make a TableDataInfo if and only if we are going to dump the
3005 : : * table data; the "dump" field in such objects isn't very interesting.
3006 : : */
3007 : : static void
2482 andres@anarazel.de 3008 : 6407 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
3009 : : {
3010 : : TableDataInfo *tdinfo;
3011 : :
3012 : : /*
3013 : : * Nothing to do if we already decided to dump the table. This will
3014 : : * happen for "config" tables.
3015 : : */
4959 tgl@sss.pgh.pa.us 3016 [ + + ]: 6407 : if (tbinfo->dataObj != NULL)
3017 : 1 : return;
3018 : :
3019 : : /* Skip VIEWs (no data to dump) */
3020 [ + + ]: 6406 : if (tbinfo->relkind == RELKIND_VIEW)
3021 : 487 : return;
3022 : : /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
1991 alvherre@alvh.no-ip. 3023 [ + + ]: 5919 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
3024 [ + + ]: 44 : (foreign_servers_include_oids.head == NULL ||
1941 tgl@sss.pgh.pa.us 3025 [ + + ]: 4 : !simple_oid_list_member(&foreign_servers_include_oids,
3026 : : tbinfo->foreign_server)))
4959 3027 : 43 : return;
3028 : : /* Skip partitioned tables (data in partitions) */
3195 rhaas@postgresql.org 3029 [ + + ]: 5876 : if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
3030 : 511 : return;
3031 : :
3032 : : /* Don't dump data in unlogged tables, if so requested */
4959 tgl@sss.pgh.pa.us 3033 [ + + ]: 5365 : if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
3980 alvherre@alvh.no-ip. 3034 [ + + ]: 41 : dopt->no_unlogged_table_data)
4959 tgl@sss.pgh.pa.us 3035 : 18 : return;
3036 : :
3037 : : /* Check that the data is not explicitly excluded */
3038 [ + + ]: 5347 : if (simple_oid_list_member(&tabledata_exclude_oids,
3039 : : tbinfo->dobj.catId.oid))
3040 : 8 : return;
3041 : :
3042 : : /* OK, let's dump it */
5034 bruce@momjian.us 3043 : 5339 : tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
3044 : :
4570 kgrittn@postgresql.o 3045 [ + + ]: 5339 : if (tbinfo->relkind == RELKIND_MATVIEW)
3046 : 432 : tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
3301 peter_e@gmx.net 3047 [ + + ]: 4907 : else if (tbinfo->relkind == RELKIND_SEQUENCE)
3048 : 411 : tdinfo->dobj.objType = DO_SEQUENCE_SET;
3049 : : else
4570 kgrittn@postgresql.o 3050 : 4496 : tdinfo->dobj.objType = DO_TABLE_DATA;
3051 : :
3052 : : /*
3053 : : * Note: use tableoid 0 so that this object won't be mistaken for
3054 : : * something that pg_depend entries apply to.
3055 : : */
5324 tgl@sss.pgh.pa.us 3056 : 5339 : tdinfo->dobj.catId.tableoid = 0;
3057 : 5339 : tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3058 : 5339 : AssignDumpId(&tdinfo->dobj);
3059 : 5339 : tdinfo->dobj.name = tbinfo->dobj.name;
3060 : 5339 : tdinfo->dobj.namespace = tbinfo->dobj.namespace;
3061 : 5339 : tdinfo->tdtable = tbinfo;
5263 bruce@momjian.us 3062 : 5339 : tdinfo->filtercond = NULL; /* might get set later */
5324 tgl@sss.pgh.pa.us 3063 : 5339 : addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
3064 : :
3065 : : /* A TableDataInfo contains data, of course */
1370 3066 : 5339 : tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
3067 : :
5324 3068 : 5339 : tbinfo->dataObj = tdinfo;
3069 : :
3070 : : /*
3071 : : * Materialized view statistics must be restored after the data, because
3072 : : * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
3073 : : *
3074 : : * The dependency is added here because the statistics objects are created
3075 : : * first.
3076 : : */
162 jdavis@postgresql.or 3077 [ + + + + ]: 5339 : if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
3078 : : {
3079 : 350 : tbinfo->stats->section = SECTION_POST_DATA;
3080 : 350 : addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
3081 : : }
3082 : :
3083 : : /* Make sure that we'll collect per-column info for this table. */
1795 tgl@sss.pgh.pa.us 3084 : 5339 : tbinfo->interesting = true;
3085 : : }
3086 : :
3087 : : /*
3088 : : * The refresh for a materialized view must be dependent on the refresh for
3089 : : * any materialized view that this one is dependent on.
3090 : : *
3091 : : * This must be called after all the objects are created, but before they are
3092 : : * sorted.
3093 : : */
3094 : : static void
4570 kgrittn@postgresql.o 3095 : 145 : buildMatViewRefreshDependencies(Archive *fout)
3096 : : {
3097 : : PQExpBuffer query;
3098 : : PGresult *res;
3099 : : int ntups,
3100 : : i;
3101 : : int i_classid,
3102 : : i_objid,
3103 : : i_refobjid;
3104 : :
3105 : : /* No Mat Views before 9.3. */
4560 3106 [ - + ]: 145 : if (fout->remoteVersion < 90300)
4560 kgrittn@postgresql.o 3107 :UBC 0 : return;
3108 : :
4560 kgrittn@postgresql.o 3109 :CBC 145 : query = createPQExpBuffer();
3110 : :
4310 heikki.linnakangas@i 3111 : 145 : appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
3112 : : "( "
3113 : : "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
3114 : : "FROM pg_depend d1 "
3115 : : "JOIN pg_class c1 ON c1.oid = d1.objid "
3116 : : "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
3117 : : " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
3118 : : "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
3119 : : "AND d2.objid = r1.oid "
3120 : : "AND d2.refobjid <> d1.objid "
3121 : : "JOIN pg_class c2 ON c2.oid = d2.refobjid "
3122 : : "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
3123 : : CppAsString2(RELKIND_VIEW) ") "
3124 : : "WHERE d1.classid = 'pg_class'::regclass "
3125 : : "UNION "
3126 : : "SELECT w.objid, d3.refobjid, c3.relkind "
3127 : : "FROM w "
3128 : : "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
3129 : : "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
3130 : : "AND d3.objid = r3.oid "
3131 : : "AND d3.refobjid <> w.refobjid "
3132 : : "JOIN pg_class c3 ON c3.oid = d3.refobjid "
3133 : : "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
3134 : : CppAsString2(RELKIND_VIEW) ") "
3135 : : ") "
3136 : : "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
3137 : : "FROM w "
3138 : : "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
3139 : :
4570 kgrittn@postgresql.o 3140 : 145 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3141 : :
3142 : 145 : ntups = PQntuples(res);
3143 : :
3144 : 145 : i_classid = PQfnumber(res, "classid");
3145 : 145 : i_objid = PQfnumber(res, "objid");
3146 : 145 : i_refobjid = PQfnumber(res, "refobjid");
3147 : :
3148 [ + + ]: 445 : for (i = 0; i < ntups; i++)
3149 : : {
3150 : : CatalogId objId;
3151 : : CatalogId refobjId;
3152 : : DumpableObject *dobj;
3153 : : DumpableObject *refdobj;
3154 : : TableInfo *tbinfo;
3155 : : TableInfo *reftbinfo;
3156 : :
3157 : 300 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
3158 : 300 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
3159 : 300 : refobjId.tableoid = objId.tableoid;
3160 : 300 : refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
3161 : :
3162 : 300 : dobj = findObjectByCatalogId(objId);
3163 [ - + ]: 300 : if (dobj == NULL)
3164 : 48 : continue;
3165 : :
3166 [ - + ]: 300 : Assert(dobj->objType == DO_TABLE);
3167 : 300 : tbinfo = (TableInfo *) dobj;
3168 [ - + ]: 300 : Assert(tbinfo->relkind == RELKIND_MATVIEW);
3169 : 300 : dobj = (DumpableObject *) tbinfo->dataObj;
3170 [ + + ]: 300 : if (dobj == NULL)
3171 : 48 : continue;
3172 [ - + ]: 252 : Assert(dobj->objType == DO_REFRESH_MATVIEW);
3173 : :
3174 : 252 : refdobj = findObjectByCatalogId(refobjId);
3175 [ - + ]: 252 : if (refdobj == NULL)
4570 kgrittn@postgresql.o 3176 :UBC 0 : continue;
3177 : :
4570 kgrittn@postgresql.o 3178 [ - + ]:CBC 252 : Assert(refdobj->objType == DO_TABLE);
3179 : 252 : reftbinfo = (TableInfo *) refdobj;
3180 [ - + ]: 252 : Assert(reftbinfo->relkind == RELKIND_MATVIEW);
3181 : 252 : refdobj = (DumpableObject *) reftbinfo->dataObj;
3182 [ - + ]: 252 : if (refdobj == NULL)
4570 kgrittn@postgresql.o 3183 :UBC 0 : continue;
4570 kgrittn@postgresql.o 3184 [ - + ]:CBC 252 : Assert(refdobj->objType == DO_REFRESH_MATVIEW);
3185 : :
3186 : 252 : addObjectDependency(dobj, refdobj->dumpId);
3187 : :
4506 tgl@sss.pgh.pa.us 3188 [ + + ]: 252 : if (!reftbinfo->relispopulated)
3189 : 40 : tbinfo->relispopulated = false;
3190 : : }
3191 : :
4570 kgrittn@postgresql.o 3192 : 145 : PQclear(res);
3193 : :
3194 : 145 : destroyPQExpBuffer(query);
3195 : : }
3196 : :
3197 : : /*
3198 : : * getTableDataFKConstraints -
3199 : : * add dump-order dependencies reflecting foreign key constraints
3200 : : *
3201 : : * This code is executed only in a data-only dump --- in schema+data dumps
3202 : : * we handle foreign key issues by not creating the FK constraints until
3203 : : * after the data is loaded. In a data-only dump, however, we want to
3204 : : * order the table data objects in such a way that a table's referenced
3205 : : * tables are restored first. (In the presence of circular references or
3206 : : * self-references this may be impossible; we'll detect and complain about
3207 : : * that during the dependency sorting step.)
3208 : : */
3209 : : static void
6207 tgl@sss.pgh.pa.us 3210 : 7 : getTableDataFKConstraints(void)
3211 : : {
3212 : : DumpableObject **dobjs;
3213 : : int numObjs;
3214 : : int i;
3215 : :
3216 : : /* Search through all the dumpable objects for FK constraints */
3217 : 7 : getDumpableObjects(&dobjs, &numObjs);
3218 [ + + ]: 30721 : for (i = 0; i < numObjs; i++)
3219 : : {
3220 [ + + ]: 30714 : if (dobjs[i]->objType == DO_FK_CONSTRAINT)
3221 : : {
3222 : 8 : ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
3223 : : TableInfo *ftable;
3224 : :
3225 : : /* Not interesting unless both tables are to be dumped */
3226 [ + - ]: 8 : if (cinfo->contable == NULL ||
3227 [ + + ]: 8 : cinfo->contable->dataObj == NULL)
3228 : 4 : continue;
3229 : 4 : ftable = findTableByOid(cinfo->confrelid);
3230 [ + - ]: 4 : if (ftable == NULL ||
3231 [ - + ]: 4 : ftable->dataObj == NULL)
6207 tgl@sss.pgh.pa.us 3232 :UBC 0 : continue;
3233 : :
3234 : : /*
3235 : : * Okay, make referencing table's TABLE_DATA object depend on the
3236 : : * referenced table's TABLE_DATA object.
3237 : : */
6207 tgl@sss.pgh.pa.us 3238 :CBC 4 : addObjectDependency(&cinfo->contable->dataObj->dobj,
3239 : 4 : ftable->dataObj->dobj.dumpId);
3240 : : }
3241 : : }
3242 : 7 : free(dobjs);
3243 : 7 : }
3244 : :
3245 : :
3246 : : /*
3247 : : * dumpDatabase:
3248 : : * dump the database definition
3249 : : */
3250 : : static void
3524 3251 : 84 : dumpDatabase(Archive *fout)
3252 : : {
3253 : 84 : DumpOptions *dopt = fout->dopt;
8934 bruce@momjian.us 3254 : 84 : PQExpBuffer dbQry = createPQExpBuffer();
3255 : 84 : PQExpBuffer delQry = createPQExpBuffer();
3256 : 84 : PQExpBuffer creaQry = createPQExpBuffer();
2784 tgl@sss.pgh.pa.us 3257 : 84 : PQExpBuffer labelq = createPQExpBuffer();
4951 rhaas@postgresql.org 3258 : 84 : PGconn *conn = GetConnection(fout);
3259 : : PGresult *res;
3260 : : int i_tableoid,
3261 : : i_oid,
3262 : : i_datname,
3263 : : i_datdba,
3264 : : i_encoding,
3265 : : i_datlocprovider,
3266 : : i_collate,
3267 : : i_ctype,
3268 : : i_datlocale,
3269 : : i_daticurules,
3270 : : i_frozenxid,
3271 : : i_minmxid,
3272 : : i_datacl,
3273 : : i_acldefault,
3274 : : i_datistemplate,
3275 : : i_datconnlimit,
3276 : : i_datcollversion,
3277 : : i_tablespace;
3278 : : CatalogId dbCatId;
3279 : : DumpId dbDumpId;
3280 : : DumpableAcl dbdacl;
3281 : : const char *datname,
3282 : : *dba,
3283 : : *encoding,
3284 : : *datlocprovider,
3285 : : *collate,
3286 : : *ctype,
3287 : : *locale,
3288 : : *icurules,
3289 : : *datistemplate,
3290 : : *datconnlimit,
3291 : : *tablespace;
3292 : : uint32 frozenxid,
3293 : : minmxid;
3294 : : char *qdatname;
3295 : :
2350 peter@eisentraut.org 3296 : 84 : pg_log_info("saving database definition");
3297 : :
3298 : : /*
3299 : : * Fetch the database-level properties for this database.
3300 : : */
1096 drowley@postgresql.o 3301 : 84 : appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
3302 : : "datdba, "
3303 : : "pg_encoding_to_char(encoding) AS encoding, "
3304 : : "datcollate, datctype, datfrozenxid, "
3305 : : "datacl, acldefault('d', datdba) AS acldefault, "
3306 : : "datistemplate, datconnlimit, ");
1370 tgl@sss.pgh.pa.us 3307 [ + - ]: 84 : if (fout->remoteVersion >= 90300)
1096 drowley@postgresql.o 3308 : 84 : appendPQExpBufferStr(dbQry, "datminmxid, ");
3309 : : else
1096 drowley@postgresql.o 3310 :UBC 0 : appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
546 jdavis@postgresql.or 3311 [ + - ]:CBC 84 : if (fout->remoteVersion >= 170000)
3312 : 84 : appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
546 jdavis@postgresql.or 3313 [ # # ]:UBC 0 : else if (fout->remoteVersion >= 150000)
3314 : 0 : appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
3315 : : else
3316 : 0 : appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
913 peter@eisentraut.org 3317 [ + - ]:CBC 84 : if (fout->remoteVersion >= 160000)
3318 : 84 : appendPQExpBufferStr(dbQry, "daticurules, ");
3319 : : else
913 peter@eisentraut.org 3320 :UBC 0 : appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
1096 drowley@postgresql.o 3321 :CBC 84 : appendPQExpBufferStr(dbQry,
3322 : : "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
3323 : : "shobj_description(oid, 'pg_database') AS description "
3324 : : "FROM pg_database "
3325 : : "WHERE datname = current_database()");
3326 : :
4951 rhaas@postgresql.org 3327 : 84 : res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
3328 : :
7945 tgl@sss.pgh.pa.us 3329 : 84 : i_tableoid = PQfnumber(res, "tableoid");
3330 : 84 : i_oid = PQfnumber(res, "oid");
2706 peter_e@gmx.net 3331 : 84 : i_datname = PQfnumber(res, "datname");
1345 tgl@sss.pgh.pa.us 3332 : 84 : i_datdba = PQfnumber(res, "datdba");
8608 3333 : 84 : i_encoding = PQfnumber(res, "encoding");
1269 peter@eisentraut.org 3334 : 84 : i_datlocprovider = PQfnumber(res, "datlocprovider");
6191 heikki.linnakangas@i 3335 : 84 : i_collate = PQfnumber(res, "datcollate");
3336 : 84 : i_ctype = PQfnumber(res, "datctype");
546 jdavis@postgresql.or 3337 : 84 : i_datlocale = PQfnumber(res, "datlocale");
913 peter@eisentraut.org 3338 : 84 : i_daticurules = PQfnumber(res, "daticurules");
6044 bruce@momjian.us 3339 : 84 : i_frozenxid = PQfnumber(res, "datfrozenxid");
4084 3340 : 84 : i_minmxid = PQfnumber(res, "datminmxid");
2784 tgl@sss.pgh.pa.us 3341 : 84 : i_datacl = PQfnumber(res, "datacl");
1370 3342 : 84 : i_acldefault = PQfnumber(res, "acldefault");
2784 3343 : 84 : i_datistemplate = PQfnumber(res, "datistemplate");
3344 : 84 : i_datconnlimit = PQfnumber(res, "datconnlimit");
1300 peter@eisentraut.org 3345 : 84 : i_datcollversion = PQfnumber(res, "datcollversion");
7750 tgl@sss.pgh.pa.us 3346 : 84 : i_tablespace = PQfnumber(res, "tablespace");
3347 : :
7945 3348 : 84 : dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
3349 : 84 : dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2706 peter_e@gmx.net 3350 : 84 : datname = PQgetvalue(res, 0, i_datname);
1345 tgl@sss.pgh.pa.us 3351 : 84 : dba = getRoleName(PQgetvalue(res, 0, i_datdba));
8608 3352 : 84 : encoding = PQgetvalue(res, 0, i_encoding);
1269 peter@eisentraut.org 3353 : 84 : datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
6192 heikki.linnakangas@i 3354 : 84 : collate = PQgetvalue(res, 0, i_collate);
3355 : 84 : ctype = PQgetvalue(res, 0, i_ctype);
546 jdavis@postgresql.or 3356 [ + + ]: 84 : if (!PQgetisnull(res, 0, i_datlocale))
3357 : 14 : locale = PQgetvalue(res, 0, i_datlocale);
3358 : : else
3359 : 70 : locale = NULL;
913 peter@eisentraut.org 3360 [ - + ]: 84 : if (!PQgetisnull(res, 0, i_daticurules))
913 peter@eisentraut.org 3361 :UBC 0 : icurules = PQgetvalue(res, 0, i_daticurules);
3362 : : else
913 peter@eisentraut.org 3363 :CBC 84 : icurules = NULL;
6044 bruce@momjian.us 3364 : 84 : frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
4084 3365 : 84 : minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
1370 tgl@sss.pgh.pa.us 3366 : 84 : dbdacl.acl = PQgetvalue(res, 0, i_datacl);
3367 : 84 : dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
2784 3368 : 84 : datistemplate = PQgetvalue(res, 0, i_datistemplate);
3369 : 84 : datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
7750 3370 : 84 : tablespace = PQgetvalue(res, 0, i_tablespace);
3371 : :
2706 peter_e@gmx.net 3372 : 84 : qdatname = pg_strdup(fmtId(datname));
3373 : :
3374 : : /*
3375 : : * Prepare the CREATE DATABASE command. We must specify OID (if we want
3376 : : * to preserve that), as well as the encoding, locale, and tablespace
3377 : : * since those can't be altered later. Other DB properties are left to
3378 : : * the DATABASE PROPERTIES entry, so that they can be applied after
3379 : : * reconnecting to the target DB.
3380 : : *
3381 : : * For binary upgrade, we use the FILE_COPY strategy because testing has
3382 : : * shown it to be faster. When the server is in binary upgrade mode, it
3383 : : * will also skip the checkpoints this strategy ordinarily performs.
3384 : : */
1321 rhaas@postgresql.org 3385 [ + + ]: 84 : if (dopt->binary_upgrade)
3386 : : {
425 nathan@postgresql.or 3387 : 35 : appendPQExpBuffer(creaQry,
3388 : : "CREATE DATABASE %s WITH TEMPLATE = template0 "
3389 : : "OID = %u STRATEGY = FILE_COPY",
3390 : : qdatname, dbCatId.oid);
3391 : : }
3392 : : else
3393 : : {
1321 rhaas@postgresql.org 3394 : 49 : appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
3395 : : qdatname);
3396 : : }
8295 tgl@sss.pgh.pa.us 3397 [ + - ]: 84 : if (strlen(encoding) > 0)
3398 : : {
4310 heikki.linnakangas@i 3399 : 84 : appendPQExpBufferStr(creaQry, " ENCODING = ");
4961 rhaas@postgresql.org 3400 : 84 : appendStringLiteralAH(creaQry, encoding, fout);
3401 : : }
3402 : :
1269 peter@eisentraut.org 3403 : 84 : appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
542 jdavis@postgresql.or 3404 [ + + ]: 84 : if (datlocprovider[0] == 'b')
3405 : 14 : appendPQExpBufferStr(creaQry, "builtin");
3406 [ + - ]: 70 : else if (datlocprovider[0] == 'c')
1269 peter@eisentraut.org 3407 : 70 : appendPQExpBufferStr(creaQry, "libc");
1269 peter@eisentraut.org 3408 [ # # ]:UBC 0 : else if (datlocprovider[0] == 'i')
3409 : 0 : appendPQExpBufferStr(creaQry, "icu");
3410 : : else
1247 tgl@sss.pgh.pa.us 3411 : 0 : pg_fatal("unrecognized locale provider: %s",
3412 : : datlocprovider);
3413 : :
2237 peter@eisentraut.org 3414 [ + - + - ]:CBC 84 : if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
3415 : : {
3416 : 84 : appendPQExpBufferStr(creaQry, " LOCALE = ");
4961 rhaas@postgresql.org 3417 : 84 : appendStringLiteralAH(creaQry, collate, fout);
3418 : : }
3419 : : else
3420 : : {
2237 peter@eisentraut.org 3421 [ # # ]:UBC 0 : if (strlen(collate) > 0)
3422 : : {
3423 : 0 : appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
3424 : 0 : appendStringLiteralAH(creaQry, collate, fout);
3425 : : }
3426 [ # # ]: 0 : if (strlen(ctype) > 0)
3427 : : {
3428 : 0 : appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
3429 : 0 : appendStringLiteralAH(creaQry, ctype, fout);
3430 : : }
3431 : : }
546 jdavis@postgresql.or 3432 [ + + ]:CBC 84 : if (locale)
3433 : : {
542 3434 [ + - ]: 14 : if (datlocprovider[0] == 'b')
3435 : 14 : appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
3436 : : else
542 jdavis@postgresql.or 3437 :UBC 0 : appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
3438 : :
546 jdavis@postgresql.or 3439 :CBC 14 : appendStringLiteralAH(creaQry, locale, fout);
3440 : : }
3441 : :
913 peter@eisentraut.org 3442 [ - + ]: 84 : if (icurules)
3443 : : {
913 peter@eisentraut.org 3444 :UBC 0 : appendPQExpBufferStr(creaQry, " ICU_RULES = ");
3445 : 0 : appendStringLiteralAH(creaQry, icurules, fout);
3446 : : }
3447 : :
3448 : : /*
3449 : : * For binary upgrade, carry over the collation version. For normal
3450 : : * dump/restore, omit the version, so that it is computed upon restore.
3451 : : */
1300 peter@eisentraut.org 3452 [ + + ]:CBC 84 : if (dopt->binary_upgrade)
3453 : : {
3454 [ + + ]: 35 : if (!PQgetisnull(res, 0, i_datcollversion))
3455 : : {
3456 : 6 : appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
3457 : 6 : appendStringLiteralAH(creaQry,
3458 : : PQgetvalue(res, 0, i_datcollversion),
3459 : : fout);
3460 : : }
3461 : : }
3462 : :
3463 : : /*
3464 : : * Note: looking at dopt->outputNoTablespaces here is completely the wrong
3465 : : * thing; the decision whether to specify a tablespace should be left till
3466 : : * pg_restore, so that pg_restore --no-tablespaces applies. Ideally we'd
3467 : : * label the DATABASE entry with the tablespace and let the normal
3468 : : * tablespace selection logic work ... but CREATE DATABASE doesn't pay
3469 : : * attention to default_tablespace, so that won't work.
3470 : : */
3285 tgl@sss.pgh.pa.us 3471 [ + - + + ]: 84 : if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
3285 tgl@sss.pgh.pa.us 3472 [ + - ]:GBC 5 : !dopt->outputNoTablespaces)
7628 3473 : 5 : appendPQExpBuffer(creaQry, " TABLESPACE = %s",
3474 : : fmtId(tablespace));
4310 heikki.linnakangas@i 3475 :CBC 84 : appendPQExpBufferStr(creaQry, ";\n");
3476 : :
8608 tgl@sss.pgh.pa.us 3477 : 84 : appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
3478 : : qdatname);
3479 : :
7945 3480 : 84 : dbDumpId = createDumpId();
3481 : :
4961 rhaas@postgresql.org 3482 : 84 : ArchiveEntry(fout,
3483 : : dbCatId, /* catalog ID */
3484 : : dbDumpId, /* dump ID */
2409 alvherre@alvh.no-ip. 3485 : 84 : ARCHIVE_OPTS(.tag = datname,
3486 : : .owner = dba,
3487 : : .description = "DATABASE",
3488 : : .section = SECTION_PRE_DATA,
3489 : : .createStmt = creaQry->data,
3490 : : .dropStmt = delQry->data));
3491 : :
3492 : : /* Compute correct tag for archive entry */
2784 tgl@sss.pgh.pa.us 3493 : 84 : appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
3494 : :
3495 : : /* Dump DB comment if any */
3496 : : {
3497 : : /*
3498 : : * 8.2 and up keep comments on shared objects in a shared table, so we
3499 : : * cannot use the dumpComment() code used for other database objects.
3500 : : * Be careful that the ArchiveEntry parameters match that function.
3501 : : */
3502 : 84 : char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
3503 : :
2781 3504 [ + - + + : 84 : if (comment && *comment && !dopt->no_comments)
+ - ]
3505 : : {
2784 3506 : 39 : resetPQExpBuffer(dbQry);
3507 : :
3508 : : /*
3509 : : * Generates warning when loaded into a differently-named
3510 : : * database.
3511 : : */
3512 : 39 : appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
3513 : 39 : appendStringLiteralAH(dbQry, comment, fout);
3514 : 39 : appendPQExpBufferStr(dbQry, ";\n");
3515 : :
3516 : 39 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 3517 : 39 : ARCHIVE_OPTS(.tag = labelq->data,
3518 : : .owner = dba,
3519 : : .description = "COMMENT",
3520 : : .section = SECTION_NONE,
3521 : : .createStmt = dbQry->data,
3522 : : .deps = &dbDumpId,
3523 : : .nDeps = 1));
3524 : : }
3525 : : }
3526 : :
3527 : : /* Dump DB security label, if enabled */
1362 tgl@sss.pgh.pa.us 3528 [ + - ]: 84 : if (!dopt->no_security_labels)
3529 : : {
3530 : : PGresult *shres;
3531 : : PQExpBuffer seclabelQry;
3532 : :
2784 3533 : 84 : seclabelQry = createPQExpBuffer();
3534 : :
1838 peter@eisentraut.org 3535 : 84 : buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
2784 tgl@sss.pgh.pa.us 3536 : 84 : shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
3537 : 84 : resetPQExpBuffer(seclabelQry);
3538 : 84 : emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
3539 [ - + ]: 84 : if (seclabelQry->len > 0)
2784 tgl@sss.pgh.pa.us 3540 :UBC 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 3541 : 0 : ARCHIVE_OPTS(.tag = labelq->data,
3542 : : .owner = dba,
3543 : : .description = "SECURITY LABEL",
3544 : : .section = SECTION_NONE,
3545 : : .createStmt = seclabelQry->data,
3546 : : .deps = &dbDumpId,
3547 : : .nDeps = 1));
2784 tgl@sss.pgh.pa.us 3548 :CBC 84 : destroyPQExpBuffer(seclabelQry);
3549 : 84 : PQclear(shres);
3550 : : }
3551 : :
3552 : : /*
3553 : : * Dump ACL if any. Note that we do not support initial privileges
3554 : : * (pg_init_privs) on databases.
3555 : : */
1370 3556 : 84 : dbdacl.privtype = 0;
3557 : 84 : dbdacl.initprivs = NULL;
3558 : :
1883 3559 : 84 : dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
3560 : : qdatname, NULL, NULL,
3561 : : NULL, dba, &dbdacl);
3562 : :
3563 : : /*
3564 : : * Now construct a DATABASE PROPERTIES archive entry to restore any
3565 : : * non-default database-level properties. (The reason this must be
3566 : : * separate is that we cannot put any additional commands into the TOC
3567 : : * entry that has CREATE DATABASE. pg_restore would execute such a group
3568 : : * in an implicit transaction block, and the backend won't allow CREATE
3569 : : * DATABASE in that context.)
3570 : : */
2784 3571 : 84 : resetPQExpBuffer(creaQry);
3572 : 84 : resetPQExpBuffer(delQry);
3573 : :
3574 [ + - - + ]: 84 : if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2784 tgl@sss.pgh.pa.us 3575 :UBC 0 : appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
3576 : : qdatname, datconnlimit);
3577 : :
2784 tgl@sss.pgh.pa.us 3578 [ + + ]:CBC 84 : if (strcmp(datistemplate, "t") == 0)
3579 : : {
3580 : 10 : appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
3581 : : qdatname);
3582 : :
3583 : : /*
3584 : : * The backend won't accept DROP DATABASE on a template database. We
3585 : : * can deal with that by removing the template marking before the DROP
3586 : : * gets issued. We'd prefer to use ALTER DATABASE IF EXISTS here, but
3587 : : * since no such command is currently supported, fake it with a direct
3588 : : * UPDATE on pg_database.
3589 : : */
3590 : 10 : appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
3591 : : "SET datistemplate = false WHERE datname = ");
3592 : 10 : appendStringLiteralAH(delQry, datname, fout);
3593 : 10 : appendPQExpBufferStr(delQry, ";\n");
3594 : : }
3595 : :
3596 : : /*
3597 : : * We do not restore pg_database.dathasloginevt because it is set
3598 : : * automatically on login event trigger creation.
3599 : : */
3600 : :
3601 : : /* Add database-specific SET options */
3602 : 84 : dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
3603 : :
3604 : : /*
3605 : : * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
3606 : : * entry, too, for lack of a better place.
3607 : : */
3608 [ + + ]: 84 : if (dopt->binary_upgrade)
3609 : : {
3610 : 35 : appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
3611 : 35 : appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
3612 : : "SET datfrozenxid = '%u', datminmxid = '%u'\n"
3613 : : "WHERE datname = ",
3614 : : frozenxid, minmxid);
3615 : 35 : appendStringLiteralAH(creaQry, datname, fout);
3616 : 35 : appendPQExpBufferStr(creaQry, ";\n");
3617 : : }
3618 : :
3619 [ + + ]: 84 : if (creaQry->len > 0)
3620 : 39 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 3621 : 39 : ARCHIVE_OPTS(.tag = datname,
3622 : : .owner = dba,
3623 : : .description = "DATABASE PROPERTIES",
3624 : : .section = SECTION_PRE_DATA,
3625 : : .createStmt = creaQry->data,
3626 : : .dropStmt = delQry->data,
3627 : : .deps = &dbDumpId));
3628 : :
3629 : : /*
3630 : : * pg_largeobject comes from the old system intact, so set its
3631 : : * relfrozenxids, relminmxids and relfilenode.
3632 : : */
3980 3633 [ + + ]: 84 : if (dopt->binary_upgrade)
3634 : : {
3635 : : PGresult *lo_res;
5892 bruce@momjian.us 3636 : 35 : PQExpBuffer loFrozenQry = createPQExpBuffer();
3637 : 35 : PQExpBuffer loOutQry = createPQExpBuffer();
1135 rhaas@postgresql.org 3638 : 35 : PQExpBuffer loHorizonQry = createPQExpBuffer();
3639 : : int ii_relfrozenxid,
3640 : : ii_relfilenode,
3641 : : ii_oid,
3642 : : ii_relminmxid;
3643 : :
3644 : : /*
3645 : : * pg_largeobject
3646 : : */
4084 bruce@momjian.us 3647 [ + - ]: 35 : if (fout->remoteVersion >= 90300)
1156 rhaas@postgresql.org 3648 : 35 : appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
3649 : : "FROM pg_catalog.pg_class\n"
3650 : : "WHERE oid IN (%u, %u);\n",
3651 : : LargeObjectRelationId, LargeObjectLOidPNIndexId);
3652 : : else
1156 rhaas@postgresql.org 3653 :UBC 0 : appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
3654 : : "FROM pg_catalog.pg_class\n"
3655 : : "WHERE oid IN (%u, %u);\n",
3656 : : LargeObjectRelationId, LargeObjectLOidPNIndexId);
3657 : :
1156 rhaas@postgresql.org 3658 :CBC 35 : lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
3659 : :
1113 drowley@postgresql.o 3660 : 35 : ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
3661 : 35 : ii_relminmxid = PQfnumber(lo_res, "relminmxid");
3662 : 35 : ii_relfilenode = PQfnumber(lo_res, "relfilenode");
3663 : 35 : ii_oid = PQfnumber(lo_res, "oid");
3664 : :
1135 rhaas@postgresql.org 3665 : 35 : appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3666 : 35 : appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
1156 3667 [ + + ]: 105 : for (int i = 0; i < PQntuples(lo_res); ++i)
3668 : : {
3669 : : Oid oid;
3670 : : RelFileNumber relfilenumber;
3671 : :
1135 3672 : 70 : appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
3673 : : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3674 : : "WHERE oid = %u;\n",
1113 drowley@postgresql.o 3675 : 70 : atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
3676 : 70 : atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
3677 : 70 : atooid(PQgetvalue(lo_res, i, ii_oid)));
3678 : :
3679 : 70 : oid = atooid(PQgetvalue(lo_res, i, ii_oid));
1074 rhaas@postgresql.org 3680 : 70 : relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
3681 : :
1136 3682 [ + + ]: 70 : if (oid == LargeObjectRelationId)
1135 3683 : 35 : appendPQExpBuffer(loOutQry,
3684 : : "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
3685 : : relfilenumber);
1136 3686 [ + - ]: 35 : else if (oid == LargeObjectLOidPNIndexId)
1135 3687 : 35 : appendPQExpBuffer(loOutQry,
3688 : : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
3689 : : relfilenumber);
3690 : : }
3691 : :
3692 : 35 : appendPQExpBufferStr(loOutQry,
3693 : : "TRUNCATE pg_catalog.pg_largeobject;\n");
3694 : 35 : appendPQExpBufferStr(loOutQry, loHorizonQry->data);
3695 : :
4961 3696 : 35 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 3697 : 35 : ARCHIVE_OPTS(.tag = "pg_largeobject",
3698 : : .description = "pg_largeobject",
3699 : : .section = SECTION_PRE_DATA,
3700 : : .createStmt = loOutQry->data));
3701 : :
5892 bruce@momjian.us 3702 : 35 : PQclear(lo_res);
3703 : :
3704 : 35 : destroyPQExpBuffer(loFrozenQry);
1135 rhaas@postgresql.org 3705 : 35 : destroyPQExpBuffer(loHorizonQry);
5892 bruce@momjian.us 3706 : 35 : destroyPQExpBuffer(loOutQry);
3707 : : }
3708 : :
3884 andres@anarazel.de 3709 : 84 : PQclear(res);
3710 : :
2784 tgl@sss.pgh.pa.us 3711 : 84 : free(qdatname);
8800 3712 : 84 : destroyPQExpBuffer(dbQry);
3713 : 84 : destroyPQExpBuffer(delQry);
3714 : 84 : destroyPQExpBuffer(creaQry);
2784 3715 : 84 : destroyPQExpBuffer(labelq);
9167 pjw@rhyme.com.au 3716 : 84 : }
3717 : :
3718 : : /*
3719 : : * Collect any database-specific or role-and-database-specific SET options
3720 : : * for this database, and append them to outbuf.
3721 : : */
3722 : : static void
2784 tgl@sss.pgh.pa.us 3723 : 84 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
3724 : : const char *dbname, Oid dboid)
3725 : : {
3726 : 84 : PGconn *conn = GetConnection(AH);
3727 : 84 : PQExpBuffer buf = createPQExpBuffer();
3728 : : PGresult *res;
3729 : :
3730 : : /* First collect database-specific options */
843 akorotkov@postgresql 3731 : 84 : printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
3732 : : "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3733 : : dboid);
3734 : :
1362 tgl@sss.pgh.pa.us 3735 : 84 : res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3736 : :
3737 [ + + ]: 114 : for (int i = 0; i < PQntuples(res); i++)
843 akorotkov@postgresql 3738 : 30 : makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
3739 : : "DATABASE", dbname, NULL, NULL,
3740 : : outbuf);
3741 : :
1362 tgl@sss.pgh.pa.us 3742 : 84 : PQclear(res);
3743 : :
3744 : : /* Now look for role-and-database-specific options */
843 akorotkov@postgresql 3745 : 84 : printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3746 : : "FROM pg_db_role_setting s, pg_roles r "
3747 : : "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3748 : : dboid);
3749 : :
1362 tgl@sss.pgh.pa.us 3750 : 84 : res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3751 : :
3752 [ - + ]: 84 : for (int i = 0; i < PQntuples(res); i++)
843 akorotkov@postgresql 3753 :UBC 0 : makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
1362 tgl@sss.pgh.pa.us 3754 : 0 : "ROLE", PQgetvalue(res, i, 0),
3755 : : "DATABASE", dbname,
3756 : : outbuf);
3757 : :
1362 tgl@sss.pgh.pa.us 3758 :CBC 84 : PQclear(res);
3759 : :
2784 3760 : 84 : destroyPQExpBuffer(buf);
3761 : 84 : }
3762 : :
3763 : : /*
3764 : : * dumpEncoding: put the correct encoding into the archive
3765 : : */
3766 : : static void
7865 3767 : 185 : dumpEncoding(Archive *AH)
3768 : : {
7041 3769 : 185 : const char *encname = pg_encoding_to_char(AH->encoding);
3770 : 185 : PQExpBuffer qry = createPQExpBuffer();
3771 : :
2350 peter@eisentraut.org 3772 : 185 : pg_log_info("saving encoding = %s", encname);
3773 : :
4310 heikki.linnakangas@i 3774 : 185 : appendPQExpBufferStr(qry, "SET client_encoding = ");
7041 tgl@sss.pgh.pa.us 3775 : 185 : appendStringLiteralAH(qry, encname, AH);
4310 heikki.linnakangas@i 3776 : 185 : appendPQExpBufferStr(qry, ";\n");
3777 : :
7865 tgl@sss.pgh.pa.us 3778 : 185 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 3779 : 185 : ARCHIVE_OPTS(.tag = "ENCODING",
3780 : : .description = "ENCODING",
3781 : : .section = SECTION_PRE_DATA,
3782 : : .createStmt = qry->data));
3783 : :
7865 tgl@sss.pgh.pa.us 3784 : 185 : destroyPQExpBuffer(qry);
3785 : 185 : }
3786 : :
3787 : :
3788 : : /*
3789 : : * dumpStdStrings: put the correct escape string behavior into the archive
3790 : : */
3791 : : static void
7043 bruce@momjian.us 3792 : 185 : dumpStdStrings(Archive *AH)
3793 : : {
7041 tgl@sss.pgh.pa.us 3794 [ + - ]: 185 : const char *stdstrings = AH->std_strings ? "on" : "off";
3795 : 185 : PQExpBuffer qry = createPQExpBuffer();
3796 : :
477 peter@eisentraut.org 3797 : 185 : pg_log_info("saving \"standard_conforming_strings = %s\"",
3798 : : stdstrings);
3799 : :
7041 tgl@sss.pgh.pa.us 3800 : 185 : appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3801 : : stdstrings);
3802 : :
7043 bruce@momjian.us 3803 : 185 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 3804 : 185 : ARCHIVE_OPTS(.tag = "STDSTRINGS",
3805 : : .description = "STDSTRINGS",
3806 : : .section = SECTION_PRE_DATA,
3807 : : .createStmt = qry->data));
3808 : :
7043 bruce@momjian.us 3809 : 185 : destroyPQExpBuffer(qry);
3810 : 185 : }
3811 : :
3812 : : /*
3813 : : * dumpSearchPath: record the active search_path in the archive
3814 : : */
3815 : : static void
2749 tgl@sss.pgh.pa.us 3816 : 185 : dumpSearchPath(Archive *AH)
3817 : : {
3818 : 185 : PQExpBuffer qry = createPQExpBuffer();
3819 : 185 : PQExpBuffer path = createPQExpBuffer();
3820 : : PGresult *res;
3821 : 185 : char **schemanames = NULL;
3822 : 185 : int nschemanames = 0;
3823 : : int i;
3824 : :
3825 : : /*
3826 : : * We use the result of current_schemas(), not the search_path GUC,
3827 : : * because that might contain wildcards such as "$user", which won't
3828 : : * necessarily have the same value during restore. Also, this way avoids
3829 : : * listing schemas that may appear in search_path but not actually exist,
3830 : : * which seems like a prudent exclusion.
3831 : : */
3832 : 185 : res = ExecuteSqlQueryForSingleRow(AH,
3833 : : "SELECT pg_catalog.current_schemas(false)");
3834 : :
3835 [ - + ]: 185 : if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
1247 tgl@sss.pgh.pa.us 3836 :UBC 0 : pg_fatal("could not parse result of current_schemas()");
3837 : :
3838 : : /*
3839 : : * We use set_config(), not a simple "SET search_path" command, because
3840 : : * the latter has less-clean behavior if the search path is empty. While
3841 : : * that's likely to get fixed at some point, it seems like a good idea to
3842 : : * be as backwards-compatible as possible in what we put into archives.
3843 : : */
2749 tgl@sss.pgh.pa.us 3844 [ - + ]:CBC 185 : for (i = 0; i < nschemanames; i++)
3845 : : {
2749 tgl@sss.pgh.pa.us 3846 [ # # ]:UBC 0 : if (i > 0)
3847 : 0 : appendPQExpBufferStr(path, ", ");
3848 : 0 : appendPQExpBufferStr(path, fmtId(schemanames[i]));
3849 : : }
3850 : :
2749 tgl@sss.pgh.pa.us 3851 :CBC 185 : appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3852 : 185 : appendStringLiteralAH(qry, path->data, AH);
3853 : 185 : appendPQExpBufferStr(qry, ", false);\n");
3854 : :
477 peter@eisentraut.org 3855 : 185 : pg_log_info("saving \"search_path = %s\"", path->data);
3856 : :
2749 tgl@sss.pgh.pa.us 3857 : 185 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 3858 : 185 : ARCHIVE_OPTS(.tag = "SEARCHPATH",
3859 : : .description = "SEARCHPATH",
3860 : : .section = SECTION_PRE_DATA,
3861 : : .createStmt = qry->data));
3862 : :
3863 : : /* Also save it in AH->searchpath, in case we're doing plain text dump */
2749 tgl@sss.pgh.pa.us 3864 : 185 : AH->searchpath = pg_strdup(qry->data);
3865 : :
1178 peter@eisentraut.org 3866 : 185 : free(schemanames);
2749 tgl@sss.pgh.pa.us 3867 : 185 : PQclear(res);
3868 : 185 : destroyPQExpBuffer(qry);
3869 : 185 : destroyPQExpBuffer(path);
3870 : 185 : }
3871 : :
3872 : :
3873 : : /*
3874 : : * getLOs:
3875 : : * Collect schema-level data about large objects
3876 : : */
3877 : : static void
1006 peter@eisentraut.org 3878 : 157 : getLOs(Archive *fout)
3879 : : {
3440 sfrost@snowman.net 3880 : 157 : DumpOptions *dopt = fout->dopt;
1006 peter@eisentraut.org 3881 : 157 : PQExpBuffer loQry = createPQExpBuffer();
3882 : : PGresult *res;
3883 : : int ntups;
3884 : : int i;
3885 : : int n;
3886 : : int i_oid;
3887 : : int i_lomowner;
3888 : : int i_lomacl;
3889 : : int i_acldefault;
3890 : :
2350 3891 : 157 : pg_log_info("reading large objects");
3892 : :
3893 : : /*
3894 : : * Fetch LO OIDs and owner/ACL data. Order the data so that all the blobs
3895 : : * with the same owner/ACL appear together.
3896 : : */
1006 3897 : 157 : appendPQExpBufferStr(loQry,
3898 : : "SELECT oid, lomowner, lomacl, "
3899 : : "acldefault('L', lomowner) AS acldefault "
3900 : : "FROM pg_largeobject_metadata "
3901 : : "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
3902 : :
3903 : 157 : res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
3904 : :
3440 sfrost@snowman.net 3905 : 157 : i_oid = PQfnumber(res, "oid");
1345 tgl@sss.pgh.pa.us 3906 : 157 : i_lomowner = PQfnumber(res, "lomowner");
3440 sfrost@snowman.net 3907 : 157 : i_lomacl = PQfnumber(res, "lomacl");
1370 tgl@sss.pgh.pa.us 3908 : 157 : i_acldefault = PQfnumber(res, "acldefault");
3909 : :
5679 3910 : 157 : ntups = PQntuples(res);
3911 : :
3912 : : /*
3913 : : * Group the blobs into suitably-sized groups that have the same owner and
3914 : : * ACL setting, and build a metadata and a data DumpableObject for each
3915 : : * group. (If we supported initprivs for blobs, we'd have to insist that
3916 : : * groups also share initprivs settings, since the DumpableObject only has
3917 : : * room for one.) i is the index of the first tuple in the current group,
3918 : : * and n is the number of tuples we include in the group.
3919 : : */
523 3920 [ + + ]: 242 : for (i = 0; i < ntups; i += n)
3921 : : {
3922 : 85 : Oid thisoid = atooid(PQgetvalue(res, i, i_oid));
3923 : 85 : char *thisowner = PQgetvalue(res, i, i_lomowner);
3924 : 85 : char *thisacl = PQgetvalue(res, i, i_lomacl);
3925 : : LoInfo *loinfo;
3926 : : DumpableObject *lodata;
3927 : : char namebuf[64];
3928 : :
3929 : : /* Scan to find first tuple not to be included in group */
3930 : 85 : n = 1;
3931 [ + - + + ]: 95 : while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
3932 : : {
3933 [ + - ]: 50 : if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
3934 [ + + ]: 50 : strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
3935 : : break;
3936 : 10 : n++;
3937 : : }
3938 : :
3939 : : /* Build the metadata DumpableObject */
3940 : 85 : loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
3941 : :
3942 : 85 : loinfo->dobj.objType = DO_LARGE_OBJECT;
3943 : 85 : loinfo->dobj.catId.tableoid = LargeObjectRelationId;
3944 : 85 : loinfo->dobj.catId.oid = thisoid;
3945 : 85 : AssignDumpId(&loinfo->dobj);
3946 : :
3947 [ + + ]: 85 : if (n > 1)
3948 : 5 : snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
3949 : 5 : atooid(PQgetvalue(res, i + n - 1, i_oid)));
3950 : : else
3951 : 80 : snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
3952 : 85 : loinfo->dobj.name = pg_strdup(namebuf);
3953 : 85 : loinfo->dacl.acl = pg_strdup(thisacl);
3954 : 85 : loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
3955 : 85 : loinfo->dacl.privtype = 0;
3956 : 85 : loinfo->dacl.initprivs = NULL;
3957 : 85 : loinfo->rolname = getRoleName(thisowner);
3958 : 85 : loinfo->numlos = n;
3959 : 85 : loinfo->looids[0] = thisoid;
3960 : : /* Collect OIDs of the remaining blobs in this group */
3961 [ + + ]: 95 : for (int k = 1; k < n; k++)
3962 : : {
3963 : : CatalogId extraID;
3964 : :
3965 : 10 : loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
3966 : :
3967 : : /* Make sure we can look up loinfo by any of the blobs' OIDs */
3968 : 10 : extraID.tableoid = LargeObjectRelationId;
3969 : 10 : extraID.oid = loinfo->looids[k];
3970 : 10 : recordAdditionalCatalogID(extraID, &loinfo->dobj);
3971 : : }
3972 : :
3973 : : /* LOs have data */
3974 : 85 : loinfo->dobj.components |= DUMP_COMPONENT_DATA;
3975 : :
3976 : : /* Mark whether LO group has a non-empty ACL */
1370 3977 [ + + ]: 85 : if (!PQgetisnull(res, i, i_lomacl))
523 3978 : 40 : loinfo->dobj.components |= DUMP_COMPONENT_ACL;
3979 : :
3980 : : /*
3981 : : * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
3982 : : * as it will be copied by pg_upgrade, which simply copies the
3983 : : * pg_largeobject table. We *do* however dump out anything but the
3984 : : * data, as pg_upgrade copies just pg_largeobject, but not
3985 : : * pg_largeobject_metadata, after the dump is restored. In versions
3986 : : * before v12, this is done via proper large object commands. In
3987 : : * newer versions, we dump the content of pg_largeobject_metadata and
3988 : : * any associated pg_shdepend rows, which is faster to restore. (On
3989 : : * <v12, pg_largeobject_metadata was created WITH OIDS, so the OID
3990 : : * column is hidden and won't be dumped.)
3991 : : */
3106 sfrost@snowman.net 3992 [ + + ]: 85 : if (dopt->binary_upgrade)
3993 : : {
50 nathan@postgresql.or 3994 [ + - ]:GNC 3 : if (fout->remoteVersion >= 120000)
3995 : : {
3996 : : /*
3997 : : * We should've saved pg_largeobject_metadata's dump ID before
3998 : : * this point.
3999 : : */
4000 [ - + ]: 3 : Assert(lo_metadata_dumpId);
4001 : :
4002 : 3 : loinfo->dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL | DUMP_COMPONENT_DEFINITION);
4003 : :
4004 : : /*
4005 : : * Mark the large object as dependent on
4006 : : * pg_largeobject_metadata so that any large object
4007 : : * comments/seclables are dumped after it.
4008 : : */
4009 : 3 : loinfo->dobj.dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
4010 : 3 : loinfo->dobj.dependencies[0] = lo_metadata_dumpId;
4011 : 3 : loinfo->dobj.nDeps = loinfo->dobj.allocDeps = 1;
4012 : : }
4013 : : else
50 nathan@postgresql.or 4014 :UNC 0 : loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
4015 : : }
4016 : :
4017 : : /*
4018 : : * Create a "BLOBS" data item for the group, too. This is just a
4019 : : * placeholder for sorting; it carries no data now.
4020 : : */
1006 peter@eisentraut.org 4021 :CBC 85 : lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
4022 : 85 : lodata->objType = DO_LARGE_OBJECT_DATA;
4023 : 85 : lodata->catId = nilCatalogId;
4024 : 85 : AssignDumpId(lodata);
523 tgl@sss.pgh.pa.us 4025 : 85 : lodata->name = pg_strdup(namebuf);
1006 peter@eisentraut.org 4026 : 85 : lodata->components |= DUMP_COMPONENT_DATA;
4027 : : /* Set up explicit dependency from data to metadata */
523 tgl@sss.pgh.pa.us 4028 : 85 : lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
4029 : 85 : lodata->dependencies[0] = loinfo->dobj.dumpId;
4030 : 85 : lodata->nDeps = lodata->allocDeps = 1;
4031 : : }
4032 : :
7373 4033 : 157 : PQclear(res);
1006 peter@eisentraut.org 4034 : 157 : destroyPQExpBuffer(loQry);
5679 tgl@sss.pgh.pa.us 4035 : 157 : }
4036 : :
4037 : : /*
4038 : : * dumpLO
4039 : : *
4040 : : * dump the definition (metadata) of the given large object group
4041 : : */
4042 : : static void
1006 peter@eisentraut.org 4043 : 84 : dumpLO(Archive *fout, const LoInfo *loinfo)
4044 : : {
5671 bruce@momjian.us 4045 : 84 : PQExpBuffer cquery = createPQExpBuffer();
4046 : :
4047 : : /*
4048 : : * The "definition" is just a newline-separated list of OIDs. We need to
4049 : : * put something into the dropStmt too, but it can just be a comment.
4050 : : */
523 tgl@sss.pgh.pa.us 4051 [ + + ]: 178 : for (int i = 0; i < loinfo->numlos; i++)
4052 : 94 : appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
4053 : :
1006 peter@eisentraut.org 4054 [ + + ]: 84 : if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4055 : 82 : ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
4056 : 82 : ARCHIVE_OPTS(.tag = loinfo->dobj.name,
4057 : : .owner = loinfo->rolname,
4058 : : .description = "BLOB METADATA",
4059 : : .section = SECTION_DATA,
4060 : : .createStmt = cquery->data,
4061 : : .dropStmt = "-- dummy"));
4062 : :
4063 : : /*
4064 : : * Dump per-blob comments and seclabels if any. We assume these are rare
4065 : : * enough that it's okay to generate retail TOC entries for them.
4066 : : */
523 tgl@sss.pgh.pa.us 4067 [ + + ]: 84 : if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
4068 : : DUMP_COMPONENT_SECLABEL))
4069 : : {
4070 [ + + ]: 100 : for (int i = 0; i < loinfo->numlos; i++)
4071 : : {
4072 : : CatalogId catId;
4073 : : char namebuf[32];
4074 : :
4075 : : /* Build identifying info for this blob */
4076 : 55 : catId.tableoid = loinfo->dobj.catId.tableoid;
4077 : 55 : catId.oid = loinfo->looids[i];
4078 : 55 : snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
4079 : :
4080 [ + - ]: 55 : if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4081 : 55 : dumpComment(fout, "LARGE OBJECT", namebuf,
4082 : 55 : NULL, loinfo->rolname,
4083 : 55 : catId, 0, loinfo->dobj.dumpId);
4084 : :
4085 [ - + ]: 55 : if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
523 tgl@sss.pgh.pa.us 4086 :UBC 0 : dumpSecLabel(fout, "LARGE OBJECT", namebuf,
4087 : 0 : NULL, loinfo->rolname,
4088 : 0 : catId, 0, loinfo->dobj.dumpId);
4089 : : }
4090 : : }
4091 : :
4092 : : /*
4093 : : * Dump the ACLs if any (remember that all blobs in the group will have
4094 : : * the same ACL). If there's just one blob, dump a simple ACL entry; if
4095 : : * there's more, make a "LARGE OBJECTS" entry that really contains only
4096 : : * the ACL for the first blob. _printTocEntry() will be cued by the tag
4097 : : * string to emit a mutated version for each blob.
4098 : : */
1006 peter@eisentraut.org 4099 [ + + ]:CBC 84 : if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
4100 : : {
4101 : : char namebuf[32];
4102 : :
4103 : : /* Build identifying info for the first blob */
523 tgl@sss.pgh.pa.us 4104 : 39 : snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
4105 : :
4106 [ - + ]: 39 : if (loinfo->numlos > 1)
4107 : : {
4108 : : char tagbuf[64];
4109 : :
523 tgl@sss.pgh.pa.us 4110 :UBC 0 : snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
4111 : 0 : loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
4112 : :
4113 : 0 : dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
4114 : : "LARGE OBJECT", namebuf, NULL, NULL,
4115 : 0 : tagbuf, loinfo->rolname, &loinfo->dacl);
4116 : : }
4117 : : else
4118 : : {
523 tgl@sss.pgh.pa.us 4119 :CBC 39 : dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
4120 : : "LARGE OBJECT", namebuf, NULL, NULL,
4121 : 39 : NULL, loinfo->rolname, &loinfo->dacl);
4122 : : }
4123 : : }
4124 : :
5679 4125 : 84 : destroyPQExpBuffer(cquery);
7373 4126 : 84 : }
4127 : :
4128 : : /*
4129 : : * dumpLOs:
4130 : : * dump the data contents of the large objects in the given group
4131 : : */
4132 : : static int
1006 peter@eisentraut.org 4133 : 78 : dumpLOs(Archive *fout, const void *arg)
4134 : : {
523 tgl@sss.pgh.pa.us 4135 : 78 : const LoInfo *loinfo = (const LoInfo *) arg;
4951 rhaas@postgresql.org 4136 : 78 : PGconn *conn = GetConnection(fout);
4137 : : char buf[LOBBUFSIZE];
4138 : :
523 tgl@sss.pgh.pa.us 4139 : 78 : pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
4140 : :
4141 [ + + ]: 164 : for (int i = 0; i < loinfo->numlos; i++)
4142 : : {
4143 : 86 : Oid loOid = loinfo->looids[i];
4144 : : int loFd;
4145 : : int cnt;
4146 : :
4147 : : /* Open the LO */
4148 : 86 : loFd = lo_open(conn, loOid, INV_READ);
4149 [ - + ]: 86 : if (loFd == -1)
523 tgl@sss.pgh.pa.us 4150 :UBC 0 : pg_fatal("could not open large object %u: %s",
4151 : : loOid, PQerrorMessage(conn));
4152 : :
523 tgl@sss.pgh.pa.us 4153 :CBC 86 : StartLO(fout, loOid);
4154 : :
4155 : : /* Now read it in chunks, sending data to archive */
4156 : : do
4157 : : {
4158 : 131 : cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
4159 [ - + ]: 131 : if (cnt < 0)
523 tgl@sss.pgh.pa.us 4160 :UBC 0 : pg_fatal("error reading large object %u: %s",
4161 : : loOid, PQerrorMessage(conn));
4162 : :
523 tgl@sss.pgh.pa.us 4163 :CBC 131 : WriteData(fout, buf, cnt);
4164 [ + + ]: 131 : } while (cnt > 0);
4165 : :
4166 : 86 : lo_close(conn, loFd);
4167 : :
4168 : 86 : EndLO(fout, loOid);
4169 : : }
4170 : :
7373 4171 : 78 : return 1;
4172 : : }
4173 : :
4174 : : /*
4175 : : * getPolicies
4176 : : * get information about all RLS policies on dumpable tables.
4177 : : */
4178 : : void
3936 sfrost@snowman.net 4179 : 185 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
4180 : : {
174 tgl@sss.pgh.pa.us 4181 : 185 : DumpOptions *dopt = fout->dopt;
4182 : : PQExpBuffer query;
4183 : : PQExpBuffer tbloids;
4184 : : PGresult *res;
4185 : : PolicyInfo *polinfo;
4186 : : int i_oid;
4187 : : int i_tableoid;
4188 : : int i_polrelid;
4189 : : int i_polname;
4190 : : int i_polcmd;
4191 : : int i_polpermissive;
4192 : : int i_polroles;
4193 : : int i_polqual;
4194 : : int i_polwithcheck;
4195 : : int i,
4196 : : j,
4197 : : ntups;
4198 : :
4199 : : /* No policies before 9.5 */
4005 sfrost@snowman.net 4200 [ - + ]: 185 : if (fout->remoteVersion < 90500)
4005 sfrost@snowman.net 4201 :UBC 0 : return;
4202 : :
4203 : : /* Skip if --no-policies was specified */
174 tgl@sss.pgh.pa.us 4204 [ + + ]:CBC 185 : if (dopt->no_policies)
4205 : 1 : return;
4206 : :
4000 sfrost@snowman.net 4207 : 184 : query = createPQExpBuffer();
1345 tgl@sss.pgh.pa.us 4208 : 184 : tbloids = createPQExpBuffer();
4209 : :
4210 : : /*
4211 : : * Identify tables of interest, and check which ones have RLS enabled.
4212 : : */
4213 : 184 : appendPQExpBufferChar(tbloids, '{');
4005 sfrost@snowman.net 4214 [ + + ]: 48955 : for (i = 0; i < numTables; i++)
4215 : : {
3977 tgl@sss.pgh.pa.us 4216 : 48771 : TableInfo *tbinfo = &tblinfo[i];
4217 : :
4218 : : /* Ignore row security on tables not to be dumped */
3440 sfrost@snowman.net 4219 [ + + ]: 48771 : if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
4005 4220 : 41490 : continue;
4221 : :
4222 : : /* It can't have RLS or policies if it's not a table */
1345 tgl@sss.pgh.pa.us 4223 [ + + ]: 7281 : if (tbinfo->relkind != RELKIND_RELATION &&
4224 [ + + ]: 2077 : tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
4225 : 1467 : continue;
4226 : :
4227 : : /* Add it to the list of table OIDs to be probed below */
4228 [ + + ]: 5814 : if (tbloids->len > 1) /* do we have more than the '{'? */
4229 : 5694 : appendPQExpBufferChar(tbloids, ',');
4230 : 5814 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
4231 : :
4232 : : /* Is RLS enabled? (That's separate from whether it has policies) */
4000 sfrost@snowman.net 4233 [ + + ]: 5814 : if (tbinfo->rowsec)
4234 : : {
1370 tgl@sss.pgh.pa.us 4235 : 59 : tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
4236 : :
4237 : : /*
4238 : : * We represent RLS being enabled on a table by creating a
4239 : : * PolicyInfo object with null polname.
4240 : : *
4241 : : * Note: use tableoid 0 so that this object won't be mistaken for
4242 : : * something that pg_depend entries apply to.
4243 : : */
3936 sfrost@snowman.net 4244 : 59 : polinfo = pg_malloc(sizeof(PolicyInfo));
4245 : 59 : polinfo->dobj.objType = DO_POLICY;
4246 : 59 : polinfo->dobj.catId.tableoid = 0;
4247 : 59 : polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
4248 : 59 : AssignDumpId(&polinfo->dobj);
4249 : 59 : polinfo->dobj.namespace = tbinfo->dobj.namespace;
4250 : 59 : polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
4251 : 59 : polinfo->poltable = tbinfo;
4252 : 59 : polinfo->polname = NULL;
3197 4253 : 59 : polinfo->polcmd = '\0';
4254 : 59 : polinfo->polpermissive = 0;
3936 4255 : 59 : polinfo->polroles = NULL;
4256 : 59 : polinfo->polqual = NULL;
4257 : 59 : polinfo->polwithcheck = NULL;
4258 : : }
4259 : : }
1345 tgl@sss.pgh.pa.us 4260 : 184 : appendPQExpBufferChar(tbloids, '}');
4261 : :
4262 : : /*
4263 : : * Now, read all RLS policies belonging to the tables of interest, and
4264 : : * create PolicyInfo objects for them. (Note that we must filter the
4265 : : * results server-side not locally, because we dare not apply pg_get_expr
4266 : : * to tables we don't have lock on.)
4267 : : */
1467 4268 : 184 : pg_log_info("reading row-level security policies");
4269 : :
4270 : 184 : printfPQExpBuffer(query,
4271 : : "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
4272 [ + - ]: 184 : if (fout->remoteVersion >= 100000)
1096 drowley@postgresql.o 4273 : 184 : appendPQExpBufferStr(query, "pol.polpermissive, ");
4274 : : else
1096 drowley@postgresql.o 4275 :UBC 0 : appendPQExpBufferStr(query, "'t' as polpermissive, ");
1467 tgl@sss.pgh.pa.us 4276 :CBC 184 : appendPQExpBuffer(query,
4277 : : "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
4278 : : " pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, "
4279 : : "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
4280 : : "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
4281 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
4282 : : "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
4283 : : tbloids->data);
4284 : :
4285 : 184 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4286 : :
4287 : 184 : ntups = PQntuples(res);
4288 [ + + ]: 184 : if (ntups > 0)
4289 : : {
4005 sfrost@snowman.net 4290 : 49 : i_oid = PQfnumber(res, "oid");
4291 : 49 : i_tableoid = PQfnumber(res, "tableoid");
1467 tgl@sss.pgh.pa.us 4292 : 49 : i_polrelid = PQfnumber(res, "polrelid");
3936 sfrost@snowman.net 4293 : 49 : i_polname = PQfnumber(res, "polname");
4294 : 49 : i_polcmd = PQfnumber(res, "polcmd");
3197 4295 : 49 : i_polpermissive = PQfnumber(res, "polpermissive");
3936 4296 : 49 : i_polroles = PQfnumber(res, "polroles");
4297 : 49 : i_polqual = PQfnumber(res, "polqual");
4298 : 49 : i_polwithcheck = PQfnumber(res, "polwithcheck");
4299 : :
4300 : 49 : polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
4301 : :
4005 4302 [ + + ]: 358 : for (j = 0; j < ntups; j++)
4303 : : {
1467 tgl@sss.pgh.pa.us 4304 : 309 : Oid polrelid = atooid(PQgetvalue(res, j, i_polrelid));
4305 : 309 : TableInfo *tbinfo = findTableByOid(polrelid);
4306 : :
1370 4307 : 309 : tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
4308 : :
3936 sfrost@snowman.net 4309 : 309 : polinfo[j].dobj.objType = DO_POLICY;
4310 : 309 : polinfo[j].dobj.catId.tableoid =
4005 4311 : 309 : atooid(PQgetvalue(res, j, i_tableoid));
3936 4312 : 309 : polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4313 : 309 : AssignDumpId(&polinfo[j].dobj);
4314 : 309 : polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4315 : 309 : polinfo[j].poltable = tbinfo;
4316 : 309 : polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
4317 : 309 : polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
4318 : :
3197 4319 : 309 : polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
4320 : 309 : polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
4321 : :
4322 [ + + ]: 309 : if (PQgetisnull(res, j, i_polroles))
4323 : 133 : polinfo[j].polroles = NULL;
4324 : : else
4325 : 176 : polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
4326 : :
3936 4327 [ + + ]: 309 : if (PQgetisnull(res, j, i_polqual))
4328 : 44 : polinfo[j].polqual = NULL;
4329 : : else
4330 : 265 : polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
4331 : :
4332 [ + + ]: 309 : if (PQgetisnull(res, j, i_polwithcheck))
4333 : 162 : polinfo[j].polwithcheck = NULL;
4334 : : else
4335 : 147 : polinfo[j].polwithcheck
4336 : 147 : = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
4337 : : }
4338 : : }
4339 : :
1467 tgl@sss.pgh.pa.us 4340 : 184 : PQclear(res);
4341 : :
4005 sfrost@snowman.net 4342 : 184 : destroyPQExpBuffer(query);
1345 tgl@sss.pgh.pa.us 4343 : 184 : destroyPQExpBuffer(tbloids);
4344 : : }
4345 : :
4346 : : /*
4347 : : * dumpPolicy
4348 : : * dump the definition of the given policy
4349 : : */
4350 : : static void
1669 peter@eisentraut.org 4351 : 368 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
4352 : : {
3524 tgl@sss.pgh.pa.us 4353 : 368 : DumpOptions *dopt = fout->dopt;
3936 sfrost@snowman.net 4354 : 368 : TableInfo *tbinfo = polinfo->poltable;
4355 : : PQExpBuffer query;
4356 : : PQExpBuffer delqry;
4357 : : PQExpBuffer polprefix;
4358 : : char *qtabname;
4359 : : const char *cmd;
4360 : : char *tag;
4361 : :
4362 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 4363 [ + + ]: 368 : if (!dopt->dumpSchema)
4005 sfrost@snowman.net 4364 : 49 : return;
4365 : :
4366 : : /*
4367 : : * If polname is NULL, then this record is just indicating that ROW LEVEL
4368 : : * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
4369 : : * ROW LEVEL SECURITY.
4370 : : */
3936 4371 [ + + ]: 319 : if (polinfo->polname == NULL)
4372 : : {
4005 4373 : 52 : query = createPQExpBuffer();
4374 : :
4375 : 52 : appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
2567 tgl@sss.pgh.pa.us 4376 : 52 : fmtQualifiedDumpable(tbinfo));
4377 : :
4378 : : /*
4379 : : * We must emit the ROW SECURITY object's dependency on its table
4380 : : * explicitly, because it will not match anything in pg_depend (unlike
4381 : : * the case for other PolicyInfo objects).
4382 : : */
1370 4383 [ + - ]: 52 : if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3440 sfrost@snowman.net 4384 : 52 : ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 4385 : 52 : ARCHIVE_OPTS(.tag = polinfo->dobj.name,
4386 : : .namespace = polinfo->dobj.namespace->dobj.name,
4387 : : .owner = tbinfo->rolname,
4388 : : .description = "ROW SECURITY",
4389 : : .section = SECTION_POST_DATA,
4390 : : .createStmt = query->data,
4391 : : .deps = &(tbinfo->dobj.dumpId),
4392 : : .nDeps = 1));
4393 : :
4005 sfrost@snowman.net 4394 : 52 : destroyPQExpBuffer(query);
4395 : 52 : return;
4396 : : }
4397 : :
3197 4398 [ + + ]: 267 : if (polinfo->polcmd == '*')
4399 : 89 : cmd = "";
4400 [ + + ]: 178 : else if (polinfo->polcmd == 'r')
4401 : 47 : cmd = " FOR SELECT";
4402 [ + + ]: 131 : else if (polinfo->polcmd == 'a')
4403 : 37 : cmd = " FOR INSERT";
4404 [ + + ]: 94 : else if (polinfo->polcmd == 'w')
4405 : 47 : cmd = " FOR UPDATE";
4406 [ + - ]: 47 : else if (polinfo->polcmd == 'd')
4407 : 47 : cmd = " FOR DELETE";
4408 : : else
1247 tgl@sss.pgh.pa.us 4409 :UBC 0 : pg_fatal("unexpected policy command type: %c",
4410 : : polinfo->polcmd);
4411 : :
4005 sfrost@snowman.net 4412 :CBC 267 : query = createPQExpBuffer();
4413 : 267 : delqry = createPQExpBuffer();
2028 tgl@sss.pgh.pa.us 4414 : 267 : polprefix = createPQExpBuffer();
4415 : :
4416 : 267 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
4417 : :
3878 4418 : 267 : appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
4419 : :
2749 4420 : 267 : appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3197 sfrost@snowman.net 4421 [ + + ]: 267 : !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
4422 : :
3936 4423 [ + + ]: 267 : if (polinfo->polroles != NULL)
4424 : 148 : appendPQExpBuffer(query, " TO %s", polinfo->polroles);
4425 : :
4426 [ + + ]: 267 : if (polinfo->polqual != NULL)
3694 mail@joeconway.com 4427 : 230 : appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
4428 : :
3936 sfrost@snowman.net 4429 [ + + ]: 267 : if (polinfo->polwithcheck != NULL)
3694 mail@joeconway.com 4430 : 126 : appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
4431 : :
2256 drowley@postgresql.o 4432 : 267 : appendPQExpBufferStr(query, ";\n");
4433 : :
3878 tgl@sss.pgh.pa.us 4434 : 267 : appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
2749 4435 : 267 : appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
4436 : :
2028 4437 : 267 : appendPQExpBuffer(polprefix, "POLICY %s ON",
4438 : 267 : fmtId(polinfo->polname));
4439 : :
3481 peter_e@gmx.net 4440 : 267 : tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
4441 : :
1370 tgl@sss.pgh.pa.us 4442 [ + - ]: 267 : if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3440 sfrost@snowman.net 4443 : 267 : ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 4444 : 267 : ARCHIVE_OPTS(.tag = tag,
4445 : : .namespace = polinfo->dobj.namespace->dobj.name,
4446 : : .owner = tbinfo->rolname,
4447 : : .description = "POLICY",
4448 : : .section = SECTION_POST_DATA,
4449 : : .createStmt = query->data,
4450 : : .dropStmt = delqry->data));
4451 : :
2028 tgl@sss.pgh.pa.us 4452 [ - + ]: 267 : if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2028 tgl@sss.pgh.pa.us 4453 :UBC 0 : dumpComment(fout, polprefix->data, qtabname,
4454 : 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
4455 : 0 : polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
4456 : :
3481 peter_e@gmx.net 4457 :CBC 267 : free(tag);
4005 sfrost@snowman.net 4458 : 267 : destroyPQExpBuffer(query);
4459 : 267 : destroyPQExpBuffer(delqry);
2028 tgl@sss.pgh.pa.us 4460 : 267 : destroyPQExpBuffer(polprefix);
4461 : 267 : free(qtabname);
4462 : : }
4463 : :
4464 : : /*
4465 : : * getPublications
4466 : : * get information about publications
4467 : : */
4468 : : void
431 nathan@postgresql.or 4469 : 185 : getPublications(Archive *fout)
4470 : : {
3039 peter_e@gmx.net 4471 : 185 : DumpOptions *dopt = fout->dopt;
4472 : : PQExpBuffer query;
4473 : : PGresult *res;
4474 : : PublicationInfo *pubinfo;
4475 : : int i_tableoid;
4476 : : int i_oid;
4477 : : int i_pubname;
4478 : : int i_pubowner;
4479 : : int i_puballtables;
4480 : : int i_pubinsert;
4481 : : int i_pubupdate;
4482 : : int i_pubdelete;
4483 : : int i_pubtruncate;
4484 : : int i_pubviaroot;
4485 : : int i_pubgencols;
4486 : : int i,
4487 : : ntups;
4488 : :
4489 [ + - - + ]: 185 : if (dopt->no_publications || fout->remoteVersion < 100000)
431 nathan@postgresql.or 4490 :UBC 0 : return;
4491 : :
3152 peter_e@gmx.net 4492 :CBC 185 : query = createPQExpBuffer();
4493 : :
4494 : : /* Get the publications. */
303 akapila@postgresql.o 4495 : 185 : appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
4496 : : "p.pubowner, p.puballtables, p.pubinsert, "
4497 : : "p.pubupdate, p.pubdelete, ");
4498 : :
4499 [ + - ]: 185 : if (fout->remoteVersion >= 110000)
4500 : 185 : appendPQExpBufferStr(query, "p.pubtruncate, ");
4501 : : else
303 akapila@postgresql.o 4502 :UBC 0 : appendPQExpBufferStr(query, "false AS pubtruncate, ");
4503 : :
1248 tomas.vondra@postgre 4504 [ + - ]:CBC 185 : if (fout->remoteVersion >= 130000)
303 akapila@postgresql.o 4505 : 185 : appendPQExpBufferStr(query, "p.pubviaroot, ");
4506 : : else
303 akapila@postgresql.o 4507 :UBC 0 : appendPQExpBufferStr(query, "false AS pubviaroot, ");
4508 : :
303 akapila@postgresql.o 4509 [ + - ]:CBC 185 : if (fout->remoteVersion >= 180000)
221 4510 : 185 : appendPQExpBufferStr(query, "p.pubgencols ");
4511 : : else
221 akapila@postgresql.o 4512 :UBC 0 : appendPQExpBuffer(query, "'%c' AS pubgencols ", PUBLISH_GENCOLS_NONE);
4513 : :
303 akapila@postgresql.o 4514 :CBC 185 : appendPQExpBufferStr(query, "FROM pg_publication p");
4515 : :
3152 peter_e@gmx.net 4516 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4517 : :
4518 : 185 : ntups = PQntuples(res);
4519 : :
339 dgustafsson@postgres 4520 [ + + ]: 185 : if (ntups == 0)
4521 : 126 : goto cleanup;
4522 : :
3152 peter_e@gmx.net 4523 : 59 : i_tableoid = PQfnumber(res, "tableoid");
4524 : 59 : i_oid = PQfnumber(res, "oid");
4525 : 59 : i_pubname = PQfnumber(res, "pubname");
1345 tgl@sss.pgh.pa.us 4526 : 59 : i_pubowner = PQfnumber(res, "pubowner");
3152 peter_e@gmx.net 4527 : 59 : i_puballtables = PQfnumber(res, "puballtables");
4528 : 59 : i_pubinsert = PQfnumber(res, "pubinsert");
4529 : 59 : i_pubupdate = PQfnumber(res, "pubupdate");
4530 : 59 : i_pubdelete = PQfnumber(res, "pubdelete");
2709 4531 : 59 : i_pubtruncate = PQfnumber(res, "pubtruncate");
1977 peter@eisentraut.org 4532 : 59 : i_pubviaroot = PQfnumber(res, "pubviaroot");
221 akapila@postgresql.o 4533 : 59 : i_pubgencols = PQfnumber(res, "pubgencols");
4534 : :
3152 peter_e@gmx.net 4535 : 59 : pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
4536 : :
4537 [ + + ]: 350 : for (i = 0; i < ntups; i++)
4538 : : {
4539 : 291 : pubinfo[i].dobj.objType = DO_PUBLICATION;
4540 : 291 : pubinfo[i].dobj.catId.tableoid =
4541 : 291 : atooid(PQgetvalue(res, i, i_tableoid));
4542 : 291 : pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4543 : 291 : AssignDumpId(&pubinfo[i].dobj);
4544 : 291 : pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
1345 tgl@sss.pgh.pa.us 4545 : 291 : pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
3152 peter_e@gmx.net 4546 : 291 : pubinfo[i].puballtables =
4547 : 291 : (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
4548 : 291 : pubinfo[i].pubinsert =
4549 : 291 : (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
4550 : 291 : pubinfo[i].pubupdate =
4551 : 291 : (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
4552 : 291 : pubinfo[i].pubdelete =
4553 : 291 : (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
2709 4554 : 291 : pubinfo[i].pubtruncate =
4555 : 291 : (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
1977 peter@eisentraut.org 4556 : 291 : pubinfo[i].pubviaroot =
4557 : 291 : (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
226 akapila@postgresql.o 4558 : 291 : pubinfo[i].pubgencols_type =
221 4559 : 291 : *(PQgetvalue(res, i, i_pubgencols));
4560 : :
4561 : : /* Decide whether we want to dump it */
3091 peter_e@gmx.net 4562 : 291 : selectDumpableObject(&(pubinfo[i].dobj), fout);
4563 : : }
4564 : :
339 dgustafsson@postgres 4565 : 59 : cleanup:
3152 peter_e@gmx.net 4566 : 185 : PQclear(res);
4567 : :
4568 : 185 : destroyPQExpBuffer(query);
4569 : : }
4570 : :
4571 : : /*
4572 : : * dumpPublication
4573 : : * dump the definition of the given publication
4574 : : */
4575 : : static void
1669 peter@eisentraut.org 4576 : 241 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
4577 : : {
1346 tgl@sss.pgh.pa.us 4578 : 241 : DumpOptions *dopt = fout->dopt;
4579 : : PQExpBuffer delq;
4580 : : PQExpBuffer query;
4581 : : char *qpubname;
3039 peter_e@gmx.net 4582 : 241 : bool first = true;
4583 : :
4584 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 4585 [ + + ]: 241 : if (!dopt->dumpSchema)
1346 tgl@sss.pgh.pa.us 4586 : 30 : return;
4587 : :
3152 peter_e@gmx.net 4588 : 211 : delq = createPQExpBuffer();
4589 : 211 : query = createPQExpBuffer();
4590 : :
2749 tgl@sss.pgh.pa.us 4591 : 211 : qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
4592 : :
3152 peter_e@gmx.net 4593 : 211 : appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
4594 : : qpubname);
4595 : :
4596 : 211 : appendPQExpBuffer(query, "CREATE PUBLICATION %s",
4597 : : qpubname);
4598 : :
4599 [ + + ]: 211 : if (pubinfo->puballtables)
4600 : 38 : appendPQExpBufferStr(query, " FOR ALL TABLES");
4601 : :
3039 4602 : 211 : appendPQExpBufferStr(query, " WITH (publish = '");
3152 4603 [ + + ]: 211 : if (pubinfo->pubinsert)
4604 : : {
3039 4605 : 174 : appendPQExpBufferStr(query, "insert");
4606 : 174 : first = false;
4607 : : }
4608 : :
3152 4609 [ + + ]: 211 : if (pubinfo->pubupdate)
4610 : : {
3036 tgl@sss.pgh.pa.us 4611 [ + - ]: 174 : if (!first)
4612 : 174 : appendPQExpBufferStr(query, ", ");
4613 : :
3039 peter_e@gmx.net 4614 : 174 : appendPQExpBufferStr(query, "update");
4615 : 174 : first = false;
4616 : : }
4617 : :
3152 4618 [ + + ]: 211 : if (pubinfo->pubdelete)
4619 : : {
3036 tgl@sss.pgh.pa.us 4620 [ + - ]: 174 : if (!first)
4621 : 174 : appendPQExpBufferStr(query, ", ");
4622 : :
3039 peter_e@gmx.net 4623 : 174 : appendPQExpBufferStr(query, "delete");
4624 : 174 : first = false;
4625 : : }
4626 : :
2709 4627 [ + + ]: 211 : if (pubinfo->pubtruncate)
4628 : : {
4629 [ + - ]: 174 : if (!first)
4630 : 174 : appendPQExpBufferStr(query, ", ");
4631 : :
4632 : 174 : appendPQExpBufferStr(query, "truncate");
4633 : 174 : first = false;
4634 : : }
4635 : :
1096 drowley@postgresql.o 4636 : 211 : appendPQExpBufferChar(query, '\'');
4637 : :
1977 peter@eisentraut.org 4638 [ + + ]: 211 : if (pubinfo->pubviaroot)
4639 : 5 : appendPQExpBufferStr(query, ", publish_via_partition_root = true");
4640 : :
226 akapila@postgresql.o 4641 [ + + ]: 211 : if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
4642 : 37 : appendPQExpBufferStr(query, ", publish_generated_columns = stored");
4643 : :
1977 peter@eisentraut.org 4644 : 211 : appendPQExpBufferStr(query, ");\n");
4645 : :
1370 tgl@sss.pgh.pa.us 4646 [ + - ]: 211 : if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4647 : 211 : ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
4648 : 211 : ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
4649 : : .owner = pubinfo->rolname,
4650 : : .description = "PUBLICATION",
4651 : : .section = SECTION_POST_DATA,
4652 : : .createStmt = query->data,
4653 : : .dropStmt = delq->data));
4654 : :
3068 peter_e@gmx.net 4655 [ + + ]: 211 : if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 4656 : 37 : dumpComment(fout, "PUBLICATION", qpubname,
3068 peter_e@gmx.net 4657 : 37 : NULL, pubinfo->rolname,
4658 : 37 : pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4659 : :
4660 [ - + ]: 211 : if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 4661 :UBC 0 : dumpSecLabel(fout, "PUBLICATION", qpubname,
3068 peter_e@gmx.net 4662 : 0 : NULL, pubinfo->rolname,
4663 : 0 : pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4664 : :
3152 peter_e@gmx.net 4665 :CBC 211 : destroyPQExpBuffer(delq);
4666 : 211 : destroyPQExpBuffer(query);
2749 tgl@sss.pgh.pa.us 4667 : 211 : free(qpubname);
4668 : : }
4669 : :
4670 : : /*
4671 : : * getPublicationNamespaces
4672 : : * get information about publication membership for dumpable schemas.
4673 : : */
4674 : : void
1410 akapila@postgresql.o 4675 : 185 : getPublicationNamespaces(Archive *fout)
4676 : : {
4677 : : PQExpBuffer query;
4678 : : PGresult *res;
4679 : : PublicationSchemaInfo *pubsinfo;
4680 : 185 : DumpOptions *dopt = fout->dopt;
4681 : : int i_tableoid;
4682 : : int i_oid;
4683 : : int i_pnpubid;
4684 : : int i_pnnspid;
4685 : : int i,
4686 : : j,
4687 : : ntups;
4688 : :
4689 [ + - - + ]: 185 : if (dopt->no_publications || fout->remoteVersion < 150000)
1410 akapila@postgresql.o 4690 :UBC 0 : return;
4691 : :
1410 akapila@postgresql.o 4692 :CBC 185 : query = createPQExpBuffer();
4693 : :
4694 : : /* Collect all publication membership info. */
4695 : 185 : appendPQExpBufferStr(query,
4696 : : "SELECT tableoid, oid, pnpubid, pnnspid "
4697 : : "FROM pg_catalog.pg_publication_namespace");
4698 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4699 : :
4700 : 185 : ntups = PQntuples(res);
4701 : :
4702 : 185 : i_tableoid = PQfnumber(res, "tableoid");
4703 : 185 : i_oid = PQfnumber(res, "oid");
4704 : 185 : i_pnpubid = PQfnumber(res, "pnpubid");
4705 : 185 : i_pnnspid = PQfnumber(res, "pnnspid");
4706 : :
4707 : : /* this allocation may be more than we need */
4708 : 185 : pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
4709 : 185 : j = 0;
4710 : :
4711 [ + + ]: 322 : for (i = 0; i < ntups; i++)
4712 : : {
4713 : 137 : Oid pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
4714 : 137 : Oid pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
4715 : : PublicationInfo *pubinfo;
4716 : : NamespaceInfo *nspinfo;
4717 : :
4718 : : /*
4719 : : * Ignore any entries for which we aren't interested in either the
4720 : : * publication or the rel.
4721 : : */
4722 : 137 : pubinfo = findPublicationByOid(pnpubid);
4723 [ - + ]: 137 : if (pubinfo == NULL)
1410 akapila@postgresql.o 4724 :UBC 0 : continue;
1410 akapila@postgresql.o 4725 :CBC 137 : nspinfo = findNamespaceByOid(pnnspid);
4726 [ - + ]: 137 : if (nspinfo == NULL)
1410 akapila@postgresql.o 4727 :UBC 0 : continue;
4728 : :
4729 : : /* OK, make a DumpableObject for this relationship */
1397 akapila@postgresql.o 4730 :CBC 137 : pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
1410 4731 : 137 : pubsinfo[j].dobj.catId.tableoid =
4732 : 137 : atooid(PQgetvalue(res, i, i_tableoid));
4733 : 137 : pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4734 : 137 : AssignDumpId(&pubsinfo[j].dobj);
4735 : 137 : pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
4736 : 137 : pubsinfo[j].dobj.name = nspinfo->dobj.name;
4737 : 137 : pubsinfo[j].publication = pubinfo;
4738 : 137 : pubsinfo[j].pubschema = nspinfo;
4739 : :
4740 : : /* Decide whether we want to dump it */
4741 : 137 : selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
4742 : :
4743 : 137 : j++;
4744 : : }
4745 : :
4746 : 185 : PQclear(res);
4747 : 185 : destroyPQExpBuffer(query);
4748 : : }
4749 : :
4750 : : /*
4751 : : * getPublicationTables
4752 : : * get information about publication membership for dumpable tables.
4753 : : */
4754 : : void
3152 peter_e@gmx.net 4755 : 185 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
4756 : : {
4757 : : PQExpBuffer query;
4758 : : PGresult *res;
4759 : : PublicationRelInfo *pubrinfo;
2538 michael@paquier.xyz 4760 : 185 : DumpOptions *dopt = fout->dopt;
4761 : : int i_tableoid;
4762 : : int i_oid;
4763 : : int i_prpubid;
4764 : : int i_prrelid;
4765 : : int i_prrelqual;
4766 : : int i_prattrs;
4767 : : int i,
4768 : : j,
4769 : : ntups;
4770 : :
4771 [ + - - + ]: 185 : if (dopt->no_publications || fout->remoteVersion < 100000)
3152 peter_e@gmx.net 4772 :UBC 0 : return;
4773 : :
3152 peter_e@gmx.net 4774 :CBC 185 : query = createPQExpBuffer();
4775 : :
4776 : : /* Collect all publication membership info. */
1292 akapila@postgresql.o 4777 [ + - ]: 185 : if (fout->remoteVersion >= 150000)
4778 : 185 : appendPQExpBufferStr(query,
4779 : : "SELECT tableoid, oid, prpubid, prrelid, "
4780 : : "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
4781 : : "(CASE\n"
4782 : : " WHEN pr.prattrs IS NOT NULL THEN\n"
4783 : : " (SELECT array_agg(attname)\n"
4784 : : " FROM\n"
4785 : : " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
4786 : : " pg_catalog.pg_attribute\n"
4787 : : " WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
4788 : : " ELSE NULL END) prattrs "
4789 : : "FROM pg_catalog.pg_publication_rel pr");
4790 : : else
1292 akapila@postgresql.o 4791 :UBC 0 : appendPQExpBufferStr(query,
4792 : : "SELECT tableoid, oid, prpubid, prrelid, "
4793 : : "NULL AS prrelqual, NULL AS prattrs "
4794 : : "FROM pg_catalog.pg_publication_rel");
1696 tgl@sss.pgh.pa.us 4795 :CBC 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4796 : :
4797 : 185 : ntups = PQntuples(res);
4798 : :
4799 : 185 : i_tableoid = PQfnumber(res, "tableoid");
4800 : 185 : i_oid = PQfnumber(res, "oid");
4801 : 185 : i_prpubid = PQfnumber(res, "prpubid");
4802 : 185 : i_prrelid = PQfnumber(res, "prrelid");
1292 akapila@postgresql.o 4803 : 185 : i_prrelqual = PQfnumber(res, "prrelqual");
1260 tomas.vondra@postgre 4804 : 185 : i_prattrs = PQfnumber(res, "prattrs");
4805 : :
4806 : : /* this allocation may be more than we need */
1696 tgl@sss.pgh.pa.us 4807 : 185 : pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
4808 : 185 : j = 0;
4809 : :
4810 [ + + ]: 577 : for (i = 0; i < ntups; i++)
4811 : : {
4812 : 392 : Oid prpubid = atooid(PQgetvalue(res, i, i_prpubid));
4813 : 392 : Oid prrelid = atooid(PQgetvalue(res, i, i_prrelid));
4814 : : PublicationInfo *pubinfo;
4815 : : TableInfo *tbinfo;
4816 : :
4817 : : /*
4818 : : * Ignore any entries for which we aren't interested in either the
4819 : : * publication or the rel.
4820 : : */
4821 : 392 : pubinfo = findPublicationByOid(prpubid);
4822 [ - + ]: 392 : if (pubinfo == NULL)
1696 tgl@sss.pgh.pa.us 4823 :UBC 0 : continue;
1696 tgl@sss.pgh.pa.us 4824 :CBC 392 : tbinfo = findTableByOid(prrelid);
4825 [ - + ]: 392 : if (tbinfo == NULL)
3152 peter_e@gmx.net 4826 :UBC 0 : continue;
4827 : :
4828 : : /* OK, make a DumpableObject for this relationship */
1696 tgl@sss.pgh.pa.us 4829 :CBC 392 : pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
4830 : 392 : pubrinfo[j].dobj.catId.tableoid =
4831 : 392 : atooid(PQgetvalue(res, i, i_tableoid));
4832 : 392 : pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4833 : 392 : AssignDumpId(&pubrinfo[j].dobj);
4834 : 392 : pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4835 : 392 : pubrinfo[j].dobj.name = tbinfo->dobj.name;
4836 : 392 : pubrinfo[j].publication = pubinfo;
4837 : 392 : pubrinfo[j].pubtable = tbinfo;
1292 akapila@postgresql.o 4838 [ + + ]: 392 : if (PQgetisnull(res, i, i_prrelqual))
4839 : 218 : pubrinfo[j].pubrelqual = NULL;
4840 : : else
4841 : 174 : pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
4842 : :
1260 tomas.vondra@postgre 4843 [ + + ]: 392 : if (!PQgetisnull(res, i, i_prattrs))
4844 : : {
4845 : : char **attnames;
4846 : : int nattnames;
4847 : : PQExpBuffer attribs;
4848 : :
4849 [ - + ]: 123 : if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
4850 : : &attnames, &nattnames))
1247 tgl@sss.pgh.pa.us 4851 :UBC 0 : pg_fatal("could not parse %s array", "prattrs");
1260 tomas.vondra@postgre 4852 :CBC 123 : attribs = createPQExpBuffer();
4853 [ + + ]: 355 : for (int k = 0; k < nattnames; k++)
4854 : : {
4855 [ + + ]: 232 : if (k > 0)
4856 : 109 : appendPQExpBufferStr(attribs, ", ");
4857 : :
4858 : 232 : appendPQExpBufferStr(attribs, fmtId(attnames[k]));
4859 : : }
4860 : 123 : pubrinfo[j].pubrattrs = attribs->data;
206 tgl@sss.pgh.pa.us 4861 : 123 : free(attribs); /* but not attribs->data */
4862 : 123 : free(attnames);
4863 : : }
4864 : : else
1260 tomas.vondra@postgre 4865 : 269 : pubrinfo[j].pubrattrs = NULL;
4866 : :
4867 : : /* Decide whether we want to dump it */
1410 akapila@postgresql.o 4868 : 392 : selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
4869 : :
1696 tgl@sss.pgh.pa.us 4870 : 392 : j++;
4871 : : }
4872 : :
4873 : 185 : PQclear(res);
3152 peter_e@gmx.net 4874 : 185 : destroyPQExpBuffer(query);
4875 : : }
4876 : :
4877 : : /*
4878 : : * dumpPublicationNamespace
4879 : : * dump the definition of the given publication schema mapping.
4880 : : */
4881 : : static void
1410 akapila@postgresql.o 4882 : 111 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
4883 : : {
1346 tgl@sss.pgh.pa.us 4884 : 111 : DumpOptions *dopt = fout->dopt;
1410 akapila@postgresql.o 4885 : 111 : NamespaceInfo *schemainfo = pubsinfo->pubschema;
4886 : 111 : PublicationInfo *pubinfo = pubsinfo->publication;
4887 : : PQExpBuffer query;
4888 : : char *tag;
4889 : :
4890 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 4891 [ + + ]: 111 : if (!dopt->dumpSchema)
1410 akapila@postgresql.o 4892 : 12 : return;
4893 : :
4894 : 99 : tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
4895 : :
4896 : 99 : query = createPQExpBuffer();
4897 : :
4898 : 99 : appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
1080 alvherre@alvh.no-ip. 4899 : 99 : appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
4900 : :
4901 : : /*
4902 : : * There is no point in creating drop query as the drop is done by schema
4903 : : * drop.
4904 : : */
1346 tgl@sss.pgh.pa.us 4905 [ + - ]: 99 : if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4906 : 99 : ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
4907 : 99 : ARCHIVE_OPTS(.tag = tag,
4908 : : .namespace = schemainfo->dobj.name,
4909 : : .owner = pubinfo->rolname,
4910 : : .description = "PUBLICATION TABLES IN SCHEMA",
4911 : : .section = SECTION_POST_DATA,
4912 : : .createStmt = query->data));
4913 : :
4914 : : /* These objects can't currently have comments or seclabels */
4915 : :
1410 akapila@postgresql.o 4916 : 99 : free(tag);
4917 : 99 : destroyPQExpBuffer(query);
4918 : : }
4919 : :
4920 : : /*
4921 : : * dumpPublicationTable
4922 : : * dump the definition of the given publication table mapping
4923 : : */
4924 : : static void
1669 peter@eisentraut.org 4925 : 326 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
4926 : : {
1346 tgl@sss.pgh.pa.us 4927 : 326 : DumpOptions *dopt = fout->dopt;
1696 4928 : 326 : PublicationInfo *pubinfo = pubrinfo->publication;
3152 peter_e@gmx.net 4929 : 326 : TableInfo *tbinfo = pubrinfo->pubtable;
4930 : : PQExpBuffer query;
4931 : : char *tag;
4932 : :
4933 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 4934 [ + + ]: 326 : if (!dopt->dumpSchema)
1346 tgl@sss.pgh.pa.us 4935 : 42 : return;
4936 : :
1696 4937 : 284 : tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
4938 : :
3152 peter_e@gmx.net 4939 : 284 : query = createPQExpBuffer();
4940 : :
1248 tomas.vondra@postgre 4941 : 284 : appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4942 : 284 : fmtId(pubinfo->dobj.name));
1292 akapila@postgresql.o 4943 : 284 : appendPQExpBuffer(query, " %s",
2749 tgl@sss.pgh.pa.us 4944 : 284 : fmtQualifiedDumpable(tbinfo));
4945 : :
1260 tomas.vondra@postgre 4946 [ + + ]: 284 : if (pubrinfo->pubrattrs)
4947 : 89 : appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
4948 : :
1292 akapila@postgresql.o 4949 [ + + ]: 284 : if (pubrinfo->pubrelqual)
4950 : : {
4951 : : /*
4952 : : * It's necessary to add parentheses around the expression because
4953 : : * pg_get_expr won't supply the parentheses for things like WHERE
4954 : : * TRUE.
4955 : : */
4956 : 126 : appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
4957 : : }
4958 : 284 : appendPQExpBufferStr(query, ";\n");
4959 : :
4960 : : /*
4961 : : * There is no point in creating a drop query as the drop is done by table
4962 : : * drop. (If you think to change this, see also _printTocEntry().)
4963 : : * Although this object doesn't really have ownership as such, set the
4964 : : * owner field anyway to ensure that the command is run by the correct
4965 : : * role at restore time.
4966 : : */
1370 tgl@sss.pgh.pa.us 4967 [ + - ]: 284 : if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4968 : 284 : ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
4969 : 284 : ARCHIVE_OPTS(.tag = tag,
4970 : : .namespace = tbinfo->dobj.namespace->dobj.name,
4971 : : .owner = pubinfo->rolname,
4972 : : .description = "PUBLICATION TABLE",
4973 : : .section = SECTION_POST_DATA,
4974 : : .createStmt = query->data));
4975 : :
4976 : : /* These objects can't currently have comments or seclabels */
4977 : :
3152 peter_e@gmx.net 4978 : 284 : free(tag);
4979 : 284 : destroyPQExpBuffer(query);
4980 : : }
4981 : :
4982 : : /*
4983 : : * Is the currently connected user a superuser?
4984 : : */
4985 : : static bool
3070 4986 : 185 : is_superuser(Archive *fout)
4987 : : {
4988 : 185 : ArchiveHandle *AH = (ArchiveHandle *) fout;
4989 : : const char *val;
4990 : :
4991 : 185 : val = PQparameterStatus(AH->connection, "is_superuser");
4992 : :
4993 [ + - + + ]: 185 : if (val && strcmp(val, "on") == 0)
4994 : 182 : return true;
4995 : :
4996 : 3 : return false;
4997 : : }
4998 : :
4999 : : /*
5000 : : * Set the given value to restrict_nonsystem_relation_kind value. Since
5001 : : * restrict_nonsystem_relation_kind is introduced in minor version releases,
5002 : : * the setting query is effective only where available.
5003 : : */
5004 : : static void
397 msawada@postgresql.o 5005 : 221 : set_restrict_relation_kind(Archive *AH, const char *value)
5006 : : {
5007 : 221 : PQExpBuffer query = createPQExpBuffer();
5008 : : PGresult *res;
5009 : :
5010 : 221 : appendPQExpBuffer(query,
5011 : : "SELECT set_config(name, '%s', false) "
5012 : : "FROM pg_settings "
5013 : : "WHERE name = 'restrict_nonsystem_relation_kind'",
5014 : : value);
5015 : 221 : res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
5016 : :
5017 : 221 : PQclear(res);
5018 : 221 : destroyPQExpBuffer(query);
5019 : 221 : }
5020 : :
5021 : : /*
5022 : : * getSubscriptions
5023 : : * get information about subscriptions
5024 : : */
5025 : : void
3152 peter_e@gmx.net 5026 : 185 : getSubscriptions(Archive *fout)
5027 : : {
3042 5028 : 185 : DumpOptions *dopt = fout->dopt;
5029 : : PQExpBuffer query;
5030 : : PGresult *res;
5031 : : SubscriptionInfo *subinfo;
5032 : : int i_tableoid;
5033 : : int i_oid;
5034 : : int i_subname;
5035 : : int i_subowner;
5036 : : int i_subbinary;
5037 : : int i_substream;
5038 : : int i_subtwophasestate;
5039 : : int i_subdisableonerr;
5040 : : int i_subpasswordrequired;
5041 : : int i_subrunasowner;
5042 : : int i_subconninfo;
5043 : : int i_subslotname;
5044 : : int i_subsynccommit;
5045 : : int i_subpublications;
5046 : : int i_suborigin;
5047 : : int i_suboriginremotelsn;
5048 : : int i_subenabled;
5049 : : int i_subfailover;
5050 : : int i_subretaindeadtuples;
5051 : : int i_submaxretention;
5052 : : int i,
5053 : : ntups;
5054 : :
5055 [ + - - + ]: 185 : if (dopt->no_subscriptions || fout->remoteVersion < 100000)
3070 peter_e@gmx.net 5056 :UBC 0 : return;
5057 : :
3070 peter_e@gmx.net 5058 [ + + ]:CBC 185 : if (!is_superuser(fout))
5059 : : {
5060 : : int n;
5061 : :
5062 : 3 : res = ExecuteSqlQuery(fout,
5063 : : "SELECT count(*) FROM pg_subscription "
5064 : : "WHERE subdbid = (SELECT oid FROM pg_database"
5065 : : " WHERE datname = current_database())",
5066 : : PGRES_TUPLES_OK);
5067 : 3 : n = atoi(PQgetvalue(res, 0, 0));
5068 [ + + ]: 3 : if (n > 0)
2350 peter@eisentraut.org 5069 : 2 : pg_log_warning("subscriptions not dumped because current user is not a superuser");
3070 peter_e@gmx.net 5070 : 3 : PQclear(res);
3152 5071 : 3 : return;
5072 : : }
5073 : :
5074 : 182 : query = createPQExpBuffer();
5075 : :
5076 : : /* Get the subscriptions in current database. */
1096 drowley@postgresql.o 5077 : 182 : appendPQExpBufferStr(query,
5078 : : "SELECT s.tableoid, s.oid, s.subname,\n"
5079 : : " s.subowner,\n"
5080 : : " s.subconninfo, s.subslotname, s.subsynccommit,\n"
5081 : : " s.subpublications,\n");
5082 : :
1876 tgl@sss.pgh.pa.us 5083 [ + - ]: 182 : if (fout->remoteVersion >= 140000)
1787 drowley@postgresql.o 5084 : 182 : appendPQExpBufferStr(query, " s.subbinary,\n");
5085 : : else
1787 drowley@postgresql.o 5086 :UBC 0 : appendPQExpBufferStr(query, " false AS subbinary,\n");
5087 : :
1829 akapila@postgresql.o 5088 [ + - ]:CBC 182 : if (fout->remoteVersion >= 140000)
1515 5089 : 182 : appendPQExpBufferStr(query, " s.substream,\n");
5090 : : else
971 akapila@postgresql.o 5091 :UBC 0 : appendPQExpBufferStr(query, " 'f' AS substream,\n");
5092 : :
1515 akapila@postgresql.o 5093 [ + - ]:CBC 182 : if (fout->remoteVersion >= 150000)
1272 5094 : 182 : appendPQExpBufferStr(query,
5095 : : " s.subtwophasestate,\n"
5096 : : " s.subdisableonerr,\n");
5097 : : else
1515 akapila@postgresql.o 5098 :UBC 0 : appendPQExpBuffer(query,
5099 : : " '%c' AS subtwophasestate,\n"
5100 : : " false AS subdisableonerr,\n",
5101 : : LOGICALREP_TWOPHASE_STATE_DISABLED);
5102 : :
1143 akapila@postgresql.o 5103 [ + - ]:CBC 182 : if (fout->remoteVersion >= 160000)
891 rhaas@postgresql.org 5104 : 182 : appendPQExpBufferStr(query,
5105 : : " s.subpasswordrequired,\n"
5106 : : " s.subrunasowner,\n"
5107 : : " s.suborigin,\n");
5108 : : else
891 rhaas@postgresql.org 5109 :UBC 0 : appendPQExpBuffer(query,
5110 : : " 't' AS subpasswordrequired,\n"
5111 : : " 't' AS subrunasowner,\n"
5112 : : " '%s' AS suborigin,\n",
5113 : : LOGICALREP_ORIGIN_ANY);
5114 : :
613 akapila@postgresql.o 5115 [ + + + - ]:CBC 182 : if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5116 : 36 : appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
5117 : : " s.subenabled,\n");
5118 : : else
5119 : 146 : appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
5120 : : " false AS subenabled,\n");
5121 : :
501 5122 [ + - ]: 182 : if (fout->remoteVersion >= 170000)
5123 : 182 : appendPQExpBufferStr(query,
5124 : : " s.subfailover,\n");
5125 : : else
141 drowley@postgresql.o 5126 :UNC 0 : appendPQExpBufferStr(query,
5127 : : " false AS subfailover,\n");
5128 : :
45 akapila@postgresql.o 5129 [ + - ]:GNC 182 : if (fout->remoteVersion >= 190000)
5130 : 182 : appendPQExpBufferStr(query,
5131 : : " s.subretaindeadtuples,\n");
5132 : : else
45 akapila@postgresql.o 5133 :UBC 0 : appendPQExpBufferStr(query,
5134 : : " false AS subretaindeadtuples,\n");
5135 : :
4 akapila@postgresql.o 5136 [ + - ]:GNC 182 : if (fout->remoteVersion >= 190000)
5137 : 182 : appendPQExpBufferStr(query,
5138 : : " s.submaxretention\n");
5139 : : else
4 akapila@postgresql.o 5140 :UNC 0 : appendPQExpBuffer(query,
5141 : : " 0 AS submaxretention\n");
5142 : :
613 akapila@postgresql.o 5143 :CBC 182 : appendPQExpBufferStr(query,
5144 : : "FROM pg_subscription s\n");
5145 : :
5146 [ + + + - ]: 182 : if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5147 : 36 : appendPQExpBufferStr(query,
5148 : : "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
5149 : : " ON o.external_id = 'pg_' || s.oid::text \n");
5150 : :
1787 drowley@postgresql.o 5151 : 182 : appendPQExpBufferStr(query,
5152 : : "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
5153 : : " WHERE datname = current_database())");
5154 : :
3152 peter_e@gmx.net 5155 : 182 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5156 : :
5157 : 182 : ntups = PQntuples(res);
5158 : :
5159 : : /*
5160 : : * Get subscription fields. We don't include subskiplsn in the dump as
5161 : : * after restoring the dump this value may no longer be relevant.
5162 : : */
5163 : 182 : i_tableoid = PQfnumber(res, "tableoid");
5164 : 182 : i_oid = PQfnumber(res, "oid");
5165 : 182 : i_subname = PQfnumber(res, "subname");
1345 tgl@sss.pgh.pa.us 5166 : 182 : i_subowner = PQfnumber(res, "subowner");
277 michael@paquier.xyz 5167 : 182 : i_subenabled = PQfnumber(res, "subenabled");
1876 tgl@sss.pgh.pa.us 5168 : 182 : i_subbinary = PQfnumber(res, "subbinary");
1829 akapila@postgresql.o 5169 : 182 : i_substream = PQfnumber(res, "substream");
1515 5170 : 182 : i_subtwophasestate = PQfnumber(res, "subtwophasestate");
1272 5171 : 182 : i_subdisableonerr = PQfnumber(res, "subdisableonerr");
891 rhaas@postgresql.org 5172 : 182 : i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
678 tgl@sss.pgh.pa.us 5173 : 182 : i_subrunasowner = PQfnumber(res, "subrunasowner");
277 michael@paquier.xyz 5174 : 182 : i_subfailover = PQfnumber(res, "subfailover");
45 akapila@postgresql.o 5175 :GNC 182 : i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
4 5176 : 182 : i_submaxretention = PQfnumber(res, "submaxretention");
678 tgl@sss.pgh.pa.us 5177 :CBC 182 : i_subconninfo = PQfnumber(res, "subconninfo");
5178 : 182 : i_subslotname = PQfnumber(res, "subslotname");
5179 : 182 : i_subsynccommit = PQfnumber(res, "subsynccommit");
5180 : 182 : i_subpublications = PQfnumber(res, "subpublications");
5181 : 182 : i_suborigin = PQfnumber(res, "suborigin");
613 akapila@postgresql.o 5182 : 182 : i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
5183 : :
3152 peter_e@gmx.net 5184 : 182 : subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
5185 : :
5186 [ + + ]: 331 : for (i = 0; i < ntups; i++)
5187 : : {
5188 : 149 : subinfo[i].dobj.objType = DO_SUBSCRIPTION;
5189 : 149 : subinfo[i].dobj.catId.tableoid =
5190 : 149 : atooid(PQgetvalue(res, i, i_tableoid));
5191 : 149 : subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5192 : 149 : AssignDumpId(&subinfo[i].dobj);
5193 : 149 : subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
1345 tgl@sss.pgh.pa.us 5194 : 149 : subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
5195 : :
277 michael@paquier.xyz 5196 : 149 : subinfo[i].subenabled =
5197 : 149 : (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
1876 tgl@sss.pgh.pa.us 5198 : 149 : subinfo[i].subbinary =
277 michael@paquier.xyz 5199 : 149 : (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
5200 : 149 : subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
5201 : 149 : subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
1272 akapila@postgresql.o 5202 : 149 : subinfo[i].subdisableonerr =
277 michael@paquier.xyz 5203 : 149 : (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
891 rhaas@postgresql.org 5204 : 149 : subinfo[i].subpasswordrequired =
277 michael@paquier.xyz 5205 : 149 : (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
678 tgl@sss.pgh.pa.us 5206 : 149 : subinfo[i].subrunasowner =
277 michael@paquier.xyz 5207 : 149 : (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
5208 : 149 : subinfo[i].subfailover =
5209 : 149 : (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
45 akapila@postgresql.o 5210 :GNC 149 : subinfo[i].subretaindeadtuples =
5211 : 149 : (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
4 5212 : 149 : subinfo[i].submaxretention =
5213 : 149 : atoi(PQgetvalue(res, i, i_submaxretention));
678 tgl@sss.pgh.pa.us 5214 :CBC 298 : subinfo[i].subconninfo =
5215 : 149 : pg_strdup(PQgetvalue(res, i, i_subconninfo));
5216 [ - + ]: 149 : if (PQgetisnull(res, i, i_subslotname))
678 tgl@sss.pgh.pa.us 5217 :UBC 0 : subinfo[i].subslotname = NULL;
5218 : : else
678 tgl@sss.pgh.pa.us 5219 :CBC 149 : subinfo[i].subslotname =
5220 : 149 : pg_strdup(PQgetvalue(res, i, i_subslotname));
5221 : 298 : subinfo[i].subsynccommit =
5222 : 149 : pg_strdup(PQgetvalue(res, i, i_subsynccommit));
5223 : 298 : subinfo[i].subpublications =
5224 : 149 : pg_strdup(PQgetvalue(res, i, i_subpublications));
5225 : 149 : subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
613 akapila@postgresql.o 5226 [ + + ]: 149 : if (PQgetisnull(res, i, i_suboriginremotelsn))
5227 : 148 : subinfo[i].suboriginremotelsn = NULL;
5228 : : else
5229 : 1 : subinfo[i].suboriginremotelsn =
5230 : 1 : pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
5231 : :
5232 : : /* Decide whether we want to dump it */
3070 peter_e@gmx.net 5233 : 149 : selectDumpableObject(&(subinfo[i].dobj), fout);
5234 : : }
3152 5235 : 182 : PQclear(res);
5236 : :
5237 : 182 : destroyPQExpBuffer(query);
5238 : : }
5239 : :
5240 : : /*
5241 : : * getSubscriptionTables
5242 : : * Get information about subscription membership for dumpable tables. This
5243 : : * will be used only in binary-upgrade mode for PG17 or later versions.
5244 : : */
5245 : : void
613 akapila@postgresql.o 5246 : 185 : getSubscriptionTables(Archive *fout)
5247 : : {
5248 : 185 : DumpOptions *dopt = fout->dopt;
5249 : 185 : SubscriptionInfo *subinfo = NULL;
5250 : : SubRelInfo *subrinfo;
5251 : : PGresult *res;
5252 : : int i_srsubid;
5253 : : int i_srrelid;
5254 : : int i_srsubstate;
5255 : : int i_srsublsn;
5256 : : int ntups;
5257 : 185 : Oid last_srsubid = InvalidOid;
5258 : :
5259 [ + - + + ]: 185 : if (dopt->no_subscriptions || !dopt->binary_upgrade ||
5260 [ - + ]: 36 : fout->remoteVersion < 170000)
5261 : 149 : return;
5262 : :
5263 : 36 : res = ExecuteSqlQuery(fout,
5264 : : "SELECT srsubid, srrelid, srsubstate, srsublsn "
5265 : : "FROM pg_catalog.pg_subscription_rel "
5266 : : "ORDER BY srsubid",
5267 : : PGRES_TUPLES_OK);
5268 : 36 : ntups = PQntuples(res);
5269 [ + + ]: 36 : if (ntups == 0)
5270 : 35 : goto cleanup;
5271 : :
5272 : : /* Get pg_subscription_rel attributes */
5273 : 1 : i_srsubid = PQfnumber(res, "srsubid");
5274 : 1 : i_srrelid = PQfnumber(res, "srrelid");
5275 : 1 : i_srsubstate = PQfnumber(res, "srsubstate");
5276 : 1 : i_srsublsn = PQfnumber(res, "srsublsn");
5277 : :
5278 : 1 : subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
5279 [ + + ]: 3 : for (int i = 0; i < ntups; i++)
5280 : : {
5281 : 2 : Oid cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
5282 : 2 : Oid relid = atooid(PQgetvalue(res, i, i_srrelid));
5283 : : TableInfo *tblinfo;
5284 : :
5285 : : /*
5286 : : * If we switched to a new subscription, check if the subscription
5287 : : * exists.
5288 : : */
5289 [ + - ]: 2 : if (cur_srsubid != last_srsubid)
5290 : : {
5291 : 2 : subinfo = findSubscriptionByOid(cur_srsubid);
5292 [ - + ]: 2 : if (subinfo == NULL)
613 akapila@postgresql.o 5293 :UBC 0 : pg_fatal("subscription with OID %u does not exist", cur_srsubid);
5294 : :
613 akapila@postgresql.o 5295 :CBC 2 : last_srsubid = cur_srsubid;
5296 : : }
5297 : :
5298 : 2 : tblinfo = findTableByOid(relid);
5299 [ - + ]: 2 : if (tblinfo == NULL)
613 akapila@postgresql.o 5300 :UBC 0 : pg_fatal("failed sanity check, table with OID %u not found",
5301 : : relid);
5302 : :
5303 : : /* OK, make a DumpableObject for this relationship */
613 akapila@postgresql.o 5304 :CBC 2 : subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
5305 : 2 : subrinfo[i].dobj.catId.tableoid = relid;
5306 : 2 : subrinfo[i].dobj.catId.oid = cur_srsubid;
5307 : 2 : AssignDumpId(&subrinfo[i].dobj);
5308 : 2 : subrinfo[i].dobj.name = pg_strdup(subinfo->dobj.name);
5309 : 2 : subrinfo[i].tblinfo = tblinfo;
5310 : 2 : subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
5311 [ + + ]: 2 : if (PQgetisnull(res, i, i_srsublsn))
5312 : 1 : subrinfo[i].srsublsn = NULL;
5313 : : else
5314 : 1 : subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
5315 : :
5316 : 2 : subrinfo[i].subinfo = subinfo;
5317 : :
5318 : : /* Decide whether we want to dump it */
5319 : 2 : selectDumpableObject(&(subrinfo[i].dobj), fout);
5320 : : }
5321 : :
5322 : 1 : cleanup:
5323 : 36 : PQclear(res);
5324 : : }
5325 : :
5326 : : /*
5327 : : * dumpSubscriptionTable
5328 : : * Dump the definition of the given subscription table mapping. This will be
5329 : : * used only in binary-upgrade mode for PG17 or later versions.
5330 : : */
5331 : : static void
5332 : 2 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
5333 : : {
5334 : 2 : DumpOptions *dopt = fout->dopt;
5335 : 2 : SubscriptionInfo *subinfo = subrinfo->subinfo;
5336 : : PQExpBuffer query;
5337 : : char *tag;
5338 : :
5339 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 5340 [ - + ]: 2 : if (!dopt->dumpSchema)
613 akapila@postgresql.o 5341 :UBC 0 : return;
5342 : :
613 akapila@postgresql.o 5343 [ + - + - ]:CBC 2 : Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
5344 : :
5345 : 2 : tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->dobj.name);
5346 : :
5347 : 2 : query = createPQExpBuffer();
5348 : :
5349 [ + - ]: 2 : if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5350 : : {
5351 : : /*
5352 : : * binary_upgrade_add_sub_rel_state will add the subscription relation
5353 : : * to pg_subscription_rel table. This will be used only in
5354 : : * binary-upgrade mode.
5355 : : */
5356 : 2 : appendPQExpBufferStr(query,
5357 : : "\n-- For binary upgrade, must preserve the subscriber table.\n");
5358 : 2 : appendPQExpBufferStr(query,
5359 : : "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
5360 : 2 : appendStringLiteralAH(query, subrinfo->dobj.name, fout);
5361 : 2 : appendPQExpBuffer(query,
5362 : : ", %u, '%c'",
5363 : 2 : subrinfo->tblinfo->dobj.catId.oid,
5364 : 2 : subrinfo->srsubstate);
5365 : :
5366 [ + + + - ]: 2 : if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
5367 : 1 : appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
5368 : : else
141 drowley@postgresql.o 5369 : 1 : appendPQExpBufferStr(query, ", NULL");
5370 : :
613 akapila@postgresql.o 5371 : 2 : appendPQExpBufferStr(query, ");\n");
5372 : : }
5373 : :
5374 : : /*
5375 : : * There is no point in creating a drop query as the drop is done by table
5376 : : * drop. (If you think to change this, see also _printTocEntry().)
5377 : : * Although this object doesn't really have ownership as such, set the
5378 : : * owner field anyway to ensure that the command is run by the correct
5379 : : * role at restore time.
5380 : : */
5381 [ + - ]: 2 : if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5382 : 2 : ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
5383 : 2 : ARCHIVE_OPTS(.tag = tag,
5384 : : .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
5385 : : .owner = subinfo->rolname,
5386 : : .description = "SUBSCRIPTION TABLE",
5387 : : .section = SECTION_POST_DATA,
5388 : : .createStmt = query->data));
5389 : :
5390 : : /* These objects can't currently have comments or seclabels */
5391 : :
5392 : 2 : free(tag);
5393 : 2 : destroyPQExpBuffer(query);
5394 : : }
5395 : :
5396 : : /*
5397 : : * dumpSubscription
5398 : : * dump the definition of the given subscription
5399 : : */
5400 : : static void
1669 peter@eisentraut.org 5401 : 131 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
5402 : : {
1346 tgl@sss.pgh.pa.us 5403 : 131 : DumpOptions *dopt = fout->dopt;
5404 : : PQExpBuffer delq;
5405 : : PQExpBuffer query;
5406 : : PQExpBuffer publications;
5407 : : char *qsubname;
3152 peter_e@gmx.net 5408 : 131 : char **pubnames = NULL;
5409 : 131 : int npubnames = 0;
5410 : : int i;
5411 : :
5412 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 5413 [ + + ]: 131 : if (!dopt->dumpSchema)
1346 tgl@sss.pgh.pa.us 5414 : 18 : return;
5415 : :
3152 peter_e@gmx.net 5416 : 113 : delq = createPQExpBuffer();
5417 : 113 : query = createPQExpBuffer();
5418 : :
2749 tgl@sss.pgh.pa.us 5419 : 113 : qsubname = pg_strdup(fmtId(subinfo->dobj.name));
5420 : :
3152 peter_e@gmx.net 5421 : 113 : appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
5422 : : qsubname);
5423 : :
5424 : 113 : appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
5425 : : qsubname);
5426 : 113 : appendStringLiteralAH(query, subinfo->subconninfo, fout);
5427 : :
5428 : : /* Build list of quoted publications and append them to query. */
5429 [ - + ]: 113 : if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
1247 tgl@sss.pgh.pa.us 5430 :UBC 0 : pg_fatal("could not parse %s array", "subpublications");
5431 : :
3152 peter_e@gmx.net 5432 :CBC 113 : publications = createPQExpBuffer();
5433 [ + + ]: 226 : for (i = 0; i < npubnames; i++)
5434 : : {
5435 [ - + ]: 113 : if (i > 0)
3152 peter_e@gmx.net 5436 :UBC 0 : appendPQExpBufferStr(publications, ", ");
5437 : :
3152 peter_e@gmx.net 5438 :CBC 113 : appendPQExpBufferStr(publications, fmtId(pubnames[i]));
5439 : : }
5440 : :
3039 5441 : 113 : appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
3034 5442 [ + - ]: 113 : if (subinfo->subslotname)
5443 : 113 : appendStringLiteralAH(query, subinfo->subslotname, fout);
5444 : : else
3034 peter_e@gmx.net 5445 :UBC 0 : appendPQExpBufferStr(query, "NONE");
5446 : :
277 michael@paquier.xyz 5447 [ - + ]:CBC 113 : if (subinfo->subbinary)
1787 drowley@postgresql.o 5448 :UBC 0 : appendPQExpBufferStr(query, ", binary = true");
5449 : :
277 michael@paquier.xyz 5450 [ + + ]:CBC 113 : if (subinfo->substream == LOGICALREP_STREAM_ON)
1787 drowley@postgresql.o 5451 : 37 : appendPQExpBufferStr(query, ", streaming = on");
277 michael@paquier.xyz 5452 [ + + ]: 76 : else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
971 akapila@postgresql.o 5453 : 39 : appendPQExpBufferStr(query, ", streaming = parallel");
5454 : : else
313 5455 : 37 : appendPQExpBufferStr(query, ", streaming = off");
5456 : :
277 michael@paquier.xyz 5457 [ - + ]: 113 : if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
1515 akapila@postgresql.o 5458 :UBC 0 : appendPQExpBufferStr(query, ", two_phase = on");
5459 : :
277 michael@paquier.xyz 5460 [ - + ]:CBC 113 : if (subinfo->subdisableonerr)
1272 akapila@postgresql.o 5461 :UBC 0 : appendPQExpBufferStr(query, ", disable_on_error = true");
5462 : :
277 michael@paquier.xyz 5463 [ - + ]:CBC 113 : if (!subinfo->subpasswordrequired)
141 drowley@postgresql.o 5464 :UBC 0 : appendPQExpBufferStr(query, ", password_required = false");
5465 : :
277 michael@paquier.xyz 5466 [ - + ]:CBC 113 : if (subinfo->subrunasowner)
678 tgl@sss.pgh.pa.us 5467 :UBC 0 : appendPQExpBufferStr(query, ", run_as_owner = true");
5468 : :
277 michael@paquier.xyz 5469 [ + + ]:CBC 113 : if (subinfo->subfailover)
501 akapila@postgresql.o 5470 : 1 : appendPQExpBufferStr(query, ", failover = true");
5471 : :
45 akapila@postgresql.o 5472 [ + + ]:GNC 113 : if (subinfo->subretaindeadtuples)
5473 : 1 : appendPQExpBufferStr(query, ", retain_dead_tuples = true");
5474 : :
4 5475 [ - + ]: 113 : if (subinfo->submaxretention)
4 akapila@postgresql.o 5476 :UNC 0 : appendPQExpBuffer(query, ", max_retention_duration = %d", subinfo->submaxretention);
5477 : :
3067 peter_e@gmx.net 5478 [ - + ]:CBC 113 : if (strcmp(subinfo->subsynccommit, "off") != 0)
3039 peter_e@gmx.net 5479 :UBC 0 : appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
5480 : :
678 tgl@sss.pgh.pa.us 5481 [ + + ]:CBC 113 : if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
5482 : 37 : appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
5483 : :
3152 peter_e@gmx.net 5484 : 113 : appendPQExpBufferStr(query, ");\n");
5485 : :
5486 : : /*
5487 : : * In binary-upgrade mode, we allow the replication to continue after the
5488 : : * upgrade.
5489 : : */
613 akapila@postgresql.o 5490 [ + + + - ]: 113 : if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5491 : : {
5492 [ + + ]: 5 : if (subinfo->suboriginremotelsn)
5493 : : {
5494 : : /*
5495 : : * Preserve the remote_lsn for the subscriber's replication
5496 : : * origin. This value is required to start the replication from
5497 : : * the position before the upgrade. This value will be stale if
5498 : : * the publisher gets upgraded before the subscriber node.
5499 : : * However, this shouldn't be a problem as the upgrade of the
5500 : : * publisher ensures that all the transactions were replicated
5501 : : * before upgrading it.
5502 : : */
5503 : 1 : appendPQExpBufferStr(query,
5504 : : "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
5505 : 1 : appendPQExpBufferStr(query,
5506 : : "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
5507 : 1 : appendStringLiteralAH(query, subinfo->dobj.name, fout);
5508 : 1 : appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
5509 : : }
5510 : :
277 michael@paquier.xyz 5511 [ + + ]: 5 : if (subinfo->subenabled)
5512 : : {
5513 : : /*
5514 : : * Enable the subscription to allow the replication to continue
5515 : : * after the upgrade.
5516 : : */
613 akapila@postgresql.o 5517 : 1 : appendPQExpBufferStr(query,
5518 : : "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
5519 : 1 : appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
5520 : : }
5521 : : }
5522 : :
1370 tgl@sss.pgh.pa.us 5523 [ + - ]: 113 : if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5524 : 113 : ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
5525 : 113 : ARCHIVE_OPTS(.tag = subinfo->dobj.name,
5526 : : .owner = subinfo->rolname,
5527 : : .description = "SUBSCRIPTION",
5528 : : .section = SECTION_POST_DATA,
5529 : : .createStmt = query->data,
5530 : : .dropStmt = delq->data));
5531 : :
3068 peter_e@gmx.net 5532 [ + + ]: 113 : if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 5533 : 37 : dumpComment(fout, "SUBSCRIPTION", qsubname,
3068 peter_e@gmx.net 5534 : 37 : NULL, subinfo->rolname,
5535 : 37 : subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5536 : :
5537 [ - + ]: 113 : if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 5538 :UBC 0 : dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
3068 peter_e@gmx.net 5539 : 0 : NULL, subinfo->rolname,
5540 : 0 : subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5541 : :
3152 peter_e@gmx.net 5542 :CBC 113 : destroyPQExpBuffer(publications);
1178 peter@eisentraut.org 5543 : 113 : free(pubnames);
5544 : :
3152 peter_e@gmx.net 5545 : 113 : destroyPQExpBuffer(delq);
5546 : 113 : destroyPQExpBuffer(query);
2749 tgl@sss.pgh.pa.us 5547 : 113 : free(qsubname);
5548 : : }
5549 : :
5550 : : /*
5551 : : * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
5552 : : * the object needs.
5553 : : */
5554 : : static void
2005 alvherre@alvh.no-ip. 5555 : 5324 : append_depends_on_extension(Archive *fout,
5556 : : PQExpBuffer create,
5557 : : const DumpableObject *dobj,
5558 : : const char *catalog,
5559 : : const char *keyword,
5560 : : const char *objname)
5561 : : {
5562 [ + + ]: 5324 : if (dobj->depends_on_ext)
5563 : : {
5564 : : char *nm;
5565 : : PGresult *res;
5566 : : PQExpBuffer query;
5567 : : int ntups;
5568 : : int i_extname;
5569 : : int i;
5570 : :
5571 : : /* dodge fmtId() non-reentrancy */
5572 : 42 : nm = pg_strdup(objname);
5573 : :
5574 : 42 : query = createPQExpBuffer();
5575 : 42 : appendPQExpBuffer(query,
5576 : : "SELECT e.extname "
5577 : : "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
5578 : : "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
5579 : : "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
5580 : : "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
5581 : : catalog,
5582 : 42 : dobj->catId.oid);
5583 : 42 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5584 : 42 : ntups = PQntuples(res);
5585 : 42 : i_extname = PQfnumber(res, "extname");
5586 [ + + ]: 84 : for (i = 0; i < ntups; i++)
5587 : : {
743 5588 : 42 : appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
5589 : : keyword, nm,
2005 5590 : 42 : fmtId(PQgetvalue(res, i, i_extname)));
5591 : : }
5592 : :
5593 : 42 : PQclear(res);
2000 5594 : 42 : destroyPQExpBuffer(query);
2005 5595 : 42 : pg_free(nm);
5596 : : }
5597 : 5324 : }
5598 : :
5599 : : static Oid
1721 akorotkov@postgresql 5600 :UBC 0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
5601 : : {
5602 : : /*
5603 : : * If the old version didn't assign an array type, but the new version
5604 : : * does, we must select an unused type OID to assign. This currently only
5605 : : * happens for domains, when upgrading pre-v11 to v11 and up.
5606 : : *
5607 : : * Note: local state here is kind of ugly, but we must have some, since we
5608 : : * mustn't choose the same unused OID more than once.
5609 : : */
5610 : : static Oid next_possible_free_oid = FirstNormalObjectId;
5611 : : PGresult *res;
5612 : : bool is_dup;
5613 : :
5614 : : do
5615 : : {
5616 : 0 : ++next_possible_free_oid;
5617 : 0 : printfPQExpBuffer(upgrade_query,
5618 : : "SELECT EXISTS(SELECT 1 "
5619 : : "FROM pg_catalog.pg_type "
5620 : : "WHERE oid = '%u'::pg_catalog.oid);",
5621 : : next_possible_free_oid);
5622 : 0 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5623 : 0 : is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
5624 : 0 : PQclear(res);
5625 [ # # ]: 0 : } while (is_dup);
5626 : :
5627 : 0 : return next_possible_free_oid;
5628 : : }
5629 : :
5630 : : static void
4960 rhaas@postgresql.org 5631 :CBC 943 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
5632 : : PQExpBuffer upgrade_buffer,
5633 : : Oid pg_type_oid,
5634 : : bool force_array_type,
5635 : : bool include_multirange_type)
5636 : : {
5735 bruce@momjian.us 5637 : 943 : PQExpBuffer upgrade_query = createPQExpBuffer();
5638 : : PGresult *res;
5639 : : Oid pg_type_array_oid;
5640 : : Oid pg_type_multirange_oid;
5641 : : Oid pg_type_multirange_array_oid;
5642 : : TypeInfo *tinfo;
5643 : :
4310 heikki.linnakangas@i 5644 : 943 : appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
5735 bruce@momjian.us 5645 : 943 : appendPQExpBuffer(upgrade_buffer,
5646 : : "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5647 : : pg_type_oid);
5648 : :
369 dgustafsson@postgres 5649 : 943 : tinfo = findTypeByOid(pg_type_oid);
366 5650 [ + - ]: 943 : if (tinfo)
5651 : 943 : pg_type_array_oid = tinfo->typarray;
5652 : : else
366 dgustafsson@postgres 5653 :UBC 0 : pg_type_array_oid = InvalidOid;
5654 : :
2898 tgl@sss.pgh.pa.us 5655 [ + + - + ]:CBC 943 : if (!OidIsValid(pg_type_array_oid) && force_array_type)
1721 akorotkov@postgresql 5656 :UBC 0 : pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5657 : :
5735 bruce@momjian.us 5658 [ + + ]:CBC 943 : if (OidIsValid(pg_type_array_oid))
5659 : : {
4310 heikki.linnakangas@i 5660 : 941 : appendPQExpBufferStr(upgrade_buffer,
5661 : : "\n-- For binary upgrade, must preserve pg_type array oid\n");
5735 bruce@momjian.us 5662 : 941 : appendPQExpBuffer(upgrade_buffer,
5663 : : "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5664 : : pg_type_array_oid);
5665 : : }
5666 : :
5667 : : /*
5668 : : * Pre-set the multirange type oid and its own array type oid.
5669 : : */
1721 akorotkov@postgresql 5670 [ + + ]: 943 : if (include_multirange_type)
5671 : : {
5672 [ + - ]: 8 : if (fout->remoteVersion >= 140000)
5673 : : {
1322 tgl@sss.pgh.pa.us 5674 : 8 : printfPQExpBuffer(upgrade_query,
5675 : : "SELECT t.oid, t.typarray "
5676 : : "FROM pg_catalog.pg_type t "
5677 : : "JOIN pg_catalog.pg_range r "
5678 : : "ON t.oid = r.rngmultitypid "
5679 : : "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
5680 : : pg_type_oid);
5681 : :
1721 akorotkov@postgresql 5682 : 8 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5683 : :
5684 : 8 : pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
5685 : 8 : pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
5686 : :
5687 : 8 : PQclear(res);
5688 : : }
5689 : : else
5690 : : {
1721 akorotkov@postgresql 5691 :UBC 0 : pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5692 : 0 : pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5693 : : }
5694 : :
1721 akorotkov@postgresql 5695 :CBC 8 : appendPQExpBufferStr(upgrade_buffer,
5696 : : "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
5697 : 8 : appendPQExpBuffer(upgrade_buffer,
5698 : : "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5699 : : pg_type_multirange_oid);
5700 : 8 : appendPQExpBufferStr(upgrade_buffer,
5701 : : "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
5702 : 8 : appendPQExpBuffer(upgrade_buffer,
5703 : : "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5704 : : pg_type_multirange_array_oid);
5705 : : }
5706 : :
5735 bruce@momjian.us 5707 : 943 : destroyPQExpBuffer(upgrade_query);
5708 : 943 : }
5709 : :
5710 : : static void
1370 tgl@sss.pgh.pa.us 5711 : 868 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
5712 : : PQExpBuffer upgrade_buffer,
5713 : : const TableInfo *tbinfo)
5714 : : {
5715 : 868 : Oid pg_type_oid = tbinfo->reltype;
5716 : :
1887 5717 [ + - ]: 868 : if (OidIsValid(pg_type_oid))
5718 : 868 : binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
5719 : : pg_type_oid, false, false);
5735 bruce@momjian.us 5720 : 868 : }
5721 : :
5722 : : /*
5723 : : * bsearch() comparator for BinaryUpgradeClassOidItem
5724 : : */
5725 : : static int
430 nathan@postgresql.or 5726 : 12361 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
5727 : : {
5728 : 12361 : BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
5729 : 12361 : BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
5730 : :
5731 : 12361 : return pg_cmp_u32(v1.oid, v2.oid);
5732 : : }
5733 : :
5734 : : /*
5735 : : * collectBinaryUpgradeClassOids
5736 : : *
5737 : : * Construct a table of pg_class information required for
5738 : : * binary_upgrade_set_pg_class_oids(). The table is sorted by OID for speed in
5739 : : * lookup.
5740 : : */
5741 : : static void
5742 : 36 : collectBinaryUpgradeClassOids(Archive *fout)
5743 : : {
5744 : : PGresult *res;
5745 : : const char *query;
5746 : :
5747 : 36 : query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
5748 : : "ct.relfilenode, i.indexrelid, cti.relfilenode "
5749 : : "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
5750 : : "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
5751 : : "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
5752 : : "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
5753 : : "ORDER BY c.oid;";
5754 : :
5755 : 36 : res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
5756 : :
5757 : 36 : nbinaryUpgradeClassOids = PQntuples(res);
5758 : 36 : binaryUpgradeClassOids = (BinaryUpgradeClassOidItem *)
5759 : 36 : pg_malloc(nbinaryUpgradeClassOids * sizeof(BinaryUpgradeClassOidItem));
5760 : :
5761 [ + + ]: 16826 : for (int i = 0; i < nbinaryUpgradeClassOids; i++)
5762 : : {
5763 : 16790 : binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
5764 : 16790 : binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
5765 : 16790 : binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
5766 : 16790 : binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
5767 : 16790 : binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
5768 : 16790 : binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
5769 : 16790 : binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
5770 : : }
5771 : :
5772 : 36 : PQclear(res);
5773 : 36 : }
5774 : :
5775 : : static void
4960 rhaas@postgresql.org 5776 : 1254 : binary_upgrade_set_pg_class_oids(Archive *fout,
5777 : : PQExpBuffer upgrade_buffer, Oid pg_class_oid)
5778 : : {
430 nathan@postgresql.or 5779 : 1254 : BinaryUpgradeClassOidItem key = {0};
5780 : : BinaryUpgradeClassOidItem *entry;
5781 : :
5782 [ - + ]: 1254 : Assert(binaryUpgradeClassOids);
5783 : :
5784 : : /*
5785 : : * Preserve the OID and relfilenumber of the table, table's index, table's
5786 : : * toast table and toast table's index if any.
5787 : : *
5788 : : * One complexity is that the current table definition might not require
5789 : : * the creation of a TOAST table, but the old database might have a TOAST
5790 : : * table that was created earlier, before some wide columns were dropped.
5791 : : * By setting the TOAST oid we force creation of the TOAST heap and index
5792 : : * by the new backend, so we can copy the files during binary upgrade
5793 : : * without worrying about this case.
5794 : : */
5795 : 1254 : key.oid = pg_class_oid;
5796 : 1254 : entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
5797 : : sizeof(BinaryUpgradeClassOidItem),
5798 : : BinaryUpgradeClassOidItemCmp);
5799 : :
4310 heikki.linnakangas@i 5800 : 1254 : appendPQExpBufferStr(upgrade_buffer,
5801 : : "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
5802 : :
430 nathan@postgresql.or 5803 [ + + ]: 1254 : if (entry->relkind != RELKIND_INDEX &&
5804 [ + + ]: 977 : entry->relkind != RELKIND_PARTITIONED_INDEX)
5805 : : {
5722 bruce@momjian.us 5806 : 952 : appendPQExpBuffer(upgrade_buffer,
5807 : : "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
5808 : : pg_class_oid);
5809 : :
5810 : : /*
5811 : : * Not every relation has storage. Also, in a pre-v12 database,
5812 : : * partitioned tables have a relfilenumber, which should not be
5813 : : * preserved when upgrading.
5814 : : */
430 nathan@postgresql.or 5815 [ + + ]: 952 : if (RelFileNumberIsValid(entry->relfilenumber) &&
5816 [ + - ]: 790 : entry->relkind != RELKIND_PARTITIONED_TABLE)
1328 rhaas@postgresql.org 5817 : 790 : appendPQExpBuffer(upgrade_buffer,
5818 : : "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
5819 : : entry->relfilenumber);
5820 : :
5821 : : /*
5822 : : * In a pre-v12 database, partitioned tables might be marked as having
5823 : : * toast tables, but we should ignore them if so.
5824 : : */
430 nathan@postgresql.or 5825 [ + + ]: 952 : if (OidIsValid(entry->toast_oid) &&
5826 [ + - ]: 280 : entry->relkind != RELKIND_PARTITIONED_TABLE)
5827 : : {
5358 bruce@momjian.us 5828 : 280 : appendPQExpBuffer(upgrade_buffer,
5829 : : "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
5830 : : entry->toast_oid);
1328 rhaas@postgresql.org 5831 : 280 : appendPQExpBuffer(upgrade_buffer,
5832 : : "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
5833 : : entry->toast_relfilenumber);
5834 : :
5835 : : /* every toast table has an index */
5358 bruce@momjian.us 5836 : 280 : appendPQExpBuffer(upgrade_buffer,
5837 : : "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5838 : : entry->toast_index_oid);
1328 rhaas@postgresql.org 5839 : 280 : appendPQExpBuffer(upgrade_buffer,
5840 : : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5841 : : entry->toast_index_relfilenumber);
5842 : : }
5843 : : }
5844 : : else
5845 : : {
5846 : : /* Preserve the OID and relfilenumber of the index */
5722 bruce@momjian.us 5847 : 302 : appendPQExpBuffer(upgrade_buffer,
5848 : : "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5849 : : pg_class_oid);
1328 rhaas@postgresql.org 5850 : 302 : appendPQExpBuffer(upgrade_buffer,
5851 : : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5852 : : entry->relfilenumber);
5853 : : }
5854 : :
4310 heikki.linnakangas@i 5855 : 1254 : appendPQExpBufferChar(upgrade_buffer, '\n');
5735 bruce@momjian.us 5856 : 1254 : }
5857 : :
5858 : : /*
5859 : : * If the DumpableObject is a member of an extension, add a suitable
5860 : : * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
5861 : : *
5862 : : * For somewhat historical reasons, objname should already be quoted,
5863 : : * but not objnamespace (if any).
5864 : : */
5865 : : static void
5323 tgl@sss.pgh.pa.us 5866 : 1499 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
5867 : : const DumpableObject *dobj,
5868 : : const char *objtype,
5869 : : const char *objname,
5870 : : const char *objnamespace)
5871 : : {
5872 : 1499 : DumpableObject *extobj = NULL;
5873 : : int i;
5874 : :
5875 [ + + ]: 1499 : if (!dobj->ext_member)
5876 : 1483 : return;
5877 : :
5878 : : /*
5879 : : * Find the parent extension. We could avoid this search if we wanted to
5880 : : * add a link field to DumpableObject, but the space costs of that would
5881 : : * be considerable. We assume that member objects could only have a
5882 : : * direct dependency on their own extension, not any others.
5883 : : */
5884 [ + - ]: 16 : for (i = 0; i < dobj->nDeps; i++)
5885 : : {
5886 : 16 : extobj = findObjectByDumpId(dobj->dependencies[i]);
5887 [ + - + - ]: 16 : if (extobj && extobj->objType == DO_EXTENSION)
5888 : 16 : break;
5323 tgl@sss.pgh.pa.us 5889 :UBC 0 : extobj = NULL;
5890 : : }
5323 tgl@sss.pgh.pa.us 5891 [ - + ]:CBC 16 : if (extobj == NULL)
1247 tgl@sss.pgh.pa.us 5892 :UBC 0 : pg_fatal("could not find parent extension for %s %s",
5893 : : objtype, objname);
5894 : :
4310 heikki.linnakangas@i 5895 :CBC 16 : appendPQExpBufferStr(upgrade_buffer,
5896 : : "\n-- For binary upgrade, handle extension membership the hard way\n");
2749 tgl@sss.pgh.pa.us 5897 : 16 : appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
5323 5898 : 16 : fmtId(extobj->name),
5899 : : objtype);
2749 5900 [ + + + - ]: 16 : if (objnamespace && *objnamespace)
5901 : 13 : appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
5902 : 16 : appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
5903 : : }
5904 : :
5905 : : /*
5906 : : * getNamespaces:
5907 : : * get information about all namespaces in the system catalogs
5908 : : */
5909 : : void
431 nathan@postgresql.or 5910 : 186 : getNamespaces(Archive *fout)
5911 : : {
5912 : : PGresult *res;
5913 : : int ntups;
5914 : : int i;
5915 : : PQExpBuffer query;
5916 : : NamespaceInfo *nsinfo;
5917 : : int i_tableoid;
5918 : : int i_oid;
5919 : : int i_nspname;
5920 : : int i_nspowner;
5921 : : int i_nspacl;
5922 : : int i_acldefault;
5923 : :
8520 tgl@sss.pgh.pa.us 5924 : 186 : query = createPQExpBuffer();
5925 : :
5926 : : /*
5927 : : * we fetch all namespaces including system ones, so that every object we
5928 : : * read in can be linked to a containing namespace.
5929 : : */
1096 drowley@postgresql.o 5930 : 186 : appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
5931 : : "n.nspowner, "
5932 : : "n.nspacl, "
5933 : : "acldefault('n', n.nspowner) AS acldefault "
5934 : : "FROM pg_namespace n");
5935 : :
4960 rhaas@postgresql.org 5936 : 186 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5937 : :
10226 bruce@momjian.us 5938 : 186 : ntups = PQntuples(res);
5939 : :
5034 5940 : 186 : nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
5941 : :
7945 tgl@sss.pgh.pa.us 5942 : 186 : i_tableoid = PQfnumber(res, "tableoid");
10226 bruce@momjian.us 5943 : 186 : i_oid = PQfnumber(res, "oid");
8520 tgl@sss.pgh.pa.us 5944 : 186 : i_nspname = PQfnumber(res, "nspname");
1531 noah@leadboat.com 5945 : 186 : i_nspowner = PQfnumber(res, "nspowner");
8520 tgl@sss.pgh.pa.us 5946 : 186 : i_nspacl = PQfnumber(res, "nspacl");
1370 5947 : 186 : i_acldefault = PQfnumber(res, "acldefault");
5948 : :
10226 bruce@momjian.us 5949 [ + + ]: 1620 : for (i = 0; i < ntups; i++)
5950 : : {
5951 : : const char *nspowner;
5952 : :
7945 tgl@sss.pgh.pa.us 5953 : 1434 : nsinfo[i].dobj.objType = DO_NAMESPACE;
5954 : 1434 : nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5955 : 1434 : nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5956 : 1434 : AssignDumpId(&nsinfo[i].dobj);
5034 bruce@momjian.us 5957 : 1434 : nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
1370 tgl@sss.pgh.pa.us 5958 : 1434 : nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
5959 : 1434 : nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
5960 : 1434 : nsinfo[i].dacl.privtype = 0;
5961 : 1434 : nsinfo[i].dacl.initprivs = NULL;
1345 5962 : 1434 : nspowner = PQgetvalue(res, i, i_nspowner);
5963 : 1434 : nsinfo[i].nspowner = atooid(nspowner);
5964 : 1434 : nsinfo[i].rolname = getRoleName(nspowner);
5965 : :
5966 : : /* Decide whether to dump this namespace */
3440 sfrost@snowman.net 5967 : 1434 : selectDumpableNamespace(&nsinfo[i], fout);
5968 : :
5969 : : /* Mark whether namespace has an ACL */
1370 tgl@sss.pgh.pa.us 5970 [ + + ]: 1434 : if (!PQgetisnull(res, i, i_nspacl))
5971 : 626 : nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5972 : :
5973 : : /*
5974 : : * We ignore any pg_init_privs.initprivs entry for the public schema
5975 : : * and assume a predetermined default, for several reasons. First,
5976 : : * dropping and recreating the schema removes its pg_init_privs entry,
5977 : : * but an empty destination database starts with this ACL nonetheless.
5978 : : * Second, we support dump/reload of public schema ownership changes.
5979 : : * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
5980 : : * initprivs continues to reflect the initial owner. Hence,
5981 : : * synthesize the value that nspacl will have after the restore's
5982 : : * ALTER SCHEMA OWNER. Third, this makes the destination database
5983 : : * match the source's ACL, even if the latter was an initdb-default
5984 : : * ACL, which changed in v15. An upgrade pulls in changes to most
5985 : : * system object ACLs that the DBA had not customized. We've made the
5986 : : * public schema depart from that, because changing its ACL so easily
5987 : : * breaks applications.
5988 : : */
5989 [ + + ]: 1434 : if (strcmp(nsinfo[i].dobj.name, "public") == 0)
5990 : : {
5991 : 182 : PQExpBuffer aclarray = createPQExpBuffer();
5992 : 182 : PQExpBuffer aclitem = createPQExpBuffer();
5993 : :
5994 : : /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
5995 : 182 : appendPQExpBufferChar(aclarray, '{');
5996 : 182 : quoteAclUserName(aclitem, nsinfo[i].rolname);
5997 : 182 : appendPQExpBufferStr(aclitem, "=UC/");
5998 : 182 : quoteAclUserName(aclitem, nsinfo[i].rolname);
5999 : 182 : appendPGArray(aclarray, aclitem->data);
6000 : 182 : resetPQExpBuffer(aclitem);
6001 : 182 : appendPQExpBufferStr(aclitem, "=U/");
6002 : 182 : quoteAclUserName(aclitem, nsinfo[i].rolname);
6003 : 182 : appendPGArray(aclarray, aclitem->data);
6004 : 182 : appendPQExpBufferChar(aclarray, '}');
6005 : :
6006 : 182 : nsinfo[i].dacl.privtype = 'i';
6007 : 182 : nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
6008 : 182 : nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6009 : :
6010 : 182 : destroyPQExpBuffer(aclarray);
6011 : 182 : destroyPQExpBuffer(aclitem);
6012 : : }
6013 : : }
6014 : :
10226 bruce@momjian.us 6015 : 186 : PQclear(res);
8800 tgl@sss.pgh.pa.us 6016 : 186 : destroyPQExpBuffer(query);
10323 scrappy@hub.org 6017 : 186 : }
6018 : :
6019 : : /*
6020 : : * findNamespace:
6021 : : * given a namespace OID, look up the info read by getNamespaces
6022 : : */
6023 : : static NamespaceInfo *
1838 peter@eisentraut.org 6024 : 714800 : findNamespace(Oid nsoid)
6025 : : {
6026 : : NamespaceInfo *nsinfo;
6027 : :
3251 tgl@sss.pgh.pa.us 6028 : 714800 : nsinfo = findNamespaceByOid(nsoid);
4852 6029 [ - + ]: 714800 : if (nsinfo == NULL)
1247 tgl@sss.pgh.pa.us 6030 :UBC 0 : pg_fatal("schema with OID %u does not exist", nsoid);
4852 tgl@sss.pgh.pa.us 6031 :CBC 714800 : return nsinfo;
6032 : : }
6033 : :
6034 : : /*
6035 : : * getExtensions:
6036 : : * read all extensions in the system catalogs and return them in the
6037 : : * ExtensionInfo* structure
6038 : : *
6039 : : * numExtensions is set to the number of extensions read in
6040 : : */
6041 : : ExtensionInfo *
3524 6042 : 186 : getExtensions(Archive *fout, int *numExtensions)
6043 : : {
6044 : 186 : DumpOptions *dopt = fout->dopt;
6045 : : PGresult *res;
6046 : : int ntups;
6047 : : int i;
6048 : : PQExpBuffer query;
339 dgustafsson@postgres 6049 : 186 : ExtensionInfo *extinfo = NULL;
6050 : : int i_tableoid;
6051 : : int i_oid;
6052 : : int i_extname;
6053 : : int i_nspname;
6054 : : int i_extrelocatable;
6055 : : int i_extversion;
6056 : : int i_extconfig;
6057 : : int i_extcondition;
6058 : :
5324 tgl@sss.pgh.pa.us 6059 : 186 : query = createPQExpBuffer();
6060 : :
4310 heikki.linnakangas@i 6061 : 186 : appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
6062 : : "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
6063 : : "FROM pg_extension x "
6064 : : "JOIN pg_namespace n ON n.oid = x.extnamespace");
6065 : :
4960 rhaas@postgresql.org 6066 : 186 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6067 : :
5324 tgl@sss.pgh.pa.us 6068 : 186 : ntups = PQntuples(res);
339 dgustafsson@postgres 6069 [ - + ]: 186 : if (ntups == 0)
339 dgustafsson@postgres 6070 :UBC 0 : goto cleanup;
6071 : :
5034 bruce@momjian.us 6072 :CBC 186 : extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
6073 : :
5324 tgl@sss.pgh.pa.us 6074 : 186 : i_tableoid = PQfnumber(res, "tableoid");
6075 : 186 : i_oid = PQfnumber(res, "oid");
6076 : 186 : i_extname = PQfnumber(res, "extname");
6077 : 186 : i_nspname = PQfnumber(res, "nspname");
5323 6078 : 186 : i_extrelocatable = PQfnumber(res, "extrelocatable");
6079 : 186 : i_extversion = PQfnumber(res, "extversion");
5324 6080 : 186 : i_extconfig = PQfnumber(res, "extconfig");
6081 : 186 : i_extcondition = PQfnumber(res, "extcondition");
6082 : :
6083 [ + + ]: 397 : for (i = 0; i < ntups; i++)
6084 : : {
6085 : 211 : extinfo[i].dobj.objType = DO_EXTENSION;
6086 : 211 : extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6087 : 211 : extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6088 : 211 : AssignDumpId(&extinfo[i].dobj);
5034 bruce@momjian.us 6089 : 211 : extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
6090 : 211 : extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
5323 tgl@sss.pgh.pa.us 6091 : 211 : extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
5034 bruce@momjian.us 6092 : 211 : extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
6093 : 211 : extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
6094 : 211 : extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
6095 : :
6096 : : /* Decide whether we want to dump it */
3524 tgl@sss.pgh.pa.us 6097 : 211 : selectDumpableExtension(&(extinfo[i]), dopt);
6098 : : }
6099 : :
339 dgustafsson@postgres 6100 : 186 : cleanup:
5324 tgl@sss.pgh.pa.us 6101 : 186 : PQclear(res);
6102 : 186 : destroyPQExpBuffer(query);
6103 : :
6104 : 186 : *numExtensions = ntups;
6105 : :
6106 : 186 : return extinfo;
6107 : : }
6108 : :
6109 : : /*
6110 : : * getTypes:
6111 : : * get information about all types in the system catalogs
6112 : : *
6113 : : * NB: this must run after getFuncs() because we assume we can do
6114 : : * findFuncByOid().
6115 : : */
6116 : : void
431 nathan@postgresql.or 6117 : 185 : getTypes(Archive *fout)
6118 : : {
6119 : : PGresult *res;
6120 : : int ntups;
6121 : : int i;
9278 bruce@momjian.us 6122 : 185 : PQExpBuffer query = createPQExpBuffer();
6123 : : TypeInfo *tyinfo;
6124 : : ShellTypeInfo *stinfo;
6125 : : int i_tableoid;
6126 : : int i_oid;
6127 : : int i_typname;
6128 : : int i_typnamespace;
6129 : : int i_typacl;
6130 : : int i_acldefault;
6131 : : int i_typowner;
6132 : : int i_typelem;
6133 : : int i_typrelid;
6134 : : int i_typrelkind;
6135 : : int i_typtype;
6136 : : int i_typisdefined;
6137 : : int i_isarray;
6138 : : int i_typarray;
6139 : :
6140 : : /*
6141 : : * we include even the built-in types because those may be used as array
6142 : : * elements by user-defined types
6143 : : *
6144 : : * we filter out the built-in types when we dump out the types
6145 : : *
6146 : : * same approach for undefined (shell) types and array types
6147 : : *
6148 : : * Note: as of 8.3 we can reliably detect whether a type is an
6149 : : * auto-generated array type by checking the element type's typarray.
6150 : : * (Before that the test is capable of generating false positives.) We
6151 : : * still check for name beginning with '_', though, so as to avoid the
6152 : : * cost of the subselect probe for all standard types. This would have to
6153 : : * be revisited if the backend ever allows renaming of array types.
6154 : : */
1096 drowley@postgresql.o 6155 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
6156 : : "typnamespace, typacl, "
6157 : : "acldefault('T', typowner) AS acldefault, "
6158 : : "typowner, "
6159 : : "typelem, typrelid, typarray, "
6160 : : "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
6161 : : "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
6162 : : "typtype, typisdefined, "
6163 : : "typname[0] = '_' AND typelem != 0 AND "
6164 : : "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
6165 : : "FROM pg_type");
6166 : :
4960 rhaas@postgresql.org 6167 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6168 : :
10226 bruce@momjian.us 6169 : 185 : ntups = PQntuples(res);
6170 : :
5034 6171 : 185 : tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
6172 : :
7945 tgl@sss.pgh.pa.us 6173 : 185 : i_tableoid = PQfnumber(res, "tableoid");
10226 bruce@momjian.us 6174 : 185 : i_oid = PQfnumber(res, "oid");
8520 tgl@sss.pgh.pa.us 6175 : 185 : i_typname = PQfnumber(res, "typname");
6176 : 185 : i_typnamespace = PQfnumber(res, "typnamespace");
4654 6177 : 185 : i_typacl = PQfnumber(res, "typacl");
1370 6178 : 185 : i_acldefault = PQfnumber(res, "acldefault");
1345 6179 : 185 : i_typowner = PQfnumber(res, "typowner");
8520 6180 : 185 : i_typelem = PQfnumber(res, "typelem");
6181 : 185 : i_typrelid = PQfnumber(res, "typrelid");
8423 bruce@momjian.us 6182 : 185 : i_typrelkind = PQfnumber(res, "typrelkind");
8520 tgl@sss.pgh.pa.us 6183 : 185 : i_typtype = PQfnumber(res, "typtype");
6184 : 185 : i_typisdefined = PQfnumber(res, "typisdefined");
6693 6185 : 185 : i_isarray = PQfnumber(res, "isarray");
369 dgustafsson@postgres 6186 : 185 : i_typarray = PQfnumber(res, "typarray");
6187 : :
10226 bruce@momjian.us 6188 [ + + ]: 134940 : for (i = 0; i < ntups; i++)
6189 : : {
5736 6190 : 134755 : tyinfo[i].dobj.objType = DO_TYPE;
6191 : 134755 : tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6192 : 134755 : tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6193 : 134755 : AssignDumpId(&tyinfo[i].dobj);
5034 6194 : 134755 : tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4961 rhaas@postgresql.org 6195 : 269510 : tyinfo[i].dobj.namespace =
1838 peter@eisentraut.org 6196 : 134755 : findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
1370 tgl@sss.pgh.pa.us 6197 : 134755 : tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
6198 : 134755 : tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6199 : 134755 : tyinfo[i].dacl.privtype = 0;
6200 : 134755 : tyinfo[i].dacl.initprivs = NULL;
1467 6201 : 134755 : tyinfo[i].ftypname = NULL; /* may get filled later */
1345 6202 : 134755 : tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
5736 bruce@momjian.us 6203 : 134755 : tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
6204 : 134755 : tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
6205 : 134755 : tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
6206 : 134755 : tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
6207 : 134755 : tyinfo[i].shellType = NULL;
6208 : :
8520 tgl@sss.pgh.pa.us 6209 [ + + ]: 134755 : if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
5736 bruce@momjian.us 6210 : 134697 : tyinfo[i].isDefined = true;
6211 : : else
6212 : 58 : tyinfo[i].isDefined = false;
6213 : :
6693 tgl@sss.pgh.pa.us 6214 [ + + ]: 134755 : if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
5736 bruce@momjian.us 6215 : 64666 : tyinfo[i].isArray = true;
6216 : : else
6217 : 70089 : tyinfo[i].isArray = false;
6218 : :
369 dgustafsson@postgres 6219 : 134755 : tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
6220 : :
570 tgl@sss.pgh.pa.us 6221 [ + + ]: 134755 : if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
1721 akorotkov@postgresql 6222 : 1254 : tyinfo[i].isMultirange = true;
6223 : : else
6224 : 133501 : tyinfo[i].isMultirange = false;
6225 : :
6226 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 6227 : 134755 : selectDumpableType(&tyinfo[i], fout);
6228 : :
6229 : : /* Mark whether type has an ACL */
1370 tgl@sss.pgh.pa.us 6230 [ + + ]: 134755 : if (!PQgetisnull(res, i, i_typacl))
6231 : 229 : tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6232 : :
6233 : : /*
6234 : : * If it's a domain, fetch info about its constraints, if any
6235 : : */
5736 bruce@momjian.us 6236 : 134755 : tyinfo[i].nDomChecks = 0;
6237 : 134755 : tyinfo[i].domChecks = NULL;
47 alvherre@kurilemu.de 6238 : 134755 : tyinfo[i].notnull = NULL;
3440 sfrost@snowman.net 6239 [ + + ]: 134755 : if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6240 [ + + ]: 15879 : tyinfo[i].typtype == TYPTYPE_DOMAIN)
4961 rhaas@postgresql.org 6241 : 164 : getDomainConstraints(fout, &(tyinfo[i]));
6242 : :
6243 : : /*
6244 : : * If it's a base type, make a DumpableObject representing a shell
6245 : : * definition of the type. We will need to dump that ahead of the I/O
6246 : : * functions for the type. Similarly, range types need a shell
6247 : : * definition in case they have a canonicalize function.
6248 : : *
6249 : : * Note: the shell type doesn't have a catId. You might think it
6250 : : * should copy the base type's catId, but then it might capture the
6251 : : * pg_depend entries for the type, which we don't want.
6252 : : */
3440 sfrost@snowman.net 6253 [ + + ]: 134755 : if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6254 [ + + ]: 15879 : (tyinfo[i].typtype == TYPTYPE_BASE ||
6255 [ + + ]: 7723 : tyinfo[i].typtype == TYPTYPE_RANGE))
6256 : : {
5034 bruce@momjian.us 6257 : 8292 : stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
7128 tgl@sss.pgh.pa.us 6258 : 8292 : stinfo->dobj.objType = DO_SHELL_TYPE;
6259 : 8292 : stinfo->dobj.catId = nilCatalogId;
6260 : 8292 : AssignDumpId(&stinfo->dobj);
5034 bruce@momjian.us 6261 : 8292 : stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
5736 6262 : 8292 : stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
6263 : 8292 : stinfo->baseType = &(tyinfo[i]);
6264 : 8292 : tyinfo[i].shellType = stinfo;
6265 : :
6266 : : /*
6267 : : * Initially mark the shell type as not to be dumped. We'll only
6268 : : * dump it if the I/O or canonicalize functions need to be dumped;
6269 : : * this is taken care of while sorting dependencies.
6270 : : */
3440 sfrost@snowman.net 6271 : 8292 : stinfo->dobj.dump = DUMP_COMPONENT_NONE;
6272 : : }
6273 : : }
6274 : :
10226 bruce@momjian.us 6275 : 185 : PQclear(res);
6276 : :
8800 tgl@sss.pgh.pa.us 6277 : 185 : destroyPQExpBuffer(query);
10651 scrappy@hub.org 6278 : 185 : }
6279 : :
6280 : : /*
6281 : : * getOperators:
6282 : : * get information about all operators in the system catalogs
6283 : : */
6284 : : void
431 nathan@postgresql.or 6285 : 185 : getOperators(Archive *fout)
6286 : : {
6287 : : PGresult *res;
6288 : : int ntups;
6289 : : int i;
9278 bruce@momjian.us 6290 : 185 : PQExpBuffer query = createPQExpBuffer();
6291 : : OprInfo *oprinfo;
6292 : : int i_tableoid;
6293 : : int i_oid;
6294 : : int i_oprname;
6295 : : int i_oprnamespace;
6296 : : int i_oprowner;
6297 : : int i_oprkind;
6298 : : int i_oprleft;
6299 : : int i_oprright;
6300 : : int i_oprcode;
6301 : :
6302 : : /*
6303 : : * find all operators, including builtin operators; we filter out
6304 : : * system-defined operators at dump-out time.
6305 : : */
6306 : :
1096 drowley@postgresql.o 6307 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
6308 : : "oprnamespace, "
6309 : : "oprowner, "
6310 : : "oprkind, "
6311 : : "oprleft, "
6312 : : "oprright, "
6313 : : "oprcode::oid AS oprcode "
6314 : : "FROM pg_operator");
6315 : :
4960 rhaas@postgresql.org 6316 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6317 : :
10226 bruce@momjian.us 6318 : 185 : ntups = PQntuples(res);
6319 : :
5034 6320 : 185 : oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
6321 : :
7945 tgl@sss.pgh.pa.us 6322 : 185 : i_tableoid = PQfnumber(res, "tableoid");
10226 bruce@momjian.us 6323 : 185 : i_oid = PQfnumber(res, "oid");
8520 tgl@sss.pgh.pa.us 6324 : 185 : i_oprname = PQfnumber(res, "oprname");
6325 : 185 : i_oprnamespace = PQfnumber(res, "oprnamespace");
1345 6326 : 185 : i_oprowner = PQfnumber(res, "oprowner");
4993 peter_e@gmx.net 6327 : 185 : i_oprkind = PQfnumber(res, "oprkind");
37 noah@leadboat.com 6328 : 185 : i_oprleft = PQfnumber(res, "oprleft");
6329 : 185 : i_oprright = PQfnumber(res, "oprright");
8520 tgl@sss.pgh.pa.us 6330 : 185 : i_oprcode = PQfnumber(res, "oprcode");
6331 : :
10226 bruce@momjian.us 6332 [ + + ]: 148148 : for (i = 0; i < ntups; i++)
6333 : : {
7945 tgl@sss.pgh.pa.us 6334 : 147963 : oprinfo[i].dobj.objType = DO_OPERATOR;
6335 : 147963 : oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6336 : 147963 : oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6337 : 147963 : AssignDumpId(&oprinfo[i].dobj);
5034 bruce@momjian.us 6338 : 147963 : oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
4961 rhaas@postgresql.org 6339 : 295926 : oprinfo[i].dobj.namespace =
1838 peter@eisentraut.org 6340 : 147963 : findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
1345 tgl@sss.pgh.pa.us 6341 : 147963 : oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
4993 peter_e@gmx.net 6342 : 147963 : oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
37 noah@leadboat.com 6343 : 147963 : oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
6344 : 147963 : oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
7945 tgl@sss.pgh.pa.us 6345 : 147963 : oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
6346 : :
6347 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 6348 : 147963 : selectDumpableObject(&(oprinfo[i].dobj), fout);
6349 : : }
6350 : :
10226 bruce@momjian.us 6351 : 185 : PQclear(res);
6352 : :
8800 tgl@sss.pgh.pa.us 6353 : 185 : destroyPQExpBuffer(query);
10651 scrappy@hub.org 6354 : 185 : }
6355 : :
6356 : : /*
6357 : : * getCollations:
6358 : : * get information about all collations in the system catalogs
6359 : : */
6360 : : void
431 nathan@postgresql.or 6361 : 185 : getCollations(Archive *fout)
6362 : : {
6363 : : PGresult *res;
6364 : : int ntups;
6365 : : int i;
6366 : : PQExpBuffer query;
6367 : : CollInfo *collinfo;
6368 : : int i_tableoid;
6369 : : int i_oid;
6370 : : int i_collname;
6371 : : int i_collnamespace;
6372 : : int i_collowner;
6373 : : int i_collencoding;
6374 : :
4925 peter_e@gmx.net 6375 : 185 : query = createPQExpBuffer();
6376 : :
6377 : : /*
6378 : : * find all collations, including builtin collations; we filter out
6379 : : * system-defined collations at dump-out time.
6380 : : */
6381 : :
1096 drowley@postgresql.o 6382 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
6383 : : "collnamespace, "
6384 : : "collowner, "
6385 : : "collencoding "
6386 : : "FROM pg_collation");
6387 : :
4960 rhaas@postgresql.org 6388 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6389 : :
5320 peter_e@gmx.net 6390 : 185 : ntups = PQntuples(res);
6391 : :
5034 bruce@momjian.us 6392 : 185 : collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
6393 : :
5320 peter_e@gmx.net 6394 : 185 : i_tableoid = PQfnumber(res, "tableoid");
6395 : 185 : i_oid = PQfnumber(res, "oid");
6396 : 185 : i_collname = PQfnumber(res, "collname");
6397 : 185 : i_collnamespace = PQfnumber(res, "collnamespace");
1345 tgl@sss.pgh.pa.us 6398 : 185 : i_collowner = PQfnumber(res, "collowner");
37 noah@leadboat.com 6399 : 185 : i_collencoding = PQfnumber(res, "collencoding");
6400 : :
5320 peter_e@gmx.net 6401 [ + + ]: 281138 : for (i = 0; i < ntups; i++)
6402 : : {
6403 : 280953 : collinfo[i].dobj.objType = DO_COLLATION;
6404 : 280953 : collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6405 : 280953 : collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6406 : 280953 : AssignDumpId(&collinfo[i].dobj);
5034 bruce@momjian.us 6407 : 280953 : collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
4961 rhaas@postgresql.org 6408 : 561906 : collinfo[i].dobj.namespace =
1838 peter@eisentraut.org 6409 : 280953 : findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
1345 tgl@sss.pgh.pa.us 6410 : 280953 : collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
37 noah@leadboat.com 6411 : 280953 : collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
6412 : :
6413 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 6414 : 280953 : selectDumpableObject(&(collinfo[i].dobj), fout);
6415 : : }
6416 : :
5320 peter_e@gmx.net 6417 : 185 : PQclear(res);
6418 : :
6419 : 185 : destroyPQExpBuffer(query);
6420 : 185 : }
6421 : :
6422 : : /*
6423 : : * getConversions:
6424 : : * get information about all conversions in the system catalogs
6425 : : */
6426 : : void
431 nathan@postgresql.or 6427 : 185 : getConversions(Archive *fout)
6428 : : {
6429 : : PGresult *res;
6430 : : int ntups;
6431 : : int i;
6432 : : PQExpBuffer query;
6433 : : ConvInfo *convinfo;
6434 : : int i_tableoid;
6435 : : int i_oid;
6436 : : int i_conname;
6437 : : int i_connamespace;
6438 : : int i_conowner;
6439 : :
4241 sfrost@snowman.net 6440 : 185 : query = createPQExpBuffer();
6441 : :
6442 : : /*
6443 : : * find all conversions, including builtin conversions; we filter out
6444 : : * system-defined conversions at dump-out time.
6445 : : */
6446 : :
1096 drowley@postgresql.o 6447 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
6448 : : "connamespace, "
6449 : : "conowner "
6450 : : "FROM pg_conversion");
6451 : :
4960 rhaas@postgresql.org 6452 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6453 : :
7960 tgl@sss.pgh.pa.us 6454 : 185 : ntups = PQntuples(res);
6455 : :
5034 bruce@momjian.us 6456 : 185 : convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
6457 : :
7945 tgl@sss.pgh.pa.us 6458 : 185 : i_tableoid = PQfnumber(res, "tableoid");
7960 6459 : 185 : i_oid = PQfnumber(res, "oid");
6460 : 185 : i_conname = PQfnumber(res, "conname");
6461 : 185 : i_connamespace = PQfnumber(res, "connamespace");
1345 6462 : 185 : i_conowner = PQfnumber(res, "conowner");
6463 : :
7960 6464 [ + + ]: 23916 : for (i = 0; i < ntups; i++)
6465 : : {
7945 6466 : 23731 : convinfo[i].dobj.objType = DO_CONVERSION;
6467 : 23731 : convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6468 : 23731 : convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6469 : 23731 : AssignDumpId(&convinfo[i].dobj);
5034 bruce@momjian.us 6470 : 23731 : convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
4961 rhaas@postgresql.org 6471 : 47462 : convinfo[i].dobj.namespace =
1838 peter@eisentraut.org 6472 : 23731 : findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
1345 tgl@sss.pgh.pa.us 6473 : 23731 : convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
6474 : :
6475 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 6476 : 23731 : selectDumpableObject(&(convinfo[i].dobj), fout);
6477 : : }
6478 : :
7960 tgl@sss.pgh.pa.us 6479 : 185 : PQclear(res);
6480 : :
6481 : 185 : destroyPQExpBuffer(query);
6482 : 185 : }
6483 : :
6484 : : /*
6485 : : * getAccessMethods:
6486 : : * get information about all user-defined access methods
6487 : : */
6488 : : void
431 nathan@postgresql.or 6489 : 185 : getAccessMethods(Archive *fout)
6490 : : {
6491 : : PGresult *res;
6492 : : int ntups;
6493 : : int i;
6494 : : PQExpBuffer query;
6495 : : AccessMethodInfo *aminfo;
6496 : : int i_tableoid;
6497 : : int i_oid;
6498 : : int i_amname;
6499 : : int i_amhandler;
6500 : : int i_amtype;
6501 : :
3454 alvherre@alvh.no-ip. 6502 : 185 : query = createPQExpBuffer();
6503 : :
6504 : : /*
6505 : : * Select all access methods from pg_am table. v9.6 introduced CREATE
6506 : : * ACCESS METHOD, so earlier versions usually have only built-in access
6507 : : * methods. v9.6 also changed the access method API, replacing dozens of
6508 : : * pg_am columns with amhandler. Even if a user created an access method
6509 : : * by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am
6510 : : * columns to a v9.6+ CREATE ACCESS METHOD. Hence, before v9.6, read
6511 : : * pg_am just to facilitate findAccessMethodByOid() providing the
6512 : : * OID-to-name mapping.
6513 : : */
37 noah@leadboat.com 6514 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
6515 [ + - ]: 185 : if (fout->remoteVersion >= 90600)
6516 : 185 : appendPQExpBufferStr(query,
6517 : : "amtype, "
6518 : : "amhandler::pg_catalog.regproc AS amhandler ");
6519 : : else
37 noah@leadboat.com 6520 :UBC 0 : appendPQExpBufferStr(query,
6521 : : "'i'::pg_catalog.\"char\" AS amtype, "
6522 : : "'-'::pg_catalog.regproc AS amhandler ");
37 noah@leadboat.com 6523 :CBC 185 : appendPQExpBufferStr(query, "FROM pg_am");
6524 : :
3454 alvherre@alvh.no-ip. 6525 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6526 : :
6527 : 185 : ntups = PQntuples(res);
6528 : :
6529 : 185 : aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
6530 : :
6531 : 185 : i_tableoid = PQfnumber(res, "tableoid");
6532 : 185 : i_oid = PQfnumber(res, "oid");
6533 : 185 : i_amname = PQfnumber(res, "amname");
6534 : 185 : i_amhandler = PQfnumber(res, "amhandler");
6535 : 185 : i_amtype = PQfnumber(res, "amtype");
6536 : :
6537 [ + + ]: 1614 : for (i = 0; i < ntups; i++)
6538 : : {
6539 : 1429 : aminfo[i].dobj.objType = DO_ACCESS_METHOD;
6540 : 1429 : aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6541 : 1429 : aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6542 : 1429 : AssignDumpId(&aminfo[i].dobj);
6543 : 1429 : aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
6544 : 1429 : aminfo[i].dobj.namespace = NULL;
6545 : 1429 : aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
6546 : 1429 : aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
6547 : :
6548 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 6549 : 1429 : selectDumpableAccessMethod(&(aminfo[i]), fout);
6550 : : }
6551 : :
3454 alvherre@alvh.no-ip. 6552 : 185 : PQclear(res);
6553 : :
6554 : 185 : destroyPQExpBuffer(query);
6555 : 185 : }
6556 : :
6557 : :
6558 : : /*
6559 : : * getOpclasses:
6560 : : * get information about all opclasses in the system catalogs
6561 : : */
6562 : : void
431 nathan@postgresql.or 6563 : 185 : getOpclasses(Archive *fout)
6564 : : {
6565 : : PGresult *res;
6566 : : int ntups;
6567 : : int i;
8439 tgl@sss.pgh.pa.us 6568 : 185 : PQExpBuffer query = createPQExpBuffer();
6569 : : OpclassInfo *opcinfo;
6570 : : int i_tableoid;
6571 : : int i_oid;
6572 : : int i_opcmethod;
6573 : : int i_opcname;
6574 : : int i_opcnamespace;
6575 : : int i_opcowner;
6576 : :
6577 : : /*
6578 : : * find all opclasses, including builtin opclasses; we filter out
6579 : : * system-defined opclasses at dump-out time.
6580 : : */
6581 : :
37 noah@leadboat.com 6582 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
6583 : : "opcnamespace, "
6584 : : "opcowner "
6585 : : "FROM pg_opclass");
6586 : :
4960 rhaas@postgresql.org 6587 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6588 : :
8439 tgl@sss.pgh.pa.us 6589 : 185 : ntups = PQntuples(res);
6590 : :
5034 bruce@momjian.us 6591 : 185 : opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
6592 : :
7945 tgl@sss.pgh.pa.us 6593 : 185 : i_tableoid = PQfnumber(res, "tableoid");
8439 6594 : 185 : i_oid = PQfnumber(res, "oid");
37 noah@leadboat.com 6595 : 185 : i_opcmethod = PQfnumber(res, "opcmethod");
8439 tgl@sss.pgh.pa.us 6596 : 185 : i_opcname = PQfnumber(res, "opcname");
6597 : 185 : i_opcnamespace = PQfnumber(res, "opcnamespace");
1345 6598 : 185 : i_opcowner = PQfnumber(res, "opcowner");
6599 : :
8439 6600 [ + + ]: 33104 : for (i = 0; i < ntups; i++)
6601 : : {
7945 6602 : 32919 : opcinfo[i].dobj.objType = DO_OPCLASS;
6603 : 32919 : opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6604 : 32919 : opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6605 : 32919 : AssignDumpId(&opcinfo[i].dobj);
5034 bruce@momjian.us 6606 : 32919 : opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
4961 rhaas@postgresql.org 6607 : 65838 : opcinfo[i].dobj.namespace =
1838 peter@eisentraut.org 6608 : 32919 : findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
37 noah@leadboat.com 6609 : 32919 : opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
1345 tgl@sss.pgh.pa.us 6610 : 32919 : opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
6611 : :
6612 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 6613 : 32919 : selectDumpableObject(&(opcinfo[i].dobj), fout);
6614 : : }
6615 : :
8439 tgl@sss.pgh.pa.us 6616 : 185 : PQclear(res);
6617 : :
6618 : 185 : destroyPQExpBuffer(query);
6619 : 185 : }
6620 : :
6621 : : /*
6622 : : * getOpfamilies:
6623 : : * get information about all opfamilies in the system catalogs
6624 : : */
6625 : : void
431 nathan@postgresql.or 6626 : 185 : getOpfamilies(Archive *fout)
6627 : : {
6628 : : PGresult *res;
6629 : : int ntups;
6630 : : int i;
6631 : : PQExpBuffer query;
6632 : : OpfamilyInfo *opfinfo;
6633 : : int i_tableoid;
6634 : : int i_oid;
6635 : : int i_opfmethod;
6636 : : int i_opfname;
6637 : : int i_opfnamespace;
6638 : : int i_opfowner;
6639 : :
6801 tgl@sss.pgh.pa.us 6640 : 185 : query = createPQExpBuffer();
6641 : :
6642 : : /*
6643 : : * find all opfamilies, including builtin opfamilies; we filter out
6644 : : * system-defined opfamilies at dump-out time.
6645 : : */
6646 : :
37 noah@leadboat.com 6647 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
6648 : : "opfnamespace, "
6649 : : "opfowner "
6650 : : "FROM pg_opfamily");
6651 : :
4960 rhaas@postgresql.org 6652 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6653 : :
6801 tgl@sss.pgh.pa.us 6654 : 185 : ntups = PQntuples(res);
6655 : :
5034 bruce@momjian.us 6656 : 185 : opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
6657 : :
6801 tgl@sss.pgh.pa.us 6658 : 185 : i_tableoid = PQfnumber(res, "tableoid");
6659 : 185 : i_oid = PQfnumber(res, "oid");
6660 : 185 : i_opfname = PQfnumber(res, "opfname");
37 noah@leadboat.com 6661 : 185 : i_opfmethod = PQfnumber(res, "opfmethod");
6801 tgl@sss.pgh.pa.us 6662 : 185 : i_opfnamespace = PQfnumber(res, "opfnamespace");
1345 6663 : 185 : i_opfowner = PQfnumber(res, "opfowner");
6664 : :
6801 6665 [ + + ]: 27346 : for (i = 0; i < ntups; i++)
6666 : : {
6667 : 27161 : opfinfo[i].dobj.objType = DO_OPFAMILY;
6668 : 27161 : opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6669 : 27161 : opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6670 : 27161 : AssignDumpId(&opfinfo[i].dobj);
5034 bruce@momjian.us 6671 : 27161 : opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
4961 rhaas@postgresql.org 6672 : 54322 : opfinfo[i].dobj.namespace =
1838 peter@eisentraut.org 6673 : 27161 : findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
37 noah@leadboat.com 6674 : 27161 : opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
1345 tgl@sss.pgh.pa.us 6675 : 27161 : opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
6676 : :
6677 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 6678 : 27161 : selectDumpableObject(&(opfinfo[i].dobj), fout);
6679 : : }
6680 : :
6801 tgl@sss.pgh.pa.us 6681 : 185 : PQclear(res);
6682 : :
6683 : 185 : destroyPQExpBuffer(query);
6684 : 185 : }
6685 : :
6686 : : /*
6687 : : * getAggregates:
6688 : : * get information about all user-defined aggregates in the system catalogs
6689 : : */
6690 : : void
431 nathan@postgresql.or 6691 : 185 : getAggregates(Archive *fout)
6692 : : {
3524 tgl@sss.pgh.pa.us 6693 : 185 : DumpOptions *dopt = fout->dopt;
6694 : : PGresult *res;
6695 : : int ntups;
6696 : : int i;
9278 bruce@momjian.us 6697 : 185 : PQExpBuffer query = createPQExpBuffer();
6698 : : AggInfo *agginfo;
6699 : : int i_tableoid;
6700 : : int i_oid;
6701 : : int i_aggname;
6702 : : int i_aggnamespace;
6703 : : int i_pronargs;
6704 : : int i_proargtypes;
6705 : : int i_proowner;
6706 : : int i_aggacl;
6707 : : int i_acldefault;
6708 : :
6709 : : /*
6710 : : * Find all interesting aggregates. See comment in getFuncs() for the
6711 : : * rationale behind the filtering logic.
6712 : : */
3440 sfrost@snowman.net 6713 [ + - ]: 185 : if (fout->remoteVersion >= 90600)
6714 : : {
6715 : : const char *agg_check;
6716 : :
2745 peter_e@gmx.net 6717 : 370 : agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
6718 [ + - ]: 185 : : "p.proisagg");
6719 : :
3440 sfrost@snowman.net 6720 : 185 : appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
6721 : : "p.proname AS aggname, "
6722 : : "p.pronamespace AS aggnamespace, "
6723 : : "p.pronargs, p.proargtypes, "
6724 : : "p.proowner, "
6725 : : "p.proacl AS aggacl, "
6726 : : "acldefault('f', p.proowner) AS acldefault "
6727 : : "FROM pg_proc p "
6728 : : "LEFT JOIN pg_init_privs pip ON "
6729 : : "(p.oid = pip.objoid "
6730 : : "AND pip.classoid = 'pg_proc'::regclass "
6731 : : "AND pip.objsubid = 0) "
6732 : : "WHERE %s AND ("
6733 : : "p.pronamespace != "
6734 : : "(SELECT oid FROM pg_namespace "
6735 : : "WHERE nspname = 'pg_catalog') OR "
6736 : : "p.proacl IS DISTINCT FROM pip.initprivs",
6737 : : agg_check);
6738 [ + + ]: 185 : if (dopt->binary_upgrade)
6739 : 36 : appendPQExpBufferStr(query,
6740 : : " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6741 : : "classid = 'pg_proc'::regclass AND "
6742 : : "objid = p.oid AND "
6743 : : "refclassid = 'pg_extension'::regclass AND "
6744 : : "deptype = 'e')");
6745 : 185 : appendPQExpBufferChar(query, ')');
6746 : : }
6747 : : else
6748 : : {
1096 drowley@postgresql.o 6749 :UBC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
6750 : : "pronamespace AS aggnamespace, "
6751 : : "pronargs, proargtypes, "
6752 : : "proowner, "
6753 : : "proacl AS aggacl, "
6754 : : "acldefault('f', proowner) AS acldefault "
6755 : : "FROM pg_proc p "
6756 : : "WHERE proisagg AND ("
6757 : : "pronamespace != "
6758 : : "(SELECT oid FROM pg_namespace "
6759 : : "WHERE nspname = 'pg_catalog')");
1370 tgl@sss.pgh.pa.us 6760 [ # # ]: 0 : if (dopt->binary_upgrade)
6761 : 0 : appendPQExpBufferStr(query,
6762 : : " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6763 : : "classid = 'pg_proc'::regclass AND "
6764 : : "objid = p.oid AND "
6765 : : "refclassid = 'pg_extension'::regclass AND "
6766 : : "deptype = 'e')");
6767 : 0 : appendPQExpBufferChar(query, ')');
6768 : : }
6769 : :
4960 rhaas@postgresql.org 6770 :CBC 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6771 : :
10226 bruce@momjian.us 6772 : 185 : ntups = PQntuples(res);
6773 : :
5034 6774 : 185 : agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
6775 : :
7945 tgl@sss.pgh.pa.us 6776 : 185 : i_tableoid = PQfnumber(res, "tableoid");
8520 6777 : 185 : i_oid = PQfnumber(res, "oid");
6778 : 185 : i_aggname = PQfnumber(res, "aggname");
6779 : 185 : i_aggnamespace = PQfnumber(res, "aggnamespace");
6981 6780 : 185 : i_pronargs = PQfnumber(res, "pronargs");
6781 : 185 : i_proargtypes = PQfnumber(res, "proargtypes");
1345 6782 : 185 : i_proowner = PQfnumber(res, "proowner");
8511 peter_e@gmx.net 6783 : 185 : i_aggacl = PQfnumber(res, "aggacl");
1370 tgl@sss.pgh.pa.us 6784 : 185 : i_acldefault = PQfnumber(res, "acldefault");
6785 : :
10226 bruce@momjian.us 6786 [ + + ]: 590 : for (i = 0; i < ntups; i++)
6787 : : {
7945 tgl@sss.pgh.pa.us 6788 : 405 : agginfo[i].aggfn.dobj.objType = DO_AGG;
6789 : 405 : agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6790 : 405 : agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6791 : 405 : AssignDumpId(&agginfo[i].aggfn.dobj);
5034 bruce@momjian.us 6792 : 405 : agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
4961 rhaas@postgresql.org 6793 : 810 : agginfo[i].aggfn.dobj.namespace =
1838 peter@eisentraut.org 6794 : 405 : findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
1370 tgl@sss.pgh.pa.us 6795 : 405 : agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
6796 : 405 : agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6797 : 405 : agginfo[i].aggfn.dacl.privtype = 0;
6798 : 405 : agginfo[i].aggfn.dacl.initprivs = NULL;
1345 6799 : 405 : agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
2999 6800 : 405 : agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
6801 : 405 : agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
6981 6802 : 405 : agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
6803 [ + + ]: 405 : if (agginfo[i].aggfn.nargs == 0)
6804 : 56 : agginfo[i].aggfn.argtypes = NULL;
6805 : : else
6806 : : {
5034 bruce@momjian.us 6807 : 349 : agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
3251 tgl@sss.pgh.pa.us 6808 : 349 : parseOidArray(PQgetvalue(res, i, i_proargtypes),
6809 : 349 : agginfo[i].aggfn.argtypes,
6810 : 349 : agginfo[i].aggfn.nargs);
6811 : : }
825 6812 : 405 : agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
6813 : :
6814 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 6815 : 405 : selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
6816 : :
6817 : : /* Mark whether aggregate has an ACL */
1370 tgl@sss.pgh.pa.us 6818 [ + + ]: 405 : if (!PQgetisnull(res, i, i_aggacl))
6819 : 25 : agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
6820 : : }
6821 : :
8520 6822 : 185 : PQclear(res);
6823 : :
6824 : 185 : destroyPQExpBuffer(query);
6825 : 185 : }
6826 : :
6827 : : /*
6828 : : * getFuncs:
6829 : : * get information about all user-defined functions in the system catalogs
6830 : : */
6831 : : void
431 nathan@postgresql.or 6832 : 185 : getFuncs(Archive *fout)
6833 : : {
3524 tgl@sss.pgh.pa.us 6834 : 185 : DumpOptions *dopt = fout->dopt;
6835 : : PGresult *res;
6836 : : int ntups;
6837 : : int i;
8520 6838 : 185 : PQExpBuffer query = createPQExpBuffer();
6839 : : FuncInfo *finfo;
6840 : : int i_tableoid;
6841 : : int i_oid;
6842 : : int i_proname;
6843 : : int i_pronamespace;
6844 : : int i_proowner;
6845 : : int i_prolang;
6846 : : int i_pronargs;
6847 : : int i_proargtypes;
6848 : : int i_prorettype;
6849 : : int i_proacl;
6850 : : int i_acldefault;
6851 : :
6852 : : /*
6853 : : * Find all interesting functions. This is a bit complicated:
6854 : : *
6855 : : * 1. Always exclude aggregates; those are handled elsewhere.
6856 : : *
6857 : : * 2. Always exclude functions that are internally dependent on something
6858 : : * else, since presumably those will be created as a result of creating
6859 : : * the something else. This currently acts only to suppress constructor
6860 : : * functions for range types. Note this is OK only because the
6861 : : * constructors don't have any dependencies the range type doesn't have;
6862 : : * otherwise we might not get creation ordering correct.
6863 : : *
6864 : : * 3. Otherwise, we normally exclude functions in pg_catalog. However, if
6865 : : * they're members of extensions and we are in binary-upgrade mode then
6866 : : * include them, since we want to dump extension members individually in
6867 : : * that mode. Also, if they are used by casts or transforms then we need
6868 : : * to gather the information about them, though they won't be dumped if
6869 : : * they are built-in. Also, in 9.6 and up, include functions in
6870 : : * pg_catalog if they have an ACL different from what's shown in
6871 : : * pg_init_privs (so we have to join to pg_init_privs; annoying).
6872 : : */
3440 sfrost@snowman.net 6873 [ + - ]: 185 : if (fout->remoteVersion >= 90600)
6874 : : {
6875 : : const char *not_agg_check;
6876 : :
2745 peter_e@gmx.net 6877 : 370 : not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
6878 [ + - ]: 185 : : "NOT p.proisagg");
6879 : :
3440 sfrost@snowman.net 6880 : 185 : appendPQExpBuffer(query,
6881 : : "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
6882 : : "p.pronargs, p.proargtypes, p.prorettype, "
6883 : : "p.proacl, "
6884 : : "acldefault('f', p.proowner) AS acldefault, "
6885 : : "p.pronamespace, "
6886 : : "p.proowner "
6887 : : "FROM pg_proc p "
6888 : : "LEFT JOIN pg_init_privs pip ON "
6889 : : "(p.oid = pip.objoid "
6890 : : "AND pip.classoid = 'pg_proc'::regclass "
6891 : : "AND pip.objsubid = 0) "
6892 : : "WHERE %s"
6893 : : "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6894 : : "WHERE classid = 'pg_proc'::regclass AND "
6895 : : "objid = p.oid AND deptype = 'i')"
6896 : : "\n AND ("
6897 : : "\n pronamespace != "
6898 : : "(SELECT oid FROM pg_namespace "
6899 : : "WHERE nspname = 'pg_catalog')"
6900 : : "\n OR EXISTS (SELECT 1 FROM pg_cast"
6901 : : "\n WHERE pg_cast.oid > %u "
6902 : : "\n AND p.oid = pg_cast.castfunc)"
6903 : : "\n OR EXISTS (SELECT 1 FROM pg_transform"
6904 : : "\n WHERE pg_transform.oid > %u AND "
6905 : : "\n (p.oid = pg_transform.trffromsql"
6906 : : "\n OR p.oid = pg_transform.trftosql))",
6907 : : not_agg_check,
6908 : : g_last_builtin_oid,
6909 : : g_last_builtin_oid);
6910 [ + + ]: 185 : if (dopt->binary_upgrade)
6911 : 36 : appendPQExpBufferStr(query,
6912 : : "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6913 : : "classid = 'pg_proc'::regclass AND "
6914 : : "objid = p.oid AND "
6915 : : "refclassid = 'pg_extension'::regclass AND "
6916 : : "deptype = 'e')");
3270 tgl@sss.pgh.pa.us 6917 : 185 : appendPQExpBufferStr(query,
6918 : : "\n OR p.proacl IS DISTINCT FROM pip.initprivs");
3440 sfrost@snowman.net 6919 : 185 : appendPQExpBufferChar(query, ')');
6920 : : }
6921 : : else
6922 : : {
8520 tgl@sss.pgh.pa.us 6923 :UBC 0 : appendPQExpBuffer(query,
6924 : : "SELECT tableoid, oid, proname, prolang, "
6925 : : "pronargs, proargtypes, prorettype, proacl, "
6926 : : "acldefault('f', proowner) AS acldefault, "
6927 : : "pronamespace, "
6928 : : "proowner "
6929 : : "FROM pg_proc p "
6930 : : "WHERE NOT proisagg"
6931 : : "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6932 : : "WHERE classid = 'pg_proc'::regclass AND "
6933 : : "objid = p.oid AND deptype = 'i')"
6934 : : "\n AND ("
6935 : : "\n pronamespace != "
6936 : : "(SELECT oid FROM pg_namespace "
6937 : : "WHERE nspname = 'pg_catalog')"
6938 : : "\n OR EXISTS (SELECT 1 FROM pg_cast"
6939 : : "\n WHERE pg_cast.oid > '%u'::oid"
6940 : : "\n AND p.oid = pg_cast.castfunc)",
6941 : : g_last_builtin_oid);
6942 : :
3181 sfrost@snowman.net 6943 [ # # ]: 0 : if (fout->remoteVersion >= 90500)
6944 : 0 : appendPQExpBuffer(query,
6945 : : "\n OR EXISTS (SELECT 1 FROM pg_transform"
6946 : : "\n WHERE pg_transform.oid > '%u'::oid"
6947 : : "\n AND (p.oid = pg_transform.trffromsql"
6948 : : "\n OR p.oid = pg_transform.trftosql))",
6949 : : g_last_builtin_oid);
6950 : :
1362 tgl@sss.pgh.pa.us 6951 [ # # ]: 0 : if (dopt->binary_upgrade)
4310 heikki.linnakangas@i 6952 : 0 : appendPQExpBufferStr(query,
6953 : : "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6954 : : "classid = 'pg_proc'::regclass AND "
6955 : : "objid = p.oid AND "
6956 : : "refclassid = 'pg_extension'::regclass AND "
6957 : : "deptype = 'e')");
6958 : 0 : appendPQExpBufferChar(query, ')');
6959 : : }
6960 : :
4960 rhaas@postgresql.org 6961 :CBC 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6962 : :
8520 tgl@sss.pgh.pa.us 6963 : 185 : ntups = PQntuples(res);
6964 : :
4722 6965 : 185 : finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
6966 : :
7945 6967 : 185 : i_tableoid = PQfnumber(res, "tableoid");
8520 6968 : 185 : i_oid = PQfnumber(res, "oid");
6969 : 185 : i_proname = PQfnumber(res, "proname");
6970 : 185 : i_pronamespace = PQfnumber(res, "pronamespace");
1345 6971 : 185 : i_proowner = PQfnumber(res, "proowner");
8520 6972 : 185 : i_prolang = PQfnumber(res, "prolang");
6973 : 185 : i_pronargs = PQfnumber(res, "pronargs");
6974 : 185 : i_proargtypes = PQfnumber(res, "proargtypes");
6975 : 185 : i_prorettype = PQfnumber(res, "prorettype");
8511 peter_e@gmx.net 6976 : 185 : i_proacl = PQfnumber(res, "proacl");
1370 tgl@sss.pgh.pa.us 6977 : 185 : i_acldefault = PQfnumber(res, "acldefault");
6978 : :
8520 6979 [ + + ]: 4995 : for (i = 0; i < ntups; i++)
6980 : : {
7945 6981 : 4810 : finfo[i].dobj.objType = DO_FUNC;
6982 : 4810 : finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6983 : 4810 : finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6984 : 4810 : AssignDumpId(&finfo[i].dobj);
5034 bruce@momjian.us 6985 : 4810 : finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
7266 6986 : 9620 : finfo[i].dobj.namespace =
1838 peter@eisentraut.org 6987 : 4810 : findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
1370 tgl@sss.pgh.pa.us 6988 : 4810 : finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
6989 : 4810 : finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6990 : 4810 : finfo[i].dacl.privtype = 0;
6991 : 4810 : finfo[i].dacl.initprivs = NULL;
1345 6992 : 4810 : finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
8520 6993 : 4810 : finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
7945 6994 : 4810 : finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
8520 6995 : 4810 : finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
6996 [ + + ]: 4810 : if (finfo[i].nargs == 0)
6997 : 1094 : finfo[i].argtypes = NULL;
6998 : : else
6999 : : {
5034 bruce@momjian.us 7000 : 3716 : finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
7945 tgl@sss.pgh.pa.us 7001 : 3716 : parseOidArray(PQgetvalue(res, i, i_proargtypes),
7002 : 3716 : finfo[i].argtypes, finfo[i].nargs);
7003 : : }
825 7004 : 4810 : finfo[i].postponed_def = false; /* might get set during sort */
7005 : :
7006 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 7007 : 4810 : selectDumpableObject(&(finfo[i].dobj), fout);
7008 : :
7009 : : /* Mark whether function has an ACL */
1370 tgl@sss.pgh.pa.us 7010 [ + + ]: 4810 : if (!PQgetisnull(res, i, i_proacl))
7011 : 152 : finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
7012 : : }
7013 : :
8520 7014 : 185 : PQclear(res);
7015 : :
7016 : 185 : destroyPQExpBuffer(query);
7017 : 185 : }
7018 : :
7019 : : /*
7020 : : * getRelationStatistics
7021 : : * register the statistics object as a dependent of the relation.
7022 : : *
7023 : : * reltuples is passed as a string to avoid complexities in converting from/to
7024 : : * floating point.
7025 : : */
7026 : : static RelStatsInfo *
193 jdavis@postgresql.or 7027 : 10089 : getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
7028 : : char *reltuples, int32 relallvisible,
7029 : : int32 relallfrozen, char relkind,
7030 : : char **indAttNames, int nindAttNames)
7031 : : {
198 7032 [ + + ]: 10089 : if (!fout->dopt->dumpStatistics)
7033 : 6036 : return NULL;
7034 : :
7035 [ + + + + ]: 4053 : if ((relkind == RELKIND_RELATION) ||
7036 [ + + ]: 1707 : (relkind == RELKIND_PARTITIONED_TABLE) ||
7037 [ + + ]: 1047 : (relkind == RELKIND_INDEX) ||
7038 [ + + ]: 687 : (relkind == RELKIND_PARTITIONED_INDEX) ||
80 fujii@postgresql.org 7039 [ + + ]: 299 : (relkind == RELKIND_MATVIEW ||
7040 : : relkind == RELKIND_FOREIGN_TABLE))
7041 : : {
198 jdavis@postgresql.or 7042 : 3792 : RelStatsInfo *info = pg_malloc0(sizeof(RelStatsInfo));
7043 : 3792 : DumpableObject *dobj = &info->dobj;
7044 : :
7045 : 3792 : dobj->objType = DO_REL_STATS;
7046 : 3792 : dobj->catId.tableoid = 0;
7047 : 3792 : dobj->catId.oid = 0;
7048 : 3792 : AssignDumpId(dobj);
7049 : 3792 : dobj->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
7050 : 3792 : dobj->dependencies[0] = rel->dumpId;
7051 : 3792 : dobj->nDeps = 1;
7052 : 3792 : dobj->allocDeps = 1;
7053 : 3792 : dobj->components |= DUMP_COMPONENT_STATISTICS;
7054 : 3792 : dobj->name = pg_strdup(rel->name);
7055 : 3792 : dobj->namespace = rel->namespace;
193 7056 : 3792 : info->relpages = relpages;
182 7057 : 3792 : info->reltuples = pstrdup(reltuples);
193 7058 : 3792 : info->relallvisible = relallvisible;
160 7059 : 3792 : info->relallfrozen = relallfrozen;
198 7060 : 3792 : info->relkind = relkind;
192 tgl@sss.pgh.pa.us 7061 : 3792 : info->indAttNames = indAttNames;
7062 : 3792 : info->nindAttNames = nindAttNames;
7063 : :
7064 : : /*
7065 : : * Ordinarily, stats go in SECTION_DATA for tables and
7066 : : * SECTION_POST_DATA for indexes.
7067 : : *
7068 : : * However, the section may be updated later for materialized view
7069 : : * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
7070 : : * the stats, so the stats must be restored after the data. Also, the
7071 : : * materialized view definition may be postponed to SECTION_POST_DATA
7072 : : * (see repairMatViewBoundaryMultiLoop()).
7073 : : */
162 jdavis@postgresql.or 7074 [ + + - ]: 3792 : switch (info->relkind)
7075 : : {
7076 : 2772 : case RELKIND_RELATION:
7077 : : case RELKIND_PARTITIONED_TABLE:
7078 : : case RELKIND_MATVIEW:
7079 : : case RELKIND_FOREIGN_TABLE:
7080 : 2772 : info->section = SECTION_DATA;
7081 : 2772 : break;
7082 : 1020 : case RELKIND_INDEX:
7083 : : case RELKIND_PARTITIONED_INDEX:
7084 : 1020 : info->section = SECTION_POST_DATA;
7085 : 1020 : break;
162 jdavis@postgresql.or 7086 :UBC 0 : default:
82 peter@eisentraut.org 7087 : 0 : pg_fatal("cannot dump statistics for relation kind \"%c\"",
7088 : : info->relkind);
7089 : : }
7090 : :
198 jdavis@postgresql.or 7091 :CBC 3792 : return info;
7092 : : }
7093 : 261 : return NULL;
7094 : : }
7095 : :
7096 : : /*
7097 : : * getTables
7098 : : * read all the tables (no indexes) in the system catalogs,
7099 : : * and return them as an array of TableInfo structures
7100 : : *
7101 : : * *numTables is set to the number of tables read in
7102 : : */
7103 : : TableInfo *
3524 tgl@sss.pgh.pa.us 7104 : 186 : getTables(Archive *fout, int *numTables)
7105 : : {
7106 : 186 : DumpOptions *dopt = fout->dopt;
7107 : : PGresult *res;
7108 : : int ntups;
7109 : : int i;
8520 7110 : 186 : PQExpBuffer query = createPQExpBuffer();
7111 : : TableInfo *tblinfo;
7112 : : int i_reltableoid;
7113 : : int i_reloid;
7114 : : int i_relname;
7115 : : int i_relnamespace;
7116 : : int i_relkind;
7117 : : int i_reltype;
7118 : : int i_relowner;
7119 : : int i_relchecks;
7120 : : int i_relhasindex;
7121 : : int i_relhasrules;
7122 : : int i_relpages;
7123 : : int i_reltuples;
7124 : : int i_relallvisible;
7125 : : int i_relallfrozen;
7126 : : int i_toastpages;
7127 : : int i_owning_tab;
7128 : : int i_owning_col;
7129 : : int i_reltablespace;
7130 : : int i_relhasoids;
7131 : : int i_relhastriggers;
7132 : : int i_relpersistence;
7133 : : int i_relispopulated;
7134 : : int i_relreplident;
7135 : : int i_relrowsec;
7136 : : int i_relforcerowsec;
7137 : : int i_relfrozenxid;
7138 : : int i_toastfrozenxid;
7139 : : int i_toastoid;
7140 : : int i_relminmxid;
7141 : : int i_toastminmxid;
7142 : : int i_reloptions;
7143 : : int i_checkoption;
7144 : : int i_toastreloptions;
7145 : : int i_reloftype;
7146 : : int i_foreignserver;
7147 : : int i_amname;
7148 : : int i_is_identity_sequence;
7149 : : int i_relacl;
7150 : : int i_acldefault;
7151 : : int i_ispartition;
7152 : :
7153 : : /*
7154 : : * Find all the tables and table-like objects.
7155 : : *
7156 : : * We must fetch all tables in this phase because otherwise we cannot
7157 : : * correctly identify inherited columns, owned sequences, etc.
7158 : : *
7159 : : * We include system catalogs, so that we can work if a user table is
7160 : : * defined to inherit from a system catalog (pretty weird, but...)
7161 : : *
7162 : : * Note: in this phase we should collect only a minimal amount of
7163 : : * information about each table, basically just enough to decide if it is
7164 : : * interesting. In particular, since we do not yet have lock on any user
7165 : : * table, we MUST NOT invoke any server-side data collection functions
7166 : : * (for instance, pg_get_partkeydef()). Those are likely to fail or give
7167 : : * wrong answers if any concurrent DDL is happening.
7168 : : */
7169 : :
1096 drowley@postgresql.o 7170 : 186 : appendPQExpBufferStr(query,
7171 : : "SELECT c.tableoid, c.oid, c.relname, "
7172 : : "c.relnamespace, c.relkind, c.reltype, "
7173 : : "c.relowner, "
7174 : : "c.relchecks, "
7175 : : "c.relhasindex, c.relhasrules, c.relpages, "
7176 : : "c.reltuples, c.relallvisible, ");
7177 : :
160 jdavis@postgresql.or 7178 [ + - ]: 186 : if (fout->remoteVersion >= 180000)
7179 : 186 : appendPQExpBufferStr(query, "c.relallfrozen, ");
7180 : : else
160 jdavis@postgresql.or 7181 :UBC 0 : appendPQExpBufferStr(query, "0 AS relallfrozen, ");
7182 : :
160 jdavis@postgresql.or 7183 :CBC 186 : appendPQExpBufferStr(query,
7184 : : "c.relhastriggers, c.relpersistence, "
7185 : : "c.reloftype, "
7186 : : "c.relacl, "
7187 : : "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
7188 : : " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
7189 : : "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
7190 : : "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
7191 : : "ELSE 0 END AS foreignserver, "
7192 : : "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
7193 : : "tc.oid AS toid, "
7194 : : "tc.relpages AS toastpages, "
7195 : : "tc.reloptions AS toast_reloptions, "
7196 : : "d.refobjid AS owning_tab, "
7197 : : "d.refobjsubid AS owning_col, "
7198 : : "tsp.spcname AS reltablespace, ");
7199 : :
1418 tgl@sss.pgh.pa.us 7200 [ + - ]: 186 : if (fout->remoteVersion >= 120000)
7201 : 186 : appendPQExpBufferStr(query,
7202 : : "false AS relhasoids, ");
7203 : : else
1418 tgl@sss.pgh.pa.us 7204 :UBC 0 : appendPQExpBufferStr(query,
7205 : : "c.relhasoids, ");
7206 : :
1418 tgl@sss.pgh.pa.us 7207 [ + - ]:CBC 186 : if (fout->remoteVersion >= 90300)
7208 : 186 : appendPQExpBufferStr(query,
7209 : : "c.relispopulated, ");
7210 : : else
1418 tgl@sss.pgh.pa.us 7211 :UBC 0 : appendPQExpBufferStr(query,
7212 : : "'t' as relispopulated, ");
7213 : :
1418 tgl@sss.pgh.pa.us 7214 [ + - ]:CBC 186 : if (fout->remoteVersion >= 90400)
7215 : 186 : appendPQExpBufferStr(query,
7216 : : "c.relreplident, ");
7217 : : else
1418 tgl@sss.pgh.pa.us 7218 :UBC 0 : appendPQExpBufferStr(query,
7219 : : "'d' AS relreplident, ");
7220 : :
1418 tgl@sss.pgh.pa.us 7221 [ + - ]:CBC 186 : if (fout->remoteVersion >= 90500)
7222 : 186 : appendPQExpBufferStr(query,
7223 : : "c.relrowsecurity, c.relforcerowsecurity, ");
7224 : : else
1418 tgl@sss.pgh.pa.us 7225 :UBC 0 : appendPQExpBufferStr(query,
7226 : : "false AS relrowsecurity, "
7227 : : "false AS relforcerowsecurity, ");
7228 : :
1418 tgl@sss.pgh.pa.us 7229 [ + - ]:CBC 186 : if (fout->remoteVersion >= 90300)
7230 : 186 : appendPQExpBufferStr(query,
7231 : : "c.relminmxid, tc.relminmxid AS tminmxid, ");
7232 : : else
1418 tgl@sss.pgh.pa.us 7233 :UBC 0 : appendPQExpBufferStr(query,
7234 : : "0 AS relminmxid, 0 AS tminmxid, ");
7235 : :
1418 tgl@sss.pgh.pa.us 7236 [ + - ]:CBC 186 : if (fout->remoteVersion >= 90300)
7237 : 186 : appendPQExpBufferStr(query,
7238 : : "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
7239 : : "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
7240 : : "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
7241 : : else
1418 tgl@sss.pgh.pa.us 7242 :UBC 0 : appendPQExpBufferStr(query,
7243 : : "c.reloptions, NULL AS checkoption, ");
7244 : :
3440 sfrost@snowman.net 7245 [ + - ]:CBC 186 : if (fout->remoteVersion >= 90600)
1418 tgl@sss.pgh.pa.us 7246 : 186 : appendPQExpBufferStr(query,
7247 : : "am.amname, ");
7248 : : else
1418 tgl@sss.pgh.pa.us 7249 :UBC 0 : appendPQExpBufferStr(query,
7250 : : "NULL AS amname, ");
7251 : :
1418 tgl@sss.pgh.pa.us 7252 [ + - ]:CBC 186 : if (fout->remoteVersion >= 90600)
7253 : 186 : appendPQExpBufferStr(query,
7254 : : "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
7255 : : else
1418 tgl@sss.pgh.pa.us 7256 :UBC 0 : appendPQExpBufferStr(query,
7257 : : "false AS is_identity_sequence, ");
7258 : :
1418 tgl@sss.pgh.pa.us 7259 [ + - ]:CBC 186 : if (fout->remoteVersion >= 100000)
7260 : 186 : appendPQExpBufferStr(query,
7261 : : "c.relispartition AS ispartition ");
7262 : : else
1418 tgl@sss.pgh.pa.us 7263 :UBC 0 : appendPQExpBufferStr(query,
7264 : : "false AS ispartition ");
7265 : :
7266 : : /*
7267 : : * Left join to pg_depend to pick up dependency info linking sequences to
7268 : : * their owning column, if any (note this dependency is AUTO except for
7269 : : * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
7270 : : * collect the spcname.
7271 : : */
1418 tgl@sss.pgh.pa.us 7272 :CBC 186 : appendPQExpBufferStr(query,
7273 : : "\nFROM pg_class c\n"
7274 : : "LEFT JOIN pg_depend d ON "
7275 : : "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
7276 : : "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
7277 : : "d.objsubid = 0 AND "
7278 : : "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
7279 : : "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
7280 : :
7281 : : /*
7282 : : * In 9.6 and up, left join to pg_am to pick up the amname.
7283 : : */
7284 [ + - ]: 186 : if (fout->remoteVersion >= 90600)
7285 : 186 : appendPQExpBufferStr(query,
7286 : : "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
7287 : :
7288 : : /*
7289 : : * We purposefully ignore toast OIDs for partitioned tables; the reason is
7290 : : * that versions 10 and 11 have them, but later versions do not, so
7291 : : * emitting them causes the upgrade to fail.
7292 : : */
1370 7293 : 186 : appendPQExpBufferStr(query,
7294 : : "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
7295 : : " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
7296 : : " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
7297 : :
7298 : : /*
7299 : : * Restrict to interesting relkinds (in particular, not indexes). Not all
7300 : : * relkinds are possible in older servers, but it's not worth the trouble
7301 : : * to emit a version-dependent list.
7302 : : *
7303 : : * Composite-type table entries won't be dumped as such, but we have to
7304 : : * make a DumpableObject for them so that we can track dependencies of the
7305 : : * composite type (pg_depend entries for columns of the composite type
7306 : : * link to the pg_class entry not the pg_type entry).
7307 : : */
1418 7308 : 186 : appendPQExpBufferStr(query,
7309 : : "WHERE c.relkind IN ("
7310 : : CppAsString2(RELKIND_RELATION) ", "
7311 : : CppAsString2(RELKIND_SEQUENCE) ", "
7312 : : CppAsString2(RELKIND_VIEW) ", "
7313 : : CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
7314 : : CppAsString2(RELKIND_MATVIEW) ", "
7315 : : CppAsString2(RELKIND_FOREIGN_TABLE) ", "
7316 : : CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
7317 : : "ORDER BY c.oid");
7318 : :
4960 rhaas@postgresql.org 7319 : 186 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7320 : :
8520 tgl@sss.pgh.pa.us 7321 : 186 : ntups = PQntuples(res);
7322 : :
7323 : 186 : *numTables = ntups;
7324 : :
7325 : : /*
7326 : : * Extract data from result and lock dumpable tables. We do the locking
7327 : : * before anything else, to minimize the window wherein a table could
7328 : : * disappear under us.
7329 : : *
7330 : : * Note that we have to save info about all tables here, even when dumping
7331 : : * only one, because we don't yet know which tables might be inheritance
7332 : : * ancestors of the target table.
7333 : : */
4722 7334 : 186 : tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
7335 : :
7945 7336 : 186 : i_reltableoid = PQfnumber(res, "tableoid");
8520 7337 : 186 : i_reloid = PQfnumber(res, "oid");
7338 : 186 : i_relname = PQfnumber(res, "relname");
7339 : 186 : i_relnamespace = PQfnumber(res, "relnamespace");
7340 : 186 : i_relkind = PQfnumber(res, "relkind");
1370 7341 : 186 : i_reltype = PQfnumber(res, "reltype");
1345 7342 : 186 : i_relowner = PQfnumber(res, "relowner");
8520 7343 : 186 : i_relchecks = PQfnumber(res, "relchecks");
7344 : 186 : i_relhasindex = PQfnumber(res, "relhasindex");
7345 : 186 : i_relhasrules = PQfnumber(res, "relhasrules");
1418 7346 : 186 : i_relpages = PQfnumber(res, "relpages");
193 jdavis@postgresql.or 7347 : 186 : i_reltuples = PQfnumber(res, "reltuples");
7348 : 186 : i_relallvisible = PQfnumber(res, "relallvisible");
160 7349 : 186 : i_relallfrozen = PQfnumber(res, "relallfrozen");
1370 tgl@sss.pgh.pa.us 7350 : 186 : i_toastpages = PQfnumber(res, "toastpages");
1418 7351 : 186 : i_owning_tab = PQfnumber(res, "owning_tab");
7352 : 186 : i_owning_col = PQfnumber(res, "owning_col");
7353 : 186 : i_reltablespace = PQfnumber(res, "reltablespace");
7354 : 186 : i_relhasoids = PQfnumber(res, "relhasoids");
7355 : 186 : i_relhastriggers = PQfnumber(res, "relhastriggers");
7356 : 186 : i_relpersistence = PQfnumber(res, "relpersistence");
7357 : 186 : i_relispopulated = PQfnumber(res, "relispopulated");
7358 : 186 : i_relreplident = PQfnumber(res, "relreplident");
4000 sfrost@snowman.net 7359 : 186 : i_relrowsec = PQfnumber(res, "relrowsecurity");
3625 7360 : 186 : i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6044 bruce@momjian.us 7361 : 186 : i_relfrozenxid = PQfnumber(res, "relfrozenxid");
5265 7362 : 186 : i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
1418 tgl@sss.pgh.pa.us 7363 : 186 : i_toastoid = PQfnumber(res, "toid");
7364 : 186 : i_relminmxid = PQfnumber(res, "relminmxid");
4084 bruce@momjian.us 7365 : 186 : i_toastminmxid = PQfnumber(res, "tminmxid");
7006 7366 : 186 : i_reloptions = PQfnumber(res, "reloptions");
4433 sfrost@snowman.net 7367 : 186 : i_checkoption = PQfnumber(res, "checkoption");
6060 alvherre@alvh.no-ip. 7368 : 186 : i_toastreloptions = PQfnumber(res, "toast_reloptions");
5700 peter_e@gmx.net 7369 : 186 : i_reloftype = PQfnumber(res, "reloftype");
1418 tgl@sss.pgh.pa.us 7370 : 186 : i_foreignserver = PQfnumber(res, "foreignserver");
7371 : 186 : i_amname = PQfnumber(res, "amname");
3075 peter_e@gmx.net 7372 : 186 : i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
1418 tgl@sss.pgh.pa.us 7373 : 186 : i_relacl = PQfnumber(res, "relacl");
1370 7374 : 186 : i_acldefault = PQfnumber(res, "acldefault");
3047 sfrost@snowman.net 7375 : 186 : i_ispartition = PQfnumber(res, "ispartition");
7376 : :
3251 tgl@sss.pgh.pa.us 7377 [ + + ]: 186 : if (dopt->lockWaitTimeout)
7378 : : {
7379 : : /*
7380 : : * Arrange to fail instead of waiting forever for a table lock.
7381 : : *
7382 : : * NB: this coding assumes that the only queries issued within the
7383 : : * following loop are LOCK TABLEs; else the timeout may be undesirably
7384 : : * applied to other things too.
7385 : : */
6257 7386 : 2 : resetPQExpBuffer(query);
4310 heikki.linnakangas@i 7387 : 2 : appendPQExpBufferStr(query, "SET statement_timeout = ");
3980 alvherre@alvh.no-ip. 7388 : 2 : appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
4960 rhaas@postgresql.org 7389 : 2 : ExecuteSqlStatement(fout, query->data);
7390 : : }
7391 : :
977 tgl@sss.pgh.pa.us 7392 : 186 : resetPQExpBuffer(query);
7393 : :
8520 7394 [ + + ]: 49501 : for (i = 0; i < ntups; i++)
7395 : : {
193 jdavis@postgresql.or 7396 : 49315 : int32 relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
160 7397 : 49315 : int32 relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
7398 : :
7945 tgl@sss.pgh.pa.us 7399 : 49315 : tblinfo[i].dobj.objType = DO_TABLE;
7400 : 49315 : tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
7401 : 49315 : tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
7402 : 49315 : AssignDumpId(&tblinfo[i].dobj);
5034 bruce@momjian.us 7403 : 49315 : tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4961 rhaas@postgresql.org 7404 : 98630 : tblinfo[i].dobj.namespace =
1838 peter@eisentraut.org 7405 : 49315 : findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
1370 tgl@sss.pgh.pa.us 7406 : 49315 : tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
7407 : 49315 : tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
7408 : 49315 : tblinfo[i].dacl.privtype = 0;
7409 : 49315 : tblinfo[i].dacl.initprivs = NULL;
8520 7410 : 49315 : tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
1370 7411 : 49315 : tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
1345 7412 : 49315 : tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
1418 7413 : 49315 : tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
8520 7414 : 49315 : tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
7415 : 49315 : tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4549 andrew@dunslane.net 7416 : 49315 : tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
1370 tgl@sss.pgh.pa.us 7417 [ + + ]: 49315 : if (PQgetisnull(res, i, i_toastpages))
7418 : 39514 : tblinfo[i].toastpages = 0;
7419 : : else
7420 : 9801 : tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
8419 7421 [ + + ]: 49315 : if (PQgetisnull(res, i, i_owning_tab))
7422 : : {
7945 7423 : 48882 : tblinfo[i].owning_tab = InvalidOid;
8419 7424 : 48882 : tblinfo[i].owning_col = 0;
7425 : : }
7426 : : else
7427 : : {
7945 7428 : 433 : tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
8419 7429 : 433 : tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
7430 : : }
5034 bruce@momjian.us 7431 : 49315 : tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
1418 tgl@sss.pgh.pa.us 7432 : 49315 : tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
7433 : 49315 : tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
7434 : 49315 : tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
7435 : 49315 : tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
7436 : 49315 : tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
7437 : 49315 : tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
7438 : 49315 : tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
7439 : 49315 : tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
7440 : 49315 : tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
7441 : 49315 : tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
7442 : 49315 : tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
7443 : 49315 : tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
5034 bruce@momjian.us 7444 : 49315 : tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
1418 tgl@sss.pgh.pa.us 7445 [ + + ]: 49315 : if (PQgetisnull(res, i, i_checkoption))
4433 sfrost@snowman.net 7446 : 49263 : tblinfo[i].checkoption = NULL;
7447 : : else
7448 : 52 : tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
5034 bruce@momjian.us 7449 : 49315 : tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
1370 tgl@sss.pgh.pa.us 7450 : 49315 : tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
1418 7451 : 49315 : tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
2376 andres@anarazel.de 7452 [ + + ]: 49315 : if (PQgetisnull(res, i, i_amname))
7453 : 29238 : tblinfo[i].amname = NULL;
7454 : : else
7455 : 20077 : tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
1418 tgl@sss.pgh.pa.us 7456 : 49315 : tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
7457 : 49315 : tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
7458 : :
7459 : : /* other fields were zeroed above */
7460 : :
7461 : : /*
7462 : : * Decide whether we want to dump this table.
7463 : : */
7543 7464 [ + + ]: 49315 : if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
3440 sfrost@snowman.net 7465 : 189 : tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
7466 : : else
7467 : 49126 : selectDumpableTable(&tblinfo[i], fout);
7468 : :
7469 : : /*
7470 : : * Now, consider the table "interesting" if we need to dump its
7471 : : * definition, data or its statistics. Later on, we'll skip a lot of
7472 : : * data collection for uninteresting tables.
7473 : : *
7474 : : * Note: the "interesting" flag will also be set by flagInhTables for
7475 : : * parents of interesting tables, so that we collect necessary
7476 : : * inheritance info even when the parents are not themselves being
7477 : : * dumped. This is the main reason why we need an "interesting" flag
7478 : : * that's separate from the components-to-dump bitmask.
7479 : : */
1370 tgl@sss.pgh.pa.us 7480 : 49315 : tblinfo[i].interesting = (tblinfo[i].dobj.dump &
7481 : : (DUMP_COMPONENT_DEFINITION |
7482 : : DUMP_COMPONENT_DATA |
198 jdavis@postgresql.or 7483 : 49315 : DUMP_COMPONENT_STATISTICS)) != 0;
7484 : :
1418 tgl@sss.pgh.pa.us 7485 : 49315 : tblinfo[i].dummy_view = false; /* might get set during sort */
7486 : 49315 : tblinfo[i].postponed_def = false; /* might get set during sort */
7487 : :
7488 : : /* Tables have data */
1370 7489 : 49315 : tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
7490 : :
7491 : : /* Mark whether table has an ACL */
7492 [ + + ]: 49315 : if (!PQgetisnull(res, i, i_relacl))
7493 : 39106 : tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
7494 : 49315 : tblinfo[i].hascolumnACLs = false; /* may get set later */
7495 : :
7496 : : /* Add statistics */
198 jdavis@postgresql.or 7497 [ + + ]: 49315 : if (tblinfo[i].interesting)
7498 : : {
7499 : : RelStatsInfo *stats;
7500 : :
162 7501 : 14784 : stats = getRelationStatistics(fout, &tblinfo[i].dobj,
7502 : 7392 : tblinfo[i].relpages,
7503 : : PQgetvalue(res, i, i_reltuples),
7504 : : relallvisible, relallfrozen,
7505 : 7392 : tblinfo[i].relkind, NULL, 0);
7506 [ + + ]: 7392 : if (tblinfo[i].relkind == RELKIND_MATVIEW)
7507 : 490 : tblinfo[i].stats = stats;
7508 : : }
7509 : :
7510 : : /*
7511 : : * Read-lock target tables to make sure they aren't DROPPED or altered
7512 : : * in schema before we get around to dumping them.
7513 : : *
7514 : : * Note that we don't explicitly lock parents of the target tables; we
7515 : : * assume our lock on the child is enough to prevent schema
7516 : : * alterations to parent tables.
7517 : : *
7518 : : * NOTE: it'd be kinda nice to lock other relations too, not only
7519 : : * plain or partitioned tables, but the backend doesn't presently
7520 : : * allow that.
7521 : : *
7522 : : * We only need to lock the table for certain components; see
7523 : : * pg_dump.h
7524 : : */
1370 tgl@sss.pgh.pa.us 7525 [ + + ]: 49315 : if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
1765 7526 [ + + ]: 7392 : (tblinfo[i].relkind == RELKIND_RELATION ||
1370 7527 [ + + ]: 2112 : tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
7528 : : {
7529 : : /*
7530 : : * Tables are locked in batches. When dumping from a remote
7531 : : * server this can save a significant amount of time by reducing
7532 : : * the number of round trips.
7533 : : */
977 7534 [ + + ]: 5898 : if (query->len == 0)
7535 : 122 : appendPQExpBuffer(query, "LOCK TABLE %s",
7536 : 122 : fmtQualifiedDumpable(&tblinfo[i]));
7537 : : else
7538 : : {
7539 : 5776 : appendPQExpBuffer(query, ", %s",
7540 : 5776 : fmtQualifiedDumpable(&tblinfo[i]));
7541 : :
7542 : : /* Arbitrarily end a batch when query length reaches 100K. */
7543 [ - + ]: 5776 : if (query->len >= 100000)
7544 : : {
7545 : : /* Lock another batch of tables. */
977 tgl@sss.pgh.pa.us 7546 :UBC 0 : appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7547 : 0 : ExecuteSqlStatement(fout, query->data);
7548 : 0 : resetPQExpBuffer(query);
7549 : : }
7550 : : }
7551 : : }
7552 : : }
7553 : :
977 tgl@sss.pgh.pa.us 7554 [ + + ]:CBC 186 : if (query->len != 0)
7555 : : {
7556 : : /* Lock the tables in the last batch. */
7557 : 122 : appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7558 : 122 : ExecuteSqlStatement(fout, query->data);
7559 : : }
7560 : :
3251 7561 [ + + ]: 185 : if (dopt->lockWaitTimeout)
7562 : : {
4960 rhaas@postgresql.org 7563 : 2 : ExecuteSqlStatement(fout, "SET statement_timeout = 0");
7564 : : }
7565 : :
8520 tgl@sss.pgh.pa.us 7566 : 185 : PQclear(res);
7567 : :
4907 7568 : 185 : destroyPQExpBuffer(query);
7569 : :
7570 : 185 : return tblinfo;
7571 : : }
7572 : :
7573 : : /*
7574 : : * getOwnedSeqs
7575 : : * identify owned sequences and mark them as dumpable if owning table is
7576 : : *
7577 : : * We used to do this in getTables(), but it's better to do it after the
7578 : : * index used by findTableByOid() has been set up.
7579 : : */
7580 : : void
7581 : 185 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
7582 : : {
7583 : : int i;
7584 : :
7585 : : /*
7586 : : * Force sequences that are "owned" by table columns to be dumped whenever
7587 : : * their owning table is being dumped.
7588 : : */
7589 [ + + ]: 49228 : for (i = 0; i < numTables; i++)
7590 : : {
6956 7591 : 49043 : TableInfo *seqinfo = &tblinfo[i];
7592 : : TableInfo *owning_tab;
7593 : :
7594 [ + + ]: 49043 : if (!OidIsValid(seqinfo->owning_tab))
7595 : 48613 : continue; /* not an owned sequence */
7596 : :
4907 7597 : 430 : owning_tab = findTableByOid(seqinfo->owning_tab);
3165 sfrost@snowman.net 7598 [ - + ]: 430 : if (owning_tab == NULL)
1247 tgl@sss.pgh.pa.us 7599 :UBC 0 : pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
7600 : : seqinfo->owning_tab, seqinfo->dobj.catId.oid);
7601 : :
7602 : : /*
7603 : : * For an identity sequence, dump exactly the same components for the
7604 : : * sequence as for the owning table. This is important because we
7605 : : * treat the identity sequence as an integral part of the table. For
7606 : : * example, there is not any DDL command that allows creation of such
7607 : : * a sequence independently of the table.
7608 : : *
7609 : : * For other owned sequences such as serial sequences, we need to dump
7610 : : * the components that are being dumped for the table and any
7611 : : * components that the sequence is explicitly marked with.
7612 : : *
7613 : : * We can't simply use the set of components which are being dumped
7614 : : * for the table as the table might be in an extension (and only the
7615 : : * non-extension components, eg: ACLs if changed, security labels, and
7616 : : * policies, are being dumped) while the sequence is not (and
7617 : : * therefore the definition and other components should also be
7618 : : * dumped).
7619 : : *
7620 : : * If the sequence is part of the extension then it should be properly
7621 : : * marked by checkExtensionMembership() and this will be a no-op as
7622 : : * the table will be equivalently marked.
7623 : : */
267 tgl@sss.pgh.pa.us 7624 [ + + ]:CBC 430 : if (seqinfo->is_identity_sequence)
7625 : 205 : seqinfo->dobj.dump = owning_tab->dobj.dump;
7626 : : else
7627 : 225 : seqinfo->dobj.dump |= owning_tab->dobj.dump;
7628 : :
7629 : : /* Make sure that necessary data is available if we're dumping it */
3324 sfrost@snowman.net 7630 [ + + ]: 430 : if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
7631 : : {
4907 tgl@sss.pgh.pa.us 7632 : 334 : seqinfo->interesting = true;
267 7633 : 334 : owning_tab->interesting = true;
7634 : : }
7635 : : }
10651 scrappy@hub.org 7636 : 185 : }
7637 : :
7638 : : /*
7639 : : * getInherits
7640 : : * read all the inheritance information
7641 : : * from the system catalogs return them in the InhInfo* structure
7642 : : *
7643 : : * numInherits is set to the number of pairs read in
7644 : : */
7645 : : InhInfo *
4961 rhaas@postgresql.org 7646 : 185 : getInherits(Archive *fout, int *numInherits)
7647 : : {
7648 : : PGresult *res;
7649 : : int ntups;
7650 : : int i;
9278 bruce@momjian.us 7651 : 185 : PQExpBuffer query = createPQExpBuffer();
7652 : : InhInfo *inhinfo;
7653 : :
7654 : : int i_inhrelid;
7655 : : int i_inhparent;
7656 : :
7657 : : /* find all the inheritance information */
3047 sfrost@snowman.net 7658 : 185 : appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
7659 : :
4960 rhaas@postgresql.org 7660 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7661 : :
10226 bruce@momjian.us 7662 : 185 : ntups = PQntuples(res);
7663 : :
7664 : 185 : *numInherits = ntups;
7665 : :
5034 7666 : 185 : inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
7667 : :
9420 7668 : 185 : i_inhrelid = PQfnumber(res, "inhrelid");
10226 7669 : 185 : i_inhparent = PQfnumber(res, "inhparent");
7670 : :
7671 [ + + ]: 3690 : for (i = 0; i < ntups; i++)
7672 : : {
7945 tgl@sss.pgh.pa.us 7673 : 3505 : inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
7674 : 3505 : inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
7675 : : }
7676 : :
10226 bruce@momjian.us 7677 : 185 : PQclear(res);
7678 : :
8800 tgl@sss.pgh.pa.us 7679 : 185 : destroyPQExpBuffer(query);
7680 : :
10226 bruce@momjian.us 7681 : 185 : return inhinfo;
7682 : : }
7683 : :
7684 : : /*
7685 : : * getPartitioningInfo
7686 : : * get information about partitioning
7687 : : *
7688 : : * For the most part, we only collect partitioning info about tables we
7689 : : * intend to dump. However, this function has to consider all partitioned
7690 : : * tables in the database, because we need to know about parents of partitions
7691 : : * we are going to dump even if the parents themselves won't be dumped.
7692 : : *
7693 : : * Specifically, what we need to know is whether each partitioned table
7694 : : * has an "unsafe" partitioning scheme that requires us to force
7695 : : * load-via-partition-root mode for its children. Currently the only case
7696 : : * for which we force that is hash partitioning on enum columns, since the
7697 : : * hash codes depend on enum value OIDs which won't be replicated across
7698 : : * dump-and-reload. There are other cases in which load-via-partition-root
7699 : : * might be necessary, but we expect users to cope with them.
7700 : : */
7701 : : void
904 tgl@sss.pgh.pa.us 7702 : 185 : getPartitioningInfo(Archive *fout)
7703 : : {
7704 : : PQExpBuffer query;
7705 : : PGresult *res;
7706 : : int ntups;
7707 : :
7708 : : /* hash partitioning didn't exist before v11 */
7709 [ - + ]: 185 : if (fout->remoteVersion < 110000)
904 tgl@sss.pgh.pa.us 7710 :UBC 0 : return;
7711 : : /* needn't bother if not dumping data */
285 nathan@postgresql.or 7712 [ + + ]:CBC 185 : if (!fout->dopt->dumpData)
904 tgl@sss.pgh.pa.us 7713 : 40 : return;
7714 : :
7715 : 145 : query = createPQExpBuffer();
7716 : :
7717 : : /*
7718 : : * Unsafe partitioning schemes are exactly those for which hash enum_ops
7719 : : * appears among the partition opclasses. We needn't check partstrat.
7720 : : *
7721 : : * Note that this query may well retrieve info about tables we aren't
7722 : : * going to dump and hence have no lock on. That's okay since we need not
7723 : : * invoke any unsafe server-side functions.
7724 : : */
7725 : 145 : appendPQExpBufferStr(query,
7726 : : "SELECT partrelid FROM pg_partitioned_table WHERE\n"
7727 : : "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
7728 : : "ON c.opcmethod = a.oid\n"
7729 : : "WHERE opcname = 'enum_ops' "
7730 : : "AND opcnamespace = 'pg_catalog'::regnamespace "
7731 : : "AND amname = 'hash') = ANY(partclass)");
7732 : :
7733 : 145 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7734 : :
7735 : 145 : ntups = PQntuples(res);
7736 : :
7737 [ + + ]: 194 : for (int i = 0; i < ntups; i++)
7738 : : {
7739 : 49 : Oid tabrelid = atooid(PQgetvalue(res, i, 0));
7740 : : TableInfo *tbinfo;
7741 : :
7742 : 49 : tbinfo = findTableByOid(tabrelid);
7743 [ - + ]: 49 : if (tbinfo == NULL)
904 tgl@sss.pgh.pa.us 7744 :UBC 0 : pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
7745 : : tabrelid);
904 tgl@sss.pgh.pa.us 7746 :CBC 49 : tbinfo->unsafe_partitions = true;
7747 : : }
7748 : :
7749 : 145 : PQclear(res);
7750 : :
7751 : 145 : destroyPQExpBuffer(query);
7752 : : }
7753 : :
7754 : : /*
7755 : : * getIndexes
7756 : : * get information about every index on a dumpable table
7757 : : *
7758 : : * Note: index data is not returned directly to the caller, but it
7759 : : * does get entered into the DumpableObject tables.
7760 : : */
7761 : : void
4961 rhaas@postgresql.org 7762 : 185 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
7763 : : {
7945 tgl@sss.pgh.pa.us 7764 : 185 : PQExpBuffer query = createPQExpBuffer();
1370 7765 : 185 : PQExpBuffer tbloids = createPQExpBuffer();
7766 : : PGresult *res;
7767 : : int ntups;
7768 : : int curtblindx;
7769 : : IndxInfo *indxinfo;
7770 : : int i_tableoid,
7771 : : i_oid,
7772 : : i_indrelid,
7773 : : i_indexname,
7774 : : i_relpages,
7775 : : i_reltuples,
7776 : : i_relallvisible,
7777 : : i_relallfrozen,
7778 : : i_parentidx,
7779 : : i_indexdef,
7780 : : i_indnkeyatts,
7781 : : i_indnatts,
7782 : : i_indkey,
7783 : : i_indisclustered,
7784 : : i_indisreplident,
7785 : : i_indnullsnotdistinct,
7786 : : i_contype,
7787 : : i_conname,
7788 : : i_condeferrable,
7789 : : i_condeferred,
7790 : : i_conperiod,
7791 : : i_contableoid,
7792 : : i_conoid,
7793 : : i_condef,
7794 : : i_indattnames,
7795 : : i_tablespace,
7796 : : i_indreloptions,
7797 : : i_indstatcols,
7798 : : i_indstatvals;
7799 : :
7800 : : /*
7801 : : * We want to perform just one query against pg_index. However, we
7802 : : * mustn't try to select every row of the catalog and then sort it out on
7803 : : * the client side, because some of the server-side functions we need
7804 : : * would be unsafe to apply to tables we don't have lock on. Hence, we
7805 : : * build an array of the OIDs of tables we care about (and now have lock
7806 : : * on!), and use a WHERE clause to constrain which rows are selected.
7807 : : */
7808 : 185 : appendPQExpBufferChar(tbloids, '{');
7809 [ + + ]: 49228 : for (int i = 0; i < numTables; i++)
7810 : : {
7945 7811 : 49043 : TableInfo *tbinfo = &tblinfo[i];
7812 : :
4570 kgrittn@postgresql.o 7813 [ + + ]: 49043 : if (!tbinfo->hasindex)
7945 tgl@sss.pgh.pa.us 7814 : 34745 : continue;
7815 : :
7816 : : /*
7817 : : * We can ignore indexes of uninteresting tables.
7818 : : */
1370 7819 [ + + ]: 14298 : if (!tbinfo->interesting)
7945 7820 : 12225 : continue;
7821 : :
7822 : : /* OK, we need info for this table */
1370 7823 [ + + ]: 2073 : if (tbloids->len > 1) /* do we have more than the '{'? */
7824 : 1989 : appendPQExpBufferChar(tbloids, ',');
7825 : 2073 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
7826 : : }
7827 : 185 : appendPQExpBufferChar(tbloids, '}');
7828 : :
1096 drowley@postgresql.o 7829 : 185 : appendPQExpBufferStr(query,
7830 : : "SELECT t.tableoid, t.oid, i.indrelid, "
7831 : : "t.relname AS indexname, "
7832 : : "t.relpages, t.reltuples, t.relallvisible, ");
7833 : :
160 jdavis@postgresql.or 7834 [ + - ]: 185 : if (fout->remoteVersion >= 180000)
7835 : 185 : appendPQExpBufferStr(query, "t.relallfrozen, ");
7836 : : else
160 jdavis@postgresql.or 7837 :UBC 0 : appendPQExpBufferStr(query, "0 AS relallfrozen, ");
7838 : :
160 jdavis@postgresql.or 7839 :CBC 185 : appendPQExpBufferStr(query,
7840 : : "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7841 : : "i.indkey, i.indisclustered, "
7842 : : "c.contype, c.conname, "
7843 : : "c.condeferrable, c.condeferred, "
7844 : : "c.tableoid AS contableoid, "
7845 : : "c.oid AS conoid, "
7846 : : "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
7847 : : "CASE WHEN i.indexprs IS NOT NULL THEN "
7848 : : "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
7849 : : " FROM pg_catalog.pg_attribute "
7850 : : " WHERE attrelid = i.indexrelid) "
7851 : : "ELSE NULL END AS indattnames, "
7852 : : "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7853 : : "t.reloptions AS indreloptions, ");
7854 : :
7855 : :
1356 peter@eisentraut.org 7856 [ + - ]: 185 : if (fout->remoteVersion >= 90400)
1096 drowley@postgresql.o 7857 : 185 : appendPQExpBufferStr(query,
7858 : : "i.indisreplident, ");
7859 : : else
1096 drowley@postgresql.o 7860 :UBC 0 : appendPQExpBufferStr(query,
7861 : : "false AS indisreplident, ");
7862 : :
1356 peter@eisentraut.org 7863 [ + - ]:CBC 185 : if (fout->remoteVersion >= 110000)
1096 drowley@postgresql.o 7864 : 185 : appendPQExpBufferStr(query,
7865 : : "inh.inhparent AS parentidx, "
7866 : : "i.indnkeyatts AS indnkeyatts, "
7867 : : "i.indnatts AS indnatts, "
7868 : : "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
7869 : : " FROM pg_catalog.pg_attribute "
7870 : : " WHERE attrelid = i.indexrelid AND "
7871 : : " attstattarget >= 0) AS indstatcols, "
7872 : : "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
7873 : : " FROM pg_catalog.pg_attribute "
7874 : : " WHERE attrelid = i.indexrelid AND "
7875 : : " attstattarget >= 0) AS indstatvals, ");
7876 : : else
1096 drowley@postgresql.o 7877 :UBC 0 : appendPQExpBufferStr(query,
7878 : : "0 AS parentidx, "
7879 : : "i.indnatts AS indnkeyatts, "
7880 : : "i.indnatts AS indnatts, "
7881 : : "'' AS indstatcols, "
7882 : : "'' AS indstatvals, ");
7883 : :
1311 peter@eisentraut.org 7884 [ + - ]:CBC 185 : if (fout->remoteVersion >= 150000)
1096 drowley@postgresql.o 7885 : 185 : appendPQExpBufferStr(query,
7886 : : "i.indnullsnotdistinct, ");
7887 : : else
1096 drowley@postgresql.o 7888 :UBC 0 : appendPQExpBufferStr(query,
7889 : : "false AS indnullsnotdistinct, ");
7890 : :
354 peter@eisentraut.org 7891 [ + - ]:CBC 185 : if (fout->remoteVersion >= 180000)
7892 : 185 : appendPQExpBufferStr(query,
7893 : : "c.conperiod ");
7894 : : else
354 peter@eisentraut.org 7895 :UBC 0 : appendPQExpBufferStr(query,
7896 : : "NULL AS conperiod ");
7897 : :
7898 : : /*
7899 : : * The point of the messy-looking outer join is to find a constraint that
7900 : : * is related by an internal dependency link to the index. If we find one,
7901 : : * create a CONSTRAINT entry linked to the INDEX entry. We assume an
7902 : : * index won't have more than one internal dependency.
7903 : : *
7904 : : * Note: the check on conrelid is redundant, but useful because that
7905 : : * column is indexed while conindid is not.
7906 : : */
1370 tgl@sss.pgh.pa.us 7907 [ + - ]:CBC 185 : if (fout->remoteVersion >= 110000)
7908 : : {
7909 : 185 : appendPQExpBuffer(query,
7910 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7911 : : "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7912 : : "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7913 : : "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
7914 : : "LEFT JOIN pg_catalog.pg_constraint c "
7915 : : "ON (i.indrelid = c.conrelid AND "
7916 : : "i.indexrelid = c.conindid AND "
7917 : : "c.contype IN ('p','u','x')) "
7918 : : "LEFT JOIN pg_catalog.pg_inherits inh "
7919 : : "ON (inh.inhrelid = indexrelid) "
7920 : : "WHERE (i.indisvalid OR t2.relkind = 'p') "
7921 : : "AND i.indisready "
7922 : : "ORDER BY i.indrelid, indexname",
7923 : : tbloids->data);
7924 : : }
7925 : : else
7926 : : {
7927 : : /*
7928 : : * the test on indisready is necessary in 9.2, and harmless in
7929 : : * earlier/later versions
7930 : : */
1370 tgl@sss.pgh.pa.us 7931 :UBC 0 : appendPQExpBuffer(query,
7932 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7933 : : "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7934 : : "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7935 : : "LEFT JOIN pg_catalog.pg_constraint c "
7936 : : "ON (i.indrelid = c.conrelid AND "
7937 : : "i.indexrelid = c.conindid AND "
7938 : : "c.contype IN ('p','u','x')) "
7939 : : "WHERE i.indisvalid AND i.indisready "
7940 : : "ORDER BY i.indrelid, indexname",
7941 : : tbloids->data);
7942 : : }
7943 : :
1370 tgl@sss.pgh.pa.us 7944 :CBC 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7945 : :
7946 : 185 : ntups = PQntuples(res);
7947 : :
7948 : 185 : i_tableoid = PQfnumber(res, "tableoid");
7949 : 185 : i_oid = PQfnumber(res, "oid");
7950 : 185 : i_indrelid = PQfnumber(res, "indrelid");
7951 : 185 : i_indexname = PQfnumber(res, "indexname");
193 jdavis@postgresql.or 7952 : 185 : i_relpages = PQfnumber(res, "relpages");
7953 : 185 : i_reltuples = PQfnumber(res, "reltuples");
7954 : 185 : i_relallvisible = PQfnumber(res, "relallvisible");
160 7955 : 185 : i_relallfrozen = PQfnumber(res, "relallfrozen");
1370 tgl@sss.pgh.pa.us 7956 : 185 : i_parentidx = PQfnumber(res, "parentidx");
7957 : 185 : i_indexdef = PQfnumber(res, "indexdef");
7958 : 185 : i_indnkeyatts = PQfnumber(res, "indnkeyatts");
7959 : 185 : i_indnatts = PQfnumber(res, "indnatts");
7960 : 185 : i_indkey = PQfnumber(res, "indkey");
7961 : 185 : i_indisclustered = PQfnumber(res, "indisclustered");
7962 : 185 : i_indisreplident = PQfnumber(res, "indisreplident");
1311 peter@eisentraut.org 7963 : 185 : i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
1370 tgl@sss.pgh.pa.us 7964 : 185 : i_contype = PQfnumber(res, "contype");
7965 : 185 : i_conname = PQfnumber(res, "conname");
7966 : 185 : i_condeferrable = PQfnumber(res, "condeferrable");
7967 : 185 : i_condeferred = PQfnumber(res, "condeferred");
354 peter@eisentraut.org 7968 : 185 : i_conperiod = PQfnumber(res, "conperiod");
1370 tgl@sss.pgh.pa.us 7969 : 185 : i_contableoid = PQfnumber(res, "contableoid");
7970 : 185 : i_conoid = PQfnumber(res, "conoid");
7971 : 185 : i_condef = PQfnumber(res, "condef");
192 7972 : 185 : i_indattnames = PQfnumber(res, "indattnames");
1370 7973 : 185 : i_tablespace = PQfnumber(res, "tablespace");
7974 : 185 : i_indreloptions = PQfnumber(res, "indreloptions");
7975 : 185 : i_indstatcols = PQfnumber(res, "indstatcols");
7976 : 185 : i_indstatvals = PQfnumber(res, "indstatvals");
7977 : :
7978 : 185 : indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
7979 : :
7980 : : /*
7981 : : * Outer loop iterates once per table, not once per row. Incrementing of
7982 : : * j is handled by the inner loop.
7983 : : */
7984 : 185 : curtblindx = -1;
7985 [ + + ]: 2240 : for (int j = 0; j < ntups;)
7986 : : {
7987 : 2055 : Oid indrelid = atooid(PQgetvalue(res, j, i_indrelid));
7988 : 2055 : TableInfo *tbinfo = NULL;
192 7989 : 2055 : char **indAttNames = NULL;
7990 : 2055 : int nindAttNames = 0;
7991 : : int numinds;
7992 : :
7993 : : /* Count rows for this table */
1370 7994 [ + + ]: 2697 : for (numinds = 1; numinds < ntups - j; numinds++)
7995 [ + + ]: 2613 : if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
7996 : 1971 : break;
7997 : :
7998 : : /*
7999 : : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8000 : : * order.
8001 : : */
8002 [ + - ]: 24779 : while (++curtblindx < numTables)
8003 : : {
8004 : 24779 : tbinfo = &tblinfo[curtblindx];
8005 [ + + ]: 24779 : if (tbinfo->dobj.catId.oid == indrelid)
8006 : 2055 : break;
8007 : : }
8008 [ - + ]: 2055 : if (curtblindx >= numTables)
1247 tgl@sss.pgh.pa.us 8009 :UBC 0 : pg_fatal("unrecognized table OID %u", indrelid);
8010 : : /* cross-check that we only got requested tables */
1370 tgl@sss.pgh.pa.us 8011 [ + - ]:CBC 2055 : if (!tbinfo->hasindex ||
8012 [ - + ]: 2055 : !tbinfo->interesting)
1247 tgl@sss.pgh.pa.us 8013 :UBC 0 : pg_fatal("unexpected index data for table \"%s\"",
8014 : : tbinfo->dobj.name);
8015 : :
8016 : : /* Save data for this table */
1370 tgl@sss.pgh.pa.us 8017 :CBC 2055 : tbinfo->indexes = indxinfo + j;
8018 : 2055 : tbinfo->numIndexes = numinds;
8019 : :
8020 [ + + ]: 4752 : for (int c = 0; c < numinds; c++, j++)
8021 : : {
8022 : : char contype;
8023 : : char indexkind;
8024 : : RelStatsInfo *relstats;
193 jdavis@postgresql.or 8025 : 2697 : int32 relpages = atoi(PQgetvalue(res, j, i_relpages));
8026 : 2697 : int32 relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
160 8027 : 2697 : int32 relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
8028 : :
7945 tgl@sss.pgh.pa.us 8029 : 2697 : indxinfo[j].dobj.objType = DO_INDEX;
8030 : 2697 : indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8031 : 2697 : indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8032 : 2697 : AssignDumpId(&indxinfo[j].dobj);
2787 alvherre@alvh.no-ip. 8033 : 2697 : indxinfo[j].dobj.dump = tbinfo->dobj.dump;
5034 bruce@momjian.us 8034 : 2697 : indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7857 tgl@sss.pgh.pa.us 8035 : 2697 : indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7945 8036 : 2697 : indxinfo[j].indextable = tbinfo;
5034 bruce@momjian.us 8037 : 2697 : indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
2699 heikki.linnakangas@i 8038 : 2697 : indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
2709 teodor@sigaev.ru 8039 : 2697 : indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
5034 bruce@momjian.us 8040 : 2697 : indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
3535 tgl@sss.pgh.pa.us 8041 : 2697 : indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
2454 michael@paquier.xyz 8042 : 2697 : indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
8043 : 2697 : indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
2709 teodor@sigaev.ru 8044 : 2697 : indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7945 tgl@sss.pgh.pa.us 8045 : 2697 : parseOidArray(PQgetvalue(res, j, i_indkey),
2709 teodor@sigaev.ru 8046 : 2697 : indxinfo[j].indkeys, indxinfo[j].indnattrs);
7945 tgl@sss.pgh.pa.us 8047 : 2697 : indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
4320 rhaas@postgresql.org 8048 : 2697 : indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
1311 peter@eisentraut.org 8049 : 2697 : indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
2787 alvherre@alvh.no-ip. 8050 : 2697 : indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
1941 tgl@sss.pgh.pa.us 8051 : 2697 : indxinfo[j].partattaches = (SimplePtrList)
8052 : : {
8053 : : NULL, NULL
8054 : : };
8055 : :
198 jdavis@postgresql.or 8056 [ + + ]: 2697 : if (indxinfo[j].parentidx == 0)
8057 : 2085 : indexkind = RELKIND_INDEX;
8058 : : else
8059 : 612 : indexkind = RELKIND_PARTITIONED_INDEX;
8060 : :
192 tgl@sss.pgh.pa.us 8061 [ + + ]: 2697 : if (!PQgetisnull(res, j, i_indattnames))
8062 : : {
8063 [ - + ]: 158 : if (!parsePGArray(PQgetvalue(res, j, i_indattnames),
8064 : : &indAttNames, &nindAttNames))
192 tgl@sss.pgh.pa.us 8065 :UBC 0 : pg_fatal("could not parse %s array", "indattnames");
8066 : : }
8067 : :
193 jdavis@postgresql.or 8068 :CBC 2697 : relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
8069 : : PQgetvalue(res, j, i_reltuples),
8070 : : relallvisible, relallfrozen, indexkind,
8071 : : indAttNames, nindAttNames);
8072 : :
192 tgl@sss.pgh.pa.us 8073 : 2697 : contype = *(PQgetvalue(res, j, i_contype));
5752 8074 [ + + + + : 2697 : if (contype == 'p' || contype == 'u' || contype == 'x')
+ + ]
7945 8075 : 1573 : {
8076 : : /*
8077 : : * If we found a constraint matching the index, create an
8078 : : * entry for it.
8079 : : */
8080 : : ConstraintInfo *constrinfo;
8081 : :
1413 8082 : 1573 : constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
8083 : 1573 : constrinfo->dobj.objType = DO_CONSTRAINT;
8084 : 1573 : constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
8085 : 1573 : constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
8086 : 1573 : AssignDumpId(&constrinfo->dobj);
8087 : 1573 : constrinfo->dobj.dump = tbinfo->dobj.dump;
8088 : 1573 : constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
8089 : 1573 : constrinfo->dobj.namespace = tbinfo->dobj.namespace;
8090 : 1573 : constrinfo->contable = tbinfo;
8091 : 1573 : constrinfo->condomain = NULL;
8092 : 1573 : constrinfo->contype = contype;
5752 8093 [ + + ]: 1573 : if (contype == 'x')
1413 8094 : 10 : constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
8095 : : else
8096 : 1563 : constrinfo->condef = NULL;
8097 : 1573 : constrinfo->confrelid = InvalidOid;
8098 : 1573 : constrinfo->conindex = indxinfo[j].dobj.dumpId;
8099 : 1573 : constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
8100 : 1573 : constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
354 peter@eisentraut.org 8101 : 1573 : constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
1413 tgl@sss.pgh.pa.us 8102 : 1573 : constrinfo->conislocal = true;
8103 : 1573 : constrinfo->separate = true;
8104 : :
8105 : 1573 : indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
198 jdavis@postgresql.or 8106 [ + + ]: 1573 : if (relstats != NULL)
8107 : 598 : addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
8108 : : }
8109 : : else
8110 : : {
8111 : : /* Plain secondary index */
7945 tgl@sss.pgh.pa.us 8112 : 1124 : indxinfo[j].indexconstraint = 0;
8113 : : }
8114 : : }
8115 : : }
8116 : :
1370 8117 : 185 : PQclear(res);
8118 : :
7945 8119 : 185 : destroyPQExpBuffer(query);
1370 8120 : 185 : destroyPQExpBuffer(tbloids);
7945 8121 : 185 : }
8122 : :
8123 : : /*
8124 : : * getExtendedStatistics
8125 : : * get information about extended-statistics objects.
8126 : : *
8127 : : * Note: extended statistics data is not returned directly to the caller, but
8128 : : * it does get entered into the DumpableObject tables.
8129 : : */
8130 : : void
2764 8131 : 185 : getExtendedStatistics(Archive *fout)
8132 : : {
8133 : : PQExpBuffer query;
8134 : : PGresult *res;
8135 : : StatsExtInfo *statsextinfo;
8136 : : int ntups;
8137 : : int i_tableoid;
8138 : : int i_oid;
8139 : : int i_stxname;
8140 : : int i_stxnamespace;
8141 : : int i_stxowner;
8142 : : int i_stxrelid;
8143 : : int i_stattarget;
8144 : : int i;
8145 : :
8146 : : /* Extended statistics were new in v10 */
3088 alvherre@alvh.no-ip. 8147 [ - + ]: 185 : if (fout->remoteVersion < 100000)
3088 alvherre@alvh.no-ip. 8148 :UBC 0 : return;
8149 : :
3088 alvherre@alvh.no-ip. 8150 :CBC 185 : query = createPQExpBuffer();
8151 : :
2188 tomas.vondra@postgre 8152 [ - + ]: 185 : if (fout->remoteVersion < 130000)
1096 drowley@postgresql.o 8153 :UBC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
8154 : : "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
8155 : : "FROM pg_catalog.pg_statistic_ext");
8156 : : else
1096 drowley@postgresql.o 8157 :CBC 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
8158 : : "stxnamespace, stxowner, stxrelid, stxstattarget "
8159 : : "FROM pg_catalog.pg_statistic_ext");
8160 : :
2764 tgl@sss.pgh.pa.us 8161 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8162 : :
8163 : 185 : ntups = PQntuples(res);
8164 : :
8165 : 185 : i_tableoid = PQfnumber(res, "tableoid");
8166 : 185 : i_oid = PQfnumber(res, "oid");
8167 : 185 : i_stxname = PQfnumber(res, "stxname");
8168 : 185 : i_stxnamespace = PQfnumber(res, "stxnamespace");
1345 8169 : 185 : i_stxowner = PQfnumber(res, "stxowner");
617 8170 : 185 : i_stxrelid = PQfnumber(res, "stxrelid");
2188 tomas.vondra@postgre 8171 : 185 : i_stattarget = PQfnumber(res, "stxstattarget");
8172 : :
2764 tgl@sss.pgh.pa.us 8173 : 185 : statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
8174 : :
8175 [ + + ]: 366 : for (i = 0; i < ntups; i++)
8176 : : {
8177 : 181 : statsextinfo[i].dobj.objType = DO_STATSEXT;
8178 : 181 : statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8179 : 181 : statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8180 : 181 : AssignDumpId(&statsextinfo[i].dobj);
8181 : 181 : statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
8182 : 362 : statsextinfo[i].dobj.namespace =
1838 peter@eisentraut.org 8183 : 181 : findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
1345 tgl@sss.pgh.pa.us 8184 : 181 : statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
617 8185 : 362 : statsextinfo[i].stattable =
8186 : 181 : findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
538 peter@eisentraut.org 8187 [ + + ]: 181 : if (PQgetisnull(res, i, i_stattarget))
8188 : 130 : statsextinfo[i].stattarget = -1;
8189 : : else
8190 : 51 : statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
8191 : :
8192 : : /* Decide whether we want to dump it */
617 tgl@sss.pgh.pa.us 8193 : 181 : selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
8194 : : }
8195 : :
2764 8196 : 185 : PQclear(res);
3088 alvherre@alvh.no-ip. 8197 : 185 : destroyPQExpBuffer(query);
8198 : : }
8199 : :
8200 : : /*
8201 : : * getConstraints
8202 : : *
8203 : : * Get info about constraints on dumpable tables.
8204 : : *
8205 : : * Currently handles foreign keys only.
8206 : : * Unique and primary key constraints are handled with indexes,
8207 : : * while check constraints are processed in getTableAttrs().
8208 : : */
8209 : : void
4961 rhaas@postgresql.org 8210 : 185 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
8211 : : {
1370 tgl@sss.pgh.pa.us 8212 : 185 : PQExpBuffer query = createPQExpBuffer();
8213 : 185 : PQExpBuffer tbloids = createPQExpBuffer();
8214 : : PGresult *res;
8215 : : int ntups;
8216 : : int curtblindx;
8217 : 185 : TableInfo *tbinfo = NULL;
8218 : : ConstraintInfo *constrinfo;
8219 : : int i_contableoid,
8220 : : i_conoid,
8221 : : i_conrelid,
8222 : : i_conname,
8223 : : i_confrelid,
8224 : : i_conindid,
8225 : : i_condef;
8226 : :
8227 : : /*
8228 : : * We want to perform just one query against pg_constraint. However, we
8229 : : * mustn't try to select every row of the catalog and then sort it out on
8230 : : * the client side, because some of the server-side functions we need
8231 : : * would be unsafe to apply to tables we don't have lock on. Hence, we
8232 : : * build an array of the OIDs of tables we care about (and now have lock
8233 : : * on!), and use a WHERE clause to constrain which rows are selected.
8234 : : */
8235 : 185 : appendPQExpBufferChar(tbloids, '{');
8236 [ + + ]: 49228 : for (int i = 0; i < numTables; i++)
8237 : : {
1113 drowley@postgresql.o 8238 : 49043 : TableInfo *tinfo = &tblinfo[i];
8239 : :
157 peter@eisentraut.org 8240 [ + + ]: 49043 : if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7945 tgl@sss.pgh.pa.us 8241 : 41705 : continue;
8242 : :
8243 : : /* OK, we need info for this table */
1370 8244 [ + + ]: 7338 : if (tbloids->len > 1) /* do we have more than the '{'? */
8245 : 7215 : appendPQExpBufferChar(tbloids, ',');
1113 drowley@postgresql.o 8246 : 7338 : appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
8247 : : }
1370 tgl@sss.pgh.pa.us 8248 : 185 : appendPQExpBufferChar(tbloids, '}');
8249 : :
8250 : 185 : appendPQExpBufferStr(query,
8251 : : "SELECT c.tableoid, c.oid, "
8252 : : "conrelid, conname, confrelid, ");
8253 [ + - ]: 185 : if (fout->remoteVersion >= 110000)
8254 : 185 : appendPQExpBufferStr(query, "conindid, ");
8255 : : else
1370 tgl@sss.pgh.pa.us 8256 :UBC 0 : appendPQExpBufferStr(query, "0 AS conindid, ");
1370 tgl@sss.pgh.pa.us 8257 :CBC 185 : appendPQExpBuffer(query,
8258 : : "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
8259 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8260 : : "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
8261 : : "WHERE contype = 'f' ",
8262 : : tbloids->data);
8263 [ + - ]: 185 : if (fout->remoteVersion >= 110000)
8264 : 185 : appendPQExpBufferStr(query,
8265 : : "AND conparentid = 0 ");
8266 : 185 : appendPQExpBufferStr(query,
8267 : : "ORDER BY conrelid, conname");
8268 : :
8269 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8270 : :
8271 : 185 : ntups = PQntuples(res);
8272 : :
8273 : 185 : i_contableoid = PQfnumber(res, "tableoid");
8274 : 185 : i_conoid = PQfnumber(res, "oid");
8275 : 185 : i_conrelid = PQfnumber(res, "conrelid");
8276 : 185 : i_conname = PQfnumber(res, "conname");
8277 : 185 : i_confrelid = PQfnumber(res, "confrelid");
8278 : 185 : i_conindid = PQfnumber(res, "conindid");
8279 : 185 : i_condef = PQfnumber(res, "condef");
8280 : :
8281 : 185 : constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
8282 : :
8283 : 185 : curtblindx = -1;
8284 [ + + ]: 368 : for (int j = 0; j < ntups; j++)
8285 : : {
8286 : 183 : Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
8287 : : TableInfo *reftable;
8288 : :
8289 : : /*
8290 : : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8291 : : * order.
8292 : : */
8293 [ + + + + ]: 183 : if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
8294 : : {
8295 [ + - ]: 15008 : while (++curtblindx < numTables)
8296 : : {
8297 : 15008 : tbinfo = &tblinfo[curtblindx];
8298 [ + + ]: 15008 : if (tbinfo->dobj.catId.oid == conrelid)
8299 : 173 : break;
8300 : : }
8301 [ - + ]: 173 : if (curtblindx >= numTables)
1247 tgl@sss.pgh.pa.us 8302 :UBC 0 : pg_fatal("unrecognized table OID %u", conrelid);
8303 : : }
8304 : :
1370 tgl@sss.pgh.pa.us 8305 :CBC 183 : constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
8306 : 183 : constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
8307 : 183 : constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
8308 : 183 : AssignDumpId(&constrinfo[j].dobj);
8309 : 183 : constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
8310 : 183 : constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
8311 : 183 : constrinfo[j].contable = tbinfo;
8312 : 183 : constrinfo[j].condomain = NULL;
8313 : 183 : constrinfo[j].contype = 'f';
8314 : 183 : constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
8315 : 183 : constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
8316 : 183 : constrinfo[j].conindex = 0;
8317 : 183 : constrinfo[j].condeferrable = false;
8318 : 183 : constrinfo[j].condeferred = false;
8319 : 183 : constrinfo[j].conislocal = true;
8320 : 183 : constrinfo[j].separate = true;
8321 : :
8322 : : /*
8323 : : * Restoring an FK that points to a partitioned table requires that
8324 : : * all partition indexes have been attached beforehand. Ensure that
8325 : : * happens by making the constraint depend on each index partition
8326 : : * attach object.
8327 : : */
8328 : 183 : reftable = findTableByOid(constrinfo[j].confrelid);
8329 [ + - + + ]: 183 : if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
8330 : : {
8331 : 20 : Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));
8332 : :
8333 [ + - ]: 20 : if (indexOid != InvalidOid)
8334 : : {
8335 [ + - ]: 20 : for (int k = 0; k < reftable->numIndexes; k++)
8336 : : {
8337 : : IndxInfo *refidx;
8338 : :
8339 : : /* not our index? */
8340 [ - + ]: 20 : if (reftable->indexes[k].dobj.catId.oid != indexOid)
1370 tgl@sss.pgh.pa.us 8341 :UBC 0 : continue;
8342 : :
1370 tgl@sss.pgh.pa.us 8343 :CBC 20 : refidx = &reftable->indexes[k];
8344 : 20 : addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
8345 : 20 : break;
8346 : : }
8347 : : }
8348 : : }
8349 : : }
8350 : :
8351 : 185 : PQclear(res);
8352 : :
7945 8353 : 185 : destroyPQExpBuffer(query);
1370 8354 : 185 : destroyPQExpBuffer(tbloids);
7945 8355 : 185 : }
8356 : :
8357 : : /*
8358 : : * addConstrChildIdxDeps
8359 : : *
8360 : : * Recursive subroutine for getConstraints
8361 : : *
8362 : : * Given an object representing a foreign key constraint and an index on the
8363 : : * partitioned table it references, mark the constraint object as dependent
8364 : : * on the DO_INDEX_ATTACH object of each index partition, recursively
8365 : : * drilling down to their partitions if any. This ensures that the FK is not
8366 : : * restored until the index is fully marked valid.
8367 : : */
8368 : : static void
1669 peter@eisentraut.org 8369 : 45 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
8370 : : {
8371 : : SimplePtrListCell *cell;
8372 : :
1849 alvherre@alvh.no-ip. 8373 [ - + ]: 45 : Assert(dobj->objType == DO_FK_CONSTRAINT);
8374 : :
8375 [ + + ]: 155 : for (cell = refidx->partattaches.head; cell; cell = cell->next)
8376 : : {
8377 : 110 : IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
8378 : :
8379 : 110 : addObjectDependency(dobj, attach->dobj.dumpId);
8380 : :
8381 [ + + ]: 110 : if (attach->partitionIdx->partattaches.head != NULL)
8382 : 25 : addConstrChildIdxDeps(dobj, attach->partitionIdx);
8383 : : }
8384 : 45 : }
8385 : :
8386 : : /*
8387 : : * getDomainConstraints
8388 : : *
8389 : : * Get info about constraints on a domain.
8390 : : */
8391 : : static void
4961 rhaas@postgresql.org 8392 : 164 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
8393 : : {
8394 : : ConstraintInfo *constrinfo;
1370 tgl@sss.pgh.pa.us 8395 : 164 : PQExpBuffer query = createPQExpBuffer();
8396 : : PGresult *res;
8397 : : int i_tableoid,
8398 : : i_oid,
8399 : : i_conname,
8400 : : i_consrc,
8401 : : i_convalidated,
8402 : : i_contype;
8403 : : int ntups;
8404 : :
8405 [ + + ]: 164 : if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
8406 : : {
8407 : : /*
8408 : : * Set up query for constraint-specific details. For servers 17 and
8409 : : * up, domains have constraints of type 'n' as well as 'c', otherwise
8410 : : * just the latter.
8411 : : */
47 alvherre@kurilemu.de 8412 : 49 : appendPQExpBuffer(query,
8413 : : "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
8414 : : "SELECT tableoid, oid, conname, "
8415 : : "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8416 : : "convalidated, contype "
8417 : : "FROM pg_catalog.pg_constraint "
8418 : : "WHERE contypid = $1 AND contype IN (%s) "
8419 : : "ORDER BY conname",
8420 [ - + ]: 49 : fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
8421 : :
1370 tgl@sss.pgh.pa.us 8422 : 49 : ExecuteSqlStatement(fout, query->data);
8423 : :
8424 : 49 : fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
8425 : : }
8426 : :
8427 : 164 : printfPQExpBuffer(query,
8428 : : "EXECUTE getDomainConstraints('%u')",
8429 : : tyinfo->dobj.catId.oid);
8430 : :
4960 rhaas@postgresql.org 8431 : 164 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8432 : :
7945 tgl@sss.pgh.pa.us 8433 : 164 : ntups = PQntuples(res);
8434 : :
8435 : 164 : i_tableoid = PQfnumber(res, "tableoid");
8436 : 164 : i_oid = PQfnumber(res, "oid");
8437 : 164 : i_conname = PQfnumber(res, "conname");
8438 : 164 : i_consrc = PQfnumber(res, "consrc");
47 alvherre@kurilemu.de 8439 : 164 : i_convalidated = PQfnumber(res, "convalidated");
8440 : 164 : i_contype = PQfnumber(res, "contype");
8441 : :
5034 bruce@momjian.us 8442 : 164 : constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5736 8443 : 164 : tyinfo->domChecks = constrinfo;
8444 : :
8445 : : /* 'i' tracks result rows; 'j' counts CHECK constraints */
47 alvherre@kurilemu.de 8446 [ + + ]: 342 : for (int i = 0, j = 0; i < ntups; i++)
8447 : : {
8448 : 178 : bool validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
8449 : 178 : char contype = (PQgetvalue(res, i, i_contype))[0];
8450 : : ConstraintInfo *constraint;
8451 : :
8452 [ + + ]: 178 : if (contype == CONSTRAINT_CHECK)
8453 : : {
8454 : 119 : constraint = &constrinfo[j++];
8455 : 119 : tyinfo->nDomChecks++;
8456 : : }
8457 : : else
8458 : : {
8459 [ - + ]: 59 : Assert(contype == CONSTRAINT_NOTNULL);
8460 [ - + ]: 59 : Assert(tyinfo->notnull == NULL);
8461 : : /* use last item in array for the not-null constraint */
8462 : 59 : tyinfo->notnull = &(constrinfo[ntups - 1]);
8463 : 59 : constraint = tyinfo->notnull;
8464 : : }
8465 : :
8466 : 178 : constraint->dobj.objType = DO_CONSTRAINT;
8467 : 178 : constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8468 : 178 : constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8469 : 178 : AssignDumpId(&(constraint->dobj));
8470 : 178 : constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
8471 : 178 : constraint->dobj.namespace = tyinfo->dobj.namespace;
8472 : 178 : constraint->contable = NULL;
8473 : 178 : constraint->condomain = tyinfo;
8474 : 178 : constraint->contype = contype;
8475 : 178 : constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
8476 : 178 : constraint->confrelid = InvalidOid;
8477 : 178 : constraint->conindex = 0;
8478 : 178 : constraint->condeferrable = false;
8479 : 178 : constraint->condeferred = false;
8480 : 178 : constraint->conislocal = true;
8481 : :
8482 : 178 : constraint->separate = !validated;
8483 : :
8484 : : /*
8485 : : * Make the domain depend on the constraint, ensuring it won't be
8486 : : * output till any constraint dependencies are OK. If the constraint
8487 : : * has not been validated, it's going to be dumped after the domain
8488 : : * anyway, so this doesn't matter.
8489 : : */
5034 alvherre@alvh.no-ip. 8490 [ + + ]: 178 : if (validated)
47 alvherre@kurilemu.de 8491 : 173 : addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
8492 : : }
8493 : :
7945 tgl@sss.pgh.pa.us 8494 : 164 : PQclear(res);
8495 : :
8496 : 164 : destroyPQExpBuffer(query);
8497 : 164 : }
8498 : :
8499 : : /*
8500 : : * getRules
8501 : : * get basic information about every rule in the system
8502 : : */
8503 : : void
431 nathan@postgresql.or 8504 : 185 : getRules(Archive *fout)
8505 : : {
8506 : : PGresult *res;
8507 : : int ntups;
8508 : : int i;
7945 tgl@sss.pgh.pa.us 8509 : 185 : PQExpBuffer query = createPQExpBuffer();
8510 : : RuleInfo *ruleinfo;
8511 : : int i_tableoid;
8512 : : int i_oid;
8513 : : int i_rulename;
8514 : : int i_ruletable;
8515 : : int i_ev_type;
8516 : : int i_is_instead;
8517 : : int i_ev_enabled;
8518 : :
1362 8519 : 185 : appendPQExpBufferStr(query, "SELECT "
8520 : : "tableoid, oid, rulename, "
8521 : : "ev_class AS ruletable, ev_type, is_instead, "
8522 : : "ev_enabled "
8523 : : "FROM pg_rewrite "
8524 : : "ORDER BY oid");
8525 : :
4960 rhaas@postgresql.org 8526 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8527 : :
7945 tgl@sss.pgh.pa.us 8528 : 185 : ntups = PQntuples(res);
8529 : :
5034 bruce@momjian.us 8530 : 185 : ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
8531 : :
7945 tgl@sss.pgh.pa.us 8532 : 185 : i_tableoid = PQfnumber(res, "tableoid");
8533 : 185 : i_oid = PQfnumber(res, "oid");
8534 : 185 : i_rulename = PQfnumber(res, "rulename");
8535 : 185 : i_ruletable = PQfnumber(res, "ruletable");
8536 : 185 : i_ev_type = PQfnumber(res, "ev_type");
8537 : 185 : i_is_instead = PQfnumber(res, "is_instead");
6746 JanWieck@Yahoo.com 8538 : 185 : i_ev_enabled = PQfnumber(res, "ev_enabled");
8539 : :
7945 tgl@sss.pgh.pa.us 8540 [ + + ]: 28812 : for (i = 0; i < ntups; i++)
8541 : : {
8542 : : Oid ruletableoid;
8543 : :
8544 : 28627 : ruleinfo[i].dobj.objType = DO_RULE;
8545 : 28627 : ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8546 : 28627 : ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8547 : 28627 : AssignDumpId(&ruleinfo[i].dobj);
5034 bruce@momjian.us 8548 : 28627 : ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7945 tgl@sss.pgh.pa.us 8549 : 28627 : ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
8550 : 28627 : ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7481 8551 [ - + ]: 28627 : if (ruleinfo[i].ruletable == NULL)
1247 tgl@sss.pgh.pa.us 8552 :UBC 0 : pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
8553 : : ruletableoid, ruleinfo[i].dobj.catId.oid);
7857 tgl@sss.pgh.pa.us 8554 :CBC 28627 : ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7128 8555 : 28627 : ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7945 8556 : 28627 : ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
8557 : 28627 : ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
6746 JanWieck@Yahoo.com 8558 : 28627 : ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7945 tgl@sss.pgh.pa.us 8559 [ + - ]: 28627 : if (ruleinfo[i].ruletable)
8560 : : {
8561 : : /*
8562 : : * If the table is a view or materialized view, force its ON
8563 : : * SELECT rule to be sorted before the view itself --- this
8564 : : * ensures that any dependencies for the rule affect the table's
8565 : : * positioning. Other rules are forced to appear after their
8566 : : * table.
8567 : : */
4570 kgrittn@postgresql.o 8568 [ + + ]: 28627 : if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
4549 andrew@dunslane.net 8569 [ + + ]: 797 : ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7945 tgl@sss.pgh.pa.us 8570 [ + + + - ]: 28396 : ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
8571 : : {
8572 : 27984 : addObjectDependency(&ruleinfo[i].ruletable->dobj,
8573 : 27984 : ruleinfo[i].dobj.dumpId);
8574 : : /* We'll merge the rule into CREATE VIEW, if possible */
7571 8575 : 27984 : ruleinfo[i].separate = false;
8576 : : }
8577 : : else
8578 : : {
7945 8579 : 643 : addObjectDependency(&ruleinfo[i].dobj,
8580 : 643 : ruleinfo[i].ruletable->dobj.dumpId);
7571 8581 : 643 : ruleinfo[i].separate = true;
8582 : : }
8583 : : }
8584 : : else
7571 tgl@sss.pgh.pa.us 8585 :UBC 0 : ruleinfo[i].separate = true;
8586 : : }
8587 : :
7945 tgl@sss.pgh.pa.us 8588 :CBC 185 : PQclear(res);
8589 : :
8590 : 185 : destroyPQExpBuffer(query);
8591 : 185 : }
8592 : :
8593 : : /*
8594 : : * getTriggers
8595 : : * get information about every trigger on a dumpable table
8596 : : *
8597 : : * Note: trigger data is not returned directly to the caller, but it
8598 : : * does get entered into the DumpableObject tables.
8599 : : */
8600 : : void
4961 rhaas@postgresql.org 8601 : 185 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
8602 : : {
7945 tgl@sss.pgh.pa.us 8603 : 185 : PQExpBuffer query = createPQExpBuffer();
1370 8604 : 185 : PQExpBuffer tbloids = createPQExpBuffer();
8605 : : PGresult *res;
8606 : : int ntups;
8607 : : int curtblindx;
8608 : : TriggerInfo *tginfo;
8609 : : int i_tableoid,
8610 : : i_oid,
8611 : : i_tgrelid,
8612 : : i_tgname,
8613 : : i_tgenabled,
8614 : : i_tgispartition,
8615 : : i_tgdef;
8616 : :
8617 : : /*
8618 : : * We want to perform just one query against pg_trigger. However, we
8619 : : * mustn't try to select every row of the catalog and then sort it out on
8620 : : * the client side, because some of the server-side functions we need
8621 : : * would be unsafe to apply to tables we don't have lock on. Hence, we
8622 : : * build an array of the OIDs of tables we care about (and now have lock
8623 : : * on!), and use a WHERE clause to constrain which rows are selected.
8624 : : */
8625 : 185 : appendPQExpBufferChar(tbloids, '{');
8626 [ + + ]: 49228 : for (int i = 0; i < numTables; i++)
8627 : : {
7945 8628 : 49043 : TableInfo *tbinfo = &tblinfo[i];
8629 : :
3440 sfrost@snowman.net 8630 [ + + ]: 49043 : if (!tbinfo->hastriggers ||
8631 [ + + ]: 1168 : !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7945 tgl@sss.pgh.pa.us 8632 : 48137 : continue;
8633 : :
8634 : : /* OK, we need info for this table */
1370 8635 [ + + ]: 906 : if (tbloids->len > 1) /* do we have more than the '{'? */
8636 : 849 : appendPQExpBufferChar(tbloids, ',');
8637 : 906 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8638 : : }
8639 : 185 : appendPQExpBufferChar(tbloids, '}');
8640 : :
1340 alvherre@alvh.no-ip. 8641 [ + - ]: 185 : if (fout->remoteVersion >= 150000)
8642 : : {
8643 : : /*
8644 : : * NB: think not to use pretty=true in pg_get_triggerdef. It could
8645 : : * result in non-forward-compatible dumps of WHEN clauses due to
8646 : : * under-parenthesization.
8647 : : *
8648 : : * NB: We need to see partition triggers in case the tgenabled flag
8649 : : * has been changed from the parent.
8650 : : */
8651 : 185 : appendPQExpBuffer(query,
8652 : : "SELECT t.tgrelid, t.tgname, "
8653 : : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8654 : : "t.tgenabled, t.tableoid, t.oid, "
8655 : : "t.tgparentid <> 0 AS tgispartition\n"
8656 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8657 : : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8658 : : "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8659 : : "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
8660 : : "OR t.tgenabled != u.tgenabled) "
8661 : : "ORDER BY t.tgrelid, t.tgname",
8662 : : tbloids->data);
8663 : : }
1340 alvherre@alvh.no-ip. 8664 [ # # ]:UBC 0 : else if (fout->remoteVersion >= 130000)
8665 : : {
8666 : : /*
8667 : : * NB: think not to use pretty=true in pg_get_triggerdef. It could
8668 : : * result in non-forward-compatible dumps of WHEN clauses due to
8669 : : * under-parenthesization.
8670 : : *
8671 : : * NB: We need to see tgisinternal triggers in partitions, in case the
8672 : : * tgenabled flag has been changed from the parent.
8673 : : */
1370 tgl@sss.pgh.pa.us 8674 : 0 : appendPQExpBuffer(query,
8675 : : "SELECT t.tgrelid, t.tgname, "
8676 : : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8677 : : "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
8678 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8679 : : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8680 : : "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8681 : : "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
8682 : : "ORDER BY t.tgrelid, t.tgname",
8683 : : tbloids->data);
8684 : : }
8685 [ # # ]: 0 : else if (fout->remoteVersion >= 110000)
8686 : : {
8687 : : /*
8688 : : * NB: We need to see tgisinternal triggers in partitions, in case the
8689 : : * tgenabled flag has been changed from the parent. No tgparentid in
8690 : : * version 11-12, so we have to match them via pg_depend.
8691 : : *
8692 : : * See above about pretty=true in pg_get_triggerdef.
8693 : : */
8694 : 0 : appendPQExpBuffer(query,
8695 : : "SELECT t.tgrelid, t.tgname, "
8696 : : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8697 : : "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
8698 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8699 : : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8700 : : "LEFT JOIN pg_catalog.pg_depend AS d ON "
8701 : : " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8702 : : " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8703 : : " d.objid = t.oid "
8704 : : "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
8705 : : "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
8706 : : "ORDER BY t.tgrelid, t.tgname",
8707 : : tbloids->data);
8708 : : }
8709 : : else
8710 : : {
8711 : : /* See above about pretty=true in pg_get_triggerdef */
8712 : 0 : appendPQExpBuffer(query,
8713 : : "SELECT t.tgrelid, t.tgname, "
8714 : : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8715 : : "t.tgenabled, false as tgispartition, "
8716 : : "t.tableoid, t.oid "
8717 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8718 : : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8719 : : "WHERE NOT tgisinternal "
8720 : : "ORDER BY t.tgrelid, t.tgname",
8721 : : tbloids->data);
8722 : : }
8723 : :
1370 tgl@sss.pgh.pa.us 8724 :CBC 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8725 : :
8726 : 185 : ntups = PQntuples(res);
8727 : :
8728 : 185 : i_tableoid = PQfnumber(res, "tableoid");
8729 : 185 : i_oid = PQfnumber(res, "oid");
8730 : 185 : i_tgrelid = PQfnumber(res, "tgrelid");
8731 : 185 : i_tgname = PQfnumber(res, "tgname");
8732 : 185 : i_tgenabled = PQfnumber(res, "tgenabled");
1340 alvherre@alvh.no-ip. 8733 : 185 : i_tgispartition = PQfnumber(res, "tgispartition");
1370 tgl@sss.pgh.pa.us 8734 : 185 : i_tgdef = PQfnumber(res, "tgdef");
8735 : :
8736 : 185 : tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
8737 : :
8738 : : /*
8739 : : * Outer loop iterates once per table, not once per row. Incrementing of
8740 : : * j is handled by the inner loop.
8741 : : */
8742 : 185 : curtblindx = -1;
8743 [ + + ]: 521 : for (int j = 0; j < ntups;)
8744 : : {
8745 : 336 : Oid tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
8746 : 336 : TableInfo *tbinfo = NULL;
8747 : : int numtrigs;
8748 : :
8749 : : /* Count rows for this table */
8750 [ + + ]: 553 : for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
8751 [ + + ]: 496 : if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
8752 : 279 : break;
8753 : :
8754 : : /*
8755 : : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8756 : : * order.
8757 : : */
8758 [ + - ]: 17616 : while (++curtblindx < numTables)
8759 : : {
8760 : 17616 : tbinfo = &tblinfo[curtblindx];
8761 [ + + ]: 17616 : if (tbinfo->dobj.catId.oid == tgrelid)
8762 : 336 : break;
8763 : : }
8764 [ - + ]: 336 : if (curtblindx >= numTables)
1247 tgl@sss.pgh.pa.us 8765 :UBC 0 : pg_fatal("unrecognized table OID %u", tgrelid);
8766 : :
8767 : : /* Save data for this table */
1370 tgl@sss.pgh.pa.us 8768 :CBC 336 : tbinfo->triggers = tginfo + j;
8769 : 336 : tbinfo->numTriggers = numtrigs;
8770 : :
8771 [ + + ]: 889 : for (int c = 0; c < numtrigs; c++, j++)
8772 : : {
7945 8773 : 553 : tginfo[j].dobj.objType = DO_TRIGGER;
8774 : 553 : tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8775 : 553 : tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8776 : 553 : AssignDumpId(&tginfo[j].dobj);
5034 bruce@momjian.us 8777 : 553 : tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7857 tgl@sss.pgh.pa.us 8778 : 553 : tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7945 8779 : 553 : tginfo[j].tgtable = tbinfo;
6746 JanWieck@Yahoo.com 8780 : 553 : tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
1340 alvherre@alvh.no-ip. 8781 : 553 : tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
601 peter@eisentraut.org 8782 : 553 : tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
8783 : : }
8784 : : }
8785 : :
1370 tgl@sss.pgh.pa.us 8786 : 185 : PQclear(res);
8787 : :
7945 8788 : 185 : destroyPQExpBuffer(query);
1370 8789 : 185 : destroyPQExpBuffer(tbloids);
7945 8790 : 185 : }
8791 : :
8792 : : /*
8793 : : * getEventTriggers
8794 : : * get information about event triggers
8795 : : */
8796 : : void
431 nathan@postgresql.or 8797 : 185 : getEventTriggers(Archive *fout)
8798 : : {
8799 : : int i;
8800 : : PQExpBuffer query;
8801 : : PGresult *res;
8802 : : EventTriggerInfo *evtinfo;
8803 : : int i_tableoid,
8804 : : i_oid,
8805 : : i_evtname,
8806 : : i_evtevent,
8807 : : i_evtowner,
8808 : : i_evttags,
8809 : : i_evtfname,
8810 : : i_evtenabled;
8811 : : int ntups;
8812 : :
8813 : : /* Before 9.3, there are no event triggers */
4798 rhaas@postgresql.org 8814 [ - + ]: 185 : if (fout->remoteVersion < 90300)
431 nathan@postgresql.or 8815 :UBC 0 : return;
8816 : :
4437 sfrost@snowman.net 8817 :CBC 185 : query = createPQExpBuffer();
8818 : :
1096 drowley@postgresql.o 8819 : 185 : appendPQExpBufferStr(query,
8820 : : "SELECT e.tableoid, e.oid, evtname, evtenabled, "
8821 : : "evtevent, evtowner, "
8822 : : "array_to_string(array("
8823 : : "select quote_literal(x) "
8824 : : " from unnest(evttags) as t(x)), ', ') as evttags, "
8825 : : "e.evtfoid::regproc as evtfname "
8826 : : "FROM pg_event_trigger e "
8827 : : "ORDER BY e.oid");
8828 : :
4798 rhaas@postgresql.org 8829 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8830 : :
8831 : 185 : ntups = PQntuples(res);
8832 : :
8833 : 185 : evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
8834 : :
8835 : 185 : i_tableoid = PQfnumber(res, "tableoid");
8836 : 185 : i_oid = PQfnumber(res, "oid");
8837 : 185 : i_evtname = PQfnumber(res, "evtname");
8838 : 185 : i_evtevent = PQfnumber(res, "evtevent");
8839 : 185 : i_evtowner = PQfnumber(res, "evtowner");
8840 : 185 : i_evttags = PQfnumber(res, "evttags");
8841 : 185 : i_evtfname = PQfnumber(res, "evtfname");
8842 : 185 : i_evtenabled = PQfnumber(res, "evtenabled");
8843 : :
8844 [ + + ]: 243 : for (i = 0; i < ntups; i++)
8845 : : {
8846 : 58 : evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
8847 : 58 : evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8848 : 58 : evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8849 : 58 : AssignDumpId(&evtinfo[i].dobj);
8850 : 58 : evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
8851 : 58 : evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
8852 : 58 : evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
1345 tgl@sss.pgh.pa.us 8853 : 58 : evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
4798 rhaas@postgresql.org 8854 : 58 : evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
8855 : 58 : evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
8856 : 58 : evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
8857 : :
8858 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 8859 : 58 : selectDumpableObject(&(evtinfo[i].dobj), fout);
8860 : : }
8861 : :
4798 rhaas@postgresql.org 8862 : 185 : PQclear(res);
8863 : :
8864 : 185 : destroyPQExpBuffer(query);
8865 : : }
8866 : :
8867 : : /*
8868 : : * getProcLangs
8869 : : * get basic information about every procedural language in the system
8870 : : *
8871 : : * NB: this must run after getFuncs() because we assume we can do
8872 : : * findFuncByOid().
8873 : : */
8874 : : void
431 nathan@postgresql.or 8875 : 185 : getProcLangs(Archive *fout)
8876 : : {
8877 : : PGresult *res;
8878 : : int ntups;
8879 : : int i;
7945 tgl@sss.pgh.pa.us 8880 : 185 : PQExpBuffer query = createPQExpBuffer();
8881 : : ProcLangInfo *planginfo;
8882 : : int i_tableoid;
8883 : : int i_oid;
8884 : : int i_lanname;
8885 : : int i_lanpltrusted;
8886 : : int i_lanplcallfoid;
8887 : : int i_laninline;
8888 : : int i_lanvalidator;
8889 : : int i_lanacl;
8890 : : int i_acldefault;
8891 : : int i_lanowner;
8892 : :
1096 drowley@postgresql.o 8893 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8894 : : "lanname, lanpltrusted, lanplcallfoid, "
8895 : : "laninline, lanvalidator, "
8896 : : "lanacl, "
8897 : : "acldefault('l', lanowner) AS acldefault, "
8898 : : "lanowner "
8899 : : "FROM pg_language "
8900 : : "WHERE lanispl "
8901 : : "ORDER BY oid");
8902 : :
4960 rhaas@postgresql.org 8903 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8904 : :
7945 tgl@sss.pgh.pa.us 8905 : 185 : ntups = PQntuples(res);
8906 : :
5034 bruce@momjian.us 8907 : 185 : planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
8908 : :
7945 tgl@sss.pgh.pa.us 8909 : 185 : i_tableoid = PQfnumber(res, "tableoid");
8910 : 185 : i_oid = PQfnumber(res, "oid");
8911 : 185 : i_lanname = PQfnumber(res, "lanname");
8912 : 185 : i_lanpltrusted = PQfnumber(res, "lanpltrusted");
8913 : 185 : i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
5828 8914 : 185 : i_laninline = PQfnumber(res, "laninline");
7217 8915 : 185 : i_lanvalidator = PQfnumber(res, "lanvalidator");
8916 : 185 : i_lanacl = PQfnumber(res, "lanacl");
1370 8917 : 185 : i_acldefault = PQfnumber(res, "acldefault");
7217 8918 : 185 : i_lanowner = PQfnumber(res, "lanowner");
8919 : :
7945 8920 [ + + ]: 421 : for (i = 0; i < ntups; i++)
8921 : : {
8922 : 236 : planginfo[i].dobj.objType = DO_PROCLANG;
8923 : 236 : planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8924 : 236 : planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8925 : 236 : AssignDumpId(&planginfo[i].dobj);
8926 : :
5034 bruce@momjian.us 8927 : 236 : planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
1370 tgl@sss.pgh.pa.us 8928 : 236 : planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
8929 : 236 : planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
8930 : 236 : planginfo[i].dacl.privtype = 0;
8931 : 236 : planginfo[i].dacl.initprivs = NULL;
7945 8932 : 236 : planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
8933 : 236 : planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
3680 8934 : 236 : planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
8935 : 236 : planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
1345 8936 : 236 : planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
8937 : :
8938 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 8939 : 236 : selectDumpableProcLang(&(planginfo[i]), fout);
8940 : :
8941 : : /* Mark whether language has an ACL */
1370 tgl@sss.pgh.pa.us 8942 [ + + ]: 236 : if (!PQgetisnull(res, i, i_lanacl))
8943 : 51 : planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
8944 : : }
8945 : :
7945 8946 : 185 : PQclear(res);
8947 : :
8948 : 185 : destroyPQExpBuffer(query);
8949 : 185 : }
8950 : :
8951 : : /*
8952 : : * getCasts
8953 : : * get basic information about most casts in the system
8954 : : *
8955 : : * Skip casts from a range to its multirange, since we'll create those
8956 : : * automatically.
8957 : : */
8958 : : void
431 nathan@postgresql.or 8959 : 185 : getCasts(Archive *fout)
8960 : : {
8961 : : PGresult *res;
8962 : : int ntups;
8963 : : int i;
7945 tgl@sss.pgh.pa.us 8964 : 185 : PQExpBuffer query = createPQExpBuffer();
8965 : : CastInfo *castinfo;
8966 : : int i_tableoid;
8967 : : int i_oid;
8968 : : int i_castsource;
8969 : : int i_casttarget;
8970 : : int i_castfunc;
8971 : : int i_castcontext;
8972 : : int i_castmethod;
8973 : :
1721 akorotkov@postgresql 8974 [ + - ]: 185 : if (fout->remoteVersion >= 140000)
8975 : : {
8976 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8977 : : "castsource, casttarget, castfunc, castcontext, "
8978 : : "castmethod "
8979 : : "FROM pg_cast c "
8980 : : "WHERE NOT EXISTS ( "
8981 : : "SELECT 1 FROM pg_range r "
8982 : : "WHERE c.castsource = r.rngtypid "
8983 : : "AND c.casttarget = r.rngmultitypid "
8984 : : ") "
8985 : : "ORDER BY 3,4");
8986 : : }
8987 : : else
8988 : : {
4310 heikki.linnakangas@i 8989 :UBC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8990 : : "castsource, casttarget, castfunc, castcontext, "
8991 : : "castmethod "
8992 : : "FROM pg_cast ORDER BY 3,4");
8993 : : }
8994 : :
4960 rhaas@postgresql.org 8995 :CBC 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8996 : :
7945 tgl@sss.pgh.pa.us 8997 : 185 : ntups = PQntuples(res);
8998 : :
5034 bruce@momjian.us 8999 : 185 : castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
9000 : :
7945 tgl@sss.pgh.pa.us 9001 : 185 : i_tableoid = PQfnumber(res, "tableoid");
9002 : 185 : i_oid = PQfnumber(res, "oid");
9003 : 185 : i_castsource = PQfnumber(res, "castsource");
9004 : 185 : i_casttarget = PQfnumber(res, "casttarget");
9005 : 185 : i_castfunc = PQfnumber(res, "castfunc");
9006 : 185 : i_castcontext = PQfnumber(res, "castcontext");
6154 heikki.linnakangas@i 9007 : 185 : i_castmethod = PQfnumber(res, "castmethod");
9008 : :
7945 tgl@sss.pgh.pa.us 9009 [ + + ]: 43938 : for (i = 0; i < ntups; i++)
9010 : : {
9011 : : PQExpBufferData namebuf;
9012 : : TypeInfo *sTypeInfo;
9013 : : TypeInfo *tTypeInfo;
9014 : :
9015 : 43753 : castinfo[i].dobj.objType = DO_CAST;
9016 : 43753 : castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9017 : 43753 : castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9018 : 43753 : AssignDumpId(&castinfo[i].dobj);
9019 : 43753 : castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
9020 : 43753 : castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
9021 : 43753 : castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
9022 : 43753 : castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
6154 heikki.linnakangas@i 9023 : 43753 : castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
9024 : :
9025 : : /*
9026 : : * Try to name cast as concatenation of typnames. This is only used
9027 : : * for purposes of sorting. If we fail to find either type, the name
9028 : : * will be an empty string.
9029 : : */
7857 tgl@sss.pgh.pa.us 9030 : 43753 : initPQExpBuffer(&namebuf);
9031 : 43753 : sTypeInfo = findTypeByOid(castinfo[i].castsource);
9032 : 43753 : tTypeInfo = findTypeByOid(castinfo[i].casttarget);
9033 [ + - + - ]: 43753 : if (sTypeInfo && tTypeInfo)
9034 : 43753 : appendPQExpBuffer(&namebuf, "%s %s",
9035 : : sTypeInfo->dobj.name, tTypeInfo->dobj.name);
9036 : 43753 : castinfo[i].dobj.name = namebuf.data;
9037 : :
9038 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 9039 : 43753 : selectDumpableCast(&(castinfo[i]), fout);
9040 : : }
9041 : :
7945 tgl@sss.pgh.pa.us 9042 : 185 : PQclear(res);
9043 : :
9044 : 185 : destroyPQExpBuffer(query);
9045 : 185 : }
9046 : :
9047 : : static char *
3786 peter_e@gmx.net 9048 : 100 : get_language_name(Archive *fout, Oid langid)
9049 : : {
9050 : : PQExpBuffer query;
9051 : : PGresult *res;
9052 : : char *lanname;
9053 : :
9054 : 100 : query = createPQExpBuffer();
9055 : 100 : appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
9056 : 100 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
9057 : 100 : lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
9058 : 100 : destroyPQExpBuffer(query);
9059 : 100 : PQclear(res);
9060 : :
9061 : 100 : return lanname;
9062 : : }
9063 : :
9064 : : /*
9065 : : * getTransforms
9066 : : * get basic information about every transform in the system
9067 : : */
9068 : : void
431 nathan@postgresql.or 9069 : 185 : getTransforms(Archive *fout)
9070 : : {
9071 : : PGresult *res;
9072 : : int ntups;
9073 : : int i;
9074 : : PQExpBuffer query;
9075 : : TransformInfo *transforminfo;
9076 : : int i_tableoid;
9077 : : int i_oid;
9078 : : int i_trftype;
9079 : : int i_trflang;
9080 : : int i_trffromsql;
9081 : : int i_trftosql;
9082 : :
9083 : : /* Transforms didn't exist pre-9.5 */
3786 peter_e@gmx.net 9084 [ - + ]: 185 : if (fout->remoteVersion < 90500)
431 nathan@postgresql.or 9085 :UBC 0 : return;
9086 : :
3775 magnus@hagander.net 9087 :CBC 185 : query = createPQExpBuffer();
9088 : :
2256 drowley@postgresql.o 9089 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9090 : : "trftype, trflang, trffromsql::oid, trftosql::oid "
9091 : : "FROM pg_transform "
9092 : : "ORDER BY 3,4");
9093 : :
3786 peter_e@gmx.net 9094 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9095 : :
9096 : 185 : ntups = PQntuples(res);
9097 : :
9098 : 185 : transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
9099 : :
9100 : 185 : i_tableoid = PQfnumber(res, "tableoid");
9101 : 185 : i_oid = PQfnumber(res, "oid");
9102 : 185 : i_trftype = PQfnumber(res, "trftype");
9103 : 185 : i_trflang = PQfnumber(res, "trflang");
9104 : 185 : i_trffromsql = PQfnumber(res, "trffromsql");
9105 : 185 : i_trftosql = PQfnumber(res, "trftosql");
9106 : :
9107 [ + + ]: 243 : for (i = 0; i < ntups; i++)
9108 : : {
9109 : : PQExpBufferData namebuf;
9110 : : TypeInfo *typeInfo;
9111 : : char *lanname;
9112 : :
9113 : 58 : transforminfo[i].dobj.objType = DO_TRANSFORM;
9114 : 58 : transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9115 : 58 : transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9116 : 58 : AssignDumpId(&transforminfo[i].dobj);
9117 : 58 : transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
9118 : 58 : transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
9119 : 58 : transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
9120 : 58 : transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
9121 : :
9122 : : /*
9123 : : * Try to name transform as concatenation of type and language name.
9124 : : * This is only used for purposes of sorting. If we fail to find
9125 : : * either, the name will be an empty string.
9126 : : */
9127 : 58 : initPQExpBuffer(&namebuf);
9128 : 58 : typeInfo = findTypeByOid(transforminfo[i].trftype);
9129 : 58 : lanname = get_language_name(fout, transforminfo[i].trflang);
9130 [ + - + - ]: 58 : if (typeInfo && lanname)
9131 : 58 : appendPQExpBuffer(&namebuf, "%s %s",
9132 : : typeInfo->dobj.name, lanname);
9133 : 58 : transforminfo[i].dobj.name = namebuf.data;
3709 tgl@sss.pgh.pa.us 9134 : 58 : free(lanname);
9135 : :
9136 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 9137 : 58 : selectDumpableObject(&(transforminfo[i].dobj), fout);
9138 : : }
9139 : :
3786 peter_e@gmx.net 9140 : 185 : PQclear(res);
9141 : :
9142 : 185 : destroyPQExpBuffer(query);
9143 : : }
9144 : :
9145 : : /*
9146 : : * getTableAttrs -
9147 : : * for each interesting table, read info about its attributes
9148 : : * (names, types, default values, CHECK constraints, etc)
9149 : : *
9150 : : * modifies tblinfo
9151 : : */
9152 : : void
3524 tgl@sss.pgh.pa.us 9153 : 185 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
9154 : : {
9155 : 185 : DumpOptions *dopt = fout->dopt;
7945 9156 : 185 : PQExpBuffer q = createPQExpBuffer();
1370 9157 : 185 : PQExpBuffer tbloids = createPQExpBuffer();
9158 : 185 : PQExpBuffer checkoids = createPQExpBuffer();
152 alvherre@alvh.no-ip. 9159 : 185 : PQExpBuffer invalidnotnulloids = NULL;
9160 : : PGresult *res;
9161 : : int ntups;
9162 : : int curtblindx;
9163 : : int i_attrelid;
9164 : : int i_attnum;
9165 : : int i_attname;
9166 : : int i_atttypname;
9167 : : int i_attstattarget;
9168 : : int i_attstorage;
9169 : : int i_typstorage;
9170 : : int i_attidentity;
9171 : : int i_attgenerated;
9172 : : int i_attisdropped;
9173 : : int i_attlen;
9174 : : int i_attalign;
9175 : : int i_attislocal;
9176 : : int i_notnull_name;
9177 : : int i_notnull_comment;
9178 : : int i_notnull_noinherit;
9179 : : int i_notnull_islocal;
9180 : : int i_notnull_invalidoid;
9181 : : int i_attoptions;
9182 : : int i_attcollation;
9183 : : int i_attcompression;
9184 : : int i_attfdwoptions;
9185 : : int i_attmissingval;
9186 : : int i_atthasdef;
9187 : :
9188 : : /*
9189 : : * We want to perform just one query against pg_attribute, and then just
9190 : : * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
9191 : : * (for CHECK constraints and for NOT NULL constraints). However, we
9192 : : * mustn't try to select every row of those catalogs and then sort it out
9193 : : * on the client side, because some of the server-side functions we need
9194 : : * would be unsafe to apply to tables we don't have lock on. Hence, we
9195 : : * build an array of the OIDs of tables we care about (and now have lock
9196 : : * on!), and use a WHERE clause to constrain which rows are selected.
9197 : : */
1370 tgl@sss.pgh.pa.us 9198 : 185 : appendPQExpBufferChar(tbloids, '{');
9199 : 185 : appendPQExpBufferChar(checkoids, '{');
1885 peter@eisentraut.org 9200 [ + + ]: 49228 : for (int i = 0; i < numTables; i++)
9201 : : {
8403 bruce@momjian.us 9202 : 49043 : TableInfo *tbinfo = &tblinfo[i];
9203 : :
9204 : : /* Don't bother to collect info for sequences */
8419 tgl@sss.pgh.pa.us 9205 [ + + ]: 49043 : if (tbinfo->relkind == RELKIND_SEQUENCE)
10226 bruce@momjian.us 9206 : 656 : continue;
9207 : :
9208 : : /*
9209 : : * Don't bother with uninteresting tables, either. For binary
9210 : : * upgrades, this is bypassed for pg_largeobject_metadata and
9211 : : * pg_shdepend so that the columns names are collected for the
9212 : : * corresponding COPY commands. Restoring the data for those catalogs
9213 : : * is faster than restoring the equivalent set of large object
9214 : : * commands. We can only do this for upgrades from v12 and newer; in
9215 : : * older versions, pg_largeobject_metadata was created WITH OIDS, so
9216 : : * the OID column is hidden and won't be dumped.
9217 : : */
50 nathan@postgresql.or 9218 [ + + ]:GNC 48387 : if (!tbinfo->interesting &&
9219 [ + + + - ]: 41420 : !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
9220 [ + + ]: 7722 : (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
9221 [ + + ]: 7686 : tbinfo->dobj.catId.oid == SharedDependRelationId)))
8520 tgl@sss.pgh.pa.us 9222 :CBC 41348 : continue;
9223 : :
9224 : : /* OK, we need info for this table */
1370 9225 [ + + ]: 7039 : if (tbloids->len > 1) /* do we have more than the '{'? */
9226 : 6898 : appendPQExpBufferChar(tbloids, ',');
9227 : 7039 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
9228 : :
9229 [ + + ]: 7039 : if (tbinfo->ncheck > 0)
9230 : : {
9231 : : /* Also make a list of the ones with check constraints */
9232 [ + + ]: 586 : if (checkoids->len > 1) /* do we have more than the '{'? */
9233 : 511 : appendPQExpBufferChar(checkoids, ',');
9234 : 586 : appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
9235 : : }
9236 : : }
9237 : 185 : appendPQExpBufferChar(tbloids, '}');
9238 : 185 : appendPQExpBufferChar(checkoids, '}');
9239 : :
9240 : : /*
9241 : : * Find all the user attributes and their types.
9242 : : *
9243 : : * Since we only want to dump COLLATE clauses for attributes whose
9244 : : * collation is different from their type's default, we use a CASE here to
9245 : : * suppress uninteresting attcollations cheaply.
9246 : : */
9247 : 185 : appendPQExpBufferStr(q,
9248 : : "SELECT\n"
9249 : : "a.attrelid,\n"
9250 : : "a.attnum,\n"
9251 : : "a.attname,\n"
9252 : : "a.attstattarget,\n"
9253 : : "a.attstorage,\n"
9254 : : "t.typstorage,\n"
9255 : : "a.atthasdef,\n"
9256 : : "a.attisdropped,\n"
9257 : : "a.attlen,\n"
9258 : : "a.attalign,\n"
9259 : : "a.attislocal,\n"
9260 : : "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
9261 : : "array_to_string(a.attoptions, ', ') AS attoptions,\n"
9262 : : "CASE WHEN a.attcollation <> t.typcollation "
9263 : : "THEN a.attcollation ELSE 0 END AS attcollation,\n"
9264 : : "pg_catalog.array_to_string(ARRAY("
9265 : : "SELECT pg_catalog.quote_ident(option_name) || "
9266 : : "' ' || pg_catalog.quote_literal(option_value) "
9267 : : "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
9268 : : "ORDER BY option_name"
9269 : : "), E',\n ') AS attfdwoptions,\n");
9270 : :
9271 : : /*
9272 : : * Find out any NOT NULL markings for each column. In 18 and up we read
9273 : : * pg_constraint to obtain the constraint name, and for valid constraints
9274 : : * also pg_description to obtain its comment. notnull_noinherit is set
9275 : : * according to the NO INHERIT property. For versions prior to 18, we
9276 : : * store an empty string as the name when a constraint is marked as
9277 : : * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
9278 : : * without a name); also, such cases are never NO INHERIT.
9279 : : *
9280 : : * For invalid constraints, we need to store their OIDs for processing
9281 : : * elsewhere, so we bring the pg_constraint.oid value when the constraint
9282 : : * is invalid, and NULL otherwise. Their comments are handled not here
9283 : : * but by collectComments, because they're their own dumpable object.
9284 : : *
9285 : : * We track in notnull_islocal whether the constraint was defined directly
9286 : : * in this table or via an ancestor, for binary upgrade. flagInhAttrs
9287 : : * might modify this later; that routine is also in charge of determining
9288 : : * the correct inhcount.
9289 : : */
302 alvherre@alvh.no-ip. 9290 [ + - ]: 185 : if (fout->remoteVersion >= 180000)
9291 : 185 : appendPQExpBufferStr(q,
9292 : : "co.conname AS notnull_name,\n"
9293 : : "CASE WHEN co.convalidated THEN pt.description"
9294 : : " ELSE NULL END AS notnull_comment,\n"
9295 : : "CASE WHEN NOT co.convalidated THEN co.oid "
9296 : : "ELSE NULL END AS notnull_invalidoid,\n"
9297 : : "co.connoinherit AS notnull_noinherit,\n"
9298 : : "co.conislocal AS notnull_islocal,\n");
9299 : : else
302 alvherre@alvh.no-ip. 9300 :UBC 0 : appendPQExpBufferStr(q,
9301 : : "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
9302 : : "NULL AS notnull_comment,\n"
9303 : : "NULL AS notnull_invalidoid,\n"
9304 : : "false AS notnull_noinherit,\n"
9305 : : "a.attislocal AS notnull_islocal,\n");
9306 : :
1370 tgl@sss.pgh.pa.us 9307 [ + - ]:CBC 185 : if (fout->remoteVersion >= 140000)
9308 : 185 : appendPQExpBufferStr(q,
9309 : : "a.attcompression AS attcompression,\n");
9310 : : else
1370 tgl@sss.pgh.pa.us 9311 :UBC 0 : appendPQExpBufferStr(q,
9312 : : "'' AS attcompression,\n");
9313 : :
1370 tgl@sss.pgh.pa.us 9314 [ + - ]:CBC 185 : if (fout->remoteVersion >= 100000)
9315 : 185 : appendPQExpBufferStr(q,
9316 : : "a.attidentity,\n");
9317 : : else
1370 tgl@sss.pgh.pa.us 9318 :UBC 0 : appendPQExpBufferStr(q,
9319 : : "'' AS attidentity,\n");
9320 : :
1370 tgl@sss.pgh.pa.us 9321 [ + - ]:CBC 185 : if (fout->remoteVersion >= 110000)
9322 : 185 : appendPQExpBufferStr(q,
9323 : : "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
9324 : : "THEN a.attmissingval ELSE null END AS attmissingval,\n");
9325 : : else
1370 tgl@sss.pgh.pa.us 9326 :UBC 0 : appendPQExpBufferStr(q,
9327 : : "NULL AS attmissingval,\n");
9328 : :
1370 tgl@sss.pgh.pa.us 9329 [ + - ]:CBC 185 : if (fout->remoteVersion >= 120000)
9330 : 185 : appendPQExpBufferStr(q,
9331 : : "a.attgenerated\n");
9332 : : else
1370 tgl@sss.pgh.pa.us 9333 :UBC 0 : appendPQExpBufferStr(q,
9334 : : "'' AS attgenerated\n");
9335 : :
9336 : : /* need left join to pg_type to not fail on dropped columns ... */
1370 tgl@sss.pgh.pa.us 9337 :CBC 185 : appendPQExpBuffer(q,
9338 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9339 : : "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
9340 : : "LEFT JOIN pg_catalog.pg_type t "
9341 : : "ON (a.atttypid = t.oid)\n",
9342 : : tbloids->data);
9343 : :
9344 : : /*
9345 : : * In versions 18 and up, we need pg_constraint for explicit NOT NULL
9346 : : * entries and pg_description to get their comments.
9347 : : */
302 alvherre@alvh.no-ip. 9348 [ + - ]: 185 : if (fout->remoteVersion >= 180000)
9349 : 185 : appendPQExpBufferStr(q,
9350 : : " LEFT JOIN pg_catalog.pg_constraint co ON "
9351 : : "(a.attrelid = co.conrelid\n"
9352 : : " AND co.contype = 'n' AND "
9353 : : "co.conkey = array[a.attnum])\n"
9354 : : " LEFT JOIN pg_catalog.pg_description pt ON "
9355 : : "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
9356 : :
9357 : 185 : appendPQExpBufferStr(q,
9358 : : "WHERE a.attnum > 0::pg_catalog.int2\n"
9359 : : "ORDER BY a.attrelid, a.attnum");
9360 : :
1370 tgl@sss.pgh.pa.us 9361 : 185 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9362 : :
9363 : 185 : ntups = PQntuples(res);
9364 : :
9365 : 185 : i_attrelid = PQfnumber(res, "attrelid");
9366 : 185 : i_attnum = PQfnumber(res, "attnum");
9367 : 185 : i_attname = PQfnumber(res, "attname");
9368 : 185 : i_atttypname = PQfnumber(res, "atttypname");
9369 : 185 : i_attstattarget = PQfnumber(res, "attstattarget");
9370 : 185 : i_attstorage = PQfnumber(res, "attstorage");
9371 : 185 : i_typstorage = PQfnumber(res, "typstorage");
9372 : 185 : i_attidentity = PQfnumber(res, "attidentity");
9373 : 185 : i_attgenerated = PQfnumber(res, "attgenerated");
9374 : 185 : i_attisdropped = PQfnumber(res, "attisdropped");
9375 : 185 : i_attlen = PQfnumber(res, "attlen");
9376 : 185 : i_attalign = PQfnumber(res, "attalign");
9377 : 185 : i_attislocal = PQfnumber(res, "attislocal");
302 alvherre@alvh.no-ip. 9378 : 185 : i_notnull_name = PQfnumber(res, "notnull_name");
72 alvherre@kurilemu.de 9379 : 185 : i_notnull_comment = PQfnumber(res, "notnull_comment");
152 alvherre@alvh.no-ip. 9380 : 185 : i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
302 9381 : 185 : i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
9382 : 185 : i_notnull_islocal = PQfnumber(res, "notnull_islocal");
1370 tgl@sss.pgh.pa.us 9383 : 185 : i_attoptions = PQfnumber(res, "attoptions");
9384 : 185 : i_attcollation = PQfnumber(res, "attcollation");
9385 : 185 : i_attcompression = PQfnumber(res, "attcompression");
9386 : 185 : i_attfdwoptions = PQfnumber(res, "attfdwoptions");
9387 : 185 : i_attmissingval = PQfnumber(res, "attmissingval");
9388 : 185 : i_atthasdef = PQfnumber(res, "atthasdef");
9389 : :
9390 : : /* Within the next loop, we'll accumulate OIDs of tables with defaults */
878 alvherre@alvh.no-ip. 9391 : 185 : resetPQExpBuffer(tbloids);
9392 : 185 : appendPQExpBufferChar(tbloids, '{');
9393 : :
9394 : : /*
9395 : : * Outer loop iterates once per table, not once per row. Incrementing of
9396 : : * r is handled by the inner loop.
9397 : : */
1370 tgl@sss.pgh.pa.us 9398 : 185 : curtblindx = -1;
9399 [ + + ]: 7068 : for (int r = 0; r < ntups;)
9400 : : {
9401 : 6883 : Oid attrelid = atooid(PQgetvalue(res, r, i_attrelid));
9402 : 6883 : TableInfo *tbinfo = NULL;
9403 : : int numatts;
9404 : : bool hasdefaults;
9405 : :
9406 : : /* Count rows for this table */
9407 [ + + ]: 25248 : for (numatts = 1; numatts < ntups - r; numatts++)
9408 [ + + ]: 25110 : if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
9409 : 6745 : break;
9410 : :
9411 : : /*
9412 : : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
9413 : : * order.
9414 : : */
9415 [ + - ]: 33963 : while (++curtblindx < numTables)
9416 : : {
9417 : 33963 : tbinfo = &tblinfo[curtblindx];
9418 [ + + ]: 33963 : if (tbinfo->dobj.catId.oid == attrelid)
9419 : 6883 : break;
9420 : : }
9421 [ - + ]: 6883 : if (curtblindx >= numTables)
1247 tgl@sss.pgh.pa.us 9422 :UBC 0 : pg_fatal("unrecognized table OID %u", attrelid);
9423 : : /* cross-check that we only got requested tables */
1370 tgl@sss.pgh.pa.us 9424 [ + - ]:CBC 6883 : if (tbinfo->relkind == RELKIND_SEQUENCE ||
50 nathan@postgresql.or 9425 [ + + ]:GNC 6883 : (!tbinfo->interesting &&
9426 [ + - + - ]: 72 : !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
9427 [ + + ]: 72 : (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
9428 [ - + ]: 36 : tbinfo->dobj.catId.oid == SharedDependRelationId))))
1247 tgl@sss.pgh.pa.us 9429 :UBC 0 : pg_fatal("unexpected column data for table \"%s\"",
9430 : : tbinfo->dobj.name);
9431 : :
9432 : : /* Save data for this table */
1370 tgl@sss.pgh.pa.us 9433 :CBC 6883 : tbinfo->numatts = numatts;
9434 : 6883 : tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
9435 : 6883 : tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
9436 : 6883 : tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
9437 : 6883 : tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
9438 : 6883 : tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
9439 : 6883 : tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
9440 : 6883 : tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
9441 : 6883 : tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
9442 : 6883 : tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
9443 : 6883 : tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
9444 : 6883 : tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
9445 : 6883 : tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
9446 : 6883 : tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
9447 : 6883 : tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
9448 : 6883 : tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
9449 : 6883 : tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
302 alvherre@alvh.no-ip. 9450 : 6883 : tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
72 alvherre@kurilemu.de 9451 : 6883 : tbinfo->notnull_comment = (char **) pg_malloc(numatts * sizeof(char *));
131 9452 : 6883 : tbinfo->notnull_invalid = (bool *) pg_malloc(numatts * sizeof(bool));
302 alvherre@alvh.no-ip. 9453 : 6883 : tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
9454 : 6883 : tbinfo->notnull_islocal = (bool *) pg_malloc(numatts * sizeof(bool));
1370 tgl@sss.pgh.pa.us 9455 : 6883 : tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
8520 9456 : 6883 : hasdefaults = false;
9457 : :
1370 9458 [ + + ]: 32131 : for (int j = 0; j < numatts; j++, r++)
9459 : : {
9460 [ - + ]: 25248 : if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
1247 tgl@sss.pgh.pa.us 9461 :UBC 0 : pg_fatal("invalid column numbering in table \"%s\"",
9462 : : tbinfo->dobj.name);
1370 tgl@sss.pgh.pa.us 9463 :CBC 25248 : tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
9464 : 25248 : tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
602 peter@eisentraut.org 9465 [ + + ]: 25248 : if (PQgetisnull(res, r, i_attstattarget))
9466 : 25202 : tbinfo->attstattarget[j] = -1;
9467 : : else
9468 : 46 : tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
1370 tgl@sss.pgh.pa.us 9469 : 25248 : tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
9470 : 25248 : tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
9471 : 25248 : tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
9472 : 25248 : tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
3075 peter_e@gmx.net 9473 [ + + + + ]: 25248 : tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
1370 tgl@sss.pgh.pa.us 9474 : 25248 : tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
9475 : 25248 : tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
9476 : 25248 : tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
9477 : 25248 : tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
9478 : :
9479 : : /* Handle not-null constraint name and flags */
302 alvherre@alvh.no-ip. 9480 : 25248 : determineNotNullFlags(fout, res, r,
9481 : : tbinfo, j,
9482 : : i_notnull_name,
9483 : : i_notnull_comment,
9484 : : i_notnull_invalidoid,
9485 : : i_notnull_noinherit,
9486 : : i_notnull_islocal,
9487 : : &invalidnotnulloids);
9488 : :
72 alvherre@kurilemu.de 9489 : 25248 : tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
9490 [ + + ]: 25248 : NULL : pg_strdup(PQgetvalue(res, r, i_notnull_comment));
1370 tgl@sss.pgh.pa.us 9491 : 25248 : tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
9492 : 25248 : tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
9493 : 25248 : tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
9494 : 25248 : tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
9495 : 25248 : tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
7678 bruce@momjian.us 9496 : 25248 : tbinfo->attrdefs[j] = NULL; /* fix below */
1370 tgl@sss.pgh.pa.us 9497 [ + + ]: 25248 : if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
8520 9498 : 1364 : hasdefaults = true;
9499 : : }
9500 : :
1370 9501 [ + + ]: 6883 : if (hasdefaults)
9502 : : {
9503 : : /* Collect OIDs of interesting tables that have defaults */
878 alvherre@alvh.no-ip. 9504 [ + + ]: 1018 : if (tbloids->len > 1) /* do we have more than the '{'? */
9505 : 944 : appendPQExpBufferChar(tbloids, ',');
9506 : 1018 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
9507 : : }
9508 : : }
9509 : :
9510 : : /* If invalidnotnulloids has any data, finalize it */
152 9511 [ + + ]: 185 : if (invalidnotnulloids != NULL)
9512 : 49 : appendPQExpBufferChar(invalidnotnulloids, '}');
9513 : :
1370 tgl@sss.pgh.pa.us 9514 : 185 : PQclear(res);
9515 : :
9516 : : /*
9517 : : * Now get info about column defaults. This is skipped for a data-only
9518 : : * dump, as it is only needed for table schemas.
9519 : : */
285 nathan@postgresql.or 9520 [ + + + + ]: 185 : if (dopt->dumpSchema && tbloids->len > 1)
9521 : : {
9522 : : AttrDefInfo *attrdefs;
9523 : : int numDefaults;
1370 tgl@sss.pgh.pa.us 9524 : 66 : TableInfo *tbinfo = NULL;
9525 : :
9526 : 66 : pg_log_info("finding table default expressions");
9527 : :
878 alvherre@alvh.no-ip. 9528 : 66 : appendPQExpBufferChar(tbloids, '}');
9529 : :
1370 tgl@sss.pgh.pa.us 9530 : 66 : printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
9531 : : "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
9532 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9533 : : "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
9534 : : "ORDER BY a.adrelid, a.adnum",
9535 : : tbloids->data);
9536 : :
9537 : 66 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9538 : :
9539 : 66 : numDefaults = PQntuples(res);
9540 : 66 : attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
9541 : :
9542 : 66 : curtblindx = -1;
9543 [ + + ]: 1332 : for (int j = 0; j < numDefaults; j++)
9544 : : {
9545 : 1266 : Oid adtableoid = atooid(PQgetvalue(res, j, 0));
9546 : 1266 : Oid adoid = atooid(PQgetvalue(res, j, 1));
9547 : 1266 : Oid adrelid = atooid(PQgetvalue(res, j, 2));
9548 : 1266 : int adnum = atoi(PQgetvalue(res, j, 3));
9549 : 1266 : char *adsrc = PQgetvalue(res, j, 4);
9550 : :
9551 : : /*
9552 : : * Locate the associated TableInfo; we rely on tblinfo[] being in
9553 : : * OID order.
9554 : : */
9555 [ + + + + ]: 1266 : if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
9556 : : {
9557 [ + - ]: 20267 : while (++curtblindx < numTables)
9558 : : {
9559 : 20267 : tbinfo = &tblinfo[curtblindx];
9560 [ + + ]: 20267 : if (tbinfo->dobj.catId.oid == adrelid)
9561 : 950 : break;
9562 : : }
9563 [ - + ]: 950 : if (curtblindx >= numTables)
1247 tgl@sss.pgh.pa.us 9564 :UBC 0 : pg_fatal("unrecognized table OID %u", adrelid);
9565 : : }
9566 : :
1370 tgl@sss.pgh.pa.us 9567 [ + - - + ]:CBC 1266 : if (adnum <= 0 || adnum > tbinfo->numatts)
1247 tgl@sss.pgh.pa.us 9568 :UBC 0 : pg_fatal("invalid adnum value %d for table \"%s\"",
9569 : : adnum, tbinfo->dobj.name);
9570 : :
9571 : : /*
9572 : : * dropped columns shouldn't have defaults, but just in case,
9573 : : * ignore 'em
9574 : : */
1370 tgl@sss.pgh.pa.us 9575 [ - + ]:CBC 1266 : if (tbinfo->attisdropped[adnum - 1])
1370 tgl@sss.pgh.pa.us 9576 :UBC 0 : continue;
9577 : :
1370 tgl@sss.pgh.pa.us 9578 :CBC 1266 : attrdefs[j].dobj.objType = DO_ATTRDEF;
9579 : 1266 : attrdefs[j].dobj.catId.tableoid = adtableoid;
9580 : 1266 : attrdefs[j].dobj.catId.oid = adoid;
9581 : 1266 : AssignDumpId(&attrdefs[j].dobj);
9582 : 1266 : attrdefs[j].adtable = tbinfo;
9583 : 1266 : attrdefs[j].adnum = adnum;
9584 : 1266 : attrdefs[j].adef_expr = pg_strdup(adsrc);
9585 : :
9586 : 1266 : attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
9587 : 1266 : attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
9588 : :
9589 : 1266 : attrdefs[j].dobj.dump = tbinfo->dobj.dump;
9590 : :
9591 : : /*
9592 : : * Figure out whether the default/generation expression should be
9593 : : * dumped as part of the main CREATE TABLE (or similar) command or
9594 : : * as a separate ALTER TABLE (or similar) command. The preference
9595 : : * is to put it into the CREATE command, but in some cases that's
9596 : : * not possible.
9597 : : */
9598 [ + + ]: 1266 : if (tbinfo->attgenerated[adnum - 1])
9599 : : {
9600 : : /*
9601 : : * Column generation expressions cannot be dumped separately,
9602 : : * because there is no syntax for it. By setting separate to
9603 : : * false here we prevent the "default" from being processed as
9604 : : * its own dumpable object. Later, flagInhAttrs() will mark
9605 : : * it as not to be dumped at all, if possible (that is, if it
9606 : : * can be inherited from a parent).
9607 : : */
9608 : 704 : attrdefs[j].separate = false;
9609 : : }
9610 [ + + ]: 562 : else if (tbinfo->relkind == RELKIND_VIEW)
9611 : : {
9612 : : /*
9613 : : * Defaults on a VIEW must always be dumped as separate ALTER
9614 : : * TABLE commands.
9615 : : */
9616 : 38 : attrdefs[j].separate = true;
9617 : : }
9618 [ + + ]: 524 : else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
9619 : : {
9620 : : /* column will be suppressed, print default separately */
9621 : 4 : attrdefs[j].separate = true;
9622 : : }
9623 : : else
9624 : : {
9625 : 520 : attrdefs[j].separate = false;
9626 : : }
9627 : :
9628 [ + + ]: 1266 : if (!attrdefs[j].separate)
9629 : : {
9630 : : /*
9631 : : * Mark the default as needing to appear before the table, so
9632 : : * that any dependencies it has must be emitted before the
9633 : : * CREATE TABLE. If this is not possible, we'll change to
9634 : : * "separate" mode while sorting dependencies.
9635 : : */
9636 : 1224 : addObjectDependency(&tbinfo->dobj,
9637 : 1224 : attrdefs[j].dobj.dumpId);
9638 : : }
9639 : :
9640 : 1266 : tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
9641 : : }
9642 : :
9643 : 66 : PQclear(res);
9644 : : }
9645 : :
9646 : : /*
9647 : : * Get info about NOT NULL NOT VALID constraints. This is skipped for a
9648 : : * data-only dump, as it is only needed for table schemas.
9649 : : */
152 alvherre@alvh.no-ip. 9650 [ + + + + ]: 185 : if (dopt->dumpSchema && invalidnotnulloids)
9651 : : {
9652 : : ConstraintInfo *constrs;
9653 : : int numConstrs;
9654 : : int i_tableoid;
9655 : : int i_oid;
9656 : : int i_conrelid;
9657 : : int i_conname;
9658 : : int i_consrc;
9659 : : int i_conislocal;
9660 : :
82 peter@eisentraut.org 9661 : 43 : pg_log_info("finding invalid not-null constraints");
9662 : :
152 alvherre@alvh.no-ip. 9663 : 43 : resetPQExpBuffer(q);
9664 : 43 : appendPQExpBuffer(q,
9665 : : "SELECT c.tableoid, c.oid, conrelid, conname, "
9666 : : "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9667 : : "conislocal, convalidated "
9668 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(conoid)\n"
9669 : : "JOIN pg_catalog.pg_constraint c ON (src.conoid = c.oid)\n"
9670 : : "ORDER BY c.conrelid, c.conname",
9671 : 43 : invalidnotnulloids->data);
9672 : :
9673 : 43 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9674 : :
9675 : 43 : numConstrs = PQntuples(res);
9676 : 43 : constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
9677 : :
9678 : 43 : i_tableoid = PQfnumber(res, "tableoid");
9679 : 43 : i_oid = PQfnumber(res, "oid");
9680 : 43 : i_conrelid = PQfnumber(res, "conrelid");
9681 : 43 : i_conname = PQfnumber(res, "conname");
9682 : 43 : i_consrc = PQfnumber(res, "consrc");
9683 : 43 : i_conislocal = PQfnumber(res, "conislocal");
9684 : :
9685 : : /* As above, this loop iterates once per table, not once per row */
9686 : 43 : curtblindx = -1;
9687 [ + + ]: 116 : for (int j = 0; j < numConstrs;)
9688 : : {
9689 : 73 : Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9690 : 73 : TableInfo *tbinfo = NULL;
9691 : : int numcons;
9692 : :
9693 : : /* Count rows for this table */
9694 [ + + ]: 73 : for (numcons = 1; numcons < numConstrs - j; numcons++)
9695 [ + - ]: 30 : if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9696 : 30 : break;
9697 : :
9698 : : /*
9699 : : * Locate the associated TableInfo; we rely on tblinfo[] being in
9700 : : * OID order.
9701 : : */
9702 [ + - ]: 14202 : while (++curtblindx < numTables)
9703 : : {
9704 : 14202 : tbinfo = &tblinfo[curtblindx];
9705 [ + + ]: 14202 : if (tbinfo->dobj.catId.oid == conrelid)
9706 : 73 : break;
9707 : : }
9708 [ - + ]: 73 : if (curtblindx >= numTables)
152 alvherre@alvh.no-ip. 9709 :UBC 0 : pg_fatal("unrecognized table OID %u", conrelid);
9710 : :
152 alvherre@alvh.no-ip. 9711 [ + + ]:CBC 146 : for (int c = 0; c < numcons; c++, j++)
9712 : : {
9713 : 73 : constrs[j].dobj.objType = DO_CONSTRAINT;
9714 : 73 : constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9715 : 73 : constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
9716 : 73 : AssignDumpId(&constrs[j].dobj);
9717 : 73 : constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
9718 : 73 : constrs[j].dobj.namespace = tbinfo->dobj.namespace;
9719 : 73 : constrs[j].contable = tbinfo;
9720 : 73 : constrs[j].condomain = NULL;
9721 : 73 : constrs[j].contype = 'n';
9722 : 73 : constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
9723 : 73 : constrs[j].confrelid = InvalidOid;
9724 : 73 : constrs[j].conindex = 0;
9725 : 73 : constrs[j].condeferrable = false;
9726 : 73 : constrs[j].condeferred = false;
9727 : 73 : constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9728 : :
9729 : : /*
9730 : : * All invalid not-null constraints must be dumped separately,
9731 : : * because CREATE TABLE would not create them as invalid, and
9732 : : * also because they must be created after potentially
9733 : : * violating data has been loaded.
9734 : : */
9735 : 73 : constrs[j].separate = true;
9736 : :
9737 : 73 : constrs[j].dobj.dump = tbinfo->dobj.dump;
9738 : : }
9739 : : }
9740 : 43 : PQclear(res);
9741 : : }
9742 : :
9743 : : /*
9744 : : * Get info about table CHECK constraints. This is skipped for a
9745 : : * data-only dump, as it is only needed for table schemas.
9746 : : */
285 nathan@postgresql.or 9747 [ + + + + ]: 185 : if (dopt->dumpSchema && checkoids->len > 2)
9748 : : {
9749 : : ConstraintInfo *constrs;
9750 : : int numConstrs;
9751 : : int i_tableoid;
9752 : : int i_oid;
9753 : : int i_conrelid;
9754 : : int i_conname;
9755 : : int i_consrc;
9756 : : int i_conislocal;
9757 : : int i_convalidated;
9758 : :
1370 tgl@sss.pgh.pa.us 9759 : 67 : pg_log_info("finding table check constraints");
9760 : :
9761 : 67 : resetPQExpBuffer(q);
9762 : 67 : appendPQExpBuffer(q,
9763 : : "SELECT c.tableoid, c.oid, conrelid, conname, "
9764 : : "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9765 : : "conislocal, convalidated "
9766 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9767 : : "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
9768 : : "WHERE contype = 'c' "
9769 : : "ORDER BY c.conrelid, c.conname",
9770 : : checkoids->data);
9771 : :
9772 : 67 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9773 : :
9774 : 67 : numConstrs = PQntuples(res);
9775 : 67 : constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
9776 : :
9777 : 67 : i_tableoid = PQfnumber(res, "tableoid");
9778 : 67 : i_oid = PQfnumber(res, "oid");
9779 : 67 : i_conrelid = PQfnumber(res, "conrelid");
9780 : 67 : i_conname = PQfnumber(res, "conname");
9781 : 67 : i_consrc = PQfnumber(res, "consrc");
9782 : 67 : i_conislocal = PQfnumber(res, "conislocal");
9783 : 67 : i_convalidated = PQfnumber(res, "convalidated");
9784 : :
9785 : : /* As above, this loop iterates once per table, not once per row */
9786 : 67 : curtblindx = -1;
9787 [ + + ]: 602 : for (int j = 0; j < numConstrs;)
9788 : : {
9789 : 535 : Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9790 : 535 : TableInfo *tbinfo = NULL;
9791 : : int numcons;
9792 : :
9793 : : /* Count rows for this table */
9794 [ + + ]: 682 : for (numcons = 1; numcons < numConstrs - j; numcons++)
9795 [ + + ]: 615 : if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9796 : 468 : break;
9797 : :
9798 : : /*
9799 : : * Locate the associated TableInfo; we rely on tblinfo[] being in
9800 : : * OID order.
9801 : : */
9802 [ + - ]: 19592 : while (++curtblindx < numTables)
9803 : : {
9804 : 19592 : tbinfo = &tblinfo[curtblindx];
9805 [ + + ]: 19592 : if (tbinfo->dobj.catId.oid == conrelid)
9806 : 535 : break;
9807 : : }
9808 [ - + ]: 535 : if (curtblindx >= numTables)
1247 tgl@sss.pgh.pa.us 9809 :UBC 0 : pg_fatal("unrecognized table OID %u", conrelid);
9810 : :
1370 tgl@sss.pgh.pa.us 9811 [ - + ]:CBC 535 : if (numcons != tbinfo->ncheck)
9812 : : {
2350 peter@eisentraut.org 9813 :UBC 0 : pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
9814 : : "expected %d check constraints on table \"%s\" but found %d",
9815 : : tbinfo->ncheck),
9816 : : tbinfo->ncheck, tbinfo->dobj.name, numcons);
1247 tgl@sss.pgh.pa.us 9817 : 0 : pg_log_error_hint("The system catalogs might be corrupted.");
4951 rhaas@postgresql.org 9818 : 0 : exit_nicely(1);
9819 : : }
9820 : :
1370 tgl@sss.pgh.pa.us 9821 :CBC 535 : tbinfo->checkexprs = constrs + j;
9822 : :
9823 [ + + ]: 1217 : for (int c = 0; c < numcons; c++, j++)
9824 : : {
9825 : 682 : bool validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
9826 : :
7945 9827 : 682 : constrs[j].dobj.objType = DO_CONSTRAINT;
1370 9828 : 682 : constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9829 : 682 : constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7945 9830 : 682 : AssignDumpId(&constrs[j].dobj);
1370 9831 : 682 : constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7857 9832 : 682 : constrs[j].dobj.namespace = tbinfo->dobj.namespace;
7945 9833 : 682 : constrs[j].contable = tbinfo;
9834 : 682 : constrs[j].condomain = NULL;
9835 : 682 : constrs[j].contype = 'c';
1370 9836 : 682 : constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
6207 9837 : 682 : constrs[j].confrelid = InvalidOid;
7945 9838 : 682 : constrs[j].conindex = 0;
5883 9839 : 682 : constrs[j].condeferrable = false;
9840 : 682 : constrs[j].condeferred = false;
1370 9841 : 682 : constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9842 : :
9843 : : /*
9844 : : * An unvalidated constraint needs to be dumped separately, so
9845 : : * that potentially-violating existing data is loaded before
9846 : : * the constraint.
9847 : : */
4887 alvherre@alvh.no-ip. 9848 : 682 : constrs[j].separate = !validated;
9849 : :
7128 tgl@sss.pgh.pa.us 9850 : 682 : constrs[j].dobj.dump = tbinfo->dobj.dump;
9851 : :
9852 : : /*
9853 : : * Mark the constraint as needing to appear before the table
9854 : : * --- this is so that any other dependencies of the
9855 : : * constraint will be emitted before we try to create the
9856 : : * table. If the constraint is to be dumped separately, it
9857 : : * will be dumped after data is loaded anyway, so don't do it.
9858 : : * (There's an automatic dependency in the opposite direction
9859 : : * anyway, so don't need to add one manually here.)
9860 : : */
5024 alvherre@alvh.no-ip. 9861 [ + + ]: 682 : if (!constrs[j].separate)
5035 9862 : 617 : addObjectDependency(&tbinfo->dobj,
9863 : 617 : constrs[j].dobj.dumpId);
9864 : :
9865 : : /*
9866 : : * We will detect later whether the constraint must be split
9867 : : * out from the table definition.
9868 : : */
9869 : : }
9870 : : }
9871 : :
1370 tgl@sss.pgh.pa.us 9872 : 67 : PQclear(res);
9873 : : }
9874 : :
8800 9875 : 185 : destroyPQExpBuffer(q);
1370 9876 : 185 : destroyPQExpBuffer(tbloids);
9877 : 185 : destroyPQExpBuffer(checkoids);
10651 scrappy@hub.org 9878 : 185 : }
9879 : :
9880 : : /*
9881 : : * Based on the getTableAttrs query's row corresponding to one column, set
9882 : : * the name and flags to handle a not-null constraint for that column in
9883 : : * the tbinfo struct.
9884 : : *
9885 : : * Result row 'r' is for tbinfo's attribute 'j'.
9886 : : *
9887 : : * There are four possibilities:
9888 : : * 1) the column has no not-null constraints. In that case, ->notnull_constrs
9889 : : * (the constraint name) remains NULL.
9890 : : * 2) The column has a constraint with no name (this is the case when
9891 : : * constraints come from pre-18 servers). In this case, ->notnull_constrs
9892 : : * is set to the empty string; dumpTableSchema will print just "NOT NULL".
9893 : : * 3) The column has an invalid not-null constraint. This must be treated
9894 : : * as a separate object (because it must be created after the table data
9895 : : * is loaded). So we add its OID to invalidnotnulloids for processing
9896 : : * elsewhere and do nothing further with it here. We distinguish this
9897 : : * case because the "notnull_invalidoid" column has been set to a non-NULL
9898 : : * value, which is the constraint OID. Valid constraints have a null OID.
9899 : : * 4) The column has a constraint with a known name; in that case
9900 : : * notnull_constrs carries that name and dumpTableSchema will print
9901 : : * "CONSTRAINT the_name NOT NULL". However, if the name is the default
9902 : : * (table_column_not_null) and there's no comment on the constraint,
9903 : : * there's no need to print that name in the dump, so notnull_constrs
9904 : : * is set to the empty string and it behaves as case 2.
9905 : : *
9906 : : * In a child table that inherits from a parent already containing NOT NULL
9907 : : * constraints and the columns in the child don't have their own NOT NULL
9908 : : * declarations, we suppress printing constraints in the child: the
9909 : : * constraints are acquired at the point where the child is attached to the
9910 : : * parent. This is tracked in ->notnull_islocal; for servers pre-18 this is
9911 : : * set not here but in flagInhAttrs. That flag is also used when the
9912 : : * constraint was validated in a child but all its parent have it as NOT
9913 : : * VALID.
9914 : : *
9915 : : * Any of these constraints might have the NO INHERIT bit. If so we set
9916 : : * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
9917 : : *
9918 : : * In case 4 above, the name comparison is a bit of a hack; it actually fails
9919 : : * to do the right thing in all but the trivial case. However, the downside
9920 : : * of getting it wrong is simply that the name is printed rather than
9921 : : * suppressed, so it's not a big deal.
9922 : : *
9923 : : * invalidnotnulloids is expected to be given as NULL; if any invalid not-null
9924 : : * constraints are found, it is initialized and filled with the array of
9925 : : * OIDs of such constraints, for later processing.
9926 : : */
9927 : : static void
302 alvherre@alvh.no-ip. 9928 : 25248 : determineNotNullFlags(Archive *fout, PGresult *res, int r,
9929 : : TableInfo *tbinfo, int j,
9930 : : int i_notnull_name,
9931 : : int i_notnull_comment,
9932 : : int i_notnull_invalidoid,
9933 : : int i_notnull_noinherit,
9934 : : int i_notnull_islocal,
9935 : : PQExpBuffer *invalidnotnulloids)
9936 : : {
9937 : 25248 : DumpOptions *dopt = fout->dopt;
9938 : :
9939 : : /*
9940 : : * If this not-null constraint is not valid, list its OID in
9941 : : * invalidnotnulloids and do nothing further. It'll be processed
9942 : : * elsewhere later.
9943 : : *
9944 : : * Because invalid not-null constraints are rare, we don't want to malloc
9945 : : * invalidnotnulloids until we're sure we're going it need it, which
9946 : : * happens here.
9947 : : */
152 9948 [ + + ]: 25248 : if (!PQgetisnull(res, r, i_notnull_invalidoid))
9949 : : {
9950 : 79 : char *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
9951 : :
9952 [ + + ]: 79 : if (*invalidnotnulloids == NULL)
9953 : : {
9954 : 49 : *invalidnotnulloids = createPQExpBuffer();
9955 : 49 : appendPQExpBufferChar(*invalidnotnulloids, '{');
142 drowley@postgresql.o 9956 : 49 : appendPQExpBufferStr(*invalidnotnulloids, constroid);
9957 : : }
9958 : : else
152 alvherre@alvh.no-ip. 9959 : 30 : appendPQExpBuffer(*invalidnotnulloids, ",%s", constroid);
9960 : :
9961 : : /*
9962 : : * Track when a parent constraint is invalid for the cases where a
9963 : : * child constraint has been validated independenly.
9964 : : */
131 alvherre@kurilemu.de 9965 : 79 : tbinfo->notnull_invalid[j] = true;
9966 : :
9967 : : /* nothing else to do */
152 alvherre@alvh.no-ip. 9968 : 79 : tbinfo->notnull_constrs[j] = NULL;
9969 : 79 : return;
9970 : : }
9971 : :
9972 : : /*
9973 : : * notnull_noinh is straight from the query result. notnull_islocal also,
9974 : : * though flagInhAttrs may change that one later.
9975 : : */
302 9976 : 25169 : tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
9977 : 25169 : tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
131 alvherre@kurilemu.de 9978 : 25169 : tbinfo->notnull_invalid[j] = false;
9979 : :
9980 : : /*
9981 : : * Determine a constraint name to use. If the column is not marked not-
9982 : : * null, we set NULL which cues ... to do nothing. An empty string says
9983 : : * to print an unnamed NOT NULL, and anything else is a constraint name to
9984 : : * use.
9985 : : */
302 alvherre@alvh.no-ip. 9986 [ - + ]: 25169 : if (fout->remoteVersion < 180000)
9987 : : {
9988 : : /*
9989 : : * < 18 doesn't have not-null names, so an unnamed constraint is
9990 : : * sufficient.
9991 : : */
302 alvherre@alvh.no-ip. 9992 [ # # ]:UBC 0 : if (PQgetisnull(res, r, i_notnull_name))
9993 : 0 : tbinfo->notnull_constrs[j] = NULL;
9994 : : else
9995 : 0 : tbinfo->notnull_constrs[j] = "";
9996 : : }
9997 : : else
9998 : : {
302 alvherre@alvh.no-ip. 9999 [ + + ]:CBC 25169 : if (PQgetisnull(res, r, i_notnull_name))
10000 : 22417 : tbinfo->notnull_constrs[j] = NULL;
10001 : : else
10002 : : {
10003 : : /*
10004 : : * In binary upgrade of inheritance child tables, must have a
10005 : : * constraint name that we can UPDATE later; same if there's a
10006 : : * comment on the constraint.
10007 : : */
72 alvherre@kurilemu.de 10008 [ + + ]: 2752 : if ((dopt->binary_upgrade &&
10009 [ + + ]: 326 : !tbinfo->ispartition &&
10010 [ + - + + ]: 3000 : !tbinfo->notnull_islocal) ||
10011 : 2752 : !PQgetisnull(res, r, i_notnull_comment))
10012 : : {
302 alvherre@alvh.no-ip. 10013 : 54 : tbinfo->notnull_constrs[j] =
10014 : 54 : pstrdup(PQgetvalue(res, r, i_notnull_name));
10015 : : }
10016 : : else
10017 : : {
10018 : : char *default_name;
10019 : :
10020 : : /* XXX should match ChooseConstraintName better */
10021 : 2698 : default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
10022 : 2698 : tbinfo->attnames[j]);
10023 [ + + ]: 2698 : if (strcmp(default_name,
10024 : 2698 : PQgetvalue(res, r, i_notnull_name)) == 0)
10025 : 1762 : tbinfo->notnull_constrs[j] = "";
10026 : : else
10027 : : {
10028 : 936 : tbinfo->notnull_constrs[j] =
10029 : 936 : pstrdup(PQgetvalue(res, r, i_notnull_name));
10030 : : }
206 tgl@sss.pgh.pa.us 10031 : 2698 : free(default_name);
10032 : : }
10033 : : }
10034 : : }
10035 : : }
10036 : :
10037 : : /*
10038 : : * Test whether a column should be printed as part of table's CREATE TABLE.
10039 : : * Column number is zero-based.
10040 : : *
10041 : : * Normally this is always true, but it's false for dropped columns, as well
10042 : : * as those that were inherited without any local definition. (If we print
10043 : : * such a column it will mistakenly get pg_attribute.attislocal set to true.)
10044 : : * For partitions, it's always true, because we want the partitions to be
10045 : : * created independently and ATTACH PARTITION used afterwards.
10046 : : *
10047 : : * In binary_upgrade mode, we must print all columns and fix the attislocal/
10048 : : * attisdropped state later, so as to keep control of the physical column
10049 : : * order.
10050 : : *
10051 : : * This function exists because there are scattered nonobvious places that
10052 : : * must be kept in sync with this decision.
10053 : : */
10054 : : bool
1669 peter@eisentraut.org 10055 : 41146 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
10056 : : {
3980 alvherre@alvh.no-ip. 10057 [ + + ]: 41146 : if (dopt->binary_upgrade)
4957 tgl@sss.pgh.pa.us 10058 : 6206 : return true;
2280 alvherre@alvh.no-ip. 10059 [ + + ]: 34940 : if (tbinfo->attisdropped[colno])
10060 : 738 : return false;
10061 [ + + + + ]: 34202 : return (tbinfo->attislocal[colno] || tbinfo->ispartition);
10062 : : }
10063 : :
10064 : :
10065 : : /*
10066 : : * getTSParsers:
10067 : : * get information about all text search parsers in the system catalogs
10068 : : */
10069 : : void
431 nathan@postgresql.or 10070 : 185 : getTSParsers(Archive *fout)
10071 : : {
10072 : : PGresult *res;
10073 : : int ntups;
10074 : : int i;
10075 : : PQExpBuffer query;
10076 : : TSParserInfo *prsinfo;
10077 : : int i_tableoid;
10078 : : int i_oid;
10079 : : int i_prsname;
10080 : : int i_prsnamespace;
10081 : : int i_prsstart;
10082 : : int i_prstoken;
10083 : : int i_prsend;
10084 : : int i_prsheadline;
10085 : : int i_prslextype;
10086 : :
4925 peter_e@gmx.net 10087 : 185 : query = createPQExpBuffer();
10088 : :
10089 : : /*
10090 : : * find all text search objects, including builtin ones; we filter out
10091 : : * system-defined objects at dump-out time.
10092 : : */
10093 : :
4310 heikki.linnakangas@i 10094 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
10095 : : "prsstart::oid, prstoken::oid, "
10096 : : "prsend::oid, prsheadline::oid, prslextype::oid "
10097 : : "FROM pg_ts_parser");
10098 : :
4960 rhaas@postgresql.org 10099 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10100 : :
6591 tgl@sss.pgh.pa.us 10101 : 185 : ntups = PQntuples(res);
10102 : :
5034 bruce@momjian.us 10103 : 185 : prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
10104 : :
6591 tgl@sss.pgh.pa.us 10105 : 185 : i_tableoid = PQfnumber(res, "tableoid");
10106 : 185 : i_oid = PQfnumber(res, "oid");
10107 : 185 : i_prsname = PQfnumber(res, "prsname");
10108 : 185 : i_prsnamespace = PQfnumber(res, "prsnamespace");
10109 : 185 : i_prsstart = PQfnumber(res, "prsstart");
10110 : 185 : i_prstoken = PQfnumber(res, "prstoken");
10111 : 185 : i_prsend = PQfnumber(res, "prsend");
10112 : 185 : i_prsheadline = PQfnumber(res, "prsheadline");
10113 : 185 : i_prslextype = PQfnumber(res, "prslextype");
10114 : :
10115 [ + + ]: 421 : for (i = 0; i < ntups; i++)
10116 : : {
10117 : 236 : prsinfo[i].dobj.objType = DO_TSPARSER;
10118 : 236 : prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10119 : 236 : prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10120 : 236 : AssignDumpId(&prsinfo[i].dobj);
5034 bruce@momjian.us 10121 : 236 : prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
4961 rhaas@postgresql.org 10122 : 472 : prsinfo[i].dobj.namespace =
1838 peter@eisentraut.org 10123 : 236 : findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
6591 tgl@sss.pgh.pa.us 10124 : 236 : prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
10125 : 236 : prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
10126 : 236 : prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
10127 : 236 : prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
10128 : 236 : prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
10129 : :
10130 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 10131 : 236 : selectDumpableObject(&(prsinfo[i].dobj), fout);
10132 : : }
10133 : :
6591 tgl@sss.pgh.pa.us 10134 : 185 : PQclear(res);
10135 : :
10136 : 185 : destroyPQExpBuffer(query);
10137 : 185 : }
10138 : :
10139 : : /*
10140 : : * getTSDictionaries:
10141 : : * get information about all text search dictionaries in the system catalogs
10142 : : */
10143 : : void
431 nathan@postgresql.or 10144 : 185 : getTSDictionaries(Archive *fout)
10145 : : {
10146 : : PGresult *res;
10147 : : int ntups;
10148 : : int i;
10149 : : PQExpBuffer query;
10150 : : TSDictInfo *dictinfo;
10151 : : int i_tableoid;
10152 : : int i_oid;
10153 : : int i_dictname;
10154 : : int i_dictnamespace;
10155 : : int i_dictowner;
10156 : : int i_dicttemplate;
10157 : : int i_dictinitoption;
10158 : :
4925 peter_e@gmx.net 10159 : 185 : query = createPQExpBuffer();
10160 : :
1096 drowley@postgresql.o 10161 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
10162 : : "dictnamespace, dictowner, "
10163 : : "dicttemplate, dictinitoption "
10164 : : "FROM pg_ts_dict");
10165 : :
4960 rhaas@postgresql.org 10166 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10167 : :
6591 tgl@sss.pgh.pa.us 10168 : 185 : ntups = PQntuples(res);
10169 : :
5034 bruce@momjian.us 10170 : 185 : dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
10171 : :
6591 tgl@sss.pgh.pa.us 10172 : 185 : i_tableoid = PQfnumber(res, "tableoid");
10173 : 185 : i_oid = PQfnumber(res, "oid");
10174 : 185 : i_dictname = PQfnumber(res, "dictname");
10175 : 185 : i_dictnamespace = PQfnumber(res, "dictnamespace");
1345 10176 : 185 : i_dictowner = PQfnumber(res, "dictowner");
6591 10177 : 185 : i_dictinitoption = PQfnumber(res, "dictinitoption");
10178 : 185 : i_dicttemplate = PQfnumber(res, "dicttemplate");
10179 : :
10180 [ + + ]: 5849 : for (i = 0; i < ntups; i++)
10181 : : {
10182 : 5664 : dictinfo[i].dobj.objType = DO_TSDICT;
10183 : 5664 : dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10184 : 5664 : dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10185 : 5664 : AssignDumpId(&dictinfo[i].dobj);
5034 bruce@momjian.us 10186 : 5664 : dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
4961 rhaas@postgresql.org 10187 : 11328 : dictinfo[i].dobj.namespace =
1838 peter@eisentraut.org 10188 : 5664 : findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
1345 tgl@sss.pgh.pa.us 10189 : 5664 : dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
6591 10190 : 5664 : dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
10191 [ + + ]: 5664 : if (PQgetisnull(res, i, i_dictinitoption))
10192 : 236 : dictinfo[i].dictinitoption = NULL;
10193 : : else
5034 bruce@momjian.us 10194 : 5428 : dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
10195 : :
10196 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 10197 : 5664 : selectDumpableObject(&(dictinfo[i].dobj), fout);
10198 : : }
10199 : :
6591 tgl@sss.pgh.pa.us 10200 : 185 : PQclear(res);
10201 : :
10202 : 185 : destroyPQExpBuffer(query);
10203 : 185 : }
10204 : :
10205 : : /*
10206 : : * getTSTemplates:
10207 : : * get information about all text search templates in the system catalogs
10208 : : */
10209 : : void
431 nathan@postgresql.or 10210 : 185 : getTSTemplates(Archive *fout)
10211 : : {
10212 : : PGresult *res;
10213 : : int ntups;
10214 : : int i;
10215 : : PQExpBuffer query;
10216 : : TSTemplateInfo *tmplinfo;
10217 : : int i_tableoid;
10218 : : int i_oid;
10219 : : int i_tmplname;
10220 : : int i_tmplnamespace;
10221 : : int i_tmplinit;
10222 : : int i_tmpllexize;
10223 : :
4925 peter_e@gmx.net 10224 : 185 : query = createPQExpBuffer();
10225 : :
4310 heikki.linnakangas@i 10226 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
10227 : : "tmplnamespace, tmplinit::oid, tmpllexize::oid "
10228 : : "FROM pg_ts_template");
10229 : :
4960 rhaas@postgresql.org 10230 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10231 : :
6591 tgl@sss.pgh.pa.us 10232 : 185 : ntups = PQntuples(res);
10233 : :
5034 bruce@momjian.us 10234 : 185 : tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
10235 : :
6591 tgl@sss.pgh.pa.us 10236 : 185 : i_tableoid = PQfnumber(res, "tableoid");
10237 : 185 : i_oid = PQfnumber(res, "oid");
10238 : 185 : i_tmplname = PQfnumber(res, "tmplname");
10239 : 185 : i_tmplnamespace = PQfnumber(res, "tmplnamespace");
10240 : 185 : i_tmplinit = PQfnumber(res, "tmplinit");
10241 : 185 : i_tmpllexize = PQfnumber(res, "tmpllexize");
10242 : :
10243 [ + + ]: 1161 : for (i = 0; i < ntups; i++)
10244 : : {
10245 : 976 : tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
10246 : 976 : tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10247 : 976 : tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10248 : 976 : AssignDumpId(&tmplinfo[i].dobj);
5034 bruce@momjian.us 10249 : 976 : tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
4961 rhaas@postgresql.org 10250 : 1952 : tmplinfo[i].dobj.namespace =
1838 peter@eisentraut.org 10251 : 976 : findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
6591 tgl@sss.pgh.pa.us 10252 : 976 : tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
10253 : 976 : tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
10254 : :
10255 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 10256 : 976 : selectDumpableObject(&(tmplinfo[i].dobj), fout);
10257 : : }
10258 : :
6591 tgl@sss.pgh.pa.us 10259 : 185 : PQclear(res);
10260 : :
10261 : 185 : destroyPQExpBuffer(query);
10262 : 185 : }
10263 : :
10264 : : /*
10265 : : * getTSConfigurations:
10266 : : * get information about all text search configurations
10267 : : */
10268 : : void
431 nathan@postgresql.or 10269 : 185 : getTSConfigurations(Archive *fout)
10270 : : {
10271 : : PGresult *res;
10272 : : int ntups;
10273 : : int i;
10274 : : PQExpBuffer query;
10275 : : TSConfigInfo *cfginfo;
10276 : : int i_tableoid;
10277 : : int i_oid;
10278 : : int i_cfgname;
10279 : : int i_cfgnamespace;
10280 : : int i_cfgowner;
10281 : : int i_cfgparser;
10282 : :
4925 peter_e@gmx.net 10283 : 185 : query = createPQExpBuffer();
10284 : :
1096 drowley@postgresql.o 10285 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
10286 : : "cfgnamespace, cfgowner, cfgparser "
10287 : : "FROM pg_ts_config");
10288 : :
4960 rhaas@postgresql.org 10289 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10290 : :
6591 tgl@sss.pgh.pa.us 10291 : 185 : ntups = PQntuples(res);
10292 : :
5034 bruce@momjian.us 10293 : 185 : cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
10294 : :
6591 tgl@sss.pgh.pa.us 10295 : 185 : i_tableoid = PQfnumber(res, "tableoid");
10296 : 185 : i_oid = PQfnumber(res, "oid");
10297 : 185 : i_cfgname = PQfnumber(res, "cfgname");
10298 : 185 : i_cfgnamespace = PQfnumber(res, "cfgnamespace");
1345 10299 : 185 : i_cfgowner = PQfnumber(res, "cfgowner");
6591 10300 : 185 : i_cfgparser = PQfnumber(res, "cfgparser");
10301 : :
10302 [ + + ]: 5814 : for (i = 0; i < ntups; i++)
10303 : : {
10304 : 5629 : cfginfo[i].dobj.objType = DO_TSCONFIG;
10305 : 5629 : cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10306 : 5629 : cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10307 : 5629 : AssignDumpId(&cfginfo[i].dobj);
5034 bruce@momjian.us 10308 : 5629 : cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
4961 rhaas@postgresql.org 10309 : 11258 : cfginfo[i].dobj.namespace =
1838 peter@eisentraut.org 10310 : 5629 : findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
1345 tgl@sss.pgh.pa.us 10311 : 5629 : cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
6591 10312 : 5629 : cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
10313 : :
10314 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 10315 : 5629 : selectDumpableObject(&(cfginfo[i].dobj), fout);
10316 : : }
10317 : :
6591 tgl@sss.pgh.pa.us 10318 : 185 : PQclear(res);
10319 : :
10320 : 185 : destroyPQExpBuffer(query);
10321 : 185 : }
10322 : :
10323 : : /*
10324 : : * getForeignDataWrappers:
10325 : : * get information about all foreign-data wrappers in the system catalogs
10326 : : */
10327 : : void
431 nathan@postgresql.or 10328 : 185 : getForeignDataWrappers(Archive *fout)
10329 : : {
10330 : : PGresult *res;
10331 : : int ntups;
10332 : : int i;
10333 : : PQExpBuffer query;
10334 : : FdwInfo *fdwinfo;
10335 : : int i_tableoid;
10336 : : int i_oid;
10337 : : int i_fdwname;
10338 : : int i_fdwowner;
10339 : : int i_fdwhandler;
10340 : : int i_fdwvalidator;
10341 : : int i_fdwacl;
10342 : : int i_acldefault;
10343 : : int i_fdwoptions;
10344 : :
4228 sfrost@snowman.net 10345 : 185 : query = createPQExpBuffer();
10346 : :
1096 drowley@postgresql.o 10347 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
10348 : : "fdwowner, "
10349 : : "fdwhandler::pg_catalog.regproc, "
10350 : : "fdwvalidator::pg_catalog.regproc, "
10351 : : "fdwacl, "
10352 : : "acldefault('F', fdwowner) AS acldefault, "
10353 : : "array_to_string(ARRAY("
10354 : : "SELECT quote_ident(option_name) || ' ' || "
10355 : : "quote_literal(option_value) "
10356 : : "FROM pg_options_to_table(fdwoptions) "
10357 : : "ORDER BY option_name"
10358 : : "), E',\n ') AS fdwoptions "
10359 : : "FROM pg_foreign_data_wrapper");
10360 : :
4960 rhaas@postgresql.org 10361 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10362 : :
6105 peter_e@gmx.net 10363 : 185 : ntups = PQntuples(res);
10364 : :
5034 bruce@momjian.us 10365 : 185 : fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
10366 : :
5462 heikki.linnakangas@i 10367 : 185 : i_tableoid = PQfnumber(res, "tableoid");
6105 peter_e@gmx.net 10368 : 185 : i_oid = PQfnumber(res, "oid");
10369 : 185 : i_fdwname = PQfnumber(res, "fdwname");
1345 tgl@sss.pgh.pa.us 10370 : 185 : i_fdwowner = PQfnumber(res, "fdwowner");
5313 10371 : 185 : i_fdwhandler = PQfnumber(res, "fdwhandler");
6038 peter_e@gmx.net 10372 : 185 : i_fdwvalidator = PQfnumber(res, "fdwvalidator");
6105 10373 : 185 : i_fdwacl = PQfnumber(res, "fdwacl");
1370 tgl@sss.pgh.pa.us 10374 : 185 : i_acldefault = PQfnumber(res, "acldefault");
6105 peter_e@gmx.net 10375 : 185 : i_fdwoptions = PQfnumber(res, "fdwoptions");
10376 : :
10377 [ + + ]: 262 : for (i = 0; i < ntups; i++)
10378 : : {
10379 : 77 : fdwinfo[i].dobj.objType = DO_FDW;
5462 heikki.linnakangas@i 10380 : 77 : fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6105 peter_e@gmx.net 10381 : 77 : fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10382 : 77 : AssignDumpId(&fdwinfo[i].dobj);
5034 bruce@momjian.us 10383 : 77 : fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
6105 peter_e@gmx.net 10384 : 77 : fdwinfo[i].dobj.namespace = NULL;
1370 tgl@sss.pgh.pa.us 10385 : 77 : fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
10386 : 77 : fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10387 : 77 : fdwinfo[i].dacl.privtype = 0;
10388 : 77 : fdwinfo[i].dacl.initprivs = NULL;
1345 10389 : 77 : fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
5034 bruce@momjian.us 10390 : 77 : fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
10391 : 77 : fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
10392 : 77 : fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
10393 : :
10394 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 10395 : 77 : selectDumpableObject(&(fdwinfo[i].dobj), fout);
10396 : :
10397 : : /* Mark whether FDW has an ACL */
1370 tgl@sss.pgh.pa.us 10398 [ + + ]: 77 : if (!PQgetisnull(res, i, i_fdwacl))
10399 : 51 : fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10400 : : }
10401 : :
6105 peter_e@gmx.net 10402 : 185 : PQclear(res);
10403 : :
10404 : 185 : destroyPQExpBuffer(query);
10405 : 185 : }
10406 : :
10407 : : /*
10408 : : * getForeignServers:
10409 : : * get information about all foreign servers in the system catalogs
10410 : : */
10411 : : void
431 nathan@postgresql.or 10412 : 185 : getForeignServers(Archive *fout)
10413 : : {
10414 : : PGresult *res;
10415 : : int ntups;
10416 : : int i;
10417 : : PQExpBuffer query;
10418 : : ForeignServerInfo *srvinfo;
10419 : : int i_tableoid;
10420 : : int i_oid;
10421 : : int i_srvname;
10422 : : int i_srvowner;
10423 : : int i_srvfdw;
10424 : : int i_srvtype;
10425 : : int i_srvversion;
10426 : : int i_srvacl;
10427 : : int i_acldefault;
10428 : : int i_srvoptions;
10429 : :
4228 sfrost@snowman.net 10430 : 185 : query = createPQExpBuffer();
10431 : :
1096 drowley@postgresql.o 10432 : 185 : appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
10433 : : "srvowner, "
10434 : : "srvfdw, srvtype, srvversion, srvacl, "
10435 : : "acldefault('S', srvowner) AS acldefault, "
10436 : : "array_to_string(ARRAY("
10437 : : "SELECT quote_ident(option_name) || ' ' || "
10438 : : "quote_literal(option_value) "
10439 : : "FROM pg_options_to_table(srvoptions) "
10440 : : "ORDER BY option_name"
10441 : : "), E',\n ') AS srvoptions "
10442 : : "FROM pg_foreign_server");
10443 : :
4960 rhaas@postgresql.org 10444 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10445 : :
6105 peter_e@gmx.net 10446 : 185 : ntups = PQntuples(res);
10447 : :
5034 bruce@momjian.us 10448 : 185 : srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
10449 : :
5462 heikki.linnakangas@i 10450 : 185 : i_tableoid = PQfnumber(res, "tableoid");
6105 peter_e@gmx.net 10451 : 185 : i_oid = PQfnumber(res, "oid");
10452 : 185 : i_srvname = PQfnumber(res, "srvname");
1345 tgl@sss.pgh.pa.us 10453 : 185 : i_srvowner = PQfnumber(res, "srvowner");
6105 peter_e@gmx.net 10454 : 185 : i_srvfdw = PQfnumber(res, "srvfdw");
10455 : 185 : i_srvtype = PQfnumber(res, "srvtype");
10456 : 185 : i_srvversion = PQfnumber(res, "srvversion");
10457 : 185 : i_srvacl = PQfnumber(res, "srvacl");
1370 tgl@sss.pgh.pa.us 10458 : 185 : i_acldefault = PQfnumber(res, "acldefault");
6105 peter_e@gmx.net 10459 : 185 : i_srvoptions = PQfnumber(res, "srvoptions");
10460 : :
10461 [ + + ]: 266 : for (i = 0; i < ntups; i++)
10462 : : {
10463 : 81 : srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
5462 heikki.linnakangas@i 10464 : 81 : srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6105 peter_e@gmx.net 10465 : 81 : srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10466 : 81 : AssignDumpId(&srvinfo[i].dobj);
5034 bruce@momjian.us 10467 : 81 : srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
6105 peter_e@gmx.net 10468 : 81 : srvinfo[i].dobj.namespace = NULL;
1370 tgl@sss.pgh.pa.us 10469 : 81 : srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
10470 : 81 : srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10471 : 81 : srvinfo[i].dacl.privtype = 0;
10472 : 81 : srvinfo[i].dacl.initprivs = NULL;
1345 10473 : 81 : srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
6105 peter_e@gmx.net 10474 : 81 : srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
5034 bruce@momjian.us 10475 : 81 : srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
10476 : 81 : srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
10477 : 81 : srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
10478 : :
10479 : : /* Decide whether we want to dump it */
3440 sfrost@snowman.net 10480 : 81 : selectDumpableObject(&(srvinfo[i].dobj), fout);
10481 : :
10482 : : /* Servers have user mappings */
1370 tgl@sss.pgh.pa.us 10483 : 81 : srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
10484 : :
10485 : : /* Mark whether server has an ACL */
10486 [ + + ]: 81 : if (!PQgetisnull(res, i, i_srvacl))
10487 : 51 : srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10488 : : }
10489 : :
6105 peter_e@gmx.net 10490 : 185 : PQclear(res);
10491 : :
10492 : 185 : destroyPQExpBuffer(query);
10493 : 185 : }
10494 : :
10495 : : /*
10496 : : * getDefaultACLs:
10497 : : * get information about all default ACL information in the system catalogs
10498 : : */
10499 : : void
431 nathan@postgresql.or 10500 : 185 : getDefaultACLs(Archive *fout)
10501 : : {
3524 tgl@sss.pgh.pa.us 10502 : 185 : DumpOptions *dopt = fout->dopt;
10503 : : DefaultACLInfo *daclinfo;
10504 : : PQExpBuffer query;
10505 : : PGresult *res;
10506 : : int i_oid;
10507 : : int i_tableoid;
10508 : : int i_defaclrole;
10509 : : int i_defaclnamespace;
10510 : : int i_defaclobjtype;
10511 : : int i_defaclacl;
10512 : : int i_acldefault;
10513 : : int i,
10514 : : ntups;
10515 : :
5815 10516 : 185 : query = createPQExpBuffer();
10517 : :
10518 : : /*
10519 : : * Global entries (with defaclnamespace=0) replace the hard-wired default
10520 : : * ACL for their object type. We should dump them as deltas from the
10521 : : * default ACL, since that will be used as a starting point for
10522 : : * interpreting the ALTER DEFAULT PRIVILEGES commands. On the other hand,
10523 : : * non-global entries can only add privileges not revoke them. We must
10524 : : * dump those as-is (i.e., as deltas from an empty ACL).
10525 : : *
10526 : : * We can use defaclobjtype as the object type for acldefault(), except
10527 : : * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
10528 : : * 's'.
10529 : : */
1096 drowley@postgresql.o 10530 : 185 : appendPQExpBufferStr(query,
10531 : : "SELECT oid, tableoid, "
10532 : : "defaclrole, "
10533 : : "defaclnamespace, "
10534 : : "defaclobjtype, "
10535 : : "defaclacl, "
10536 : : "CASE WHEN defaclnamespace = 0 THEN "
10537 : : "acldefault(CASE WHEN defaclobjtype = 'S' "
10538 : : "THEN 's'::\"char\" ELSE defaclobjtype END, "
10539 : : "defaclrole) ELSE '{}' END AS acldefault "
10540 : : "FROM pg_default_acl");
10541 : :
4960 rhaas@postgresql.org 10542 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10543 : :
5815 tgl@sss.pgh.pa.us 10544 : 185 : ntups = PQntuples(res);
10545 : :
5034 bruce@momjian.us 10546 : 185 : daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
10547 : :
5815 tgl@sss.pgh.pa.us 10548 : 185 : i_oid = PQfnumber(res, "oid");
10549 : 185 : i_tableoid = PQfnumber(res, "tableoid");
10550 : 185 : i_defaclrole = PQfnumber(res, "defaclrole");
10551 : 185 : i_defaclnamespace = PQfnumber(res, "defaclnamespace");
10552 : 185 : i_defaclobjtype = PQfnumber(res, "defaclobjtype");
10553 : 185 : i_defaclacl = PQfnumber(res, "defaclacl");
1370 10554 : 185 : i_acldefault = PQfnumber(res, "acldefault");
10555 : :
5815 10556 [ + + ]: 403 : for (i = 0; i < ntups; i++)
10557 : : {
5671 bruce@momjian.us 10558 : 218 : Oid nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
10559 : :
5815 tgl@sss.pgh.pa.us 10560 : 218 : daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
10561 : 218 : daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10562 : 218 : daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10563 : 218 : AssignDumpId(&daclinfo[i].dobj);
10564 : : /* cheesy ... is it worth coming up with a better object name? */
5034 bruce@momjian.us 10565 : 218 : daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
10566 : :
5815 tgl@sss.pgh.pa.us 10567 [ + + ]: 218 : if (nspid != InvalidOid)
1838 peter@eisentraut.org 10568 : 102 : daclinfo[i].dobj.namespace = findNamespace(nspid);
10569 : : else
5815 tgl@sss.pgh.pa.us 10570 : 116 : daclinfo[i].dobj.namespace = NULL;
10571 : :
1370 10572 : 218 : daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
10573 : 218 : daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10574 : 218 : daclinfo[i].dacl.privtype = 0;
10575 : 218 : daclinfo[i].dacl.initprivs = NULL;
1345 10576 : 218 : daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
5815 10577 : 218 : daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
10578 : :
10579 : : /* Default ACLs are ACLs, of course */
1370 10580 : 218 : daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10581 : :
10582 : : /* Decide whether we want to dump it */
3524 10583 : 218 : selectDumpableDefaultACL(&(daclinfo[i]), dopt);
10584 : : }
10585 : :
5815 10586 : 185 : PQclear(res);
10587 : :
10588 : 185 : destroyPQExpBuffer(query);
10589 : 185 : }
10590 : :
10591 : : /*
10592 : : * getRoleName -- look up the name of a role, given its OID
10593 : : *
10594 : : * In current usage, we don't expect failures, so error out for a bad OID.
10595 : : */
10596 : : static const char *
1345 10597 : 716199 : getRoleName(const char *roleoid_str)
10598 : : {
10599 : 716199 : Oid roleoid = atooid(roleoid_str);
10600 : :
10601 : : /*
10602 : : * Do binary search to find the appropriate item.
10603 : : */
10604 [ + - ]: 716199 : if (nrolenames > 0)
10605 : : {
10606 : 716199 : RoleNameItem *low = &rolenames[0];
10607 : 716199 : RoleNameItem *high = &rolenames[nrolenames - 1];
10608 : :
10609 [ + - ]: 2864502 : while (low <= high)
10610 : : {
10611 : 2864502 : RoleNameItem *middle = low + (high - low) / 2;
10612 : :
10613 [ + + ]: 2864502 : if (roleoid < middle->roleoid)
10614 : 2147357 : high = middle - 1;
10615 [ + + ]: 717145 : else if (roleoid > middle->roleoid)
10616 : 946 : low = middle + 1;
10617 : : else
10618 : 716199 : return middle->rolename; /* found a match */
10619 : : }
10620 : : }
10621 : :
1247 tgl@sss.pgh.pa.us 10622 :UBC 0 : pg_fatal("role with OID %u does not exist", roleoid);
10623 : : return NULL; /* keep compiler quiet */
10624 : : }
10625 : :
10626 : : /*
10627 : : * collectRoleNames --
10628 : : *
10629 : : * Construct a table of all known roles.
10630 : : * The table is sorted by OID for speed in lookup.
10631 : : */
10632 : : static void
1345 tgl@sss.pgh.pa.us 10633 :CBC 186 : collectRoleNames(Archive *fout)
10634 : : {
10635 : : PGresult *res;
10636 : : const char *query;
10637 : : int i;
10638 : :
10639 : 186 : query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
10640 : :
10641 : 186 : res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
10642 : :
10643 : 186 : nrolenames = PQntuples(res);
10644 : :
10645 : 186 : rolenames = (RoleNameItem *) pg_malloc(nrolenames * sizeof(RoleNameItem));
10646 : :
10647 [ + + ]: 3631 : for (i = 0; i < nrolenames; i++)
10648 : : {
10649 : 3445 : rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
10650 : 3445 : rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
10651 : : }
10652 : :
10653 : 186 : PQclear(res);
10654 : 186 : }
10655 : :
10656 : : /*
10657 : : * getAdditionalACLs
10658 : : *
10659 : : * We have now created all the DumpableObjects, and collected the ACL data
10660 : : * that appears in the directly-associated catalog entries. However, there's
10661 : : * more ACL-related info to collect. If any of a table's columns have ACLs,
10662 : : * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
10663 : : * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
10664 : : * Also, in versions having the pg_init_privs catalog, read that and load the
10665 : : * information into the relevant DumpableObjects.
10666 : : */
10667 : : static void
1370 10668 : 183 : getAdditionalACLs(Archive *fout)
10669 : : {
10670 : 183 : PQExpBuffer query = createPQExpBuffer();
10671 : : PGresult *res;
10672 : : int ntups,
10673 : : i;
10674 : :
10675 : : /* Check for per-column ACLs */
1362 10676 : 183 : appendPQExpBufferStr(query,
10677 : : "SELECT DISTINCT attrelid FROM pg_attribute "
10678 : : "WHERE attacl IS NOT NULL");
10679 : :
10680 : 183 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10681 : :
10682 : 183 : ntups = PQntuples(res);
10683 [ + + ]: 554 : for (i = 0; i < ntups; i++)
10684 : : {
10685 : 371 : Oid relid = atooid(PQgetvalue(res, i, 0));
10686 : : TableInfo *tblinfo;
10687 : :
10688 : 371 : tblinfo = findTableByOid(relid);
10689 : : /* OK to ignore tables we haven't got a DumpableObject for */
10690 [ + - ]: 371 : if (tblinfo)
10691 : : {
10692 : 371 : tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
10693 : 371 : tblinfo->hascolumnACLs = true;
10694 : : }
10695 : : }
10696 : 183 : PQclear(res);
10697 : :
10698 : : /* Fetch initial-privileges data */
1370 10699 [ + - ]: 183 : if (fout->remoteVersion >= 90600)
10700 : : {
10701 : 183 : printfPQExpBuffer(query,
10702 : : "SELECT objoid, classoid, objsubid, privtype, initprivs "
10703 : : "FROM pg_init_privs");
10704 : :
10705 : 183 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10706 : :
10707 : 183 : ntups = PQntuples(res);
10708 [ + + ]: 43313 : for (i = 0; i < ntups; i++)
10709 : : {
10710 : 43130 : Oid objoid = atooid(PQgetvalue(res, i, 0));
10711 : 43130 : Oid classoid = atooid(PQgetvalue(res, i, 1));
10712 : 43130 : int objsubid = atoi(PQgetvalue(res, i, 2));
10713 : 43130 : char privtype = *(PQgetvalue(res, i, 3));
10714 : 43130 : char *initprivs = PQgetvalue(res, i, 4);
10715 : : CatalogId objId;
10716 : : DumpableObject *dobj;
10717 : :
10718 : 43130 : objId.tableoid = classoid;
10719 : 43130 : objId.oid = objoid;
10720 : 43130 : dobj = findObjectByCatalogId(objId);
10721 : : /* OK to ignore entries we haven't got a DumpableObject for */
10722 [ + + ]: 43130 : if (dobj)
10723 : : {
10724 : : /* Cope with sub-object initprivs */
10725 [ + + ]: 30919 : if (objsubid != 0)
10726 : : {
10727 [ + - ]: 3684 : if (dobj->objType == DO_TABLE)
10728 : : {
10729 : : /* For a column initprivs, set the table's ACL flags */
10730 : 3684 : dobj->components |= DUMP_COMPONENT_ACL;
10731 : 3684 : ((TableInfo *) dobj)->hascolumnACLs = true;
10732 : : }
10733 : : else
1370 tgl@sss.pgh.pa.us 10734 :UBC 0 : pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10735 : : classoid, objoid, objsubid);
1370 tgl@sss.pgh.pa.us 10736 :CBC 3863 : continue;
10737 : : }
10738 : :
10739 : : /*
10740 : : * We ignore any pg_init_privs.initprivs entry for the public
10741 : : * schema, as explained in getNamespaces().
10742 : : */
10743 [ + + ]: 27235 : if (dobj->objType == DO_NAMESPACE &&
10744 [ + + ]: 362 : strcmp(dobj->name, "public") == 0)
10745 : 179 : continue;
10746 : :
10747 : : /* Else it had better be of a type we think has ACLs */
10748 [ + + ]: 27056 : if (dobj->objType == DO_NAMESPACE ||
10749 [ + + ]: 26873 : dobj->objType == DO_TYPE ||
10750 [ + + ]: 26849 : dobj->objType == DO_FUNC ||
10751 [ + + ]: 26751 : dobj->objType == DO_AGG ||
10752 [ - + ]: 26727 : dobj->objType == DO_TABLE ||
1370 tgl@sss.pgh.pa.us 10753 [ # # ]:UBC 0 : dobj->objType == DO_PROCLANG ||
10754 [ # # ]: 0 : dobj->objType == DO_FDW ||
10755 [ # # ]: 0 : dobj->objType == DO_FOREIGN_SERVER)
1370 tgl@sss.pgh.pa.us 10756 :CBC 27056 : {
10757 : 27056 : DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
10758 : :
10759 : 27056 : daobj->dacl.privtype = privtype;
10760 : 27056 : daobj->dacl.initprivs = pstrdup(initprivs);
10761 : : }
10762 : : else
1370 tgl@sss.pgh.pa.us 10763 :UBC 0 : pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10764 : : classoid, objoid, objsubid);
10765 : : }
10766 : : }
1370 tgl@sss.pgh.pa.us 10767 :CBC 183 : PQclear(res);
10768 : : }
10769 : :
10770 : 183 : destroyPQExpBuffer(query);
10771 : 183 : }
10772 : :
10773 : : /*
10774 : : * dumpCommentExtended --
10775 : : *
10776 : : * This routine is used to dump any comments associated with the
10777 : : * object handed to this routine. The routine takes the object type
10778 : : * and object name (ready to print, except for schema decoration), plus
10779 : : * the namespace and owner of the object (for labeling the ArchiveEntry),
10780 : : * plus catalog ID and subid which are the lookup key for pg_description,
10781 : : * plus the dump ID for the object (for setting a dependency).
10782 : : * If a matching pg_description entry is found, it is dumped.
10783 : : *
10784 : : * Note: in some cases, such as comments for triggers and rules, the "type"
10785 : : * string really looks like, e.g., "TRIGGER name ON". This is a bit of a hack
10786 : : * but it doesn't seem worth complicating the API for all callers to make
10787 : : * it cleaner.
10788 : : *
10789 : : * Note: although this routine takes a dumpId for dependency purposes,
10790 : : * that purpose is just to mark the dependency in the emitted dump file
10791 : : * for possible future use by pg_restore. We do NOT use it for determining
10792 : : * ordering of the comment in the dump file, because this routine is called
10793 : : * after dependency sorting occurs. This routine should be called just after
10794 : : * calling ArchiveEntry() for the specified object.
10795 : : */
10796 : : static void
1531 noah@leadboat.com 10797 : 6666 : dumpCommentExtended(Archive *fout, const char *type,
10798 : : const char *name, const char *namespace,
10799 : : const char *owner, CatalogId catalogId,
10800 : : int subid, DumpId dumpId,
10801 : : const char *initdb_comment)
10802 : : {
3524 tgl@sss.pgh.pa.us 10803 : 6666 : DumpOptions *dopt = fout->dopt;
10804 : : CommentItem *comments;
10805 : : int ncomments;
10806 : :
10807 : : /* do nothing, if --no-comments is supplied */
2781 10808 [ - + ]: 6666 : if (dopt->no_comments)
2781 tgl@sss.pgh.pa.us 10809 :UBC 0 : return;
10810 : :
10811 : : /* Comments are schema not data ... except LO comments are data */
2749 tgl@sss.pgh.pa.us 10812 [ + + ]:CBC 6666 : if (strcmp(type, "LARGE OBJECT") != 0)
10813 : : {
285 nathan@postgresql.or 10814 [ - + ]: 6611 : if (!dopt->dumpSchema)
5679 tgl@sss.pgh.pa.us 10815 :UBC 0 : return;
10816 : : }
10817 : : else
10818 : : {
10819 : : /* We do dump LO comments in binary-upgrade mode */
285 nathan@postgresql.or 10820 [ + + - + ]:CBC 55 : if (!dopt->dumpData && !dopt->binary_upgrade)
5679 tgl@sss.pgh.pa.us 10821 :UBC 0 : return;
10822 : : }
10823 : :
10824 : : /* Search for comments associated with catalogId, using table */
1346 tgl@sss.pgh.pa.us 10825 :CBC 6666 : ncomments = findComments(catalogId.tableoid, catalogId.oid,
10826 : : &comments);
10827 : :
10828 : : /* Is there one matching the subid? */
7840 10829 [ + + ]: 6666 : while (ncomments > 0)
10830 : : {
10831 [ + - ]: 6619 : if (comments->objsubid == subid)
10832 : 6619 : break;
7840 tgl@sss.pgh.pa.us 10833 :UBC 0 : comments++;
10834 : 0 : ncomments--;
10835 : : }
10836 : :
1531 noah@leadboat.com 10837 [ + + ]:CBC 6666 : if (initdb_comment != NULL)
10838 : : {
10839 : : static CommentItem empty_comment = {.descr = ""};
10840 : :
10841 : : /*
10842 : : * initdb creates this object with a comment. Skip dumping the
10843 : : * initdb-provided comment, which would complicate matters for
10844 : : * non-superuser use of pg_dump. When the DBA has removed initdb's
10845 : : * comment, replicate that.
10846 : : */
10847 [ + + ]: 116 : if (ncomments == 0)
10848 : : {
10849 : 4 : comments = &empty_comment;
10850 : 4 : ncomments = 1;
10851 : : }
10852 [ + - ]: 112 : else if (strcmp(comments->descr, initdb_comment) == 0)
10853 : 112 : ncomments = 0;
10854 : : }
10855 : :
10856 : : /* If a comment exists, build COMMENT ON statement */
7840 tgl@sss.pgh.pa.us 10857 [ + + ]: 6666 : if (ncomments > 0)
10858 : : {
10859 : 6511 : PQExpBuffer query = createPQExpBuffer();
2749 10860 : 6511 : PQExpBuffer tag = createPQExpBuffer();
10861 : :
10862 : 6511 : appendPQExpBuffer(query, "COMMENT ON %s ", type);
10863 [ + + + - ]: 6511 : if (namespace && *namespace)
10864 : 6326 : appendPQExpBuffer(query, "%s.", fmtId(namespace));
10865 : 6511 : appendPQExpBuffer(query, "%s IS ", name);
7041 10866 : 6511 : appendStringLiteralAH(query, comments->descr, fout);
4310 heikki.linnakangas@i 10867 : 6511 : appendPQExpBufferStr(query, ";\n");
10868 : :
2749 tgl@sss.pgh.pa.us 10869 : 6511 : appendPQExpBuffer(tag, "%s %s", type, name);
10870 : :
10871 : : /*
10872 : : * We mark comments as SECTION_NONE because they really belong in the
10873 : : * same section as their parent, whether that is pre-data or
10874 : : * post-data.
10875 : : */
7945 10876 : 6511 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 10877 : 6511 : ARCHIVE_OPTS(.tag = tag->data,
10878 : : .namespace = namespace,
10879 : : .owner = owner,
10880 : : .description = "COMMENT",
10881 : : .section = SECTION_NONE,
10882 : : .createStmt = query->data,
10883 : : .deps = &dumpId,
10884 : : .nDeps = 1));
10885 : :
7840 tgl@sss.pgh.pa.us 10886 : 6511 : destroyPQExpBuffer(query);
2749 10887 : 6511 : destroyPQExpBuffer(tag);
10888 : : }
10889 : : }
10890 : :
10891 : : /*
10892 : : * dumpComment --
10893 : : *
10894 : : * Typical simplification of the above function.
10895 : : */
10896 : : static inline void
1531 noah@leadboat.com 10897 : 6511 : dumpComment(Archive *fout, const char *type,
10898 : : const char *name, const char *namespace,
10899 : : const char *owner, CatalogId catalogId,
10900 : : int subid, DumpId dumpId)
10901 : : {
10902 : 6511 : dumpCommentExtended(fout, type, name, namespace, owner,
10903 : : catalogId, subid, dumpId, NULL);
10904 : 6511 : }
10905 : :
10906 : : /*
10907 : : * appendNamedArgument --
10908 : : *
10909 : : * Convenience routine for constructing parameters of the form:
10910 : : * 'paraname', 'value'::type
10911 : : */
10912 : : static void
198 jdavis@postgresql.or 10913 : 5700 : appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
10914 : : const char *argtype, const char *argval)
10915 : : {
192 tgl@sss.pgh.pa.us 10916 : 5700 : appendPQExpBufferStr(out, ",\n\t");
10917 : :
198 jdavis@postgresql.or 10918 : 5700 : appendStringLiteralAH(out, argname, fout);
10919 : 5700 : appendPQExpBufferStr(out, ", ");
10920 : :
10921 : 5700 : appendStringLiteralAH(out, argval, fout);
10922 : 5700 : appendPQExpBuffer(out, "::%s", argtype);
10923 : 5700 : }
10924 : :
10925 : : /*
10926 : : * fetchAttributeStats --
10927 : : *
10928 : : * Fetch next batch of attribute statistics for dumpRelationStats_dumper().
10929 : : */
10930 : : static PGresult *
155 nathan@postgresql.or 10931 : 1198 : fetchAttributeStats(Archive *fout)
10932 : : {
10933 : 1198 : ArchiveHandle *AH = (ArchiveHandle *) fout;
10934 : 1198 : PQExpBuffer nspnames = createPQExpBuffer();
10935 : 1198 : PQExpBuffer relnames = createPQExpBuffer();
10936 : 1198 : int count = 0;
10937 : 1198 : PGresult *res = NULL;
10938 : : static TocEntry *te;
10939 : : static bool restarted;
10940 : 1198 : int max_rels = MAX_ATTR_STATS_RELS;
10941 : :
10942 : : /*
10943 : : * Our query for retrieving statistics for multiple relations uses WITH
10944 : : * ORDINALITY and multi-argument UNNEST(), both of which were introduced
10945 : : * in v9.4. For older versions, we resort to gathering statistics for a
10946 : : * single relation at a time.
10947 : : */
10948 [ - + ]: 1198 : if (fout->remoteVersion < 90400)
155 nathan@postgresql.or 10949 :UBC 0 : max_rels = 1;
10950 : :
10951 : : /* If we're just starting, set our TOC pointer. */
155 nathan@postgresql.or 10952 [ + + ]:CBC 1198 : if (!te)
10953 : 60 : te = AH->toc->next;
10954 : :
10955 : : /*
10956 : : * We can't easily avoid a second TOC scan for the tar format because it
10957 : : * writes restore.sql separately, which means we must execute the queries
10958 : : * twice. This feels risky, but there is no known reason it should
10959 : : * generate different output than the first pass. Even if it does, the
10960 : : * worst-case scenario is that restore.sql might have different statistics
10961 : : * data than the archive.
10962 : : */
10963 [ + + + + : 1198 : if (!restarted && te == AH->toc && AH->format == archTar)
+ + ]
10964 : : {
10965 : 1 : te = AH->toc->next;
10966 : 1 : restarted = true;
10967 : : }
10968 : :
109 10969 : 1198 : appendPQExpBufferChar(nspnames, '{');
10970 : 1198 : appendPQExpBufferChar(relnames, '{');
10971 : :
10972 : : /*
10973 : : * Scan the TOC for the next set of relevant stats entries. We assume
10974 : : * that statistics are dumped in the order they are listed in the TOC.
10975 : : * This is perhaps not the sturdiest assumption, so we verify it matches
10976 : : * reality in dumpRelationStats_dumper().
10977 : : */
155 10978 [ + + + + ]: 18109 : for (; te != AH->toc && count < max_rels; te = te->next)
10979 : : {
10980 [ + + ]: 16911 : if ((te->reqs & REQ_STATS) != 0 &&
10981 [ + - ]: 3720 : strcmp(te->desc, "STATISTICS DATA") == 0)
10982 : : {
109 10983 : 3720 : appendPGArray(nspnames, te->namespace);
10984 : 3720 : appendPGArray(relnames, te->tag);
155 10985 : 3720 : count++;
10986 : : }
10987 : : }
10988 : :
109 10989 : 1198 : appendPQExpBufferChar(nspnames, '}');
10990 : 1198 : appendPQExpBufferChar(relnames, '}');
10991 : :
10992 : : /* Execute the query for the next batch of relations. */
155 10993 [ + + ]: 1198 : if (count > 0)
10994 : : {
10995 : 109 : PQExpBuffer query = createPQExpBuffer();
10996 : :
109 10997 : 109 : appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
10998 : 109 : appendStringLiteralAH(query, nspnames->data, fout);
10999 : 109 : appendPQExpBufferStr(query, "::pg_catalog.name[],");
11000 : 109 : appendStringLiteralAH(query, relnames->data, fout);
11001 : 109 : appendPQExpBufferStr(query, "::pg_catalog.name[])");
155 11002 : 109 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11003 : 109 : destroyPQExpBuffer(query);
11004 : : }
11005 : :
11006 : 1198 : destroyPQExpBuffer(nspnames);
11007 : 1198 : destroyPQExpBuffer(relnames);
11008 : 1198 : return res;
11009 : : }
11010 : :
11011 : : /*
11012 : : * dumpRelationStats_dumper --
11013 : : *
11014 : : * Generate command to import stats into the relation on the new database.
11015 : : * This routine is called by the Archiver when it wants the statistics to be
11016 : : * dumped.
11017 : : */
11018 : : static char *
11019 : 3720 : dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
11020 : : {
11021 : 3720 : const RelStatsInfo *rsinfo = (RelStatsInfo *) userArg;
11022 : : static PGresult *res;
11023 : : static int rownum;
11024 : : PQExpBuffer query;
11025 : : PQExpBufferData out_data;
11026 : 3720 : PQExpBuffer out = &out_data;
11027 : : int i_schemaname;
11028 : : int i_tablename;
11029 : : int i_attname;
11030 : : int i_inherited;
11031 : : int i_null_frac;
11032 : : int i_avg_width;
11033 : : int i_n_distinct;
11034 : : int i_most_common_vals;
11035 : : int i_most_common_freqs;
11036 : : int i_histogram_bounds;
11037 : : int i_correlation;
11038 : : int i_most_common_elems;
11039 : : int i_most_common_elem_freqs;
11040 : : int i_elem_count_histogram;
11041 : : int i_range_length_histogram;
11042 : : int i_range_empty_frac;
11043 : : int i_range_bounds_histogram;
11044 : : static TocEntry *expected_te;
11045 : :
11046 : : /*
11047 : : * fetchAttributeStats() assumes that the statistics are dumped in the
11048 : : * order they are listed in the TOC. We verify that here for safety.
11049 : : */
11050 [ + + ]: 3720 : if (!expected_te)
11051 : 60 : expected_te = ((ArchiveHandle *) fout)->toc;
11052 : :
11053 : 3720 : expected_te = expected_te->next;
11054 [ + + ]: 14912 : while ((expected_te->reqs & REQ_STATS) == 0 ||
11055 [ - + ]: 3720 : strcmp(expected_te->desc, "STATISTICS DATA") != 0)
11056 : 11192 : expected_te = expected_te->next;
11057 : :
11058 [ - + ]: 3720 : if (te != expected_te)
82 peter@eisentraut.org 11059 :UBC 0 : pg_fatal("statistics dumped out of order (current: %d %s %s, expected: %d %s %s)",
11060 : : te->dumpId, te->desc, te->tag,
11061 : : expected_te->dumpId, expected_te->desc, expected_te->tag);
11062 : :
193 jdavis@postgresql.or 11063 :CBC 3720 : query = createPQExpBuffer();
11064 [ + + ]: 3720 : if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
11065 : : {
11066 : 60 : appendPQExpBufferStr(query,
11067 : : "PREPARE getAttributeStats(pg_catalog.name[], pg_catalog.name[]) AS\n"
11068 : : "SELECT s.schemaname, s.tablename, s.attname, s.inherited, "
11069 : : "s.null_frac, s.avg_width, s.n_distinct, "
11070 : : "s.most_common_vals, s.most_common_freqs, "
11071 : : "s.histogram_bounds, s.correlation, "
11072 : : "s.most_common_elems, s.most_common_elem_freqs, "
11073 : : "s.elem_count_histogram, ");
11074 : :
11075 [ + - ]: 60 : if (fout->remoteVersion >= 170000)
11076 : 60 : appendPQExpBufferStr(query,
11077 : : "s.range_length_histogram, "
11078 : : "s.range_empty_frac, "
11079 : : "s.range_bounds_histogram ");
11080 : : else
193 jdavis@postgresql.or 11081 :UBC 0 : appendPQExpBufferStr(query,
11082 : : "NULL AS range_length_histogram,"
11083 : : "NULL AS range_empty_frac,"
11084 : : "NULL AS range_bounds_histogram ");
11085 : :
11086 : : /*
11087 : : * The results must be in the order of the relations supplied in the
11088 : : * parameters to ensure we remain in sync as we walk through the TOC.
11089 : : * The redundant filter clause on s.tablename = ANY(...) seems
11090 : : * sufficient to convince the planner to use
11091 : : * pg_class_relname_nsp_index, which avoids a full scan of pg_stats.
11092 : : * This may not work for all versions.
11093 : : *
11094 : : * Our query for retrieving statistics for multiple relations uses
11095 : : * WITH ORDINALITY and multi-argument UNNEST(), both of which were
11096 : : * introduced in v9.4. For older versions, we resort to gathering
11097 : : * statistics for a single relation at a time.
11098 : : */
155 nathan@postgresql.or 11099 [ + - ]:CBC 60 : if (fout->remoteVersion >= 90400)
11100 : 60 : appendPQExpBufferStr(query,
11101 : : "FROM pg_catalog.pg_stats s "
11102 : : "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) "
11103 : : "ON s.schemaname = u.schemaname "
11104 : : "AND s.tablename = u.tablename "
11105 : : "WHERE s.tablename = ANY($2) "
11106 : : "ORDER BY u.ord, s.attname, s.inherited");
11107 : : else
155 nathan@postgresql.or 11108 :UBC 0 : appendPQExpBufferStr(query,
11109 : : "FROM pg_catalog.pg_stats s "
11110 : : "WHERE s.schemaname = $1[1] "
11111 : : "AND s.tablename = $2[1] "
11112 : : "ORDER BY s.attname, s.inherited");
11113 : :
193 jdavis@postgresql.or 11114 :CBC 60 : ExecuteSqlStatement(fout, query->data);
11115 : :
11116 : 60 : fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
11117 : 60 : resetPQExpBuffer(query);
11118 : : }
11119 : :
155 nathan@postgresql.or 11120 : 3720 : initPQExpBuffer(out);
11121 : :
11122 : : /* restore relation stats */
192 tgl@sss.pgh.pa.us 11123 : 3720 : appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
149 peter@eisentraut.org 11124 : 3720 : appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
11125 : : fout->remoteVersion);
165 jdavis@postgresql.or 11126 : 3720 : appendPQExpBufferStr(out, "\t'schemaname', ");
11127 : 3720 : appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
11128 : 3720 : appendPQExpBufferStr(out, ",\n");
11129 : 3720 : appendPQExpBufferStr(out, "\t'relname', ");
11130 : 3720 : appendStringLiteralAH(out, rsinfo->dobj.name, fout);
11131 : 3720 : appendPQExpBufferStr(out, ",\n");
192 tgl@sss.pgh.pa.us 11132 : 3720 : appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
11133 : :
11134 : : /*
11135 : : * Before v14, a reltuples value of 0 was ambiguous: it could either mean
11136 : : * the relation is empty, or it could mean that it hadn't yet been
11137 : : * vacuumed or analyzed. (Newer versions use -1 for the latter case.)
11138 : : * This ambiguity allegedly can cause the planner to choose inefficient
11139 : : * plans after restoring to v18 or newer. To deal with this, let's just
11140 : : * set reltuples to -1 in that case.
11141 : : */
107 nathan@postgresql.or 11142 [ - + - - ]: 3720 : if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
107 nathan@postgresql.or 11143 :UBC 0 : appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
11144 : : else
107 nathan@postgresql.or 11145 :CBC 3720 : appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
11146 : :
160 jdavis@postgresql.or 11147 : 3720 : appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
192 tgl@sss.pgh.pa.us 11148 : 3720 : rsinfo->relallvisible);
11149 : :
160 jdavis@postgresql.or 11150 [ + - ]: 3720 : if (fout->remoteVersion >= 180000)
11151 : 3720 : appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
11152 : :
11153 : 3720 : appendPQExpBufferStr(out, "\n);\n");
11154 : :
11155 : : /* Fetch the next batch of attribute statistics if needed. */
155 nathan@postgresql.or 11156 [ + + ]: 3720 : if (rownum >= PQntuples(res))
11157 : : {
11158 : 1198 : PQclear(res);
11159 : 1198 : res = fetchAttributeStats(fout);
11160 : 1198 : rownum = 0;
11161 : : }
11162 : :
11163 : 3720 : i_schemaname = PQfnumber(res, "schemaname");
11164 : 3720 : i_tablename = PQfnumber(res, "tablename");
192 tgl@sss.pgh.pa.us 11165 : 3720 : i_attname = PQfnumber(res, "attname");
11166 : 3720 : i_inherited = PQfnumber(res, "inherited");
11167 : 3720 : i_null_frac = PQfnumber(res, "null_frac");
11168 : 3720 : i_avg_width = PQfnumber(res, "avg_width");
11169 : 3720 : i_n_distinct = PQfnumber(res, "n_distinct");
11170 : 3720 : i_most_common_vals = PQfnumber(res, "most_common_vals");
11171 : 3720 : i_most_common_freqs = PQfnumber(res, "most_common_freqs");
11172 : 3720 : i_histogram_bounds = PQfnumber(res, "histogram_bounds");
11173 : 3720 : i_correlation = PQfnumber(res, "correlation");
11174 : 3720 : i_most_common_elems = PQfnumber(res, "most_common_elems");
11175 : 3720 : i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
11176 : 3720 : i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
11177 : 3720 : i_range_length_histogram = PQfnumber(res, "range_length_histogram");
11178 : 3720 : i_range_empty_frac = PQfnumber(res, "range_empty_frac");
11179 : 3720 : i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
11180 : :
11181 : : /* restore attribute stats */
155 nathan@postgresql.or 11182 [ + + ]: 4577 : for (; rownum < PQntuples(res); rownum++)
11183 : : {
11184 : : const char *attname;
11185 : :
11186 : : /* Stop if the next stat row in our cache isn't for this relation. */
11187 [ + + ]: 3379 : if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
11188 [ + - ]: 857 : strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
11189 : : break;
11190 : :
192 tgl@sss.pgh.pa.us 11191 : 857 : appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
149 peter@eisentraut.org 11192 : 857 : appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
11193 : : fout->remoteVersion);
165 jdavis@postgresql.or 11194 : 857 : appendPQExpBufferStr(out, "\t'schemaname', ");
11195 : 857 : appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
11196 : 857 : appendPQExpBufferStr(out, ",\n\t'relname', ");
11197 : 857 : appendStringLiteralAH(out, rsinfo->dobj.name, fout);
11198 : :
192 tgl@sss.pgh.pa.us 11199 [ - + ]: 857 : if (PQgetisnull(res, rownum, i_attname))
82 peter@eisentraut.org 11200 :UBC 0 : pg_fatal("unexpected null attname");
192 tgl@sss.pgh.pa.us 11201 :CBC 857 : attname = PQgetvalue(res, rownum, i_attname);
11202 : :
11203 : : /*
11204 : : * Indexes look up attname in indAttNames to derive attnum, all others
11205 : : * use attname directly. We must specify attnum for indexes, since
11206 : : * their attnames are not necessarily stable across dump/reload.
11207 : : */
11208 [ + + ]: 857 : if (rsinfo->nindAttNames == 0)
11209 : : {
142 drowley@postgresql.o 11210 : 816 : appendPQExpBufferStr(out, ",\n\t'attname', ");
165 jdavis@postgresql.or 11211 : 816 : appendStringLiteralAH(out, attname, fout);
11212 : : }
11213 : : else
11214 : : {
192 tgl@sss.pgh.pa.us 11215 : 41 : bool found = false;
11216 : :
11217 [ + - ]: 78 : for (int i = 0; i < rsinfo->nindAttNames; i++)
11218 : : {
11219 [ + + ]: 78 : if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
11220 : : {
11221 : 41 : appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
11222 : : i + 1);
11223 : 41 : found = true;
11224 : 41 : break;
11225 : : }
11226 : : }
11227 : :
11228 [ - + ]: 41 : if (!found)
192 tgl@sss.pgh.pa.us 11229 :UBC 0 : pg_fatal("could not find index attname \"%s\"", attname);
11230 : : }
11231 : :
192 tgl@sss.pgh.pa.us 11232 [ + - ]:CBC 857 : if (!PQgetisnull(res, rownum, i_inherited))
11233 : 857 : appendNamedArgument(out, fout, "inherited", "boolean",
11234 : 857 : PQgetvalue(res, rownum, i_inherited));
11235 [ + - ]: 857 : if (!PQgetisnull(res, rownum, i_null_frac))
11236 : 857 : appendNamedArgument(out, fout, "null_frac", "real",
11237 : 857 : PQgetvalue(res, rownum, i_null_frac));
11238 [ + - ]: 857 : if (!PQgetisnull(res, rownum, i_avg_width))
11239 : 857 : appendNamedArgument(out, fout, "avg_width", "integer",
11240 : 857 : PQgetvalue(res, rownum, i_avg_width));
11241 [ + - ]: 857 : if (!PQgetisnull(res, rownum, i_n_distinct))
11242 : 857 : appendNamedArgument(out, fout, "n_distinct", "real",
11243 : 857 : PQgetvalue(res, rownum, i_n_distinct));
11244 [ + + ]: 857 : if (!PQgetisnull(res, rownum, i_most_common_vals))
11245 : 441 : appendNamedArgument(out, fout, "most_common_vals", "text",
11246 : 441 : PQgetvalue(res, rownum, i_most_common_vals));
11247 [ + + ]: 857 : if (!PQgetisnull(res, rownum, i_most_common_freqs))
11248 : 441 : appendNamedArgument(out, fout, "most_common_freqs", "real[]",
11249 : 441 : PQgetvalue(res, rownum, i_most_common_freqs));
11250 [ + + ]: 857 : if (!PQgetisnull(res, rownum, i_histogram_bounds))
11251 : 538 : appendNamedArgument(out, fout, "histogram_bounds", "text",
11252 : 538 : PQgetvalue(res, rownum, i_histogram_bounds));
11253 [ + + ]: 857 : if (!PQgetisnull(res, rownum, i_correlation))
11254 : 817 : appendNamedArgument(out, fout, "correlation", "real",
11255 : 817 : PQgetvalue(res, rownum, i_correlation));
11256 [ + + ]: 857 : if (!PQgetisnull(res, rownum, i_most_common_elems))
11257 : 8 : appendNamedArgument(out, fout, "most_common_elems", "text",
11258 : 8 : PQgetvalue(res, rownum, i_most_common_elems));
11259 [ + + ]: 857 : if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
11260 : 8 : appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
11261 : 8 : PQgetvalue(res, rownum, i_most_common_elem_freqs));
11262 [ + + ]: 857 : if (!PQgetisnull(res, rownum, i_elem_count_histogram))
11263 : 7 : appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
11264 : 7 : PQgetvalue(res, rownum, i_elem_count_histogram));
11265 [ + - ]: 857 : if (fout->remoteVersion >= 170000)
11266 : : {
11267 [ + + ]: 857 : if (!PQgetisnull(res, rownum, i_range_length_histogram))
11268 : 4 : appendNamedArgument(out, fout, "range_length_histogram", "text",
11269 : 4 : PQgetvalue(res, rownum, i_range_length_histogram));
11270 [ + + ]: 857 : if (!PQgetisnull(res, rownum, i_range_empty_frac))
11271 : 4 : appendNamedArgument(out, fout, "range_empty_frac", "real",
11272 : 4 : PQgetvalue(res, rownum, i_range_empty_frac));
11273 [ + + ]: 857 : if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
11274 : 4 : appendNamedArgument(out, fout, "range_bounds_histogram", "text",
11275 : 4 : PQgetvalue(res, rownum, i_range_bounds_histogram));
11276 : : }
11277 : 857 : appendPQExpBufferStr(out, "\n);\n");
11278 : : }
11279 : :
155 nathan@postgresql.or 11280 : 3720 : destroyPQExpBuffer(query);
11281 : 3720 : return out->data;
11282 : : }
11283 : :
11284 : : /*
11285 : : * dumpRelationStats --
11286 : : *
11287 : : * Make an ArchiveEntry for the relation statistics. The Archiver will take
11288 : : * care of gathering the statistics and generating the restore commands when
11289 : : * they are needed.
11290 : : */
11291 : : static void
11292 : 3792 : dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
11293 : : {
11294 : 3792 : const DumpableObject *dobj = &rsinfo->dobj;
11295 : :
11296 : : /* nothing to do if we are not dumping statistics */
11297 [ - + ]: 3792 : if (!fout->dopt->dumpStatistics)
155 nathan@postgresql.or 11298 :UBC 0 : return;
11299 : :
198 jdavis@postgresql.or 11300 :CBC 3792 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
191 11301 : 3792 : ARCHIVE_OPTS(.tag = dobj->name,
11302 : : .namespace = dobj->namespace->dobj.name,
11303 : : .description = "STATISTICS DATA",
11304 : : .section = rsinfo->section,
11305 : : .defnFn = dumpRelationStats_dumper,
11306 : : .defnArg = rsinfo,
11307 : : .deps = dobj->dependencies,
11308 : : .nDeps = dobj->nDeps));
11309 : : }
11310 : :
11311 : : /*
11312 : : * dumpTableComment --
11313 : : *
11314 : : * As above, but dump comments for both the specified table (or view)
11315 : : * and its columns.
11316 : : */
11317 : : static void
1669 peter@eisentraut.org 11318 : 86 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
11319 : : const char *reltypename)
11320 : : {
3524 tgl@sss.pgh.pa.us 11321 : 86 : DumpOptions *dopt = fout->dopt;
11322 : : CommentItem *comments;
11323 : : int ncomments;
11324 : : PQExpBuffer query;
11325 : : PQExpBuffer tag;
11326 : :
11327 : : /* do nothing, if --no-comments is supplied */
2781 11328 [ - + ]: 86 : if (dopt->no_comments)
2781 tgl@sss.pgh.pa.us 11329 :UBC 0 : return;
11330 : :
11331 : : /* Comments are SCHEMA not data */
285 nathan@postgresql.or 11332 [ - + ]:CBC 86 : if (!dopt->dumpSchema)
8520 tgl@sss.pgh.pa.us 11333 :UBC 0 : return;
11334 : :
11335 : : /* Search for comments associated with relation, using table */
1346 tgl@sss.pgh.pa.us 11336 :CBC 86 : ncomments = findComments(tbinfo->dobj.catId.tableoid,
7840 11337 : 86 : tbinfo->dobj.catId.oid,
11338 : : &comments);
11339 : :
11340 : : /* If comments exist, build COMMENT ON statements */
11341 [ - + ]: 86 : if (ncomments <= 0)
7840 tgl@sss.pgh.pa.us 11342 :UBC 0 : return;
11343 : :
8520 tgl@sss.pgh.pa.us 11344 :CBC 86 : query = createPQExpBuffer();
2749 11345 : 86 : tag = createPQExpBuffer();
11346 : :
7840 11347 [ + + ]: 248 : while (ncomments > 0)
11348 : : {
11349 : 162 : const char *descr = comments->descr;
11350 : 162 : int objsubid = comments->objsubid;
11351 : :
8520 11352 [ + + ]: 162 : if (objsubid == 0)
11353 : : {
2749 11354 : 38 : resetPQExpBuffer(tag);
11355 : 38 : appendPQExpBuffer(tag, "%s %s", reltypename,
7857 11356 : 38 : fmtId(tbinfo->dobj.name));
11357 : :
8520 11358 : 38 : resetPQExpBuffer(query);
2749 11359 : 38 : appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
11360 : 38 : fmtQualifiedDumpable(tbinfo));
7041 11361 : 38 : appendStringLiteralAH(query, descr, fout);
4310 heikki.linnakangas@i 11362 : 38 : appendPQExpBufferStr(query, ";\n");
11363 : :
7945 tgl@sss.pgh.pa.us 11364 : 38 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 11365 : 38 : ARCHIVE_OPTS(.tag = tag->data,
11366 : : .namespace = tbinfo->dobj.namespace->dobj.name,
11367 : : .owner = tbinfo->rolname,
11368 : : .description = "COMMENT",
11369 : : .section = SECTION_NONE,
11370 : : .createStmt = query->data,
11371 : : .deps = &(tbinfo->dobj.dumpId),
11372 : : .nDeps = 1));
11373 : : }
8520 tgl@sss.pgh.pa.us 11374 [ + - + - ]: 124 : else if (objsubid > 0 && objsubid <= tbinfo->numatts)
11375 : : {
2749 11376 : 124 : resetPQExpBuffer(tag);
11377 : 124 : appendPQExpBuffer(tag, "COLUMN %s.",
7857 11378 : 124 : fmtId(tbinfo->dobj.name));
2749 11379 : 124 : appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
11380 : :
8520 11381 : 124 : resetPQExpBuffer(query);
2749 11382 : 124 : appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11383 : 124 : fmtQualifiedDumpable(tbinfo));
11384 : 124 : appendPQExpBuffer(query, "%s IS ",
11385 : 124 : fmtId(tbinfo->attnames[objsubid - 1]));
7041 11386 : 124 : appendStringLiteralAH(query, descr, fout);
4310 heikki.linnakangas@i 11387 : 124 : appendPQExpBufferStr(query, ";\n");
11388 : :
7945 tgl@sss.pgh.pa.us 11389 : 124 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 11390 : 124 : ARCHIVE_OPTS(.tag = tag->data,
11391 : : .namespace = tbinfo->dobj.namespace->dobj.name,
11392 : : .owner = tbinfo->rolname,
11393 : : .description = "COMMENT",
11394 : : .section = SECTION_NONE,
11395 : : .createStmt = query->data,
11396 : : .deps = &(tbinfo->dobj.dumpId),
11397 : : .nDeps = 1));
11398 : : }
11399 : :
7840 tgl@sss.pgh.pa.us 11400 : 162 : comments++;
11401 : 162 : ncomments--;
11402 : : }
11403 : :
8800 11404 : 86 : destroyPQExpBuffer(query);
2749 11405 : 86 : destroyPQExpBuffer(tag);
11406 : : }
11407 : :
11408 : : /*
11409 : : * findComments --
11410 : : *
11411 : : * Find the comment(s), if any, associated with the given object. All the
11412 : : * objsubid values associated with the given classoid/objoid are found with
11413 : : * one search.
11414 : : */
11415 : : static int
1346 11416 : 6790 : findComments(Oid classoid, Oid objoid, CommentItem **items)
11417 : : {
7840 11418 : 6790 : CommentItem *middle = NULL;
11419 : : CommentItem *low;
11420 : : CommentItem *high;
11421 : : int nmatch;
11422 : :
11423 : : /*
11424 : : * Do binary search to find some item matching the object.
11425 : : */
11426 : 6790 : low = &comments[0];
7678 bruce@momjian.us 11427 : 6790 : high = &comments[ncomments - 1];
7840 tgl@sss.pgh.pa.us 11428 [ + + ]: 67878 : while (low <= high)
11429 : : {
11430 : 67831 : middle = low + (high - low) / 2;
11431 : :
11432 [ + + ]: 67831 : if (classoid < middle->classoid)
11433 : 7763 : high = middle - 1;
11434 [ + + ]: 60068 : else if (classoid > middle->classoid)
11435 : 7326 : low = middle + 1;
11436 [ + + ]: 52742 : else if (objoid < middle->objoid)
11437 : 22411 : high = middle - 1;
11438 [ + + ]: 30331 : else if (objoid > middle->objoid)
11439 : 23588 : low = middle + 1;
11440 : : else
11441 : 6743 : break; /* found a match */
11442 : : }
11443 : :
11444 [ + + ]: 6790 : if (low > high) /* no matches */
11445 : : {
11446 : 47 : *items = NULL;
11447 : 47 : return 0;
11448 : : }
11449 : :
11450 : : /*
11451 : : * Now determine how many items match the object. The search loop
11452 : : * invariant still holds: only items between low and high inclusive could
11453 : : * match.
11454 : : */
11455 : 6743 : nmatch = 1;
11456 [ + + ]: 6819 : while (middle > low)
11457 : : {
11458 [ + + ]: 3302 : if (classoid != middle[-1].classoid ||
11459 [ + + ]: 3123 : objoid != middle[-1].objoid)
11460 : : break;
7840 tgl@sss.pgh.pa.us 11461 :GBC 76 : middle--;
11462 : 76 : nmatch++;
11463 : : }
11464 : :
7840 tgl@sss.pgh.pa.us 11465 :CBC 6743 : *items = middle;
11466 : :
11467 : 6743 : middle += nmatch;
11468 [ + + ]: 6743 : while (middle <= high)
11469 : : {
11470 [ + + ]: 3494 : if (classoid != middle->classoid ||
11471 [ - + ]: 3238 : objoid != middle->objoid)
11472 : : break;
7840 tgl@sss.pgh.pa.us 11473 :LBC (76) : middle++;
11474 : (76) : nmatch++;
11475 : : }
11476 : :
7840 tgl@sss.pgh.pa.us 11477 :CBC 6743 : return nmatch;
11478 : : }
11479 : :
11480 : : /*
11481 : : * collectComments --
11482 : : *
11483 : : * Construct a table of all comments available for database objects;
11484 : : * also set the has-comment component flag for each relevant object.
11485 : : *
11486 : : * We used to do per-object queries for the comments, but it's much faster
11487 : : * to pull them all over at once, and on most databases the memory cost
11488 : : * isn't high.
11489 : : *
11490 : : * The table is sorted by classoid/objid/objsubid for speed in lookup.
11491 : : */
11492 : : static void
1370 11493 : 185 : collectComments(Archive *fout)
11494 : : {
11495 : : PGresult *res;
11496 : : PQExpBuffer query;
11497 : : int i_description;
11498 : : int i_classoid;
11499 : : int i_objoid;
11500 : : int i_objsubid;
11501 : : int ntups;
11502 : : int i;
11503 : : DumpableObject *dobj;
11504 : :
7840 11505 : 185 : query = createPQExpBuffer();
11506 : :
3251 11507 : 185 : appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
11508 : : "FROM pg_catalog.pg_description "
11509 : : "ORDER BY classoid, objoid, objsubid");
11510 : :
4960 rhaas@postgresql.org 11511 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11512 : :
11513 : : /* Construct lookup table containing OIDs in numeric form */
11514 : :
7840 tgl@sss.pgh.pa.us 11515 : 185 : i_description = PQfnumber(res, "description");
11516 : 185 : i_classoid = PQfnumber(res, "classoid");
11517 : 185 : i_objoid = PQfnumber(res, "objoid");
11518 : 185 : i_objsubid = PQfnumber(res, "objsubid");
11519 : :
11520 : 185 : ntups = PQntuples(res);
11521 : :
5034 bruce@momjian.us 11522 : 185 : comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
1370 tgl@sss.pgh.pa.us 11523 : 185 : ncomments = 0;
11524 : 185 : dobj = NULL;
11525 : :
7840 11526 [ + + ]: 993463 : for (i = 0; i < ntups; i++)
11527 : : {
11528 : : CatalogId objId;
11529 : : int subid;
11530 : :
1370 11531 : 993278 : objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
11532 : 993278 : objId.oid = atooid(PQgetvalue(res, i, i_objoid));
11533 : 993278 : subid = atoi(PQgetvalue(res, i, i_objsubid));
11534 : :
11535 : : /* We needn't remember comments that don't match any dumpable object */
11536 [ + + ]: 993278 : if (dobj == NULL ||
11537 [ + + ]: 362930 : dobj->catId.tableoid != objId.tableoid ||
11538 [ + + ]: 360676 : dobj->catId.oid != objId.oid)
11539 : 993176 : dobj = findObjectByCatalogId(objId);
11540 [ + + ]: 993278 : if (dobj == NULL)
11541 : 630169 : continue;
11542 : :
11543 : : /*
11544 : : * Comments on columns of composite types are linked to the type's
11545 : : * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
11546 : : * in the type's own DumpableObject.
11547 : : */
11548 [ + + + - ]: 363109 : if (subid != 0 && dobj->objType == DO_TABLE &&
11549 [ + + ]: 218 : ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
11550 : 51 : {
11551 : : TypeInfo *cTypeInfo;
11552 : :
11553 : 51 : cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
11554 [ + - ]: 51 : if (cTypeInfo)
11555 : 51 : cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
11556 : : }
11557 : : else
11558 : 363058 : dobj->components |= DUMP_COMPONENT_COMMENT;
11559 : :
11560 : 363109 : comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
11561 : 363109 : comments[ncomments].classoid = objId.tableoid;
11562 : 363109 : comments[ncomments].objoid = objId.oid;
11563 : 363109 : comments[ncomments].objsubid = subid;
11564 : 363109 : ncomments++;
11565 : : }
11566 : :
11567 : 185 : PQclear(res);
7840 11568 : 185 : destroyPQExpBuffer(query);
11569 : 185 : }
11570 : :
11571 : : /*
11572 : : * dumpDumpableObject
11573 : : *
11574 : : * This routine and its subsidiaries are responsible for creating
11575 : : * ArchiveEntries (TOC objects) for each object to be dumped.
11576 : : */
11577 : : static void
1370 11578 : 819195 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
11579 : : {
11580 : : /*
11581 : : * Clear any dump-request bits for components that don't exist for this
11582 : : * object. (This makes it safe to initially use DUMP_COMPONENT_ALL as the
11583 : : * request for every kind of object.)
11584 : : */
11585 : 819195 : dobj->dump &= dobj->components;
11586 : :
11587 : : /* Now, short-circuit if there's nothing to be done here. */
11588 [ + + ]: 819195 : if (dobj->dump == 0)
11589 : 738209 : return;
11590 : :
7945 11591 [ + + + + : 80986 : switch (dobj->objType)
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + - ]
11592 : : {
11593 : 495 : case DO_NAMESPACE:
1669 peter@eisentraut.org 11594 : 495 : dumpNamespace(fout, (const NamespaceInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11595 : 495 : break;
5324 11596 : 19 : case DO_EXTENSION:
1669 peter@eisentraut.org 11597 : 19 : dumpExtension(fout, (const ExtensionInfo *) dobj);
5324 tgl@sss.pgh.pa.us 11598 : 19 : break;
7945 11599 : 968 : case DO_TYPE:
1669 peter@eisentraut.org 11600 : 968 : dumpType(fout, (const TypeInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11601 : 968 : break;
7128 11602 : 79 : case DO_SHELL_TYPE:
1669 peter@eisentraut.org 11603 : 79 : dumpShellType(fout, (const ShellTypeInfo *) dobj);
7128 tgl@sss.pgh.pa.us 11604 : 79 : break;
7945 11605 : 1873 : case DO_FUNC:
1669 peter@eisentraut.org 11606 : 1873 : dumpFunc(fout, (const FuncInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11607 : 1873 : break;
11608 : 298 : case DO_AGG:
1669 peter@eisentraut.org 11609 : 298 : dumpAgg(fout, (const AggInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11610 : 298 : break;
11611 : 2510 : case DO_OPERATOR:
1669 peter@eisentraut.org 11612 : 2510 : dumpOpr(fout, (const OprInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11613 : 2510 : break;
3454 alvherre@alvh.no-ip. 11614 : 92 : case DO_ACCESS_METHOD:
1669 peter@eisentraut.org 11615 : 92 : dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
3454 alvherre@alvh.no-ip. 11616 : 92 : break;
7945 tgl@sss.pgh.pa.us 11617 : 678 : case DO_OPCLASS:
1669 peter@eisentraut.org 11618 : 678 : dumpOpclass(fout, (const OpclassInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11619 : 678 : break;
6801 11620 : 561 : case DO_OPFAMILY:
1669 peter@eisentraut.org 11621 : 561 : dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
6801 tgl@sss.pgh.pa.us 11622 : 561 : break;
5320 peter_e@gmx.net 11623 : 4655 : case DO_COLLATION:
1669 peter@eisentraut.org 11624 : 4655 : dumpCollation(fout, (const CollInfo *) dobj);
5320 peter_e@gmx.net 11625 : 4655 : break;
7945 tgl@sss.pgh.pa.us 11626 : 428 : case DO_CONVERSION:
1669 peter@eisentraut.org 11627 : 428 : dumpConversion(fout, (const ConvInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11628 : 428 : break;
11629 : 31135 : case DO_TABLE:
1669 peter@eisentraut.org 11630 : 31135 : dumpTable(fout, (const TableInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11631 : 31135 : break;
1699 11632 : 1435 : case DO_TABLE_ATTACH:
1669 peter@eisentraut.org 11633 : 1435 : dumpTableAttach(fout, (const TableAttachInfo *) dobj);
1699 tgl@sss.pgh.pa.us 11634 : 1435 : break;
7945 11635 : 1104 : case DO_ATTRDEF:
1669 peter@eisentraut.org 11636 : 1104 : dumpAttrDef(fout, (const AttrDefInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11637 : 1104 : break;
11638 : 2688 : case DO_INDEX:
1669 peter@eisentraut.org 11639 : 2688 : dumpIndex(fout, (const IndxInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11640 : 2688 : break;
2787 alvherre@alvh.no-ip. 11641 : 612 : case DO_INDEX_ATTACH:
1669 peter@eisentraut.org 11642 : 612 : dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
2787 alvherre@alvh.no-ip. 11643 : 612 : break;
3088 11644 : 151 : case DO_STATSEXT:
1669 peter@eisentraut.org 11645 : 151 : dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
3088 alvherre@alvh.no-ip. 11646 : 151 : break;
4570 kgrittn@postgresql.o 11647 : 432 : case DO_REFRESH_MATVIEW:
1669 peter@eisentraut.org 11648 : 432 : refreshMatViewData(fout, (const TableDataInfo *) dobj);
4570 kgrittn@postgresql.o 11649 : 432 : break;
7945 tgl@sss.pgh.pa.us 11650 : 1223 : case DO_RULE:
1669 peter@eisentraut.org 11651 : 1223 : dumpRule(fout, (const RuleInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11652 : 1223 : break;
11653 : 553 : case DO_TRIGGER:
1669 peter@eisentraut.org 11654 : 553 : dumpTrigger(fout, (const TriggerInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11655 : 553 : break;
4798 rhaas@postgresql.org 11656 : 48 : case DO_EVENT_TRIGGER:
1669 peter@eisentraut.org 11657 : 48 : dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
4798 rhaas@postgresql.org 11658 : 48 : break;
7945 tgl@sss.pgh.pa.us 11659 : 2462 : case DO_CONSTRAINT:
1669 peter@eisentraut.org 11660 : 2462 : dumpConstraint(fout, (const ConstraintInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11661 : 2462 : break;
11662 : 183 : case DO_FK_CONSTRAINT:
1669 peter@eisentraut.org 11663 : 183 : dumpConstraint(fout, (const ConstraintInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11664 : 183 : break;
11665 : 94 : case DO_PROCLANG:
1669 peter@eisentraut.org 11666 : 94 : dumpProcLang(fout, (const ProcLangInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11667 : 94 : break;
11668 : 73 : case DO_CAST:
1669 peter@eisentraut.org 11669 : 73 : dumpCast(fout, (const CastInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11670 : 73 : break;
3786 peter_e@gmx.net 11671 : 48 : case DO_TRANSFORM:
1669 peter@eisentraut.org 11672 : 48 : dumpTransform(fout, (const TransformInfo *) dobj);
3786 peter_e@gmx.net 11673 : 48 : break;
3301 11674 : 411 : case DO_SEQUENCE_SET:
1669 peter@eisentraut.org 11675 : 411 : dumpSequenceData(fout, (const TableDataInfo *) dobj);
3301 peter_e@gmx.net 11676 : 411 : break;
7945 tgl@sss.pgh.pa.us 11677 : 4496 : case DO_TABLE_DATA:
1669 peter@eisentraut.org 11678 : 4496 : dumpTableData(fout, (const TableDataInfo *) dobj);
7945 tgl@sss.pgh.pa.us 11679 : 4496 : break;
6075 11680 : 14929 : case DO_DUMMY_TYPE:
11681 : : /* table rowtypes and array types are never dumped separately */
7857 11682 : 14929 : break;
6591 11683 : 47 : case DO_TSPARSER:
1669 peter@eisentraut.org 11684 : 47 : dumpTSParser(fout, (const TSParserInfo *) dobj);
6591 tgl@sss.pgh.pa.us 11685 : 47 : break;
11686 : 179 : case DO_TSDICT:
1669 peter@eisentraut.org 11687 : 179 : dumpTSDictionary(fout, (const TSDictInfo *) dobj);
6591 tgl@sss.pgh.pa.us 11688 : 179 : break;
11689 : 59 : case DO_TSTEMPLATE:
1669 peter@eisentraut.org 11690 : 59 : dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
6591 tgl@sss.pgh.pa.us 11691 : 59 : break;
11692 : 154 : case DO_TSCONFIG:
1669 peter@eisentraut.org 11693 : 154 : dumpTSConfig(fout, (const TSConfigInfo *) dobj);
6591 tgl@sss.pgh.pa.us 11694 : 154 : break;
6105 peter_e@gmx.net 11695 : 58 : case DO_FDW:
1669 peter@eisentraut.org 11696 : 58 : dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
6105 peter_e@gmx.net 11697 : 58 : break;
11698 : 62 : case DO_FOREIGN_SERVER:
1669 peter@eisentraut.org 11699 : 62 : dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
6105 peter_e@gmx.net 11700 : 62 : break;
5815 tgl@sss.pgh.pa.us 11701 : 184 : case DO_DEFAULT_ACL:
1669 peter@eisentraut.org 11702 : 184 : dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
5815 tgl@sss.pgh.pa.us 11703 : 184 : break;
1006 peter@eisentraut.org 11704 : 84 : case DO_LARGE_OBJECT:
11705 : 84 : dumpLO(fout, (const LoInfo *) dobj);
5679 tgl@sss.pgh.pa.us 11706 : 84 : break;
1006 peter@eisentraut.org 11707 : 85 : case DO_LARGE_OBJECT_DATA:
3440 sfrost@snowman.net 11708 [ + - ]: 85 : if (dobj->dump & DUMP_COMPONENT_DATA)
11709 : : {
11710 : : LoInfo *loinfo;
11711 : : TocEntry *te;
11712 : :
523 tgl@sss.pgh.pa.us 11713 : 85 : loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
11714 [ - + ]: 85 : if (loinfo == NULL)
523 tgl@sss.pgh.pa.us 11715 :UBC 0 : pg_fatal("missing metadata for large objects \"%s\"",
11716 : : dobj->name);
11717 : :
2549 tgl@sss.pgh.pa.us 11718 :CBC 85 : te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
2409 alvherre@alvh.no-ip. 11719 : 85 : ARCHIVE_OPTS(.tag = dobj->name,
11720 : : .owner = loinfo->rolname,
11721 : : .description = "BLOBS",
11722 : : .section = SECTION_DATA,
11723 : : .deps = dobj->dependencies,
11724 : : .nDeps = dobj->nDeps,
11725 : : .dumpFn = dumpLOs,
11726 : : .dumpArg = loinfo));
11727 : :
11728 : : /*
11729 : : * Set the TocEntry's dataLength in case we are doing a
11730 : : * parallel dump and want to order dump jobs by table size.
11731 : : * (We need some size estimate for every TocEntry with a
11732 : : * DataDumper function.) We don't currently have any cheap
11733 : : * way to estimate the size of LOs, but fortunately it doesn't
11734 : : * matter too much as long as we get large batches of LOs
11735 : : * processed reasonably early. Assume 8K per blob.
11736 : : */
523 tgl@sss.pgh.pa.us 11737 : 85 : te->dataLength = loinfo->numlos * (pgoff_t) 8192;
11738 : : }
7857 11739 : 85 : break;
3936 sfrost@snowman.net 11740 : 368 : case DO_POLICY:
1669 peter@eisentraut.org 11741 : 368 : dumpPolicy(fout, (const PolicyInfo *) dobj);
4005 sfrost@snowman.net 11742 : 368 : break;
3152 peter_e@gmx.net 11743 : 241 : case DO_PUBLICATION:
1669 peter@eisentraut.org 11744 : 241 : dumpPublication(fout, (const PublicationInfo *) dobj);
3152 peter_e@gmx.net 11745 : 241 : break;
11746 : 326 : case DO_PUBLICATION_REL:
1669 peter@eisentraut.org 11747 : 326 : dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
3152 peter_e@gmx.net 11748 : 326 : break;
1397 akapila@postgresql.o 11749 : 111 : case DO_PUBLICATION_TABLE_IN_SCHEMA:
1410 11750 : 111 : dumpPublicationNamespace(fout,
11751 : : (const PublicationSchemaInfo *) dobj);
11752 : 111 : break;
3152 peter_e@gmx.net 11753 : 131 : case DO_SUBSCRIPTION:
1669 peter@eisentraut.org 11754 : 131 : dumpSubscription(fout, (const SubscriptionInfo *) dobj);
3152 peter_e@gmx.net 11755 : 131 : break;
613 akapila@postgresql.o 11756 : 2 : case DO_SUBSCRIPTION_REL:
11757 : 2 : dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
11758 : 2 : break;
198 jdavis@postgresql.or 11759 : 3792 : case DO_REL_STATS:
11760 : 3792 : dumpRelationStats(fout, (const RelStatsInfo *) dobj);
11761 : 3792 : break;
4821 tgl@sss.pgh.pa.us 11762 : 370 : case DO_PRE_DATA_BOUNDARY:
11763 : : case DO_POST_DATA_BOUNDARY:
11764 : : /* never dumped, nothing to do */
11765 : 370 : break;
11766 : : }
11767 : : }
11768 : :
11769 : : /*
11770 : : * dumpNamespace
11771 : : * writes out to fout the queries to recreate a user-defined namespace
11772 : : */
11773 : : static void
1669 peter@eisentraut.org 11774 : 495 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
11775 : : {
3524 tgl@sss.pgh.pa.us 11776 : 495 : DumpOptions *dopt = fout->dopt;
11777 : : PQExpBuffer q;
11778 : : PQExpBuffer delq;
11779 : : char *qnspname;
11780 : :
11781 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 11782 [ + + ]: 495 : if (!dopt->dumpSchema)
7945 tgl@sss.pgh.pa.us 11783 : 28 : return;
11784 : :
11785 : 467 : q = createPQExpBuffer();
11786 : 467 : delq = createPQExpBuffer();
11787 : :
5034 bruce@momjian.us 11788 : 467 : qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
11789 : :
1531 noah@leadboat.com 11790 [ + + ]: 467 : if (nspinfo->create)
11791 : : {
11792 : 317 : appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
11793 : 317 : appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
11794 : : }
11795 : : else
11796 : : {
11797 : : /* see selectDumpableNamespace() */
11798 : 150 : appendPQExpBufferStr(delq,
11799 : : "-- *not* dropping schema, since initdb creates it\n");
11800 : 150 : appendPQExpBufferStr(q,
11801 : : "-- *not* creating schema, since initdb creates it\n");
11802 : : }
11803 : :
3980 alvherre@alvh.no-ip. 11804 [ + + ]: 467 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 11805 : 90 : binary_upgrade_extension_member(q, &nspinfo->dobj,
11806 : : "SCHEMA", qnspname, NULL);
11807 : :
3440 sfrost@snowman.net 11808 [ + + ]: 467 : if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11809 : 203 : ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 11810 : 203 : ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
11811 : : .owner = nspinfo->rolname,
11812 : : .description = "SCHEMA",
11813 : : .section = SECTION_PRE_DATA,
11814 : : .createStmt = q->data,
11815 : : .dropStmt = delq->data));
11816 : :
11817 : : /* Dump Schema Comments and Security Labels */
3440 sfrost@snowman.net 11818 [ + + ]: 467 : if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11819 : : {
1531 noah@leadboat.com 11820 : 155 : const char *initdb_comment = NULL;
11821 : :
11822 [ + + + + ]: 155 : if (!nspinfo->create && strcmp(qnspname, "public") == 0)
1362 tgl@sss.pgh.pa.us 11823 : 116 : initdb_comment = "standard public schema";
1531 noah@leadboat.com 11824 : 155 : dumpCommentExtended(fout, "SCHEMA", qnspname,
11825 : 155 : NULL, nspinfo->rolname,
11826 : 155 : nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
11827 : : initdb_comment);
11828 : : }
11829 : :
3440 sfrost@snowman.net 11830 [ - + ]: 467 : if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 11831 :UBC 0 : dumpSecLabel(fout, "SCHEMA", qnspname,
3440 sfrost@snowman.net 11832 : 0 : NULL, nspinfo->rolname,
11833 : 0 : nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
11834 : :
3440 sfrost@snowman.net 11835 [ + + ]:CBC 467 : if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
1883 tgl@sss.pgh.pa.us 11836 : 359 : dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
11837 : : qnspname, NULL, NULL,
523 11838 : 359 : NULL, nspinfo->rolname, &nspinfo->dacl);
11839 : :
7945 11840 : 467 : free(qnspname);
11841 : :
8520 11842 : 467 : destroyPQExpBuffer(q);
11843 : 467 : destroyPQExpBuffer(delq);
11844 : : }
11845 : :
11846 : : /*
11847 : : * dumpExtension
11848 : : * writes out to fout the queries to recreate an extension
11849 : : */
11850 : : static void
1669 peter@eisentraut.org 11851 : 19 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
11852 : : {
3524 tgl@sss.pgh.pa.us 11853 : 19 : DumpOptions *dopt = fout->dopt;
11854 : : PQExpBuffer q;
11855 : : PQExpBuffer delq;
11856 : : char *qextname;
11857 : :
11858 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 11859 [ + + ]: 19 : if (!dopt->dumpSchema)
5324 tgl@sss.pgh.pa.us 11860 : 1 : return;
11861 : :
11862 : 18 : q = createPQExpBuffer();
11863 : 18 : delq = createPQExpBuffer();
11864 : :
5034 bruce@momjian.us 11865 : 18 : qextname = pg_strdup(fmtId(extinfo->dobj.name));
11866 : :
5324 tgl@sss.pgh.pa.us 11867 : 18 : appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
11868 : :
3980 alvherre@alvh.no-ip. 11869 [ + + ]: 18 : if (!dopt->binary_upgrade)
11870 : : {
11871 : : /*
11872 : : * In a regular dump, we simply create the extension, intentionally
11873 : : * not specifying a version, so that the destination installation's
11874 : : * default version is used.
11875 : : *
11876 : : * Use of IF NOT EXISTS here is unlike our behavior for other object
11877 : : * types; but there are various scenarios in which it's convenient to
11878 : : * manually create the desired extension before restoring, so we
11879 : : * prefer to allow it to exist already.
11880 : : */
5300 tgl@sss.pgh.pa.us 11881 : 17 : appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
5323 11882 : 17 : qextname, fmtId(extinfo->namespace));
11883 : : }
11884 : : else
11885 : : {
11886 : : /*
11887 : : * In binary-upgrade mode, it's critical to reproduce the state of the
11888 : : * database exactly, so our procedure is to create an empty extension,
11889 : : * restore all the contained objects normally, and add them to the
11890 : : * extension one by one. This function performs just the first of
11891 : : * those steps. binary_upgrade_extension_member() takes care of
11892 : : * adding member objects as they're created.
11893 : : */
11894 : : int i;
11895 : : int n;
11896 : :
4310 heikki.linnakangas@i 11897 : 1 : appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
11898 : :
11899 : : /*
11900 : : * We unconditionally create the extension, so we must drop it if it
11901 : : * exists. This could happen if the user deleted 'plpgsql' and then
11902 : : * readded it, causing its oid to be greater than g_last_builtin_oid.
11903 : : */
4812 bruce@momjian.us 11904 : 1 : appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
11905 : :
4310 heikki.linnakangas@i 11906 : 1 : appendPQExpBufferStr(q,
11907 : : "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
5323 tgl@sss.pgh.pa.us 11908 : 1 : appendStringLiteralAH(q, extinfo->dobj.name, fout);
4310 heikki.linnakangas@i 11909 : 1 : appendPQExpBufferStr(q, ", ");
5323 tgl@sss.pgh.pa.us 11910 : 1 : appendStringLiteralAH(q, extinfo->namespace, fout);
4310 heikki.linnakangas@i 11911 : 1 : appendPQExpBufferStr(q, ", ");
5323 tgl@sss.pgh.pa.us 11912 [ + - ]: 1 : appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
5321 11913 : 1 : appendStringLiteralAH(q, extinfo->extversion, fout);
4310 heikki.linnakangas@i 11914 : 1 : appendPQExpBufferStr(q, ", ");
11915 : :
11916 : : /*
11917 : : * Note that we're pushing extconfig (an OID array) back into
11918 : : * pg_extension exactly as-is. This is OK because pg_class OIDs are
11919 : : * preserved in binary upgrade.
11920 : : */
5323 tgl@sss.pgh.pa.us 11921 [ + - ]: 1 : if (strlen(extinfo->extconfig) > 2)
11922 : 1 : appendStringLiteralAH(q, extinfo->extconfig, fout);
11923 : : else
4310 heikki.linnakangas@i 11924 :UBC 0 : appendPQExpBufferStr(q, "NULL");
4310 heikki.linnakangas@i 11925 :CBC 1 : appendPQExpBufferStr(q, ", ");
5323 tgl@sss.pgh.pa.us 11926 [ + - ]: 1 : if (strlen(extinfo->extcondition) > 2)
11927 : 1 : appendStringLiteralAH(q, extinfo->extcondition, fout);
11928 : : else
4310 heikki.linnakangas@i 11929 :UBC 0 : appendPQExpBufferStr(q, "NULL");
4310 heikki.linnakangas@i 11930 :CBC 1 : appendPQExpBufferStr(q, ", ");
11931 : 1 : appendPQExpBufferStr(q, "ARRAY[");
5323 tgl@sss.pgh.pa.us 11932 : 1 : n = 0;
11933 [ + + ]: 2 : for (i = 0; i < extinfo->dobj.nDeps; i++)
11934 : : {
11935 : : DumpableObject *extobj;
11936 : :
11937 : 1 : extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
11938 [ + - - + ]: 1 : if (extobj && extobj->objType == DO_EXTENSION)
11939 : : {
5323 tgl@sss.pgh.pa.us 11940 [ # # ]:UBC 0 : if (n++ > 0)
4310 heikki.linnakangas@i 11941 : 0 : appendPQExpBufferChar(q, ',');
5323 tgl@sss.pgh.pa.us 11942 : 0 : appendStringLiteralAH(q, extobj->name, fout);
11943 : : }
11944 : : }
4310 heikki.linnakangas@i 11945 :CBC 1 : appendPQExpBufferStr(q, "]::pg_catalog.text[]");
11946 : 1 : appendPQExpBufferStr(q, ");\n");
11947 : : }
11948 : :
3440 sfrost@snowman.net 11949 [ + - ]: 18 : if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11950 : 18 : ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 11951 : 18 : ARCHIVE_OPTS(.tag = extinfo->dobj.name,
11952 : : .description = "EXTENSION",
11953 : : .section = SECTION_PRE_DATA,
11954 : : .createStmt = q->data,
11955 : : .dropStmt = delq->data));
11956 : :
11957 : : /* Dump Extension Comments and Security Labels */
3440 sfrost@snowman.net 11958 [ + - ]: 18 : if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 11959 : 18 : dumpComment(fout, "EXTENSION", qextname,
11960 : : NULL, "",
3440 sfrost@snowman.net 11961 : 18 : extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
11962 : :
11963 [ - + ]: 18 : if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 11964 :UBC 0 : dumpSecLabel(fout, "EXTENSION", qextname,
11965 : : NULL, "",
3440 sfrost@snowman.net 11966 : 0 : extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
11967 : :
5324 tgl@sss.pgh.pa.us 11968 :CBC 18 : free(qextname);
11969 : :
11970 : 18 : destroyPQExpBuffer(q);
11971 : 18 : destroyPQExpBuffer(delq);
11972 : : }
11973 : :
11974 : : /*
11975 : : * dumpType
11976 : : * writes out to fout the queries to recreate a user-defined type
11977 : : */
11978 : : static void
1669 peter@eisentraut.org 11979 : 968 : dumpType(Archive *fout, const TypeInfo *tyinfo)
11980 : : {
3524 tgl@sss.pgh.pa.us 11981 : 968 : DumpOptions *dopt = fout->dopt;
11982 : :
11983 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 11984 [ + + ]: 968 : if (!dopt->dumpSchema)
7945 tgl@sss.pgh.pa.us 11985 : 49 : return;
11986 : :
11987 : : /* Dump out in proper style */
5736 bruce@momjian.us 11988 [ + + ]: 919 : if (tyinfo->typtype == TYPTYPE_BASE)
3524 tgl@sss.pgh.pa.us 11989 : 286 : dumpBaseType(fout, tyinfo);
5736 bruce@momjian.us 11990 [ + + ]: 633 : else if (tyinfo->typtype == TYPTYPE_DOMAIN)
3524 tgl@sss.pgh.pa.us 11991 : 158 : dumpDomain(fout, tyinfo);
5736 bruce@momjian.us 11992 [ + + ]: 475 : else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
3524 tgl@sss.pgh.pa.us 11993 : 136 : dumpCompositeType(fout, tyinfo);
5736 bruce@momjian.us 11994 [ + + ]: 339 : else if (tyinfo->typtype == TYPTYPE_ENUM)
3524 tgl@sss.pgh.pa.us 11995 : 97 : dumpEnumType(fout, tyinfo);
5056 heikki.linnakangas@i 11996 [ + + ]: 242 : else if (tyinfo->typtype == TYPTYPE_RANGE)
3524 tgl@sss.pgh.pa.us 11997 : 124 : dumpRangeType(fout, tyinfo);
3686 11998 [ + - + + ]: 118 : else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
3524 11999 : 43 : dumpUndefinedType(fout, tyinfo);
12000 : : else
2350 peter@eisentraut.org 12001 : 75 : pg_log_warning("typtype of data type \"%s\" appears to be invalid",
12002 : : tyinfo->dobj.name);
12003 : : }
12004 : :
12005 : : /*
12006 : : * dumpEnumType
12007 : : * writes out to fout the queries to recreate a user-defined enum type
12008 : : */
12009 : : static void
1669 12010 : 97 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
12011 : : {
3524 tgl@sss.pgh.pa.us 12012 : 97 : DumpOptions *dopt = fout->dopt;
6732 12013 : 97 : PQExpBuffer q = createPQExpBuffer();
12014 : 97 : PQExpBuffer delq = createPQExpBuffer();
12015 : 97 : PQExpBuffer query = createPQExpBuffer();
12016 : : PGresult *res;
12017 : : int num,
12018 : : i;
12019 : : Oid enum_oid;
12020 : : char *qtypname;
12021 : : char *qualtypname;
12022 : : char *label;
12023 : : int i_enumlabel;
12024 : : int i_oid;
12025 : :
1370 12026 [ + + ]: 97 : if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
12027 : : {
12028 : : /* Set up query for enum-specific details */
12029 : 46 : appendPQExpBufferStr(query,
12030 : : "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
12031 : : "SELECT oid, enumlabel "
12032 : : "FROM pg_catalog.pg_enum "
12033 : : "WHERE enumtypid = $1 "
12034 : : "ORDER BY enumsortorder");
12035 : :
12036 : 46 : ExecuteSqlStatement(fout, query->data);
12037 : :
12038 : 46 : fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
12039 : : }
12040 : :
12041 : 97 : printfPQExpBuffer(query,
12042 : : "EXECUTE dumpEnumType('%u')",
12043 : 97 : tyinfo->dobj.catId.oid);
12044 : :
4960 rhaas@postgresql.org 12045 : 97 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12046 : :
6732 tgl@sss.pgh.pa.us 12047 : 97 : num = PQntuples(res);
12048 : :
4654 12049 : 97 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2749 12050 : 97 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
12051 : :
12052 : : /*
12053 : : * CASCADE shouldn't be required here as for normal types since the I/O
12054 : : * functions are generic and do not get dropped.
12055 : : */
12056 : 97 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12057 : :
3980 alvherre@alvh.no-ip. 12058 [ + + ]: 97 : if (dopt->binary_upgrade)
4960 rhaas@postgresql.org 12059 : 6 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2898 tgl@sss.pgh.pa.us 12060 : 6 : tyinfo->dobj.catId.oid,
12061 : : false, false);
12062 : :
5732 bruce@momjian.us 12063 : 97 : appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
12064 : : qualtypname);
12065 : :
3980 alvherre@alvh.no-ip. 12066 [ + + ]: 97 : if (!dopt->binary_upgrade)
12067 : : {
1471 dgustafsson@postgres 12068 : 91 : i_enumlabel = PQfnumber(res, "enumlabel");
12069 : :
12070 : : /* Labels with server-assigned oids */
5732 bruce@momjian.us 12071 [ + + ]: 530 : for (i = 0; i < num; i++)
12072 : : {
1471 dgustafsson@postgres 12073 : 439 : label = PQgetvalue(res, i, i_enumlabel);
5732 bruce@momjian.us 12074 [ + + ]: 439 : if (i > 0)
4310 heikki.linnakangas@i 12075 : 348 : appendPQExpBufferChar(q, ',');
12076 : 439 : appendPQExpBufferStr(q, "\n ");
5732 bruce@momjian.us 12077 : 439 : appendStringLiteralAH(q, label, fout);
12078 : : }
12079 : : }
12080 : :
4310 heikki.linnakangas@i 12081 : 97 : appendPQExpBufferStr(q, "\n);\n");
12082 : :
3980 alvherre@alvh.no-ip. 12083 [ + + ]: 97 : if (dopt->binary_upgrade)
12084 : : {
1471 dgustafsson@postgres 12085 : 6 : i_oid = PQfnumber(res, "oid");
12086 : 6 : i_enumlabel = PQfnumber(res, "enumlabel");
12087 : :
12088 : : /* Labels with dump-assigned (preserved) oids */
5732 bruce@momjian.us 12089 [ + + ]: 62 : for (i = 0; i < num; i++)
12090 : : {
1471 dgustafsson@postgres 12091 : 56 : enum_oid = atooid(PQgetvalue(res, i, i_oid));
12092 : 56 : label = PQgetvalue(res, i, i_enumlabel);
12093 : :
5732 bruce@momjian.us 12094 [ + + ]: 56 : if (i == 0)
4310 heikki.linnakangas@i 12095 : 6 : appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
5732 bruce@momjian.us 12096 : 56 : appendPQExpBuffer(q,
12097 : : "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
12098 : : enum_oid);
2749 tgl@sss.pgh.pa.us 12099 : 56 : appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
5732 bruce@momjian.us 12100 : 56 : appendStringLiteralAH(q, label, fout);
4310 heikki.linnakangas@i 12101 : 56 : appendPQExpBufferStr(q, ";\n\n");
12102 : : }
12103 : : }
12104 : :
3980 alvherre@alvh.no-ip. 12105 [ + + ]: 97 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 12106 : 6 : binary_upgrade_extension_member(q, &tyinfo->dobj,
12107 : : "TYPE", qtypname,
12108 : 6 : tyinfo->dobj.namespace->dobj.name);
12109 : :
3440 sfrost@snowman.net 12110 [ + - ]: 97 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12111 : 97 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 12112 : 97 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12113 : : .namespace = tyinfo->dobj.namespace->dobj.name,
12114 : : .owner = tyinfo->rolname,
12115 : : .description = "TYPE",
12116 : : .section = SECTION_PRE_DATA,
12117 : : .createStmt = q->data,
12118 : : .dropStmt = delq->data));
12119 : :
12120 : : /* Dump Type Comments and Security Labels */
3440 sfrost@snowman.net 12121 [ + + ]: 97 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 12122 : 38 : dumpComment(fout, "TYPE", qtypname,
3440 sfrost@snowman.net 12123 : 38 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12124 : 38 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12125 : :
12126 [ - + ]: 97 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 12127 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
3440 sfrost@snowman.net 12128 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12129 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12130 : :
3440 sfrost@snowman.net 12131 [ + + ]:CBC 97 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1883 tgl@sss.pgh.pa.us 12132 : 38 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12133 : : qtypname, NULL,
3440 sfrost@snowman.net 12134 : 38 : tyinfo->dobj.namespace->dobj.name,
523 tgl@sss.pgh.pa.us 12135 : 38 : NULL, tyinfo->rolname, &tyinfo->dacl);
12136 : :
5056 heikki.linnakangas@i 12137 : 97 : PQclear(res);
12138 : 97 : destroyPQExpBuffer(q);
12139 : 97 : destroyPQExpBuffer(delq);
12140 : 97 : destroyPQExpBuffer(query);
2749 tgl@sss.pgh.pa.us 12141 : 97 : free(qtypname);
12142 : 97 : free(qualtypname);
5056 heikki.linnakangas@i 12143 : 97 : }
12144 : :
12145 : : /*
12146 : : * dumpRangeType
12147 : : * writes out to fout the queries to recreate a user-defined range type
12148 : : */
12149 : : static void
1669 peter@eisentraut.org 12150 : 124 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
12151 : : {
3524 tgl@sss.pgh.pa.us 12152 : 124 : DumpOptions *dopt = fout->dopt;
5056 heikki.linnakangas@i 12153 : 124 : PQExpBuffer q = createPQExpBuffer();
12154 : 124 : PQExpBuffer delq = createPQExpBuffer();
12155 : 124 : PQExpBuffer query = createPQExpBuffer();
12156 : : PGresult *res;
12157 : : Oid collationOid;
12158 : : char *qtypname;
12159 : : char *qualtypname;
12160 : : char *procname;
12161 : :
1370 tgl@sss.pgh.pa.us 12162 [ + + ]: 124 : if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
12163 : : {
12164 : : /* Set up query for range-specific details */
12165 : 46 : appendPQExpBufferStr(query,
12166 : : "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
12167 : :
12168 : 46 : appendPQExpBufferStr(query,
12169 : : "SELECT ");
12170 : :
12171 [ + - ]: 46 : if (fout->remoteVersion >= 140000)
12172 : 46 : appendPQExpBufferStr(query,
12173 : : "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
12174 : : else
1370 tgl@sss.pgh.pa.us 12175 :UBC 0 : appendPQExpBufferStr(query,
12176 : : "NULL AS rngmultitype, ");
12177 : :
1370 tgl@sss.pgh.pa.us 12178 :CBC 46 : appendPQExpBufferStr(query,
12179 : : "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
12180 : : "opc.opcname AS opcname, "
12181 : : "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
12182 : : " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
12183 : : "opc.opcdefault, "
12184 : : "CASE WHEN rngcollation = st.typcollation THEN 0 "
12185 : : " ELSE rngcollation END AS collation, "
12186 : : "rngcanonical, rngsubdiff "
12187 : : "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
12188 : : " pg_catalog.pg_opclass opc "
12189 : : "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
12190 : : "rngtypid = $1");
12191 : :
12192 : 46 : ExecuteSqlStatement(fout, query->data);
12193 : :
12194 : 46 : fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
12195 : : }
12196 : :
12197 : 124 : printfPQExpBuffer(query,
12198 : : "EXECUTE dumpRangeType('%u')",
5056 heikki.linnakangas@i 12199 : 124 : tyinfo->dobj.catId.oid);
12200 : :
4951 rhaas@postgresql.org 12201 : 124 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
12202 : :
4654 tgl@sss.pgh.pa.us 12203 : 124 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2749 12204 : 124 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
12205 : :
12206 : : /*
12207 : : * CASCADE shouldn't be required here as for normal types since the I/O
12208 : : * functions are generic and do not get dropped.
12209 : : */
12210 : 124 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12211 : :
3980 alvherre@alvh.no-ip. 12212 [ + + ]: 124 : if (dopt->binary_upgrade)
2898 tgl@sss.pgh.pa.us 12213 : 8 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
12214 : 8 : tyinfo->dobj.catId.oid,
12215 : : false, true);
12216 : :
5056 heikki.linnakangas@i 12217 : 124 : appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
12218 : : qualtypname);
12219 : :
5039 tgl@sss.pgh.pa.us 12220 : 124 : appendPQExpBuffer(q, "\n subtype = %s",
12221 : : PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
12222 : :
1721 akorotkov@postgresql 12223 [ + - ]: 124 : if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
12224 : 124 : appendPQExpBuffer(q, ",\n multirange_type_name = %s",
12225 : : PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
12226 : :
12227 : : /* print subtype_opclass only if not default for subtype */
5039 tgl@sss.pgh.pa.us 12228 [ + + ]: 124 : if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
12229 : : {
4836 bruce@momjian.us 12230 : 38 : char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
12231 : 38 : char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
12232 : :
5039 tgl@sss.pgh.pa.us 12233 : 38 : appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
12234 : : fmtId(nspname));
4310 heikki.linnakangas@i 12235 : 38 : appendPQExpBufferStr(q, fmtId(opcname));
12236 : : }
12237 : :
5039 tgl@sss.pgh.pa.us 12238 : 124 : collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
5056 heikki.linnakangas@i 12239 [ + + ]: 124 : if (OidIsValid(collationOid))
12240 : : {
5039 tgl@sss.pgh.pa.us 12241 : 43 : CollInfo *coll = findCollationByOid(collationOid);
12242 : :
5056 heikki.linnakangas@i 12243 [ + - ]: 43 : if (coll)
2749 tgl@sss.pgh.pa.us 12244 : 43 : appendPQExpBuffer(q, ",\n collation = %s",
12245 : 43 : fmtQualifiedDumpable(coll));
12246 : : }
12247 : :
5039 12248 : 124 : procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
12249 [ + + ]: 124 : if (strcmp(procname, "-") != 0)
12250 : 9 : appendPQExpBuffer(q, ",\n canonical = %s", procname);
12251 : :
12252 : 124 : procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
12253 [ + + ]: 124 : if (strcmp(procname, "-") != 0)
12254 : 23 : appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
12255 : :
4310 heikki.linnakangas@i 12256 : 124 : appendPQExpBufferStr(q, "\n);\n");
12257 : :
3980 alvherre@alvh.no-ip. 12258 [ + + ]: 124 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 12259 : 8 : binary_upgrade_extension_member(q, &tyinfo->dobj,
12260 : : "TYPE", qtypname,
12261 : 8 : tyinfo->dobj.namespace->dobj.name);
12262 : :
3440 sfrost@snowman.net 12263 [ + - ]: 124 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12264 : 124 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 12265 : 124 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12266 : : .namespace = tyinfo->dobj.namespace->dobj.name,
12267 : : .owner = tyinfo->rolname,
12268 : : .description = "TYPE",
12269 : : .section = SECTION_PRE_DATA,
12270 : : .createStmt = q->data,
12271 : : .dropStmt = delq->data));
12272 : :
12273 : : /* Dump Type Comments and Security Labels */
3440 sfrost@snowman.net 12274 [ + + ]: 124 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 12275 : 56 : dumpComment(fout, "TYPE", qtypname,
3440 sfrost@snowman.net 12276 : 56 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12277 : 56 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12278 : :
12279 [ - + ]: 124 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 12280 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
3440 sfrost@snowman.net 12281 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12282 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12283 : :
3440 sfrost@snowman.net 12284 [ + + ]:CBC 124 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1883 tgl@sss.pgh.pa.us 12285 : 38 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12286 : : qtypname, NULL,
3440 sfrost@snowman.net 12287 : 38 : tyinfo->dobj.namespace->dobj.name,
523 tgl@sss.pgh.pa.us 12288 : 38 : NULL, tyinfo->rolname, &tyinfo->dacl);
12289 : :
6732 12290 : 124 : PQclear(res);
12291 : 124 : destroyPQExpBuffer(q);
12292 : 124 : destroyPQExpBuffer(delq);
12293 : 124 : destroyPQExpBuffer(query);
2749 12294 : 124 : free(qtypname);
12295 : 124 : free(qualtypname);
7945 12296 : 124 : }
12297 : :
12298 : : /*
12299 : : * dumpUndefinedType
12300 : : * writes out to fout the queries to recreate a !typisdefined type
12301 : : *
12302 : : * This is a shell type, but we use different terminology to distinguish
12303 : : * this case from where we have to emit a shell type definition to break
12304 : : * circular dependencies. An undefined type shouldn't ever have anything
12305 : : * depending on it.
12306 : : */
12307 : : static void
1669 peter@eisentraut.org 12308 : 43 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
12309 : : {
3524 tgl@sss.pgh.pa.us 12310 : 43 : DumpOptions *dopt = fout->dopt;
3686 12311 : 43 : PQExpBuffer q = createPQExpBuffer();
12312 : 43 : PQExpBuffer delq = createPQExpBuffer();
12313 : : char *qtypname;
12314 : : char *qualtypname;
12315 : :
12316 : 43 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2749 12317 : 43 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
12318 : :
12319 : 43 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12320 : :
3686 12321 [ + + ]: 43 : if (dopt->binary_upgrade)
2898 12322 : 2 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
12323 : 2 : tyinfo->dobj.catId.oid,
12324 : : false, false);
12325 : :
3686 12326 : 43 : appendPQExpBuffer(q, "CREATE TYPE %s;\n",
12327 : : qualtypname);
12328 : :
12329 [ + + ]: 43 : if (dopt->binary_upgrade)
2749 12330 : 2 : binary_upgrade_extension_member(q, &tyinfo->dobj,
12331 : : "TYPE", qtypname,
12332 : 2 : tyinfo->dobj.namespace->dobj.name);
12333 : :
3440 sfrost@snowman.net 12334 [ + - ]: 43 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12335 : 43 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 12336 : 43 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12337 : : .namespace = tyinfo->dobj.namespace->dobj.name,
12338 : : .owner = tyinfo->rolname,
12339 : : .description = "TYPE",
12340 : : .section = SECTION_PRE_DATA,
12341 : : .createStmt = q->data,
12342 : : .dropStmt = delq->data));
12343 : :
12344 : : /* Dump Type Comments and Security Labels */
3440 sfrost@snowman.net 12345 [ + + ]: 43 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 12346 : 38 : dumpComment(fout, "TYPE", qtypname,
3440 sfrost@snowman.net 12347 : 38 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12348 : 38 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12349 : :
12350 [ - + ]: 43 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 12351 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
3440 sfrost@snowman.net 12352 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12353 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12354 : :
3440 sfrost@snowman.net 12355 [ - + ]:CBC 43 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1883 tgl@sss.pgh.pa.us 12356 :UBC 0 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12357 : : qtypname, NULL,
3440 sfrost@snowman.net 12358 : 0 : tyinfo->dobj.namespace->dobj.name,
523 tgl@sss.pgh.pa.us 12359 : 0 : NULL, tyinfo->rolname, &tyinfo->dacl);
12360 : :
3686 tgl@sss.pgh.pa.us 12361 :CBC 43 : destroyPQExpBuffer(q);
12362 : 43 : destroyPQExpBuffer(delq);
2749 12363 : 43 : free(qtypname);
12364 : 43 : free(qualtypname);
3686 12365 : 43 : }
12366 : :
12367 : : /*
12368 : : * dumpBaseType
12369 : : * writes out to fout the queries to recreate a user-defined base type
12370 : : */
12371 : : static void
1669 peter@eisentraut.org 12372 : 286 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
12373 : : {
3524 tgl@sss.pgh.pa.us 12374 : 286 : DumpOptions *dopt = fout->dopt;
8520 12375 : 286 : PQExpBuffer q = createPQExpBuffer();
12376 : 286 : PQExpBuffer delq = createPQExpBuffer();
12377 : 286 : PQExpBuffer query = createPQExpBuffer();
12378 : : PGresult *res;
12379 : : char *qtypname;
12380 : : char *qualtypname;
12381 : : char *typlen;
12382 : : char *typinput;
12383 : : char *typoutput;
12384 : : char *typreceive;
12385 : : char *typsend;
12386 : : char *typmodin;
12387 : : char *typmodout;
12388 : : char *typanalyze;
12389 : : char *typsubscript;
12390 : : Oid typreceiveoid;
12391 : : Oid typsendoid;
12392 : : Oid typmodinoid;
12393 : : Oid typmodoutoid;
12394 : : Oid typanalyzeoid;
12395 : : Oid typsubscriptoid;
12396 : : char *typcategory;
12397 : : char *typispreferred;
12398 : : char *typdelim;
12399 : : char *typbyval;
12400 : : char *typalign;
12401 : : char *typstorage;
12402 : : char *typcollatable;
12403 : : char *typdefault;
7137 12404 : 286 : bool typdefault_is_literal = false;
12405 : :
1370 12406 [ + + ]: 286 : if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
12407 : : {
12408 : : /* Set up query for type-specific details */
1735 12409 : 46 : appendPQExpBufferStr(query,
12410 : : "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
12411 : : "SELECT typlen, "
12412 : : "typinput, typoutput, typreceive, typsend, "
12413 : : "typreceive::pg_catalog.oid AS typreceiveoid, "
12414 : : "typsend::pg_catalog.oid AS typsendoid, "
12415 : : "typanalyze, "
12416 : : "typanalyze::pg_catalog.oid AS typanalyzeoid, "
12417 : : "typdelim, typbyval, typalign, typstorage, "
12418 : : "typmodin, typmodout, "
12419 : : "typmodin::pg_catalog.oid AS typmodinoid, "
12420 : : "typmodout::pg_catalog.oid AS typmodoutoid, "
12421 : : "typcategory, typispreferred, "
12422 : : "(typcollation <> 0) AS typcollatable, "
12423 : : "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
12424 : :
1370 12425 [ + - ]: 46 : if (fout->remoteVersion >= 140000)
12426 : 46 : appendPQExpBufferStr(query,
12427 : : "typsubscript, "
12428 : : "typsubscript::pg_catalog.oid AS typsubscriptoid ");
12429 : : else
1370 tgl@sss.pgh.pa.us 12430 :UBC 0 : appendPQExpBufferStr(query,
12431 : : "'-' AS typsubscript, 0 AS typsubscriptoid ");
12432 : :
1370 tgl@sss.pgh.pa.us 12433 :CBC 46 : appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
12434 : : "WHERE oid = $1");
12435 : :
12436 : 46 : ExecuteSqlStatement(fout, query->data);
12437 : :
12438 : 46 : fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
12439 : : }
12440 : :
12441 : 286 : printfPQExpBuffer(query,
12442 : : "EXECUTE dumpBaseType('%u')",
1735 12443 : 286 : tyinfo->dobj.catId.oid);
12444 : :
4951 rhaas@postgresql.org 12445 : 286 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
12446 : :
8520 tgl@sss.pgh.pa.us 12447 : 286 : typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
12448 : 286 : typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
12449 : 286 : typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
8157 12450 : 286 : typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
12451 : 286 : typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
6825 12452 : 286 : typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
12453 : 286 : typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
7877 12454 : 286 : typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
1732 12455 : 286 : typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
7945 12456 : 286 : typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
12457 : 286 : typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
6825 12458 : 286 : typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
12459 : 286 : typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
7877 12460 : 286 : typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
1732 12461 : 286 : typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
6247 12462 : 286 : typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
12463 : 286 : typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
8520 12464 : 286 : typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
12465 : 286 : typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
12466 : 286 : typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
12467 : 286 : typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
5303 peter_e@gmx.net 12468 : 286 : typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
7137 tgl@sss.pgh.pa.us 12469 [ - + ]: 286 : if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
7137 tgl@sss.pgh.pa.us 12470 :UBC 0 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
7137 tgl@sss.pgh.pa.us 12471 [ + + ]:CBC 286 : else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
12472 : : {
12473 : 48 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6912 bruce@momjian.us 12474 : 48 : typdefault_is_literal = true; /* it needs quotes */
12475 : : }
12476 : : else
7137 tgl@sss.pgh.pa.us 12477 : 238 : typdefault = NULL;
12478 : :
4654 12479 : 286 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2749 12480 : 286 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
12481 : :
12482 : : /*
12483 : : * The reason we include CASCADE is that the circular dependency between
12484 : : * the type and its I/O functions makes it impossible to drop the type any
12485 : : * other way.
12486 : : */
12487 : 286 : appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
12488 : :
12489 : : /*
12490 : : * We might already have a shell type, but setting pg_type_oid is
12491 : : * harmless, and in any case we'd better set the array type OID.
12492 : : */
3980 alvherre@alvh.no-ip. 12493 [ + + ]: 286 : if (dopt->binary_upgrade)
4960 rhaas@postgresql.org 12494 : 8 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2898 tgl@sss.pgh.pa.us 12495 : 8 : tyinfo->dobj.catId.oid,
12496 : : false, false);
12497 : :
8520 12498 : 286 : appendPQExpBuffer(q,
12499 : : "CREATE TYPE %s (\n"
12500 : : " INTERNALLENGTH = %s",
12501 : : qualtypname,
8445 peter_e@gmx.net 12502 [ + + ]: 286 : (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
12503 : :
12504 : : /* regproc result is sufficiently quoted already */
3251 tgl@sss.pgh.pa.us 12505 : 286 : appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
12506 : 286 : appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
12507 [ + + ]: 286 : if (OidIsValid(typreceiveoid))
12508 : 207 : appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
12509 [ + + ]: 286 : if (OidIsValid(typsendoid))
12510 : 207 : appendPQExpBuffer(q, ",\n SEND = %s", typsend);
12511 [ + + ]: 286 : if (OidIsValid(typmodinoid))
12512 : 35 : appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
12513 [ + + ]: 286 : if (OidIsValid(typmodoutoid))
12514 : 35 : appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
12515 [ + + ]: 286 : if (OidIsValid(typanalyzeoid))
12516 : 3 : appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
12517 : :
5303 peter_e@gmx.net 12518 [ + + ]: 286 : if (strcmp(typcollatable, "t") == 0)
4310 heikki.linnakangas@i 12519 : 30 : appendPQExpBufferStr(q, ",\n COLLATABLE = true");
12520 : :
8520 tgl@sss.pgh.pa.us 12521 [ + + ]: 286 : if (typdefault != NULL)
12522 : : {
4310 heikki.linnakangas@i 12523 : 48 : appendPQExpBufferStr(q, ",\n DEFAULT = ");
7137 tgl@sss.pgh.pa.us 12524 [ + - ]: 48 : if (typdefault_is_literal)
7041 12525 : 48 : appendStringLiteralAH(q, typdefault, fout);
12526 : : else
7137 tgl@sss.pgh.pa.us 12527 :UBC 0 : appendPQExpBufferStr(q, typdefault);
12528 : : }
12529 : :
1732 tgl@sss.pgh.pa.us 12530 [ + + ]:CBC 286 : if (OidIsValid(typsubscriptoid))
12531 : 29 : appendPQExpBuffer(q, ",\n SUBSCRIPT = %s", typsubscript);
12532 : :
5736 bruce@momjian.us 12533 [ + + ]: 286 : if (OidIsValid(tyinfo->typelem))
1459 tgl@sss.pgh.pa.us 12534 : 26 : appendPQExpBuffer(q, ",\n ELEMENT = %s",
12535 : 26 : getFormattedTypeName(fout, tyinfo->typelem,
12536 : : zeroIsError));
12537 : :
6247 12538 [ + + ]: 286 : if (strcmp(typcategory, "U") != 0)
12539 : : {
4310 heikki.linnakangas@i 12540 : 158 : appendPQExpBufferStr(q, ",\n CATEGORY = ");
6247 tgl@sss.pgh.pa.us 12541 : 158 : appendStringLiteralAH(q, typcategory, fout);
12542 : : }
12543 : :
12544 [ + + ]: 286 : if (strcmp(typispreferred, "t") == 0)
4310 heikki.linnakangas@i 12545 : 29 : appendPQExpBufferStr(q, ",\n PREFERRED = true");
12546 : :
8157 tgl@sss.pgh.pa.us 12547 [ + - + + ]: 286 : if (typdelim && strcmp(typdelim, ",") != 0)
12548 : : {
4310 heikki.linnakangas@i 12549 : 3 : appendPQExpBufferStr(q, ",\n DELIMITER = ");
7041 tgl@sss.pgh.pa.us 12550 : 3 : appendStringLiteralAH(q, typdelim, fout);
12551 : : }
12552 : :
2012 12553 [ + + ]: 286 : if (*typalign == TYPALIGN_CHAR)
4310 heikki.linnakangas@i 12554 : 12 : appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
2012 tgl@sss.pgh.pa.us 12555 [ + + ]: 274 : else if (*typalign == TYPALIGN_SHORT)
4310 heikki.linnakangas@i 12556 : 6 : appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
2012 tgl@sss.pgh.pa.us 12557 [ + + ]: 268 : else if (*typalign == TYPALIGN_INT)
4310 heikki.linnakangas@i 12558 : 193 : appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
2012 tgl@sss.pgh.pa.us 12559 [ + - ]: 75 : else if (*typalign == TYPALIGN_DOUBLE)
4310 heikki.linnakangas@i 12560 : 75 : appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
12561 : :
2012 tgl@sss.pgh.pa.us 12562 [ + + ]: 286 : if (*typstorage == TYPSTORAGE_PLAIN)
4310 heikki.linnakangas@i 12563 : 211 : appendPQExpBufferStr(q, ",\n STORAGE = plain");
2012 tgl@sss.pgh.pa.us 12564 [ - + ]: 75 : else if (*typstorage == TYPSTORAGE_EXTERNAL)
4310 heikki.linnakangas@i 12565 :UBC 0 : appendPQExpBufferStr(q, ",\n STORAGE = external");
2012 tgl@sss.pgh.pa.us 12566 [ + + ]:CBC 75 : else if (*typstorage == TYPSTORAGE_EXTENDED)
4310 heikki.linnakangas@i 12567 : 66 : appendPQExpBufferStr(q, ",\n STORAGE = extended");
2012 tgl@sss.pgh.pa.us 12568 [ + - ]: 9 : else if (*typstorage == TYPSTORAGE_MAIN)
4310 heikki.linnakangas@i 12569 : 9 : appendPQExpBufferStr(q, ",\n STORAGE = main");
12570 : :
8520 tgl@sss.pgh.pa.us 12571 [ + + ]: 286 : if (strcmp(typbyval, "t") == 0)
4310 heikki.linnakangas@i 12572 : 140 : appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
12573 : :
12574 : 286 : appendPQExpBufferStr(q, "\n);\n");
12575 : :
3980 alvherre@alvh.no-ip. 12576 [ + + ]: 286 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 12577 : 8 : binary_upgrade_extension_member(q, &tyinfo->dobj,
12578 : : "TYPE", qtypname,
12579 : 8 : tyinfo->dobj.namespace->dobj.name);
12580 : :
3440 sfrost@snowman.net 12581 [ + - ]: 286 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12582 : 286 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 12583 : 286 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12584 : : .namespace = tyinfo->dobj.namespace->dobj.name,
12585 : : .owner = tyinfo->rolname,
12586 : : .description = "TYPE",
12587 : : .section = SECTION_PRE_DATA,
12588 : : .createStmt = q->data,
12589 : : .dropStmt = delq->data));
12590 : :
12591 : : /* Dump Type Comments and Security Labels */
3440 sfrost@snowman.net 12592 [ + + ]: 286 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 12593 : 251 : dumpComment(fout, "TYPE", qtypname,
3440 sfrost@snowman.net 12594 : 251 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12595 : 251 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12596 : :
12597 [ - + ]: 286 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 12598 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
3440 sfrost@snowman.net 12599 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12600 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12601 : :
3440 sfrost@snowman.net 12602 [ + + ]:CBC 286 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1883 tgl@sss.pgh.pa.us 12603 : 38 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12604 : : qtypname, NULL,
3440 sfrost@snowman.net 12605 : 38 : tyinfo->dobj.namespace->dobj.name,
523 tgl@sss.pgh.pa.us 12606 : 38 : NULL, tyinfo->rolname, &tyinfo->dacl);
12607 : :
9363 bruce@momjian.us 12608 : 286 : PQclear(res);
8520 tgl@sss.pgh.pa.us 12609 : 286 : destroyPQExpBuffer(q);
12610 : 286 : destroyPQExpBuffer(delq);
8800 12611 : 286 : destroyPQExpBuffer(query);
2749 12612 : 286 : free(qtypname);
12613 : 286 : free(qualtypname);
9363 bruce@momjian.us 12614 : 286 : }
12615 : :
12616 : : /*
12617 : : * dumpDomain
12618 : : * writes out to fout the queries to recreate a user-defined domain
12619 : : */
12620 : : static void
1669 peter@eisentraut.org 12621 : 158 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
12622 : : {
3524 tgl@sss.pgh.pa.us 12623 : 158 : DumpOptions *dopt = fout->dopt;
8555 bruce@momjian.us 12624 : 158 : PQExpBuffer q = createPQExpBuffer();
12625 : 158 : PQExpBuffer delq = createPQExpBuffer();
12626 : 158 : PQExpBuffer query = createPQExpBuffer();
12627 : : PGresult *res;
12628 : : int i;
12629 : : char *qtypname;
12630 : : char *qualtypname;
12631 : : char *typnotnull;
12632 : : char *typdefn;
12633 : : char *typdefault;
12634 : : Oid typcollation;
7137 tgl@sss.pgh.pa.us 12635 : 158 : bool typdefault_is_literal = false;
12636 : :
1370 12637 [ + + ]: 158 : if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
12638 : : {
12639 : : /* Set up query for domain-specific details */
12640 : 43 : appendPQExpBufferStr(query,
12641 : : "PREPARE dumpDomain(pg_catalog.oid) AS\n");
12642 : :
1362 12643 : 43 : appendPQExpBufferStr(query, "SELECT t.typnotnull, "
12644 : : "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
12645 : : "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
12646 : : "t.typdefault, "
12647 : : "CASE WHEN t.typcollation <> u.typcollation "
12648 : : "THEN t.typcollation ELSE 0 END AS typcollation "
12649 : : "FROM pg_catalog.pg_type t "
12650 : : "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
12651 : : "WHERE t.oid = $1");
12652 : :
1370 12653 : 43 : ExecuteSqlStatement(fout, query->data);
12654 : :
12655 : 43 : fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
12656 : : }
12657 : :
12658 : 158 : printfPQExpBuffer(query,
12659 : : "EXECUTE dumpDomain('%u')",
12660 : 158 : tyinfo->dobj.catId.oid);
12661 : :
4951 rhaas@postgresql.org 12662 : 158 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
12663 : :
8520 tgl@sss.pgh.pa.us 12664 : 158 : typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
12665 : 158 : typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
7137 12666 [ + + ]: 158 : if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
12667 : 43 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
12668 [ - + ]: 115 : else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
12669 : : {
8502 tgl@sss.pgh.pa.us 12670 :UBC 0 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6912 bruce@momjian.us 12671 : 0 : typdefault_is_literal = true; /* it needs quotes */
12672 : : }
12673 : : else
7137 tgl@sss.pgh.pa.us 12674 :CBC 115 : typdefault = NULL;
5294 12675 : 158 : typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
12676 : :
3980 alvherre@alvh.no-ip. 12677 [ + + ]: 158 : if (dopt->binary_upgrade)
4960 rhaas@postgresql.org 12678 : 25 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2898 tgl@sss.pgh.pa.us 12679 : 25 : tyinfo->dobj.catId.oid,
12680 : : true, /* force array type */
12681 : : false); /* force multirange type */
12682 : :
4654 12683 : 158 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2749 12684 : 158 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
12685 : :
8555 bruce@momjian.us 12686 : 158 : appendPQExpBuffer(q,
12687 : : "CREATE DOMAIN %s AS %s",
12688 : : qualtypname,
12689 : : typdefn);
12690 : :
12691 : : /* Print collation only if different from base type's collation */
5294 tgl@sss.pgh.pa.us 12692 [ + + ]: 158 : if (OidIsValid(typcollation))
12693 : : {
12694 : : CollInfo *coll;
12695 : :
12696 : 38 : coll = findCollationByOid(typcollation);
12697 [ + - ]: 38 : if (coll)
2749 12698 : 38 : appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
12699 : : }
12700 : :
12701 : : /*
12702 : : * Print a not-null constraint if there's one. In servers older than 17
12703 : : * these don't have names, so just print it unadorned; in newer ones they
12704 : : * do, but most of the time it's going to be the standard generated one,
12705 : : * so omit the name in that case also.
12706 : : */
8520 12707 [ + + ]: 158 : if (typnotnull[0] == 't')
12708 : : {
47 alvherre@kurilemu.de 12709 [ + - - + ]: 53 : if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
47 alvherre@kurilemu.de 12710 :UBC 0 : appendPQExpBufferStr(q, " NOT NULL");
12711 : : else
12712 : : {
47 alvherre@kurilemu.de 12713 :CBC 53 : ConstraintInfo *notnull = tyinfo->notnull;
12714 : :
12715 [ + - ]: 53 : if (!notnull->separate)
12716 : : {
12717 : : char *default_name;
12718 : :
12719 : : /* XXX should match ChooseConstraintName better */
12720 : 53 : default_name = psprintf("%s_not_null", tyinfo->dobj.name);
12721 : :
12722 [ + + ]: 53 : if (strcmp(default_name, notnull->dobj.name) == 0)
12723 : 15 : appendPQExpBufferStr(q, " NOT NULL");
12724 : : else
12725 : 38 : appendPQExpBuffer(q, " CONSTRAINT %s %s",
12726 : 38 : fmtId(notnull->dobj.name), notnull->condef);
12727 : 53 : free(default_name);
12728 : : }
12729 : : }
12730 : : }
12731 : :
7137 tgl@sss.pgh.pa.us 12732 [ + + ]: 158 : if (typdefault != NULL)
12733 : : {
4310 heikki.linnakangas@i 12734 : 43 : appendPQExpBufferStr(q, " DEFAULT ");
7137 tgl@sss.pgh.pa.us 12735 [ - + ]: 43 : if (typdefault_is_literal)
7041 tgl@sss.pgh.pa.us 12736 :UBC 0 : appendStringLiteralAH(q, typdefault, fout);
12737 : : else
7137 tgl@sss.pgh.pa.us 12738 :CBC 43 : appendPQExpBufferStr(q, typdefault);
12739 : : }
12740 : :
8304 12741 : 158 : PQclear(res);
12742 : :
12743 : : /*
12744 : : * Add any CHECK constraints for the domain
12745 : : */
5736 bruce@momjian.us 12746 [ + + ]: 271 : for (i = 0; i < tyinfo->nDomChecks; i++)
12747 : : {
12748 : 113 : ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
12749 : :
47 alvherre@kurilemu.de 12750 [ + + + - ]: 113 : if (!domcheck->separate && domcheck->contype == 'c')
7945 tgl@sss.pgh.pa.us 12751 : 108 : appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
7266 bruce@momjian.us 12752 : 108 : fmtId(domcheck->dobj.name), domcheck->condef);
12753 : : }
12754 : :
4310 heikki.linnakangas@i 12755 : 158 : appendPQExpBufferStr(q, ";\n");
12756 : :
2749 tgl@sss.pgh.pa.us 12757 : 158 : appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
12758 : :
3980 alvherre@alvh.no-ip. 12759 [ + + ]: 158 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 12760 : 25 : binary_upgrade_extension_member(q, &tyinfo->dobj,
12761 : : "DOMAIN", qtypname,
12762 : 25 : tyinfo->dobj.namespace->dobj.name);
12763 : :
3440 sfrost@snowman.net 12764 [ + - ]: 158 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12765 : 158 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 12766 : 158 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12767 : : .namespace = tyinfo->dobj.namespace->dobj.name,
12768 : : .owner = tyinfo->rolname,
12769 : : .description = "DOMAIN",
12770 : : .section = SECTION_PRE_DATA,
12771 : : .createStmt = q->data,
12772 : : .dropStmt = delq->data));
12773 : :
12774 : : /* Dump Domain Comments and Security Labels */
3440 sfrost@snowman.net 12775 [ - + ]: 158 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 12776 :UBC 0 : dumpComment(fout, "DOMAIN", qtypname,
3440 sfrost@snowman.net 12777 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12778 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12779 : :
3440 sfrost@snowman.net 12780 [ - + ]:CBC 158 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 12781 :UBC 0 : dumpSecLabel(fout, "DOMAIN", qtypname,
3440 sfrost@snowman.net 12782 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12783 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12784 : :
3440 sfrost@snowman.net 12785 [ + + ]:CBC 158 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1883 tgl@sss.pgh.pa.us 12786 : 38 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12787 : : qtypname, NULL,
3440 sfrost@snowman.net 12788 : 38 : tyinfo->dobj.namespace->dobj.name,
523 tgl@sss.pgh.pa.us 12789 : 38 : NULL, tyinfo->rolname, &tyinfo->dacl);
12790 : :
12791 : : /* Dump any per-constraint comments */
3910 alvherre@alvh.no-ip. 12792 [ + + ]: 271 : for (i = 0; i < tyinfo->nDomChecks; i++)
12793 : : {
12794 : 113 : ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
12795 : : PQExpBuffer conprefix;
12796 : :
12797 : : /* but only if the constraint itself was dumped here */
52 alvherre@kurilemu.de 12798 [ + + ]: 113 : if (domcheck->separate)
12799 : 5 : continue;
12800 : :
12801 : 108 : conprefix = createPQExpBuffer();
2749 tgl@sss.pgh.pa.us 12802 : 108 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
3910 alvherre@alvh.no-ip. 12803 : 108 : fmtId(domcheck->dobj.name));
12804 : :
1039 tgl@sss.pgh.pa.us 12805 [ + + ]: 108 : if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 12806 : 38 : dumpComment(fout, conprefix->data, qtypname,
3440 sfrost@snowman.net 12807 : 38 : tyinfo->dobj.namespace->dobj.name,
12808 : 38 : tyinfo->rolname,
12809 : 38 : domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
12810 : :
2749 tgl@sss.pgh.pa.us 12811 : 108 : destroyPQExpBuffer(conprefix);
12812 : : }
12813 : :
12814 : : /*
12815 : : * And a comment on the not-null constraint, if there's one -- but only if
12816 : : * the constraint itself was dumped here
12817 : : */
47 alvherre@kurilemu.de 12818 [ + + + - ]: 158 : if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
12819 : : {
12820 : 53 : PQExpBuffer conprefix = createPQExpBuffer();
12821 : :
12822 : 53 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
12823 : 53 : fmtId(tyinfo->notnull->dobj.name));
12824 : :
12825 [ + + ]: 53 : if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
12826 : 38 : dumpComment(fout, conprefix->data, qtypname,
12827 : 38 : tyinfo->dobj.namespace->dobj.name,
12828 : 38 : tyinfo->rolname,
12829 : 38 : tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
12830 : 53 : destroyPQExpBuffer(conprefix);
12831 : : }
12832 : :
8520 tgl@sss.pgh.pa.us 12833 : 158 : destroyPQExpBuffer(q);
12834 : 158 : destroyPQExpBuffer(delq);
12835 : 158 : destroyPQExpBuffer(query);
2749 12836 : 158 : free(qtypname);
12837 : 158 : free(qualtypname);
8555 bruce@momjian.us 12838 : 158 : }
12839 : :
12840 : : /*
12841 : : * dumpCompositeType
12842 : : * writes out to fout the queries to recreate a user-defined stand-alone
12843 : : * composite type
12844 : : */
12845 : : static void
1669 peter@eisentraut.org 12846 : 136 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
12847 : : {
3524 tgl@sss.pgh.pa.us 12848 : 136 : DumpOptions *dopt = fout->dopt;
8423 bruce@momjian.us 12849 : 136 : PQExpBuffer q = createPQExpBuffer();
5222 heikki.linnakangas@i 12850 : 136 : PQExpBuffer dropped = createPQExpBuffer();
8423 bruce@momjian.us 12851 : 136 : PQExpBuffer delq = createPQExpBuffer();
12852 : 136 : PQExpBuffer query = createPQExpBuffer();
12853 : : PGresult *res;
12854 : : char *qtypname;
12855 : : char *qualtypname;
12856 : : int ntups;
12857 : : int i_attname;
12858 : : int i_atttypdefn;
12859 : : int i_attlen;
12860 : : int i_attalign;
12861 : : int i_attisdropped;
12862 : : int i_attcollation;
12863 : : int i;
12864 : : int actual_atts;
12865 : :
1370 tgl@sss.pgh.pa.us 12866 [ + + ]: 136 : if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
12867 : : {
12868 : : /*
12869 : : * Set up query for type-specific details.
12870 : : *
12871 : : * Since we only want to dump COLLATE clauses for attributes whose
12872 : : * collation is different from their type's default, we use a CASE
12873 : : * here to suppress uninteresting attcollations cheaply. atttypid
12874 : : * will be 0 for dropped columns; collation does not matter for those.
12875 : : */
12876 : 61 : appendPQExpBufferStr(query,
12877 : : "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
12878 : : "SELECT a.attname, a.attnum, "
12879 : : "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
12880 : : "a.attlen, a.attalign, a.attisdropped, "
12881 : : "CASE WHEN a.attcollation <> at.typcollation "
12882 : : "THEN a.attcollation ELSE 0 END AS attcollation "
12883 : : "FROM pg_catalog.pg_type ct "
12884 : : "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
12885 : : "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
12886 : : "WHERE ct.oid = $1 "
12887 : : "ORDER BY a.attnum");
12888 : :
12889 : 61 : ExecuteSqlStatement(fout, query->data);
12890 : :
12891 : 61 : fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
12892 : : }
12893 : :
12894 : 136 : printfPQExpBuffer(query,
12895 : : "EXECUTE dumpCompositeType('%u')",
12896 : 136 : tyinfo->dobj.catId.oid);
12897 : :
4960 rhaas@postgresql.org 12898 : 136 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12899 : :
8423 bruce@momjian.us 12900 : 136 : ntups = PQntuples(res);
12901 : :
8409 tgl@sss.pgh.pa.us 12902 : 136 : i_attname = PQfnumber(res, "attname");
12903 : 136 : i_atttypdefn = PQfnumber(res, "atttypdefn");
5222 heikki.linnakangas@i 12904 : 136 : i_attlen = PQfnumber(res, "attlen");
12905 : 136 : i_attalign = PQfnumber(res, "attalign");
12906 : 136 : i_attisdropped = PQfnumber(res, "attisdropped");
5256 tgl@sss.pgh.pa.us 12907 : 136 : i_attcollation = PQfnumber(res, "attcollation");
12908 : :
3980 alvherre@alvh.no-ip. 12909 [ + + ]: 136 : if (dopt->binary_upgrade)
12910 : : {
4960 rhaas@postgresql.org 12911 : 18 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2898 tgl@sss.pgh.pa.us 12912 : 18 : tyinfo->dobj.catId.oid,
12913 : : false, false);
430 nathan@postgresql.or 12914 : 18 : binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
12915 : : }
12916 : :
4654 tgl@sss.pgh.pa.us 12917 : 136 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2749 12918 : 136 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
12919 : :
8409 12920 : 136 : appendPQExpBuffer(q, "CREATE TYPE %s AS (",
12921 : : qualtypname);
12922 : :
5222 heikki.linnakangas@i 12923 : 136 : actual_atts = 0;
8423 bruce@momjian.us 12924 [ + + ]: 430 : for (i = 0; i < ntups; i++)
12925 : : {
12926 : : char *attname;
12927 : : char *atttypdefn;
12928 : : char *attlen;
12929 : : char *attalign;
12930 : : bool attisdropped;
12931 : : Oid attcollation;
12932 : :
8409 tgl@sss.pgh.pa.us 12933 : 294 : attname = PQgetvalue(res, i, i_attname);
12934 : 294 : atttypdefn = PQgetvalue(res, i, i_atttypdefn);
5222 heikki.linnakangas@i 12935 : 294 : attlen = PQgetvalue(res, i, i_attlen);
12936 : 294 : attalign = PQgetvalue(res, i, i_attalign);
12937 : 294 : attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
5256 tgl@sss.pgh.pa.us 12938 : 294 : attcollation = atooid(PQgetvalue(res, i, i_attcollation));
12939 : :
3980 alvherre@alvh.no-ip. 12940 [ + + + + ]: 294 : if (attisdropped && !dopt->binary_upgrade)
5222 heikki.linnakangas@i 12941 : 8 : continue;
12942 : :
12943 : : /* Format properly if not first attr */
12944 [ + + ]: 286 : if (actual_atts++ > 0)
4310 12945 : 150 : appendPQExpBufferChar(q, ',');
12946 : 286 : appendPQExpBufferStr(q, "\n\t");
12947 : :
5222 12948 [ + + ]: 286 : if (!attisdropped)
12949 : : {
12950 : 284 : appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
12951 : :
12952 : : /* Add collation if not default for the column type */
12953 [ - + ]: 284 : if (OidIsValid(attcollation))
12954 : : {
12955 : : CollInfo *coll;
12956 : :
5222 heikki.linnakangas@i 12957 :UBC 0 : coll = findCollationByOid(attcollation);
12958 [ # # ]: 0 : if (coll)
2749 tgl@sss.pgh.pa.us 12959 : 0 : appendPQExpBuffer(q, " COLLATE %s",
12960 : 0 : fmtQualifiedDumpable(coll));
12961 : : }
12962 : : }
12963 : : else
12964 : : {
12965 : : /*
12966 : : * This is a dropped attribute and we're in binary_upgrade mode.
12967 : : * Insert a placeholder for it in the CREATE TYPE command, and set
12968 : : * length and alignment with direct UPDATE to the catalogs
12969 : : * afterwards. See similar code in dumpTableSchema().
12970 : : */
5222 heikki.linnakangas@i 12971 :CBC 2 : appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
12972 : :
12973 : : /* stash separately for insertion after the CREATE TYPE */
4310 12974 : 2 : appendPQExpBufferStr(dropped,
12975 : : "\n-- For binary upgrade, recreate dropped column.\n");
5222 12976 : 2 : appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
12977 : : "SET attlen = %s, "
12978 : : "attalign = '%s', attbyval = false\n"
12979 : : "WHERE attname = ", attlen, attalign);
12980 : 2 : appendStringLiteralAH(dropped, attname, fout);
4310 12981 : 2 : appendPQExpBufferStr(dropped, "\n AND attrelid = ");
2749 tgl@sss.pgh.pa.us 12982 : 2 : appendStringLiteralAH(dropped, qualtypname, fout);
4310 heikki.linnakangas@i 12983 : 2 : appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
12984 : :
5222 12985 : 2 : appendPQExpBuffer(dropped, "ALTER TYPE %s ",
12986 : : qualtypname);
12987 : 2 : appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
12988 : : fmtId(attname));
12989 : : }
12990 : : }
4310 12991 : 136 : appendPQExpBufferStr(q, "\n);\n");
5222 12992 : 136 : appendPQExpBufferStr(q, dropped->data);
12993 : :
2749 tgl@sss.pgh.pa.us 12994 : 136 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12995 : :
3980 alvherre@alvh.no-ip. 12996 [ + + ]: 136 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 12997 : 18 : binary_upgrade_extension_member(q, &tyinfo->dobj,
12998 : : "TYPE", qtypname,
12999 : 18 : tyinfo->dobj.namespace->dobj.name);
13000 : :
3440 sfrost@snowman.net 13001 [ + + ]: 136 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13002 : 119 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 13003 : 119 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
13004 : : .namespace = tyinfo->dobj.namespace->dobj.name,
13005 : : .owner = tyinfo->rolname,
13006 : : .description = "TYPE",
13007 : : .section = SECTION_PRE_DATA,
13008 : : .createStmt = q->data,
13009 : : .dropStmt = delq->data));
13010 : :
13011 : :
13012 : : /* Dump Type Comments and Security Labels */
3440 sfrost@snowman.net 13013 [ + + ]: 136 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 13014 : 38 : dumpComment(fout, "TYPE", qtypname,
3440 sfrost@snowman.net 13015 : 38 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
13016 : 38 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
13017 : :
13018 [ - + ]: 136 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 13019 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
3440 sfrost@snowman.net 13020 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
13021 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
13022 : :
3440 sfrost@snowman.net 13023 [ + + ]:CBC 136 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1883 tgl@sss.pgh.pa.us 13024 : 18 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
13025 : : qtypname, NULL,
3440 sfrost@snowman.net 13026 : 18 : tyinfo->dobj.namespace->dobj.name,
523 tgl@sss.pgh.pa.us 13027 : 18 : NULL, tyinfo->rolname, &tyinfo->dacl);
13028 : :
13029 : : /* Dump any per-column comments */
1346 13030 [ + + ]: 136 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13031 : 38 : dumpCompositeTypeColComments(fout, tyinfo, res);
13032 : :
7945 13033 : 136 : PQclear(res);
13034 : 136 : destroyPQExpBuffer(q);
5222 heikki.linnakangas@i 13035 : 136 : destroyPQExpBuffer(dropped);
7945 tgl@sss.pgh.pa.us 13036 : 136 : destroyPQExpBuffer(delq);
13037 : 136 : destroyPQExpBuffer(query);
2749 13038 : 136 : free(qtypname);
13039 : 136 : free(qualtypname);
5889 13040 : 136 : }
13041 : :
13042 : : /*
13043 : : * dumpCompositeTypeColComments
13044 : : * writes out to fout the queries to recreate comments on the columns of
13045 : : * a user-defined stand-alone composite type.
13046 : : *
13047 : : * The caller has already made a query to collect the names and attnums
13048 : : * of the type's columns, so we just pass that result into here rather
13049 : : * than reading them again.
13050 : : */
13051 : : static void
1346 13052 : 38 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
13053 : : PGresult *res)
13054 : : {
13055 : : CommentItem *comments;
13056 : : int ncomments;
13057 : : PQExpBuffer query;
13058 : : PQExpBuffer target;
13059 : : int i;
13060 : : int ntups;
13061 : : int i_attname;
13062 : : int i_attnum;
13063 : : int i_attisdropped;
13064 : :
13065 : : /* do nothing, if --no-comments is supplied */
2781 13066 [ - + ]: 38 : if (fout->dopt->no_comments)
2781 tgl@sss.pgh.pa.us 13067 :UBC 0 : return;
13068 : :
13069 : : /* Search for comments associated with type's pg_class OID */
1346 tgl@sss.pgh.pa.us 13070 :CBC 38 : ncomments = findComments(RelationRelationId, tyinfo->typrelid,
13071 : : &comments);
13072 : :
13073 : : /* If no comments exist, we're done */
5889 13074 [ - + ]: 38 : if (ncomments <= 0)
5889 tgl@sss.pgh.pa.us 13075 :UBC 0 : return;
13076 : :
13077 : : /* Build COMMENT ON statements */
1346 tgl@sss.pgh.pa.us 13078 :CBC 38 : query = createPQExpBuffer();
5889 13079 : 38 : target = createPQExpBuffer();
13080 : :
1346 13081 : 38 : ntups = PQntuples(res);
5889 13082 : 38 : i_attnum = PQfnumber(res, "attnum");
13083 : 38 : i_attname = PQfnumber(res, "attname");
1346 13084 : 38 : i_attisdropped = PQfnumber(res, "attisdropped");
5889 13085 [ + + ]: 76 : while (ncomments > 0)
13086 : : {
13087 : : const char *attname;
13088 : :
13089 : 38 : attname = NULL;
13090 [ + - ]: 38 : for (i = 0; i < ntups; i++)
13091 : : {
1346 13092 [ + - ]: 38 : if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
13093 [ + - ]: 38 : PQgetvalue(res, i, i_attisdropped)[0] != 't')
13094 : : {
5889 13095 : 38 : attname = PQgetvalue(res, i, i_attname);
13096 : 38 : break;
13097 : : }
13098 : : }
13099 [ + - ]: 38 : if (attname) /* just in case we don't find it */
13100 : : {
13101 : 38 : const char *descr = comments->descr;
13102 : :
13103 : 38 : resetPQExpBuffer(target);
13104 : 38 : appendPQExpBuffer(target, "COLUMN %s.",
5736 bruce@momjian.us 13105 : 38 : fmtId(tyinfo->dobj.name));
4310 heikki.linnakangas@i 13106 : 38 : appendPQExpBufferStr(target, fmtId(attname));
13107 : :
5889 tgl@sss.pgh.pa.us 13108 : 38 : resetPQExpBuffer(query);
2749 13109 : 38 : appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
13110 : 38 : fmtQualifiedDumpable(tyinfo));
13111 : 38 : appendPQExpBuffer(query, "%s IS ", fmtId(attname));
5889 13112 : 38 : appendStringLiteralAH(query, descr, fout);
4310 heikki.linnakangas@i 13113 : 38 : appendPQExpBufferStr(query, ";\n");
13114 : :
5889 tgl@sss.pgh.pa.us 13115 : 38 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 13116 : 38 : ARCHIVE_OPTS(.tag = target->data,
13117 : : .namespace = tyinfo->dobj.namespace->dobj.name,
13118 : : .owner = tyinfo->rolname,
13119 : : .description = "COMMENT",
13120 : : .section = SECTION_NONE,
13121 : : .createStmt = query->data,
13122 : : .deps = &(tyinfo->dobj.dumpId),
13123 : : .nDeps = 1));
13124 : : }
13125 : :
5889 tgl@sss.pgh.pa.us 13126 : 38 : comments++;
13127 : 38 : ncomments--;
13128 : : }
13129 : :
13130 : 38 : destroyPQExpBuffer(query);
13131 : 38 : destroyPQExpBuffer(target);
13132 : : }
13133 : :
13134 : : /*
13135 : : * dumpShellType
13136 : : * writes out to fout the queries to create a shell type
13137 : : *
13138 : : * We dump a shell definition in advance of the I/O functions for the type.
13139 : : */
13140 : : static void
1669 peter@eisentraut.org 13141 : 79 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
13142 : : {
3524 tgl@sss.pgh.pa.us 13143 : 79 : DumpOptions *dopt = fout->dopt;
13144 : : PQExpBuffer q;
13145 : :
13146 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 13147 [ + + ]: 79 : if (!dopt->dumpSchema)
7128 tgl@sss.pgh.pa.us 13148 : 6 : return;
13149 : :
13150 : 73 : q = createPQExpBuffer();
13151 : :
13152 : : /*
13153 : : * Note the lack of a DROP command for the shell type; any required DROP
13154 : : * is driven off the base type entry, instead. This interacts with
13155 : : * _printTocEntry()'s use of the presence of a DROP command to decide
13156 : : * whether an entry needs an ALTER OWNER command. We don't want to alter
13157 : : * the shell type's owner immediately on creation; that should happen only
13158 : : * after it's filled in, otherwise the backend complains.
13159 : : */
13160 : :
3980 alvherre@alvh.no-ip. 13161 [ + + ]: 73 : if (dopt->binary_upgrade)
4960 rhaas@postgresql.org 13162 : 8 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2898 tgl@sss.pgh.pa.us 13163 : 8 : stinfo->baseType->dobj.catId.oid,
13164 : : false, false);
13165 : :
7128 13166 : 73 : appendPQExpBuffer(q, "CREATE TYPE %s;\n",
2749 13167 : 73 : fmtQualifiedDumpable(stinfo));
13168 : :
3440 sfrost@snowman.net 13169 [ + - ]: 73 : if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13170 : 73 : ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 13171 : 73 : ARCHIVE_OPTS(.tag = stinfo->dobj.name,
13172 : : .namespace = stinfo->dobj.namespace->dobj.name,
13173 : : .owner = stinfo->baseType->rolname,
13174 : : .description = "SHELL TYPE",
13175 : : .section = SECTION_PRE_DATA,
13176 : : .createStmt = q->data));
13177 : :
7128 tgl@sss.pgh.pa.us 13178 : 73 : destroyPQExpBuffer(q);
13179 : : }
13180 : :
13181 : : /*
13182 : : * dumpProcLang
13183 : : * writes out to fout the queries to recreate a user-defined
13184 : : * procedural language
13185 : : */
13186 : : static void
1669 peter@eisentraut.org 13187 : 94 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
13188 : : {
3524 tgl@sss.pgh.pa.us 13189 : 94 : DumpOptions *dopt = fout->dopt;
13190 : : PQExpBuffer defqry;
13191 : : PQExpBuffer delqry;
13192 : : bool useParams;
13193 : : char *qlanname;
13194 : : FuncInfo *funcInfo;
5828 13195 : 94 : FuncInfo *inlineInfo = NULL;
7945 13196 : 94 : FuncInfo *validatorInfo = NULL;
13197 : :
13198 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 13199 [ + + ]: 94 : if (!dopt->dumpSchema)
7945 tgl@sss.pgh.pa.us 13200 : 13 : return;
13201 : :
13202 : : /*
13203 : : * Try to find the support function(s). It is not an error if we don't
13204 : : * find them --- if the functions are in the pg_catalog schema, as is
13205 : : * standard in 8.1 and up, then we won't have loaded them. (In this case
13206 : : * we will emit a parameterless CREATE LANGUAGE command, which will
13207 : : * require PL template knowledge in the backend to reload.)
13208 : : */
13209 : :
13210 : 81 : funcInfo = findFuncByOid(plang->lanplcallfoid);
7128 13211 [ + + + + ]: 81 : if (funcInfo != NULL && !funcInfo->dobj.dump)
7306 13212 : 2 : funcInfo = NULL; /* treat not-dumped same as not-found */
13213 : :
5828 13214 [ + + ]: 81 : if (OidIsValid(plang->laninline))
13215 : : {
13216 : 44 : inlineInfo = findFuncByOid(plang->laninline);
13217 [ + + + - ]: 44 : if (inlineInfo != NULL && !inlineInfo->dobj.dump)
13218 : 1 : inlineInfo = NULL;
13219 : : }
13220 : :
7945 13221 [ + + ]: 81 : if (OidIsValid(plang->lanvalidator))
13222 : : {
13223 : 44 : validatorInfo = findFuncByOid(plang->lanvalidator);
7128 13224 [ + + + - ]: 44 : if (validatorInfo != NULL && !validatorInfo->dobj.dump)
7306 13225 : 1 : validatorInfo = NULL;
13226 : : }
13227 : :
13228 : : /*
13229 : : * If the functions are dumpable then emit a complete CREATE LANGUAGE with
13230 : : * parameters. Otherwise, we'll write a parameterless command, which will
13231 : : * be interpreted as CREATE EXTENSION.
13232 : : */
13233 [ + - ]: 36 : useParams = (funcInfo != NULL &&
5828 13234 [ + + + - : 153 : (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
+ - ]
7306 13235 [ + - ]: 36 : (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
13236 : :
7945 13237 : 81 : defqry = createPQExpBuffer();
13238 : 81 : delqry = createPQExpBuffer();
13239 : :
5034 bruce@momjian.us 13240 : 81 : qlanname = pg_strdup(fmtId(plang->dobj.name));
13241 : :
7945 tgl@sss.pgh.pa.us 13242 : 81 : appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
13243 : : qlanname);
13244 : :
7306 13245 [ + + ]: 81 : if (useParams)
13246 : : {
5673 13247 : 36 : appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
13248 [ - + ]: 36 : plang->lanpltrusted ? "TRUSTED " : "",
13249 : : qlanname);
7306 13250 : 36 : appendPQExpBuffer(defqry, " HANDLER %s",
2749 13251 : 36 : fmtQualifiedDumpable(funcInfo));
5828 13252 [ - + ]: 36 : if (OidIsValid(plang->laninline))
2749 tgl@sss.pgh.pa.us 13253 :UBC 0 : appendPQExpBuffer(defqry, " INLINE %s",
13254 : 0 : fmtQualifiedDumpable(inlineInfo));
7306 tgl@sss.pgh.pa.us 13255 [ - + ]:CBC 36 : if (OidIsValid(plang->lanvalidator))
2749 tgl@sss.pgh.pa.us 13256 :UBC 0 : appendPQExpBuffer(defqry, " VALIDATOR %s",
13257 : 0 : fmtQualifiedDumpable(validatorInfo));
13258 : : }
13259 : : else
13260 : : {
13261 : : /*
13262 : : * If not dumping parameters, then use CREATE OR REPLACE so that the
13263 : : * command will not fail if the language is preinstalled in the target
13264 : : * database.
13265 : : *
13266 : : * Modern servers will interpret this as CREATE EXTENSION IF NOT
13267 : : * EXISTS; perhaps we should emit that instead? But it might just add
13268 : : * confusion.
13269 : : */
5673 tgl@sss.pgh.pa.us 13270 :CBC 45 : appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
13271 : : qlanname);
13272 : : }
4310 heikki.linnakangas@i 13273 : 81 : appendPQExpBufferStr(defqry, ";\n");
13274 : :
3980 alvherre@alvh.no-ip. 13275 [ + + ]: 81 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 13276 : 2 : binary_upgrade_extension_member(defqry, &plang->dobj,
13277 : : "LANGUAGE", qlanname, NULL);
13278 : :
3440 sfrost@snowman.net 13279 [ + + ]: 81 : if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
13280 : 37 : ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
2409 alvherre@alvh.no-ip. 13281 : 37 : ARCHIVE_OPTS(.tag = plang->dobj.name,
13282 : : .owner = plang->lanowner,
13283 : : .description = "PROCEDURAL LANGUAGE",
13284 : : .section = SECTION_PRE_DATA,
13285 : : .createStmt = defqry->data,
13286 : : .dropStmt = delqry->data,
13287 : : ));
13288 : :
13289 : : /* Dump Proc Lang Comments and Security Labels */
3440 sfrost@snowman.net 13290 [ - + ]: 81 : if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 13291 :UBC 0 : dumpComment(fout, "LANGUAGE", qlanname,
13292 : 0 : NULL, plang->lanowner,
3440 sfrost@snowman.net 13293 : 0 : plang->dobj.catId, 0, plang->dobj.dumpId);
13294 : :
3440 sfrost@snowman.net 13295 [ - + ]:CBC 81 : if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 13296 :UBC 0 : dumpSecLabel(fout, "LANGUAGE", qlanname,
13297 : 0 : NULL, plang->lanowner,
3440 sfrost@snowman.net 13298 : 0 : plang->dobj.catId, 0, plang->dobj.dumpId);
13299 : :
3440 sfrost@snowman.net 13300 [ + + + - ]:CBC 81 : if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
1883 tgl@sss.pgh.pa.us 13301 : 44 : dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
13302 : : qlanname, NULL, NULL,
523 13303 : 44 : NULL, plang->lanowner, &plang->dacl);
13304 : :
7945 13305 : 81 : free(qlanname);
13306 : :
13307 : 81 : destroyPQExpBuffer(defqry);
13308 : 81 : destroyPQExpBuffer(delqry);
13309 : : }
13310 : :
13311 : : /*
13312 : : * format_function_arguments: generate function name and argument list
13313 : : *
13314 : : * This is used when we can rely on pg_get_function_arguments to format
13315 : : * the argument list. Note, however, that pg_get_function_arguments
13316 : : * does not special-case zero-argument aggregates.
13317 : : */
13318 : : static char *
1669 peter@eisentraut.org 13319 : 4204 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
13320 : : {
13321 : : PQExpBufferData fn;
13322 : :
6259 tgl@sss.pgh.pa.us 13323 : 4204 : initPQExpBuffer(&fn);
4310 heikki.linnakangas@i 13324 : 4204 : appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
4386 tgl@sss.pgh.pa.us 13325 [ + + + + ]: 4204 : if (is_agg && finfo->nargs == 0)
4310 heikki.linnakangas@i 13326 : 80 : appendPQExpBufferStr(&fn, "(*)");
13327 : : else
4386 tgl@sss.pgh.pa.us 13328 : 4124 : appendPQExpBuffer(&fn, "(%s)", funcargs);
6259 13329 : 4204 : return fn.data;
13330 : : }
13331 : :
13332 : : /*
13333 : : * format_function_signature: generate function name and argument list
13334 : : *
13335 : : * Only a minimal list of input argument types is generated; this is
13336 : : * sufficient to reference the function, but not to define it.
13337 : : *
13338 : : * If honor_quotes is false then the function name is never quoted.
13339 : : * This is appropriate for use in TOC tags, but not in SQL commands.
13340 : : */
13341 : : static char *
1669 peter@eisentraut.org 13342 : 2228 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
13343 : : {
13344 : : PQExpBufferData fn;
13345 : : int j;
13346 : :
7463 tgl@sss.pgh.pa.us 13347 : 2228 : initPQExpBuffer(&fn);
13348 [ + + ]: 2228 : if (honor_quotes)
13349 : 417 : appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
13350 : : else
13351 : 1811 : appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
13352 [ + + ]: 4072 : for (j = 0; j < finfo->nargs; j++)
13353 : : {
4310 heikki.linnakangas@i 13354 [ + + ]: 1844 : if (j > 0)
13355 : 422 : appendPQExpBufferStr(&fn, ", ");
13356 : :
1459 tgl@sss.pgh.pa.us 13357 : 1844 : appendPQExpBufferStr(&fn,
13358 : 1844 : getFormattedTypeName(fout, finfo->argtypes[j],
13359 : : zeroIsError));
13360 : : }
4310 heikki.linnakangas@i 13361 : 2228 : appendPQExpBufferChar(&fn, ')');
7463 tgl@sss.pgh.pa.us 13362 : 2228 : return fn.data;
13363 : : }
13364 : :
13365 : :
13366 : : /*
13367 : : * dumpFunc:
13368 : : * dump out one function
13369 : : */
13370 : : static void
1669 peter@eisentraut.org 13371 : 1873 : dumpFunc(Archive *fout, const FuncInfo *finfo)
13372 : : {
3524 tgl@sss.pgh.pa.us 13373 : 1873 : DumpOptions *dopt = fout->dopt;
13374 : : PQExpBuffer query;
13375 : : PQExpBuffer q;
13376 : : PQExpBuffer delqry;
13377 : : PQExpBuffer asPart;
13378 : : PGresult *res;
13379 : : char *funcsig; /* identity signature */
2999 13380 : 1873 : char *funcfullsig = NULL; /* full signature */
13381 : : char *funcsig_tag;
13382 : : char *qual_funcsig;
13383 : : char *proretset;
13384 : : char *prosrc;
13385 : : char *probin;
13386 : : char *prosqlbody;
13387 : : char *funcargs;
13388 : : char *funciargs;
13389 : : char *funcresult;
13390 : : char *protrftypes;
13391 : : char *prokind;
13392 : : char *provolatile;
13393 : : char *proisstrict;
13394 : : char *prosecdef;
13395 : : char *proleakproof;
13396 : : char *proconfig;
13397 : : char *procost;
13398 : : char *prorows;
13399 : : char *prosupport;
13400 : : char *proparallel;
13401 : : char *lanname;
6578 13402 : 1873 : char **configitems = NULL;
13403 : 1873 : int nconfigitems = 0;
13404 : : const char *keyword;
13405 : :
13406 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 13407 [ + + ]: 1873 : if (!dopt->dumpSchema)
7327 tgl@sss.pgh.pa.us 13408 : 62 : return;
13409 : :
7945 13410 : 1811 : query = createPQExpBuffer();
13411 : 1811 : q = createPQExpBuffer();
13412 : 1811 : delqry = createPQExpBuffer();
13413 : 1811 : asPart = createPQExpBuffer();
13414 : :
1370 13415 [ + + ]: 1811 : if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
13416 : : {
13417 : : /* Set up query for function-specific details */
1787 drowley@postgresql.o 13418 : 67 : appendPQExpBufferStr(query,
13419 : : "PREPARE dumpFunc(pg_catalog.oid) AS\n");
13420 : :
13421 : 67 : appendPQExpBufferStr(query,
13422 : : "SELECT\n"
13423 : : "proretset,\n"
13424 : : "prosrc,\n"
13425 : : "probin,\n"
13426 : : "provolatile,\n"
13427 : : "proisstrict,\n"
13428 : : "prosecdef,\n"
13429 : : "lanname,\n"
13430 : : "proconfig,\n"
13431 : : "procost,\n"
13432 : : "prorows,\n"
13433 : : "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
13434 : : "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
13435 : : "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
13436 : : "proleakproof,\n");
13437 : :
1370 tgl@sss.pgh.pa.us 13438 [ + - ]: 67 : if (fout->remoteVersion >= 90500)
13439 : 67 : appendPQExpBufferStr(query,
13440 : : "array_to_string(protrftypes, ' ') AS protrftypes,\n");
13441 : : else
1357 tgl@sss.pgh.pa.us 13442 :UBC 0 : appendPQExpBufferStr(query,
13443 : : "NULL AS protrftypes,\n");
13444 : :
1370 tgl@sss.pgh.pa.us 13445 [ + - ]:CBC 67 : if (fout->remoteVersion >= 90600)
13446 : 67 : appendPQExpBufferStr(query,
13447 : : "proparallel,\n");
13448 : : else
1370 tgl@sss.pgh.pa.us 13449 :UBC 0 : appendPQExpBufferStr(query,
13450 : : "'u' AS proparallel,\n");
13451 : :
1370 tgl@sss.pgh.pa.us 13452 [ + - ]:CBC 67 : if (fout->remoteVersion >= 110000)
13453 : 67 : appendPQExpBufferStr(query,
13454 : : "prokind,\n");
13455 : : else
1370 tgl@sss.pgh.pa.us 13456 :UBC 0 : appendPQExpBufferStr(query,
13457 : : "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
13458 : :
1370 tgl@sss.pgh.pa.us 13459 [ + - ]:CBC 67 : if (fout->remoteVersion >= 120000)
13460 : 67 : appendPQExpBufferStr(query,
13461 : : "prosupport,\n");
13462 : : else
1370 tgl@sss.pgh.pa.us 13463 :UBC 0 : appendPQExpBufferStr(query,
13464 : : "'-' AS prosupport,\n");
13465 : :
1370 tgl@sss.pgh.pa.us 13466 [ + - ]:CBC 67 : if (fout->remoteVersion >= 140000)
13467 : 67 : appendPQExpBufferStr(query,
13468 : : "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
13469 : : else
1370 tgl@sss.pgh.pa.us 13470 :UBC 0 : appendPQExpBufferStr(query,
13471 : : "NULL AS prosqlbody\n");
13472 : :
1613 peter@eisentraut.org 13473 :CBC 67 : appendPQExpBufferStr(query,
13474 : : "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
13475 : : "WHERE p.oid = $1 "
13476 : : "AND l.oid = p.prolang");
13477 : :
1370 tgl@sss.pgh.pa.us 13478 : 67 : ExecuteSqlStatement(fout, query->data);
13479 : :
13480 : 67 : fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
13481 : : }
13482 : :
13483 : 1811 : printfPQExpBuffer(query,
13484 : : "EXECUTE dumpFunc('%u')",
1879 peter@eisentraut.org 13485 : 1811 : finfo->dobj.catId.oid);
13486 : :
4951 rhaas@postgresql.org 13487 : 1811 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13488 : :
8520 tgl@sss.pgh.pa.us 13489 : 1811 : proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
1613 peter@eisentraut.org 13490 [ + + ]: 1811 : if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
13491 : : {
13492 : 1757 : prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
13493 : 1757 : probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
13494 : 1757 : prosqlbody = NULL;
13495 : : }
13496 : : else
13497 : : {
13498 : 54 : prosrc = NULL;
13499 : 54 : probin = NULL;
13500 : 54 : prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
13501 : : }
1362 tgl@sss.pgh.pa.us 13502 : 1811 : funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13503 : 1811 : funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13504 : 1811 : funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
1357 13505 : 1811 : protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
2745 peter_e@gmx.net 13506 : 1811 : prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
8520 tgl@sss.pgh.pa.us 13507 : 1811 : provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
13508 : 1811 : proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
8512 peter_e@gmx.net 13509 : 1811 : prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
4954 rhaas@postgresql.org 13510 : 1811 : proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
6578 tgl@sss.pgh.pa.us 13511 : 1811 : proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
6802 13512 : 1811 : procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
13513 : 1811 : prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
2401 13514 : 1811 : prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
1879 peter@eisentraut.org 13515 : 1811 : proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
8520 tgl@sss.pgh.pa.us 13516 : 1811 : lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
13517 : :
13518 : : /*
13519 : : * See backend/commands/functioncmds.c for details of how the 'AS' clause
13520 : : * is used.
13521 : : */
1613 peter@eisentraut.org 13522 [ + + ]: 1811 : if (prosqlbody)
13523 : : {
13524 : 54 : appendPQExpBufferStr(asPart, prosqlbody);
13525 : : }
1360 tgl@sss.pgh.pa.us 13526 [ + + ]: 1757 : else if (probin[0] != '\0')
13527 : : {
4310 heikki.linnakangas@i 13528 : 138 : appendPQExpBufferStr(asPart, "AS ");
7041 tgl@sss.pgh.pa.us 13529 : 138 : appendStringLiteralAH(asPart, probin, fout);
1360 13530 [ + - ]: 138 : if (prosrc[0] != '\0')
13531 : : {
4310 heikki.linnakangas@i 13532 : 138 : appendPQExpBufferStr(asPart, ", ");
13533 : :
13534 : : /*
13535 : : * where we have bin, use dollar quoting if allowed and src
13536 : : * contains quote or backslash; else use regular quoting.
13537 : : */
3980 alvherre@alvh.no-ip. 13538 [ + - ]: 138 : if (dopt->disable_dollar_quoting ||
2999 tgl@sss.pgh.pa.us 13539 [ + - + - ]: 138 : (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
7041 13540 : 138 : appendStringLiteralAH(asPart, prosrc, fout);
13541 : : else
7041 tgl@sss.pgh.pa.us 13542 :UBC 0 : appendStringLiteralDQ(asPart, prosrc, NULL);
13543 : : }
13544 : : }
13545 : : else
13546 : : {
1360 tgl@sss.pgh.pa.us 13547 :CBC 1619 : appendPQExpBufferStr(asPart, "AS ");
13548 : : /* with no bin, dollar quote src unconditionally if allowed */
13549 [ - + ]: 1619 : if (dopt->disable_dollar_quoting)
1360 tgl@sss.pgh.pa.us 13550 :UBC 0 : appendStringLiteralAH(asPart, prosrc, fout);
13551 : : else
1360 tgl@sss.pgh.pa.us 13552 :CBC 1619 : appendStringLiteralDQ(asPart, prosrc, NULL);
13553 : : }
13554 : :
1357 13555 [ + + ]: 1811 : if (*proconfig)
13556 : : {
6578 13557 [ - + ]: 15 : if (!parsePGArray(proconfig, &configitems, &nconfigitems))
1247 tgl@sss.pgh.pa.us 13558 :UBC 0 : pg_fatal("could not parse %s array", "proconfig");
13559 : : }
13560 : : else
13561 : : {
1752 michael@paquier.xyz 13562 :CBC 1796 : configitems = NULL;
13563 : 1796 : nconfigitems = 0;
13564 : : }
13565 : :
1362 tgl@sss.pgh.pa.us 13566 : 1811 : funcfullsig = format_function_arguments(finfo, funcargs, false);
13567 : 1811 : funcsig = format_function_arguments(finfo, funciargs, false);
13568 : :
4961 rhaas@postgresql.org 13569 : 1811 : funcsig_tag = format_function_signature(fout, finfo, false);
13570 : :
1413 tgl@sss.pgh.pa.us 13571 : 1811 : qual_funcsig = psprintf("%s.%s",
13572 : 1811 : fmtId(finfo->dobj.namespace->dobj.name),
13573 : : funcsig);
13574 : :
2745 peter_e@gmx.net 13575 [ + + ]: 1811 : if (prokind[0] == PROKIND_PROCEDURE)
13576 : 98 : keyword = "PROCEDURE";
13577 : : else
13578 : 1713 : keyword = "FUNCTION"; /* works for window functions too */
13579 : :
1413 tgl@sss.pgh.pa.us 13580 : 1811 : appendPQExpBuffer(delqry, "DROP %s %s;\n",
13581 : : keyword, qual_funcsig);
13582 : :
2749 13583 [ + - ]: 3622 : appendPQExpBuffer(q, "CREATE %s %s.%s",
13584 : : keyword,
13585 : 1811 : fmtId(finfo->dobj.namespace->dobj.name),
13586 : : funcfullsig ? funcfullsig :
13587 : : funcsig);
13588 : :
2745 peter_e@gmx.net 13589 [ + + ]: 1811 : if (prokind[0] == PROKIND_PROCEDURE)
13590 : : /* no result type to output */ ;
2837 13591 [ + - ]: 1713 : else if (funcresult)
13592 : 1713 : appendPQExpBuffer(q, " RETURNS %s", funcresult);
13593 : : else
2837 peter_e@gmx.net 13594 :UBC 0 : appendPQExpBuffer(q, " RETURNS %s%s",
6259 tgl@sss.pgh.pa.us 13595 [ # # ]: 0 : (proretset[0] == 't') ? "SETOF " : "",
1459 13596 : 0 : getFormattedTypeName(fout, finfo->prorettype,
13597 : : zeroIsError));
13598 : :
6276 heikki.linnakangas@i 13599 :CBC 1811 : appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
13600 : :
1357 tgl@sss.pgh.pa.us 13601 [ - + ]: 1811 : if (*protrftypes)
13602 : : {
269 dgustafsson@postgres 13603 :UBC 0 : Oid *typeids = pg_malloc(FUNC_MAX_ARGS * sizeof(Oid));
13604 : : int i;
13605 : :
3786 peter_e@gmx.net 13606 : 0 : appendPQExpBufferStr(q, " TRANSFORM ");
13607 : 0 : parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
13608 [ # # ]: 0 : for (i = 0; typeids[i]; i++)
13609 : : {
13610 [ # # ]: 0 : if (i != 0)
13611 : 0 : appendPQExpBufferStr(q, ", ");
13612 : 0 : appendPQExpBuffer(q, "FOR TYPE %s",
2999 tgl@sss.pgh.pa.us 13613 : 0 : getFormattedTypeName(fout, typeids[i], zeroAsNone));
13614 : : }
13615 : :
269 dgustafsson@postgres 13616 : 0 : free(typeids);
13617 : : }
13618 : :
2745 peter_e@gmx.net 13619 [ + + ]:CBC 1811 : if (prokind[0] == PROKIND_WINDOW)
4310 heikki.linnakangas@i 13620 : 5 : appendPQExpBufferStr(q, " WINDOW");
13621 : :
8513 peter_e@gmx.net 13622 [ + + ]: 1811 : if (provolatile[0] != PROVOLATILE_VOLATILE)
13623 : : {
8520 tgl@sss.pgh.pa.us 13624 [ + + ]: 363 : if (provolatile[0] == PROVOLATILE_IMMUTABLE)
4310 heikki.linnakangas@i 13625 : 342 : appendPQExpBufferStr(q, " IMMUTABLE");
8520 tgl@sss.pgh.pa.us 13626 [ + - ]: 21 : else if (provolatile[0] == PROVOLATILE_STABLE)
4310 heikki.linnakangas@i 13627 : 21 : appendPQExpBufferStr(q, " STABLE");
8520 tgl@sss.pgh.pa.us 13628 [ # # ]:UBC 0 : else if (provolatile[0] != PROVOLATILE_VOLATILE)
1247 13629 : 0 : pg_fatal("unrecognized provolatile value for function \"%s\"",
13630 : : finfo->dobj.name);
13631 : : }
13632 : :
8513 peter_e@gmx.net 13633 [ + + ]:CBC 1811 : if (proisstrict[0] == 't')
4310 heikki.linnakangas@i 13634 : 371 : appendPQExpBufferStr(q, " STRICT");
13635 : :
8512 peter_e@gmx.net 13636 [ - + ]: 1811 : if (prosecdef[0] == 't')
4310 heikki.linnakangas@i 13637 :UBC 0 : appendPQExpBufferStr(q, " SECURITY DEFINER");
13638 : :
4954 rhaas@postgresql.org 13639 [ + + ]:CBC 1811 : if (proleakproof[0] == 't')
4310 heikki.linnakangas@i 13640 : 10 : appendPQExpBufferStr(q, " LEAKPROOF");
13641 : :
13642 : : /*
13643 : : * COST and ROWS are emitted only if present and not default, so as not to
13644 : : * break backwards-compatibility of the dump without need. Keep this code
13645 : : * in sync with the defaults in functioncmds.c.
13646 : : */
6802 tgl@sss.pgh.pa.us 13647 [ + - ]: 1811 : if (strcmp(procost, "0") != 0)
13648 : : {
13649 [ + + + + ]: 1811 : if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
13650 : : {
13651 : : /* default cost is 1 */
13652 [ - + ]: 391 : if (strcmp(procost, "1") != 0)
6802 tgl@sss.pgh.pa.us 13653 :UBC 0 : appendPQExpBuffer(q, " COST %s", procost);
13654 : : }
13655 : : else
13656 : : {
13657 : : /* default cost is 100 */
6802 tgl@sss.pgh.pa.us 13658 [ + + ]:CBC 1420 : if (strcmp(procost, "100") != 0)
13659 : 6 : appendPQExpBuffer(q, " COST %s", procost);
13660 : : }
13661 : : }
13662 [ + + ]: 1811 : if (proretset[0] == 't' &&
13663 [ + - - + ]: 193 : strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
6802 tgl@sss.pgh.pa.us 13664 :UBC 0 : appendPQExpBuffer(q, " ROWS %s", prorows);
13665 : :
2401 tgl@sss.pgh.pa.us 13666 [ + + ]:CBC 1811 : if (strcmp(prosupport, "-") != 0)
13667 : : {
13668 : : /* We rely on regprocout to provide quoting and qualification */
13669 : 48 : appendPQExpBuffer(q, " SUPPORT %s", prosupport);
13670 : : }
13671 : :
1879 peter@eisentraut.org 13672 [ + + ]: 1811 : if (proparallel[0] != PROPARALLEL_UNSAFE)
13673 : : {
3643 rhaas@postgresql.org 13674 [ + + ]: 128 : if (proparallel[0] == PROPARALLEL_SAFE)
13675 : 123 : appendPQExpBufferStr(q, " PARALLEL SAFE");
13676 [ + - ]: 5 : else if (proparallel[0] == PROPARALLEL_RESTRICTED)
13677 : 5 : appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
3643 rhaas@postgresql.org 13678 [ # # ]:UBC 0 : else if (proparallel[0] != PROPARALLEL_UNSAFE)
1247 tgl@sss.pgh.pa.us 13679 : 0 : pg_fatal("unrecognized proparallel value for function \"%s\"",
13680 : : finfo->dobj.name);
13681 : : }
13682 : :
1109 drowley@postgresql.o 13683 [ + + ]:CBC 1846 : for (int i = 0; i < nconfigitems; i++)
13684 : : {
13685 : : /* we feel free to scribble on configitems[] here */
6578 tgl@sss.pgh.pa.us 13686 : 35 : char *configitem = configitems[i];
13687 : : char *pos;
13688 : :
13689 : 35 : pos = strchr(configitem, '=');
13690 [ - + ]: 35 : if (pos == NULL)
6578 tgl@sss.pgh.pa.us 13691 :UBC 0 : continue;
6578 tgl@sss.pgh.pa.us 13692 :CBC 35 : *pos++ = '\0';
13693 : 35 : appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
13694 : :
13695 : : /*
13696 : : * Variables that are marked GUC_LIST_QUOTE were already fully quoted
13697 : : * by flatten_set_variable_args() before they were put into the
13698 : : * proconfig array. However, because the quoting rules used there
13699 : : * aren't exactly like SQL's, we have to break the list value apart
13700 : : * and then quote the elements as string literals. (The elements may
13701 : : * be double-quoted as-is, but we can't just feed them to the SQL
13702 : : * parser; it would do the wrong thing with elements that are
13703 : : * zero-length or longer than NAMEDATALEN.)
13704 : : *
13705 : : * Variables that are not so marked should just be emitted as simple
13706 : : * string literals. If the variable is not known to
13707 : : * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
13708 : : * to use GUC_LIST_QUOTE for extension variables.
13709 : : */
2726 13710 [ + + ]: 35 : if (variable_is_guc_list_quote(configitem))
13711 : : {
13712 : : char **namelist;
13713 : : char **nameptr;
13714 : :
13715 : : /* Parse string into list of identifiers */
13716 : : /* this shouldn't fail really */
2594 13717 [ + - ]: 10 : if (SplitGUCList(pos, ',', &namelist))
13718 : : {
13719 [ + + ]: 35 : for (nameptr = namelist; *nameptr; nameptr++)
13720 : : {
13721 [ + + ]: 25 : if (nameptr != namelist)
13722 : 15 : appendPQExpBufferStr(q, ", ");
13723 : 25 : appendStringLiteralAH(q, *nameptr, fout);
13724 : : }
13725 : : }
13726 : 10 : pg_free(namelist);
13727 : : }
13728 : : else
6578 13729 : 25 : appendStringLiteralAH(q, pos, fout);
13730 : : }
13731 : :
6276 heikki.linnakangas@i 13732 : 1811 : appendPQExpBuffer(q, "\n %s;\n", asPart->data);
13733 : :
2005 alvherre@alvh.no-ip. 13734 : 1811 : append_depends_on_extension(fout, q, &finfo->dobj,
13735 : : "pg_catalog.pg_proc", keyword,
13736 : : qual_funcsig);
13737 : :
3980 13738 [ + + ]: 1811 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 13739 : 288 : binary_upgrade_extension_member(q, &finfo->dobj,
13740 : : keyword, funcsig,
13741 : 288 : finfo->dobj.namespace->dobj.name);
13742 : :
3440 sfrost@snowman.net 13743 [ + + ]: 1811 : if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13744 : 1703 : ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 13745 [ + + ]: 1703 : ARCHIVE_OPTS(.tag = funcsig_tag,
13746 : : .namespace = finfo->dobj.namespace->dobj.name,
13747 : : .owner = finfo->rolname,
13748 : : .description = keyword,
13749 : : .section = finfo->postponed_def ?
13750 : : SECTION_POST_DATA : SECTION_PRE_DATA,
13751 : : .createStmt = q->data,
13752 : : .dropStmt = delqry->data));
13753 : :
13754 : : /* Dump Function Comments and Security Labels */
3440 sfrost@snowman.net 13755 [ + + ]: 1811 : if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 13756 : 9 : dumpComment(fout, keyword, funcsig,
3440 sfrost@snowman.net 13757 : 9 : finfo->dobj.namespace->dobj.name, finfo->rolname,
13758 : 9 : finfo->dobj.catId, 0, finfo->dobj.dumpId);
13759 : :
13760 [ - + ]: 1811 : if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 13761 :UBC 0 : dumpSecLabel(fout, keyword, funcsig,
3440 sfrost@snowman.net 13762 : 0 : finfo->dobj.namespace->dobj.name, finfo->rolname,
13763 : 0 : finfo->dobj.catId, 0, finfo->dobj.dumpId);
13764 : :
3440 sfrost@snowman.net 13765 [ + + ]:CBC 1811 : if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
1883 tgl@sss.pgh.pa.us 13766 : 112 : dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
13767 : : funcsig, NULL,
3440 sfrost@snowman.net 13768 : 112 : finfo->dobj.namespace->dobj.name,
523 tgl@sss.pgh.pa.us 13769 : 112 : NULL, finfo->rolname, &finfo->dacl);
13770 : :
8520 13771 : 1811 : PQclear(res);
13772 : :
13773 : 1811 : destroyPQExpBuffer(query);
8800 13774 : 1811 : destroyPQExpBuffer(q);
13775 : 1811 : destroyPQExpBuffer(delqry);
13776 : 1811 : destroyPQExpBuffer(asPart);
8511 peter_e@gmx.net 13777 : 1811 : free(funcsig);
1178 peter@eisentraut.org 13778 : 1811 : free(funcfullsig);
8465 bruce@momjian.us 13779 : 1811 : free(funcsig_tag);
1413 tgl@sss.pgh.pa.us 13780 : 1811 : free(qual_funcsig);
1178 peter@eisentraut.org 13781 : 1811 : free(configitems);
13782 : : }
13783 : :
13784 : :
13785 : : /*
13786 : : * Dump a user-defined cast
13787 : : */
13788 : : static void
1669 13789 : 73 : dumpCast(Archive *fout, const CastInfo *cast)
13790 : : {
3524 tgl@sss.pgh.pa.us 13791 : 73 : DumpOptions *dopt = fout->dopt;
13792 : : PQExpBuffer defqry;
13793 : : PQExpBuffer delqry;
13794 : : PQExpBuffer labelq;
13795 : : PQExpBuffer castargs;
7945 13796 : 73 : FuncInfo *funcInfo = NULL;
13797 : : const char *sourceType;
13798 : : const char *targetType;
13799 : :
13800 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 13801 [ + + ]: 73 : if (!dopt->dumpSchema)
7945 tgl@sss.pgh.pa.us 13802 : 6 : return;
13803 : :
13804 : : /* Cannot dump if we don't have the cast function's info */
13805 [ + + ]: 67 : if (OidIsValid(cast->castfunc))
13806 : : {
13807 : 42 : funcInfo = findFuncByOid(cast->castfunc);
13808 [ - + ]: 42 : if (funcInfo == NULL)
1247 tgl@sss.pgh.pa.us 13809 :UBC 0 : pg_fatal("could not find function definition for function with OID %u",
13810 : : cast->castfunc);
13811 : : }
13812 : :
7945 tgl@sss.pgh.pa.us 13813 :CBC 67 : defqry = createPQExpBuffer();
13814 : 67 : delqry = createPQExpBuffer();
5323 13815 : 67 : labelq = createPQExpBuffer();
2749 13816 : 67 : castargs = createPQExpBuffer();
13817 : :
3719 heikki.linnakangas@i 13818 : 67 : sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
13819 : 67 : targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
7945 tgl@sss.pgh.pa.us 13820 : 67 : appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
13821 : : sourceType, targetType);
13822 : :
13823 : 67 : appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
13824 : : sourceType, targetType);
13825 : :
5931 bruce@momjian.us 13826 [ + - + - ]: 67 : switch (cast->castmethod)
13827 : : {
6154 heikki.linnakangas@i 13828 : 25 : case COERCION_METHOD_BINARY:
4310 13829 : 25 : appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
6154 13830 : 25 : break;
6154 heikki.linnakangas@i 13831 :UBC 0 : case COERCION_METHOD_INOUT:
4310 13832 : 0 : appendPQExpBufferStr(defqry, "WITH INOUT");
6154 13833 : 0 : break;
6154 heikki.linnakangas@i 13834 :CBC 42 : case COERCION_METHOD_FUNCTION:
4922 peter_e@gmx.net 13835 [ + - ]: 42 : if (funcInfo)
13836 : : {
4836 bruce@momjian.us 13837 : 42 : char *fsig = format_function_signature(fout, funcInfo, true);
13838 : :
13839 : : /*
13840 : : * Always qualify the function name (format_function_signature
13841 : : * won't qualify it).
13842 : : */
4922 peter_e@gmx.net 13843 : 42 : appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
2999 tgl@sss.pgh.pa.us 13844 : 42 : fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
4922 peter_e@gmx.net 13845 : 42 : free(fsig);
13846 : : }
13847 : : else
2350 peter@eisentraut.org 13848 :UBC 0 : pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
6154 heikki.linnakangas@i 13849 :CBC 42 : break;
6154 heikki.linnakangas@i 13850 :UBC 0 : default:
2350 peter@eisentraut.org 13851 : 0 : pg_log_warning("bogus value in pg_cast.castmethod field");
13852 : : }
13853 : :
7945 tgl@sss.pgh.pa.us 13854 [ + + ]:CBC 67 : if (cast->castcontext == 'a')
4310 heikki.linnakangas@i 13855 : 37 : appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
7945 tgl@sss.pgh.pa.us 13856 [ + + ]: 30 : else if (cast->castcontext == 'i')
4310 heikki.linnakangas@i 13857 : 10 : appendPQExpBufferStr(defqry, " AS IMPLICIT");
13858 : 67 : appendPQExpBufferStr(defqry, ";\n");
13859 : :
5323 tgl@sss.pgh.pa.us 13860 : 67 : appendPQExpBuffer(labelq, "CAST (%s AS %s)",
13861 : : sourceType, targetType);
13862 : :
2749 13863 : 67 : appendPQExpBuffer(castargs, "(%s AS %s)",
13864 : : sourceType, targetType);
13865 : :
3980 alvherre@alvh.no-ip. 13866 [ + + ]: 67 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 13867 : 7 : binary_upgrade_extension_member(defqry, &cast->dobj,
13868 : 7 : "CAST", castargs->data, NULL);
13869 : :
3440 sfrost@snowman.net 13870 [ + - ]: 67 : if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
13871 : 67 : ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
2409 alvherre@alvh.no-ip. 13872 : 67 : ARCHIVE_OPTS(.tag = labelq->data,
13873 : : .description = "CAST",
13874 : : .section = SECTION_PRE_DATA,
13875 : : .createStmt = defqry->data,
13876 : : .dropStmt = delqry->data));
13877 : :
13878 : : /* Dump Cast Comments */
3440 sfrost@snowman.net 13879 [ - + ]: 67 : if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 13880 :UBC 0 : dumpComment(fout, "CAST", castargs->data,
13881 : : NULL, "",
3440 sfrost@snowman.net 13882 : 0 : cast->dobj.catId, 0, cast->dobj.dumpId);
13883 : :
8451 peter_e@gmx.net 13884 :CBC 67 : destroyPQExpBuffer(defqry);
13885 : 67 : destroyPQExpBuffer(delqry);
5323 tgl@sss.pgh.pa.us 13886 : 67 : destroyPQExpBuffer(labelq);
2749 13887 : 67 : destroyPQExpBuffer(castargs);
13888 : : }
13889 : :
13890 : : /*
13891 : : * Dump a transform
13892 : : */
13893 : : static void
1669 peter@eisentraut.org 13894 : 48 : dumpTransform(Archive *fout, const TransformInfo *transform)
13895 : : {
3524 tgl@sss.pgh.pa.us 13896 : 48 : DumpOptions *dopt = fout->dopt;
13897 : : PQExpBuffer defqry;
13898 : : PQExpBuffer delqry;
13899 : : PQExpBuffer labelq;
13900 : : PQExpBuffer transformargs;
3786 peter_e@gmx.net 13901 : 48 : FuncInfo *fromsqlFuncInfo = NULL;
13902 : 48 : FuncInfo *tosqlFuncInfo = NULL;
13903 : : char *lanname;
13904 : : const char *transformType;
13905 : :
13906 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 13907 [ + + ]: 48 : if (!dopt->dumpSchema)
3786 peter_e@gmx.net 13908 : 6 : return;
13909 : :
13910 : : /* Cannot dump if we don't have the transform functions' info */
13911 [ + - ]: 42 : if (OidIsValid(transform->trffromsql))
13912 : : {
13913 : 42 : fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
13914 [ - + ]: 42 : if (fromsqlFuncInfo == NULL)
1247 tgl@sss.pgh.pa.us 13915 :UBC 0 : pg_fatal("could not find function definition for function with OID %u",
13916 : : transform->trffromsql);
13917 : : }
3786 peter_e@gmx.net 13918 [ + - ]:CBC 42 : if (OidIsValid(transform->trftosql))
13919 : : {
13920 : 42 : tosqlFuncInfo = findFuncByOid(transform->trftosql);
13921 [ - + ]: 42 : if (tosqlFuncInfo == NULL)
1247 tgl@sss.pgh.pa.us 13922 :UBC 0 : pg_fatal("could not find function definition for function with OID %u",
13923 : : transform->trftosql);
13924 : : }
13925 : :
3786 peter_e@gmx.net 13926 :CBC 42 : defqry = createPQExpBuffer();
13927 : 42 : delqry = createPQExpBuffer();
13928 : 42 : labelq = createPQExpBuffer();
2749 tgl@sss.pgh.pa.us 13929 : 42 : transformargs = createPQExpBuffer();
13930 : :
3786 peter_e@gmx.net 13931 : 42 : lanname = get_language_name(fout, transform->trflang);
3719 heikki.linnakangas@i 13932 : 42 : transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
13933 : :
3786 peter_e@gmx.net 13934 : 42 : appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
13935 : : transformType, lanname);
13936 : :
13937 : 42 : appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
13938 : : transformType, lanname);
13939 : :
13940 [ - + - - ]: 42 : if (!transform->trffromsql && !transform->trftosql)
2350 peter@eisentraut.org 13941 :UBC 0 : pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
13942 : :
3786 peter_e@gmx.net 13943 [ + - ]:CBC 42 : if (transform->trffromsql)
13944 : : {
13945 [ + - ]: 42 : if (fromsqlFuncInfo)
13946 : : {
13947 : 42 : char *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
13948 : :
13949 : : /*
13950 : : * Always qualify the function name (format_function_signature
13951 : : * won't qualify it).
13952 : : */
13953 : 42 : appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
2999 tgl@sss.pgh.pa.us 13954 : 42 : fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
3786 peter_e@gmx.net 13955 : 42 : free(fsig);
13956 : : }
13957 : : else
2350 peter@eisentraut.org 13958 :UBC 0 : pg_log_warning("bogus value in pg_transform.trffromsql field");
13959 : : }
13960 : :
3786 peter_e@gmx.net 13961 [ + - ]:CBC 42 : if (transform->trftosql)
13962 : : {
13963 [ + - ]: 42 : if (transform->trffromsql)
2256 drowley@postgresql.o 13964 : 42 : appendPQExpBufferStr(defqry, ", ");
13965 : :
3786 peter_e@gmx.net 13966 [ + - ]: 42 : if (tosqlFuncInfo)
13967 : : {
13968 : 42 : char *fsig = format_function_signature(fout, tosqlFuncInfo, true);
13969 : :
13970 : : /*
13971 : : * Always qualify the function name (format_function_signature
13972 : : * won't qualify it).
13973 : : */
13974 : 42 : appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
2999 tgl@sss.pgh.pa.us 13975 : 42 : fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
3786 peter_e@gmx.net 13976 : 42 : free(fsig);
13977 : : }
13978 : : else
2350 peter@eisentraut.org 13979 :UBC 0 : pg_log_warning("bogus value in pg_transform.trftosql field");
13980 : : }
13981 : :
2256 drowley@postgresql.o 13982 :CBC 42 : appendPQExpBufferStr(defqry, ");\n");
13983 : :
3786 peter_e@gmx.net 13984 : 42 : appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
13985 : : transformType, lanname);
13986 : :
2749 tgl@sss.pgh.pa.us 13987 : 42 : appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
13988 : : transformType, lanname);
13989 : :
3786 peter_e@gmx.net 13990 [ + + ]: 42 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 13991 : 2 : binary_upgrade_extension_member(defqry, &transform->dobj,
13992 : 2 : "TRANSFORM", transformargs->data, NULL);
13993 : :
3440 sfrost@snowman.net 13994 [ + - ]: 42 : if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
13995 : 42 : ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
2409 alvherre@alvh.no-ip. 13996 : 42 : ARCHIVE_OPTS(.tag = labelq->data,
13997 : : .description = "TRANSFORM",
13998 : : .section = SECTION_PRE_DATA,
13999 : : .createStmt = defqry->data,
14000 : : .dropStmt = delqry->data,
14001 : : .deps = transform->dobj.dependencies,
14002 : : .nDeps = transform->dobj.nDeps));
14003 : :
14004 : : /* Dump Transform Comments */
3440 sfrost@snowman.net 14005 [ - + ]: 42 : if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 14006 :UBC 0 : dumpComment(fout, "TRANSFORM", transformargs->data,
14007 : : NULL, "",
3440 sfrost@snowman.net 14008 : 0 : transform->dobj.catId, 0, transform->dobj.dumpId);
14009 : :
3786 peter_e@gmx.net 14010 :CBC 42 : free(lanname);
14011 : 42 : destroyPQExpBuffer(defqry);
14012 : 42 : destroyPQExpBuffer(delqry);
14013 : 42 : destroyPQExpBuffer(labelq);
2749 tgl@sss.pgh.pa.us 14014 : 42 : destroyPQExpBuffer(transformargs);
14015 : : }
14016 : :
14017 : :
14018 : : /*
14019 : : * dumpOpr
14020 : : * write out a single operator definition
14021 : : */
14022 : : static void
1669 peter@eisentraut.org 14023 : 2510 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
14024 : : {
3524 tgl@sss.pgh.pa.us 14025 : 2510 : DumpOptions *dopt = fout->dopt;
14026 : : PQExpBuffer query;
14027 : : PQExpBuffer q;
14028 : : PQExpBuffer delq;
14029 : : PQExpBuffer oprid;
14030 : : PQExpBuffer details;
14031 : : PGresult *res;
14032 : : int i_oprkind;
14033 : : int i_oprcode;
14034 : : int i_oprleft;
14035 : : int i_oprright;
14036 : : int i_oprcom;
14037 : : int i_oprnegate;
14038 : : int i_oprrest;
14039 : : int i_oprjoin;
14040 : : int i_oprcanmerge;
14041 : : int i_oprcanhash;
14042 : : char *oprkind;
14043 : : char *oprcode;
14044 : : char *oprleft;
14045 : : char *oprright;
14046 : : char *oprcom;
14047 : : char *oprnegate;
14048 : : char *oprrest;
14049 : : char *oprjoin;
14050 : : char *oprcanmerge;
14051 : : char *oprcanhash;
14052 : : char *oprregproc;
14053 : : char *oprref;
14054 : :
14055 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 14056 [ + + ]: 2510 : if (!dopt->dumpSchema)
7945 tgl@sss.pgh.pa.us 14057 : 6 : return;
14058 : :
14059 : : /*
14060 : : * some operators are invalid because they were the result of user
14061 : : * defining operators before commutators exist
14062 : : */
14063 [ + + ]: 2504 : if (!OidIsValid(oprinfo->oprcode))
14064 : 14 : return;
14065 : :
14066 : 2490 : query = createPQExpBuffer();
14067 : 2490 : q = createPQExpBuffer();
14068 : 2490 : delq = createPQExpBuffer();
14069 : 2490 : oprid = createPQExpBuffer();
14070 : 2490 : details = createPQExpBuffer();
14071 : :
1370 14072 [ + + ]: 2490 : if (!fout->is_prepared[PREPQUERY_DUMPOPR])
14073 : : {
14074 : : /* Set up query for operator-specific details */
14075 : 46 : appendPQExpBufferStr(query,
14076 : : "PREPARE dumpOpr(pg_catalog.oid) AS\n"
14077 : : "SELECT oprkind, "
14078 : : "oprcode::pg_catalog.regprocedure, "
14079 : : "oprleft::pg_catalog.regtype, "
14080 : : "oprright::pg_catalog.regtype, "
14081 : : "oprcom, "
14082 : : "oprnegate, "
14083 : : "oprrest::pg_catalog.regprocedure, "
14084 : : "oprjoin::pg_catalog.regprocedure, "
14085 : : "oprcanmerge, oprcanhash "
14086 : : "FROM pg_catalog.pg_operator "
14087 : : "WHERE oid = $1");
14088 : :
14089 : 46 : ExecuteSqlStatement(fout, query->data);
14090 : :
14091 : 46 : fout->is_prepared[PREPQUERY_DUMPOPR] = true;
14092 : : }
14093 : :
14094 : 2490 : printfPQExpBuffer(query,
14095 : : "EXECUTE dumpOpr('%u')",
14096 : 2490 : oprinfo->dobj.catId.oid);
14097 : :
4951 rhaas@postgresql.org 14098 : 2490 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
14099 : :
8520 tgl@sss.pgh.pa.us 14100 : 2490 : i_oprkind = PQfnumber(res, "oprkind");
14101 : 2490 : i_oprcode = PQfnumber(res, "oprcode");
14102 : 2490 : i_oprleft = PQfnumber(res, "oprleft");
14103 : 2490 : i_oprright = PQfnumber(res, "oprright");
14104 : 2490 : i_oprcom = PQfnumber(res, "oprcom");
14105 : 2490 : i_oprnegate = PQfnumber(res, "oprnegate");
14106 : 2490 : i_oprrest = PQfnumber(res, "oprrest");
14107 : 2490 : i_oprjoin = PQfnumber(res, "oprjoin");
6832 14108 : 2490 : i_oprcanmerge = PQfnumber(res, "oprcanmerge");
8520 14109 : 2490 : i_oprcanhash = PQfnumber(res, "oprcanhash");
14110 : :
14111 : 2490 : oprkind = PQgetvalue(res, 0, i_oprkind);
14112 : 2490 : oprcode = PQgetvalue(res, 0, i_oprcode);
14113 : 2490 : oprleft = PQgetvalue(res, 0, i_oprleft);
14114 : 2490 : oprright = PQgetvalue(res, 0, i_oprright);
14115 : 2490 : oprcom = PQgetvalue(res, 0, i_oprcom);
14116 : 2490 : oprnegate = PQgetvalue(res, 0, i_oprnegate);
14117 : 2490 : oprrest = PQgetvalue(res, 0, i_oprrest);
14118 : 2490 : oprjoin = PQgetvalue(res, 0, i_oprjoin);
6832 14119 : 2490 : oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
8520 14120 : 2490 : oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
14121 : :
14122 : : /* In PG14 upwards postfix operator support does not exist anymore. */
1815 14123 [ - + ]: 2490 : if (strcmp(oprkind, "r") == 0)
1815 tgl@sss.pgh.pa.us 14124 :UBC 0 : pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
14125 : : oprcode);
14126 : :
1838 peter@eisentraut.org 14127 :CBC 2490 : oprregproc = convertRegProcReference(oprcode);
4207 sfrost@snowman.net 14128 [ + - ]: 2490 : if (oprregproc)
14129 : : {
2579 peter_e@gmx.net 14130 : 2490 : appendPQExpBuffer(details, " FUNCTION = %s", oprregproc);
4207 sfrost@snowman.net 14131 : 2490 : free(oprregproc);
14132 : : }
14133 : :
8520 tgl@sss.pgh.pa.us 14134 : 2490 : appendPQExpBuffer(oprid, "%s (",
7857 14135 : 2490 : oprinfo->dobj.name);
14136 : :
14137 : : /*
14138 : : * right unary means there's a left arg and left unary means there's a
14139 : : * right arg. (Although the "r" case is dead code for PG14 and later,
14140 : : * continue to support it in case we're dumping from an old server.)
14141 : : */
8520 14142 [ + - ]: 2490 : if (strcmp(oprkind, "r") == 0 ||
14143 [ + + ]: 2490 : strcmp(oprkind, "b") == 0)
14144 : : {
3251 14145 : 2347 : appendPQExpBuffer(details, ",\n LEFTARG = %s", oprleft);
14146 : 2347 : appendPQExpBufferStr(oprid, oprleft);
14147 : : }
14148 : : else
4310 heikki.linnakangas@i 14149 : 143 : appendPQExpBufferStr(oprid, "NONE");
14150 : :
8520 tgl@sss.pgh.pa.us 14151 [ + + ]: 2490 : if (strcmp(oprkind, "l") == 0 ||
14152 [ + - ]: 2347 : strcmp(oprkind, "b") == 0)
14153 : : {
3251 14154 : 2490 : appendPQExpBuffer(details, ",\n RIGHTARG = %s", oprright);
14155 : 2490 : appendPQExpBuffer(oprid, ", %s)", oprright);
14156 : : }
14157 : : else
4310 heikki.linnakangas@i 14158 :UBC 0 : appendPQExpBufferStr(oprid, ", NONE)");
14159 : :
1838 peter@eisentraut.org 14160 :CBC 2490 : oprref = getFormattedOperatorName(oprcom);
4207 sfrost@snowman.net 14161 [ + + ]: 2490 : if (oprref)
14162 : : {
14163 : 1661 : appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
14164 : 1661 : free(oprref);
14165 : : }
14166 : :
1838 peter@eisentraut.org 14167 : 2490 : oprref = getFormattedOperatorName(oprnegate);
4207 sfrost@snowman.net 14168 [ + + ]: 2490 : if (oprref)
14169 : : {
14170 : 1163 : appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
14171 : 1163 : free(oprref);
14172 : : }
14173 : :
6832 tgl@sss.pgh.pa.us 14174 [ + + ]: 2490 : if (strcmp(oprcanmerge, "t") == 0)
4310 heikki.linnakangas@i 14175 : 185 : appendPQExpBufferStr(details, ",\n MERGES");
14176 : :
8520 tgl@sss.pgh.pa.us 14177 [ + + ]: 2490 : if (strcmp(oprcanhash, "t") == 0)
4310 heikki.linnakangas@i 14178 : 138 : appendPQExpBufferStr(details, ",\n HASHES");
14179 : :
1838 peter@eisentraut.org 14180 : 2490 : oprregproc = convertRegProcReference(oprrest);
4207 sfrost@snowman.net 14181 [ + + ]: 2490 : if (oprregproc)
14182 : : {
14183 : 1514 : appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
14184 : 1514 : free(oprregproc);
14185 : : }
14186 : :
1838 peter@eisentraut.org 14187 : 2490 : oprregproc = convertRegProcReference(oprjoin);
4207 sfrost@snowman.net 14188 [ + + ]: 2490 : if (oprregproc)
14189 : : {
14190 : 1514 : appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
14191 : 1514 : free(oprregproc);
14192 : : }
14193 : :
8502 tgl@sss.pgh.pa.us 14194 : 2490 : appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
7857 14195 : 2490 : fmtId(oprinfo->dobj.namespace->dobj.name),
14196 : : oprid->data);
14197 : :
2749 14198 : 2490 : appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
14199 : 2490 : fmtId(oprinfo->dobj.namespace->dobj.name),
7857 14200 : 2490 : oprinfo->dobj.name, details->data);
14201 : :
3980 alvherre@alvh.no-ip. 14202 [ + + ]: 2490 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 14203 : 12 : binary_upgrade_extension_member(q, &oprinfo->dobj,
14204 : 12 : "OPERATOR", oprid->data,
14205 : 12 : oprinfo->dobj.namespace->dobj.name);
14206 : :
3440 sfrost@snowman.net 14207 [ + - ]: 2490 : if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14208 : 2490 : ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 14209 : 2490 : ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
14210 : : .namespace = oprinfo->dobj.namespace->dobj.name,
14211 : : .owner = oprinfo->rolname,
14212 : : .description = "OPERATOR",
14213 : : .section = SECTION_PRE_DATA,
14214 : : .createStmt = q->data,
14215 : : .dropStmt = delq->data));
14216 : :
14217 : : /* Dump Operator Comments */
3440 sfrost@snowman.net 14218 [ + + ]: 2490 : if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 14219 : 2397 : dumpComment(fout, "OPERATOR", oprid->data,
3440 sfrost@snowman.net 14220 : 2397 : oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
14221 : 2397 : oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
14222 : :
8520 tgl@sss.pgh.pa.us 14223 : 2490 : PQclear(res);
14224 : :
14225 : 2490 : destroyPQExpBuffer(query);
14226 : 2490 : destroyPQExpBuffer(q);
14227 : 2490 : destroyPQExpBuffer(delq);
14228 : 2490 : destroyPQExpBuffer(oprid);
14229 : 2490 : destroyPQExpBuffer(details);
14230 : : }
14231 : :
14232 : : /*
14233 : : * Convert a function reference obtained from pg_operator
14234 : : *
14235 : : * Returns allocated string of what to print, or NULL if function references
14236 : : * is InvalidOid. Returned string is expected to be free'd by the caller.
14237 : : *
14238 : : * The input is a REGPROCEDURE display; we have to strip the argument-types
14239 : : * part.
14240 : : */
14241 : : static char *
1838 peter@eisentraut.org 14242 : 7470 : convertRegProcReference(const char *proc)
14243 : : {
14244 : : char *name;
14245 : : char *paren;
14246 : : bool inquote;
14247 : :
14248 : : /* In all cases "-" means a null reference */
8520 tgl@sss.pgh.pa.us 14249 [ + + ]: 7470 : if (strcmp(proc, "-") == 0)
14250 : 1952 : return NULL;
14251 : :
3251 14252 : 5518 : name = pg_strdup(proc);
14253 : : /* find non-double-quoted left paren */
14254 : 5518 : inquote = false;
14255 [ + - ]: 66474 : for (paren = name; *paren; paren++)
14256 : : {
14257 [ + + + - ]: 66474 : if (*paren == '(' && !inquote)
14258 : : {
14259 : 5518 : *paren = '\0';
14260 : 5518 : break;
14261 : : }
14262 [ + + ]: 60956 : if (*paren == '"')
14263 : 50 : inquote = !inquote;
14264 : : }
14265 : 5518 : return name;
14266 : : }
14267 : :
14268 : : /*
14269 : : * getFormattedOperatorName - retrieve the operator name for the
14270 : : * given operator OID (presented in string form).
14271 : : *
14272 : : * Returns an allocated string, or NULL if the given OID is invalid.
14273 : : * Caller is responsible for free'ing result string.
14274 : : *
14275 : : * What we produce has the format "OPERATOR(schema.oprname)". This is only
14276 : : * useful in commands where the operator's argument types can be inferred from
14277 : : * context. We always schema-qualify the name, though. The predecessor to
14278 : : * this code tried to skip the schema qualification if possible, but that led
14279 : : * to wrong results in corner cases, such as if an operator and its negator
14280 : : * are in different schemas.
14281 : : */
14282 : : static char *
1838 peter@eisentraut.org 14283 : 5271 : getFormattedOperatorName(const char *oproid)
14284 : : {
14285 : : OprInfo *oprInfo;
14286 : :
14287 : : /* In all cases "0" means a null reference */
2749 tgl@sss.pgh.pa.us 14288 [ + + ]: 5271 : if (strcmp(oproid, "0") == 0)
8520 14289 : 2447 : return NULL;
14290 : :
2749 14291 : 2824 : oprInfo = findOprByOid(atooid(oproid));
14292 [ - + ]: 2824 : if (oprInfo == NULL)
14293 : : {
2350 peter@eisentraut.org 14294 :UBC 0 : pg_log_warning("could not find operator with OID %s",
14295 : : oproid);
2749 tgl@sss.pgh.pa.us 14296 : 0 : return NULL;
14297 : : }
14298 : :
2749 tgl@sss.pgh.pa.us 14299 :CBC 2824 : return psprintf("OPERATOR(%s.%s)",
14300 : 2824 : fmtId(oprInfo->dobj.namespace->dobj.name),
14301 : : oprInfo->dobj.name);
14302 : : }
14303 : :
14304 : : /*
14305 : : * Convert a function OID obtained from pg_ts_parser or pg_ts_template
14306 : : *
14307 : : * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
14308 : : * argument lists of these functions are predetermined. Note that the
14309 : : * caller should ensure we are in the proper schema, because the results
14310 : : * are search path dependent!
14311 : : */
14312 : : static char *
4960 rhaas@postgresql.org 14313 : 235 : convertTSFunction(Archive *fout, Oid funcOid)
14314 : : {
14315 : : char *result;
14316 : : char query[128];
14317 : : PGresult *res;
14318 : :
6591 tgl@sss.pgh.pa.us 14319 : 235 : snprintf(query, sizeof(query),
14320 : : "SELECT '%u'::pg_catalog.regproc", funcOid);
4951 rhaas@postgresql.org 14321 : 235 : res = ExecuteSqlQueryForSingleRow(fout, query);
14322 : :
5034 bruce@momjian.us 14323 : 235 : result = pg_strdup(PQgetvalue(res, 0, 0));
14324 : :
6591 tgl@sss.pgh.pa.us 14325 : 235 : PQclear(res);
14326 : :
14327 : 235 : return result;
14328 : : }
14329 : :
14330 : : /*
14331 : : * dumpAccessMethod
14332 : : * write out a single access method definition
14333 : : */
14334 : : static void
1669 peter@eisentraut.org 14335 : 92 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
14336 : : {
3454 alvherre@alvh.no-ip. 14337 : 92 : DumpOptions *dopt = fout->dopt;
14338 : : PQExpBuffer q;
14339 : : PQExpBuffer delq;
14340 : : char *qamname;
14341 : :
14342 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 14343 [ + + ]: 92 : if (!dopt->dumpSchema)
3454 alvherre@alvh.no-ip. 14344 : 12 : return;
14345 : :
14346 : 80 : q = createPQExpBuffer();
14347 : 80 : delq = createPQExpBuffer();
14348 : :
14349 : 80 : qamname = pg_strdup(fmtId(aminfo->dobj.name));
14350 : :
14351 : 80 : appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
14352 : :
14353 [ + + - ]: 80 : switch (aminfo->amtype)
14354 : : {
14355 : 38 : case AMTYPE_INDEX:
2256 drowley@postgresql.o 14356 : 38 : appendPQExpBufferStr(q, "TYPE INDEX ");
3454 alvherre@alvh.no-ip. 14357 : 38 : break;
2376 andres@anarazel.de 14358 : 42 : case AMTYPE_TABLE:
2256 drowley@postgresql.o 14359 : 42 : appendPQExpBufferStr(q, "TYPE TABLE ");
2376 andres@anarazel.de 14360 : 42 : break;
3454 alvherre@alvh.no-ip. 14361 :UBC 0 : default:
2350 peter@eisentraut.org 14362 : 0 : pg_log_warning("invalid type \"%c\" of access method \"%s\"",
14363 : : aminfo->amtype, qamname);
3454 alvherre@alvh.no-ip. 14364 : 0 : destroyPQExpBuffer(q);
14365 : 0 : destroyPQExpBuffer(delq);
2749 tgl@sss.pgh.pa.us 14366 : 0 : free(qamname);
3454 alvherre@alvh.no-ip. 14367 : 0 : return;
14368 : : }
14369 : :
3454 alvherre@alvh.no-ip. 14370 :CBC 80 : appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
14371 : :
14372 : 80 : appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
14373 : : qamname);
14374 : :
3261 tgl@sss.pgh.pa.us 14375 [ + + ]: 80 : if (dopt->binary_upgrade)
2749 14376 : 4 : binary_upgrade_extension_member(q, &aminfo->dobj,
14377 : : "ACCESS METHOD", qamname, NULL);
14378 : :
3378 sfrost@snowman.net 14379 [ + - ]: 80 : if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14380 : 80 : ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 14381 : 80 : ARCHIVE_OPTS(.tag = aminfo->dobj.name,
14382 : : .description = "ACCESS METHOD",
14383 : : .section = SECTION_PRE_DATA,
14384 : : .createStmt = q->data,
14385 : : .dropStmt = delq->data));
14386 : :
14387 : : /* Dump Access Method Comments */
3378 sfrost@snowman.net 14388 [ - + ]: 80 : if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 14389 :UBC 0 : dumpComment(fout, "ACCESS METHOD", qamname,
14390 : : NULL, "",
3378 sfrost@snowman.net 14391 : 0 : aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
14392 : :
3454 alvherre@alvh.no-ip. 14393 :CBC 80 : destroyPQExpBuffer(q);
14394 : 80 : destroyPQExpBuffer(delq);
2749 tgl@sss.pgh.pa.us 14395 : 80 : free(qamname);
14396 : : }
14397 : :
14398 : : /*
14399 : : * dumpOpclass
14400 : : * write out a single operator class definition
14401 : : */
14402 : : static void
1669 peter@eisentraut.org 14403 : 678 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
14404 : : {
3524 tgl@sss.pgh.pa.us 14405 : 678 : DumpOptions *dopt = fout->dopt;
14406 : : PQExpBuffer query;
14407 : : PQExpBuffer q;
14408 : : PQExpBuffer delq;
14409 : : PQExpBuffer nameusing;
14410 : : PGresult *res;
14411 : : int ntups;
14412 : : int i_opcintype;
14413 : : int i_opckeytype;
14414 : : int i_opcdefault;
14415 : : int i_opcfamily;
14416 : : int i_opcfamilyname;
14417 : : int i_opcfamilynsp;
14418 : : int i_amname;
14419 : : int i_amopstrategy;
14420 : : int i_amopopr;
14421 : : int i_sortfamily;
14422 : : int i_sortfamilynsp;
14423 : : int i_amprocnum;
14424 : : int i_amproc;
14425 : : int i_amproclefttype;
14426 : : int i_amprocrighttype;
14427 : : char *opcintype;
14428 : : char *opckeytype;
14429 : : char *opcdefault;
14430 : : char *opcfamily;
14431 : : char *opcfamilyname;
14432 : : char *opcfamilynsp;
14433 : : char *amname;
14434 : : char *amopstrategy;
14435 : : char *amopopr;
14436 : : char *sortfamily;
14437 : : char *sortfamilynsp;
14438 : : char *amprocnum;
14439 : : char *amproc;
14440 : : char *amproclefttype;
14441 : : char *amprocrighttype;
14442 : : bool needComma;
14443 : : int i;
14444 : :
14445 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 14446 [ + + ]: 678 : if (!dopt->dumpSchema)
7945 tgl@sss.pgh.pa.us 14447 : 18 : return;
14448 : :
14449 : 660 : query = createPQExpBuffer();
14450 : 660 : q = createPQExpBuffer();
14451 : 660 : delq = createPQExpBuffer();
2749 14452 : 660 : nameusing = createPQExpBuffer();
14453 : :
14454 : : /* Get additional fields from the pg_opclass row */
1362 14455 : 660 : appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
14456 : : "opckeytype::pg_catalog.regtype, "
14457 : : "opcdefault, opcfamily, "
14458 : : "opfname AS opcfamilyname, "
14459 : : "nspname AS opcfamilynsp, "
14460 : : "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
14461 : : "FROM pg_catalog.pg_opclass c "
14462 : : "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
14463 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14464 : : "WHERE c.oid = '%u'::pg_catalog.oid",
14465 : 660 : opcinfo->dobj.catId.oid);
14466 : :
4951 rhaas@postgresql.org 14467 : 660 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
14468 : :
8439 tgl@sss.pgh.pa.us 14469 : 660 : i_opcintype = PQfnumber(res, "opcintype");
14470 : 660 : i_opckeytype = PQfnumber(res, "opckeytype");
14471 : 660 : i_opcdefault = PQfnumber(res, "opcdefault");
6801 14472 : 660 : i_opcfamily = PQfnumber(res, "opcfamily");
5400 14473 : 660 : i_opcfamilyname = PQfnumber(res, "opcfamilyname");
6801 14474 : 660 : i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
8439 14475 : 660 : i_amname = PQfnumber(res, "amname");
14476 : :
14477 : : /* opcintype may still be needed after we PQclear res */
3025 14478 : 660 : opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
8439 14479 : 660 : opckeytype = PQgetvalue(res, 0, i_opckeytype);
14480 : 660 : opcdefault = PQgetvalue(res, 0, i_opcdefault);
14481 : : /* opcfamily will still be needed after we PQclear res */
5034 bruce@momjian.us 14482 : 660 : opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
5400 tgl@sss.pgh.pa.us 14483 : 660 : opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
6801 14484 : 660 : opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
14485 : : /* amname will still be needed after we PQclear res */
5034 bruce@momjian.us 14486 : 660 : amname = pg_strdup(PQgetvalue(res, 0, i_amname));
14487 : :
8439 tgl@sss.pgh.pa.us 14488 : 660 : appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
2749 14489 : 660 : fmtQualifiedDumpable(opcinfo));
8439 14490 : 660 : appendPQExpBuffer(delq, " USING %s;\n",
14491 : : fmtId(amname));
14492 : :
14493 : : /* Build the fixed portion of the CREATE command */
8420 peter_e@gmx.net 14494 : 660 : appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
2749 tgl@sss.pgh.pa.us 14495 : 660 : fmtQualifiedDumpable(opcinfo));
8439 14496 [ + + ]: 660 : if (strcmp(opcdefault, "t") == 0)
4310 heikki.linnakangas@i 14497 : 357 : appendPQExpBufferStr(q, "DEFAULT ");
6801 tgl@sss.pgh.pa.us 14498 : 660 : appendPQExpBuffer(q, "FOR TYPE %s USING %s",
14499 : : opcintype,
14500 : : fmtId(amname));
3433 14501 [ + - ]: 660 : if (strlen(opcfamilyname) > 0)
14502 : : {
4310 heikki.linnakangas@i 14503 : 660 : appendPQExpBufferStr(q, " FAMILY ");
2749 tgl@sss.pgh.pa.us 14504 : 660 : appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
3719 heikki.linnakangas@i 14505 : 660 : appendPQExpBufferStr(q, fmtId(opcfamilyname));
14506 : : }
4310 14507 : 660 : appendPQExpBufferStr(q, " AS\n ");
14508 : :
8439 tgl@sss.pgh.pa.us 14509 : 660 : needComma = false;
14510 : :
14511 [ + + ]: 660 : if (strcmp(opckeytype, "-") != 0)
14512 : : {
8420 peter_e@gmx.net 14513 : 252 : appendPQExpBuffer(q, "STORAGE %s",
14514 : : opckeytype);
8439 tgl@sss.pgh.pa.us 14515 : 252 : needComma = true;
14516 : : }
14517 : :
14518 : 660 : PQclear(res);
14519 : :
14520 : : /*
14521 : : * Now fetch and print the OPERATOR entries (pg_amop rows).
14522 : : *
14523 : : * Print only those opfamily members that are tied to the opclass by
14524 : : * pg_depend entries.
14525 : : */
14526 : 660 : resetPQExpBuffer(query);
1362 14527 : 660 : appendPQExpBuffer(query, "SELECT amopstrategy, "
14528 : : "amopopr::pg_catalog.regoperator, "
14529 : : "opfname AS sortfamily, "
14530 : : "nspname AS sortfamilynsp "
14531 : : "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
14532 : : "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
14533 : : "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
14534 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14535 : : "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
14536 : : "AND refobjid = '%u'::pg_catalog.oid "
14537 : : "AND amopfamily = '%s'::pg_catalog.oid "
14538 : : "ORDER BY amopstrategy",
14539 : 660 : opcinfo->dobj.catId.oid,
14540 : : opcfamily);
14541 : :
4960 rhaas@postgresql.org 14542 : 660 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14543 : :
8439 tgl@sss.pgh.pa.us 14544 : 660 : ntups = PQntuples(res);
14545 : :
14546 : 660 : i_amopstrategy = PQfnumber(res, "amopstrategy");
14547 : 660 : i_amopopr = PQfnumber(res, "amopopr");
5400 14548 : 660 : i_sortfamily = PQfnumber(res, "sortfamily");
14549 : 660 : i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
14550 : :
8439 14551 [ + + ]: 898 : for (i = 0; i < ntups; i++)
14552 : : {
14553 : 238 : amopstrategy = PQgetvalue(res, i, i_amopstrategy);
14554 : 238 : amopopr = PQgetvalue(res, i, i_amopopr);
5400 14555 : 238 : sortfamily = PQgetvalue(res, i, i_sortfamily);
14556 : 238 : sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
14557 : :
8439 14558 [ + + ]: 238 : if (needComma)
4310 heikki.linnakangas@i 14559 : 152 : appendPQExpBufferStr(q, " ,\n ");
14560 : :
8420 peter_e@gmx.net 14561 : 238 : appendPQExpBuffer(q, "OPERATOR %s %s",
14562 : : amopstrategy, amopopr);
14563 : :
5400 tgl@sss.pgh.pa.us 14564 [ - + ]: 238 : if (strlen(sortfamily) > 0)
14565 : : {
4310 heikki.linnakangas@i 14566 :UBC 0 : appendPQExpBufferStr(q, " FOR ORDER BY ");
2749 tgl@sss.pgh.pa.us 14567 : 0 : appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
4310 heikki.linnakangas@i 14568 : 0 : appendPQExpBufferStr(q, fmtId(sortfamily));
14569 : : }
14570 : :
8439 tgl@sss.pgh.pa.us 14571 :CBC 238 : needComma = true;
14572 : : }
14573 : :
14574 : 660 : PQclear(res);
14575 : :
14576 : : /*
14577 : : * Now fetch and print the FUNCTION entries (pg_amproc rows).
14578 : : *
14579 : : * Print only those opfamily members that are tied to the opclass by
14580 : : * pg_depend entries.
14581 : : *
14582 : : * We print the amproclefttype/amprocrighttype even though in most cases
14583 : : * the backend could deduce the right values, because of the corner case
14584 : : * of a btree sort support function for a cross-type comparison.
14585 : : */
14586 : 660 : resetPQExpBuffer(query);
14587 : :
1362 14588 : 660 : appendPQExpBuffer(query, "SELECT amprocnum, "
14589 : : "amproc::pg_catalog.regprocedure, "
14590 : : "amproclefttype::pg_catalog.regtype, "
14591 : : "amprocrighttype::pg_catalog.regtype "
14592 : : "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
14593 : : "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
14594 : : "AND refobjid = '%u'::pg_catalog.oid "
14595 : : "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
14596 : : "AND objid = ap.oid "
14597 : : "ORDER BY amprocnum",
14598 : 660 : opcinfo->dobj.catId.oid);
14599 : :
4960 rhaas@postgresql.org 14600 : 660 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14601 : :
8439 tgl@sss.pgh.pa.us 14602 : 660 : ntups = PQntuples(res);
14603 : :
14604 : 660 : i_amprocnum = PQfnumber(res, "amprocnum");
14605 : 660 : i_amproc = PQfnumber(res, "amproc");
5022 14606 : 660 : i_amproclefttype = PQfnumber(res, "amproclefttype");
14607 : 660 : i_amprocrighttype = PQfnumber(res, "amprocrighttype");
14608 : :
8439 14609 [ + + ]: 698 : for (i = 0; i < ntups; i++)
14610 : : {
14611 : 38 : amprocnum = PQgetvalue(res, i, i_amprocnum);
14612 : 38 : amproc = PQgetvalue(res, i, i_amproc);
5022 14613 : 38 : amproclefttype = PQgetvalue(res, i, i_amproclefttype);
14614 : 38 : amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
14615 : :
8439 14616 [ + - ]: 38 : if (needComma)
4310 heikki.linnakangas@i 14617 : 38 : appendPQExpBufferStr(q, " ,\n ");
14618 : :
5022 tgl@sss.pgh.pa.us 14619 : 38 : appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
14620 : :
14621 [ + - + - ]: 38 : if (*amproclefttype && *amprocrighttype)
14622 : 38 : appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
14623 : :
14624 : 38 : appendPQExpBuffer(q, " %s", amproc);
14625 : :
8439 14626 : 38 : needComma = true;
14627 : : }
14628 : :
14629 : 660 : PQclear(res);
14630 : :
14631 : : /*
14632 : : * If needComma is still false it means we haven't added anything after
14633 : : * the AS keyword. To avoid printing broken SQL, append a dummy STORAGE
14634 : : * clause with the same datatype. This isn't sanctioned by the
14635 : : * documentation, but actually DefineOpClass will treat it as a no-op.
14636 : : */
3025 14637 [ + + ]: 660 : if (!needComma)
14638 : 322 : appendPQExpBuffer(q, "STORAGE %s", opcintype);
14639 : :
4310 heikki.linnakangas@i 14640 : 660 : appendPQExpBufferStr(q, ";\n");
14641 : :
2749 tgl@sss.pgh.pa.us 14642 : 660 : appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
14643 : 660 : appendPQExpBuffer(nameusing, " USING %s",
14644 : : fmtId(amname));
14645 : :
3980 alvherre@alvh.no-ip. 14646 [ + + ]: 660 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 14647 : 6 : binary_upgrade_extension_member(q, &opcinfo->dobj,
14648 : 6 : "OPERATOR CLASS", nameusing->data,
14649 : 6 : opcinfo->dobj.namespace->dobj.name);
14650 : :
3440 sfrost@snowman.net 14651 [ + - ]: 660 : if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14652 : 660 : ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 14653 : 660 : ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
14654 : : .namespace = opcinfo->dobj.namespace->dobj.name,
14655 : : .owner = opcinfo->rolname,
14656 : : .description = "OPERATOR CLASS",
14657 : : .section = SECTION_PRE_DATA,
14658 : : .createStmt = q->data,
14659 : : .dropStmt = delq->data));
14660 : :
14661 : : /* Dump Operator Class Comments */
3440 sfrost@snowman.net 14662 [ - + ]: 660 : if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 14663 :UBC 0 : dumpComment(fout, "OPERATOR CLASS", nameusing->data,
3106 14664 : 0 : opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
3440 sfrost@snowman.net 14665 : 0 : opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
14666 : :
3025 tgl@sss.pgh.pa.us 14667 :CBC 660 : free(opcintype);
14668 : 660 : free(opcfamily);
7960 14669 : 660 : free(amname);
8439 14670 : 660 : destroyPQExpBuffer(query);
14671 : 660 : destroyPQExpBuffer(q);
14672 : 660 : destroyPQExpBuffer(delq);
2749 14673 : 660 : destroyPQExpBuffer(nameusing);
14674 : : }
14675 : :
14676 : : /*
14677 : : * dumpOpfamily
14678 : : * write out a single operator family definition
14679 : : *
14680 : : * Note: this also dumps any "loose" operator members that aren't bound to a
14681 : : * specific opclass within the opfamily.
14682 : : */
14683 : : static void
1669 peter@eisentraut.org 14684 : 561 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
14685 : : {
3524 tgl@sss.pgh.pa.us 14686 : 561 : DumpOptions *dopt = fout->dopt;
14687 : : PQExpBuffer query;
14688 : : PQExpBuffer q;
14689 : : PQExpBuffer delq;
14690 : : PQExpBuffer nameusing;
14691 : : PGresult *res;
14692 : : PGresult *res_ops;
14693 : : PGresult *res_procs;
14694 : : int ntups;
14695 : : int i_amname;
14696 : : int i_amopstrategy;
14697 : : int i_amopopr;
14698 : : int i_sortfamily;
14699 : : int i_sortfamilynsp;
14700 : : int i_amprocnum;
14701 : : int i_amproc;
14702 : : int i_amproclefttype;
14703 : : int i_amprocrighttype;
14704 : : char *amname;
14705 : : char *amopstrategy;
14706 : : char *amopopr;
14707 : : char *sortfamily;
14708 : : char *sortfamilynsp;
14709 : : char *amprocnum;
14710 : : char *amproc;
14711 : : char *amproclefttype;
14712 : : char *amprocrighttype;
14713 : : bool needComma;
14714 : : int i;
14715 : :
14716 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 14717 [ + + ]: 561 : if (!dopt->dumpSchema)
6801 tgl@sss.pgh.pa.us 14718 : 12 : return;
14719 : :
14720 : 549 : query = createPQExpBuffer();
14721 : 549 : q = createPQExpBuffer();
14722 : 549 : delq = createPQExpBuffer();
2749 14723 : 549 : nameusing = createPQExpBuffer();
14724 : :
14725 : : /*
14726 : : * Fetch only those opfamily members that are tied directly to the
14727 : : * opfamily by pg_depend entries.
14728 : : */
1362 14729 : 549 : appendPQExpBuffer(query, "SELECT amopstrategy, "
14730 : : "amopopr::pg_catalog.regoperator, "
14731 : : "opfname AS sortfamily, "
14732 : : "nspname AS sortfamilynsp "
14733 : : "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
14734 : : "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
14735 : : "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
14736 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14737 : : "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
14738 : : "AND refobjid = '%u'::pg_catalog.oid "
14739 : : "AND amopfamily = '%u'::pg_catalog.oid "
14740 : : "ORDER BY amopstrategy",
14741 : 549 : opfinfo->dobj.catId.oid,
14742 : 549 : opfinfo->dobj.catId.oid);
14743 : :
4960 rhaas@postgresql.org 14744 : 549 : res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14745 : :
6801 tgl@sss.pgh.pa.us 14746 : 549 : resetPQExpBuffer(query);
14747 : :
14748 : 549 : appendPQExpBuffer(query, "SELECT amprocnum, "
14749 : : "amproc::pg_catalog.regprocedure, "
14750 : : "amproclefttype::pg_catalog.regtype, "
14751 : : "amprocrighttype::pg_catalog.regtype "
14752 : : "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
14753 : : "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
14754 : : "AND refobjid = '%u'::pg_catalog.oid "
14755 : : "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
14756 : : "AND objid = ap.oid "
14757 : : "ORDER BY amprocnum",
14758 : 549 : opfinfo->dobj.catId.oid);
14759 : :
4960 rhaas@postgresql.org 14760 : 549 : res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14761 : :
14762 : : /* Get additional fields from the pg_opfamily row */
6801 tgl@sss.pgh.pa.us 14763 : 549 : resetPQExpBuffer(query);
14764 : :
14765 : 549 : appendPQExpBuffer(query, "SELECT "
14766 : : "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
14767 : : "FROM pg_catalog.pg_opfamily "
14768 : : "WHERE oid = '%u'::pg_catalog.oid",
14769 : 549 : opfinfo->dobj.catId.oid);
14770 : :
4951 rhaas@postgresql.org 14771 : 549 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
14772 : :
6801 tgl@sss.pgh.pa.us 14773 : 549 : i_amname = PQfnumber(res, "amname");
14774 : :
14775 : : /* amname will still be needed after we PQclear res */
5034 bruce@momjian.us 14776 : 549 : amname = pg_strdup(PQgetvalue(res, 0, i_amname));
14777 : :
6801 tgl@sss.pgh.pa.us 14778 : 549 : appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
2749 14779 : 549 : fmtQualifiedDumpable(opfinfo));
6801 14780 : 549 : appendPQExpBuffer(delq, " USING %s;\n",
14781 : : fmtId(amname));
14782 : :
14783 : : /* Build the fixed portion of the CREATE command */
14784 : 549 : appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
2749 14785 : 549 : fmtQualifiedDumpable(opfinfo));
6801 14786 : 549 : appendPQExpBuffer(q, " USING %s;\n",
14787 : : fmtId(amname));
14788 : :
14789 : 549 : PQclear(res);
14790 : :
14791 : : /* Do we need an ALTER to add loose members? */
14792 [ + + + + ]: 549 : if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
14793 : : {
14794 : 53 : appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
2749 14795 : 53 : fmtQualifiedDumpable(opfinfo));
6801 14796 : 53 : appendPQExpBuffer(q, " USING %s ADD\n ",
14797 : : fmtId(amname));
14798 : :
14799 : 53 : needComma = false;
14800 : :
14801 : : /*
14802 : : * Now fetch and print the OPERATOR entries (pg_amop rows).
14803 : : */
14804 : 53 : ntups = PQntuples(res_ops);
14805 : :
14806 : 53 : i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
14807 : 53 : i_amopopr = PQfnumber(res_ops, "amopopr");
5400 14808 : 53 : i_sortfamily = PQfnumber(res_ops, "sortfamily");
14809 : 53 : i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
14810 : :
6801 14811 [ + + ]: 243 : for (i = 0; i < ntups; i++)
14812 : : {
14813 : 190 : amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
14814 : 190 : amopopr = PQgetvalue(res_ops, i, i_amopopr);
5400 14815 : 190 : sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
14816 : 190 : sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
14817 : :
6801 14818 [ + + ]: 190 : if (needComma)
4310 heikki.linnakangas@i 14819 : 152 : appendPQExpBufferStr(q, " ,\n ");
14820 : :
6801 tgl@sss.pgh.pa.us 14821 : 190 : appendPQExpBuffer(q, "OPERATOR %s %s",
14822 : : amopstrategy, amopopr);
14823 : :
5400 14824 [ - + ]: 190 : if (strlen(sortfamily) > 0)
14825 : : {
4310 heikki.linnakangas@i 14826 :UBC 0 : appendPQExpBufferStr(q, " FOR ORDER BY ");
2749 tgl@sss.pgh.pa.us 14827 : 0 : appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
4310 heikki.linnakangas@i 14828 : 0 : appendPQExpBufferStr(q, fmtId(sortfamily));
14829 : : }
14830 : :
6801 tgl@sss.pgh.pa.us 14831 :CBC 190 : needComma = true;
14832 : : }
14833 : :
14834 : : /*
14835 : : * Now fetch and print the FUNCTION entries (pg_amproc rows).
14836 : : */
14837 : 53 : ntups = PQntuples(res_procs);
14838 : :
14839 : 53 : i_amprocnum = PQfnumber(res_procs, "amprocnum");
14840 : 53 : i_amproc = PQfnumber(res_procs, "amproc");
14841 : 53 : i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
14842 : 53 : i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
14843 : :
14844 [ + + ]: 258 : for (i = 0; i < ntups; i++)
14845 : : {
14846 : 205 : amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
14847 : 205 : amproc = PQgetvalue(res_procs, i, i_amproc);
14848 : 205 : amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
14849 : 205 : amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
14850 : :
14851 [ + + ]: 205 : if (needComma)
4310 heikki.linnakangas@i 14852 : 190 : appendPQExpBufferStr(q, " ,\n ");
14853 : :
6801 tgl@sss.pgh.pa.us 14854 : 205 : appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
14855 : : amprocnum, amproclefttype, amprocrighttype,
14856 : : amproc);
14857 : :
14858 : 205 : needComma = true;
14859 : : }
14860 : :
4310 heikki.linnakangas@i 14861 : 53 : appendPQExpBufferStr(q, ";\n");
14862 : : }
14863 : :
2749 tgl@sss.pgh.pa.us 14864 : 549 : appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
14865 : 549 : appendPQExpBuffer(nameusing, " USING %s",
14866 : : fmtId(amname));
14867 : :
3980 alvherre@alvh.no-ip. 14868 [ + + ]: 549 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 14869 : 9 : binary_upgrade_extension_member(q, &opfinfo->dobj,
14870 : 9 : "OPERATOR FAMILY", nameusing->data,
14871 : 9 : opfinfo->dobj.namespace->dobj.name);
14872 : :
3440 sfrost@snowman.net 14873 [ + - ]: 549 : if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14874 : 549 : ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 14875 : 549 : ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
14876 : : .namespace = opfinfo->dobj.namespace->dobj.name,
14877 : : .owner = opfinfo->rolname,
14878 : : .description = "OPERATOR FAMILY",
14879 : : .section = SECTION_PRE_DATA,
14880 : : .createStmt = q->data,
14881 : : .dropStmt = delq->data));
14882 : :
14883 : : /* Dump Operator Family Comments */
3440 sfrost@snowman.net 14884 [ - + ]: 549 : if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 14885 :UBC 0 : dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
3106 14886 : 0 : opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
3440 sfrost@snowman.net 14887 : 0 : opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
14888 : :
6801 tgl@sss.pgh.pa.us 14889 :CBC 549 : free(amname);
14890 : 549 : PQclear(res_ops);
14891 : 549 : PQclear(res_procs);
14892 : 549 : destroyPQExpBuffer(query);
14893 : 549 : destroyPQExpBuffer(q);
14894 : 549 : destroyPQExpBuffer(delq);
2749 14895 : 549 : destroyPQExpBuffer(nameusing);
14896 : : }
14897 : :
14898 : : /*
14899 : : * dumpCollation
14900 : : * write out a single collation definition
14901 : : */
14902 : : static void
1669 peter@eisentraut.org 14903 : 4655 : dumpCollation(Archive *fout, const CollInfo *collinfo)
14904 : : {
3524 tgl@sss.pgh.pa.us 14905 : 4655 : DumpOptions *dopt = fout->dopt;
14906 : : PQExpBuffer query;
14907 : : PQExpBuffer q;
14908 : : PQExpBuffer delq;
14909 : : char *qcollname;
14910 : : PGresult *res;
14911 : : int i_collprovider;
14912 : : int i_collisdeterministic;
14913 : : int i_collcollate;
14914 : : int i_collctype;
14915 : : int i_colllocale;
14916 : : int i_collicurules;
14917 : : const char *collprovider;
14918 : : const char *collcollate;
14919 : : const char *collctype;
14920 : : const char *colllocale;
14921 : : const char *collicurules;
14922 : :
14923 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 14924 [ + + ]: 4655 : if (!dopt->dumpSchema)
5320 peter_e@gmx.net 14925 : 12 : return;
14926 : :
14927 : 4643 : query = createPQExpBuffer();
14928 : 4643 : q = createPQExpBuffer();
14929 : 4643 : delq = createPQExpBuffer();
14930 : :
2749 tgl@sss.pgh.pa.us 14931 : 4643 : qcollname = pg_strdup(fmtId(collinfo->dobj.name));
14932 : :
14933 : : /* Get collation-specific details */
2256 drowley@postgresql.o 14934 : 4643 : appendPQExpBufferStr(query, "SELECT ");
14935 : :
3089 peter_e@gmx.net 14936 [ + - ]: 4643 : if (fout->remoteVersion >= 100000)
2256 drowley@postgresql.o 14937 : 4643 : appendPQExpBufferStr(query,
14938 : : "collprovider, "
14939 : : "collversion, ");
14940 : : else
2256 drowley@postgresql.o 14941 :UBC 0 : appendPQExpBufferStr(query,
14942 : : "'c' AS collprovider, "
14943 : : "NULL AS collversion, ");
14944 : :
2360 peter@eisentraut.org 14945 [ + - ]:CBC 4643 : if (fout->remoteVersion >= 120000)
2256 drowley@postgresql.o 14946 : 4643 : appendPQExpBufferStr(query,
14947 : : "collisdeterministic, ");
14948 : : else
2256 drowley@postgresql.o 14949 :UBC 0 : appendPQExpBufferStr(query,
14950 : : "true AS collisdeterministic, ");
14951 : :
546 jdavis@postgresql.or 14952 [ + - ]:CBC 4643 : if (fout->remoteVersion >= 170000)
14953 : 4643 : appendPQExpBufferStr(query,
14954 : : "colllocale, ");
546 jdavis@postgresql.or 14955 [ # # ]:UBC 0 : else if (fout->remoteVersion >= 150000)
1109 peter@eisentraut.org 14956 : 0 : appendPQExpBufferStr(query,
14957 : : "colliculocale AS colllocale, ");
14958 : : else
14959 : 0 : appendPQExpBufferStr(query,
14960 : : "NULL AS colllocale, ");
14961 : :
913 peter@eisentraut.org 14962 [ + - ]:CBC 4643 : if (fout->remoteVersion >= 160000)
14963 : 4643 : appendPQExpBufferStr(query,
14964 : : "collicurules, ");
14965 : : else
913 peter@eisentraut.org 14966 :UBC 0 : appendPQExpBufferStr(query,
14967 : : "NULL AS collicurules, ");
14968 : :
2360 peter@eisentraut.org 14969 :CBC 4643 : appendPQExpBuffer(query,
14970 : : "collcollate, "
14971 : : "collctype "
14972 : : "FROM pg_catalog.pg_collation c "
14973 : : "WHERE c.oid = '%u'::pg_catalog.oid",
14974 : 4643 : collinfo->dobj.catId.oid);
14975 : :
4951 rhaas@postgresql.org 14976 : 4643 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
14977 : :
3089 peter_e@gmx.net 14978 : 4643 : i_collprovider = PQfnumber(res, "collprovider");
2360 peter@eisentraut.org 14979 : 4643 : i_collisdeterministic = PQfnumber(res, "collisdeterministic");
5320 peter_e@gmx.net 14980 : 4643 : i_collcollate = PQfnumber(res, "collcollate");
14981 : 4643 : i_collctype = PQfnumber(res, "collctype");
546 jdavis@postgresql.or 14982 : 4643 : i_colllocale = PQfnumber(res, "colllocale");
913 peter@eisentraut.org 14983 : 4643 : i_collicurules = PQfnumber(res, "collicurules");
14984 : :
3089 peter_e@gmx.net 14985 : 4643 : collprovider = PQgetvalue(res, 0, i_collprovider);
14986 : :
1109 peter@eisentraut.org 14987 [ + + ]: 4643 : if (!PQgetisnull(res, 0, i_collcollate))
14988 : 2020 : collcollate = PQgetvalue(res, 0, i_collcollate);
14989 : : else
14990 : 2623 : collcollate = NULL;
14991 : :
14992 [ + + ]: 4643 : if (!PQgetisnull(res, 0, i_collctype))
14993 : 2020 : collctype = PQgetvalue(res, 0, i_collctype);
14994 : : else
14995 : 2623 : collctype = NULL;
14996 : :
14997 : : /*
14998 : : * Before version 15, collcollate and collctype were of type NAME and
14999 : : * non-nullable. Treat empty strings as NULL for consistency.
15000 : : */
746 jdavis@postgresql.or 15001 [ - + ]: 4643 : if (fout->remoteVersion < 150000)
15002 : : {
746 jdavis@postgresql.or 15003 [ # # ]:UBC 0 : if (collcollate[0] == '\0')
15004 : 0 : collcollate = NULL;
15005 [ # # ]: 0 : if (collctype[0] == '\0')
15006 : 0 : collctype = NULL;
15007 : : }
15008 : :
546 jdavis@postgresql.or 15009 [ + + ]:CBC 4643 : if (!PQgetisnull(res, 0, i_colllocale))
15010 : 2620 : colllocale = PQgetvalue(res, 0, i_colllocale);
15011 : : else
15012 : 2023 : colllocale = NULL;
15013 : :
913 peter@eisentraut.org 15014 [ - + ]: 4643 : if (!PQgetisnull(res, 0, i_collicurules))
913 peter@eisentraut.org 15015 :UBC 0 : collicurules = PQgetvalue(res, 0, i_collicurules);
15016 : : else
913 peter@eisentraut.org 15017 :CBC 4643 : collicurules = NULL;
15018 : :
2749 tgl@sss.pgh.pa.us 15019 : 4643 : appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
15020 : 4643 : fmtQualifiedDumpable(collinfo));
15021 : :
3089 peter_e@gmx.net 15022 : 4643 : appendPQExpBuffer(q, "CREATE COLLATION %s (",
2749 tgl@sss.pgh.pa.us 15023 : 4643 : fmtQualifiedDumpable(collinfo));
15024 : :
3089 peter_e@gmx.net 15025 : 4643 : appendPQExpBufferStr(q, "provider = ");
542 jdavis@postgresql.or 15026 [ + + ]: 4643 : if (collprovider[0] == 'b')
15027 : 19 : appendPQExpBufferStr(q, "builtin");
15028 [ + + ]: 4624 : else if (collprovider[0] == 'c')
3089 peter_e@gmx.net 15029 : 2020 : appendPQExpBufferStr(q, "libc");
15030 [ + + ]: 2604 : else if (collprovider[0] == 'i')
15031 : 2601 : appendPQExpBufferStr(q, "icu");
3007 15032 [ + - ]: 3 : else if (collprovider[0] == 'd')
15033 : : /* to allow dumping pg_catalog; not accepted on input */
15034 : 3 : appendPQExpBufferStr(q, "default");
15035 : : else
1247 tgl@sss.pgh.pa.us 15036 :UBC 0 : pg_fatal("unrecognized collation provider: %s",
15037 : : collprovider);
15038 : :
2360 peter@eisentraut.org 15039 [ - + ]:CBC 4643 : if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
2360 peter@eisentraut.org 15040 :UBC 0 : appendPQExpBufferStr(q, ", deterministic = false");
15041 : :
746 jdavis@postgresql.or 15042 [ + + ]:CBC 4643 : if (collprovider[0] == 'd')
15043 : : {
546 15044 [ + - + - : 3 : if (collcollate || collctype || colllocale || collicurules)
+ - - + ]
746 jdavis@postgresql.or 15045 :UBC 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
15046 : :
15047 : : /* no locale -- the default collation cannot be reloaded anyway */
15048 : : }
542 jdavis@postgresql.or 15049 [ + + ]:CBC 4640 : else if (collprovider[0] == 'b')
15050 : : {
15051 [ + - + - : 19 : if (collcollate || collctype || !colllocale || collicurules)
+ - - + ]
542 jdavis@postgresql.or 15052 :UBC 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
15053 : :
542 jdavis@postgresql.or 15054 :CBC 19 : appendPQExpBufferStr(q, ", locale = ");
15055 [ + - ]: 19 : appendStringLiteralAH(q, colllocale ? colllocale : "",
15056 : : fout);
15057 : : }
746 15058 [ + + ]: 4621 : else if (collprovider[0] == 'i')
15059 : : {
15060 [ + - ]: 2601 : if (fout->remoteVersion >= 150000)
15061 : : {
546 15062 [ + - + - : 2601 : if (collcollate || collctype || !colllocale)
- + ]
746 jdavis@postgresql.or 15063 :UBC 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
15064 : :
746 jdavis@postgresql.or 15065 :CBC 2601 : appendPQExpBufferStr(q, ", locale = ");
546 15066 [ + - ]: 2601 : appendStringLiteralAH(q, colllocale ? colllocale : "",
15067 : : fout);
15068 : : }
15069 : : else
15070 : : {
546 jdavis@postgresql.or 15071 [ # # # # :UBC 0 : if (!collcollate || !collctype || colllocale ||
# # ]
746 15072 [ # # ]: 0 : strcmp(collcollate, collctype) != 0)
15073 : 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
15074 : :
1109 peter@eisentraut.org 15075 : 0 : appendPQExpBufferStr(q, ", locale = ");
746 jdavis@postgresql.or 15076 [ # # ]: 0 : appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
15077 : : }
15078 : :
746 jdavis@postgresql.or 15079 [ - + ]:CBC 2601 : if (collicurules)
15080 : : {
746 jdavis@postgresql.or 15081 :UBC 0 : appendPQExpBufferStr(q, ", rules = ");
15082 [ # # ]: 0 : appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
15083 : : }
15084 : : }
746 jdavis@postgresql.or 15085 [ + - ]:CBC 2020 : else if (collprovider[0] == 'c')
15086 : : {
546 15087 [ + - + - : 2020 : if (colllocale || collicurules || !collcollate || !collctype)
+ - - + ]
746 jdavis@postgresql.or 15088 :UBC 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
15089 : :
746 jdavis@postgresql.or 15090 [ + - + - :CBC 2020 : if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
+ - ]
15091 : : {
15092 : 2020 : appendPQExpBufferStr(q, ", locale = ");
15093 [ + - ]: 2020 : appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
15094 : : }
15095 : : else
15096 : : {
1109 peter@eisentraut.org 15097 :UBC 0 : appendPQExpBufferStr(q, ", lc_collate = ");
746 jdavis@postgresql.or 15098 [ # # ]: 0 : appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
1109 peter@eisentraut.org 15099 : 0 : appendPQExpBufferStr(q, ", lc_ctype = ");
746 jdavis@postgresql.or 15100 [ # # ]: 0 : appendStringLiteralAH(q, collctype ? collctype : "", fout);
15101 : : }
15102 : : }
15103 : : else
732 peter@eisentraut.org 15104 : 0 : pg_fatal("unrecognized collation provider: %s", collprovider);
15105 : :
15106 : : /*
15107 : : * For binary upgrade, carry over the collation version. For normal
15108 : : * dump/restore, omit the version, so that it is computed upon restore.
15109 : : */
1583 tmunro@postgresql.or 15110 [ + + ]:CBC 4643 : if (dopt->binary_upgrade)
15111 : : {
15112 : : int i_collversion;
15113 : :
15114 : 5 : i_collversion = PQfnumber(res, "collversion");
15115 [ + + ]: 5 : if (!PQgetisnull(res, 0, i_collversion))
15116 : : {
15117 : 4 : appendPQExpBufferStr(q, ", version = ");
15118 : 4 : appendStringLiteralAH(q,
15119 : : PQgetvalue(res, 0, i_collversion),
15120 : : fout);
15121 : : }
15122 : : }
15123 : :
4310 heikki.linnakangas@i 15124 : 4643 : appendPQExpBufferStr(q, ");\n");
15125 : :
3980 alvherre@alvh.no-ip. 15126 [ + + ]: 4643 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 15127 : 5 : binary_upgrade_extension_member(q, &collinfo->dobj,
15128 : : "COLLATION", qcollname,
15129 : 5 : collinfo->dobj.namespace->dobj.name);
15130 : :
3440 sfrost@snowman.net 15131 [ + - ]: 4643 : if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15132 : 4643 : ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 15133 : 4643 : ARCHIVE_OPTS(.tag = collinfo->dobj.name,
15134 : : .namespace = collinfo->dobj.namespace->dobj.name,
15135 : : .owner = collinfo->rolname,
15136 : : .description = "COLLATION",
15137 : : .section = SECTION_PRE_DATA,
15138 : : .createStmt = q->data,
15139 : : .dropStmt = delq->data));
15140 : :
15141 : : /* Dump Collation Comments */
3440 sfrost@snowman.net 15142 [ + + ]: 4643 : if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 15143 : 2563 : dumpComment(fout, "COLLATION", qcollname,
3440 sfrost@snowman.net 15144 : 2563 : collinfo->dobj.namespace->dobj.name, collinfo->rolname,
15145 : 2563 : collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
15146 : :
5320 peter_e@gmx.net 15147 : 4643 : PQclear(res);
15148 : :
15149 : 4643 : destroyPQExpBuffer(query);
15150 : 4643 : destroyPQExpBuffer(q);
15151 : 4643 : destroyPQExpBuffer(delq);
2749 tgl@sss.pgh.pa.us 15152 : 4643 : free(qcollname);
15153 : : }
15154 : :
15155 : : /*
15156 : : * dumpConversion
15157 : : * write out a single conversion definition
15158 : : */
15159 : : static void
1669 peter@eisentraut.org 15160 : 428 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
15161 : : {
3524 tgl@sss.pgh.pa.us 15162 : 428 : DumpOptions *dopt = fout->dopt;
15163 : : PQExpBuffer query;
15164 : : PQExpBuffer q;
15165 : : PQExpBuffer delq;
15166 : : char *qconvname;
15167 : : PGresult *res;
15168 : : int i_conforencoding;
15169 : : int i_contoencoding;
15170 : : int i_conproc;
15171 : : int i_condefault;
15172 : : const char *conforencoding;
15173 : : const char *contoencoding;
15174 : : const char *conproc;
15175 : : bool condefault;
15176 : :
15177 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 15178 [ + + ]: 428 : if (!dopt->dumpSchema)
7945 tgl@sss.pgh.pa.us 15179 : 6 : return;
15180 : :
15181 : 422 : query = createPQExpBuffer();
15182 : 422 : q = createPQExpBuffer();
15183 : 422 : delq = createPQExpBuffer();
15184 : :
2749 15185 : 422 : qconvname = pg_strdup(fmtId(convinfo->dobj.name));
15186 : :
15187 : : /* Get conversion-specific details */
5262 peter_e@gmx.net 15188 : 422 : appendPQExpBuffer(query, "SELECT "
15189 : : "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
15190 : : "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
15191 : : "conproc, condefault "
15192 : : "FROM pg_catalog.pg_conversion c "
15193 : : "WHERE c.oid = '%u'::pg_catalog.oid",
7945 tgl@sss.pgh.pa.us 15194 : 422 : convinfo->dobj.catId.oid);
15195 : :
4951 rhaas@postgresql.org 15196 : 422 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
15197 : :
7960 tgl@sss.pgh.pa.us 15198 : 422 : i_conforencoding = PQfnumber(res, "conforencoding");
15199 : 422 : i_contoencoding = PQfnumber(res, "contoencoding");
15200 : 422 : i_conproc = PQfnumber(res, "conproc");
15201 : 422 : i_condefault = PQfnumber(res, "condefault");
15202 : :
15203 : 422 : conforencoding = PQgetvalue(res, 0, i_conforencoding);
15204 : 422 : contoencoding = PQgetvalue(res, 0, i_contoencoding);
15205 : 422 : conproc = PQgetvalue(res, 0, i_conproc);
15206 : 422 : condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
15207 : :
2749 15208 : 422 : appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
15209 : 422 : fmtQualifiedDumpable(convinfo));
15210 : :
7960 15211 [ + - ]: 422 : appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
15212 : : (condefault) ? "DEFAULT " : "",
2749 15213 : 422 : fmtQualifiedDumpable(convinfo));
7041 15214 : 422 : appendStringLiteralAH(q, conforencoding, fout);
4310 heikki.linnakangas@i 15215 : 422 : appendPQExpBufferStr(q, " TO ");
7041 tgl@sss.pgh.pa.us 15216 : 422 : appendStringLiteralAH(q, contoencoding, fout);
15217 : : /* regproc output is already sufficiently quoted */
7960 15218 : 422 : appendPQExpBuffer(q, " FROM %s;\n", conproc);
15219 : :
3980 alvherre@alvh.no-ip. 15220 [ + + ]: 422 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 15221 : 1 : binary_upgrade_extension_member(q, &convinfo->dobj,
15222 : : "CONVERSION", qconvname,
15223 : 1 : convinfo->dobj.namespace->dobj.name);
15224 : :
3440 sfrost@snowman.net 15225 [ + - ]: 422 : if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15226 : 422 : ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 15227 : 422 : ARCHIVE_OPTS(.tag = convinfo->dobj.name,
15228 : : .namespace = convinfo->dobj.namespace->dobj.name,
15229 : : .owner = convinfo->rolname,
15230 : : .description = "CONVERSION",
15231 : : .section = SECTION_PRE_DATA,
15232 : : .createStmt = q->data,
15233 : : .dropStmt = delq->data));
15234 : :
15235 : : /* Dump Conversion Comments */
3440 sfrost@snowman.net 15236 [ + - ]: 422 : if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 15237 : 422 : dumpComment(fout, "CONVERSION", qconvname,
3440 sfrost@snowman.net 15238 : 422 : convinfo->dobj.namespace->dobj.name, convinfo->rolname,
15239 : 422 : convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
15240 : :
7945 tgl@sss.pgh.pa.us 15241 : 422 : PQclear(res);
15242 : :
15243 : 422 : destroyPQExpBuffer(query);
15244 : 422 : destroyPQExpBuffer(q);
15245 : 422 : destroyPQExpBuffer(delq);
2749 15246 : 422 : free(qconvname);
15247 : : }
15248 : :
15249 : : /*
15250 : : * format_aggregate_signature: generate aggregate name and argument list
15251 : : *
15252 : : * The argument type names are qualified if needed. The aggregate name
15253 : : * is never qualified.
15254 : : */
15255 : : static char *
1669 peter@eisentraut.org 15256 : 291 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
15257 : : {
15258 : : PQExpBufferData buf;
15259 : : int j;
15260 : :
8511 peter_e@gmx.net 15261 : 291 : initPQExpBuffer(&buf);
8465 bruce@momjian.us 15262 [ - + ]: 291 : if (honor_quotes)
4310 heikki.linnakangas@i 15263 :UBC 0 : appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
15264 : : else
4310 heikki.linnakangas@i 15265 :CBC 291 : appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
15266 : :
6981 tgl@sss.pgh.pa.us 15267 [ + + ]: 291 : if (agginfo->aggfn.nargs == 0)
2256 drowley@postgresql.o 15268 : 40 : appendPQExpBufferStr(&buf, "(*)");
15269 : : else
15270 : : {
4310 heikki.linnakangas@i 15271 : 251 : appendPQExpBufferChar(&buf, '(');
6981 tgl@sss.pgh.pa.us 15272 [ + + ]: 547 : for (j = 0; j < agginfo->aggfn.nargs; j++)
15273 [ + + ]: 296 : appendPQExpBuffer(&buf, "%s%s",
15274 : : (j > 0) ? ", " : "",
15275 : : getFormattedTypeName(fout,
1459 15276 : 296 : agginfo->aggfn.argtypes[j],
15277 : : zeroIsError));
4310 heikki.linnakangas@i 15278 : 251 : appendPQExpBufferChar(&buf, ')');
15279 : : }
8511 peter_e@gmx.net 15280 : 291 : return buf.data;
15281 : : }
15282 : :
15283 : : /*
15284 : : * dumpAgg
15285 : : * write out a single aggregate definition
15286 : : */
15287 : : static void
1669 peter@eisentraut.org 15288 : 298 : dumpAgg(Archive *fout, const AggInfo *agginfo)
15289 : : {
3524 tgl@sss.pgh.pa.us 15290 : 298 : DumpOptions *dopt = fout->dopt;
15291 : : PQExpBuffer query;
15292 : : PQExpBuffer q;
15293 : : PQExpBuffer delq;
15294 : : PQExpBuffer details;
15295 : : char *aggsig; /* identity signature */
2999 15296 : 298 : char *aggfullsig = NULL; /* full signature */
15297 : : char *aggsig_tag;
15298 : : PGresult *res;
15299 : : int i_agginitval;
15300 : : int i_aggminitval;
15301 : : const char *aggtransfn;
15302 : : const char *aggfinalfn;
15303 : : const char *aggcombinefn;
15304 : : const char *aggserialfn;
15305 : : const char *aggdeserialfn;
15306 : : const char *aggmtransfn;
15307 : : const char *aggminvtransfn;
15308 : : const char *aggmfinalfn;
15309 : : bool aggfinalextra;
15310 : : bool aggmfinalextra;
15311 : : char aggfinalmodify;
15312 : : char aggmfinalmodify;
15313 : : const char *aggsortop;
15314 : : char *aggsortconvop;
15315 : : char aggkind;
15316 : : const char *aggtranstype;
15317 : : const char *aggtransspace;
15318 : : const char *aggmtranstype;
15319 : : const char *aggmtransspace;
15320 : : const char *agginitval;
15321 : : const char *aggminitval;
15322 : : const char *proparallel;
15323 : : char defaultfinalmodify;
15324 : :
15325 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 15326 [ + + ]: 298 : if (!dopt->dumpSchema)
7945 tgl@sss.pgh.pa.us 15327 : 7 : return;
15328 : :
15329 : 291 : query = createPQExpBuffer();
15330 : 291 : q = createPQExpBuffer();
15331 : 291 : delq = createPQExpBuffer();
15332 : 291 : details = createPQExpBuffer();
15333 : :
1370 15334 [ + + ]: 291 : if (!fout->is_prepared[PREPQUERY_DUMPAGG])
15335 : : {
15336 : : /* Set up query for aggregate-specific details */
1787 drowley@postgresql.o 15337 : 61 : appendPQExpBufferStr(query,
15338 : : "PREPARE dumpAgg(pg_catalog.oid) AS\n");
15339 : :
15340 : 61 : appendPQExpBufferStr(query,
15341 : : "SELECT "
15342 : : "aggtransfn,\n"
15343 : : "aggfinalfn,\n"
15344 : : "aggtranstype::pg_catalog.regtype,\n"
15345 : : "agginitval,\n"
15346 : : "aggsortop,\n"
15347 : : "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
15348 : : "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
15349 : :
1370 tgl@sss.pgh.pa.us 15350 [ + - ]: 61 : if (fout->remoteVersion >= 90400)
15351 : 61 : appendPQExpBufferStr(query,
15352 : : "aggkind,\n"
15353 : : "aggmtransfn,\n"
15354 : : "aggminvtransfn,\n"
15355 : : "aggmfinalfn,\n"
15356 : : "aggmtranstype::pg_catalog.regtype,\n"
15357 : : "aggfinalextra,\n"
15358 : : "aggmfinalextra,\n"
15359 : : "aggtransspace,\n"
15360 : : "aggmtransspace,\n"
15361 : : "aggminitval,\n");
15362 : : else
1370 tgl@sss.pgh.pa.us 15363 :UBC 0 : appendPQExpBufferStr(query,
15364 : : "'n' AS aggkind,\n"
15365 : : "'-' AS aggmtransfn,\n"
15366 : : "'-' AS aggminvtransfn,\n"
15367 : : "'-' AS aggmfinalfn,\n"
15368 : : "0 AS aggmtranstype,\n"
15369 : : "false AS aggfinalextra,\n"
15370 : : "false AS aggmfinalextra,\n"
15371 : : "0 AS aggtransspace,\n"
15372 : : "0 AS aggmtransspace,\n"
15373 : : "NULL AS aggminitval,\n");
15374 : :
1370 tgl@sss.pgh.pa.us 15375 [ + - ]:CBC 61 : if (fout->remoteVersion >= 90600)
15376 : 61 : appendPQExpBufferStr(query,
15377 : : "aggcombinefn,\n"
15378 : : "aggserialfn,\n"
15379 : : "aggdeserialfn,\n"
15380 : : "proparallel,\n");
15381 : : else
1370 tgl@sss.pgh.pa.us 15382 :UBC 0 : appendPQExpBufferStr(query,
15383 : : "'-' AS aggcombinefn,\n"
15384 : : "'-' AS aggserialfn,\n"
15385 : : "'-' AS aggdeserialfn,\n"
15386 : : "'u' AS proparallel,\n");
15387 : :
1370 tgl@sss.pgh.pa.us 15388 [ + - ]:CBC 61 : if (fout->remoteVersion >= 110000)
15389 : 61 : appendPQExpBufferStr(query,
15390 : : "aggfinalmodify,\n"
15391 : : "aggmfinalmodify\n");
15392 : : else
1370 tgl@sss.pgh.pa.us 15393 :UBC 0 : appendPQExpBufferStr(query,
15394 : : "'0' AS aggfinalmodify,\n"
15395 : : "'0' AS aggmfinalmodify\n");
15396 : :
1787 drowley@postgresql.o 15397 :CBC 61 : appendPQExpBufferStr(query,
15398 : : "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
15399 : : "WHERE a.aggfnoid = p.oid "
15400 : : "AND p.oid = $1");
15401 : :
1370 tgl@sss.pgh.pa.us 15402 : 61 : ExecuteSqlStatement(fout, query->data);
15403 : :
15404 : 61 : fout->is_prepared[PREPQUERY_DUMPAGG] = true;
15405 : : }
15406 : :
15407 : 291 : printfPQExpBuffer(query,
15408 : : "EXECUTE dumpAgg('%u')",
1879 peter@eisentraut.org 15409 : 291 : agginfo->aggfn.dobj.catId.oid);
15410 : :
4951 rhaas@postgresql.org 15411 : 291 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
15412 : :
8520 tgl@sss.pgh.pa.us 15413 : 291 : i_agginitval = PQfnumber(res, "agginitval");
4165 15414 : 291 : i_aggminitval = PQfnumber(res, "aggminitval");
15415 : :
1879 peter@eisentraut.org 15416 : 291 : aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
15417 : 291 : aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
15418 : 291 : aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
15419 : 291 : aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
15420 : 291 : aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
15421 : 291 : aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
15422 : 291 : aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
15423 : 291 : aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
15424 : 291 : aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
15425 : 291 : aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
15426 : 291 : aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
15427 : 291 : aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
15428 : 291 : aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
15429 : 291 : aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
15430 : 291 : aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
15431 : 291 : aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
15432 : 291 : aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
15433 : 291 : aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
8520 tgl@sss.pgh.pa.us 15434 : 291 : agginitval = PQgetvalue(res, 0, i_agginitval);
4165 15435 : 291 : aggminitval = PQgetvalue(res, 0, i_aggminitval);
1879 peter@eisentraut.org 15436 : 291 : proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
15437 : :
15438 : : {
15439 : : char *funcargs;
15440 : : char *funciargs;
15441 : :
4386 tgl@sss.pgh.pa.us 15442 : 291 : funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
15443 : 291 : funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
15444 : 291 : aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
15445 : 291 : aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
15446 : : }
15447 : :
7945 15448 : 291 : aggsig_tag = format_aggregate_signature(agginfo, fout, false);
15449 : :
15450 : : /* identify default modify flag for aggkind (must match DefineAggregate) */
2884 15451 [ + + ]: 291 : defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
15452 : : /* replace omitted flags for old versions */
15453 [ - + ]: 291 : if (aggfinalmodify == '0')
2884 tgl@sss.pgh.pa.us 15454 :UBC 0 : aggfinalmodify = defaultfinalmodify;
2884 tgl@sss.pgh.pa.us 15455 [ - + ]:CBC 291 : if (aggmfinalmodify == '0')
2884 tgl@sss.pgh.pa.us 15456 :UBC 0 : aggmfinalmodify = defaultfinalmodify;
15457 : :
15458 : : /* regproc and regtype output is already sufficiently quoted */
3251 tgl@sss.pgh.pa.us 15459 :CBC 291 : appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
15460 : : aggtransfn, aggtranstype);
15461 : :
4312 15462 [ + + ]: 291 : if (strcmp(aggtransspace, "0") != 0)
15463 : : {
15464 : 5 : appendPQExpBuffer(details, ",\n SSPACE = %s",
15465 : : aggtransspace);
15466 : : }
15467 : :
8520 15468 [ + + ]: 291 : if (!PQgetisnull(res, 0, i_agginitval))
15469 : : {
4310 heikki.linnakangas@i 15470 : 213 : appendPQExpBufferStr(details, ",\n INITCOND = ");
7041 tgl@sss.pgh.pa.us 15471 : 213 : appendStringLiteralAH(details, agginitval, fout);
15472 : : }
15473 : :
8520 15474 [ + + ]: 291 : if (strcmp(aggfinalfn, "-") != 0)
15475 : : {
8420 peter_e@gmx.net 15476 : 138 : appendPQExpBuffer(details, ",\n FINALFUNC = %s",
15477 : : aggfinalfn);
4154 tgl@sss.pgh.pa.us 15478 [ + + ]: 138 : if (aggfinalextra)
15479 : 10 : appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
2884 15480 [ + + ]: 138 : if (aggfinalmodify != defaultfinalmodify)
15481 : : {
15482 [ - + - - ]: 38 : switch (aggfinalmodify)
15483 : : {
2884 tgl@sss.pgh.pa.us 15484 :UBC 0 : case AGGMODIFY_READ_ONLY:
15485 : 0 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_ONLY");
15486 : 0 : break;
2665 tgl@sss.pgh.pa.us 15487 :CBC 38 : case AGGMODIFY_SHAREABLE:
15488 : 38 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = SHAREABLE");
2884 15489 : 38 : break;
2884 tgl@sss.pgh.pa.us 15490 :UBC 0 : case AGGMODIFY_READ_WRITE:
15491 : 0 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_WRITE");
15492 : 0 : break;
15493 : 0 : default:
1247 15494 : 0 : pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
15495 : : agginfo->aggfn.dobj.name);
15496 : : break;
15497 : : }
15498 : : }
15499 : : }
15500 : :
3517 rhaas@postgresql.org 15501 [ - + ]:CBC 291 : if (strcmp(aggcombinefn, "-") != 0)
3376 rhaas@postgresql.org 15502 :UBC 0 : appendPQExpBuffer(details, ",\n COMBINEFUNC = %s", aggcombinefn);
15503 : :
3448 rhaas@postgresql.org 15504 [ - + ]:CBC 291 : if (strcmp(aggserialfn, "-") != 0)
3376 rhaas@postgresql.org 15505 :UBC 0 : appendPQExpBuffer(details, ",\n SERIALFUNC = %s", aggserialfn);
15506 : :
3363 tgl@sss.pgh.pa.us 15507 [ - + ]:CBC 291 : if (strcmp(aggdeserialfn, "-") != 0)
3376 rhaas@postgresql.org 15508 :UBC 0 : appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
15509 : :
4165 tgl@sss.pgh.pa.us 15510 [ + + ]:CBC 291 : if (strcmp(aggmtransfn, "-") != 0)
15511 : : {
15512 : 30 : appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
15513 : : aggmtransfn,
15514 : : aggminvtransfn,
15515 : : aggmtranstype);
15516 : : }
15517 : :
15518 [ - + ]: 291 : if (strcmp(aggmtransspace, "0") != 0)
15519 : : {
4165 tgl@sss.pgh.pa.us 15520 :UBC 0 : appendPQExpBuffer(details, ",\n MSSPACE = %s",
15521 : : aggmtransspace);
15522 : : }
15523 : :
4165 tgl@sss.pgh.pa.us 15524 [ + + ]:CBC 291 : if (!PQgetisnull(res, 0, i_aggminitval))
15525 : : {
15526 : 10 : appendPQExpBufferStr(details, ",\n MINITCOND = ");
15527 : 10 : appendStringLiteralAH(details, aggminitval, fout);
15528 : : }
15529 : :
15530 [ - + ]: 291 : if (strcmp(aggmfinalfn, "-") != 0)
15531 : : {
4165 tgl@sss.pgh.pa.us 15532 :UBC 0 : appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
15533 : : aggmfinalfn);
4154 15534 [ # # ]: 0 : if (aggmfinalextra)
15535 : 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
2884 15536 [ # # ]: 0 : if (aggmfinalmodify != defaultfinalmodify)
15537 : : {
15538 [ # # # # ]: 0 : switch (aggmfinalmodify)
15539 : : {
15540 : 0 : case AGGMODIFY_READ_ONLY:
15541 : 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_ONLY");
15542 : 0 : break;
2665 15543 : 0 : case AGGMODIFY_SHAREABLE:
15544 : 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = SHAREABLE");
2884 15545 : 0 : break;
15546 : 0 : case AGGMODIFY_READ_WRITE:
15547 : 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_WRITE");
15548 : 0 : break;
15549 : 0 : default:
1247 15550 : 0 : pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
15551 : : agginfo->aggfn.dobj.name);
15552 : : break;
15553 : : }
15554 : : }
15555 : : }
15556 : :
1838 peter@eisentraut.org 15557 :CBC 291 : aggsortconvop = getFormattedOperatorName(aggsortop);
4207 sfrost@snowman.net 15558 [ - + ]: 291 : if (aggsortconvop)
15559 : : {
7452 tgl@sss.pgh.pa.us 15560 :UBC 0 : appendPQExpBuffer(details, ",\n SORTOP = %s",
15561 : : aggsortconvop);
4207 sfrost@snowman.net 15562 : 0 : free(aggsortconvop);
15563 : : }
15564 : :
2884 tgl@sss.pgh.pa.us 15565 [ + + ]:CBC 291 : if (aggkind == AGGKIND_HYPOTHETICAL)
4275 15566 : 5 : appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
15567 : :
1879 peter@eisentraut.org 15568 [ + + ]: 291 : if (proparallel[0] != PROPARALLEL_UNSAFE)
15569 : : {
3426 rhaas@postgresql.org 15570 [ + - ]: 5 : if (proparallel[0] == PROPARALLEL_SAFE)
15571 : 5 : appendPQExpBufferStr(details, ",\n PARALLEL = safe");
3426 rhaas@postgresql.org 15572 [ # # ]:UBC 0 : else if (proparallel[0] == PROPARALLEL_RESTRICTED)
15573 : 0 : appendPQExpBufferStr(details, ",\n PARALLEL = restricted");
15574 [ # # ]: 0 : else if (proparallel[0] != PROPARALLEL_UNSAFE)
1247 tgl@sss.pgh.pa.us 15575 : 0 : pg_fatal("unrecognized proparallel value for function \"%s\"",
15576 : : agginfo->aggfn.dobj.name);
15577 : : }
15578 : :
8502 tgl@sss.pgh.pa.us 15579 :CBC 291 : appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
7857 15580 : 291 : fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
15581 : : aggsig);
15582 : :
2749 15583 [ + - ]: 582 : appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
15584 : 291 : fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
15585 : : aggfullsig ? aggfullsig : aggsig, details->data);
15586 : :
3980 alvherre@alvh.no-ip. 15587 [ + + ]: 291 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 15588 : 49 : binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
15589 : : "AGGREGATE", aggsig,
15590 : 49 : agginfo->aggfn.dobj.namespace->dobj.name);
15591 : :
3440 sfrost@snowman.net 15592 [ + + ]: 291 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
15593 : 274 : ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
15594 : 274 : agginfo->aggfn.dobj.dumpId,
2409 alvherre@alvh.no-ip. 15595 : 274 : ARCHIVE_OPTS(.tag = aggsig_tag,
15596 : : .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
15597 : : .owner = agginfo->aggfn.rolname,
15598 : : .description = "AGGREGATE",
15599 : : .section = SECTION_PRE_DATA,
15600 : : .createStmt = q->data,
15601 : : .dropStmt = delq->data));
15602 : :
15603 : : /* Dump Aggregate Comments */
3440 sfrost@snowman.net 15604 [ + + ]: 291 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 15605 : 10 : dumpComment(fout, "AGGREGATE", aggsig,
3440 sfrost@snowman.net 15606 : 10 : agginfo->aggfn.dobj.namespace->dobj.name,
15607 : 10 : agginfo->aggfn.rolname,
15608 : 10 : agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
15609 : :
15610 [ - + ]: 291 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 15611 :UBC 0 : dumpSecLabel(fout, "AGGREGATE", aggsig,
3440 sfrost@snowman.net 15612 : 0 : agginfo->aggfn.dobj.namespace->dobj.name,
15613 : 0 : agginfo->aggfn.rolname,
2999 tgl@sss.pgh.pa.us 15614 : 0 : agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
15615 : :
15616 : : /*
15617 : : * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
15618 : : * command look like a function's GRANT; in particular this affects the
15619 : : * syntax for zero-argument aggregates and ordered-set aggregates.
15620 : : */
7945 tgl@sss.pgh.pa.us 15621 :CBC 291 : free(aggsig);
15622 : :
4961 rhaas@postgresql.org 15623 : 291 : aggsig = format_function_signature(fout, &agginfo->aggfn, true);
15624 : :
3440 sfrost@snowman.net 15625 [ + + ]: 291 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
1883 tgl@sss.pgh.pa.us 15626 : 18 : dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
15627 : : "FUNCTION", aggsig, NULL,
3440 sfrost@snowman.net 15628 : 18 : agginfo->aggfn.dobj.namespace->dobj.name,
523 tgl@sss.pgh.pa.us 15629 : 18 : NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
15630 : :
7945 15631 : 291 : free(aggsig);
1178 peter@eisentraut.org 15632 : 291 : free(aggfullsig);
7945 tgl@sss.pgh.pa.us 15633 : 291 : free(aggsig_tag);
15634 : :
8520 15635 : 291 : PQclear(res);
15636 : :
15637 : 291 : destroyPQExpBuffer(query);
8800 15638 : 291 : destroyPQExpBuffer(q);
15639 : 291 : destroyPQExpBuffer(delq);
15640 : 291 : destroyPQExpBuffer(details);
15641 : : }
15642 : :
15643 : : /*
15644 : : * dumpTSParser
15645 : : * write out a single text search parser
15646 : : */
15647 : : static void
1669 peter@eisentraut.org 15648 : 47 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
15649 : : {
3524 tgl@sss.pgh.pa.us 15650 : 47 : DumpOptions *dopt = fout->dopt;
15651 : : PQExpBuffer q;
15652 : : PQExpBuffer delq;
15653 : : char *qprsname;
15654 : :
15655 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 15656 [ + + ]: 47 : if (!dopt->dumpSchema)
6591 tgl@sss.pgh.pa.us 15657 : 6 : return;
15658 : :
15659 : 41 : q = createPQExpBuffer();
15660 : 41 : delq = createPQExpBuffer();
15661 : :
2749 15662 : 41 : qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
15663 : :
6591 15664 : 41 : appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
2749 15665 : 41 : fmtQualifiedDumpable(prsinfo));
15666 : :
6591 15667 : 41 : appendPQExpBuffer(q, " START = %s,\n",
4960 rhaas@postgresql.org 15668 : 41 : convertTSFunction(fout, prsinfo->prsstart));
6591 tgl@sss.pgh.pa.us 15669 : 41 : appendPQExpBuffer(q, " GETTOKEN = %s,\n",
4960 rhaas@postgresql.org 15670 : 41 : convertTSFunction(fout, prsinfo->prstoken));
6591 tgl@sss.pgh.pa.us 15671 : 41 : appendPQExpBuffer(q, " END = %s,\n",
4960 rhaas@postgresql.org 15672 : 41 : convertTSFunction(fout, prsinfo->prsend));
6591 tgl@sss.pgh.pa.us 15673 [ + + ]: 41 : if (prsinfo->prsheadline != InvalidOid)
15674 : 3 : appendPQExpBuffer(q, " HEADLINE = %s,\n",
4960 rhaas@postgresql.org 15675 : 3 : convertTSFunction(fout, prsinfo->prsheadline));
6591 tgl@sss.pgh.pa.us 15676 : 41 : appendPQExpBuffer(q, " LEXTYPES = %s );\n",
4960 rhaas@postgresql.org 15677 : 41 : convertTSFunction(fout, prsinfo->prslextype));
15678 : :
2749 tgl@sss.pgh.pa.us 15679 : 41 : appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
15680 : 41 : fmtQualifiedDumpable(prsinfo));
15681 : :
3980 alvherre@alvh.no-ip. 15682 [ + + ]: 41 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 15683 : 1 : binary_upgrade_extension_member(q, &prsinfo->dobj,
15684 : : "TEXT SEARCH PARSER", qprsname,
15685 : 1 : prsinfo->dobj.namespace->dobj.name);
15686 : :
3440 sfrost@snowman.net 15687 [ + - ]: 41 : if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15688 : 41 : ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 15689 : 41 : ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
15690 : : .namespace = prsinfo->dobj.namespace->dobj.name,
15691 : : .description = "TEXT SEARCH PARSER",
15692 : : .section = SECTION_PRE_DATA,
15693 : : .createStmt = q->data,
15694 : : .dropStmt = delq->data));
15695 : :
15696 : : /* Dump Parser Comments */
3440 sfrost@snowman.net 15697 [ + - ]: 41 : if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 15698 : 41 : dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
3106 15699 : 41 : prsinfo->dobj.namespace->dobj.name, "",
3440 sfrost@snowman.net 15700 : 41 : prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
15701 : :
6591 tgl@sss.pgh.pa.us 15702 : 41 : destroyPQExpBuffer(q);
15703 : 41 : destroyPQExpBuffer(delq);
2749 15704 : 41 : free(qprsname);
15705 : : }
15706 : :
15707 : : /*
15708 : : * dumpTSDictionary
15709 : : * write out a single text search dictionary
15710 : : */
15711 : : static void
1669 peter@eisentraut.org 15712 : 179 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
15713 : : {
3524 tgl@sss.pgh.pa.us 15714 : 179 : DumpOptions *dopt = fout->dopt;
15715 : : PQExpBuffer q;
15716 : : PQExpBuffer delq;
15717 : : PQExpBuffer query;
15718 : : char *qdictname;
15719 : : PGresult *res;
15720 : : char *nspname;
15721 : : char *tmplname;
15722 : :
15723 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 15724 [ + + ]: 179 : if (!dopt->dumpSchema)
6591 tgl@sss.pgh.pa.us 15725 : 6 : return;
15726 : :
15727 : 173 : q = createPQExpBuffer();
15728 : 173 : delq = createPQExpBuffer();
15729 : 173 : query = createPQExpBuffer();
15730 : :
2749 15731 : 173 : qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
15732 : :
15733 : : /* Fetch name and namespace of the dictionary's template */
6591 15734 : 173 : appendPQExpBuffer(query, "SELECT nspname, tmplname "
15735 : : "FROM pg_ts_template p, pg_namespace n "
15736 : : "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
15737 : 173 : dictinfo->dicttemplate);
4951 rhaas@postgresql.org 15738 : 173 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
6591 tgl@sss.pgh.pa.us 15739 : 173 : nspname = PQgetvalue(res, 0, 0);
15740 : 173 : tmplname = PQgetvalue(res, 0, 1);
15741 : :
15742 : 173 : appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
2749 15743 : 173 : fmtQualifiedDumpable(dictinfo));
15744 : :
4310 heikki.linnakangas@i 15745 : 173 : appendPQExpBufferStr(q, " TEMPLATE = ");
2749 tgl@sss.pgh.pa.us 15746 : 173 : appendPQExpBuffer(q, "%s.", fmtId(nspname));
4310 heikki.linnakangas@i 15747 : 173 : appendPQExpBufferStr(q, fmtId(tmplname));
15748 : :
6591 tgl@sss.pgh.pa.us 15749 : 173 : PQclear(res);
15750 : :
15751 : : /* the dictinitoption can be dumped straight into the command */
15752 [ + + ]: 173 : if (dictinfo->dictinitoption)
6590 15753 : 132 : appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
15754 : :
4310 heikki.linnakangas@i 15755 : 173 : appendPQExpBufferStr(q, " );\n");
15756 : :
2749 tgl@sss.pgh.pa.us 15757 : 173 : appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
15758 : 173 : fmtQualifiedDumpable(dictinfo));
15759 : :
3980 alvherre@alvh.no-ip. 15760 [ + + ]: 173 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 15761 : 10 : binary_upgrade_extension_member(q, &dictinfo->dobj,
15762 : : "TEXT SEARCH DICTIONARY", qdictname,
15763 : 10 : dictinfo->dobj.namespace->dobj.name);
15764 : :
3440 sfrost@snowman.net 15765 [ + - ]: 173 : if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15766 : 173 : ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 15767 : 173 : ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
15768 : : .namespace = dictinfo->dobj.namespace->dobj.name,
15769 : : .owner = dictinfo->rolname,
15770 : : .description = "TEXT SEARCH DICTIONARY",
15771 : : .section = SECTION_PRE_DATA,
15772 : : .createStmt = q->data,
15773 : : .dropStmt = delq->data));
15774 : :
15775 : : /* Dump Dictionary Comments */
3440 sfrost@snowman.net 15776 [ + + ]: 173 : if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 15777 : 128 : dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
3106 15778 : 128 : dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
3440 sfrost@snowman.net 15779 : 128 : dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
15780 : :
6591 tgl@sss.pgh.pa.us 15781 : 173 : destroyPQExpBuffer(q);
15782 : 173 : destroyPQExpBuffer(delq);
15783 : 173 : destroyPQExpBuffer(query);
2749 15784 : 173 : free(qdictname);
15785 : : }
15786 : :
15787 : : /*
15788 : : * dumpTSTemplate
15789 : : * write out a single text search template
15790 : : */
15791 : : static void
1669 peter@eisentraut.org 15792 : 59 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
15793 : : {
3524 tgl@sss.pgh.pa.us 15794 : 59 : DumpOptions *dopt = fout->dopt;
15795 : : PQExpBuffer q;
15796 : : PQExpBuffer delq;
15797 : : char *qtmplname;
15798 : :
15799 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 15800 [ + + ]: 59 : if (!dopt->dumpSchema)
6591 tgl@sss.pgh.pa.us 15801 : 6 : return;
15802 : :
15803 : 53 : q = createPQExpBuffer();
15804 : 53 : delq = createPQExpBuffer();
15805 : :
2749 15806 : 53 : qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
15807 : :
6591 15808 : 53 : appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
2749 15809 : 53 : fmtQualifiedDumpable(tmplinfo));
15810 : :
6591 15811 [ + + ]: 53 : if (tmplinfo->tmplinit != InvalidOid)
15812 : 15 : appendPQExpBuffer(q, " INIT = %s,\n",
4960 rhaas@postgresql.org 15813 : 15 : convertTSFunction(fout, tmplinfo->tmplinit));
6591 tgl@sss.pgh.pa.us 15814 : 53 : appendPQExpBuffer(q, " LEXIZE = %s );\n",
4960 rhaas@postgresql.org 15815 : 53 : convertTSFunction(fout, tmplinfo->tmpllexize));
15816 : :
2749 tgl@sss.pgh.pa.us 15817 : 53 : appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
15818 : 53 : fmtQualifiedDumpable(tmplinfo));
15819 : :
3980 alvherre@alvh.no-ip. 15820 [ + + ]: 53 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 15821 : 1 : binary_upgrade_extension_member(q, &tmplinfo->dobj,
15822 : : "TEXT SEARCH TEMPLATE", qtmplname,
15823 : 1 : tmplinfo->dobj.namespace->dobj.name);
15824 : :
3440 sfrost@snowman.net 15825 [ + - ]: 53 : if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15826 : 53 : ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 15827 : 53 : ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
15828 : : .namespace = tmplinfo->dobj.namespace->dobj.name,
15829 : : .description = "TEXT SEARCH TEMPLATE",
15830 : : .section = SECTION_PRE_DATA,
15831 : : .createStmt = q->data,
15832 : : .dropStmt = delq->data));
15833 : :
15834 : : /* Dump Template Comments */
3440 sfrost@snowman.net 15835 [ + - ]: 53 : if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 15836 : 53 : dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
3106 15837 : 53 : tmplinfo->dobj.namespace->dobj.name, "",
3440 sfrost@snowman.net 15838 : 53 : tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
15839 : :
6591 tgl@sss.pgh.pa.us 15840 : 53 : destroyPQExpBuffer(q);
15841 : 53 : destroyPQExpBuffer(delq);
2749 15842 : 53 : free(qtmplname);
15843 : : }
15844 : :
15845 : : /*
15846 : : * dumpTSConfig
15847 : : * write out a single text search configuration
15848 : : */
15849 : : static void
1669 peter@eisentraut.org 15850 : 154 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
15851 : : {
3524 tgl@sss.pgh.pa.us 15852 : 154 : DumpOptions *dopt = fout->dopt;
15853 : : PQExpBuffer q;
15854 : : PQExpBuffer delq;
15855 : : PQExpBuffer query;
15856 : : char *qcfgname;
15857 : : PGresult *res;
15858 : : char *nspname;
15859 : : char *prsname;
15860 : : int ntups,
15861 : : i;
15862 : : int i_tokenname;
15863 : : int i_dictname;
15864 : :
15865 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 15866 [ + + ]: 154 : if (!dopt->dumpSchema)
6591 tgl@sss.pgh.pa.us 15867 : 6 : return;
15868 : :
15869 : 148 : q = createPQExpBuffer();
15870 : 148 : delq = createPQExpBuffer();
15871 : 148 : query = createPQExpBuffer();
15872 : :
2749 15873 : 148 : qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
15874 : :
15875 : : /* Fetch name and namespace of the config's parser */
6591 15876 : 148 : appendPQExpBuffer(query, "SELECT nspname, prsname "
15877 : : "FROM pg_ts_parser p, pg_namespace n "
15878 : : "WHERE p.oid = '%u' AND n.oid = prsnamespace",
15879 : 148 : cfginfo->cfgparser);
4951 rhaas@postgresql.org 15880 : 148 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
6591 tgl@sss.pgh.pa.us 15881 : 148 : nspname = PQgetvalue(res, 0, 0);
15882 : 148 : prsname = PQgetvalue(res, 0, 1);
15883 : :
15884 : 148 : appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
2749 15885 : 148 : fmtQualifiedDumpable(cfginfo));
15886 : :
15887 : 148 : appendPQExpBuffer(q, " PARSER = %s.", fmtId(nspname));
6591 15888 : 148 : appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
15889 : :
15890 : 148 : PQclear(res);
15891 : :
15892 : 148 : resetPQExpBuffer(query);
15893 : 148 : appendPQExpBuffer(query,
15894 : : "SELECT\n"
15895 : : " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
15896 : : " WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
15897 : : " m.mapdict::pg_catalog.regdictionary AS dictname\n"
15898 : : "FROM pg_catalog.pg_ts_config_map AS m\n"
15899 : : "WHERE m.mapcfg = '%u'\n"
15900 : : "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
15901 : 148 : cfginfo->cfgparser, cfginfo->dobj.catId.oid);
15902 : :
4960 rhaas@postgresql.org 15903 : 148 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6591 tgl@sss.pgh.pa.us 15904 : 148 : ntups = PQntuples(res);
15905 : :
15906 : 148 : i_tokenname = PQfnumber(res, "tokenname");
15907 : 148 : i_dictname = PQfnumber(res, "dictname");
15908 : :
15909 [ + + ]: 3095 : for (i = 0; i < ntups; i++)
15910 : : {
6505 bruce@momjian.us 15911 : 2947 : char *tokenname = PQgetvalue(res, i, i_tokenname);
15912 : 2947 : char *dictname = PQgetvalue(res, i, i_dictname);
15913 : :
6591 tgl@sss.pgh.pa.us 15914 [ + + ]: 2947 : if (i == 0 ||
6505 bruce@momjian.us 15915 [ + + ]: 2799 : strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
15916 : : {
15917 : : /* starting a new token type, so start a new command */
6591 tgl@sss.pgh.pa.us 15918 [ + + ]: 2812 : if (i > 0)
4310 heikki.linnakangas@i 15919 : 2664 : appendPQExpBufferStr(q, ";\n");
6591 tgl@sss.pgh.pa.us 15920 : 2812 : appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
2749 15921 : 2812 : fmtQualifiedDumpable(cfginfo));
15922 : : /* tokenname needs quoting, dictname does NOT */
6591 15923 : 2812 : appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
15924 : : fmtId(tokenname), dictname);
15925 : : }
15926 : : else
15927 : 135 : appendPQExpBuffer(q, ", %s", dictname);
15928 : : }
15929 : :
15930 [ + - ]: 148 : if (ntups > 0)
4310 heikki.linnakangas@i 15931 : 148 : appendPQExpBufferStr(q, ";\n");
15932 : :
6591 tgl@sss.pgh.pa.us 15933 : 148 : PQclear(res);
15934 : :
2749 15935 : 148 : appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
15936 : 148 : fmtQualifiedDumpable(cfginfo));
15937 : :
3980 alvherre@alvh.no-ip. 15938 [ + + ]: 148 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 15939 : 5 : binary_upgrade_extension_member(q, &cfginfo->dobj,
15940 : : "TEXT SEARCH CONFIGURATION", qcfgname,
15941 : 5 : cfginfo->dobj.namespace->dobj.name);
15942 : :
3440 sfrost@snowman.net 15943 [ + - ]: 148 : if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15944 : 148 : ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 15945 : 148 : ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
15946 : : .namespace = cfginfo->dobj.namespace->dobj.name,
15947 : : .owner = cfginfo->rolname,
15948 : : .description = "TEXT SEARCH CONFIGURATION",
15949 : : .section = SECTION_PRE_DATA,
15950 : : .createStmt = q->data,
15951 : : .dropStmt = delq->data));
15952 : :
15953 : : /* Dump Configuration Comments */
3440 sfrost@snowman.net 15954 [ + + ]: 148 : if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 15955 : 128 : dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
3106 15956 : 128 : cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
3440 sfrost@snowman.net 15957 : 128 : cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
15958 : :
6591 tgl@sss.pgh.pa.us 15959 : 148 : destroyPQExpBuffer(q);
15960 : 148 : destroyPQExpBuffer(delq);
15961 : 148 : destroyPQExpBuffer(query);
2749 15962 : 148 : free(qcfgname);
15963 : : }
15964 : :
15965 : : /*
15966 : : * dumpForeignDataWrapper
15967 : : * write out a single foreign-data wrapper definition
15968 : : */
15969 : : static void
1669 peter@eisentraut.org 15970 : 58 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
15971 : : {
3524 tgl@sss.pgh.pa.us 15972 : 58 : DumpOptions *dopt = fout->dopt;
15973 : : PQExpBuffer q;
15974 : : PQExpBuffer delq;
15975 : : char *qfdwname;
15976 : :
15977 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 15978 [ + + ]: 58 : if (!dopt->dumpSchema)
6105 peter_e@gmx.net 15979 : 7 : return;
15980 : :
15981 : 51 : q = createPQExpBuffer();
15982 : 51 : delq = createPQExpBuffer();
15983 : :
5034 bruce@momjian.us 15984 : 51 : qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
15985 : :
6038 peter_e@gmx.net 15986 : 51 : appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
15987 : : qfdwname);
15988 : :
5313 tgl@sss.pgh.pa.us 15989 [ - + ]: 51 : if (strcmp(fdwinfo->fdwhandler, "-") != 0)
5313 tgl@sss.pgh.pa.us 15990 :UBC 0 : appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
15991 : :
5313 tgl@sss.pgh.pa.us 15992 [ - + ]:CBC 51 : if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
5313 tgl@sss.pgh.pa.us 15993 :UBC 0 : appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
15994 : :
5313 tgl@sss.pgh.pa.us 15995 [ - + ]:CBC 51 : if (strlen(fdwinfo->fdwoptions) > 0)
4993 peter_e@gmx.net 15996 :UBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
15997 : :
4310 heikki.linnakangas@i 15998 :CBC 51 : appendPQExpBufferStr(q, ";\n");
15999 : :
6105 peter_e@gmx.net 16000 : 51 : appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
16001 : : qfdwname);
16002 : :
3980 alvherre@alvh.no-ip. 16003 [ + + ]: 51 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 16004 : 2 : binary_upgrade_extension_member(q, &fdwinfo->dobj,
16005 : : "FOREIGN DATA WRAPPER", qfdwname,
16006 : : NULL);
16007 : :
3440 sfrost@snowman.net 16008 [ + - ]: 51 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16009 : 51 : ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 16010 : 51 : ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
16011 : : .owner = fdwinfo->rolname,
16012 : : .description = "FOREIGN DATA WRAPPER",
16013 : : .section = SECTION_PRE_DATA,
16014 : : .createStmt = q->data,
16015 : : .dropStmt = delq->data));
16016 : :
16017 : : /* Dump Foreign Data Wrapper Comments */
2784 tgl@sss.pgh.pa.us 16018 [ - + ]: 51 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 16019 :UBC 0 : dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
2784 16020 : 0 : NULL, fdwinfo->rolname,
16021 : 0 : fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
16022 : :
16023 : : /* Handle the ACL */
3440 sfrost@snowman.net 16024 [ + + ]:CBC 51 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
1883 tgl@sss.pgh.pa.us 16025 : 37 : dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
16026 : : "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
1370 16027 : 37 : NULL, fdwinfo->rolname, &fdwinfo->dacl);
16028 : :
5323 16029 : 51 : free(qfdwname);
16030 : :
6105 peter_e@gmx.net 16031 : 51 : destroyPQExpBuffer(q);
16032 : 51 : destroyPQExpBuffer(delq);
16033 : : }
16034 : :
16035 : : /*
16036 : : * dumpForeignServer
16037 : : * write out a foreign server definition
16038 : : */
16039 : : static void
1669 peter@eisentraut.org 16040 : 62 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
16041 : : {
3524 tgl@sss.pgh.pa.us 16042 : 62 : DumpOptions *dopt = fout->dopt;
16043 : : PQExpBuffer q;
16044 : : PQExpBuffer delq;
16045 : : PQExpBuffer query;
16046 : : PGresult *res;
16047 : : char *qsrvname;
16048 : : char *fdwname;
16049 : :
16050 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 16051 [ + + ]: 62 : if (!dopt->dumpSchema)
6105 peter_e@gmx.net 16052 : 9 : return;
16053 : :
16054 : 53 : q = createPQExpBuffer();
16055 : 53 : delq = createPQExpBuffer();
16056 : 53 : query = createPQExpBuffer();
16057 : :
5034 bruce@momjian.us 16058 : 53 : qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
16059 : :
16060 : : /* look up the foreign-data wrapper */
6105 peter_e@gmx.net 16061 : 53 : appendPQExpBuffer(query, "SELECT fdwname "
16062 : : "FROM pg_foreign_data_wrapper w "
16063 : : "WHERE w.oid = '%u'",
16064 : 53 : srvinfo->srvfdw);
4951 rhaas@postgresql.org 16065 : 53 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
6105 peter_e@gmx.net 16066 : 53 : fdwname = PQgetvalue(res, 0, 0);
16067 : :
5323 tgl@sss.pgh.pa.us 16068 : 53 : appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
6105 peter_e@gmx.net 16069 [ + - - + ]: 53 : if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
16070 : : {
4310 heikki.linnakangas@i 16071 :UBC 0 : appendPQExpBufferStr(q, " TYPE ");
5995 16072 : 0 : appendStringLiteralAH(q, srvinfo->srvtype, fout);
16073 : : }
6105 peter_e@gmx.net 16074 [ + - - + ]:CBC 53 : if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
16075 : : {
4310 heikki.linnakangas@i 16076 :UBC 0 : appendPQExpBufferStr(q, " VERSION ");
5995 16077 : 0 : appendStringLiteralAH(q, srvinfo->srvversion, fout);
16078 : : }
16079 : :
4310 heikki.linnakangas@i 16080 :CBC 53 : appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
16081 : 53 : appendPQExpBufferStr(q, fmtId(fdwname));
16082 : :
6105 peter_e@gmx.net 16083 [ + - - + ]: 53 : if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
4993 peter_e@gmx.net 16084 :UBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
16085 : :
4310 heikki.linnakangas@i 16086 :CBC 53 : appendPQExpBufferStr(q, ";\n");
16087 : :
6105 peter_e@gmx.net 16088 : 53 : appendPQExpBuffer(delq, "DROP SERVER %s;\n",
16089 : : qsrvname);
16090 : :
3980 alvherre@alvh.no-ip. 16091 [ + + ]: 53 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 16092 : 2 : binary_upgrade_extension_member(q, &srvinfo->dobj,
16093 : : "SERVER", qsrvname, NULL);
16094 : :
3440 sfrost@snowman.net 16095 [ + - ]: 53 : if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16096 : 53 : ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 16097 : 53 : ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
16098 : : .owner = srvinfo->rolname,
16099 : : .description = "SERVER",
16100 : : .section = SECTION_PRE_DATA,
16101 : : .createStmt = q->data,
16102 : : .dropStmt = delq->data));
16103 : :
16104 : : /* Dump Foreign Server Comments */
2784 tgl@sss.pgh.pa.us 16105 [ - + ]: 53 : if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 16106 :UBC 0 : dumpComment(fout, "SERVER", qsrvname,
2784 16107 : 0 : NULL, srvinfo->rolname,
16108 : 0 : srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
16109 : :
16110 : : /* Handle the ACL */
3440 sfrost@snowman.net 16111 [ + + ]:CBC 53 : if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
1883 tgl@sss.pgh.pa.us 16112 : 37 : dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
16113 : : "FOREIGN SERVER", qsrvname, NULL, NULL,
1370 16114 : 37 : NULL, srvinfo->rolname, &srvinfo->dacl);
16115 : :
16116 : : /* Dump user mappings */
3440 sfrost@snowman.net 16117 [ + - ]: 53 : if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
16118 : 53 : dumpUserMappings(fout,
16119 : 53 : srvinfo->dobj.name, NULL,
16120 : 53 : srvinfo->rolname,
16121 : 53 : srvinfo->dobj.catId, srvinfo->dobj.dumpId);
16122 : :
1413 tgl@sss.pgh.pa.us 16123 : 53 : PQclear(res);
16124 : :
5323 16125 : 53 : free(qsrvname);
16126 : :
6105 peter_e@gmx.net 16127 : 53 : destroyPQExpBuffer(q);
16128 : 53 : destroyPQExpBuffer(delq);
3435 tgl@sss.pgh.pa.us 16129 : 53 : destroyPQExpBuffer(query);
16130 : : }
16131 : :
16132 : : /*
16133 : : * dumpUserMappings
16134 : : *
16135 : : * This routine is used to dump any user mappings associated with the
16136 : : * server handed to this routine. Should be called after ArchiveEntry()
16137 : : * for the server.
16138 : : */
16139 : : static void
5533 16140 : 53 : dumpUserMappings(Archive *fout,
16141 : : const char *servername, const char *namespace,
16142 : : const char *owner,
16143 : : CatalogId catalogId, DumpId dumpId)
16144 : : {
16145 : : PQExpBuffer q;
16146 : : PQExpBuffer delq;
16147 : : PQExpBuffer query;
16148 : : PQExpBuffer tag;
16149 : : PGresult *res;
16150 : : int ntups;
16151 : : int i_usename;
16152 : : int i_umoptions;
16153 : : int i;
16154 : :
6105 peter_e@gmx.net 16155 : 53 : q = createPQExpBuffer();
16156 : 53 : tag = createPQExpBuffer();
16157 : 53 : delq = createPQExpBuffer();
16158 : 53 : query = createPQExpBuffer();
16159 : :
16160 : : /*
16161 : : * We read from the publicly accessible view pg_user_mappings, so as not
16162 : : * to fail if run by a non-superuser. Note that the view will show
16163 : : * umoptions as null if the user hasn't got privileges for the associated
16164 : : * server; this means that pg_dump will dump such a mapping, but with no
16165 : : * OPTIONS clause. A possible alternative is to skip such mappings
16166 : : * altogether, but it's not clear that that's an improvement.
16167 : : */
16168 : 53 : appendPQExpBuffer(query,
16169 : : "SELECT usename, "
16170 : : "array_to_string(ARRAY("
16171 : : "SELECT quote_ident(option_name) || ' ' || "
16172 : : "quote_literal(option_value) "
16173 : : "FROM pg_options_to_table(umoptions) "
16174 : : "ORDER BY option_name"
16175 : : "), E',\n ') AS umoptions "
16176 : : "FROM pg_user_mappings "
16177 : : "WHERE srvid = '%u' "
16178 : : "ORDER BY usename",
16179 : : catalogId.oid);
16180 : :
4960 rhaas@postgresql.org 16181 : 53 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16182 : :
6105 peter_e@gmx.net 16183 : 53 : ntups = PQntuples(res);
5533 tgl@sss.pgh.pa.us 16184 : 53 : i_usename = PQfnumber(res, "usename");
6105 peter_e@gmx.net 16185 : 53 : i_umoptions = PQfnumber(res, "umoptions");
16186 : :
16187 [ + + ]: 90 : for (i = 0; i < ntups; i++)
16188 : : {
16189 : : char *usename;
16190 : : char *umoptions;
16191 : :
5533 tgl@sss.pgh.pa.us 16192 : 37 : usename = PQgetvalue(res, i, i_usename);
6105 peter_e@gmx.net 16193 : 37 : umoptions = PQgetvalue(res, i, i_umoptions);
16194 : :
16195 : 37 : resetPQExpBuffer(q);
5533 tgl@sss.pgh.pa.us 16196 : 37 : appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
6105 peter_e@gmx.net 16197 : 37 : appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
16198 : :
16199 [ + - - + ]: 37 : if (umoptions && strlen(umoptions) > 0)
4993 peter_e@gmx.net 16200 :UBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
16201 : :
4310 heikki.linnakangas@i 16202 :CBC 37 : appendPQExpBufferStr(q, ";\n");
16203 : :
6105 peter_e@gmx.net 16204 : 37 : resetPQExpBuffer(delq);
5533 tgl@sss.pgh.pa.us 16205 : 37 : appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
16206 : 37 : appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
16207 : :
6105 peter_e@gmx.net 16208 : 37 : resetPQExpBuffer(tag);
5533 tgl@sss.pgh.pa.us 16209 : 37 : appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
16210 : : usename, servername);
16211 : :
6105 peter_e@gmx.net 16212 : 37 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 16213 : 37 : ARCHIVE_OPTS(.tag = tag->data,
16214 : : .namespace = namespace,
16215 : : .owner = owner,
16216 : : .description = "USER MAPPING",
16217 : : .section = SECTION_PRE_DATA,
16218 : : .createStmt = q->data,
16219 : : .dropStmt = delq->data));
16220 : : }
16221 : :
6105 peter_e@gmx.net 16222 : 53 : PQclear(res);
16223 : :
16224 : 53 : destroyPQExpBuffer(query);
16225 : 53 : destroyPQExpBuffer(delq);
4207 sfrost@snowman.net 16226 : 53 : destroyPQExpBuffer(tag);
6105 peter_e@gmx.net 16227 : 53 : destroyPQExpBuffer(q);
16228 : 53 : }
16229 : :
16230 : : /*
16231 : : * Write out default privileges information
16232 : : */
16233 : : static void
1669 peter@eisentraut.org 16234 : 184 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
16235 : : {
3524 tgl@sss.pgh.pa.us 16236 : 184 : DumpOptions *dopt = fout->dopt;
16237 : : PQExpBuffer q;
16238 : : PQExpBuffer tag;
16239 : : const char *type;
16240 : :
16241 : : /* Do nothing if not dumping schema, or if we're skipping ACLs */
285 nathan@postgresql.or 16242 [ + + + + ]: 184 : if (!dopt->dumpSchema || dopt->aclsSkip)
5815 tgl@sss.pgh.pa.us 16243 : 28 : return;
16244 : :
16245 : 156 : q = createPQExpBuffer();
16246 : 156 : tag = createPQExpBuffer();
16247 : :
16248 [ + - + + : 156 : switch (daclinfo->defaclobjtype)
- - - ]
16249 : : {
16250 : 73 : case DEFACLOBJ_RELATION:
5808 16251 : 73 : type = "TABLES";
5815 16252 : 73 : break;
5815 tgl@sss.pgh.pa.us 16253 :UBC 0 : case DEFACLOBJ_SEQUENCE:
5808 16254 : 0 : type = "SEQUENCES";
5815 16255 : 0 : break;
5815 tgl@sss.pgh.pa.us 16256 :CBC 73 : case DEFACLOBJ_FUNCTION:
5808 16257 : 73 : type = "FUNCTIONS";
5815 16258 : 73 : break;
4654 16259 : 10 : case DEFACLOBJ_TYPE:
16260 : 10 : type = "TYPES";
16261 : 10 : break;
3084 teodor@sigaev.ru 16262 :UBC 0 : case DEFACLOBJ_NAMESPACE:
16263 : 0 : type = "SCHEMAS";
16264 : 0 : break;
155 fujii@postgresql.org 16265 : 0 : case DEFACLOBJ_LARGEOBJECT:
16266 : 0 : type = "LARGE OBJECTS";
16267 : 0 : break;
5815 tgl@sss.pgh.pa.us 16268 : 0 : default:
16269 : : /* shouldn't get here */
1247 16270 : 0 : pg_fatal("unrecognized object type in default privileges: %d",
16271 : : (int) daclinfo->defaclobjtype);
16272 : : type = ""; /* keep compiler quiet */
16273 : : }
16274 : :
5808 tgl@sss.pgh.pa.us 16275 :CBC 156 : appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
16276 : :
16277 : : /* build the actual command(s) for this tuple */
5815 16278 [ - + ]: 156 : if (!buildDefaultACLCommands(type,
16279 : 156 : daclinfo->dobj.namespace != NULL ?
16280 : 74 : daclinfo->dobj.namespace->dobj.name : NULL,
1370 16281 : 156 : daclinfo->dacl.acl,
16282 : 156 : daclinfo->dacl.acldefault,
5815 16283 [ + + ]: 156 : daclinfo->defaclrole,
16284 : : fout->remoteVersion,
16285 : : q))
1247 tgl@sss.pgh.pa.us 16286 :UBC 0 : pg_fatal("could not parse default ACL list (%s)",
16287 : : daclinfo->dacl.acl);
16288 : :
3440 sfrost@snowman.net 16289 [ + - ]:CBC 156 : if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
16290 : 156 : ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 16291 [ + + ]: 156 : ARCHIVE_OPTS(.tag = tag->data,
16292 : : .namespace = daclinfo->dobj.namespace ?
16293 : : daclinfo->dobj.namespace->dobj.name : NULL,
16294 : : .owner = daclinfo->defaclrole,
16295 : : .description = "DEFAULT ACL",
16296 : : .section = SECTION_POST_DATA,
16297 : : .createStmt = q->data));
16298 : :
5815 tgl@sss.pgh.pa.us 16299 : 156 : destroyPQExpBuffer(tag);
16300 : 156 : destroyPQExpBuffer(q);
16301 : : }
16302 : :
16303 : : /*----------
16304 : : * Write out grant/revoke information
16305 : : *
16306 : : * 'objDumpId' is the dump ID of the underlying object.
16307 : : * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
16308 : : * or InvalidDumpId if there is no need for a second dependency.
16309 : : * 'type' must be one of
16310 : : * TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
16311 : : * FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
16312 : : * 'name' is the formatted name of the object. Must be quoted etc. already.
16313 : : * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
16314 : : * (Currently we assume that subname is only provided for table columns.)
16315 : : * 'nspname' is the namespace the object is in (NULL if none).
16316 : : * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
16317 : : * to use the default for the object type.
16318 : : * 'owner' is the owner, NULL if there is no owner (for languages).
16319 : : * 'dacl' is the DumpableAcl struct for the object.
16320 : : *
16321 : : * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
16322 : : * no ACL entry was created.
16323 : : *----------
16324 : : */
16325 : : static DumpId
1883 16326 : 28647 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
16327 : : const char *type, const char *name, const char *subname,
16328 : : const char *nspname, const char *tag, const char *owner,
16329 : : const DumpableAcl *dacl)
16330 : : {
16331 : 28647 : DumpId aclDumpId = InvalidDumpId;
3524 16332 : 28647 : DumpOptions *dopt = fout->dopt;
1370 16333 : 28647 : const char *acls = dacl->acl;
16334 : 28647 : const char *acldefault = dacl->acldefault;
16335 : 28647 : char privtype = dacl->privtype;
16336 : 28647 : const char *initprivs = dacl->initprivs;
16337 : : const char *baseacls;
16338 : : PQExpBuffer sql;
16339 : :
16340 : : /* Do nothing if ACL dump is not enabled */
3980 alvherre@alvh.no-ip. 16341 [ + + ]: 28647 : if (dopt->aclsSkip)
1883 tgl@sss.pgh.pa.us 16342 : 324 : return InvalidDumpId;
16343 : :
16344 : : /* --data-only skips ACLs *except* large object ACLs */
285 nathan@postgresql.or 16345 [ + + - + ]: 28323 : if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
1883 tgl@sss.pgh.pa.us 16346 :UBC 0 : return InvalidDumpId;
16347 : :
8524 tgl@sss.pgh.pa.us 16348 :CBC 28323 : sql = createPQExpBuffer();
16349 : :
16350 : : /*
16351 : : * In binary upgrade mode, we don't run an extension's script but instead
16352 : : * dump out the objects independently and then recreate them. To preserve
16353 : : * any initial privileges which were set on extension objects, we need to
16354 : : * compute the set of GRANT and REVOKE commands necessary to get from the
16355 : : * default privileges of an object to its initial privileges as recorded
16356 : : * in pg_init_privs.
16357 : : *
16358 : : * At restore time, we apply these commands after having called
16359 : : * binary_upgrade_set_record_init_privs(true). That tells the backend to
16360 : : * copy the results into pg_init_privs. This is how we preserve the
16361 : : * contents of that catalog across binary upgrades.
16362 : : */
1370 16363 [ + + + + : 28323 : if (dopt->binary_upgrade && privtype == 'e' &&
+ - ]
16364 [ + - ]: 13 : initprivs && *initprivs != '\0')
16365 : : {
2256 drowley@postgresql.o 16366 : 13 : appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
2749 tgl@sss.pgh.pa.us 16367 [ - + ]: 13 : if (!buildACLCommands(name, subname, nspname, type,
16368 : : initprivs, acldefault, owner,
16369 : : "", fout->remoteVersion, sql))
1247 tgl@sss.pgh.pa.us 16370 :UBC 0 : pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
16371 : : initprivs, acldefault, name, type);
2256 drowley@postgresql.o 16372 :CBC 13 : appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
16373 : : }
16374 : :
16375 : : /*
16376 : : * Now figure the GRANT and REVOKE commands needed to get to the object's
16377 : : * actual current ACL, starting from the initprivs if given, else from the
16378 : : * object-type-specific default. Also, while buildACLCommands will assume
16379 : : * that a NULL/empty acls string means it needn't do anything, what that
16380 : : * actually represents is the object-type-specific default; so we need to
16381 : : * substitute the acldefault string to get the right results in that case.
16382 : : */
1370 tgl@sss.pgh.pa.us 16383 [ + + + + ]: 28323 : if (initprivs && *initprivs != '\0')
16384 : : {
16385 : 26304 : baseacls = initprivs;
16386 [ + - + + ]: 26304 : if (acls == NULL || *acls == '\0')
16387 : 17 : acls = acldefault;
16388 : : }
16389 : : else
16390 : 2019 : baseacls = acldefault;
16391 : :
2749 16392 [ - + ]: 28323 : if (!buildACLCommands(name, subname, nspname, type,
16393 : : acls, baseacls, owner,
16394 : : "", fout->remoteVersion, sql))
1247 tgl@sss.pgh.pa.us 16395 :UBC 0 : pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
16396 : : acls, baseacls, name, type);
16397 : :
8135 tgl@sss.pgh.pa.us 16398 [ + + ]:CBC 28323 : if (sql->len > 0)
16399 : : {
523 16400 : 2090 : PQExpBuffer tagbuf = createPQExpBuffer();
16401 : : DumpId aclDeps[2];
1883 16402 : 2090 : int nDeps = 0;
16403 : :
523 16404 [ - + ]: 2090 : if (tag)
523 tgl@sss.pgh.pa.us 16405 :UBC 0 : appendPQExpBufferStr(tagbuf, tag);
523 tgl@sss.pgh.pa.us 16406 [ + + ]:CBC 2090 : else if (subname)
16407 : 1239 : appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
16408 : : else
16409 : 851 : appendPQExpBuffer(tagbuf, "%s %s", type, name);
16410 : :
1883 16411 : 2090 : aclDeps[nDeps++] = objDumpId;
16412 [ + + ]: 2090 : if (altDumpId != InvalidDumpId)
16413 : 1149 : aclDeps[nDeps++] = altDumpId;
16414 : :
16415 : 2090 : aclDumpId = createDumpId();
16416 : :
16417 : 2090 : ArchiveEntry(fout, nilCatalogId, aclDumpId,
523 16418 : 2090 : ARCHIVE_OPTS(.tag = tagbuf->data,
16419 : : .namespace = nspname,
16420 : : .owner = owner,
16421 : : .description = "ACL",
16422 : : .section = SECTION_NONE,
16423 : : .createStmt = sql->data,
16424 : : .deps = aclDeps,
16425 : : .nDeps = nDeps));
16426 : :
16427 : 2090 : destroyPQExpBuffer(tagbuf);
16428 : : }
16429 : :
8524 16430 : 28323 : destroyPQExpBuffer(sql);
16431 : :
1883 16432 : 28323 : return aclDumpId;
16433 : : }
16434 : :
16435 : : /*
16436 : : * dumpSecLabel
16437 : : *
16438 : : * This routine is used to dump any security labels associated with the
16439 : : * object handed to this routine. The routine takes the object type
16440 : : * and object name (ready to print, except for schema decoration), plus
16441 : : * the namespace and owner of the object (for labeling the ArchiveEntry),
16442 : : * plus catalog ID and subid which are the lookup key for pg_seclabel,
16443 : : * plus the dump ID for the object (for setting a dependency).
16444 : : * If a matching pg_seclabel entry is found, it is dumped.
16445 : : *
16446 : : * Note: although this routine takes a dumpId for dependency purposes,
16447 : : * that purpose is just to mark the dependency in the emitted dump file
16448 : : * for possible future use by pg_restore. We do NOT use it for determining
16449 : : * ordering of the label in the dump file, because this routine is called
16450 : : * after dependency sorting occurs. This routine should be called just after
16451 : : * calling ArchiveEntry() for the specified object.
16452 : : */
16453 : : static void
2749 tgl@sss.pgh.pa.us 16454 :UBC 0 : dumpSecLabel(Archive *fout, const char *type, const char *name,
16455 : : const char *namespace, const char *owner,
16456 : : CatalogId catalogId, int subid, DumpId dumpId)
16457 : : {
3524 16458 : 0 : DumpOptions *dopt = fout->dopt;
16459 : : SecLabelItem *labels;
16460 : : int nlabels;
16461 : : int i;
16462 : : PQExpBuffer query;
16463 : :
16464 : : /* do nothing, if --no-security-labels is supplied */
3980 alvherre@alvh.no-ip. 16465 [ # # ]: 0 : if (dopt->no_security_labels)
5458 rhaas@postgresql.org 16466 : 0 : return;
16467 : :
16468 : : /*
16469 : : * Security labels are schema not data ... except large object labels are
16470 : : * data
16471 : : */
2749 tgl@sss.pgh.pa.us 16472 [ # # ]: 0 : if (strcmp(type, "LARGE OBJECT") != 0)
16473 : : {
285 nathan@postgresql.or 16474 [ # # ]: 0 : if (!dopt->dumpSchema)
5458 rhaas@postgresql.org 16475 : 0 : return;
16476 : : }
16477 : : else
16478 : : {
16479 : : /* We do dump large object security labels in binary-upgrade mode */
285 nathan@postgresql.or 16480 [ # # # # ]: 0 : if (!dopt->dumpData && !dopt->binary_upgrade)
5458 rhaas@postgresql.org 16481 : 0 : return;
16482 : : }
16483 : :
16484 : : /* Search for security labels associated with catalogId, using table */
1346 tgl@sss.pgh.pa.us 16485 : 0 : nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
16486 : :
5458 rhaas@postgresql.org 16487 : 0 : query = createPQExpBuffer();
16488 : :
16489 [ # # ]: 0 : for (i = 0; i < nlabels; i++)
16490 : : {
16491 : : /*
16492 : : * Ignore label entries for which the subid doesn't match.
16493 : : */
16494 [ # # ]: 0 : if (labels[i].objsubid != subid)
16495 : 0 : continue;
16496 : :
16497 : 0 : appendPQExpBuffer(query,
16498 : : "SECURITY LABEL FOR %s ON %s ",
2749 tgl@sss.pgh.pa.us 16499 : 0 : fmtId(labels[i].provider), type);
16500 [ # # # # ]: 0 : if (namespace && *namespace)
16501 : 0 : appendPQExpBuffer(query, "%s.", fmtId(namespace));
16502 : 0 : appendPQExpBuffer(query, "%s IS ", name);
5458 rhaas@postgresql.org 16503 : 0 : appendStringLiteralAH(query, labels[i].label, fout);
4310 heikki.linnakangas@i 16504 : 0 : appendPQExpBufferStr(query, ";\n");
16505 : : }
16506 : :
5458 rhaas@postgresql.org 16507 [ # # ]: 0 : if (query->len > 0)
16508 : : {
2749 tgl@sss.pgh.pa.us 16509 : 0 : PQExpBuffer tag = createPQExpBuffer();
16510 : :
16511 : 0 : appendPQExpBuffer(tag, "%s %s", type, name);
5458 rhaas@postgresql.org 16512 : 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 16513 : 0 : ARCHIVE_OPTS(.tag = tag->data,
16514 : : .namespace = namespace,
16515 : : .owner = owner,
16516 : : .description = "SECURITY LABEL",
16517 : : .section = SECTION_NONE,
16518 : : .createStmt = query->data,
16519 : : .deps = &dumpId,
16520 : : .nDeps = 1));
2749 tgl@sss.pgh.pa.us 16521 : 0 : destroyPQExpBuffer(tag);
16522 : : }
16523 : :
5458 rhaas@postgresql.org 16524 : 0 : destroyPQExpBuffer(query);
16525 : : }
16526 : :
16527 : : /*
16528 : : * dumpTableSecLabel
16529 : : *
16530 : : * As above, but dump security label for both the specified table (or view)
16531 : : * and its columns.
16532 : : */
16533 : : static void
1669 peter@eisentraut.org 16534 : 0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
16535 : : {
3524 tgl@sss.pgh.pa.us 16536 : 0 : DumpOptions *dopt = fout->dopt;
16537 : : SecLabelItem *labels;
16538 : : int nlabels;
16539 : : int i;
16540 : : PQExpBuffer query;
16541 : : PQExpBuffer target;
16542 : :
16543 : : /* do nothing, if --no-security-labels is supplied */
3980 alvherre@alvh.no-ip. 16544 [ # # ]: 0 : if (dopt->no_security_labels)
5458 rhaas@postgresql.org 16545 : 0 : return;
16546 : :
16547 : : /* SecLabel are SCHEMA not data */
285 nathan@postgresql.or 16548 [ # # ]: 0 : if (!dopt->dumpSchema)
5458 rhaas@postgresql.org 16549 : 0 : return;
16550 : :
16551 : : /* Search for comments associated with relation, using table */
1346 tgl@sss.pgh.pa.us 16552 : 0 : nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
5458 rhaas@postgresql.org 16553 : 0 : tbinfo->dobj.catId.oid,
16554 : : &labels);
16555 : :
16556 : : /* If security labels exist, build SECURITY LABEL statements */
16557 [ # # ]: 0 : if (nlabels <= 0)
16558 : 0 : return;
16559 : :
16560 : 0 : query = createPQExpBuffer();
16561 : 0 : target = createPQExpBuffer();
16562 : :
16563 [ # # ]: 0 : for (i = 0; i < nlabels; i++)
16564 : : {
16565 : : const char *colname;
5263 bruce@momjian.us 16566 : 0 : const char *provider = labels[i].provider;
16567 : 0 : const char *label = labels[i].label;
16568 : 0 : int objsubid = labels[i].objsubid;
16569 : :
5458 rhaas@postgresql.org 16570 : 0 : resetPQExpBuffer(target);
16571 [ # # ]: 0 : if (objsubid == 0)
16572 : : {
16573 : 0 : appendPQExpBuffer(target, "%s %s", reltypename,
2749 tgl@sss.pgh.pa.us 16574 : 0 : fmtQualifiedDumpable(tbinfo));
16575 : : }
16576 : : else
16577 : : {
5458 rhaas@postgresql.org 16578 : 0 : colname = getAttrName(objsubid, tbinfo);
16579 : : /* first fmtXXX result must be consumed before calling again */
2749 tgl@sss.pgh.pa.us 16580 : 0 : appendPQExpBuffer(target, "COLUMN %s",
16581 : 0 : fmtQualifiedDumpable(tbinfo));
5362 rhaas@postgresql.org 16582 : 0 : appendPQExpBuffer(target, ".%s", fmtId(colname));
16583 : : }
5458 16584 : 0 : appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
16585 : : fmtId(provider), target->data);
16586 : 0 : appendStringLiteralAH(query, label, fout);
4310 heikki.linnakangas@i 16587 : 0 : appendPQExpBufferStr(query, ";\n");
16588 : : }
5458 rhaas@postgresql.org 16589 [ # # ]: 0 : if (query->len > 0)
16590 : : {
16591 : 0 : resetPQExpBuffer(target);
16592 : 0 : appendPQExpBuffer(target, "%s %s", reltypename,
16593 : 0 : fmtId(tbinfo->dobj.name));
16594 : 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 16595 : 0 : ARCHIVE_OPTS(.tag = target->data,
16596 : : .namespace = tbinfo->dobj.namespace->dobj.name,
16597 : : .owner = tbinfo->rolname,
16598 : : .description = "SECURITY LABEL",
16599 : : .section = SECTION_NONE,
16600 : : .createStmt = query->data,
16601 : : .deps = &(tbinfo->dobj.dumpId),
16602 : : .nDeps = 1));
16603 : : }
5458 rhaas@postgresql.org 16604 : 0 : destroyPQExpBuffer(query);
16605 : 0 : destroyPQExpBuffer(target);
16606 : : }
16607 : :
16608 : : /*
16609 : : * findSecLabels
16610 : : *
16611 : : * Find the security label(s), if any, associated with the given object.
16612 : : * All the objsubid values associated with the given classoid/objoid are
16613 : : * found with one search.
16614 : : */
16615 : : static int
1346 tgl@sss.pgh.pa.us 16616 : 0 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
16617 : : {
5263 bruce@momjian.us 16618 : 0 : SecLabelItem *middle = NULL;
16619 : : SecLabelItem *low;
16620 : : SecLabelItem *high;
16621 : : int nmatch;
16622 : :
1370 tgl@sss.pgh.pa.us 16623 [ # # ]: 0 : if (nseclabels <= 0) /* no labels, so no match is possible */
16624 : : {
5049 16625 : 0 : *items = NULL;
16626 : 0 : return 0;
16627 : : }
16628 : :
16629 : : /*
16630 : : * Do binary search to find some item matching the object.
16631 : : */
1370 16632 : 0 : low = &seclabels[0];
16633 : 0 : high = &seclabels[nseclabels - 1];
5458 rhaas@postgresql.org 16634 [ # # ]: 0 : while (low <= high)
16635 : : {
16636 : 0 : middle = low + (high - low) / 2;
16637 : :
16638 [ # # ]: 0 : if (classoid < middle->classoid)
16639 : 0 : high = middle - 1;
16640 [ # # ]: 0 : else if (classoid > middle->classoid)
16641 : 0 : low = middle + 1;
16642 [ # # ]: 0 : else if (objoid < middle->objoid)
16643 : 0 : high = middle - 1;
16644 [ # # ]: 0 : else if (objoid > middle->objoid)
16645 : 0 : low = middle + 1;
16646 : : else
5263 bruce@momjian.us 16647 : 0 : break; /* found a match */
16648 : : }
16649 : :
16650 [ # # ]: 0 : if (low > high) /* no matches */
16651 : : {
5458 rhaas@postgresql.org 16652 : 0 : *items = NULL;
16653 : 0 : return 0;
16654 : : }
16655 : :
16656 : : /*
16657 : : * Now determine how many items match the object. The search loop
16658 : : * invariant still holds: only items between low and high inclusive could
16659 : : * match.
16660 : : */
16661 : 0 : nmatch = 1;
16662 [ # # ]: 0 : while (middle > low)
16663 : : {
16664 [ # # ]: 0 : if (classoid != middle[-1].classoid ||
16665 [ # # ]: 0 : objoid != middle[-1].objoid)
16666 : : break;
16667 : 0 : middle--;
16668 : 0 : nmatch++;
16669 : : }
16670 : :
16671 : 0 : *items = middle;
16672 : :
16673 : 0 : middle += nmatch;
16674 [ # # ]: 0 : while (middle <= high)
16675 : : {
16676 [ # # ]: 0 : if (classoid != middle->classoid ||
16677 [ # # ]: 0 : objoid != middle->objoid)
16678 : : break;
16679 : 0 : middle++;
16680 : 0 : nmatch++;
16681 : : }
16682 : :
16683 : 0 : return nmatch;
16684 : : }
16685 : :
16686 : : /*
16687 : : * collectSecLabels
16688 : : *
16689 : : * Construct a table of all security labels available for database objects;
16690 : : * also set the has-seclabel component flag for each relevant object.
16691 : : *
16692 : : * The table is sorted by classoid/objid/objsubid for speed in lookup.
16693 : : */
16694 : : static void
1370 tgl@sss.pgh.pa.us 16695 :CBC 185 : collectSecLabels(Archive *fout)
16696 : : {
16697 : : PGresult *res;
16698 : : PQExpBuffer query;
16699 : : int i_label;
16700 : : int i_provider;
16701 : : int i_classoid;
16702 : : int i_objoid;
16703 : : int i_objsubid;
16704 : : int ntups;
16705 : : int i;
16706 : : DumpableObject *dobj;
16707 : :
5458 rhaas@postgresql.org 16708 : 185 : query = createPQExpBuffer();
16709 : :
4310 heikki.linnakangas@i 16710 : 185 : appendPQExpBufferStr(query,
16711 : : "SELECT label, provider, classoid, objoid, objsubid "
16712 : : "FROM pg_catalog.pg_seclabel "
16713 : : "ORDER BY classoid, objoid, objsubid");
16714 : :
4960 rhaas@postgresql.org 16715 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16716 : :
16717 : : /* Construct lookup table containing OIDs in numeric form */
5263 bruce@momjian.us 16718 : 185 : i_label = PQfnumber(res, "label");
16719 : 185 : i_provider = PQfnumber(res, "provider");
16720 : 185 : i_classoid = PQfnumber(res, "classoid");
16721 : 185 : i_objoid = PQfnumber(res, "objoid");
16722 : 185 : i_objsubid = PQfnumber(res, "objsubid");
16723 : :
5458 rhaas@postgresql.org 16724 : 185 : ntups = PQntuples(res);
16725 : :
1370 tgl@sss.pgh.pa.us 16726 : 185 : seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
16727 : 185 : nseclabels = 0;
16728 : 185 : dobj = NULL;
16729 : :
5458 rhaas@postgresql.org 16730 [ - + ]: 185 : for (i = 0; i < ntups; i++)
16731 : : {
16732 : : CatalogId objId;
16733 : : int subid;
16734 : :
1370 tgl@sss.pgh.pa.us 16735 :UBC 0 : objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
16736 : 0 : objId.oid = atooid(PQgetvalue(res, i, i_objoid));
16737 : 0 : subid = atoi(PQgetvalue(res, i, i_objsubid));
16738 : :
16739 : : /* We needn't remember labels that don't match any dumpable object */
16740 [ # # ]: 0 : if (dobj == NULL ||
16741 [ # # ]: 0 : dobj->catId.tableoid != objId.tableoid ||
16742 [ # # ]: 0 : dobj->catId.oid != objId.oid)
16743 : 0 : dobj = findObjectByCatalogId(objId);
16744 [ # # ]: 0 : if (dobj == NULL)
16745 : 0 : continue;
16746 : :
16747 : : /*
16748 : : * Labels on columns of composite types are linked to the type's
16749 : : * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
16750 : : * in the type's own DumpableObject.
16751 : : */
16752 [ # # # # ]: 0 : if (subid != 0 && dobj->objType == DO_TABLE &&
16753 [ # # ]: 0 : ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
16754 : 0 : {
16755 : : TypeInfo *cTypeInfo;
16756 : :
16757 : 0 : cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
16758 [ # # ]: 0 : if (cTypeInfo)
16759 : 0 : cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
16760 : : }
16761 : : else
16762 : 0 : dobj->components |= DUMP_COMPONENT_SECLABEL;
16763 : :
16764 : 0 : seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
16765 : 0 : seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
16766 : 0 : seclabels[nseclabels].classoid = objId.tableoid;
16767 : 0 : seclabels[nseclabels].objoid = objId.oid;
16768 : 0 : seclabels[nseclabels].objsubid = subid;
16769 : 0 : nseclabels++;
16770 : : }
16771 : :
1370 tgl@sss.pgh.pa.us 16772 :CBC 185 : PQclear(res);
5263 bruce@momjian.us 16773 : 185 : destroyPQExpBuffer(query);
5458 rhaas@postgresql.org 16774 : 185 : }
16775 : :
16776 : : /*
16777 : : * dumpTable
16778 : : * write out to fout the declarations (not data) of a user-defined table
16779 : : */
16780 : : static void
1669 peter@eisentraut.org 16781 : 31135 : dumpTable(Archive *fout, const TableInfo *tbinfo)
16782 : : {
3440 sfrost@snowman.net 16783 : 31135 : DumpOptions *dopt = fout->dopt;
1883 tgl@sss.pgh.pa.us 16784 : 31135 : DumpId tableAclDumpId = InvalidDumpId;
16785 : : char *namecopy;
16786 : :
16787 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 16788 [ + + ]: 31135 : if (!dopt->dumpSchema)
3438 sfrost@snowman.net 16789 : 1518 : return;
16790 : :
1370 tgl@sss.pgh.pa.us 16791 [ + + ]: 29617 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16792 : : {
16793 [ + + ]: 6989 : if (tbinfo->relkind == RELKIND_SEQUENCE)
16794 : 393 : dumpSequence(fout, tbinfo);
16795 : : else
16796 : 6596 : dumpTableSchema(fout, tbinfo);
16797 : : }
16798 : :
16799 : : /* Handle the ACL here */
3440 sfrost@snowman.net 16800 : 29617 : namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
16801 [ + + ]: 29617 : if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
16802 : : {
2784 tgl@sss.pgh.pa.us 16803 : 23388 : const char *objtype =
841 16804 [ + + ]: 23388 : (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
16805 : :
16806 : : tableAclDumpId =
1883 16807 : 23388 : dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
16808 : : objtype, namecopy, NULL,
523 16809 : 23388 : tbinfo->dobj.namespace->dobj.name,
16810 : 23388 : NULL, tbinfo->rolname, &tbinfo->dacl);
16811 : : }
16812 : :
16813 : : /*
16814 : : * Handle column ACLs, if any. Note: we pull these with a separate query
16815 : : * rather than trying to fetch them during getTableAttrs, so that we won't
16816 : : * miss ACLs on system columns. Doing it this way also allows us to dump
16817 : : * ACLs for catalogs that we didn't mark "interesting" back in getTables.
16818 : : */
1370 16819 [ + + + + ]: 29617 : if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
16820 : : {
3440 sfrost@snowman.net 16821 : 298 : PQExpBuffer query = createPQExpBuffer();
16822 : : PGresult *res;
16823 : : int i;
16824 : :
1370 tgl@sss.pgh.pa.us 16825 [ + + ]: 298 : if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
16826 : : {
16827 : : /* Set up query for column ACLs */
16828 : 159 : appendPQExpBufferStr(query,
16829 : : "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
16830 : :
16831 [ + - ]: 159 : if (fout->remoteVersion >= 90600)
16832 : : {
16833 : : /*
16834 : : * In principle we should call acldefault('c', relowner) to
16835 : : * get the default ACL for a column. However, we don't
16836 : : * currently store the numeric OID of the relowner in
16837 : : * TableInfo. We could convert the owner name using regrole,
16838 : : * but that creates a risk of failure due to concurrent role
16839 : : * renames. Given that the default ACL for columns is empty
16840 : : * and is likely to stay that way, it's not worth extra cycles
16841 : : * and risk to avoid hard-wiring that knowledge here.
16842 : : */
16843 : 159 : appendPQExpBufferStr(query,
16844 : : "SELECT at.attname, "
16845 : : "at.attacl, "
16846 : : "'{}' AS acldefault, "
16847 : : "pip.privtype, pip.initprivs "
16848 : : "FROM pg_catalog.pg_attribute at "
16849 : : "LEFT JOIN pg_catalog.pg_init_privs pip ON "
16850 : : "(at.attrelid = pip.objoid "
16851 : : "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
16852 : : "AND at.attnum = pip.objsubid) "
16853 : : "WHERE at.attrelid = $1 AND "
16854 : : "NOT at.attisdropped "
16855 : : "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
16856 : : "ORDER BY at.attnum");
16857 : : }
16858 : : else
16859 : : {
1370 tgl@sss.pgh.pa.us 16860 :UBC 0 : appendPQExpBufferStr(query,
16861 : : "SELECT attname, attacl, '{}' AS acldefault, "
16862 : : "NULL AS privtype, NULL AS initprivs "
16863 : : "FROM pg_catalog.pg_attribute "
16864 : : "WHERE attrelid = $1 AND NOT attisdropped "
16865 : : "AND attacl IS NOT NULL "
16866 : : "ORDER BY attnum");
16867 : : }
16868 : :
1370 tgl@sss.pgh.pa.us 16869 :CBC 159 : ExecuteSqlStatement(fout, query->data);
16870 : :
16871 : 159 : fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
16872 : : }
16873 : :
16874 : 298 : printfPQExpBuffer(query,
16875 : : "EXECUTE getColumnACLs('%u')",
16876 : 298 : tbinfo->dobj.catId.oid);
16877 : :
3440 sfrost@snowman.net 16878 : 298 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16879 : :
16880 [ + + ]: 4657 : for (i = 0; i < PQntuples(res); i++)
16881 : : {
16882 : 4359 : char *attname = PQgetvalue(res, i, 0);
16883 : 4359 : char *attacl = PQgetvalue(res, i, 1);
1370 tgl@sss.pgh.pa.us 16884 : 4359 : char *acldefault = PQgetvalue(res, i, 2);
16885 : 4359 : char privtype = *(PQgetvalue(res, i, 3));
16886 : 4359 : char *initprivs = PQgetvalue(res, i, 4);
16887 : : DumpableAcl coldacl;
16888 : : char *attnamecopy;
16889 : :
16890 : 4359 : coldacl.acl = attacl;
16891 : 4359 : coldacl.acldefault = acldefault;
16892 : 4359 : coldacl.privtype = privtype;
16893 : 4359 : coldacl.initprivs = initprivs;
3440 sfrost@snowman.net 16894 : 4359 : attnamecopy = pg_strdup(fmtId(attname));
16895 : :
16896 : : /*
16897 : : * Column's GRANT type is always TABLE. Each column ACL depends
16898 : : * on the table-level ACL, since we can restore column ACLs in
16899 : : * parallel but the table-level ACL has to be done first.
16900 : : */
1883 tgl@sss.pgh.pa.us 16901 : 4359 : dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
16902 : : "TABLE", namecopy, attnamecopy,
523 16903 : 4359 : tbinfo->dobj.namespace->dobj.name,
16904 : 4359 : NULL, tbinfo->rolname, &coldacl);
3440 sfrost@snowman.net 16905 : 4359 : free(attnamecopy);
16906 : : }
16907 : 298 : PQclear(res);
16908 : 298 : destroyPQExpBuffer(query);
16909 : : }
16910 : :
16911 : 29617 : free(namecopy);
16912 : : }
16913 : :
16914 : : /*
16915 : : * Create the AS clause for a view or materialized view. The semicolon is
16916 : : * stripped because a materialized view must add a WITH NO DATA clause.
16917 : : *
16918 : : * This returns a new buffer which must be freed by the caller.
16919 : : */
16920 : : static PQExpBuffer
1669 peter@eisentraut.org 16921 : 956 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
16922 : : {
4570 kgrittn@postgresql.o 16923 : 956 : PQExpBuffer query = createPQExpBuffer();
16924 : 956 : PQExpBuffer result = createPQExpBuffer();
16925 : : PGresult *res;
16926 : : int len;
16927 : :
16928 : : /* Fetch the view definition */
3251 tgl@sss.pgh.pa.us 16929 : 956 : appendPQExpBuffer(query,
16930 : : "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
16931 : 956 : tbinfo->dobj.catId.oid);
16932 : :
4570 kgrittn@postgresql.o 16933 : 956 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16934 : :
16935 [ - + ]: 956 : if (PQntuples(res) != 1)
16936 : : {
4570 kgrittn@postgresql.o 16937 [ # # ]:UBC 0 : if (PQntuples(res) < 1)
1247 tgl@sss.pgh.pa.us 16938 : 0 : pg_fatal("query to obtain definition of view \"%s\" returned no data",
16939 : : tbinfo->dobj.name);
16940 : : else
16941 : 0 : pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
16942 : : tbinfo->dobj.name);
16943 : : }
16944 : :
4570 kgrittn@postgresql.o 16945 :CBC 956 : len = PQgetlength(res, 0, 0);
16946 : :
16947 [ - + ]: 956 : if (len == 0)
1247 tgl@sss.pgh.pa.us 16948 :UBC 0 : pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
16949 : : tbinfo->dobj.name);
16950 : :
16951 : : /* Strip off the trailing semicolon so that other things may follow. */
4549 andrew@dunslane.net 16952 [ - + ]:CBC 956 : Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
4570 kgrittn@postgresql.o 16953 : 956 : appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
16954 : :
16955 : 956 : PQclear(res);
16956 : 956 : destroyPQExpBuffer(query);
16957 : :
16958 : 956 : return result;
16959 : : }
16960 : :
16961 : : /*
16962 : : * Create a dummy AS clause for a view. This is used when the real view
16963 : : * definition has to be postponed because of circular dependencies.
16964 : : * We must duplicate the view's external properties -- column names and types
16965 : : * (including collation) -- so that it works for subsequent references.
16966 : : *
16967 : : * This returns a new buffer which must be freed by the caller.
16968 : : */
16969 : : static PQExpBuffer
1669 peter@eisentraut.org 16970 : 20 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
16971 : : {
3215 tgl@sss.pgh.pa.us 16972 : 20 : PQExpBuffer result = createPQExpBuffer();
16973 : : int j;
16974 : :
16975 : 20 : appendPQExpBufferStr(result, "SELECT");
16976 : :
16977 [ + + ]: 40 : for (j = 0; j < tbinfo->numatts; j++)
16978 : : {
16979 [ + + ]: 20 : if (j > 0)
16980 : 10 : appendPQExpBufferChar(result, ',');
16981 : 20 : appendPQExpBufferStr(result, "\n ");
16982 : :
16983 : 20 : appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
16984 : :
16985 : : /*
16986 : : * Must add collation if not default for the type, because CREATE OR
16987 : : * REPLACE VIEW won't change it
16988 : : */
16989 [ - + ]: 20 : if (OidIsValid(tbinfo->attcollation[j]))
16990 : : {
16991 : : CollInfo *coll;
16992 : :
3215 tgl@sss.pgh.pa.us 16993 :UBC 0 : coll = findCollationByOid(tbinfo->attcollation[j]);
16994 [ # # ]: 0 : if (coll)
2749 16995 : 0 : appendPQExpBuffer(result, " COLLATE %s",
16996 : 0 : fmtQualifiedDumpable(coll));
16997 : : }
16998 : :
3215 tgl@sss.pgh.pa.us 16999 :CBC 20 : appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
17000 : : }
17001 : :
17002 : 20 : return result;
17003 : : }
17004 : :
17005 : : /*
17006 : : * dumpTableSchema
17007 : : * write the declaration (not data) of one user-defined table or view
17008 : : */
17009 : : static void
1669 peter@eisentraut.org 17010 : 6596 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
17011 : : {
3524 tgl@sss.pgh.pa.us 17012 : 6596 : DumpOptions *dopt = fout->dopt;
9278 bruce@momjian.us 17013 : 6596 : PQExpBuffer q = createPQExpBuffer();
9195 17014 : 6596 : PQExpBuffer delq = createPQExpBuffer();
404 tgl@sss.pgh.pa.us 17015 : 6596 : PQExpBuffer extra = createPQExpBuffer();
17016 : : char *qrelname;
17017 : : char *qualrelname;
17018 : : int numParents;
17019 : : TableInfo **parents;
17020 : : int actual_atts; /* number of attrs in this CREATE statement */
17021 : : const char *reltypename;
17022 : : char *storage;
17023 : : int j,
17024 : : k;
17025 : :
17026 : : /* We had better have loaded per-column details about this table */
1795 17027 [ - + ]: 6596 : Assert(tbinfo->interesting);
17028 : :
2749 17029 : 6596 : qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
17030 : 6596 : qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
17031 : :
2482 andres@anarazel.de 17032 [ - + ]: 6596 : if (tbinfo->hasoids)
2350 peter@eisentraut.org 17033 :UBC 0 : pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
17034 : : qrelname);
17035 : :
3980 alvherre@alvh.no-ip. 17036 [ + + ]:CBC 6596 : if (dopt->binary_upgrade)
1370 tgl@sss.pgh.pa.us 17037 : 868 : binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
17038 : :
17039 : : /* Is it a table or a view? */
8520 17040 [ + + ]: 6596 : if (tbinfo->relkind == RELKIND_VIEW)
17041 : : {
17042 : : PQExpBuffer result;
17043 : :
17044 : : /*
17045 : : * Note: keep this code in sync with the is_view case in dumpRule()
17046 : : */
17047 : :
17048 : 536 : reltypename = "VIEW";
17049 : :
2749 17050 : 536 : appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
17051 : :
3980 alvherre@alvh.no-ip. 17052 [ + + ]: 536 : if (dopt->binary_upgrade)
4960 rhaas@postgresql.org 17053 : 52 : binary_upgrade_set_pg_class_oids(fout, q,
430 nathan@postgresql.or 17054 : 52 : tbinfo->dobj.catId.oid);
17055 : :
2749 tgl@sss.pgh.pa.us 17056 : 536 : appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
17057 : :
3215 17058 [ + + ]: 536 : if (tbinfo->dummy_view)
17059 : 10 : result = createDummyViewAsClause(fout, tbinfo);
17060 : : else
17061 : : {
17062 [ + + ]: 526 : if (nonemptyReloptions(tbinfo->reloptions))
17063 : : {
17064 : 67 : appendPQExpBufferStr(q, " WITH (");
17065 : 67 : appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
17066 : 67 : appendPQExpBufferChar(q, ')');
17067 : : }
17068 : 526 : result = createViewAsClause(fout, tbinfo);
17069 : : }
4433 sfrost@snowman.net 17070 : 536 : appendPQExpBuffer(q, " AS\n%s", result->data);
4570 kgrittn@postgresql.o 17071 : 536 : destroyPQExpBuffer(result);
17072 : :
3215 tgl@sss.pgh.pa.us 17073 [ + + + - ]: 536 : if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
4433 sfrost@snowman.net 17074 : 38 : appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
4310 heikki.linnakangas@i 17075 : 536 : appendPQExpBufferStr(q, ";\n");
17076 : : }
17077 : : else
17078 : : {
1370 tgl@sss.pgh.pa.us 17079 : 6060 : char *partkeydef = NULL;
2466 sfrost@snowman.net 17080 : 6060 : char *ftoptions = NULL;
17081 : 6060 : char *srvname = NULL;
404 tgl@sss.pgh.pa.us 17082 : 6060 : const char *foreign = "";
17083 : :
17084 : : /*
17085 : : * Set reltypename, and collect any relkind-specific data that we
17086 : : * didn't fetch during getTables().
17087 : : */
4570 kgrittn@postgresql.o 17088 [ + + + + ]: 6060 : switch (tbinfo->relkind)
17089 : : {
1370 tgl@sss.pgh.pa.us 17090 : 590 : case RELKIND_PARTITIONED_TABLE:
17091 : : {
17092 : 590 : PQExpBuffer query = createPQExpBuffer();
17093 : : PGresult *res;
17094 : :
17095 : 590 : reltypename = "TABLE";
17096 : :
17097 : : /* retrieve partition key definition */
17098 : 590 : appendPQExpBuffer(query,
17099 : : "SELECT pg_get_partkeydef('%u')",
17100 : 590 : tbinfo->dobj.catId.oid);
17101 : 590 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
17102 : 590 : partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
17103 : 590 : PQclear(res);
17104 : 590 : destroyPQExpBuffer(query);
17105 : 590 : break;
17106 : : }
3103 17107 : 40 : case RELKIND_FOREIGN_TABLE:
17108 : : {
4549 andrew@dunslane.net 17109 : 40 : PQExpBuffer query = createPQExpBuffer();
17110 : : PGresult *res;
17111 : : int i_srvname;
17112 : : int i_ftoptions;
17113 : :
17114 : 40 : reltypename = "FOREIGN TABLE";
17115 : :
17116 : : /* retrieve name of foreign server and generic options */
17117 : 40 : appendPQExpBuffer(query,
17118 : : "SELECT fs.srvname, "
17119 : : "pg_catalog.array_to_string(ARRAY("
17120 : : "SELECT pg_catalog.quote_ident(option_name) || "
17121 : : "' ' || pg_catalog.quote_literal(option_value) "
17122 : : "FROM pg_catalog.pg_options_to_table(ftoptions) "
17123 : : "ORDER BY option_name"
17124 : : "), E',\n ') AS ftoptions "
17125 : : "FROM pg_catalog.pg_foreign_table ft "
17126 : : "JOIN pg_catalog.pg_foreign_server fs "
17127 : : "ON (fs.oid = ft.ftserver) "
17128 : : "WHERE ft.ftrelid = '%u'",
17129 : 40 : tbinfo->dobj.catId.oid);
17130 : 40 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
17131 : 40 : i_srvname = PQfnumber(res, "srvname");
17132 : 40 : i_ftoptions = PQfnumber(res, "ftoptions");
17133 : 40 : srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
17134 : 40 : ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
17135 : 40 : PQclear(res);
17136 : 40 : destroyPQExpBuffer(query);
17137 : :
1996 alvherre@alvh.no-ip. 17138 : 40 : foreign = "FOREIGN ";
4549 andrew@dunslane.net 17139 : 40 : break;
17140 : : }
3103 tgl@sss.pgh.pa.us 17141 : 420 : case RELKIND_MATVIEW:
4570 kgrittn@postgresql.o 17142 : 420 : reltypename = "MATERIALIZED VIEW";
17143 : 420 : break;
17144 : 5010 : default:
17145 : 5010 : reltypename = "TABLE";
1370 tgl@sss.pgh.pa.us 17146 : 5010 : break;
17147 : : }
17148 : :
8520 17149 : 6060 : numParents = tbinfo->numParents;
7945 17150 : 6060 : parents = tbinfo->parents;
17151 : :
2749 17152 : 6060 : appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
17153 : :
3980 alvherre@alvh.no-ip. 17154 [ + + ]: 6060 : if (dopt->binary_upgrade)
4960 rhaas@postgresql.org 17155 : 816 : binary_upgrade_set_pg_class_oids(fout, q,
430 nathan@postgresql.or 17156 : 816 : tbinfo->dobj.catId.oid);
17157 : :
17158 : : /*
17159 : : * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
17160 : : * ignore it when dumping if it was set in this case.
17161 : : */
5362 rhaas@postgresql.org 17162 : 6060 : appendPQExpBuffer(q, "CREATE %s%s %s",
338 michael@paquier.xyz 17163 [ + + ]: 6060 : (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
17164 [ + - ]: 20 : tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
17165 : : "UNLOGGED " : "",
17166 : : reltypename,
17167 : : qualrelname);
17168 : :
17169 : : /*
17170 : : * Attach to type, if reloftype; except in case of a binary upgrade,
17171 : : * we dump the table normally and attach it to the type afterward.
17172 : : */
1370 tgl@sss.pgh.pa.us 17173 [ + + + + ]: 6060 : if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
17174 : 24 : appendPQExpBuffer(q, " OF %s",
17175 : 24 : getFormattedTypeName(fout, tbinfo->reloftype,
17176 : : zeroIsError));
17177 : :
4570 kgrittn@postgresql.o 17178 [ + + ]: 6060 : if (tbinfo->relkind != RELKIND_MATVIEW)
17179 : : {
17180 : : /* Dump the attributes */
4549 andrew@dunslane.net 17181 : 5640 : actual_atts = 0;
17182 [ + + ]: 25985 : for (j = 0; j < tbinfo->numatts; j++)
17183 : : {
17184 : : /*
17185 : : * Normally, dump if it's locally defined in this table, and
17186 : : * not dropped. But for binary upgrade, we'll dump all the
17187 : : * columns, and then fix up the dropped and nonlocal cases
17188 : : * below.
17189 : : */
3980 alvherre@alvh.no-ip. 17190 [ + + ]: 20345 : if (shouldPrintColumn(dopt, tbinfo, j))
17191 : : {
17192 : : bool print_default;
17193 : : bool print_notnull;
17194 : :
17195 : : /*
17196 : : * Default value --- suppress if to be printed separately
17197 : : * or not at all.
17198 : : */
2280 17199 : 39751 : print_default = (tbinfo->attrdefs[j] != NULL &&
921 tgl@sss.pgh.pa.us 17200 [ + + + + ]: 20380 : tbinfo->attrdefs[j]->dobj.dump &&
2280 alvherre@alvh.no-ip. 17201 [ + + ]: 1062 : !tbinfo->attrdefs[j]->separate);
17202 : :
17203 : : /*
17204 : : * Not Null constraint --- print it if it is locally
17205 : : * defined, or if binary upgrade. (In the latter case, we
17206 : : * reset conislocal below.)
17207 : : */
302 17208 [ + + ]: 21664 : print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
17209 [ + + ]: 2346 : (tbinfo->notnull_islocal[j] ||
17210 [ + + ]: 661 : dopt->binary_upgrade ||
17211 [ + + ]: 577 : tbinfo->ispartition));
17212 : :
17213 : : /*
17214 : : * Skip column if fully defined by reloftype, except in
17215 : : * binary upgrade
17216 : : */
1370 tgl@sss.pgh.pa.us 17217 [ + + ]: 19318 : if (OidIsValid(tbinfo->reloftype) &&
17218 [ + + + + ]: 50 : !print_default && !print_notnull &&
2280 alvherre@alvh.no-ip. 17219 [ + + ]: 30 : !dopt->binary_upgrade)
4549 andrew@dunslane.net 17220 : 24 : continue;
17221 : :
17222 : : /* Format properly if not first attr */
17223 [ + + ]: 19294 : if (actual_atts == 0)
4310 heikki.linnakangas@i 17224 : 5282 : appendPQExpBufferStr(q, " (");
17225 : : else
3719 17226 : 14012 : appendPQExpBufferChar(q, ',');
4310 17227 : 19294 : appendPQExpBufferStr(q, "\n ");
4549 andrew@dunslane.net 17228 : 19294 : actual_atts++;
17229 : :
17230 : : /* Attribute name */
4310 heikki.linnakangas@i 17231 : 19294 : appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
17232 : :
4549 andrew@dunslane.net 17233 [ + + ]: 19294 : if (tbinfo->attisdropped[j])
17234 : : {
17235 : : /*
17236 : : * ALTER TABLE DROP COLUMN clears
17237 : : * pg_attribute.atttypid, so we will not have gotten a
17238 : : * valid type name; insert INTEGER as a stopgap. We'll
17239 : : * clean things up later.
17240 : : */
4310 heikki.linnakangas@i 17241 : 84 : appendPQExpBufferStr(q, " INTEGER /* dummy */");
17242 : : /* and skip to the next column */
4549 andrew@dunslane.net 17243 : 84 : continue;
17244 : : }
17245 : :
17246 : : /*
17247 : : * Attribute type; print it except when creating a typed
17248 : : * table ('OF type_name'), but in binary-upgrade mode,
17249 : : * print it in that case too.
17250 : : */
1370 tgl@sss.pgh.pa.us 17251 [ + + + + ]: 19210 : if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
17252 : : {
4549 andrew@dunslane.net 17253 : 19194 : appendPQExpBuffer(q, " %s",
3251 tgl@sss.pgh.pa.us 17254 : 19194 : tbinfo->atttypnames[j]);
17255 : : }
17256 : :
2280 alvherre@alvh.no-ip. 17257 [ + + ]: 19210 : if (print_default)
17258 : : {
2352 peter@eisentraut.org 17259 [ + + ]: 920 : if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
17260 : 295 : appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
17261 : 295 : tbinfo->attrdefs[j]->adef_expr);
211 17262 [ + + ]: 625 : else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
17263 : 229 : appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
17264 : 229 : tbinfo->attrdefs[j]->adef_expr);
17265 : : else
2352 17266 : 396 : appendPQExpBuffer(q, " DEFAULT %s",
17267 : 396 : tbinfo->attrdefs[j]->adef_expr);
17268 : : }
17269 : :
2280 alvherre@alvh.no-ip. 17270 [ + + ]: 19210 : if (print_notnull)
17271 : : {
302 17272 [ + + ]: 2309 : if (tbinfo->notnull_constrs[j][0] == '\0')
17273 : 1621 : appendPQExpBufferStr(q, " NOT NULL");
17274 : : else
17275 : 688 : appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
17276 : 688 : fmtId(tbinfo->notnull_constrs[j]));
17277 : :
17278 [ - + ]: 2309 : if (tbinfo->notnull_noinh[j])
302 alvherre@alvh.no-ip. 17279 :UBC 0 : appendPQExpBufferStr(q, " NO INHERIT");
17280 : : }
17281 : :
17282 : : /* Add collation if not default for the type */
4549 andrew@dunslane.net 17283 [ + + ]:CBC 19210 : if (OidIsValid(tbinfo->attcollation[j]))
17284 : : {
17285 : : CollInfo *coll;
17286 : :
17287 : 197 : coll = findCollationByOid(tbinfo->attcollation[j]);
17288 [ + - ]: 197 : if (coll)
2749 tgl@sss.pgh.pa.us 17289 : 197 : appendPQExpBuffer(q, " COLLATE %s",
17290 : 197 : fmtQualifiedDumpable(coll));
17291 : : }
17292 : : }
17293 : :
17294 : : /*
17295 : : * On the other hand, if we choose not to print a column
17296 : : * (likely because it is created by inheritance), but the
17297 : : * column has a locally-defined not-null constraint, we need
17298 : : * to dump the constraint as a standalone object.
17299 : : *
17300 : : * This syntax isn't SQL-conforming, but if you wanted
17301 : : * standard output you wouldn't be creating non-standard
17302 : : * objects to begin with.
17303 : : */
267 alvherre@alvh.no-ip. 17304 [ + + ]: 20237 : if (!shouldPrintColumn(dopt, tbinfo, j) &&
17305 [ + + ]: 1027 : !tbinfo->attisdropped[j] &&
17306 [ + + ]: 658 : tbinfo->notnull_constrs[j] != NULL &&
17307 [ + + ]: 191 : tbinfo->notnull_islocal[j])
17308 : : {
17309 : : /* Format properly if not first attr */
17310 [ + + ]: 61 : if (actual_atts == 0)
17311 : 57 : appendPQExpBufferStr(q, " (");
17312 : : else
17313 : 4 : appendPQExpBufferChar(q, ',');
17314 : 61 : appendPQExpBufferStr(q, "\n ");
17315 : 61 : actual_atts++;
17316 : :
17317 [ + + ]: 61 : if (tbinfo->notnull_constrs[j][0] == '\0')
17318 : 4 : appendPQExpBuffer(q, "NOT NULL %s",
17319 : 4 : fmtId(tbinfo->attnames[j]));
17320 : : else
17321 : 114 : appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
17322 : 57 : tbinfo->notnull_constrs[j],
17323 : 57 : fmtId(tbinfo->attnames[j]));
17324 : : }
17325 : : }
17326 : :
17327 : : /*
17328 : : * Add non-inherited CHECK constraints, if any.
17329 : : *
17330 : : * For partitions, we need to include check constraints even if
17331 : : * they're not defined locally, because the ALTER TABLE ATTACH
17332 : : * PARTITION that we'll emit later expects the constraint to be
17333 : : * there. (No need to fix conislocal: ATTACH PARTITION does that)
17334 : : */
4549 andrew@dunslane.net 17335 [ + + ]: 6283 : for (j = 0; j < tbinfo->ncheck; j++)
17336 : : {
17337 : 643 : ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
17338 : :
2280 alvherre@alvh.no-ip. 17339 [ + + ]: 643 : if (constr->separate ||
17340 [ + + + + ]: 573 : (!constr->conislocal && !tbinfo->ispartition))
4549 andrew@dunslane.net 17341 : 113 : continue;
17342 : :
17343 [ + + ]: 530 : if (actual_atts == 0)
4310 heikki.linnakangas@i 17344 : 16 : appendPQExpBufferStr(q, " (\n ");
17345 : : else
17346 : 514 : appendPQExpBufferStr(q, ",\n ");
17347 : :
4549 andrew@dunslane.net 17348 : 530 : appendPQExpBuffer(q, "CONSTRAINT %s ",
17349 : 530 : fmtId(constr->dobj.name));
4310 heikki.linnakangas@i 17350 : 530 : appendPQExpBufferStr(q, constr->condef);
17351 : :
4549 andrew@dunslane.net 17352 : 530 : actual_atts++;
17353 : : }
17354 : :
17355 [ + + ]: 5640 : if (actual_atts)
4310 heikki.linnakangas@i 17356 : 5355 : appendPQExpBufferStr(q, "\n)");
1370 tgl@sss.pgh.pa.us 17357 [ + + - + ]: 285 : else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
17358 : : {
17359 : : /*
17360 : : * No attributes? we must have a parenthesized attribute list,
17361 : : * even though empty, when not using the OF TYPE syntax.
17362 : : */
4310 heikki.linnakangas@i 17363 : 273 : appendPQExpBufferStr(q, " (\n)");
17364 : : }
17365 : :
17366 : : /*
17367 : : * Emit the INHERITS clause (not for partitions), except in
17368 : : * binary-upgrade mode.
17369 : : */
2280 alvherre@alvh.no-ip. 17370 [ + + + + ]: 5640 : if (numParents > 0 && !tbinfo->ispartition &&
3047 sfrost@snowman.net 17371 [ + + ]: 520 : !dopt->binary_upgrade)
17372 : : {
4310 heikki.linnakangas@i 17373 : 457 : appendPQExpBufferStr(q, "\nINHERITS (");
4549 andrew@dunslane.net 17374 [ + + ]: 991 : for (k = 0; k < numParents; k++)
17375 : : {
17376 : 534 : TableInfo *parentRel = parents[k];
17377 : :
17378 [ + + ]: 534 : if (k > 0)
4310 heikki.linnakangas@i 17379 : 77 : appendPQExpBufferStr(q, ", ");
2749 tgl@sss.pgh.pa.us 17380 : 534 : appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
17381 : : }
4310 heikki.linnakangas@i 17382 : 457 : appendPQExpBufferChar(q, ')');
17383 : : }
17384 : :
3195 rhaas@postgresql.org 17385 [ + + ]: 5640 : if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
1370 tgl@sss.pgh.pa.us 17386 : 590 : appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
17387 : :
4549 andrew@dunslane.net 17388 [ + + ]: 5640 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
17389 : 40 : appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
17390 : : }
17391 : :
3535 tgl@sss.pgh.pa.us 17392 [ + + - + ]: 11972 : if (nonemptyReloptions(tbinfo->reloptions) ||
17393 : 5912 : nonemptyReloptions(tbinfo->toast_reloptions))
17394 : : {
5931 bruce@momjian.us 17395 : 148 : bool addcomma = false;
17396 : :
4310 heikki.linnakangas@i 17397 : 148 : appendPQExpBufferStr(q, "\nWITH (");
3535 tgl@sss.pgh.pa.us 17398 [ + - ]: 148 : if (nonemptyReloptions(tbinfo->reloptions))
17399 : : {
6060 alvherre@alvh.no-ip. 17400 : 148 : addcomma = true;
3410 dean.a.rasheed@gmail 17401 : 148 : appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
17402 : : }
3535 tgl@sss.pgh.pa.us 17403 [ + + ]: 148 : if (nonemptyReloptions(tbinfo->toast_reloptions))
17404 : : {
17405 [ + - ]: 5 : if (addcomma)
17406 : 5 : appendPQExpBufferStr(q, ", ");
3410 dean.a.rasheed@gmail 17407 : 5 : appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
17408 : : fout);
17409 : : }
4310 heikki.linnakangas@i 17410 : 148 : appendPQExpBufferChar(q, ')');
17411 : : }
17412 : :
17413 : : /* Dump generic options if any */
5362 rhaas@postgresql.org 17414 [ + + + + ]: 6060 : if (ftoptions && ftoptions[0])
4993 peter_e@gmx.net 17415 : 38 : appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
17416 : :
17417 : : /*
17418 : : * For materialized views, create the AS clause just like a view. At
17419 : : * this point, we always mark the view as not populated.
17420 : : */
4570 kgrittn@postgresql.o 17421 [ + + ]: 6060 : if (tbinfo->relkind == RELKIND_MATVIEW)
17422 : : {
17423 : : PQExpBuffer result;
17424 : :
17425 : 420 : result = createViewAsClause(fout, tbinfo);
17426 : 420 : appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
17427 : : result->data);
17428 : 420 : destroyPQExpBuffer(result);
17429 : : }
17430 : : else
4310 heikki.linnakangas@i 17431 : 5640 : appendPQExpBufferStr(q, ";\n");
17432 : :
17433 : : /* Materialized views can depend on extensions */
2005 alvherre@alvh.no-ip. 17434 [ + + ]: 6060 : if (tbinfo->relkind == RELKIND_MATVIEW)
17435 : 420 : append_depends_on_extension(fout, q, &tbinfo->dobj,
17436 : : "pg_catalog.pg_class",
17437 : : "MATERIALIZED VIEW",
17438 : : qualrelname);
17439 : :
17440 : : /*
17441 : : * in binary upgrade mode, update the catalog with any missing values
17442 : : * that might be present.
17443 : : */
2633 andrew@dunslane.net 17444 [ + + ]: 6060 : if (dopt->binary_upgrade)
17445 : : {
17446 [ + + ]: 3952 : for (j = 0; j < tbinfo->numatts; j++)
17447 : : {
17448 [ + + ]: 3136 : if (tbinfo->attmissingval[j][0] != '\0')
17449 : : {
17450 : 2 : appendPQExpBufferStr(q, "\n-- set missing value.\n");
17451 : 2 : appendPQExpBufferStr(q,
17452 : : "SELECT pg_catalog.binary_upgrade_set_missing_value(");
17453 : 2 : appendStringLiteralAH(q, qualrelname, fout);
17454 : 2 : appendPQExpBufferStr(q, "::pg_catalog.regclass,");
17455 : 2 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
1096 drowley@postgresql.o 17456 : 2 : appendPQExpBufferChar(q, ',');
2633 andrew@dunslane.net 17457 : 2 : appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
17458 : 2 : appendPQExpBufferStr(q, ");\n\n");
17459 : : }
17460 : : }
17461 : : }
17462 : :
17463 : : /*
17464 : : * To create binary-compatible heap files, we have to ensure the same
17465 : : * physical column order, including dropped columns, as in the
17466 : : * original. Therefore, we create dropped columns above and drop them
17467 : : * here, also updating their attlen/attalign values so that the
17468 : : * dropped column can be skipped properly. (We do not bother with
17469 : : * restoring the original attbyval setting.) Also, inheritance
17470 : : * relationships are set up by doing ALTER TABLE INHERIT rather than
17471 : : * using an INHERITS clause --- the latter would possibly mess up the
17472 : : * column order. That also means we have to take care about setting
17473 : : * attislocal correctly, plus fix up any inherited CHECK constraints.
17474 : : * Analogously, we set up typed tables using ALTER TABLE / OF here.
17475 : : *
17476 : : * We process foreign and partitioned tables here, even though they
17477 : : * lack heap storage, because they can participate in inheritance
17478 : : * relationships and we want this stuff to be consistent across the
17479 : : * inheritance tree. We can exclude indexes, toast tables, sequences
17480 : : * and matviews, even though they have storage, because we don't
17481 : : * support altering or dropping columns in them, nor can they be part
17482 : : * of inheritance trees.
17483 : : */
3821 tgl@sss.pgh.pa.us 17484 [ + + ]: 6060 : if (dopt->binary_upgrade &&
17485 [ + + ]: 816 : (tbinfo->relkind == RELKIND_RELATION ||
3195 rhaas@postgresql.org 17486 [ + + ]: 110 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
17487 [ + + ]: 109 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
17488 : : {
17489 : : bool firstitem;
17490 : : bool firstitem_extra;
17491 : :
17492 : : /*
17493 : : * Drop any dropped columns. Merge the pg_attribute manipulations
17494 : : * into a single SQL command, so that we don't cause repeated
17495 : : * relcache flushes on the target table. Otherwise we risk O(N^2)
17496 : : * relcache bloat while dropping N columns.
17497 : : */
404 tgl@sss.pgh.pa.us 17498 : 798 : resetPQExpBuffer(extra);
17499 : 798 : firstitem = true;
6045 bruce@momjian.us 17500 [ + + ]: 3912 : for (j = 0; j < tbinfo->numatts; j++)
17501 : : {
17502 [ + + ]: 3114 : if (tbinfo->attisdropped[j])
17503 : : {
404 tgl@sss.pgh.pa.us 17504 [ + + ]: 84 : if (firstitem)
17505 : : {
17506 : 38 : appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
17507 : : "UPDATE pg_catalog.pg_attribute\n"
17508 : : "SET attlen = v.dlen, "
17509 : : "attalign = v.dalign, "
17510 : : "attbyval = false\n"
17511 : : "FROM (VALUES ");
17512 : 38 : firstitem = false;
17513 : : }
17514 : : else
17515 : 46 : appendPQExpBufferStr(q, ",\n ");
17516 : 84 : appendPQExpBufferChar(q, '(');
17517 : 84 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17518 : 84 : appendPQExpBuffer(q, ", %d, '%c')",
5910 17519 : 84 : tbinfo->attlen[j],
17520 : 84 : tbinfo->attalign[j]);
17521 : : /* The ALTER ... DROP COLUMN commands must come after */
404 17522 : 84 : appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
17523 : : foreign, qualrelname);
17524 : 84 : appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
6045 bruce@momjian.us 17525 : 84 : fmtId(tbinfo->attnames[j]));
17526 : : }
17527 : : }
404 tgl@sss.pgh.pa.us 17528 [ + + ]: 798 : if (!firstitem)
17529 : : {
17530 : 38 : appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
17531 : : "WHERE attrelid = ");
17532 : 38 : appendStringLiteralAH(q, qualrelname, fout);
17533 : 38 : appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
17534 : : " AND attname = v.dname;\n");
17535 : : /* Now we can issue the actual DROP COLUMN commands */
17536 : 38 : appendBinaryPQExpBuffer(q, extra->data, extra->len);
17537 : : }
17538 : :
17539 : : /*
17540 : : * Fix up inherited columns. As above, do the pg_attribute
17541 : : * manipulations in a single SQL command.
17542 : : */
17543 : 798 : firstitem = true;
17544 [ + + ]: 3912 : for (j = 0; j < tbinfo->numatts; j++)
17545 : : {
17546 [ + + ]: 3114 : if (!tbinfo->attisdropped[j] &&
17547 [ + + ]: 3030 : !tbinfo->attislocal[j])
17548 : : {
17549 [ + + ]: 603 : if (firstitem)
17550 : : {
17551 : 266 : appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
17552 : 266 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
17553 : : "SET attislocal = false\n"
17554 : : "WHERE attrelid = ");
17555 : 266 : appendStringLiteralAH(q, qualrelname, fout);
17556 : 266 : appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
17557 : : " AND attname IN (");
17558 : 266 : firstitem = false;
17559 : : }
17560 : : else
17561 : 337 : appendPQExpBufferStr(q, ", ");
5910 17562 : 603 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17563 : : }
17564 : : }
404 17565 [ + + ]: 798 : if (!firstitem)
17566 : 266 : appendPQExpBufferStr(q, ");\n");
17567 : :
17568 : : /*
17569 : : * Fix up not-null constraints that come from inheritance. As
17570 : : * above, do the pg_constraint manipulations in a single SQL
17571 : : * command. (Actually, two in special cases, if we're doing an
17572 : : * upgrade from < 18).
17573 : : */
302 alvherre@alvh.no-ip. 17574 : 798 : firstitem = true;
17575 : 798 : firstitem_extra = true;
17576 : 798 : resetPQExpBuffer(extra);
17577 [ + + ]: 3912 : for (j = 0; j < tbinfo->numatts; j++)
17578 : : {
17579 : : /*
17580 : : * If a not-null constraint comes from inheritance, reset
17581 : : * conislocal. The inhcount is fixed by ALTER TABLE INHERIT,
17582 : : * below. Special hack: in versions < 18, columns with no
17583 : : * local definition need their constraint to be matched by
17584 : : * column number in conkeys instead of by constraint name,
17585 : : * because the latter is not available. (We distinguish the
17586 : : * case because the constraint name is the empty string.)
17587 : : */
17588 [ + + ]: 3114 : if (tbinfo->notnull_constrs[j] != NULL &&
17589 [ + + ]: 290 : !tbinfo->notnull_islocal[j])
17590 : : {
17591 [ + + ]: 84 : if (tbinfo->notnull_constrs[j][0] != '\0')
17592 : : {
17593 [ + + ]: 71 : if (firstitem)
17594 : : {
17595 : 61 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
17596 : : "SET conislocal = false\n"
17597 : : "WHERE contype = 'n' AND conrelid = ");
17598 : 61 : appendStringLiteralAH(q, qualrelname, fout);
17599 : 61 : appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
17600 : : "conname IN (");
17601 : 61 : firstitem = false;
17602 : : }
17603 : : else
17604 : 10 : appendPQExpBufferStr(q, ", ");
17605 : 71 : appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
17606 : : }
17607 : : else
17608 : : {
17609 [ + - ]: 13 : if (firstitem_extra)
17610 : : {
17611 : 13 : appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
17612 : : "SET conislocal = false\n"
17613 : : "WHERE contype = 'n' AND conrelid = ");
17614 : 13 : appendStringLiteralAH(extra, qualrelname, fout);
17615 : 13 : appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
17616 : : "conkey IN (");
17617 : 13 : firstitem_extra = false;
17618 : : }
17619 : : else
302 alvherre@alvh.no-ip. 17620 :UBC 0 : appendPQExpBufferStr(extra, ", ");
302 alvherre@alvh.no-ip. 17621 :CBC 13 : appendPQExpBuffer(extra, "'{%d}'", j + 1);
17622 : : }
17623 : : }
17624 : : }
17625 [ + + ]: 798 : if (!firstitem)
17626 : 61 : appendPQExpBufferStr(q, ");\n");
17627 [ + + ]: 798 : if (!firstitem_extra)
17628 : 13 : appendPQExpBufferStr(extra, ");\n");
17629 : :
17630 [ + + ]: 798 : if (extra->len > 0)
17631 : 13 : appendBinaryPQExpBuffer(q, extra->data, extra->len);
17632 : :
17633 : : /*
17634 : : * Add inherited CHECK constraints, if any.
17635 : : *
17636 : : * For partitions, they were already dumped, and conislocal
17637 : : * doesn't need fixing.
17638 : : *
17639 : : * As above, issue only one direct manipulation of pg_constraint.
17640 : : * Although it is tempting to merge the ALTER ADD CONSTRAINT
17641 : : * commands into one as well, refrain for now due to concern about
17642 : : * possible backend memory bloat if there are many such
17643 : : * constraints.
17644 : : */
404 tgl@sss.pgh.pa.us 17645 : 798 : resetPQExpBuffer(extra);
17646 : 798 : firstitem = true;
5910 17647 [ + + ]: 862 : for (k = 0; k < tbinfo->ncheck; k++)
17648 : : {
17649 : 64 : ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
17650 : :
2280 alvherre@alvh.no-ip. 17651 [ + + + + : 64 : if (constr->separate || constr->conislocal || tbinfo->ispartition)
+ + ]
5910 tgl@sss.pgh.pa.us 17652 : 62 : continue;
17653 : :
404 17654 [ + - ]: 2 : if (firstitem)
17655 : 2 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
1996 alvherre@alvh.no-ip. 17656 : 2 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
17657 : : foreign, qualrelname,
17658 : 2 : fmtId(constr->dobj.name),
17659 : : constr->condef);
17660 : : /* Update pg_constraint after all the ALTER TABLEs */
404 tgl@sss.pgh.pa.us 17661 [ + - ]: 2 : if (firstitem)
17662 : : {
17663 : 2 : appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
17664 : : "SET conislocal = false\n"
17665 : : "WHERE contype = 'c' AND conrelid = ");
17666 : 2 : appendStringLiteralAH(extra, qualrelname, fout);
17667 : 2 : appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
17668 : 2 : appendPQExpBufferStr(extra, " AND conname IN (");
17669 : 2 : firstitem = false;
17670 : : }
17671 : : else
404 tgl@sss.pgh.pa.us 17672 :UBC 0 : appendPQExpBufferStr(extra, ", ");
404 tgl@sss.pgh.pa.us 17673 :CBC 2 : appendStringLiteralAH(extra, constr->dobj.name, fout);
17674 : : }
17675 [ + + ]: 798 : if (!firstitem)
17676 : : {
17677 : 2 : appendPQExpBufferStr(extra, ");\n");
17678 : 2 : appendBinaryPQExpBuffer(q, extra->data, extra->len);
17679 : : }
17680 : :
2280 alvherre@alvh.no-ip. 17681 [ + + + + ]: 798 : if (numParents > 0 && !tbinfo->ispartition)
17682 : : {
17683 : 63 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
5910 tgl@sss.pgh.pa.us 17684 [ + + ]: 137 : for (k = 0; k < numParents; k++)
17685 : : {
17686 : 74 : TableInfo *parentRel = parents[k];
17687 : :
1996 alvherre@alvh.no-ip. 17688 : 74 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
17689 : : qualrelname,
2280 17690 : 74 : fmtQualifiedDumpable(parentRel));
17691 : : }
17692 : : }
17693 : :
1370 tgl@sss.pgh.pa.us 17694 [ + + ]: 798 : if (OidIsValid(tbinfo->reloftype))
17695 : : {
4310 heikki.linnakangas@i 17696 : 6 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
5246 peter_e@gmx.net 17697 : 6 : appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
17698 : : qualrelname,
1370 tgl@sss.pgh.pa.us 17699 : 6 : getFormattedTypeName(fout, tbinfo->reloftype,
17700 : : zeroIsError));
17701 : : }
17702 : : }
17703 : :
17704 : : /*
17705 : : * In binary_upgrade mode, arrange to restore the old relfrozenxid and
17706 : : * relminmxid of all vacuumable relations. (While vacuum.c processes
17707 : : * TOAST tables semi-independently, here we see them only as children
17708 : : * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
17709 : : * child toast table is handled below.)
17710 : : */
2754 17711 [ + + ]: 6060 : if (dopt->binary_upgrade &&
17712 [ + + ]: 816 : (tbinfo->relkind == RELKIND_RELATION ||
17713 [ + + ]: 110 : tbinfo->relkind == RELKIND_MATVIEW))
17714 : : {
4084 bruce@momjian.us 17715 : 724 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
5910 tgl@sss.pgh.pa.us 17716 : 724 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
17717 : : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
17718 : : "WHERE oid = ",
4084 bruce@momjian.us 17719 : 724 : tbinfo->frozenxid, tbinfo->minmxid);
2749 tgl@sss.pgh.pa.us 17720 : 724 : appendStringLiteralAH(q, qualrelname, fout);
4310 heikki.linnakangas@i 17721 : 724 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
17722 : :
5265 bruce@momjian.us 17723 [ + + ]: 724 : if (tbinfo->toast_oid)
17724 : : {
17725 : : /*
17726 : : * The toast table will have the same OID at restore, so we
17727 : : * can safely target it by OID.
17728 : : */
4084 17729 : 280 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
5265 17730 : 280 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
17731 : : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
17732 : : "WHERE oid = '%u';\n",
4084 17733 : 280 : tbinfo->toast_frozenxid,
17734 : 280 : tbinfo->toast_minmxid, tbinfo->toast_oid);
17735 : : }
17736 : : }
17737 : :
17738 : : /*
17739 : : * In binary_upgrade mode, restore matviews' populated status by
17740 : : * poking pg_class directly. This is pretty ugly, but we can't use
17741 : : * REFRESH MATERIALIZED VIEW since it's possible that some underlying
17742 : : * matview is not populated even though this matview is; in any case,
17743 : : * we want to transfer the matview's heap storage, not run REFRESH.
17744 : : */
3980 alvherre@alvh.no-ip. 17745 [ + + + + ]: 6060 : if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
4506 tgl@sss.pgh.pa.us 17746 [ + + ]: 18 : tbinfo->relispopulated)
17747 : : {
4310 heikki.linnakangas@i 17748 : 16 : appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
17749 : 16 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
17750 : : "SET relispopulated = 't'\n"
17751 : : "WHERE oid = ");
2749 tgl@sss.pgh.pa.us 17752 : 16 : appendStringLiteralAH(q, qualrelname, fout);
4310 heikki.linnakangas@i 17753 : 16 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
17754 : : }
17755 : :
17756 : : /*
17757 : : * Dump additional per-column properties that we can't handle in the
17758 : : * main CREATE TABLE command.
17759 : : */
8403 bruce@momjian.us 17760 [ + + ]: 26911 : for (j = 0; j < tbinfo->numatts; j++)
17761 : : {
17762 : : /* None of this applies to dropped columns */
4957 tgl@sss.pgh.pa.us 17763 [ + + ]: 20851 : if (tbinfo->attisdropped[j])
17764 : 453 : continue;
17765 : :
17766 : : /*
17767 : : * Dump per-column statistics information. We only issue an ALTER
17768 : : * TABLE statement if the attstattarget entry for this column is
17769 : : * not the default value.
17770 : : */
17771 [ + + ]: 20398 : if (tbinfo->attstattarget[j] >= 0)
1996 alvherre@alvh.no-ip. 17772 : 38 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
17773 : : foreign, qualrelname,
17774 : 38 : fmtId(tbinfo->attnames[j]),
8438 tgl@sss.pgh.pa.us 17775 : 38 : tbinfo->attstattarget[j]);
17776 : :
17777 : : /*
17778 : : * Dump per-column storage information. The statement is only
17779 : : * dumped if the storage has been changed from the type's default.
17780 : : */
4957 17781 [ + + ]: 20398 : if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
17782 : : {
8069 bruce@momjian.us 17783 [ + + - + : 91 : switch (tbinfo->attstorage[j])
- ]
17784 : : {
2012 tgl@sss.pgh.pa.us 17785 : 10 : case TYPSTORAGE_PLAIN:
8206 bruce@momjian.us 17786 : 10 : storage = "PLAIN";
17787 : 10 : break;
2012 tgl@sss.pgh.pa.us 17788 : 43 : case TYPSTORAGE_EXTERNAL:
8206 bruce@momjian.us 17789 : 43 : storage = "EXTERNAL";
17790 : 43 : break;
2012 tgl@sss.pgh.pa.us 17791 :UBC 0 : case TYPSTORAGE_EXTENDED:
8206 bruce@momjian.us 17792 : 0 : storage = "EXTENDED";
17793 : 0 : break;
2012 tgl@sss.pgh.pa.us 17794 :CBC 38 : case TYPSTORAGE_MAIN:
17795 : 38 : storage = "MAIN";
17796 : 38 : break;
8206 bruce@momjian.us 17797 :UBC 0 : default:
17798 : 0 : storage = NULL;
17799 : : }
17800 : :
17801 : : /*
17802 : : * Only dump the statement if it's a storage type we recognize
17803 : : */
8069 bruce@momjian.us 17804 [ + - ]:CBC 91 : if (storage != NULL)
1996 alvherre@alvh.no-ip. 17805 : 91 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
17806 : : foreign, qualrelname,
17807 : 91 : fmtId(tbinfo->attnames[j]),
17808 : : storage);
17809 : : }
17810 : :
17811 : : /*
17812 : : * Dump per-column compression, if it's been set.
17813 : : */
1631 tgl@sss.pgh.pa.us 17814 [ + + ]: 20398 : if (!dopt->no_toast_compression)
17815 : : {
17816 : : const char *cmname;
17817 : :
17818 [ + + + ]: 20300 : switch (tbinfo->attcompression[j])
17819 : : {
17820 : 77 : case 'p':
17821 : 77 : cmname = "pglz";
17822 : 77 : break;
17823 : 99 : case 'l':
17824 : 99 : cmname = "lz4";
17825 : 99 : break;
17826 : 20124 : default:
17827 : 20124 : cmname = NULL;
17828 : 20124 : break;
17829 : : }
17830 : :
1563 17831 [ + + ]: 20300 : if (cmname != NULL)
1631 17832 : 176 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
17833 : : foreign, qualrelname,
17834 : 176 : fmtId(tbinfo->attnames[j]),
17835 : : cmname);
17836 : : }
17837 : :
17838 : : /*
17839 : : * Dump per-column attributes.
17840 : : */
1563 17841 [ + + ]: 20398 : if (tbinfo->attoptions[j][0] != '\0')
17842 : 38 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
17843 : : foreign, qualrelname,
17844 : 38 : fmtId(tbinfo->attnames[j]),
17845 : 38 : tbinfo->attoptions[j]);
17846 : :
17847 : : /*
17848 : : * Dump per-column fdw options.
17849 : : */
17850 [ + + ]: 20398 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
17851 [ + + ]: 40 : tbinfo->attfdwoptions[j][0] != '\0')
17852 : 38 : appendPQExpBuffer(q,
17853 : : "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
17854 : : " %s\n"
17855 : : ");\n",
17856 : : qualrelname,
17857 : 38 : fmtId(tbinfo->attnames[j]),
17858 : 38 : tbinfo->attfdwoptions[j]);
17859 : : } /* end loop over columns */
17860 : :
1178 peter@eisentraut.org 17861 : 6060 : free(partkeydef);
17862 : 6060 : free(ftoptions);
17863 : 6060 : free(srvname);
17864 : : }
17865 : :
17866 : : /*
17867 : : * dump properties we only have ALTER TABLE syntax for
17868 : : */
3821 tgl@sss.pgh.pa.us 17869 [ + + ]: 6596 : if ((tbinfo->relkind == RELKIND_RELATION ||
3195 rhaas@postgresql.org 17870 [ + + ]: 1586 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
3821 tgl@sss.pgh.pa.us 17871 [ + + ]: 996 : tbinfo->relkind == RELKIND_MATVIEW) &&
4318 peter_e@gmx.net 17872 [ + + ]: 6020 : tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
17873 : : {
4320 rhaas@postgresql.org 17874 [ + - ]: 192 : if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
17875 : : {
17876 : : /* nothing to do, will be set when the index is dumped */
17877 : : }
17878 [ + - ]: 192 : else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
17879 : : {
17880 : 192 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
17881 : : qualrelname);
17882 : : }
4320 rhaas@postgresql.org 17883 [ # # ]:UBC 0 : else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
17884 : : {
17885 : 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
17886 : : qualrelname);
17887 : : }
17888 : : }
17889 : :
3625 sfrost@snowman.net 17890 [ + + ]:CBC 6596 : if (tbinfo->forcerowsec)
17891 : 5 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
17892 : : qualrelname);
17893 : :
3980 alvherre@alvh.no-ip. 17894 [ + + ]: 6596 : if (dopt->binary_upgrade)
2749 tgl@sss.pgh.pa.us 17895 : 868 : binary_upgrade_extension_member(q, &tbinfo->dobj,
17896 : : reltypename, qrelname,
17897 : 868 : tbinfo->dobj.namespace->dobj.name);
17898 : :
3440 sfrost@snowman.net 17899 [ + - ]: 6596 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17900 : : {
1373 peter@eisentraut.org 17901 : 6596 : char *tablespace = NULL;
2299 tgl@sss.pgh.pa.us 17902 : 6596 : char *tableam = NULL;
17903 : :
17904 : : /*
17905 : : * _selectTablespace() relies on tablespace-enabled objects in the
17906 : : * default tablespace to have a tablespace of "" (empty string) versus
17907 : : * non-tablespace-enabled objects to have a tablespace of NULL.
17908 : : * getTables() sets tbinfo->reltablespace to "" for the default
17909 : : * tablespace (not NULL).
17910 : : */
1373 peter@eisentraut.org 17911 [ + + + - : 6596 : if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
+ - + - +
+ + + - +
+ - ]
17912 : 6020 : tablespace = tbinfo->reltablespace;
17913 : :
530 alvherre@alvh.no-ip. 17914 [ + + + - : 6596 : if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
+ + ]
17915 [ + + ]: 1166 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2376 andres@anarazel.de 17916 : 6020 : tableam = tbinfo->amname;
17917 : :
3440 sfrost@snowman.net 17918 : 6596 : ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 17919 [ + + ]: 6596 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17920 : : .namespace = tbinfo->dobj.namespace->dobj.name,
17921 : : .tablespace = tablespace,
17922 : : .tableam = tableam,
17923 : : .relkind = tbinfo->relkind,
17924 : : .owner = tbinfo->rolname,
17925 : : .description = reltypename,
17926 : : .section = tbinfo->postponed_def ?
17927 : : SECTION_POST_DATA : SECTION_PRE_DATA,
17928 : : .createStmt = q->data,
17929 : : .dropStmt = delq->data));
17930 : : }
17931 : :
17932 : : /* Dump Table Comments */
3440 sfrost@snowman.net 17933 [ + + ]: 6596 : if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17934 : 86 : dumpTableComment(fout, tbinfo, reltypename);
17935 : :
17936 : : /* Dump Table Security Labels */
17937 [ - + ]: 6596 : if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3440 sfrost@snowman.net 17938 :UBC 0 : dumpTableSecLabel(fout, tbinfo, reltypename);
17939 : :
17940 : : /*
17941 : : * Dump comments for not-null constraints that aren't to be dumped
17942 : : * separately (those are processed by collectComments/dumpComment).
17943 : : */
72 alvherre@kurilemu.de 17944 [ + - + - ]:CBC 6596 : if (!fout->dopt->no_comments && dopt->dumpSchema &&
17945 [ + - ]: 6596 : fout->remoteVersion >= 180000)
17946 : : {
17947 : 6596 : PQExpBuffer comment = NULL;
17948 : 6596 : PQExpBuffer tag = NULL;
17949 : :
17950 [ + + ]: 30801 : for (j = 0; j < tbinfo->numatts; j++)
17951 : : {
17952 [ + + ]: 24205 : if (tbinfo->notnull_constrs[j] != NULL &&
17953 [ + + ]: 2537 : tbinfo->notnull_comment[j] != NULL)
17954 : : {
17955 [ + - ]: 48 : if (comment == NULL)
17956 : : {
17957 : 48 : comment = createPQExpBuffer();
17958 : 48 : tag = createPQExpBuffer();
17959 : : }
17960 : : else
17961 : : {
72 alvherre@kurilemu.de 17962 :UBC 0 : resetPQExpBuffer(comment);
17963 : 0 : resetPQExpBuffer(tag);
17964 : : }
17965 : :
72 alvherre@kurilemu.de 17966 :CBC 48 : appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
17967 : 48 : fmtId(tbinfo->notnull_constrs[j]), qualrelname);
17968 : 48 : appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
17969 : 48 : appendPQExpBufferStr(comment, ";\n");
17970 : :
17971 : 48 : appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
17972 : 48 : fmtId(tbinfo->notnull_constrs[j]), qrelname);
17973 : :
17974 : 48 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
17975 : 48 : ARCHIVE_OPTS(.tag = tag->data,
17976 : : .namespace = tbinfo->dobj.namespace->dobj.name,
17977 : : .owner = tbinfo->rolname,
17978 : : .description = "COMMENT",
17979 : : .section = SECTION_NONE,
17980 : : .createStmt = comment->data,
17981 : : .deps = &(tbinfo->dobj.dumpId),
17982 : : .nDeps = 1));
17983 : : }
17984 : : }
17985 : :
17986 : 6596 : destroyPQExpBuffer(comment);
17987 : 6596 : destroyPQExpBuffer(tag);
17988 : : }
17989 : :
17990 : : /* Dump comments on inlined table constraints */
7571 tgl@sss.pgh.pa.us 17991 [ + + ]: 7239 : for (j = 0; j < tbinfo->ncheck; j++)
17992 : : {
17993 : 643 : ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
17994 : :
6329 17995 [ + + + + ]: 643 : if (constr->separate || !constr->conislocal)
7571 17996 : 274 : continue;
17997 : :
1039 17998 [ + + ]: 369 : if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
3440 sfrost@snowman.net 17999 : 43 : dumpTableConstraintComment(fout, constr);
18000 : : }
18001 : :
8520 tgl@sss.pgh.pa.us 18002 : 6596 : destroyPQExpBuffer(q);
18003 : 6596 : destroyPQExpBuffer(delq);
404 18004 : 6596 : destroyPQExpBuffer(extra);
2749 18005 : 6596 : free(qrelname);
18006 : 6596 : free(qualrelname);
9003 pjw@rhyme.com.au 18007 : 6596 : }
18008 : :
18009 : : /*
18010 : : * dumpTableAttach
18011 : : * write to fout the commands to attach a child partition
18012 : : *
18013 : : * Child partitions are always made by creating them separately
18014 : : * and then using ATTACH PARTITION, rather than using
18015 : : * CREATE TABLE ... PARTITION OF. This is important for preserving
18016 : : * any possible discrepancy in column layout, to allow assigning the
18017 : : * correct tablespace if different, and so that it's possible to restore
18018 : : * a partition without restoring its parent. (You'll get an error from
18019 : : * the ATTACH PARTITION command, but that can be ignored, or skipped
18020 : : * using "pg_restore -L" if you prefer.) The last point motivates
18021 : : * treating ATTACH PARTITION as a completely separate ArchiveEntry
18022 : : * rather than emitting it within the child partition's ArchiveEntry.
18023 : : */
18024 : : static void
1669 peter@eisentraut.org 18025 : 1435 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
18026 : : {
1699 tgl@sss.pgh.pa.us 18027 : 1435 : DumpOptions *dopt = fout->dopt;
18028 : : PQExpBuffer q;
18029 : : PGresult *res;
18030 : : char *partbound;
18031 : :
18032 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 18033 [ + + ]: 1435 : if (!dopt->dumpSchema)
1699 tgl@sss.pgh.pa.us 18034 : 54 : return;
18035 : :
18036 : 1381 : q = createPQExpBuffer();
18037 : :
1370 18038 [ + + ]: 1381 : if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
18039 : : {
18040 : : /* Set up query for partbound details */
18041 : 49 : appendPQExpBufferStr(q,
18042 : : "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
18043 : :
18044 : 49 : appendPQExpBufferStr(q,
18045 : : "SELECT pg_get_expr(c.relpartbound, c.oid) "
18046 : : "FROM pg_class c "
18047 : : "WHERE c.oid = $1");
18048 : :
18049 : 49 : ExecuteSqlStatement(fout, q->data);
18050 : :
18051 : 49 : fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
18052 : : }
18053 : :
18054 : 1381 : printfPQExpBuffer(q,
18055 : : "EXECUTE dumpTableAttach('%u')",
18056 : 1381 : attachinfo->partitionTbl->dobj.catId.oid);
18057 : :
18058 : 1381 : res = ExecuteSqlQueryForSingleRow(fout, q->data);
18059 : 1381 : partbound = PQgetvalue(res, 0, 0);
18060 : :
18061 : : /* Perform ALTER TABLE on the parent */
18062 : 1381 : printfPQExpBuffer(q,
18063 : : "ALTER TABLE ONLY %s ",
1699 18064 : 1381 : fmtQualifiedDumpable(attachinfo->parentTbl));
18065 : 1381 : appendPQExpBuffer(q,
18066 : : "ATTACH PARTITION %s %s;\n",
18067 : 1381 : fmtQualifiedDumpable(attachinfo->partitionTbl),
18068 : : partbound);
18069 : :
18070 : : /*
18071 : : * There is no point in creating a drop query as the drop is done by table
18072 : : * drop. (If you think to change this, see also _printTocEntry().)
18073 : : * Although this object doesn't really have ownership as such, set the
18074 : : * owner field anyway to ensure that the command is run by the correct
18075 : : * role at restore time.
18076 : : */
18077 : 1381 : ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
18078 : 1381 : ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
18079 : : .namespace = attachinfo->dobj.namespace->dobj.name,
18080 : : .owner = attachinfo->partitionTbl->rolname,
18081 : : .description = "TABLE ATTACH",
18082 : : .section = SECTION_PRE_DATA,
18083 : : .createStmt = q->data));
18084 : :
1370 18085 : 1381 : PQclear(res);
1699 18086 : 1381 : destroyPQExpBuffer(q);
18087 : : }
18088 : :
18089 : : /*
18090 : : * dumpAttrDef --- dump an attribute's default-value declaration
18091 : : */
18092 : : static void
1669 peter@eisentraut.org 18093 : 1104 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
18094 : : {
3524 tgl@sss.pgh.pa.us 18095 : 1104 : DumpOptions *dopt = fout->dopt;
7945 18096 : 1104 : TableInfo *tbinfo = adinfo->adtable;
18097 : 1104 : int adnum = adinfo->adnum;
18098 : : PQExpBuffer q;
18099 : : PQExpBuffer delq;
18100 : : char *qualrelname;
18101 : : char *tag;
18102 : : char *foreign;
18103 : :
18104 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 18105 [ - + ]: 1104 : if (!dopt->dumpSchema)
7945 tgl@sss.pgh.pa.us 18106 :UBC 0 : return;
18107 : :
18108 : : /* Skip if not "separate"; it was dumped in the table's definition */
4957 tgl@sss.pgh.pa.us 18109 [ + + ]:CBC 1104 : if (!adinfo->separate)
7945 18110 : 920 : return;
18111 : :
18112 : 184 : q = createPQExpBuffer();
18113 : 184 : delq = createPQExpBuffer();
18114 : :
2749 18115 : 184 : qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
18116 : :
1996 alvherre@alvh.no-ip. 18117 [ - + ]: 184 : foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
18118 : :
18119 : 184 : appendPQExpBuffer(q,
18120 : : "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
18121 : 184 : foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
7945 tgl@sss.pgh.pa.us 18122 : 184 : adinfo->adef_expr);
18123 : :
1996 alvherre@alvh.no-ip. 18124 : 184 : appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
18125 : : foreign, qualrelname,
7945 tgl@sss.pgh.pa.us 18126 : 184 : fmtId(tbinfo->attnames[adnum - 1]));
18127 : :
3481 peter_e@gmx.net 18128 : 184 : tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
18129 : :
3440 sfrost@snowman.net 18130 [ + - ]: 184 : if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18131 : 184 : ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 18132 : 184 : ARCHIVE_OPTS(.tag = tag,
18133 : : .namespace = tbinfo->dobj.namespace->dobj.name,
18134 : : .owner = tbinfo->rolname,
18135 : : .description = "DEFAULT",
18136 : : .section = SECTION_PRE_DATA,
18137 : : .createStmt = q->data,
18138 : : .dropStmt = delq->data));
18139 : :
3481 peter_e@gmx.net 18140 : 184 : free(tag);
7945 tgl@sss.pgh.pa.us 18141 : 184 : destroyPQExpBuffer(q);
18142 : 184 : destroyPQExpBuffer(delq);
2749 18143 : 184 : free(qualrelname);
18144 : : }
18145 : :
18146 : : /*
18147 : : * getAttrName: extract the correct name for an attribute
18148 : : *
18149 : : * The array tblInfo->attnames[] only provides names of user attributes;
18150 : : * if a system attribute number is supplied, we have to fake it.
18151 : : * We also do a little bit of bounds checking for safety's sake.
18152 : : */
18153 : : static const char *
1669 peter@eisentraut.org 18154 : 2153 : getAttrName(int attrnum, const TableInfo *tblInfo)
18155 : : {
8903 tgl@sss.pgh.pa.us 18156 [ + - + - ]: 2153 : if (attrnum > 0 && attrnum <= tblInfo->numatts)
8717 bruce@momjian.us 18157 : 2153 : return tblInfo->attnames[attrnum - 1];
8903 tgl@sss.pgh.pa.us 18158 [ # # # # :UBC 0 : switch (attrnum)
# # # ]
18159 : : {
18160 : 0 : case SelfItemPointerAttributeNumber:
18161 : 0 : return "ctid";
18162 : 0 : case MinTransactionIdAttributeNumber:
18163 : 0 : return "xmin";
18164 : 0 : case MinCommandIdAttributeNumber:
18165 : 0 : return "cmin";
18166 : 0 : case MaxTransactionIdAttributeNumber:
18167 : 0 : return "xmax";
18168 : 0 : case MaxCommandIdAttributeNumber:
18169 : 0 : return "cmax";
18170 : 0 : case TableOidAttributeNumber:
18171 : 0 : return "tableoid";
18172 : : }
1247 18173 : 0 : pg_fatal("invalid column number %d for table \"%s\"",
18174 : : attrnum, tblInfo->dobj.name);
18175 : : return NULL; /* keep compiler quiet */
18176 : : }
18177 : :
18178 : : /*
18179 : : * dumpIndex
18180 : : * write out to fout a user-defined index
18181 : : */
18182 : : static void
1669 peter@eisentraut.org 18183 :CBC 2688 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
18184 : : {
3524 tgl@sss.pgh.pa.us 18185 : 2688 : DumpOptions *dopt = fout->dopt;
7945 18186 : 2688 : TableInfo *tbinfo = indxinfo->indextable;
4454 18187 : 2688 : bool is_constraint = (indxinfo->indexconstraint != 0);
18188 : : PQExpBuffer q;
18189 : : PQExpBuffer delq;
18190 : : char *qindxname;
18191 : : char *qqindxname;
18192 : :
18193 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 18194 [ + + ]: 2688 : if (!dopt->dumpSchema)
7945 tgl@sss.pgh.pa.us 18195 : 117 : return;
18196 : :
18197 : 2571 : q = createPQExpBuffer();
18198 : 2571 : delq = createPQExpBuffer();
18199 : :
2749 18200 : 2571 : qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
2005 alvherre@alvh.no-ip. 18201 : 2571 : qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
18202 : :
18203 : : /*
18204 : : * If there's an associated constraint, don't dump the index per se, but
18205 : : * do dump any comment for it. (This is safe because dependency ordering
18206 : : * will have ensured the constraint is emitted first.) Note that the
18207 : : * emitted comment has to be shown as depending on the constraint, not the
18208 : : * index, in such cases.
18209 : : */
4454 tgl@sss.pgh.pa.us 18210 [ + + ]: 2571 : if (!is_constraint)
18211 : : {
2454 michael@paquier.xyz 18212 : 1077 : char *indstatcols = indxinfo->indstatcols;
18213 : 1077 : char *indstatvals = indxinfo->indstatvals;
18214 : 1077 : char **indstatcolsarray = NULL;
18215 : 1077 : char **indstatvalsarray = NULL;
1752 18216 : 1077 : int nstatcols = 0;
18217 : 1077 : int nstatvals = 0;
18218 : :
3980 alvherre@alvh.no-ip. 18219 [ + + ]: 1077 : if (dopt->binary_upgrade)
4960 rhaas@postgresql.org 18220 : 156 : binary_upgrade_set_pg_class_oids(fout, q,
430 nathan@postgresql.or 18221 : 156 : indxinfo->dobj.catId.oid);
18222 : :
18223 : : /* Plain secondary index */
7945 tgl@sss.pgh.pa.us 18224 : 1077 : appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
18225 : :
18226 : : /*
18227 : : * Append ALTER TABLE commands as needed to set properties that we
18228 : : * only have ALTER TABLE syntax for. Keep this in sync with the
18229 : : * similar code in dumpConstraint!
18230 : : */
18231 : :
18232 : : /* If the index is clustered, we need to record that. */
18233 [ - + ]: 1077 : if (indxinfo->indisclustered)
18234 : : {
7945 tgl@sss.pgh.pa.us 18235 :UBC 0 : appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
2749 18236 : 0 : fmtQualifiedDumpable(tbinfo));
18237 : : /* index name is not qualified in this syntax */
7945 18238 : 0 : appendPQExpBuffer(q, " ON %s;\n",
18239 : : qindxname);
18240 : : }
18241 : :
18242 : : /*
18243 : : * If the index has any statistics on some of its columns, generate
18244 : : * the associated ALTER INDEX queries.
18245 : : */
1752 michael@paquier.xyz 18246 [ + + - + ]:CBC 1077 : if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
18247 : : {
18248 : : int j;
18249 : :
18250 [ - + ]: 38 : if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
1247 tgl@sss.pgh.pa.us 18251 :UBC 0 : pg_fatal("could not parse index statistic columns");
1752 michael@paquier.xyz 18252 [ - + ]:CBC 38 : if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
1247 tgl@sss.pgh.pa.us 18253 :UBC 0 : pg_fatal("could not parse index statistic values");
1752 michael@paquier.xyz 18254 [ - + ]:CBC 38 : if (nstatcols != nstatvals)
1247 tgl@sss.pgh.pa.us 18255 :UBC 0 : pg_fatal("mismatched number of columns and values for index statistics");
18256 : :
2454 michael@paquier.xyz 18257 [ + + ]:CBC 114 : for (j = 0; j < nstatcols; j++)
18258 : : {
2005 alvherre@alvh.no-ip. 18259 : 76 : appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
18260 : :
18261 : : /*
18262 : : * Note that this is a column number, so no quotes should be
18263 : : * used.
18264 : : */
2454 michael@paquier.xyz 18265 : 76 : appendPQExpBuffer(q, "ALTER COLUMN %s ",
18266 : 76 : indstatcolsarray[j]);
18267 : 76 : appendPQExpBuffer(q, "SET STATISTICS %s;\n",
18268 : 76 : indstatvalsarray[j]);
18269 : : }
18270 : : }
18271 : :
18272 : : /* Indexes can depend on extensions */
2005 alvherre@alvh.no-ip. 18273 : 1077 : append_depends_on_extension(fout, q, &indxinfo->dobj,
18274 : : "pg_catalog.pg_class",
18275 : : "INDEX", qqindxname);
18276 : :
18277 : : /* If the index defines identity, we need to record that. */
4320 rhaas@postgresql.org 18278 [ - + ]: 1077 : if (indxinfo->indisreplident)
18279 : : {
4320 rhaas@postgresql.org 18280 :UBC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
2749 tgl@sss.pgh.pa.us 18281 : 0 : fmtQualifiedDumpable(tbinfo));
18282 : : /* index name is not qualified in this syntax */
4320 rhaas@postgresql.org 18283 : 0 : appendPQExpBuffer(q, " INDEX %s;\n",
18284 : : qindxname);
18285 : : }
18286 : :
18287 : : /*
18288 : : * If this index is a member of a partitioned index, the backend will
18289 : : * not allow us to drop it separately, so don't try. It will go away
18290 : : * automatically when we drop either the index's table or the
18291 : : * partitioned index. (If, in a selective restore with --clean, we
18292 : : * drop neither of those, then this index will not be dropped either.
18293 : : * But that's fine, and even if you think it's not, the backend won't
18294 : : * let us do differently.)
18295 : : */
143 tgl@sss.pgh.pa.us 18296 [ + + ]:CBC 1077 : if (indxinfo->parentidx == 0)
18297 : 871 : appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
18298 : :
3440 sfrost@snowman.net 18299 [ + - ]: 1077 : if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18300 : 1077 : ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 18301 : 1077 : ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
18302 : : .namespace = tbinfo->dobj.namespace->dobj.name,
18303 : : .tablespace = indxinfo->tablespace,
18304 : : .owner = tbinfo->rolname,
18305 : : .description = "INDEX",
18306 : : .section = SECTION_POST_DATA,
18307 : : .createStmt = q->data,
18308 : : .dropStmt = delq->data));
18309 : :
1178 peter@eisentraut.org 18310 : 1077 : free(indstatcolsarray);
18311 : 1077 : free(indstatvalsarray);
18312 : : }
18313 : :
18314 : : /* Dump Index Comments */
3440 sfrost@snowman.net 18315 [ + + ]: 2571 : if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 18316 [ + + ]: 15 : dumpComment(fout, "INDEX", qindxname,
3440 sfrost@snowman.net 18317 : 15 : tbinfo->dobj.namespace->dobj.name,
18318 : : tbinfo->rolname,
18319 : : indxinfo->dobj.catId, 0,
18320 : : is_constraint ? indxinfo->indexconstraint :
18321 : : indxinfo->dobj.dumpId);
18322 : :
7945 tgl@sss.pgh.pa.us 18323 : 2571 : destroyPQExpBuffer(q);
18324 : 2571 : destroyPQExpBuffer(delq);
2749 18325 : 2571 : free(qindxname);
2005 alvherre@alvh.no-ip. 18326 : 2571 : free(qqindxname);
18327 : : }
18328 : :
18329 : : /*
18330 : : * dumpIndexAttach
18331 : : * write out to fout a partitioned-index attachment clause
18332 : : */
18333 : : static void
1669 peter@eisentraut.org 18334 : 612 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
18335 : : {
18336 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 18337 [ + + ]: 612 : if (!fout->dopt->dumpSchema)
2787 alvherre@alvh.no-ip. 18338 : 48 : return;
18339 : :
18340 [ + - ]: 564 : if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
18341 : : {
2784 tgl@sss.pgh.pa.us 18342 : 564 : PQExpBuffer q = createPQExpBuffer();
18343 : :
2566 18344 : 564 : appendPQExpBuffer(q, "ALTER INDEX %s ",
2749 18345 : 564 : fmtQualifiedDumpable(attachinfo->parentIdx));
2787 alvherre@alvh.no-ip. 18346 : 564 : appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
2749 tgl@sss.pgh.pa.us 18347 : 564 : fmtQualifiedDumpable(attachinfo->partitionIdx));
18348 : :
18349 : : /*
18350 : : * There is no need for a dropStmt since the drop is done implicitly
18351 : : * when we drop either the index's table or the partitioned index.
18352 : : * Moreover, since there's no ALTER INDEX DETACH PARTITION command,
18353 : : * there's no way to do it anyway. (If you think to change this,
18354 : : * consider also what to do with --if-exists.)
18355 : : *
18356 : : * Although this object doesn't really have ownership as such, set the
18357 : : * owner field anyway to ensure that the command is run by the correct
18358 : : * role at restore time.
18359 : : */
2787 alvherre@alvh.no-ip. 18360 : 564 : ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
2409 18361 : 564 : ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
18362 : : .namespace = attachinfo->dobj.namespace->dobj.name,
18363 : : .owner = attachinfo->parentIdx->indextable->rolname,
18364 : : .description = "INDEX ATTACH",
18365 : : .section = SECTION_POST_DATA,
18366 : : .createStmt = q->data));
18367 : :
2787 18368 : 564 : destroyPQExpBuffer(q);
18369 : : }
18370 : : }
18371 : :
18372 : : /*
18373 : : * dumpStatisticsExt
18374 : : * write out to fout an extended statistics object
18375 : : */
18376 : : static void
1669 peter@eisentraut.org 18377 : 151 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
18378 : : {
3088 alvherre@alvh.no-ip. 18379 : 151 : DumpOptions *dopt = fout->dopt;
18380 : : PQExpBuffer q;
18381 : : PQExpBuffer delq;
18382 : : PQExpBuffer query;
18383 : : char *qstatsextname;
18384 : : PGresult *res;
18385 : : char *stxdef;
18386 : :
18387 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 18388 [ + + ]: 151 : if (!dopt->dumpSchema)
3088 alvherre@alvh.no-ip. 18389 : 18 : return;
18390 : :
18391 : 133 : q = createPQExpBuffer();
18392 : 133 : delq = createPQExpBuffer();
2764 tgl@sss.pgh.pa.us 18393 : 133 : query = createPQExpBuffer();
18394 : :
2749 18395 : 133 : qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
18396 : :
2764 18397 : 133 : appendPQExpBuffer(query, "SELECT "
18398 : : "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
18399 : 133 : statsextinfo->dobj.catId.oid);
18400 : :
18401 : 133 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
18402 : :
18403 : 133 : stxdef = PQgetvalue(res, 0, 0);
18404 : :
18405 : : /* Result of pg_get_statisticsobjdef is complete except for semicolon */
18406 : 133 : appendPQExpBuffer(q, "%s;\n", stxdef);
18407 : :
18408 : : /*
18409 : : * We only issue an ALTER STATISTICS statement if the stxstattarget entry
18410 : : * for this statistics object is not the default value.
18411 : : */
2188 tomas.vondra@postgre 18412 [ + + ]: 133 : if (statsextinfo->stattarget >= 0)
18413 : : {
18414 : 38 : appendPQExpBuffer(q, "ALTER STATISTICS %s ",
18415 : 38 : fmtQualifiedDumpable(statsextinfo));
18416 : 38 : appendPQExpBuffer(q, "SET STATISTICS %d;\n",
18417 : 38 : statsextinfo->stattarget);
18418 : : }
18419 : :
2749 tgl@sss.pgh.pa.us 18420 : 133 : appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
18421 : 133 : fmtQualifiedDumpable(statsextinfo));
18422 : :
3088 alvherre@alvh.no-ip. 18423 [ + - ]: 133 : if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3034 bruce@momjian.us 18424 : 133 : ArchiveEntry(fout, statsextinfo->dobj.catId,
18425 : 133 : statsextinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 18426 : 133 : ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
18427 : : .namespace = statsextinfo->dobj.namespace->dobj.name,
18428 : : .owner = statsextinfo->rolname,
18429 : : .description = "STATISTICS",
18430 : : .section = SECTION_POST_DATA,
18431 : : .createStmt = q->data,
18432 : : .dropStmt = delq->data));
18433 : :
18434 : : /* Dump Statistics Comments */
3088 18435 [ - + ]: 133 : if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 18436 :UBC 0 : dumpComment(fout, "STATISTICS", qstatsextname,
2764 18437 : 0 : statsextinfo->dobj.namespace->dobj.name,
18438 : 0 : statsextinfo->rolname,
18439 : : statsextinfo->dobj.catId, 0,
3088 alvherre@alvh.no-ip. 18440 : 0 : statsextinfo->dobj.dumpId);
18441 : :
2764 tgl@sss.pgh.pa.us 18442 :CBC 133 : PQclear(res);
3088 alvherre@alvh.no-ip. 18443 : 133 : destroyPQExpBuffer(q);
18444 : 133 : destroyPQExpBuffer(delq);
2764 tgl@sss.pgh.pa.us 18445 : 133 : destroyPQExpBuffer(query);
2749 18446 : 133 : free(qstatsextname);
18447 : : }
18448 : :
18449 : : /*
18450 : : * dumpConstraint
18451 : : * write out to fout a user-defined constraint
18452 : : */
18453 : : static void
1669 peter@eisentraut.org 18454 : 2645 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
18455 : : {
3524 tgl@sss.pgh.pa.us 18456 : 2645 : DumpOptions *dopt = fout->dopt;
7945 18457 : 2645 : TableInfo *tbinfo = coninfo->contable;
18458 : : PQExpBuffer q;
18459 : : PQExpBuffer delq;
3481 peter_e@gmx.net 18460 : 2645 : char *tag = NULL;
18461 : : char *foreign;
18462 : :
18463 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 18464 [ + + ]: 2645 : if (!dopt->dumpSchema)
7945 tgl@sss.pgh.pa.us 18465 : 98 : return;
18466 : :
18467 : 2547 : q = createPQExpBuffer();
18468 : 2547 : delq = createPQExpBuffer();
18469 : :
1996 alvherre@alvh.no-ip. 18470 : 4928 : foreign = tbinfo &&
1941 tgl@sss.pgh.pa.us 18471 [ + + - + ]: 2547 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
18472 : :
5752 18473 [ + + ]: 2547 : if (coninfo->contype == 'p' ||
18474 [ + + ]: 1298 : coninfo->contype == 'u' ||
18475 [ + + ]: 1063 : coninfo->contype == 'x')
7945 18476 : 1494 : {
18477 : : /* Index-related constraint */
18478 : : IndxInfo *indxinfo;
18479 : : int k;
18480 : :
18481 : 1494 : indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
18482 : :
18483 [ - + ]: 1494 : if (indxinfo == NULL)
1247 tgl@sss.pgh.pa.us 18484 :UBC 0 : pg_fatal("missing index for constraint \"%s\"",
18485 : : coninfo->dobj.name);
18486 : :
3980 alvherre@alvh.no-ip. 18487 [ + + ]:CBC 1494 : if (dopt->binary_upgrade)
4960 rhaas@postgresql.org 18488 : 146 : binary_upgrade_set_pg_class_oids(fout, q,
18489 : : indxinfo->dobj.catId.oid);
18490 : :
1996 alvherre@alvh.no-ip. 18491 : 1494 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
2749 tgl@sss.pgh.pa.us 18492 : 1494 : fmtQualifiedDumpable(tbinfo));
5752 18493 : 1494 : appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
18494 : 1494 : fmtId(coninfo->dobj.name));
18495 : :
18496 [ + + ]: 1494 : if (coninfo->condef)
18497 : : {
18498 : : /* pg_get_constraintdef should have provided everything */
18499 : 10 : appendPQExpBuffer(q, "%s;\n", coninfo->condef);
18500 : : }
18501 : : else
18502 : : {
1096 drowley@postgresql.o 18503 : 1484 : appendPQExpBufferStr(q,
18504 [ + + ]: 1484 : coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
18505 : :
18506 : : /*
18507 : : * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
18508 : : * indexes. Being able to create this was fixed, but we need to
18509 : : * make the index distinct in order to be able to restore the
18510 : : * dump.
18511 : : */
925 dgustafsson@postgres 18512 [ - + - - ]: 1484 : if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
1096 drowley@postgresql.o 18513 :UBC 0 : appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
1096 drowley@postgresql.o 18514 :CBC 1484 : appendPQExpBufferStr(q, " (");
2709 teodor@sigaev.ru 18515 [ + + ]: 3597 : for (k = 0; k < indxinfo->indnkeyattrs; k++)
18516 : : {
5752 tgl@sss.pgh.pa.us 18517 : 2113 : int indkey = (int) indxinfo->indkeys[k];
18518 : : const char *attname;
18519 : :
18520 [ - + ]: 2113 : if (indkey == InvalidAttrNumber)
5752 tgl@sss.pgh.pa.us 18521 :UBC 0 : break;
5752 tgl@sss.pgh.pa.us 18522 :CBC 2113 : attname = getAttrName(indkey, tbinfo);
18523 : :
18524 [ + + ]: 2113 : appendPQExpBuffer(q, "%s%s",
18525 : : (k == 0) ? "" : ", ",
18526 : : fmtId(attname));
18527 : : }
354 peter@eisentraut.org 18528 [ + + ]: 1484 : if (coninfo->conperiod)
18529 : 116 : appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
18530 : :
2709 teodor@sigaev.ru 18531 [ + + ]: 1484 : if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
2256 drowley@postgresql.o 18532 : 20 : appendPQExpBufferStr(q, ") INCLUDE (");
18533 : :
2709 teodor@sigaev.ru 18534 [ + + ]: 1524 : for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
18535 : : {
18536 : 40 : int indkey = (int) indxinfo->indkeys[k];
18537 : : const char *attname;
18538 : :
18539 [ - + ]: 40 : if (indkey == InvalidAttrNumber)
2709 teodor@sigaev.ru 18540 :UBC 0 : break;
2709 teodor@sigaev.ru 18541 :CBC 40 : attname = getAttrName(indkey, tbinfo);
18542 : :
18543 : 80 : appendPQExpBuffer(q, "%s%s",
18544 [ + + ]: 40 : (k == indxinfo->indnkeyattrs) ? "" : ", ",
18545 : : fmtId(attname));
18546 : : }
18547 : :
4310 heikki.linnakangas@i 18548 : 1484 : appendPQExpBufferChar(q, ')');
18549 : :
3535 tgl@sss.pgh.pa.us 18550 [ - + ]: 1484 : if (nonemptyReloptions(indxinfo->indreloptions))
18551 : : {
3535 tgl@sss.pgh.pa.us 18552 :UBC 0 : appendPQExpBufferStr(q, " WITH (");
3410 dean.a.rasheed@gmail 18553 : 0 : appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
3535 tgl@sss.pgh.pa.us 18554 : 0 : appendPQExpBufferChar(q, ')');
18555 : : }
18556 : :
5752 tgl@sss.pgh.pa.us 18557 [ + + ]:CBC 1484 : if (coninfo->condeferrable)
18558 : : {
4310 heikki.linnakangas@i 18559 : 25 : appendPQExpBufferStr(q, " DEFERRABLE");
5752 tgl@sss.pgh.pa.us 18560 [ + + ]: 25 : if (coninfo->condeferred)
4310 heikki.linnakangas@i 18561 : 15 : appendPQExpBufferStr(q, " INITIALLY DEFERRED");
18562 : : }
18563 : :
18564 : 1484 : appendPQExpBufferStr(q, ";\n");
18565 : : }
18566 : :
18567 : : /*
18568 : : * Append ALTER TABLE commands as needed to set properties that we
18569 : : * only have ALTER TABLE syntax for. Keep this in sync with the
18570 : : * similar code in dumpIndex!
18571 : : */
18572 : :
18573 : : /* If the index is clustered, we need to record that. */
7945 tgl@sss.pgh.pa.us 18574 [ + + ]: 1494 : if (indxinfo->indisclustered)
18575 : : {
18576 : 38 : appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
2749 18577 : 38 : fmtQualifiedDumpable(tbinfo));
18578 : : /* index name is not qualified in this syntax */
7945 18579 : 38 : appendPQExpBuffer(q, " ON %s;\n",
7857 18580 : 38 : fmtId(indxinfo->dobj.name));
18581 : : }
18582 : :
18583 : : /* If the index defines identity, we need to record that. */
2595 18584 [ - + ]: 1494 : if (indxinfo->indisreplident)
18585 : : {
2595 tgl@sss.pgh.pa.us 18586 :UBC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
18587 : 0 : fmtQualifiedDumpable(tbinfo));
18588 : : /* index name is not qualified in this syntax */
18589 : 0 : appendPQExpBuffer(q, " INDEX %s;\n",
18590 : 0 : fmtId(indxinfo->dobj.name));
18591 : : }
18592 : :
18593 : : /* Indexes can depend on extensions */
2005 alvherre@alvh.no-ip. 18594 :CBC 1494 : append_depends_on_extension(fout, q, &indxinfo->dobj,
18595 : : "pg_catalog.pg_class", "INDEX",
18596 : 1494 : fmtQualifiedDumpable(indxinfo));
18597 : :
1996 18598 : 1494 : appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
2749 tgl@sss.pgh.pa.us 18599 : 1494 : fmtQualifiedDumpable(tbinfo));
7945 18600 : 1494 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
7857 18601 : 1494 : fmtId(coninfo->dobj.name));
18602 : :
3481 peter_e@gmx.net 18603 : 1494 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18604 : :
3440 sfrost@snowman.net 18605 [ + - ]: 1494 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18606 : 1494 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 18607 : 1494 : ARCHIVE_OPTS(.tag = tag,
18608 : : .namespace = tbinfo->dobj.namespace->dobj.name,
18609 : : .tablespace = indxinfo->tablespace,
18610 : : .owner = tbinfo->rolname,
18611 : : .description = "CONSTRAINT",
18612 : : .section = SECTION_POST_DATA,
18613 : : .createStmt = q->data,
18614 : : .dropStmt = delq->data));
18615 : : }
7945 tgl@sss.pgh.pa.us 18616 [ + + ]: 1053 : else if (coninfo->contype == 'f')
18617 : : {
18618 : : char *only;
18619 : :
18620 : : /*
18621 : : * Foreign keys on partitioned tables are always declared as
18622 : : * inheriting to partitions; for all other cases, emit them as
18623 : : * applying ONLY directly to the named table, because that's how they
18624 : : * work for regular inherited tables.
18625 : : */
2712 alvherre@alvh.no-ip. 18626 [ + + ]: 171 : only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
18627 : :
18628 : : /*
18629 : : * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
18630 : : * current table data is not processed
18631 : : */
1996 18632 : 171 : appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
2712 18633 : 171 : only, fmtQualifiedDumpable(tbinfo));
7945 tgl@sss.pgh.pa.us 18634 : 171 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
7857 18635 : 171 : fmtId(coninfo->dobj.name),
7945 18636 : 171 : coninfo->condef);
18637 : :
1996 alvherre@alvh.no-ip. 18638 : 171 : appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
2712 18639 : 171 : only, fmtQualifiedDumpable(tbinfo));
7945 tgl@sss.pgh.pa.us 18640 : 171 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
7857 18641 : 171 : fmtId(coninfo->dobj.name));
18642 : :
3481 peter_e@gmx.net 18643 : 171 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18644 : :
3440 sfrost@snowman.net 18645 [ + - ]: 171 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18646 : 171 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 18647 : 171 : ARCHIVE_OPTS(.tag = tag,
18648 : : .namespace = tbinfo->dobj.namespace->dobj.name,
18649 : : .owner = tbinfo->rolname,
18650 : : .description = "FK CONSTRAINT",
18651 : : .section = SECTION_POST_DATA,
18652 : : .createStmt = q->data,
18653 : : .dropStmt = delq->data));
18654 : : }
152 18655 [ + + + - : 882 : else if ((coninfo->contype == 'c' || coninfo->contype == 'n') && tbinfo)
+ + ]
18656 : : {
18657 : : /* CHECK or invalid not-null constraint on a table */
18658 : :
18659 : : /* Ignore if not to be dumped separately, or if it was inherited */
3628 tgl@sss.pgh.pa.us 18660 [ + + + + ]: 716 : if (coninfo->separate && coninfo->conislocal)
18661 : : {
18662 : : const char *keyword;
18663 : :
152 alvherre@alvh.no-ip. 18664 [ + + ]: 113 : if (coninfo->contype == 'c')
18665 : 45 : keyword = "CHECK CONSTRAINT";
18666 : : else
18667 : 68 : keyword = "CONSTRAINT";
18668 : :
18669 : : /* not ONLY since we want it to propagate to children */
1996 18670 : 113 : appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
2749 tgl@sss.pgh.pa.us 18671 : 113 : fmtQualifiedDumpable(tbinfo));
7945 18672 : 113 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
7857 18673 : 113 : fmtId(coninfo->dobj.name),
7945 18674 : 113 : coninfo->condef);
18675 : :
1996 alvherre@alvh.no-ip. 18676 : 113 : appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
2749 tgl@sss.pgh.pa.us 18677 : 113 : fmtQualifiedDumpable(tbinfo));
7945 18678 : 113 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
7857 18679 : 113 : fmtId(coninfo->dobj.name));
18680 : :
3481 peter_e@gmx.net 18681 : 113 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18682 : :
3440 sfrost@snowman.net 18683 [ + - ]: 113 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18684 : 113 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 18685 : 113 : ARCHIVE_OPTS(.tag = tag,
18686 : : .namespace = tbinfo->dobj.namespace->dobj.name,
18687 : : .owner = tbinfo->rolname,
18688 : : .description = keyword,
18689 : : .section = SECTION_POST_DATA,
18690 : : .createStmt = q->data,
18691 : : .dropStmt = delq->data));
18692 : : }
18693 : : }
47 alvherre@kurilemu.de 18694 [ + - ]: 166 : else if (tbinfo == NULL)
18695 : : {
18696 : : /* CHECK, NOT NULL constraint on a domain */
5736 bruce@momjian.us 18697 : 166 : TypeInfo *tyinfo = coninfo->condomain;
18698 : :
47 alvherre@kurilemu.de 18699 [ + + - + ]: 166 : Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
18700 : :
18701 : : /* Ignore if not to be dumped separately */
7128 tgl@sss.pgh.pa.us 18702 [ + + ]: 166 : if (coninfo->separate)
18703 : : {
18704 : : const char *keyword;
18705 : :
47 alvherre@kurilemu.de 18706 [ + - ]: 5 : if (coninfo->contype == 'c')
18707 : 5 : keyword = "CHECK CONSTRAINT";
18708 : : else
47 alvherre@kurilemu.de 18709 :UBC 0 : keyword = "CONSTRAINT";
18710 : :
7945 tgl@sss.pgh.pa.us 18711 :CBC 5 : appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
2749 18712 : 5 : fmtQualifiedDumpable(tyinfo));
7945 18713 : 5 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
7857 18714 : 5 : fmtId(coninfo->dobj.name),
7945 18715 : 5 : coninfo->condef);
18716 : :
2749 18717 : 5 : appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
18718 : 5 : fmtQualifiedDumpable(tyinfo));
7945 18719 : 5 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
7857 18720 : 5 : fmtId(coninfo->dobj.name));
18721 : :
3481 peter_e@gmx.net 18722 : 5 : tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
18723 : :
3440 sfrost@snowman.net 18724 [ + - ]: 5 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18725 : 5 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 18726 : 5 : ARCHIVE_OPTS(.tag = tag,
18727 : : .namespace = tyinfo->dobj.namespace->dobj.name,
18728 : : .owner = tyinfo->rolname,
18729 : : .description = keyword,
18730 : : .section = SECTION_POST_DATA,
18731 : : .createStmt = q->data,
18732 : : .dropStmt = delq->data));
18733 : :
52 alvherre@kurilemu.de 18734 [ + - ]: 5 : if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18735 : : {
18736 : 5 : PQExpBuffer conprefix = createPQExpBuffer();
18737 : 5 : char *qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
18738 : :
18739 : 5 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
18740 : 5 : fmtId(coninfo->dobj.name));
18741 : :
18742 : 5 : dumpComment(fout, conprefix->data, qtypname,
18743 : 5 : tyinfo->dobj.namespace->dobj.name,
18744 : : tyinfo->rolname,
18745 : : coninfo->dobj.catId, 0, tyinfo->dobj.dumpId);
18746 : 5 : destroyPQExpBuffer(conprefix);
18747 : 5 : free(qtypname);
18748 : : }
18749 : : }
18750 : : }
18751 : : else
18752 : : {
1247 tgl@sss.pgh.pa.us 18753 :UBC 0 : pg_fatal("unrecognized constraint type: %c",
18754 : : coninfo->contype);
18755 : : }
18756 : :
18757 : : /* Dump Constraint Comments --- only works for table constraints */
3440 sfrost@snowman.net 18758 [ + + + + ]:CBC 2547 : if (tbinfo && coninfo->separate &&
18759 [ + + ]: 1808 : coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3524 tgl@sss.pgh.pa.us 18760 : 53 : dumpTableConstraintComment(fout, coninfo);
18761 : :
3481 peter_e@gmx.net 18762 : 2547 : free(tag);
8520 tgl@sss.pgh.pa.us 18763 : 2547 : destroyPQExpBuffer(q);
18764 : 2547 : destroyPQExpBuffer(delq);
18765 : : }
18766 : :
18767 : : /*
18768 : : * dumpTableConstraintComment --- dump a constraint's comment if any
18769 : : *
18770 : : * This is split out because we need the function in two different places
18771 : : * depending on whether the constraint is dumped as part of CREATE TABLE
18772 : : * or as a separate ALTER command.
18773 : : */
18774 : : static void
1669 peter@eisentraut.org 18775 : 96 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
18776 : : {
7571 tgl@sss.pgh.pa.us 18777 : 96 : TableInfo *tbinfo = coninfo->contable;
2749 18778 : 96 : PQExpBuffer conprefix = createPQExpBuffer();
18779 : : char *qtabname;
18780 : :
18781 : 96 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
18782 : :
18783 : 96 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
7571 18784 : 96 : fmtId(coninfo->dobj.name));
18785 : :
3440 sfrost@snowman.net 18786 [ + - ]: 96 : if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 18787 : 96 : dumpComment(fout, conprefix->data, qtabname,
3440 sfrost@snowman.net 18788 : 96 : tbinfo->dobj.namespace->dobj.name,
18789 : : tbinfo->rolname,
18790 : : coninfo->dobj.catId, 0,
2999 tgl@sss.pgh.pa.us 18791 [ + + ]: 96 : coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
18792 : :
2749 18793 : 96 : destroyPQExpBuffer(conprefix);
18794 : 96 : free(qtabname);
7571 18795 : 96 : }
18796 : :
18797 : : static inline SeqType
402 nathan@postgresql.or 18798 : 656 : parse_sequence_type(const char *name)
18799 : : {
18800 [ + - ]: 1461 : for (int i = 0; i < lengthof(SeqTypeNames); i++)
18801 : : {
18802 [ + + ]: 1461 : if (strcmp(SeqTypeNames[i], name) == 0)
18803 : 656 : return (SeqType) i;
18804 : : }
18805 : :
402 nathan@postgresql.or 18806 :UBC 0 : pg_fatal("unrecognized sequence type: %s", name);
18807 : : return (SeqType) 0; /* keep compiler quiet */
18808 : : }
18809 : :
18810 : : /*
18811 : : * bsearch() comparator for SequenceItem
18812 : : */
18813 : : static int
402 nathan@postgresql.or 18814 :CBC 3014 : SequenceItemCmp(const void *p1, const void *p2)
18815 : : {
18816 : 3014 : SequenceItem v1 = *((const SequenceItem *) p1);
18817 : 3014 : SequenceItem v2 = *((const SequenceItem *) p2);
18818 : :
18819 : 3014 : return pg_cmp_u32(v1.oid, v2.oid);
18820 : : }
18821 : :
18822 : : /*
18823 : : * collectSequences
18824 : : *
18825 : : * Construct a table of sequence information. This table is sorted by OID for
18826 : : * speed in lookup.
18827 : : */
18828 : : static void
18829 : 185 : collectSequences(Archive *fout)
18830 : : {
18831 : : PGresult *res;
18832 : : const char *query;
18833 : :
18834 : : /*
18835 : : * Before Postgres 10, sequence metadata is in the sequence itself. With
18836 : : * some extra effort, we might be able to use the sorted table for those
18837 : : * versions, but for now it seems unlikely to be worth it.
18838 : : *
18839 : : * Since version 18, we can gather the sequence data in this query with
18840 : : * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
18841 : : */
18842 [ - + ]: 185 : if (fout->remoteVersion < 100000)
402 nathan@postgresql.or 18843 :UBC 0 : return;
402 nathan@postgresql.or 18844 [ + - ]:CBC 185 : else if (fout->remoteVersion < 180000 ||
285 18845 [ + + + + ]: 185 : (!fout->dopt->dumpData && !fout->dopt->sequence_data))
402 18846 : 8 : query = "SELECT seqrelid, format_type(seqtypid, NULL), "
18847 : : "seqstart, seqincrement, "
18848 : : "seqmax, seqmin, "
18849 : : "seqcache, seqcycle, "
18850 : : "NULL, 'f' "
18851 : : "FROM pg_catalog.pg_sequence "
18852 : : "ORDER BY seqrelid";
18853 : : else
18854 : 177 : query = "SELECT seqrelid, format_type(seqtypid, NULL), "
18855 : : "seqstart, seqincrement, "
18856 : : "seqmax, seqmin, "
18857 : : "seqcache, seqcycle, "
18858 : : "last_value, is_called "
18859 : : "FROM pg_catalog.pg_sequence, "
18860 : : "pg_get_sequence_data(seqrelid) "
18861 : : "ORDER BY seqrelid;";
18862 : :
18863 : 185 : res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
18864 : :
18865 : 185 : nsequences = PQntuples(res);
18866 : 185 : sequences = (SequenceItem *) pg_malloc(nsequences * sizeof(SequenceItem));
18867 : :
18868 [ + + ]: 841 : for (int i = 0; i < nsequences; i++)
18869 : : {
18870 : 656 : sequences[i].oid = atooid(PQgetvalue(res, i, 0));
18871 : 656 : sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
18872 : 656 : sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
18873 : 656 : sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
18874 : 656 : sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
18875 : 656 : sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
18876 : 656 : sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
18877 : 656 : sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
18878 : 656 : sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
18879 : 656 : sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
18880 : : }
18881 : :
18882 : 185 : PQclear(res);
18883 : : }
18884 : :
18885 : : /*
18886 : : * dumpSequence
18887 : : * write the declaration (not data) of one user-defined sequence
18888 : : */
18889 : : static void
1669 peter@eisentraut.org 18890 : 393 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
18891 : : {
3524 tgl@sss.pgh.pa.us 18892 : 393 : DumpOptions *dopt = fout->dopt;
18893 : : SequenceItem *seq;
18894 : : bool is_ascending;
18895 : : int64 default_minv,
18896 : : default_maxv;
9278 bruce@momjian.us 18897 : 393 : PQExpBuffer query = createPQExpBuffer();
9195 18898 : 393 : PQExpBuffer delqry = createPQExpBuffer();
18899 : : char *qseqname;
1248 peter@eisentraut.org 18900 : 393 : TableInfo *owning_tab = NULL;
18901 : :
2749 tgl@sss.pgh.pa.us 18902 : 393 : qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
18903 : :
18904 : : /*
18905 : : * For versions >= 10, the sequence information is gathered in a sorted
18906 : : * table before any calls to dumpSequence(). See collectSequences() for
18907 : : * more information.
18908 : : */
3182 peter_e@gmx.net 18909 [ + - ]: 393 : if (fout->remoteVersion >= 100000)
18910 : : {
402 nathan@postgresql.or 18911 : 393 : SequenceItem key = {0};
18912 : :
18913 [ - + ]: 393 : Assert(sequences);
18914 : :
18915 : 393 : key.oid = tbinfo->dobj.catId.oid;
18916 : 393 : seq = bsearch(&key, sequences, nsequences,
18917 : : sizeof(SequenceItem), SequenceItemCmp);
18918 : : }
18919 : : else
18920 : : {
18921 : : PGresult *res;
18922 : :
18923 : : /*
18924 : : * Before PostgreSQL 10, sequence metadata is in the sequence itself.
18925 : : *
18926 : : * Note: it might seem that 'bigint' potentially needs to be
18927 : : * schema-qualified, but actually that's a keyword.
18928 : : */
6322 tgl@sss.pgh.pa.us 18929 :UBC 0 : appendPQExpBuffer(query,
18930 : : "SELECT 'bigint' AS sequence_type, "
18931 : : "start_value, increment_by, max_value, min_value, "
18932 : : "cache_value, is_cycled FROM %s",
2749 18933 : 0 : fmtQualifiedDumpable(tbinfo));
18934 : :
402 nathan@postgresql.or 18935 : 0 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18936 : :
18937 [ # # ]: 0 : if (PQntuples(res) != 1)
18938 : 0 : pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
18939 : : "query to get data of sequence \"%s\" returned %d rows (expected 1)",
18940 : : PQntuples(res)),
18941 : : tbinfo->dobj.name, PQntuples(res));
18942 : :
18943 : 0 : seq = pg_malloc0(sizeof(SequenceItem));
18944 : 0 : seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
18945 : 0 : seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
18946 : 0 : seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
18947 : 0 : seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
18948 : 0 : seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
18949 : 0 : seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
18950 : 0 : seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
18951 : :
18952 : 0 : PQclear(res);
18953 : : }
18954 : :
18955 : : /* Calculate default limits for a sequence of this type */
402 nathan@postgresql.or 18956 :CBC 393 : is_ascending = (seq->incby >= 0);
18957 [ + + ]: 393 : if (seq->seqtype == SEQTYPE_SMALLINT)
18958 : : {
2755 tgl@sss.pgh.pa.us 18959 [ + + ]: 25 : default_minv = is_ascending ? 1 : PG_INT16_MIN;
18960 [ + + ]: 25 : default_maxv = is_ascending ? PG_INT16_MAX : -1;
18961 : : }
402 nathan@postgresql.or 18962 [ + + ]: 368 : else if (seq->seqtype == SEQTYPE_INTEGER)
18963 : : {
2755 tgl@sss.pgh.pa.us 18964 [ + + ]: 302 : default_minv = is_ascending ? 1 : PG_INT32_MIN;
18965 [ + + ]: 302 : default_maxv = is_ascending ? PG_INT32_MAX : -1;
18966 : : }
402 nathan@postgresql.or 18967 [ + - ]: 66 : else if (seq->seqtype == SEQTYPE_BIGINT)
18968 : : {
2755 tgl@sss.pgh.pa.us 18969 [ + + ]: 66 : default_minv = is_ascending ? 1 : PG_INT64_MIN;
18970 [ + + ]: 66 : default_maxv = is_ascending ? PG_INT64_MAX : -1;
18971 : : }
18972 : : else
18973 : : {
402 nathan@postgresql.or 18974 :UBC 0 : pg_fatal("unrecognized sequence type: %d", seq->seqtype);
18975 : : default_minv = default_maxv = 0; /* keep compiler quiet */
18976 : : }
18977 : :
18978 : : /*
18979 : : * Identity sequences are not to be dropped separately.
18980 : : */
3075 peter_e@gmx.net 18981 [ + + ]:CBC 393 : if (!tbinfo->is_identity_sequence)
18982 : : {
2749 tgl@sss.pgh.pa.us 18983 : 245 : appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
18984 : 245 : fmtQualifiedDumpable(tbinfo));
18985 : : }
18986 : :
4698 18987 : 393 : resetPQExpBuffer(query);
18988 : :
3980 alvherre@alvh.no-ip. 18989 [ + + ]: 393 : if (dopt->binary_upgrade)
18990 : : {
4698 tgl@sss.pgh.pa.us 18991 : 66 : binary_upgrade_set_pg_class_oids(fout, query,
430 nathan@postgresql.or 18992 : 66 : tbinfo->dobj.catId.oid);
18993 : :
18994 : : /*
18995 : : * In older PG versions a sequence will have a pg_type entry, but v14
18996 : : * and up don't use that, so don't attempt to preserve the type OID.
18997 : : */
18998 : : }
18999 : :
3075 peter_e@gmx.net 19000 [ + + ]: 393 : if (tbinfo->is_identity_sequence)
19001 : : {
1248 peter@eisentraut.org 19002 : 148 : owning_tab = findTableByOid(tbinfo->owning_tab);
19003 : :
3075 peter_e@gmx.net 19004 : 148 : appendPQExpBuffer(query,
19005 : : "ALTER TABLE %s ",
2749 tgl@sss.pgh.pa.us 19006 : 148 : fmtQualifiedDumpable(owning_tab));
3075 peter_e@gmx.net 19007 : 148 : appendPQExpBuffer(query,
19008 : : "ALTER COLUMN %s ADD GENERATED ",
2999 tgl@sss.pgh.pa.us 19009 : 148 : fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
3075 peter_e@gmx.net 19010 [ + + ]: 148 : if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
2256 drowley@postgresql.o 19011 : 108 : appendPQExpBufferStr(query, "ALWAYS");
3075 peter_e@gmx.net 19012 [ + - ]: 40 : else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
2256 drowley@postgresql.o 19013 : 40 : appendPQExpBufferStr(query, "BY DEFAULT");
3075 peter_e@gmx.net 19014 : 148 : appendPQExpBuffer(query, " AS IDENTITY (\n SEQUENCE NAME %s\n",
2749 tgl@sss.pgh.pa.us 19015 : 148 : fmtQualifiedDumpable(tbinfo));
19016 : :
19017 : : /*
19018 : : * Emit persistence option only if it's different from the owning
19019 : : * table's. This avoids using this new syntax unnecessarily.
19020 : : */
354 19021 [ + + ]: 148 : if (tbinfo->relpersistence != owning_tab->relpersistence)
19022 : 10 : appendPQExpBuffer(query, " %s\n",
19023 [ + + ]: 10 : tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
19024 : : "UNLOGGED" : "LOGGED");
19025 : : }
19026 : : else
19027 : : {
3075 peter_e@gmx.net 19028 : 245 : appendPQExpBuffer(query,
19029 : : "CREATE %sSEQUENCE %s\n",
1248 peter@eisentraut.org 19030 [ + + ]: 245 : tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
19031 : : "UNLOGGED " : "",
2749 tgl@sss.pgh.pa.us 19032 : 245 : fmtQualifiedDumpable(tbinfo));
19033 : :
402 nathan@postgresql.or 19034 [ + + ]: 245 : if (seq->seqtype != SEQTYPE_BIGINT)
19035 : 194 : appendPQExpBuffer(query, " AS %s\n", SeqTypeNames[seq->seqtype]);
19036 : : }
19037 : :
19038 : 393 : appendPQExpBuffer(query, " START WITH " INT64_FORMAT "\n", seq->startv);
19039 : :
19040 : 393 : appendPQExpBuffer(query, " INCREMENT BY " INT64_FORMAT "\n", seq->incby);
19041 : :
19042 [ + + ]: 393 : if (seq->minv != default_minv)
19043 : 15 : appendPQExpBuffer(query, " MINVALUE " INT64_FORMAT "\n", seq->minv);
19044 : : else
4310 heikki.linnakangas@i 19045 : 378 : appendPQExpBufferStr(query, " NO MINVALUE\n");
19046 : :
402 nathan@postgresql.or 19047 [ + + ]: 393 : if (seq->maxv != default_maxv)
19048 : 15 : appendPQExpBuffer(query, " MAXVALUE " INT64_FORMAT "\n", seq->maxv);
19049 : : else
4310 heikki.linnakangas@i 19050 : 378 : appendPQExpBufferStr(query, " NO MAXVALUE\n");
19051 : :
4698 tgl@sss.pgh.pa.us 19052 : 393 : appendPQExpBuffer(query,
19053 : : " CACHE " INT64_FORMAT "%s",
402 nathan@postgresql.or 19054 [ + + ]: 393 : seq->cache, (seq->cycled ? "\n CYCLE" : ""));
19055 : :
3075 peter_e@gmx.net 19056 [ + + ]: 393 : if (tbinfo->is_identity_sequence)
19057 : 148 : appendPQExpBufferStr(query, "\n);\n");
19058 : : else
19059 : 245 : appendPQExpBufferStr(query, ";\n");
19060 : :
19061 : : /* binary_upgrade: no need to clear TOAST table oid */
19062 : :
3980 alvherre@alvh.no-ip. 19063 [ + + ]: 393 : if (dopt->binary_upgrade)
4698 tgl@sss.pgh.pa.us 19064 : 66 : binary_upgrade_extension_member(query, &tbinfo->dobj,
19065 : : "SEQUENCE", qseqname,
2749 19066 : 66 : tbinfo->dobj.namespace->dobj.name);
19067 : :
3440 sfrost@snowman.net 19068 [ + - ]: 393 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19069 : 393 : ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 19070 : 393 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19071 : : .namespace = tbinfo->dobj.namespace->dobj.name,
19072 : : .owner = tbinfo->rolname,
19073 : : .description = "SEQUENCE",
19074 : : .section = SECTION_PRE_DATA,
19075 : : .createStmt = query->data,
19076 : : .dropStmt = delqry->data));
19077 : :
19078 : : /*
19079 : : * If the sequence is owned by a table column, emit the ALTER for it as a
19080 : : * separate TOC entry immediately following the sequence's own entry. It's
19081 : : * OK to do this rather than using full sorting logic, because the
19082 : : * dependency that tells us it's owned will have forced the table to be
19083 : : * created first. We can't just include the ALTER in the TOC entry
19084 : : * because it will fail if we haven't reassigned the sequence owner to
19085 : : * match the table's owner.
19086 : : *
19087 : : * We need not schema-qualify the table reference because both sequence
19088 : : * and table must be in the same schema.
19089 : : */
3075 peter_e@gmx.net 19090 [ + + + + ]: 393 : if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
19091 : : {
1113 drowley@postgresql.o 19092 : 149 : owning_tab = findTableByOid(tbinfo->owning_tab);
19093 : :
3165 sfrost@snowman.net 19094 [ - + ]: 149 : if (owning_tab == NULL)
1247 tgl@sss.pgh.pa.us 19095 :UBC 0 : pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
19096 : : tbinfo->owning_tab, tbinfo->dobj.catId.oid);
19097 : :
3165 sfrost@snowman.net 19098 [ + + ]:CBC 149 : if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
19099 : : {
4698 tgl@sss.pgh.pa.us 19100 : 147 : resetPQExpBuffer(query);
19101 : 147 : appendPQExpBuffer(query, "ALTER SEQUENCE %s",
2749 19102 : 147 : fmtQualifiedDumpable(tbinfo));
4698 19103 : 147 : appendPQExpBuffer(query, " OWNED BY %s",
2749 19104 : 147 : fmtQualifiedDumpable(owning_tab));
4698 19105 : 147 : appendPQExpBuffer(query, ".%s;\n",
2999 19106 : 147 : fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
19107 : :
3440 sfrost@snowman.net 19108 [ + - ]: 147 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19109 : 147 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 19110 : 147 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19111 : : .namespace = tbinfo->dobj.namespace->dobj.name,
19112 : : .owner = tbinfo->rolname,
19113 : : .description = "SEQUENCE OWNED BY",
19114 : : .section = SECTION_PRE_DATA,
19115 : : .createStmt = query->data,
19116 : : .deps = &(tbinfo->dobj.dumpId),
19117 : : .nDeps = 1));
19118 : : }
19119 : : }
19120 : :
19121 : : /* Dump Sequence Comments and Security Labels */
3440 sfrost@snowman.net 19122 [ - + ]: 393 : if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 19123 :UBC 0 : dumpComment(fout, "SEQUENCE", qseqname,
3440 sfrost@snowman.net 19124 : 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19125 : 0 : tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
19126 : :
3440 sfrost@snowman.net 19127 [ - + ]:CBC 393 : if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2749 tgl@sss.pgh.pa.us 19128 :UBC 0 : dumpSecLabel(fout, "SEQUENCE", qseqname,
3440 sfrost@snowman.net 19129 : 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19130 : 0 : tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
19131 : :
402 nathan@postgresql.or 19132 [ - + ]:CBC 393 : if (fout->remoteVersion < 100000)
402 nathan@postgresql.or 19133 :UBC 0 : pg_free(seq);
8800 tgl@sss.pgh.pa.us 19134 :CBC 393 : destroyPQExpBuffer(query);
19135 : 393 : destroyPQExpBuffer(delqry);
2749 19136 : 393 : free(qseqname);
10384 vadim4o@yahoo.com 19137 : 393 : }
19138 : :
19139 : : /*
19140 : : * dumpSequenceData
19141 : : * write the data of one user-defined sequence
19142 : : */
19143 : : static void
1669 peter@eisentraut.org 19144 : 411 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
19145 : : {
4698 tgl@sss.pgh.pa.us 19146 : 411 : TableInfo *tbinfo = tdinfo->tdtable;
19147 : : int64 last;
19148 : : bool called;
19149 : 411 : PQExpBuffer query = createPQExpBuffer();
19150 : :
19151 : : /*
19152 : : * For versions >= 18, the sequence information is gathered in the sorted
19153 : : * array before any calls to dumpSequenceData(). See collectSequences()
19154 : : * for more information.
19155 : : *
19156 : : * For older versions, we have to query the sequence relations
19157 : : * individually.
19158 : : */
402 nathan@postgresql.or 19159 [ - + ]: 411 : if (fout->remoteVersion < 180000)
19160 : : {
19161 : : PGresult *res;
19162 : :
402 nathan@postgresql.or 19163 :UBC 0 : appendPQExpBuffer(query,
19164 : : "SELECT last_value, is_called FROM %s",
19165 : 0 : fmtQualifiedDumpable(tbinfo));
19166 : :
19167 : 0 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19168 : :
19169 [ # # ]: 0 : if (PQntuples(res) != 1)
19170 : 0 : pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
19171 : : "query to get data of sequence \"%s\" returned %d rows (expected 1)",
19172 : : PQntuples(res)),
19173 : : tbinfo->dobj.name, PQntuples(res));
19174 : :
19175 : 0 : last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
19176 : 0 : called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
19177 : :
19178 : 0 : PQclear(res);
19179 : : }
19180 : : else
19181 : : {
402 nathan@postgresql.or 19182 :CBC 411 : SequenceItem key = {0};
19183 : : SequenceItem *entry;
19184 : :
19185 [ - + ]: 411 : Assert(sequences);
19186 [ - + ]: 411 : Assert(tbinfo->dobj.catId.oid);
19187 : :
19188 : 411 : key.oid = tbinfo->dobj.catId.oid;
19189 : 411 : entry = bsearch(&key, sequences, nsequences,
19190 : : sizeof(SequenceItem), SequenceItemCmp);
19191 : :
19192 : 411 : last = entry->last_value;
19193 : 411 : called = entry->is_called;
19194 : : }
19195 : :
4698 tgl@sss.pgh.pa.us 19196 : 411 : resetPQExpBuffer(query);
4310 heikki.linnakangas@i 19197 : 411 : appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
2749 tgl@sss.pgh.pa.us 19198 : 411 : appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
402 nathan@postgresql.or 19199 [ + + ]: 411 : appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
19200 : : last, (called ? "true" : "false"));
19201 : :
3152 sfrost@snowman.net 19202 [ + - ]: 411 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
3440 19203 : 411 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2409 alvherre@alvh.no-ip. 19204 : 411 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19205 : : .namespace = tbinfo->dobj.namespace->dobj.name,
19206 : : .owner = tbinfo->rolname,
19207 : : .description = "SEQUENCE SET",
19208 : : .section = SECTION_DATA,
19209 : : .createStmt = query->data,
19210 : : .deps = &(tbinfo->dobj.dumpId),
19211 : : .nDeps = 1));
19212 : :
4698 tgl@sss.pgh.pa.us 19213 : 411 : destroyPQExpBuffer(query);
19214 : 411 : }
19215 : :
19216 : : /*
19217 : : * dumpTrigger
19218 : : * write the declaration of one user-defined table trigger
19219 : : */
19220 : : static void
1669 peter@eisentraut.org 19221 : 553 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
19222 : : {
3524 tgl@sss.pgh.pa.us 19223 : 553 : DumpOptions *dopt = fout->dopt;
7945 19224 : 553 : TableInfo *tbinfo = tginfo->tgtable;
19225 : : PQExpBuffer query;
19226 : : PQExpBuffer delqry;
19227 : : PQExpBuffer trigprefix;
19228 : : PQExpBuffer trigidentity;
19229 : : char *qtabname;
19230 : : char *tag;
19231 : :
19232 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 19233 [ + + ]: 553 : if (!dopt->dumpSchema)
8422 tgl@sss.pgh.pa.us 19234 : 31 : return;
19235 : :
7945 19236 : 522 : query = createPQExpBuffer();
19237 : 522 : delqry = createPQExpBuffer();
2749 19238 : 522 : trigprefix = createPQExpBuffer();
2005 alvherre@alvh.no-ip. 19239 : 522 : trigidentity = createPQExpBuffer();
19240 : :
2749 tgl@sss.pgh.pa.us 19241 : 522 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19242 : :
2005 alvherre@alvh.no-ip. 19243 : 522 : appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
19244 : 522 : appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
19245 : :
601 peter@eisentraut.org 19246 : 522 : appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
2005 alvherre@alvh.no-ip. 19247 : 522 : appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
19248 : :
19249 : : /* Triggers can depend on extensions */
19250 : 522 : append_depends_on_extension(fout, query, &tginfo->dobj,
19251 : : "pg_catalog.pg_trigger", "TRIGGER",
19252 : 522 : trigidentity->data);
19253 : :
1340 19254 [ + + ]: 522 : if (tginfo->tgispartition)
19255 : : {
19256 [ - + ]: 127 : Assert(tbinfo->ispartition);
19257 : :
19258 : : /*
19259 : : * Partition triggers only appear here because their 'tgenabled' flag
19260 : : * differs from its parent's. The trigger is created already, so
19261 : : * remove the CREATE and replace it with an ALTER. (Clear out the
19262 : : * DROP query too, so that pg_dump --create does not cause errors.)
19263 : : */
1513 19264 : 127 : resetPQExpBuffer(query);
19265 : 127 : resetPQExpBuffer(delqry);
19266 : 127 : appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
19267 [ - + ]: 127 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
19268 : 127 : fmtQualifiedDumpable(tbinfo));
19269 [ + - + + : 127 : switch (tginfo->tgenabled)
- ]
19270 : : {
19271 : 44 : case 'f':
19272 : : case 'D':
19273 : 44 : appendPQExpBufferStr(query, "DISABLE");
19274 : 44 : break;
1513 alvherre@alvh.no-ip. 19275 :UBC 0 : case 't':
19276 : : case 'O':
19277 : 0 : appendPQExpBufferStr(query, "ENABLE");
19278 : 0 : break;
1513 alvherre@alvh.no-ip. 19279 :CBC 39 : case 'R':
19280 : 39 : appendPQExpBufferStr(query, "ENABLE REPLICA");
19281 : 39 : break;
19282 : 44 : case 'A':
19283 : 44 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
19284 : 44 : break;
19285 : : }
19286 : 127 : appendPQExpBuffer(query, " TRIGGER %s;\n",
19287 : 127 : fmtId(tginfo->dobj.name));
19288 : : }
19289 [ + - - + ]: 395 : else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
19290 : : {
1996 alvherre@alvh.no-ip. 19291 :UBC 0 : appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
19292 [ # # ]: 0 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
2749 tgl@sss.pgh.pa.us 19293 : 0 : fmtQualifiedDumpable(tbinfo));
6746 JanWieck@Yahoo.com 19294 [ # # # # ]: 0 : switch (tginfo->tgenabled)
19295 : : {
19296 : 0 : case 'D':
19297 : : case 'f':
4310 heikki.linnakangas@i 19298 : 0 : appendPQExpBufferStr(query, "DISABLE");
6746 JanWieck@Yahoo.com 19299 : 0 : break;
19300 : 0 : case 'A':
4310 heikki.linnakangas@i 19301 : 0 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
6746 JanWieck@Yahoo.com 19302 : 0 : break;
19303 : 0 : case 'R':
4310 heikki.linnakangas@i 19304 : 0 : appendPQExpBufferStr(query, "ENABLE REPLICA");
6746 JanWieck@Yahoo.com 19305 : 0 : break;
19306 : 0 : default:
4310 heikki.linnakangas@i 19307 : 0 : appendPQExpBufferStr(query, "ENABLE");
6746 JanWieck@Yahoo.com 19308 : 0 : break;
19309 : : }
19310 : 0 : appendPQExpBuffer(query, " TRIGGER %s;\n",
7319 tgl@sss.pgh.pa.us 19311 : 0 : fmtId(tginfo->dobj.name));
19312 : : }
19313 : :
2749 tgl@sss.pgh.pa.us 19314 :CBC 522 : appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
5323 19315 : 522 : fmtId(tginfo->dobj.name));
19316 : :
3481 peter_e@gmx.net 19317 : 522 : tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
19318 : :
3440 sfrost@snowman.net 19319 [ + - ]: 522 : if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19320 : 522 : ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 19321 : 522 : ARCHIVE_OPTS(.tag = tag,
19322 : : .namespace = tbinfo->dobj.namespace->dobj.name,
19323 : : .owner = tbinfo->rolname,
19324 : : .description = "TRIGGER",
19325 : : .section = SECTION_POST_DATA,
19326 : : .createStmt = query->data,
19327 : : .dropStmt = delqry->data));
19328 : :
3440 sfrost@snowman.net 19329 [ - + ]: 522 : if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 19330 :UBC 0 : dumpComment(fout, trigprefix->data, qtabname,
3440 sfrost@snowman.net 19331 : 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19332 : 0 : tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
19333 : :
3481 peter_e@gmx.net 19334 :CBC 522 : free(tag);
7945 tgl@sss.pgh.pa.us 19335 : 522 : destroyPQExpBuffer(query);
19336 : 522 : destroyPQExpBuffer(delqry);
2749 19337 : 522 : destroyPQExpBuffer(trigprefix);
2005 alvherre@alvh.no-ip. 19338 : 522 : destroyPQExpBuffer(trigidentity);
2749 tgl@sss.pgh.pa.us 19339 : 522 : free(qtabname);
19340 : : }
19341 : :
19342 : : /*
19343 : : * dumpEventTrigger
19344 : : * write the declaration of one user-defined event trigger
19345 : : */
19346 : : static void
1669 peter@eisentraut.org 19347 : 48 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
19348 : : {
3524 tgl@sss.pgh.pa.us 19349 : 48 : DumpOptions *dopt = fout->dopt;
19350 : : PQExpBuffer query;
19351 : : PQExpBuffer delqry;
19352 : : char *qevtname;
19353 : :
19354 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 19355 [ + + ]: 48 : if (!dopt->dumpSchema)
4268 tgl@sss.pgh.pa.us 19356 : 6 : return;
19357 : :
4798 rhaas@postgresql.org 19358 : 42 : query = createPQExpBuffer();
2968 tgl@sss.pgh.pa.us 19359 : 42 : delqry = createPQExpBuffer();
19360 : :
2749 19361 : 42 : qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
19362 : :
4310 heikki.linnakangas@i 19363 : 42 : appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
2749 tgl@sss.pgh.pa.us 19364 : 42 : appendPQExpBufferStr(query, qevtname);
4310 heikki.linnakangas@i 19365 : 42 : appendPQExpBufferStr(query, " ON ");
4798 rhaas@postgresql.org 19366 : 42 : appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
19367 : :
19368 [ + + ]: 42 : if (strcmp("", evtinfo->evttags) != 0)
19369 : : {
19370 : 5 : appendPQExpBufferStr(query, "\n WHEN TAG IN (");
19371 : 5 : appendPQExpBufferStr(query, evtinfo->evttags);
3719 heikki.linnakangas@i 19372 : 5 : appendPQExpBufferChar(query, ')');
19373 : : }
19374 : :
2403 peter@eisentraut.org 19375 : 42 : appendPQExpBufferStr(query, "\n EXECUTE FUNCTION ");
4798 rhaas@postgresql.org 19376 : 42 : appendPQExpBufferStr(query, evtinfo->evtfname);
4310 heikki.linnakangas@i 19377 : 42 : appendPQExpBufferStr(query, "();\n");
19378 : :
4798 rhaas@postgresql.org 19379 [ - + ]: 42 : if (evtinfo->evtenabled != 'O')
19380 : : {
4798 rhaas@postgresql.org 19381 :UBC 0 : appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
19382 : : qevtname);
19383 [ # # # # ]: 0 : switch (evtinfo->evtenabled)
19384 : : {
19385 : 0 : case 'D':
4310 heikki.linnakangas@i 19386 : 0 : appendPQExpBufferStr(query, "DISABLE");
4798 rhaas@postgresql.org 19387 : 0 : break;
19388 : 0 : case 'A':
4310 heikki.linnakangas@i 19389 : 0 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
4798 rhaas@postgresql.org 19390 : 0 : break;
19391 : 0 : case 'R':
4310 heikki.linnakangas@i 19392 : 0 : appendPQExpBufferStr(query, "ENABLE REPLICA");
4798 rhaas@postgresql.org 19393 : 0 : break;
19394 : 0 : default:
4310 heikki.linnakangas@i 19395 : 0 : appendPQExpBufferStr(query, "ENABLE");
4798 rhaas@postgresql.org 19396 : 0 : break;
19397 : : }
4310 heikki.linnakangas@i 19398 : 0 : appendPQExpBufferStr(query, ";\n");
19399 : : }
19400 : :
2968 tgl@sss.pgh.pa.us 19401 :CBC 42 : appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
19402 : : qevtname);
19403 : :
2587 19404 [ + + ]: 42 : if (dopt->binary_upgrade)
19405 : 2 : binary_upgrade_extension_member(query, &evtinfo->dobj,
19406 : : "EVENT TRIGGER", qevtname, NULL);
19407 : :
3440 sfrost@snowman.net 19408 [ + - ]: 42 : if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19409 : 42 : ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 19410 : 42 : ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
19411 : : .owner = evtinfo->evtowner,
19412 : : .description = "EVENT TRIGGER",
19413 : : .section = SECTION_POST_DATA,
19414 : : .createStmt = query->data,
19415 : : .dropStmt = delqry->data));
19416 : :
3440 sfrost@snowman.net 19417 [ - + ]: 42 : if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 19418 :UBC 0 : dumpComment(fout, "EVENT TRIGGER", qevtname,
3440 sfrost@snowman.net 19419 : 0 : NULL, evtinfo->evtowner,
19420 : 0 : evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
19421 : :
4798 rhaas@postgresql.org 19422 :CBC 42 : destroyPQExpBuffer(query);
2968 tgl@sss.pgh.pa.us 19423 : 42 : destroyPQExpBuffer(delqry);
2749 19424 : 42 : free(qevtname);
19425 : : }
19426 : :
19427 : : /*
19428 : : * dumpRule
19429 : : * Dump a rule
19430 : : */
19431 : : static void
1669 peter@eisentraut.org 19432 : 1223 : dumpRule(Archive *fout, const RuleInfo *rinfo)
19433 : : {
3524 tgl@sss.pgh.pa.us 19434 : 1223 : DumpOptions *dopt = fout->dopt;
7945 19435 : 1223 : TableInfo *tbinfo = rinfo->ruletable;
19436 : : bool is_view;
19437 : : PQExpBuffer query;
19438 : : PQExpBuffer cmd;
19439 : : PQExpBuffer delcmd;
19440 : : PQExpBuffer ruleprefix;
19441 : : char *qtabname;
19442 : : PGresult *res;
19443 : : char *tag;
19444 : :
19445 : : /* Do nothing if not dumping schema */
285 nathan@postgresql.or 19446 [ + + ]: 1223 : if (!dopt->dumpSchema)
7945 tgl@sss.pgh.pa.us 19447 : 66 : return;
19448 : :
19449 : : /*
19450 : : * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
19451 : : * we do not want to dump it as a separate object.
19452 : : */
7571 19453 [ + + ]: 1157 : if (!rinfo->separate)
7945 19454 : 946 : return;
19455 : :
19456 : : /*
19457 : : * If it's an ON SELECT rule, we want to print it as a view definition,
19458 : : * instead of a rule.
19459 : : */
3215 19460 [ + + + - ]: 211 : is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
19461 : :
7945 19462 : 211 : query = createPQExpBuffer();
19463 : 211 : cmd = createPQExpBuffer();
19464 : 211 : delcmd = createPQExpBuffer();
2749 19465 : 211 : ruleprefix = createPQExpBuffer();
19466 : :
19467 : 211 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19468 : :
3215 19469 [ + + ]: 211 : if (is_view)
19470 : : {
19471 : : PQExpBuffer result;
19472 : :
19473 : : /*
19474 : : * We need OR REPLACE here because we'll be replacing a dummy view.
19475 : : * Otherwise this should look largely like the regular view dump code.
19476 : : */
19477 : 10 : appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
2749 19478 : 10 : fmtQualifiedDumpable(tbinfo));
3215 19479 [ - + ]: 10 : if (nonemptyReloptions(tbinfo->reloptions))
19480 : : {
3215 tgl@sss.pgh.pa.us 19481 :UBC 0 : appendPQExpBufferStr(cmd, " WITH (");
19482 : 0 : appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
19483 : 0 : appendPQExpBufferChar(cmd, ')');
19484 : : }
3215 tgl@sss.pgh.pa.us 19485 :CBC 10 : result = createViewAsClause(fout, tbinfo);
19486 : 10 : appendPQExpBuffer(cmd, " AS\n%s", result->data);
19487 : 10 : destroyPQExpBuffer(result);
19488 [ - + ]: 10 : if (tbinfo->checkoption != NULL)
3215 tgl@sss.pgh.pa.us 19489 :UBC 0 : appendPQExpBuffer(cmd, "\n WITH %s CHECK OPTION",
19490 : : tbinfo->checkoption);
3215 tgl@sss.pgh.pa.us 19491 :CBC 10 : appendPQExpBufferStr(cmd, ";\n");
19492 : : }
19493 : : else
19494 : : {
19495 : : /* In the rule case, just print pg_get_ruledef's result verbatim */
19496 : 201 : appendPQExpBuffer(query,
19497 : : "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
19498 : 201 : rinfo->dobj.catId.oid);
19499 : :
19500 : 201 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19501 : :
19502 [ - + ]: 201 : if (PQntuples(res) != 1)
1247 tgl@sss.pgh.pa.us 19503 :UBC 0 : pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
19504 : : rinfo->dobj.name, tbinfo->dobj.name);
19505 : :
3215 tgl@sss.pgh.pa.us 19506 :CBC 201 : printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
19507 : :
19508 : 201 : PQclear(res);
19509 : : }
19510 : :
19511 : : /*
19512 : : * Add the command to alter the rules replication firing semantics if it
19513 : : * differs from the default.
19514 : : */
6746 JanWieck@Yahoo.com 19515 [ + + ]: 211 : if (rinfo->ev_enabled != 'O')
19516 : : {
2749 tgl@sss.pgh.pa.us 19517 : 15 : appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
6746 JanWieck@Yahoo.com 19518 [ - - + - ]: 15 : switch (rinfo->ev_enabled)
19519 : : {
6746 JanWieck@Yahoo.com 19520 :UBC 0 : case 'A':
19521 : 0 : appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
6505 bruce@momjian.us 19522 : 0 : fmtId(rinfo->dobj.name));
6746 JanWieck@Yahoo.com 19523 : 0 : break;
19524 : 0 : case 'R':
19525 : 0 : appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
6505 bruce@momjian.us 19526 : 0 : fmtId(rinfo->dobj.name));
6746 JanWieck@Yahoo.com 19527 : 0 : break;
6746 JanWieck@Yahoo.com 19528 :CBC 15 : case 'D':
19529 : 15 : appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
6505 bruce@momjian.us 19530 : 15 : fmtId(rinfo->dobj.name));
6746 JanWieck@Yahoo.com 19531 : 15 : break;
19532 : : }
19533 : : }
19534 : :
3215 tgl@sss.pgh.pa.us 19535 [ + + ]: 211 : if (is_view)
19536 : : {
19537 : : /*
19538 : : * We can't DROP a view's ON SELECT rule. Instead, use CREATE OR
19539 : : * REPLACE VIEW to replace the rule with something with minimal
19540 : : * dependencies.
19541 : : */
19542 : : PQExpBuffer result;
19543 : :
2749 19544 : 10 : appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
19545 : 10 : fmtQualifiedDumpable(tbinfo));
3215 19546 : 10 : result = createDummyViewAsClause(fout, tbinfo);
19547 : 10 : appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
19548 : 10 : destroyPQExpBuffer(result);
19549 : : }
19550 : : else
19551 : : {
19552 : 201 : appendPQExpBuffer(delcmd, "DROP RULE %s ",
19553 : 201 : fmtId(rinfo->dobj.name));
2749 19554 : 201 : appendPQExpBuffer(delcmd, "ON %s;\n",
19555 : 201 : fmtQualifiedDumpable(tbinfo));
19556 : : }
19557 : :
19558 : 211 : appendPQExpBuffer(ruleprefix, "RULE %s ON",
5323 19559 : 211 : fmtId(rinfo->dobj.name));
19560 : :
3481 peter_e@gmx.net 19561 : 211 : tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
19562 : :
3440 sfrost@snowman.net 19563 [ + - ]: 211 : if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19564 : 211 : ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
2409 alvherre@alvh.no-ip. 19565 : 211 : ARCHIVE_OPTS(.tag = tag,
19566 : : .namespace = tbinfo->dobj.namespace->dobj.name,
19567 : : .owner = tbinfo->rolname,
19568 : : .description = "RULE",
19569 : : .section = SECTION_POST_DATA,
19570 : : .createStmt = cmd->data,
19571 : : .dropStmt = delcmd->data));
19572 : :
19573 : : /* Dump rule comments */
3440 sfrost@snowman.net 19574 [ - + ]: 211 : if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2749 tgl@sss.pgh.pa.us 19575 :UBC 0 : dumpComment(fout, ruleprefix->data, qtabname,
3440 sfrost@snowman.net 19576 : 0 : tbinfo->dobj.namespace->dobj.name,
19577 : : tbinfo->rolname,
19578 : 0 : rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
19579 : :
3481 peter_e@gmx.net 19580 :CBC 211 : free(tag);
8520 tgl@sss.pgh.pa.us 19581 : 211 : destroyPQExpBuffer(query);
7945 19582 : 211 : destroyPQExpBuffer(cmd);
19583 : 211 : destroyPQExpBuffer(delcmd);
2749 19584 : 211 : destroyPQExpBuffer(ruleprefix);
19585 : 211 : free(qtabname);
19586 : : }
19587 : :
19588 : : /*
19589 : : * getExtensionMembership --- obtain extension membership data
19590 : : *
19591 : : * We need to identify objects that are extension members as soon as they're
19592 : : * loaded, so that we can correctly determine whether they need to be dumped.
19593 : : * Generally speaking, extension member objects will get marked as *not* to
19594 : : * be dumped, as they will be recreated by the single CREATE EXTENSION
19595 : : * command. However, in binary upgrade mode we still need to dump the members
19596 : : * individually.
19597 : : */
19598 : : void
3524 19599 : 186 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
19600 : : int numExtensions)
19601 : : {
19602 : : PQExpBuffer query;
19603 : : PGresult *res;
19604 : : int ntups,
19605 : : i;
19606 : : int i_classid,
19607 : : i_objid,
19608 : : i_refobjid;
19609 : : ExtensionInfo *ext;
19610 : :
19611 : : /* Nothing to do if no extensions */
5323 19612 [ - + ]: 186 : if (numExtensions == 0)
5323 tgl@sss.pgh.pa.us 19613 :UBC 0 : return;
19614 : :
5323 tgl@sss.pgh.pa.us 19615 :CBC 186 : query = createPQExpBuffer();
19616 : :
19617 : : /* refclassid constraint is redundant but may speed the search */
4310 heikki.linnakangas@i 19618 : 186 : appendPQExpBufferStr(query, "SELECT "
19619 : : "classid, objid, refobjid "
19620 : : "FROM pg_depend "
19621 : : "WHERE refclassid = 'pg_extension'::regclass "
19622 : : "AND deptype = 'e' "
19623 : : "ORDER BY 3");
19624 : :
4960 rhaas@postgresql.org 19625 : 186 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19626 : :
5323 tgl@sss.pgh.pa.us 19627 : 186 : ntups = PQntuples(res);
19628 : :
19629 : 186 : i_classid = PQfnumber(res, "classid");
19630 : 186 : i_objid = PQfnumber(res, "objid");
19631 : 186 : i_refobjid = PQfnumber(res, "refobjid");
19632 : :
19633 : : /*
19634 : : * Since we ordered the SELECT by referenced ID, we can expect that
19635 : : * multiple entries for the same extension will appear together; this
19636 : : * saves on searches.
19637 : : */
3524 19638 : 186 : ext = NULL;
19639 : :
5323 19640 [ + + ]: 1530 : for (i = 0; i < ntups; i++)
19641 : : {
19642 : : CatalogId objId;
19643 : : Oid extId;
19644 : :
19645 : 1344 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
19646 : 1344 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
3524 19647 : 1344 : extId = atooid(PQgetvalue(res, i, i_refobjid));
19648 : :
19649 [ + + ]: 1344 : if (ext == NULL ||
19650 [ + + ]: 1158 : ext->dobj.catId.oid != extId)
19651 : 211 : ext = findExtensionByOid(extId);
19652 : :
19653 [ - + ]: 1344 : if (ext == NULL)
19654 : : {
19655 : : /* shouldn't happen */
2350 peter@eisentraut.org 19656 :UBC 0 : pg_log_warning("could not find referenced extension %u", extId);
5323 tgl@sss.pgh.pa.us 19657 : 0 : continue;
19658 : : }
19659 : :
1415 tgl@sss.pgh.pa.us 19660 :CBC 1344 : recordExtensionMembership(objId, ext);
19661 : : }
19662 : :
3524 19663 : 186 : PQclear(res);
19664 : :
19665 : 186 : destroyPQExpBuffer(query);
19666 : : }
19667 : :
19668 : : /*
19669 : : * processExtensionTables --- deal with extension configuration tables
19670 : : *
19671 : : * There are two parts to this process:
19672 : : *
19673 : : * 1. Identify and create dump records for extension configuration tables.
19674 : : *
19675 : : * Extensions can mark tables as "configuration", which means that the user
19676 : : * is able and expected to modify those tables after the extension has been
19677 : : * loaded. For these tables, we dump out only the data- the structure is
19678 : : * expected to be handled at CREATE EXTENSION time, including any indexes or
19679 : : * foreign keys, which brings us to-
19680 : : *
19681 : : * 2. Record FK dependencies between configuration tables.
19682 : : *
19683 : : * Due to the FKs being created at CREATE EXTENSION time and therefore before
19684 : : * the data is loaded, we have to work out what the best order for reloading
19685 : : * the data is, to avoid FK violations when the tables are restored. This is
19686 : : * not perfect- we can't handle circular dependencies and if any exist they
19687 : : * will cause an invalid dump to be produced (though at least all of the data
19688 : : * is included for a user to manually restore). This is currently documented
19689 : : * but perhaps we can provide a better solution in the future.
19690 : : */
19691 : : void
19692 : 185 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
19693 : : int numExtensions)
19694 : : {
19695 : 185 : DumpOptions *dopt = fout->dopt;
19696 : : PQExpBuffer query;
19697 : : PGresult *res;
19698 : : int ntups,
19699 : : i;
19700 : : int i_conrelid,
19701 : : i_confrelid;
19702 : :
19703 : : /* Nothing to do if no extensions */
19704 [ - + ]: 185 : if (numExtensions == 0)
3524 tgl@sss.pgh.pa.us 19705 :UBC 0 : return;
19706 : :
19707 : : /*
19708 : : * Identify extension configuration tables and create TableDataInfo
19709 : : * objects for them, ensuring their data will be dumped even though the
19710 : : * tables themselves won't be.
19711 : : *
19712 : : * Note that we create TableDataInfo objects even in schema-only mode, ie,
19713 : : * user data in a configuration table is treated like schema data. This
19714 : : * seems appropriate since system data in a config table would get
19715 : : * reloaded by CREATE EXTENSION. If the extension is not listed in the
19716 : : * list of extensions to be included, none of its data is dumped.
19717 : : */
5323 tgl@sss.pgh.pa.us 19718 [ + + ]:CBC 395 : for (i = 0; i < numExtensions; i++)
19719 : : {
4957 19720 : 210 : ExtensionInfo *curext = &(extinfo[i]);
19721 : 210 : char *extconfig = curext->extconfig;
19722 : 210 : char *extcondition = curext->extcondition;
5263 bruce@momjian.us 19723 : 210 : char **extconfigarray = NULL;
19724 : 210 : char **extconditionarray = NULL;
1752 michael@paquier.xyz 19725 : 210 : int nconfigitems = 0;
19726 : 210 : int nconditionitems = 0;
19727 : :
19728 : : /*
19729 : : * Check if this extension is listed as to include in the dump. If
19730 : : * not, any table data associated with it is discarded.
19731 : : */
1605 19732 [ + + ]: 210 : if (extension_include_oids.head != NULL &&
19733 [ + + ]: 8 : !simple_oid_list_member(&extension_include_oids,
19734 : : curext->dobj.catId.oid))
19735 : 6 : continue;
19736 : :
19737 : : /*
19738 : : * Check if this extension is listed as to exclude in the dump. If
19739 : : * yes, any table data associated with it is discarded.
19740 : : */
535 dean.a.rasheed@gmail 19741 [ + + + + ]: 210 : if (extension_exclude_oids.head != NULL &&
19742 : 4 : simple_oid_list_member(&extension_exclude_oids,
19743 : : curext->dobj.catId.oid))
19744 : 2 : continue;
19745 : :
1752 michael@paquier.xyz 19746 [ + + - + ]: 204 : if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
19747 : : {
19748 : : int j;
19749 : :
19750 [ - + ]: 20 : if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
1247 tgl@sss.pgh.pa.us 19751 :UBC 0 : pg_fatal("could not parse %s array", "extconfig");
1752 michael@paquier.xyz 19752 [ - + ]:CBC 20 : if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
1247 tgl@sss.pgh.pa.us 19753 :UBC 0 : pg_fatal("could not parse %s array", "extcondition");
1752 michael@paquier.xyz 19754 [ - + ]:CBC 20 : if (nconfigitems != nconditionitems)
1247 tgl@sss.pgh.pa.us 19755 :UBC 0 : pg_fatal("mismatched number of configurations and conditions for extension");
19756 : :
5323 tgl@sss.pgh.pa.us 19757 [ + + ]:CBC 60 : for (j = 0; j < nconfigitems; j++)
19758 : : {
19759 : : TableInfo *configtbl;
4516 mail@joeconway.com 19760 : 40 : Oid configtbloid = atooid(extconfigarray[j]);
3440 sfrost@snowman.net 19761 : 40 : bool dumpobj =
841 tgl@sss.pgh.pa.us 19762 : 40 : curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
19763 : :
4516 mail@joeconway.com 19764 : 40 : configtbl = findTableByOid(configtbloid);
4959 tgl@sss.pgh.pa.us 19765 [ - + ]: 40 : if (configtbl == NULL)
4959 tgl@sss.pgh.pa.us 19766 :UBC 0 : continue;
19767 : :
19768 : : /*
19769 : : * Tables of not-to-be-dumped extensions shouldn't be dumped
19770 : : * unless the table or its schema is explicitly included
19771 : : */
3440 sfrost@snowman.net 19772 [ + + ]:CBC 40 : if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
19773 : : {
19774 : : /* check table explicitly requested */
4516 mail@joeconway.com 19775 [ - + - - ]: 2 : if (table_include_oids.head != NULL &&
4516 mail@joeconway.com 19776 :UBC 0 : simple_oid_list_member(&table_include_oids,
19777 : : configtbloid))
19778 : 0 : dumpobj = true;
19779 : :
19780 : : /* check table's schema explicitly requested */
3440 sfrost@snowman.net 19781 [ + - ]:CBC 2 : if (configtbl->dobj.namespace->dobj.dump &
19782 : : DUMP_COMPONENT_DATA)
4516 mail@joeconway.com 19783 : 2 : dumpobj = true;
19784 : : }
19785 : :
19786 : : /* check table excluded by an exclusion switch */
19787 [ + + + + ]: 44 : if (table_exclude_oids.head != NULL &&
19788 : 4 : simple_oid_list_member(&table_exclude_oids,
19789 : : configtbloid))
19790 : 1 : dumpobj = false;
19791 : :
19792 : : /* check schema excluded by an exclusion switch */
19793 [ - + ]: 40 : if (simple_oid_list_member(&schema_exclude_oids,
2999 tgl@sss.pgh.pa.us 19794 : 40 : configtbl->dobj.namespace->dobj.catId.oid))
4516 mail@joeconway.com 19795 :UBC 0 : dumpobj = false;
19796 : :
4516 mail@joeconway.com 19797 [ + + ]:CBC 40 : if (dumpobj)
19798 : : {
2482 andres@anarazel.de 19799 : 39 : makeTableDataInfo(dopt, configtbl);
4516 mail@joeconway.com 19800 [ + - ]: 39 : if (configtbl->dataObj != NULL)
19801 : : {
19802 [ - + ]: 39 : if (strlen(extconditionarray[j]) > 0)
4516 mail@joeconway.com 19803 :UBC 0 : configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
19804 : : }
19805 : : }
19806 : : }
19807 : : }
5323 tgl@sss.pgh.pa.us 19808 [ + + ]:CBC 204 : if (extconfigarray)
19809 : 20 : free(extconfigarray);
19810 [ + + ]: 204 : if (extconditionarray)
19811 : 20 : free(extconditionarray);
19812 : : }
19813 : :
19814 : : /*
19815 : : * Now that all the TableDataInfo objects have been created for all the
19816 : : * extensions, check their FK dependencies and register them to try and
19817 : : * dump the data out in an order that they can be restored in.
19818 : : *
19819 : : * Note that this is not a problem for user tables as their FKs are
19820 : : * recreated after the data has been loaded.
19821 : : */
19822 : :
3524 19823 : 185 : query = createPQExpBuffer();
19824 : :
3841 sfrost@snowman.net 19825 : 185 : printfPQExpBuffer(query,
19826 : : "SELECT conrelid, confrelid "
19827 : : "FROM pg_constraint "
19828 : : "JOIN pg_depend ON (objid = confrelid) "
19829 : : "WHERE contype = 'f' "
19830 : : "AND refclassid = 'pg_extension'::regclass "
19831 : : "AND classid = 'pg_class'::regclass;");
19832 : :
19833 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19834 : 185 : ntups = PQntuples(res);
19835 : :
19836 : 185 : i_conrelid = PQfnumber(res, "conrelid");
19837 : 185 : i_confrelid = PQfnumber(res, "confrelid");
19838 : :
19839 : : /* Now get the dependencies and register them */
19840 [ - + ]: 185 : for (i = 0; i < ntups; i++)
19841 : : {
19842 : : Oid conrelid,
19843 : : confrelid;
19844 : : TableInfo *reftable,
19845 : : *contable;
19846 : :
3841 sfrost@snowman.net 19847 :UBC 0 : conrelid = atooid(PQgetvalue(res, i, i_conrelid));
19848 : 0 : confrelid = atooid(PQgetvalue(res, i, i_confrelid));
19849 : 0 : contable = findTableByOid(conrelid);
19850 : 0 : reftable = findTableByOid(confrelid);
19851 : :
19852 [ # # ]: 0 : if (reftable == NULL ||
19853 [ # # # # ]: 0 : reftable->dataObj == NULL ||
19854 : 0 : contable == NULL ||
19855 [ # # ]: 0 : contable->dataObj == NULL)
19856 : 0 : continue;
19857 : :
19858 : : /*
19859 : : * Make referencing TABLE_DATA object depend on the referenced table's
19860 : : * TABLE_DATA object.
19861 : : */
19862 : 0 : addObjectDependency(&contable->dataObj->dobj,
19863 : 0 : reftable->dataObj->dobj.dumpId);
19864 : : }
3709 tgl@sss.pgh.pa.us 19865 :CBC 185 : PQclear(res);
5323 19866 : 185 : destroyPQExpBuffer(query);
19867 : : }
19868 : :
19869 : : /*
19870 : : * getDependencies --- obtain available dependency data
19871 : : */
19872 : : static void
4961 rhaas@postgresql.org 19873 : 185 : getDependencies(Archive *fout)
19874 : : {
19875 : : PQExpBuffer query;
19876 : : PGresult *res;
19877 : : int ntups,
19878 : : i;
19879 : : int i_classid,
19880 : : i_objid,
19881 : : i_refclassid,
19882 : : i_refobjid,
19883 : : i_deptype;
19884 : : DumpableObject *dobj,
19885 : : *refdobj;
19886 : :
2350 peter@eisentraut.org 19887 : 185 : pg_log_info("reading dependency data");
19888 : :
7945 tgl@sss.pgh.pa.us 19889 : 185 : query = createPQExpBuffer();
19890 : :
19891 : : /*
19892 : : * Messy query to collect the dependency data we need. Note that we
19893 : : * ignore the sub-object column, so that dependencies of or on a column
19894 : : * look the same as dependencies of or on a whole table.
19895 : : *
19896 : : * PIN dependencies aren't interesting, and EXTENSION dependencies were
19897 : : * already processed by getExtensionMembership.
19898 : : */
4310 heikki.linnakangas@i 19899 : 185 : appendPQExpBufferStr(query, "SELECT "
19900 : : "classid, objid, refclassid, refobjid, deptype "
19901 : : "FROM pg_depend "
19902 : : "WHERE deptype != 'p' AND deptype != 'e'\n");
19903 : :
19904 : : /*
19905 : : * Since we don't treat pg_amop entries as separate DumpableObjects, we
19906 : : * have to translate their dependencies into dependencies of their parent
19907 : : * opfamily. Ignore internal dependencies though, as those will point to
19908 : : * their parent opclass, which we needn't consider here (and if we did,
19909 : : * it'd just result in circular dependencies). Also, "loose" opfamily
19910 : : * entries will have dependencies on their parent opfamily, which we
19911 : : * should drop since they'd likewise become useless self-dependencies.
19912 : : * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
19913 : : */
1362 tgl@sss.pgh.pa.us 19914 : 185 : appendPQExpBufferStr(query, "UNION ALL\n"
19915 : : "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
19916 : : "FROM pg_depend d, pg_amop o "
19917 : : "WHERE deptype NOT IN ('p', 'e', 'i') AND "
19918 : : "classid = 'pg_amop'::regclass AND objid = o.oid "
19919 : : "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
19920 : :
19921 : : /* Likewise for pg_amproc entries */
19922 : 185 : appendPQExpBufferStr(query, "UNION ALL\n"
19923 : : "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
19924 : : "FROM pg_depend d, pg_amproc p "
19925 : : "WHERE deptype NOT IN ('p', 'e', 'i') AND "
19926 : : "classid = 'pg_amproc'::regclass AND objid = p.oid "
19927 : : "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
19928 : :
19929 : : /* Sort the output for efficiency below */
2229 19930 : 185 : appendPQExpBufferStr(query, "ORDER BY 1,2");
19931 : :
4960 rhaas@postgresql.org 19932 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19933 : :
7945 tgl@sss.pgh.pa.us 19934 : 185 : ntups = PQntuples(res);
19935 : :
19936 : 185 : i_classid = PQfnumber(res, "classid");
19937 : 185 : i_objid = PQfnumber(res, "objid");
19938 : 185 : i_refclassid = PQfnumber(res, "refclassid");
19939 : 185 : i_refobjid = PQfnumber(res, "refobjid");
19940 : 185 : i_deptype = PQfnumber(res, "deptype");
19941 : :
19942 : : /*
19943 : : * Since we ordered the SELECT by referencing ID, we can expect that
19944 : : * multiple entries for the same object will appear together; this saves
19945 : : * on searches.
19946 : : */
19947 : 185 : dobj = NULL;
19948 : :
19949 [ + + ]: 402500 : for (i = 0; i < ntups; i++)
19950 : : {
19951 : : CatalogId objId;
19952 : : CatalogId refobjId;
19953 : : char deptype;
19954 : :
19955 : 402315 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
19956 : 402315 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
19957 : 402315 : refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
19958 : 402315 : refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
19959 : 402315 : deptype = *(PQgetvalue(res, i, i_deptype));
19960 : :
19961 [ + + ]: 402315 : if (dobj == NULL ||
19962 [ + + ]: 376636 : dobj->catId.tableoid != objId.tableoid ||
19963 [ + + ]: 374445 : dobj->catId.oid != objId.oid)
19964 : 177586 : dobj = findObjectByCatalogId(objId);
19965 : :
19966 : : /*
19967 : : * Failure to find objects mentioned in pg_depend is not unexpected,
19968 : : * since for example we don't collect info about TOAST tables.
19969 : : */
19970 [ + + ]: 402315 : if (dobj == NULL)
19971 : : {
19972 : : #ifdef NOT_USED
19973 : : pg_log_warning("no referencing object %u %u",
19974 : : objId.tableoid, objId.oid);
19975 : : #endif
19976 : 26343 : continue;
19977 : : }
19978 : :
19979 : 376821 : refdobj = findObjectByCatalogId(refobjId);
19980 : :
19981 [ + + ]: 376821 : if (refdobj == NULL)
19982 : : {
19983 : : #ifdef NOT_USED
19984 : : pg_log_warning("no referenced object %u %u",
19985 : : refobjId.tableoid, refobjId.oid);
19986 : : #endif
19987 : 849 : continue;
19988 : : }
19989 : :
19990 : : /*
19991 : : * For 'x' dependencies, mark the object for later; we still add the
19992 : : * normal dependency, for possible ordering purposes. Currently
19993 : : * pg_dump_sort.c knows to put extensions ahead of all object types
19994 : : * that could possibly depend on them, but this is safer.
19995 : : */
2005 alvherre@alvh.no-ip. 19996 [ + + ]: 375972 : if (deptype == 'x')
19997 : 44 : dobj->depends_on_ext = true;
19998 : :
19999 : : /*
20000 : : * Ordinarily, table rowtypes have implicit dependencies on their
20001 : : * tables. However, for a composite type the implicit dependency goes
20002 : : * the other way in pg_depend; which is the right thing for DROP but
20003 : : * it doesn't produce the dependency ordering we need. So in that one
20004 : : * case, we reverse the direction of the dependency.
20005 : : */
7543 tgl@sss.pgh.pa.us 20006 [ + + ]: 375972 : if (deptype == 'i' &&
20007 [ + + ]: 105925 : dobj->objType == DO_TABLE &&
20008 [ + + ]: 1280 : refdobj->objType == DO_TYPE)
20009 : 188 : addObjectDependency(refdobj, dobj->dumpId);
20010 : : else
20011 : : /* normal case */
20012 : 375784 : addObjectDependency(dobj, refdobj->dumpId);
20013 : : }
20014 : :
7945 20015 : 185 : PQclear(res);
20016 : :
8800 20017 : 185 : destroyPQExpBuffer(query);
9832 bruce@momjian.us 20018 : 185 : }
20019 : :
20020 : :
20021 : : /*
20022 : : * createBoundaryObjects - create dummy DumpableObjects to represent
20023 : : * dump section boundaries.
20024 : : */
20025 : : static DumpableObject *
4821 tgl@sss.pgh.pa.us 20026 : 185 : createBoundaryObjects(void)
20027 : : {
20028 : : DumpableObject *dobjs;
20029 : :
20030 : 185 : dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
20031 : :
20032 : 185 : dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
20033 : 185 : dobjs[0].catId = nilCatalogId;
20034 : 185 : AssignDumpId(dobjs + 0);
20035 : 185 : dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
20036 : :
20037 : 185 : dobjs[1].objType = DO_POST_DATA_BOUNDARY;
20038 : 185 : dobjs[1].catId = nilCatalogId;
20039 : 185 : AssignDumpId(dobjs + 1);
20040 : 185 : dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
20041 : :
20042 : 185 : return dobjs;
20043 : : }
20044 : :
20045 : : /*
20046 : : * addBoundaryDependencies - add dependencies as needed to enforce the dump
20047 : : * section boundaries.
20048 : : */
20049 : : static void
20050 : 185 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
20051 : : DumpableObject *boundaryObjs)
20052 : : {
20053 : 185 : DumpableObject *preDataBound = boundaryObjs + 0;
20054 : 185 : DumpableObject *postDataBound = boundaryObjs + 1;
20055 : : int i;
20056 : :
20057 [ + + ]: 819380 : for (i = 0; i < numObjs; i++)
20058 : : {
20059 : 819195 : DumpableObject *dobj = dobjs[i];
20060 : :
20061 : : /*
20062 : : * The classification of object types here must match the SECTION_xxx
20063 : : * values assigned during subsequent ArchiveEntry calls!
20064 : : */
20065 [ + + + + : 819195 : switch (dobj->objType)
+ + + +
- ]
20066 : : {
20067 : 772550 : case DO_NAMESPACE:
20068 : : case DO_EXTENSION:
20069 : : case DO_TYPE:
20070 : : case DO_SHELL_TYPE:
20071 : : case DO_FUNC:
20072 : : case DO_AGG:
20073 : : case DO_OPERATOR:
20074 : : case DO_ACCESS_METHOD:
20075 : : case DO_OPCLASS:
20076 : : case DO_OPFAMILY:
20077 : : case DO_COLLATION:
20078 : : case DO_CONVERSION:
20079 : : case DO_TABLE:
20080 : : case DO_TABLE_ATTACH:
20081 : : case DO_ATTRDEF:
20082 : : case DO_PROCLANG:
20083 : : case DO_CAST:
20084 : : case DO_DUMMY_TYPE:
20085 : : case DO_TSPARSER:
20086 : : case DO_TSDICT:
20087 : : case DO_TSTEMPLATE:
20088 : : case DO_TSCONFIG:
20089 : : case DO_FDW:
20090 : : case DO_FOREIGN_SERVER:
20091 : : case DO_TRANSFORM:
20092 : : /* Pre-data objects: must come before the pre-data boundary */
20093 : 772550 : addObjectDependency(preDataBound, dobj->dumpId);
20094 : 772550 : break;
20095 : 5077 : case DO_TABLE_DATA:
20096 : : case DO_SEQUENCE_SET:
20097 : : case DO_LARGE_OBJECT:
20098 : : case DO_LARGE_OBJECT_DATA:
20099 : : /* Data objects: must come between the boundaries */
20100 : 5077 : addObjectDependency(dobj, preDataBound->dumpId);
20101 : 5077 : addObjectDependency(postDataBound, dobj->dumpId);
20102 : 5077 : break;
20103 : 6090 : case DO_INDEX:
20104 : : case DO_INDEX_ATTACH:
20105 : : case DO_STATSEXT:
20106 : : case DO_REFRESH_MATVIEW:
20107 : : case DO_TRIGGER:
20108 : : case DO_EVENT_TRIGGER:
20109 : : case DO_DEFAULT_ACL:
20110 : : case DO_POLICY:
20111 : : case DO_PUBLICATION:
20112 : : case DO_PUBLICATION_REL:
20113 : : case DO_PUBLICATION_TABLE_IN_SCHEMA:
20114 : : case DO_SUBSCRIPTION:
20115 : : case DO_SUBSCRIPTION_REL:
20116 : : /* Post-data objects: must come after the post-data boundary */
20117 : 6090 : addObjectDependency(dobj, postDataBound->dumpId);
20118 : 6090 : break;
20119 : 28627 : case DO_RULE:
20120 : : /* Rules are post-data, but only if dumped separately */
20121 [ + + ]: 28627 : if (((RuleInfo *) dobj)->separate)
20122 : 643 : addObjectDependency(dobj, postDataBound->dumpId);
20123 : 28627 : break;
20124 : 2689 : case DO_CONSTRAINT:
20125 : : case DO_FK_CONSTRAINT:
20126 : : /* Constraints are post-data, but only if dumped separately */
20127 [ + + ]: 2689 : if (((ConstraintInfo *) dobj)->separate)
20128 : 1899 : addObjectDependency(dobj, postDataBound->dumpId);
20129 : 2689 : break;
20130 : 185 : case DO_PRE_DATA_BOUNDARY:
20131 : : /* nothing to do */
20132 : 185 : break;
20133 : 185 : case DO_POST_DATA_BOUNDARY:
20134 : : /* must come after the pre-data boundary */
20135 : 185 : addObjectDependency(dobj, preDataBound->dumpId);
20136 : 185 : break;
198 jdavis@postgresql.or 20137 : 3792 : case DO_REL_STATS:
20138 : : /* stats section varies by parent object type, DATA or POST */
162 20139 [ + + ]: 3792 : if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
20140 : : {
198 20141 : 2422 : addObjectDependency(dobj, preDataBound->dumpId);
20142 : 2422 : addObjectDependency(postDataBound, dobj->dumpId);
20143 : : }
20144 : : else
20145 : 1370 : addObjectDependency(dobj, postDataBound->dumpId);
20146 : 3792 : break;
20147 : : }
20148 : : }
4821 tgl@sss.pgh.pa.us 20149 : 185 : }
20150 : :
20151 : :
20152 : : /*
20153 : : * BuildArchiveDependencies - create dependency data for archive TOC entries
20154 : : *
20155 : : * The raw dependency data obtained by getDependencies() is not terribly
20156 : : * useful in an archive dump, because in many cases there are dependency
20157 : : * chains linking through objects that don't appear explicitly in the dump.
20158 : : * For example, a view will depend on its _RETURN rule while the _RETURN rule
20159 : : * will depend on other objects --- but the rule will not appear as a separate
20160 : : * object in the dump. We need to adjust the view's dependencies to include
20161 : : * whatever the rule depends on that is included in the dump.
20162 : : *
20163 : : * Just to make things more complicated, there are also "special" dependencies
20164 : : * such as the dependency of a TABLE DATA item on its TABLE, which we must
20165 : : * not rearrange because pg_restore knows that TABLE DATA only depends on
20166 : : * its table. In these cases we must leave the dependencies strictly as-is
20167 : : * even if they refer to not-to-be-dumped objects.
20168 : : *
20169 : : * To handle this, the convention is that "special" dependencies are created
20170 : : * during ArchiveEntry calls, and an archive TOC item that has any such
20171 : : * entries will not be touched here. Otherwise, we recursively search the
20172 : : * DumpableObject data structures to build the correct dependencies for each
20173 : : * archive TOC item.
20174 : : */
20175 : : static void
20176 : 55 : BuildArchiveDependencies(Archive *fout)
20177 : : {
20178 : 55 : ArchiveHandle *AH = (ArchiveHandle *) fout;
20179 : : TocEntry *te;
20180 : :
20181 : : /* Scan all TOC entries in the archive */
20182 [ + + ]: 8030 : for (te = AH->toc->next; te != AH->toc; te = te->next)
20183 : : {
20184 : : DumpableObject *dobj;
20185 : : DumpId *dependencies;
20186 : : int nDeps;
20187 : : int allocDeps;
20188 : :
20189 : : /* No need to process entries that will not be dumped */
20190 [ + + ]: 7975 : if (te->reqs == 0)
20191 : 3971 : continue;
20192 : : /* Ignore entries that already have "special" dependencies */
20193 [ + + ]: 7972 : if (te->nDeps > 0)
20194 : 3539 : continue;
20195 : : /* Otherwise, look up the item's original DumpableObject, if any */
20196 : 4433 : dobj = findObjectByDumpId(te->dumpId);
20197 [ + + ]: 4433 : if (dobj == NULL)
20198 : 301 : continue;
20199 : : /* No work if it has no dependencies */
20200 [ + + ]: 4132 : if (dobj->nDeps <= 0)
20201 : 128 : continue;
20202 : : /* Set up work array */
20203 : 4004 : allocDeps = 64;
20204 : 4004 : dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
20205 : 4004 : nDeps = 0;
20206 : : /* Recursively find all dumpable dependencies */
20207 : 4004 : findDumpableDependencies(AH, dobj,
20208 : : &dependencies, &nDeps, &allocDeps);
20209 : : /* And save 'em ... */
20210 [ + + ]: 4004 : if (nDeps > 0)
20211 : : {
20212 : 3134 : dependencies = (DumpId *) pg_realloc(dependencies,
20213 : : nDeps * sizeof(DumpId));
20214 : 3134 : te->dependencies = dependencies;
20215 : 3134 : te->nDeps = nDeps;
20216 : : }
20217 : : else
20218 : 870 : free(dependencies);
20219 : : }
20220 : 55 : }
20221 : :
20222 : : /* Recursive search subroutine for BuildArchiveDependencies */
20223 : : static void
1669 peter@eisentraut.org 20224 : 9405 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
20225 : : DumpId **dependencies, int *nDeps, int *allocDeps)
20226 : : {
20227 : : int i;
20228 : :
20229 : : /*
20230 : : * Ignore section boundary objects: if we search through them, we'll
20231 : : * report lots of bogus dependencies.
20232 : : */
4821 tgl@sss.pgh.pa.us 20233 [ + + ]: 9405 : if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
20234 [ + + ]: 9385 : dobj->objType == DO_POST_DATA_BOUNDARY)
20235 : 1694 : return;
20236 : :
20237 [ + + ]: 19706 : for (i = 0; i < dobj->nDeps; i++)
20238 : : {
20239 : 11995 : DumpId depid = dobj->dependencies[i];
20240 : :
20241 [ + + ]: 11995 : if (TocIDRequired(AH, depid) != 0)
20242 : : {
20243 : : /* Object will be dumped, so just reference it as a dependency */
20244 [ - + ]: 6594 : if (*nDeps >= *allocDeps)
20245 : : {
4821 tgl@sss.pgh.pa.us 20246 :UBC 0 : *allocDeps *= 2;
20247 : 0 : *dependencies = (DumpId *) pg_realloc(*dependencies,
2999 20248 : 0 : *allocDeps * sizeof(DumpId));
20249 : : }
4821 tgl@sss.pgh.pa.us 20250 :CBC 6594 : (*dependencies)[*nDeps] = depid;
20251 : 6594 : (*nDeps)++;
20252 : : }
20253 : : else
20254 : : {
20255 : : /*
20256 : : * Object will not be dumped, so recursively consider its deps. We
20257 : : * rely on the assumption that sortDumpableObjects already broke
20258 : : * any dependency loops, else we might recurse infinitely.
20259 : : */
20260 : 5401 : DumpableObject *otherdobj = findObjectByDumpId(depid);
20261 : :
20262 [ + - ]: 5401 : if (otherdobj)
20263 : 5401 : findDumpableDependencies(AH, otherdobj,
20264 : : dependencies, nDeps, allocDeps);
20265 : : }
20266 : : }
20267 : : }
20268 : :
20269 : :
20270 : : /*
20271 : : * getFormattedTypeName - retrieve a nicely-formatted type name for the
20272 : : * given type OID.
20273 : : *
20274 : : * This does not guarantee to schema-qualify the output, so it should not
20275 : : * be used to create the target object name for CREATE or ALTER commands.
20276 : : *
20277 : : * Note that the result is cached and must not be freed by the caller.
20278 : : */
20279 : : static const char *
4961 rhaas@postgresql.org 20280 : 2372 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
20281 : : {
20282 : : TypeInfo *typeInfo;
20283 : : char *result;
20284 : : PQExpBuffer query;
20285 : : PGresult *res;
20286 : :
7945 tgl@sss.pgh.pa.us 20287 [ - + ]: 2372 : if (oid == 0)
20288 : : {
2011 tgl@sss.pgh.pa.us 20289 [ # # ]:UBC 0 : if ((opts & zeroAsStar) != 0)
1459 20290 : 0 : return "*";
8520 20291 [ # # ]: 0 : else if ((opts & zeroAsNone) != 0)
1459 20292 : 0 : return "NONE";
20293 : : }
20294 : :
20295 : : /* see if we have the result cached in the type's TypeInfo record */
1467 tgl@sss.pgh.pa.us 20296 :CBC 2372 : typeInfo = findTypeByOid(oid);
20297 [ + - + + ]: 2372 : if (typeInfo && typeInfo->ftypname)
1459 20298 : 1863 : return typeInfo->ftypname;
20299 : :
8520 20300 : 509 : query = createPQExpBuffer();
3251 20301 : 509 : appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
20302 : : oid);
20303 : :
4951 rhaas@postgresql.org 20304 : 509 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
20305 : :
20306 : : /* result of format_type is already quoted */
3251 tgl@sss.pgh.pa.us 20307 : 509 : result = pg_strdup(PQgetvalue(res, 0, 0));
20308 : :
8520 20309 : 509 : PQclear(res);
20310 : 509 : destroyPQExpBuffer(query);
20311 : :
20312 : : /*
20313 : : * Cache the result for re-use in later requests, if possible. If we
20314 : : * don't have a TypeInfo for the type, the string will be leaked once the
20315 : : * caller is done with it ... but that case really should not happen, so
20316 : : * leaking if it does seems acceptable.
20317 : : */
1467 20318 [ + - ]: 509 : if (typeInfo)
1459 20319 : 509 : typeInfo->ftypname = result;
20320 : :
8520 20321 : 509 : return result;
20322 : : }
20323 : :
20324 : : /*
20325 : : * Return a column list clause for the given relation.
20326 : : *
20327 : : * Special case: if there are no undropped columns in the relation, return
20328 : : * "", not an invalid "()" column list.
20329 : : */
20330 : : static const char *
4549 andrew@dunslane.net 20331 : 8738 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
20332 : : {
8451 bruce@momjian.us 20333 : 8738 : int numatts = ti->numatts;
8403 20334 : 8738 : char **attnames = ti->attnames;
20335 : 8738 : bool *attisdropped = ti->attisdropped;
2352 peter@eisentraut.org 20336 : 8738 : char *attgenerated = ti->attgenerated;
20337 : : bool needComma;
20338 : : int i;
20339 : :
4310 heikki.linnakangas@i 20340 : 8738 : appendPQExpBufferChar(buffer, '(');
8436 tgl@sss.pgh.pa.us 20341 : 8738 : needComma = false;
8451 bruce@momjian.us 20342 [ + + ]: 41562 : for (i = 0; i < numatts; i++)
20343 : : {
8436 tgl@sss.pgh.pa.us 20344 [ + + ]: 32824 : if (attisdropped[i])
20345 : 610 : continue;
2352 peter@eisentraut.org 20346 [ + + ]: 32214 : if (attgenerated[i])
20347 : 1200 : continue;
8436 tgl@sss.pgh.pa.us 20348 [ + + ]: 31014 : if (needComma)
4310 heikki.linnakangas@i 20349 : 22536 : appendPQExpBufferStr(buffer, ", ");
20350 : 31014 : appendPQExpBufferStr(buffer, fmtId(attnames[i]));
8436 tgl@sss.pgh.pa.us 20351 : 31014 : needComma = true;
20352 : : }
20353 : :
8304 20354 [ + + ]: 8738 : if (!needComma)
8170 20355 : 260 : return ""; /* no undropped columns */
20356 : :
4310 heikki.linnakangas@i 20357 : 8478 : appendPQExpBufferChar(buffer, ')');
4549 andrew@dunslane.net 20358 : 8478 : return buffer->data;
20359 : : }
20360 : :
20361 : : /*
20362 : : * Check if a reloptions array is nonempty.
20363 : : */
20364 : : static bool
3535 tgl@sss.pgh.pa.us 20365 : 14288 : nonemptyReloptions(const char *reloptions)
20366 : : {
20367 : : /* Don't want to print it if it's just "{}" */
20368 [ + - + + ]: 14288 : return (reloptions != NULL && strlen(reloptions) > 2);
20369 : : }
20370 : :
20371 : : /*
20372 : : * Format a reloptions array and append it to the given buffer.
20373 : : *
20374 : : * "prefix" is prepended to the option names; typically it's "" or "toast.".
20375 : : */
20376 : : static void
3410 dean.a.rasheed@gmail 20377 : 220 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
20378 : : const char *prefix, Archive *fout)
20379 : : {
20380 : : bool res;
20381 : :
20382 : 220 : res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
20383 : 220 : fout->std_strings);
20384 [ - + ]: 220 : if (!res)
1407 peter@eisentraut.org 20385 :UBC 0 : pg_log_warning("could not parse %s array", "reloptions");
3535 tgl@sss.pgh.pa.us 20386 :CBC 220 : }
20387 : :
20388 : : /*
20389 : : * read_dump_filters - retrieve object identifier patterns from file
20390 : : *
20391 : : * Parse the specified filter file for include and exclude patterns, and add
20392 : : * them to the relevant lists. If the filename is "-" then filters will be
20393 : : * read from STDIN rather than a file.
20394 : : */
20395 : : static void
647 dgustafsson@postgres 20396 : 26 : read_dump_filters(const char *filename, DumpOptions *dopt)
20397 : : {
20398 : : FilterStateData fstate;
20399 : : char *objname;
20400 : : FilterCommandType comtype;
20401 : : FilterObjectType objtype;
20402 : :
20403 : 26 : filter_init(&fstate, filename, exit_nicely);
20404 : :
20405 [ + + ]: 84 : while (filter_read_item(&fstate, &objname, &comtype, &objtype))
20406 : : {
20407 [ + + ]: 33 : if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
20408 : : {
20409 [ - - + + : 17 : switch (objtype)
+ + + - ]
20410 : : {
647 dgustafsson@postgres 20411 :UBC 0 : case FILTER_OBJECT_TYPE_NONE:
20412 : 0 : break;
20413 : 0 : case FILTER_OBJECT_TYPE_DATABASE:
20414 : : case FILTER_OBJECT_TYPE_FUNCTION:
20415 : : case FILTER_OBJECT_TYPE_INDEX:
20416 : : case FILTER_OBJECT_TYPE_TABLE_DATA:
20417 : : case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
20418 : : case FILTER_OBJECT_TYPE_TRIGGER:
646 20419 : 0 : pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
20420 : : "include",
20421 : : filter_object_type_name(objtype));
647 20422 : 0 : exit_nicely(1);
20423 : : break; /* unreachable */
20424 : :
647 dgustafsson@postgres 20425 :CBC 1 : case FILTER_OBJECT_TYPE_EXTENSION:
20426 : 1 : simple_string_list_append(&extension_include_patterns, objname);
20427 : 1 : break;
20428 : 1 : case FILTER_OBJECT_TYPE_FOREIGN_DATA:
20429 : 1 : simple_string_list_append(&foreign_servers_include_patterns, objname);
20430 : 1 : break;
20431 : 1 : case FILTER_OBJECT_TYPE_SCHEMA:
20432 : 1 : simple_string_list_append(&schema_include_patterns, objname);
20433 : 1 : dopt->include_everything = false;
20434 : 1 : break;
20435 : 13 : case FILTER_OBJECT_TYPE_TABLE:
20436 : 13 : simple_string_list_append(&table_include_patterns, objname);
20437 : 13 : dopt->include_everything = false;
20438 : 13 : break;
20439 : 1 : case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
20440 : 1 : simple_string_list_append(&table_include_patterns_and_children,
20441 : : objname);
20442 : 1 : dopt->include_everything = false;
20443 : 1 : break;
20444 : : }
20445 : : }
20446 [ + + ]: 16 : else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
20447 : : {
20448 [ - + + + : 9 : switch (objtype)
+ + + +
- ]
20449 : : {
647 dgustafsson@postgres 20450 :UBC 0 : case FILTER_OBJECT_TYPE_NONE:
20451 : 0 : break;
647 dgustafsson@postgres 20452 :CBC 1 : case FILTER_OBJECT_TYPE_DATABASE:
20453 : : case FILTER_OBJECT_TYPE_FUNCTION:
20454 : : case FILTER_OBJECT_TYPE_INDEX:
20455 : : case FILTER_OBJECT_TYPE_TRIGGER:
20456 : : case FILTER_OBJECT_TYPE_FOREIGN_DATA:
646 20457 : 1 : pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
20458 : : "exclude",
20459 : : filter_object_type_name(objtype));
647 20460 : 1 : exit_nicely(1);
20461 : : break;
20462 : :
535 dean.a.rasheed@gmail 20463 : 1 : case FILTER_OBJECT_TYPE_EXTENSION:
20464 : 1 : simple_string_list_append(&extension_exclude_patterns, objname);
20465 : 1 : break;
647 dgustafsson@postgres 20466 : 1 : case FILTER_OBJECT_TYPE_TABLE_DATA:
20467 : 1 : simple_string_list_append(&tabledata_exclude_patterns,
20468 : : objname);
20469 : 1 : break;
20470 : 1 : case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
20471 : 1 : simple_string_list_append(&tabledata_exclude_patterns_and_children,
20472 : : objname);
20473 : 1 : break;
20474 : 2 : case FILTER_OBJECT_TYPE_SCHEMA:
20475 : 2 : simple_string_list_append(&schema_exclude_patterns, objname);
20476 : 2 : break;
20477 : 2 : case FILTER_OBJECT_TYPE_TABLE:
20478 : 2 : simple_string_list_append(&table_exclude_patterns, objname);
20479 : 2 : break;
20480 : 1 : case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
20481 : 1 : simple_string_list_append(&table_exclude_patterns_and_children,
20482 : : objname);
20483 : 1 : break;
20484 : : }
20485 : : }
20486 : : else
20487 : : {
20488 [ - + ]: 7 : Assert(comtype == FILTER_COMMAND_TYPE_NONE);
20489 [ - + ]: 7 : Assert(objtype == FILTER_OBJECT_TYPE_NONE);
20490 : : }
20491 : :
20492 [ + + ]: 32 : if (objname)
20493 : 25 : free(objname);
20494 : : }
20495 : :
20496 : 22 : filter_free(&fstate);
20497 : 22 : }
|