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
8571 tgl@sss.pgh.pa.us 421 :CBC 297 : main(int argc, char **argv)
422 : : {
423 : : int c;
424 : 297 : const char *filename = NULL;
425 : 297 : 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 */
2401 peter@eisentraut.org 435 : 297 : bool g_verbose = false;
4031 alvherre@alvh.no-ip. 436 : 297 : const char *dumpencoding = NULL;
3997 simon@2ndQuadrant.co 437 : 297 : const char *dumpsnapshot = NULL;
4031 alvherre@alvh.no-ip. 438 : 297 : char *use_role = NULL;
4600 andrew@dunslane.net 439 : 297 : int numWorkers = 1;
8571 tgl@sss.pgh.pa.us 440 : 297 : int plainText = 0;
5391 heikki.linnakangas@i 441 : 297 : ArchiveFormat archiveFormat = archUnknown;
442 : : ArchiveMode archiveMode;
1060 michael@paquier.xyz 443 : 297 : pg_compress_specification compression_spec = {0};
444 : 297 : char *compression_detail = NULL;
445 : 297 : char *compression_algorithm_str = "none";
446 : 297 : char *error_detail = NULL;
447 : 297 : bool user_compression_defined = false;
782 nathan@postgresql.or 448 : 297 : DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
336 449 : 297 : bool data_only = false;
450 : 297 : bool schema_only = false;
249 jdavis@postgresql.or 451 : 297 : bool statistics_only = false;
216 452 : 297 : bool with_statistics = false;
249 453 : 297 : bool no_data = false;
454 : 297 : bool no_schema = false;
455 : 297 : 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 : :
2401 peter@eisentraut.org 545 : 297 : pg_logging_init(argv[0]);
546 : 297 : pg_logging_set_level(PG_LOG_WARNING);
6164 peter_e@gmx.net 547 : 297 : 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 : : */
4600 andrew@dunslane.net 553 : 297 : init_parallel_dump_utils();
554 : :
8242 bruce@momjian.us 555 : 297 : progname = get_progname(argv[0]);
556 : :
8571 tgl@sss.pgh.pa.us 557 [ + - ]: 297 : if (argc > 1)
558 : : {
559 [ + + - + ]: 297 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
560 : : {
561 : 1 : help(progname);
5002 rhaas@postgresql.org 562 : 1 : exit_nicely(0);
563 : : }
8571 tgl@sss.pgh.pa.us 564 [ + + + + ]: 296 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
565 : : {
566 : 62 : puts("pg_dump (PostgreSQL) " PG_VERSION);
5002 rhaas@postgresql.org 567 : 62 : exit_nicely(0);
568 : : }
569 : : }
570 : :
3942 tgl@sss.pgh.pa.us 571 : 234 : InitDumpOptions(&dopt);
572 : :
249 jdavis@postgresql.or 573 : 1306 : while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
8330 peter_e@gmx.net 574 [ + + ]: 1306 : long_options, &optindex)) != -1)
575 : : {
8571 tgl@sss.pgh.pa.us 576 [ + + + + : 1080 : switch (c)
+ + + + +
+ + + + +
+ + + + +
+ + + + +
- + + + +
+ + + - +
+ + + + +
+ + - + +
+ + + + +
+ + ]
577 : : {
578 : 9 : case 'a': /* Dump data only */
336 nathan@postgresql.or 579 : 9 : data_only = true;
8571 tgl@sss.pgh.pa.us 580 : 9 : break;
581 : :
1057 peter@eisentraut.org 582 : 1 : case 'b': /* Dump LOs */
583 : 1 : dopt.outputLOs = true;
8571 tgl@sss.pgh.pa.us 584 : 1 : break;
585 : :
1057 peter@eisentraut.org 586 : 2 : case 'B': /* Don't dump LOs */
587 : 2 : dopt.dontOutputLOs = true;
3254 sfrost@snowman.net 588 : 2 : break;
589 : :
7317 bruce@momjian.us 590 : 6 : case 'c': /* clean (i.e., drop) schema prior to create */
3942 tgl@sss.pgh.pa.us 591 : 6 : dopt.outputClean = 1;
8571 592 : 6 : break;
593 : :
594 : 29 : case 'C': /* Create DB */
3942 595 : 29 : dopt.outputCreateDB = 1;
8571 596 : 29 : break;
597 : :
4627 heikki.linnakangas@i 598 : 5 : case 'd': /* database name */
1859 tgl@sss.pgh.pa.us 599 : 5 : dopt.cparams.dbname = pg_strdup(optarg);
4627 heikki.linnakangas@i 600 : 5 : break;
601 : :
1671 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 : :
7414 bruce@momjian.us 607 : 2 : case 'E': /* Dump encoding */
4763 608 : 2 : dumpencoding = pg_strdup(optarg);
7414 609 : 2 : break;
610 : :
8571 tgl@sss.pgh.pa.us 611 : 187 : case 'f':
4763 bruce@momjian.us 612 : 187 : filename = pg_strdup(optarg);
8571 tgl@sss.pgh.pa.us 613 : 187 : break;
614 : :
615 : 114 : case 'F':
4763 bruce@momjian.us 616 : 114 : format = pg_strdup(optarg);
8571 tgl@sss.pgh.pa.us 617 : 114 : break;
618 : :
619 : 34 : case 'h': /* server host */
1859 620 : 34 : dopt.cparams.pghost = pg_strdup(optarg);
8571 621 : 34 : break;
622 : :
4600 andrew@dunslane.net 623 : 12 : case 'j': /* number of dump jobs */
1556 michael@paquier.xyz 624 [ + + ]: 12 : if (!option_parse_int(optarg, "-j/--jobs", 1,
625 : : PG_MAX_JOBS,
626 : : &numWorkers))
627 : 1 : exit_nicely(1);
4600 andrew@dunslane.net 628 : 11 : break;
629 : :
6958 tgl@sss.pgh.pa.us 630 : 17 : case 'n': /* include schema(s) */
631 : 17 : simple_string_list_append(&schema_include_patterns, optarg);
3942 632 : 17 : dopt.include_everything = false;
6958 633 : 17 : break;
634 : :
635 : 1 : case 'N': /* exclude schema(s) */
636 : 1 : simple_string_list_append(&schema_exclude_patterns, optarg);
8292 bruce@momjian.us 637 : 1 : break;
638 : :
8571 tgl@sss.pgh.pa.us 639 : 2 : case 'O': /* Don't reconnect to match owner */
3942 640 : 2 : dopt.outputNoOwner = 1;
8571 641 : 2 : break;
642 : :
643 : 73 : case 'p': /* server port */
1859 644 : 73 : dopt.cparams.pgport = pg_strdup(optarg);
8571 645 : 73 : break;
646 : :
8070 647 : 2 : case 'R':
648 : : /* no-op, still accepted for backwards compatibility */
8571 649 : 2 : break;
650 : :
651 : 7 : case 's': /* dump schema only */
336 nathan@postgresql.or 652 : 7 : schema_only = true;
8571 tgl@sss.pgh.pa.us 653 : 7 : break;
654 : :
7317 bruce@momjian.us 655 : 1 : case 'S': /* Username for superuser in plain text output */
3942 tgl@sss.pgh.pa.us 656 : 1 : dopt.outputSuperuser = pg_strdup(optarg);
8571 657 : 1 : break;
658 : :
6958 659 : 8 : case 't': /* include table(s) */
660 : 8 : simple_string_list_append(&table_include_patterns, optarg);
3942 661 : 8 : dopt.include_everything = false;
6958 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 : :
8571 668 : 36 : case 'U':
1859 669 : 36 : dopt.cparams.username = pg_strdup(optarg);
8571 670 : 36 : break;
671 : :
672 : 6 : case 'v': /* verbose */
673 : 6 : g_verbose = true;
1866 674 : 6 : pg_logging_increase_verbosity();
8571 675 : 6 : break;
676 : :
6087 peter_e@gmx.net 677 : 1 : case 'w':
1859 tgl@sss.pgh.pa.us 678 : 1 : dopt.cparams.promptPassword = TRI_NO;
6087 peter_e@gmx.net 679 : 1 : break;
680 : :
8571 tgl@sss.pgh.pa.us 681 :UBC 0 : case 'W':
1859 682 : 0 : dopt.cparams.promptPassword = TRI_YES;
8571 683 : 0 : break;
684 : :
8571 tgl@sss.pgh.pa.us 685 :CBC 2 : case 'x': /* skip ACL dump */
3942 686 : 2 : dopt.aclsSkip = true;
8571 687 : 2 : break;
688 : :
1060 michael@paquier.xyz 689 : 16 : case 'Z': /* Compression */
690 : 16 : parse_compress_options(optarg, &compression_algorithm_str,
691 : : &compression_detail);
692 : 16 : user_compression_defined = true;
8571 tgl@sss.pgh.pa.us 693 : 16 : break;
694 : :
695 : 129 : case 0:
696 : : /* This covers the long options. */
697 : 129 : break;
698 : :
6139 699 : 2 : case 2: /* lock-wait-timeout */
3942 700 : 2 : dopt.lockWaitTimeout = pg_strdup(optarg);
6308 701 : 2 : break;
702 : :
6139 703 : 3 : case 3: /* SET ROLE */
4763 bruce@momjian.us 704 : 3 : use_role = pg_strdup(optarg);
6139 tgl@sss.pgh.pa.us 705 : 3 : break;
706 : :
4887 bruce@momjian.us 707 : 1 : case 4: /* exclude table(s) data */
5066 andrew@dunslane.net 708 : 1 : simple_string_list_append(&tabledata_exclude_patterns, optarg);
709 : 1 : break;
710 : :
5064 711 : 6 : case 5: /* section */
3942 tgl@sss.pgh.pa.us 712 : 6 : set_dump_section(optarg, &dopt.dumpSections);
5064 andrew@dunslane.net 713 : 6 : break;
714 : :
3997 simon@2ndQuadrant.co 715 :UBC 0 : case 6: /* snapshot */
716 : 0 : dumpsnapshot = pg_strdup(optarg);
717 : 0 : break;
718 : :
3141 andrew@dunslane.net 719 :CBC 151 : case 7: /* no-sync */
720 : 151 : dosync = false;
721 : 151 : break;
722 : :
2443 723 : 1 : case 8:
724 : 1 : have_extra_float_digits = true;
1556 michael@paquier.xyz 725 [ + - ]: 1 : if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
726 : : &extra_float_digits))
2443 andrew@dunslane.net 727 : 1 : exit_nicely(1);
2443 andrew@dunslane.net 728 :UBC 0 : break;
729 : :
2426 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 */
1556 michael@paquier.xyz 741 [ + + ]: 2 : if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
742 : : &dopt.dump_inserts))
2426 alvherre@alvh.no-ip. 743 : 1 : exit_nicely(1);
744 : 1 : break;
745 : :
2042 746 : 4 : case 11: /* include foreign data */
747 : 4 : simple_string_list_append(&foreign_servers_include_patterns,
748 : : optarg);
749 : 4 : break;
750 : :
958 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 : :
782 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 : :
698 dgustafsson@postgres 772 :CBC 26 : case 16: /* read object filters from file */
773 : 26 : read_dump_filters(optarg, &dopt);
774 : 22 : break;
775 : :
586 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 : :
249 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 : :
216 797 : 91 : case 22:
798 : 91 : with_statistics = true;
799 : 91 : break;
800 : :
77 nathan@postgresql.or 801 : 26 : case 25:
802 : 26 : dopt.restrict_key = pg_strdup(optarg);
803 : 26 : break;
804 : :
8571 tgl@sss.pgh.pa.us 805 : 1 : default:
806 : : /* getopt_long already emitted a complaint */
1298 807 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
5002 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 : : */
1859 tgl@sss.pgh.pa.us 816 [ + + + - ]: 226 : if (optind < argc && dopt.cparams.dbname == NULL)
817 : 190 : dopt.cparams.dbname = argv[optind++];
818 : :
819 : : /* Complain if any arguments remain */
5554 820 [ + + ]: 226 : if (optind < argc)
821 : : {
2401 peter@eisentraut.org 822 : 1 : pg_log_error("too many command-line arguments (first is \"%s\")",
823 : : argv[optind]);
1298 tgl@sss.pgh.pa.us 824 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
5002 rhaas@postgresql.org 825 : 1 : exit_nicely(1);
826 : : }
827 : :
828 : : /* --column-inserts implies --inserts */
2426 alvherre@alvh.no-ip. 829 [ + + + - ]: 225 : if (dopt.column_inserts && dopt.dump_inserts == 0)
830 : 1 : dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
831 : :
832 : : /* reject conflicting "-only" options */
336 nathan@postgresql.or 833 [ + + + + ]: 225 : if (data_only && schema_only)
1298 tgl@sss.pgh.pa.us 834 : 1 : pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
249 jdavis@postgresql.or 835 [ + + + + ]: 224 : if (schema_only && statistics_only)
836 : 1 : pg_fatal("options -s/--schema-only and --statistics-only cannot be used together");
837 [ + + + + ]: 223 : 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 [ + + - + ]: 222 : if (data_only && no_data)
249 jdavis@postgresql.or 842 :UBC 0 : pg_fatal("options -a/--data-only and --no-data cannot be used together");
249 jdavis@postgresql.or 843 [ + + - + ]:CBC 222 : if (schema_only && no_schema)
249 jdavis@postgresql.or 844 :UBC 0 : pg_fatal("options -s/--schema-only and --no-schema cannot be used together");
249 jdavis@postgresql.or 845 [ + + + + ]:CBC 222 : 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 */
216 849 [ + + - + ]: 221 : if (with_statistics && no_statistics)
86 jdavis@postgresql.or 850 :UBC 0 : pg_fatal("options --statistics and --no-statistics cannot be used together");
851 : :
852 : : /* reject conflicting "-only" options */
86 jdavis@postgresql.or 853 [ + + - + ]:CBC 221 : if (data_only && with_statistics)
87 jdavis@postgresql.or 854 :UBC 0 : pg_fatal("options %s and %s cannot be used together",
855 : : "-a/--data-only", "--statistics");
86 jdavis@postgresql.or 856 [ + + + + ]:CBC 221 : if (schema_only && with_statistics)
87 857 : 1 : pg_fatal("options %s and %s cannot be used together",
858 : : "-s/--schema-only", "--statistics");
859 : :
336 nathan@postgresql.or 860 [ + + + + ]: 220 : if (schema_only && foreign_servers_include_patterns.head != NULL)
1298 tgl@sss.pgh.pa.us 861 : 1 : pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
862 : :
2042 alvherre@alvh.no-ip. 863 [ + + + + ]: 219 : if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
1298 tgl@sss.pgh.pa.us 864 : 1 : pg_fatal("option --include-foreign-data is not supported with parallel backup");
865 : :
336 nathan@postgresql.or 866 [ + + + + ]: 218 : if (data_only && dopt.outputClean)
1298 tgl@sss.pgh.pa.us 867 : 1 : pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
868 : :
3942 869 [ + + + + ]: 217 : if (dopt.if_exists && !dopt.outputClean)
1298 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 : : */
216 jdavis@postgresql.or 877 [ + + + + : 216 : dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
- + ]
86 878 [ + - + + ]: 432 : data_only) && !no_data;
216 879 [ + + + + : 216 : dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
- + ]
86 880 [ + - + + ]: 432 : schema_only) && !no_schema;
216 881 [ - - - - : 216 : dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
+ + ]
882 [ - + + + : 432 : (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 : : */
2426 alvherre@alvh.no-ip. 889 [ + + + - ]: 216 : if (dopt.do_nothing && dopt.dump_inserts == 0)
1298 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 */
5391 heikki.linnakangas@i 893 : 215 : archiveFormat = parseArchiveFormat(format, &archiveMode);
894 : :
895 : : /* archiveFormat specific setup */
896 [ + + ]: 214 : if (archiveFormat == archNull)
897 : : {
6794 bruce@momjian.us 898 : 155 : plainText = 1;
899 : :
900 : : /*
901 : : * If you don't provide a restrict key, one will be appointed for you.
902 : : */
77 nathan@postgresql.or 903 [ + + ]: 155 : if (!dopt.restrict_key)
904 : 129 : dopt.restrict_key = generate_restrict_key();
905 [ - + ]: 155 : if (!dopt.restrict_key)
77 nathan@postgresql.or 906 :UBC 0 : pg_fatal("could not generate restrict key");
77 nathan@postgresql.or 907 [ - + ]:CBC 155 : if (!valid_restrict_key(dopt.restrict_key))
77 nathan@postgresql.or 908 :UBC 0 : pg_fatal("invalid restrict key");
909 : : }
77 nathan@postgresql.or 910 [ - + ]:CBC 59 : else if (dopt.restrict_key)
77 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 : : */
914 michael@paquier.xyz 918 [ + + + + ]:CBC 214 : if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
919 [ + + ]: 56 : !user_compression_defined)
920 : : {
921 : : #ifdef HAVE_LIBZ
922 : 48 : compression_algorithm_str = "gzip";
923 : : #else
924 : : compression_algorithm_str = "none";
925 : : #endif
926 : : }
927 : :
928 : : /*
929 : : * Compression options
930 : : */
1060 931 [ + + ]: 214 : if (!parse_compress_algorithm(compression_algorithm_str,
932 : : &compression_algorithm))
933 : 1 : pg_fatal("unrecognized compression algorithm: \"%s\"",
934 : : compression_algorithm_str);
935 : :
936 : 213 : parse_compress_specification(compression_algorithm, compression_detail,
937 : : &compression_spec);
938 : 213 : error_detail = validate_compress_specification(&compression_spec);
939 [ + + ]: 213 : if (error_detail != NULL)
940 : 3 : pg_fatal("invalid compression specification: %s",
941 : : error_detail);
942 : :
936 tomas.vondra@postgre 943 : 210 : error_detail = supports_compression(compression_spec);
944 [ - + ]: 210 : if (error_detail != NULL)
936 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 : : */
936 tomas.vondra@postgre 952 [ - + ]:CBC 210 : if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
936 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 : : */
2832 tgl@sss.pgh.pa.us 960 [ + + ]:CBC 210 : if (!plainText)
961 : 59 : dopt.outputCreateDB = 1;
962 : :
963 : : /* Parallel backup only in the directory archive format so far */
4600 andrew@dunslane.net 964 [ + + + + ]: 210 : if (archiveFormat != archDirectory && numWorkers > 1)
1298 tgl@sss.pgh.pa.us 965 : 1 : pg_fatal("parallel backup only supported by the directory format");
966 : :
967 : : /* Open the output file */
1060 michael@paquier.xyz 968 : 209 : fout = CreateArchive(filename, archiveFormat, compression_spec,
969 : : dosync, archiveMode, setupDumpWorker, sync_method);
970 : :
971 : : /* Make dump options accessible right away */
3575 tgl@sss.pgh.pa.us 972 : 208 : SetArchiveOptions(fout, &dopt, NULL);
973 : :
974 : : /* Register the cleanup hook */
4969 alvherre@alvh.no-ip. 975 : 208 : on_exit_close_archive(fout);
976 : :
977 : : /* Let the archiver know how noisy to be */
5012 rhaas@postgresql.org 978 : 208 : 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 : : */
1413 tgl@sss.pgh.pa.us 985 : 208 : fout->minRemoteVersion = 90200;
4598 heikki.linnakangas@i 986 : 208 : fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
987 : :
4600 andrew@dunslane.net 988 : 208 : fout->numWorkers = numWorkers;
989 : :
990 : : /*
991 : : * Open the database using the Archiver, so it knows about it. Errors mean
992 : : * death.
993 : : */
206 994 : 208 : ConnectDatabaseAhx(fout, &dopt.cparams, false);
3575 tgl@sss.pgh.pa.us 995 : 206 : 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 : : */
3441 magnus@hagander.net 1001 [ + + ]: 206 : 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 : : */
1413 tgl@sss.pgh.pa.us 1009 : 206 : g_last_builtin_oid = FirstNormalObjectId - 1;
1010 : :
2401 peter@eisentraut.org 1011 : 206 : pg_log_info("last built-in OID is %u", g_last_builtin_oid);
1012 : :
1013 : : /* Expand schema selection patterns into OID lists */
6958 tgl@sss.pgh.pa.us 1014 [ + + ]: 206 : if (schema_include_patterns.head != NULL)
1015 : : {
5012 rhaas@postgresql.org 1016 : 18 : expand_schema_name_patterns(fout, &schema_include_patterns,
1017 : : &schema_include_oids,
1018 : : strict_names);
6958 tgl@sss.pgh.pa.us 1019 [ + + ]: 12 : if (schema_include_oids.head == NULL)
1298 1020 : 1 : pg_fatal("no matching schemas were found");
1021 : : }
5012 rhaas@postgresql.org 1022 : 199 : 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 */
958 tgl@sss.pgh.pa.us 1028 : 199 : expand_table_name_patterns(fout, &table_include_patterns,
1029 : : &table_include_oids,
1030 : : strict_names, false);
1031 : 194 : expand_table_name_patterns(fout, &table_include_patterns_and_children,
1032 : : &table_include_oids,
1033 : : strict_names, true);
1034 [ + + ]: 194 : if ((table_include_patterns.head != NULL ||
1035 [ + + ]: 183 : table_include_patterns_and_children.head != NULL) &&
1036 [ + + ]: 13 : table_include_oids.head == NULL)
1037 : 2 : pg_fatal("no matching tables were found");
1038 : :
5011 rhaas@postgresql.org 1039 : 192 : expand_table_name_patterns(fout, &table_exclude_patterns,
1040 : : &table_exclude_oids,
1041 : : false, false);
958 tgl@sss.pgh.pa.us 1042 : 192 : expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
1043 : : &table_exclude_oids,
1044 : : false, true);
1045 : :
5011 rhaas@postgresql.org 1046 : 192 : expand_table_name_patterns(fout, &tabledata_exclude_patterns,
1047 : : &tabledata_exclude_oids,
1048 : : false, false);
958 tgl@sss.pgh.pa.us 1049 : 192 : expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
1050 : : &tabledata_exclude_oids,
1051 : : false, true);
1052 : :
2042 alvherre@alvh.no-ip. 1053 : 192 : 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 */
1671 michael@paquier.xyz 1059 [ + + ]: 191 : 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)
1298 tgl@sss.pgh.pa.us 1065 : 1 : pg_fatal("no matching extensions were found");
1066 : : }
586 dean.a.rasheed@gmail 1067 : 190 : 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 : : */
336 nathan@postgresql.or 1081 [ + + + + : 190 : if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
+ + ]
1057 peter@eisentraut.org 1082 : 125 : dopt.outputLOs = true;
1083 : :
1084 : : /*
1085 : : * Collect role names so we can map object owner OIDs to names.
1086 : : */
1396 tgl@sss.pgh.pa.us 1087 : 190 : collectRoleNames(fout);
1088 : :
1089 : : /*
1090 : : * Now scan the database and create DumpableObject structs for all the
1091 : : * objects we intend to dump.
1092 : : */
3575 1093 : 190 : tblinfo = getSchemaData(fout, &numTables);
1094 : :
336 nathan@postgresql.or 1095 [ + + ]: 189 : if (dopt.dumpData)
1096 : : {
2533 andres@anarazel.de 1097 : 149 : getTableData(&dopt, tblinfo, numTables, 0);
4621 kgrittn@postgresql.o 1098 : 149 : buildMatViewRefreshDependencies(fout);
336 nathan@postgresql.or 1099 [ + + ]: 149 : if (!dopt.dumpSchema)
6258 tgl@sss.pgh.pa.us 1100 : 7 : getTableDataFKConstraints();
1101 : : }
1102 : :
336 nathan@postgresql.or 1103 [ + + + + ]: 189 : if (!dopt.dumpData && dopt.sequence_data)
2533 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 : : */
101 nathan@postgresql.or 1113 [ + + + - ]:GNC 189 : 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 : : * If upgrading from v16 or newer, only dump large objects with
1137 : : * comments/seclabels. For these upgrades, pg_upgrade can copy/link
1138 : : * pg_largeobject_metadata's files (which is usually faster) but we
1139 : : * still need to dump LOs with comments/seclabels here so that the
1140 : : * subsequent COMMENT and SECURITY LABEL commands work. pg_upgrade
1141 : : * can't copy/link the files from older versions because aclitem
1142 : : * (needed by pg_largeobject_metadata.lomacl) changed its storage
1143 : : * format in v16.
1144 : : */
49 1145 [ + - ]: 36 : if (fout->remoteVersion >= 160000)
1146 : 36 : lo_metadata->dataObj->filtercond = "WHERE oid IN "
1147 : : "(SELECT objoid FROM pg_description "
1148 : : "WHERE classoid = " CppAsString2(LargeObjectRelationId) " "
1149 : : "UNION SELECT objoid FROM pg_seclabel "
1150 : : "WHERE classoid = " CppAsString2(LargeObjectRelationId) ")";
1151 : : }
1152 : :
1153 : : /*
1154 : : * In binary-upgrade mode, we do not have to worry about the actual LO
1155 : : * data or the associated metadata that resides in the pg_largeobject and
1156 : : * pg_largeobject_metadata tables, respectively.
1157 : : *
1158 : : * However, we do need to collect LO information as there may be comments
1159 : : * or other information on LOs that we do need to dump out.
1160 : : */
1057 peter@eisentraut.org 1161 [ + + + + ]:CBC 189 : if (dopt.outputLOs || dopt.binary_upgrade)
1162 : 161 : getLOs(fout);
1163 : :
1164 : : /*
1165 : : * Collect dependency data to assist in ordering the objects.
1166 : : */
5012 rhaas@postgresql.org 1167 : 189 : getDependencies(fout);
1168 : :
1169 : : /*
1170 : : * Collect ACLs, comments, and security labels, if wanted.
1171 : : */
1421 tgl@sss.pgh.pa.us 1172 [ + + ]: 189 : if (!dopt.aclsSkip)
1173 : 187 : getAdditionalACLs(fout);
1174 [ + - ]: 189 : if (!dopt.no_comments)
1175 : 189 : collectComments(fout);
1176 [ + - ]: 189 : if (!dopt.no_security_labels)
1177 : 189 : collectSecLabels(fout);
1178 : :
1179 : : /* For binary upgrade mode, collect required pg_class information. */
481 nathan@postgresql.or 1180 [ + + ]: 189 : if (dopt.binary_upgrade)
1181 : 36 : collectBinaryUpgradeClassOids(fout);
1182 : :
1183 : : /* Collect sequence information. */
453 1184 : 189 : collectSequences(fout);
1185 : :
1186 : : /* Lastly, create dummy objects to represent the section boundaries */
4872 tgl@sss.pgh.pa.us 1187 : 189 : boundaryObjs = createBoundaryObjects();
1188 : :
1189 : : /* Get pointers to all the known DumpableObjects */
1190 : 189 : getDumpableObjects(&dobjs, &numObjs);
1191 : :
1192 : : /*
1193 : : * Add dummy dependencies to enforce the dump section ordering.
1194 : : */
1195 : 189 : addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
1196 : :
1197 : : /*
1198 : : * Sort the objects into a safe dump order (no forward references).
1199 : : *
1200 : : * We rely on dependency information to help us determine a safe order, so
1201 : : * the initial sort is mostly for cosmetic purposes: we sort by name to
1202 : : * ensure that logically identical schemas will dump identically.
1203 : : */
3302 1204 : 189 : sortDumpableObjectsByTypeName(dobjs, numObjs);
1205 : :
4872 1206 : 189 : sortDumpableObjects(dobjs, numObjs,
1207 : 189 : boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
1208 : :
1209 : : /*
1210 : : * Create archive TOC entries for all the objects to be dumped, in a safe
1211 : : * order.
1212 : : */
1213 : :
1214 : : /*
1215 : : * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
1216 : : */
5012 rhaas@postgresql.org 1217 : 189 : dumpEncoding(fout);
1218 : 189 : dumpStdStrings(fout);
2800 tgl@sss.pgh.pa.us 1219 : 189 : dumpSearchPath(fout);
1220 : :
1221 : : /* The database items are always next, unless we don't want them at all */
2832 1222 [ + + ]: 189 : if (dopt.outputCreateDB)
3575 1223 : 87 : dumpDatabase(fout);
1224 : :
1225 : : /* Now the rearrangeable objects. */
7996 1226 [ + + ]: 832807 : for (i = 0; i < numObjs; i++)
3575 1227 : 832618 : dumpDumpableObject(fout, dobjs[i]);
1228 : :
1229 : : /*
1230 : : * Set up options info to ensure we dump what we want.
1231 : : */
4899 1232 : 189 : ropt = NewRestoreOptions();
1233 : 189 : ropt->filename = filename;
1234 : :
1235 : : /* if you change this list, see dumpOptionsFromRestoreOptions */
1859 1236 [ + + ]: 189 : ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
1237 [ + + ]: 189 : ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
1238 [ + + ]: 189 : ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
1239 [ + + ]: 189 : ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
1240 : 189 : ropt->cparams.promptPassword = dopt.cparams.promptPassword;
3942 1241 : 189 : ropt->dropSchema = dopt.outputClean;
336 nathan@postgresql.or 1242 : 189 : ropt->dumpData = dopt.dumpData;
1243 : 189 : ropt->dumpSchema = dopt.dumpSchema;
249 jdavis@postgresql.or 1244 : 189 : ropt->dumpStatistics = dopt.dumpStatistics;
3942 tgl@sss.pgh.pa.us 1245 : 189 : ropt->if_exists = dopt.if_exists;
1246 : 189 : ropt->column_inserts = dopt.column_inserts;
1247 : 189 : ropt->dumpSections = dopt.dumpSections;
1248 : 189 : ropt->aclsSkip = dopt.aclsSkip;
1249 : 189 : ropt->superuser = dopt.outputSuperuser;
1250 : 189 : ropt->createDB = dopt.outputCreateDB;
1251 : 189 : ropt->noOwner = dopt.outputNoOwner;
1379 michael@paquier.xyz 1252 : 189 : ropt->noTableAm = dopt.outputNoTableAm;
3942 tgl@sss.pgh.pa.us 1253 : 189 : ropt->noTablespace = dopt.outputNoTablespaces;
1254 : 189 : ropt->disable_triggers = dopt.disable_triggers;
1255 : 189 : ropt->use_setsessauth = dopt.use_setsessauth;
1256 : 189 : ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
1257 : 189 : ropt->dump_inserts = dopt.dump_inserts;
2832 1258 : 189 : ropt->no_comments = dopt.no_comments;
225 1259 : 189 : ropt->no_policies = dopt.no_policies;
3090 peter_e@gmx.net 1260 : 189 : ropt->no_publications = dopt.no_publications;
3942 tgl@sss.pgh.pa.us 1261 : 189 : ropt->no_security_labels = dopt.no_security_labels;
3093 peter_e@gmx.net 1262 : 189 : ropt->no_subscriptions = dopt.no_subscriptions;
3942 tgl@sss.pgh.pa.us 1263 : 189 : ropt->lockWaitTimeout = dopt.lockWaitTimeout;
1264 : 189 : ropt->include_everything = dopt.include_everything;
1265 : 189 : ropt->enable_row_security = dopt.enable_row_security;
3352 peter_e@gmx.net 1266 : 189 : ropt->sequence_data = dopt.sequence_data;
3157 sfrost@snowman.net 1267 : 189 : ropt->binary_upgrade = dopt.binary_upgrade;
77 nathan@postgresql.or 1268 [ + + ]: 189 : ropt->restrict_key = dopt.restrict_key ? pg_strdup(dopt.restrict_key) : NULL;
1269 : :
1060 michael@paquier.xyz 1270 : 189 : ropt->compression_spec = compression_spec;
1271 : :
4887 bruce@momjian.us 1272 : 189 : ropt->suppressDumpWarnings = true; /* We've already shown them */
1273 : :
3575 tgl@sss.pgh.pa.us 1274 : 189 : SetArchiveOptions(fout, &dopt, ropt);
1275 : :
1276 : : /* Mark which entries should be output */
1277 : 189 : ProcessArchiveRestoreOptions(fout);
1278 : :
1279 : : /*
1280 : : * The archive's TOC entries are now marked as to which ones will actually
1281 : : * be output, so we can set up their dependency lists properly. This isn't
1282 : : * necessary for plain-text output, though.
1283 : : */
4872 1284 [ + + ]: 189 : if (!plainText)
1285 : 58 : BuildArchiveDependencies(fout);
1286 : :
1287 : : /*
1288 : : * And finally we can do the actual output.
1289 : : *
1290 : : * Note: for non-plain-text output formats, the output file is written
1291 : : * inside CloseArchive(). This is, um, bizarre; but not worth changing
1292 : : * right now.
1293 : : */
4899 1294 [ + + ]: 189 : if (plainText)
89 andrew@dunslane.net 1295 : 131 : RestoreArchive(fout);
1296 : :
3575 tgl@sss.pgh.pa.us 1297 : 188 : CloseArchive(fout);
1298 : :
5002 rhaas@postgresql.org 1299 : 188 : exit_nicely(0);
1300 : : }
1301 : :
1302 : :
1303 : : static void
8571 tgl@sss.pgh.pa.us 1304 : 1 : help(const char *progname)
1305 : : {
130 peter@eisentraut.org 1306 : 1 : printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
8461 peter_e@gmx.net 1307 : 1 : printf(_("Usage:\n"));
8410 1308 : 1 : printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
1309 : :
1310 : 1 : printf(_("\nGeneral options:\n"));
4910 1311 : 1 : printf(_(" -f, --file=FILENAME output file or directory name\n"));
1312 : 1 : printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
1313 : : " plain text (default))\n"));
4600 andrew@dunslane.net 1314 : 1 : printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
4910 peter_e@gmx.net 1315 : 1 : printf(_(" -v, --verbose verbose mode\n"));
4879 1316 : 1 : printf(_(" -V, --version output version information, then exit\n"));
892 peter@eisentraut.org 1317 : 1 : printf(_(" -Z, --compress=METHOD[:DETAIL]\n"
1318 : : " compress as specified\n"));
4910 peter_e@gmx.net 1319 : 1 : printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
3141 andrew@dunslane.net 1320 : 1 : printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
782 nathan@postgresql.or 1321 : 1 : printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
4879 peter_e@gmx.net 1322 : 1 : printf(_(" -?, --help show this help, then exit\n"));
1323 : :
8410 1324 : 1 : printf(_("\nOptions controlling the output content:\n"));
249 jdavis@postgresql.or 1325 : 1 : printf(_(" -a, --data-only dump only the data, not the schema or statistics\n"));
892 peter@eisentraut.org 1326 : 1 : printf(_(" -b, --large-objects include large objects in dump\n"));
1327 : 1 : printf(_(" --blobs (same as --large-objects, deprecated)\n"));
1328 : 1 : printf(_(" -B, --no-large-objects exclude large objects in dump\n"));
1329 : 1 : printf(_(" --no-blobs (same as --no-large-objects, deprecated)\n"));
4910 peter_e@gmx.net 1330 : 1 : printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
1331 : 1 : printf(_(" -C, --create include commands to create database in dump\n"));
1671 michael@paquier.xyz 1332 : 1 : printf(_(" -e, --extension=PATTERN dump the specified extension(s) only\n"));
4910 peter_e@gmx.net 1333 : 1 : printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
2246 peter@eisentraut.org 1334 : 1 : printf(_(" -n, --schema=PATTERN dump the specified schema(s) only\n"));
1335 : 1 : printf(_(" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
4910 peter_e@gmx.net 1336 : 1 : printf(_(" -O, --no-owner skip restoration of object ownership in\n"
1337 : : " plain-text format\n"));
249 jdavis@postgresql.or 1338 : 1 : printf(_(" -s, --schema-only dump only the schema, no data or statistics\n"));
4910 peter_e@gmx.net 1339 : 1 : printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
958 tgl@sss.pgh.pa.us 1340 : 1 : printf(_(" -t, --table=PATTERN dump only the specified table(s)\n"));
2246 peter@eisentraut.org 1341 : 1 : printf(_(" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n"));
4910 peter_e@gmx.net 1342 : 1 : printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
1343 : 1 : printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
1344 : 1 : printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
1345 : 1 : printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
1346 : 1 : printf(_(" --disable-triggers disable triggers during data-only restore\n"));
3694 1347 : 1 : printf(_(" --enable-row-security enable row security (dump only content user has\n"
1348 : : " access to)\n"));
551 peter@eisentraut.org 1349 : 1 : printf(_(" --exclude-extension=PATTERN do NOT dump the specified extension(s)\n"));
958 tgl@sss.pgh.pa.us 1350 : 1 : printf(_(" --exclude-table-and-children=PATTERN\n"
1351 : : " do NOT dump the specified table(s), including\n"
1352 : : " child and partition tables\n"));
2246 peter@eisentraut.org 1353 : 1 : printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
958 tgl@sss.pgh.pa.us 1354 : 1 : printf(_(" --exclude-table-data-and-children=PATTERN\n"
1355 : : " do NOT dump data for the specified table(s),\n"
1356 : : " including child and partition tables\n"));
2443 andrew@dunslane.net 1357 : 1 : printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
698 dgustafsson@postgres 1358 : 1 : printf(_(" --filter=FILENAME include or exclude objects and data from dump\n"
1359 : : " based on expressions in FILENAME\n"));
4256 alvherre@alvh.no-ip. 1360 : 1 : printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
2042 1361 : 1 : printf(_(" --include-foreign-data=PATTERN\n"
1362 : : " include data of foreign tables on foreign\n"
1363 : : " servers matching PATTERN\n"));
4910 peter_e@gmx.net 1364 : 1 : printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
2702 1365 : 1 : printf(_(" --load-via-partition-root load partitions via the root table\n"));
341 bruce@momjian.us 1366 : 1 : printf(_(" --no-comments do not dump comment commands\n"));
249 jdavis@postgresql.or 1367 : 1 : printf(_(" --no-data do not dump data\n"));
225 tgl@sss.pgh.pa.us 1368 : 1 : printf(_(" --no-policies do not dump row security policies\n"));
3090 peter_e@gmx.net 1369 : 1 : printf(_(" --no-publications do not dump publications\n"));
249 jdavis@postgresql.or 1370 : 1 : printf(_(" --no-schema do not dump schema\n"));
4910 peter_e@gmx.net 1371 : 1 : printf(_(" --no-security-labels do not dump security label assignments\n"));
249 jdavis@postgresql.or 1372 : 1 : printf(_(" --no-statistics do not dump statistics\n"));
3093 peter_e@gmx.net 1373 : 1 : printf(_(" --no-subscriptions do not dump subscriptions\n"));
1379 michael@paquier.xyz 1374 : 1 : printf(_(" --no-table-access-method do not dump table access methods\n"));
4910 peter_e@gmx.net 1375 : 1 : printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
1627 peter@eisentraut.org 1376 : 1 : printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
4910 peter_e@gmx.net 1377 : 1 : printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
2663 tmunro@postgresql.or 1378 : 1 : printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
4910 peter_e@gmx.net 1379 : 1 : printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
77 nathan@postgresql.or 1380 : 1 : printf(_(" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n"));
2426 alvherre@alvh.no-ip. 1381 : 1 : printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
4910 peter_e@gmx.net 1382 : 1 : printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
216 nathan@postgresql.or 1383 : 1 : printf(_(" --sequence-data include sequence data in dump\n"));
4910 peter_e@gmx.net 1384 : 1 : printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
3683 1385 : 1 : printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
86 jdavis@postgresql.or 1386 : 1 : printf(_(" --statistics dump the statistics\n"));
249 1387 : 1 : printf(_(" --statistics-only dump only the statistics, not schema or data\n"));
3696 teodor@sigaev.ru 1388 : 1 : printf(_(" --strict-names require table and/or schema include patterns to\n"
1389 : : " match at least one entity each\n"));
892 peter@eisentraut.org 1390 : 1 : printf(_(" --table-and-children=PATTERN dump only the specified table(s), including\n"
1391 : : " child and partition tables\n"));
6960 peter_e@gmx.net 1392 : 1 : printf(_(" --use-set-session-authorization\n"
1393 : : " use SET SESSION AUTHORIZATION commands instead of\n"
1394 : : " ALTER OWNER commands to set ownership\n"));
1395 : :
8410 1396 : 1 : printf(_("\nConnection options:\n"));
4627 heikki.linnakangas@i 1397 : 1 : printf(_(" -d, --dbname=DBNAME database to dump\n"));
8174 bruce@momjian.us 1398 : 1 : printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
8410 peter_e@gmx.net 1399 : 1 : printf(_(" -p, --port=PORT database server port number\n"));
1400 : 1 : printf(_(" -U, --username=NAME connect as specified database user\n"));
6068 1401 : 1 : printf(_(" -w, --no-password never prompt for password\n"));
8410 1402 : 1 : printf(_(" -W, --password force password prompt (should happen automatically)\n"));
5269 1403 : 1 : printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
1404 : :
8132 1405 : 1 : printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1406 : : "variable value is used.\n\n"));
2068 peter@eisentraut.org 1407 : 1 : printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1408 : 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
8571 tgl@sss.pgh.pa.us 1409 : 1 : }
1410 : :
1411 : : static void
3575 1412 : 224 : setup_connection(Archive *AH, const char *dumpencoding,
1413 : : const char *dumpsnapshot, char *use_role)
1414 : : {
1415 : 224 : DumpOptions *dopt = AH->dopt;
5002 rhaas@postgresql.org 1416 : 224 : PGconn *conn = GetConnection(AH);
1417 : : const char *std_strings;
1418 : :
2800 noah@leadboat.com 1419 : 224 : PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1420 : :
1421 : : /*
1422 : : * Set the client encoding if requested.
1423 : : */
5022 rhaas@postgresql.org 1424 [ + + ]: 224 : if (dumpencoding)
1425 : : {
5002 1426 [ - + ]: 20 : if (PQsetClientEncoding(conn, dumpencoding) < 0)
1298 tgl@sss.pgh.pa.us 1427 :UBC 0 : pg_fatal("invalid client encoding \"%s\" specified",
1428 : : dumpencoding);
1429 : : }
1430 : :
1431 : : /*
1432 : : * Get the active encoding and the standard_conforming_strings setting, so
1433 : : * we know how to escape strings.
1434 : : */
5002 rhaas@postgresql.org 1435 :CBC 224 : AH->encoding = PQclientEncoding(conn);
259 andres@anarazel.de 1436 : 224 : setFmtEncoding(AH->encoding);
1437 : :
5002 rhaas@postgresql.org 1438 : 224 : std_strings = PQparameterStatus(conn, "standard_conforming_strings");
5022 1439 [ + - + - ]: 224 : AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1440 : :
1441 : : /*
1442 : : * Set the role if requested. In a parallel dump worker, we'll be passed
1443 : : * use_role == NULL, but AH->use_role is already set (if user specified it
1444 : : * originally) and we should use that.
1445 : : */
4600 andrew@dunslane.net 1446 [ + + + + ]: 224 : if (!use_role && AH->use_role)
1447 : 2 : use_role = AH->use_role;
1448 : :
1449 : : /* Set the role if requested */
1413 tgl@sss.pgh.pa.us 1450 [ + + ]: 224 : if (use_role)
1451 : : {
5022 rhaas@postgresql.org 1452 : 5 : PQExpBuffer query = createPQExpBuffer();
1453 : :
1454 : 5 : appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
5011 1455 : 5 : ExecuteSqlStatement(AH, query->data);
5022 1456 : 5 : destroyPQExpBuffer(query);
1457 : :
1458 : : /* save it for possible later use by parallel workers */
4600 andrew@dunslane.net 1459 [ + + ]: 5 : if (!AH->use_role)
3435 tgl@sss.pgh.pa.us 1460 : 3 : AH->use_role = pg_strdup(use_role);
1461 : : }
1462 : :
1463 : : /* Set the datestyle to ISO to ensure the dump's portability */
5011 rhaas@postgresql.org 1464 : 224 : ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1465 : :
1466 : : /* Likewise, avoid using sql_standard intervalstyle */
1413 tgl@sss.pgh.pa.us 1467 : 224 : ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1468 : :
1469 : : /*
1470 : : * Use an explicitly specified extra_float_digits if it has been provided.
1471 : : * Otherwise, set extra_float_digits so that we can dump float data
1472 : : * exactly (given correctly implemented float I/O code, anyway).
1473 : : */
2443 andrew@dunslane.net 1474 [ - + ]: 224 : if (have_extra_float_digits)
1475 : : {
2443 andrew@dunslane.net 1476 :UBC 0 : PQExpBuffer q = createPQExpBuffer();
1477 : :
1478 : 0 : appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1479 : : extra_float_digits);
1480 : 0 : ExecuteSqlStatement(AH, q->data);
1481 : 0 : destroyPQExpBuffer(q);
1482 : : }
1483 : : else
1413 tgl@sss.pgh.pa.us 1484 :CBC 224 : ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1485 : :
1486 : : /*
1487 : : * Disable synchronized scanning, to prevent unpredictable changes in row
1488 : : * ordering across a dump and reload.
1489 : : */
1490 : 224 : ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1491 : :
1492 : : /*
1493 : : * Disable timeouts if supported.
1494 : : */
3302 1495 : 224 : ExecuteSqlStatement(AH, "SET statement_timeout = 0");
4608 1496 [ + - ]: 224 : if (AH->remoteVersion >= 90300)
1497 : 224 : ExecuteSqlStatement(AH, "SET lock_timeout = 0");
3421 1498 [ + - ]: 224 : if (AH->remoteVersion >= 90600)
1499 : 224 : ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
620 akorotkov@postgresql 1500 [ + - ]: 224 : if (AH->remoteVersion >= 170000)
1501 : 224 : ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
1502 : :
1503 : : /*
1504 : : * Quote all identifiers, if requested.
1505 : : */
1413 tgl@sss.pgh.pa.us 1506 [ + + ]: 224 : if (quote_all_identifiers)
5011 rhaas@postgresql.org 1507 : 34 : ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1508 : :
1509 : : /*
1510 : : * Adjust row-security mode, if supported.
1511 : : */
3904 tgl@sss.pgh.pa.us 1512 [ + - ]: 224 : if (AH->remoteVersion >= 90500)
1513 : : {
1514 [ - + ]: 224 : if (dopt->enable_row_security)
3904 tgl@sss.pgh.pa.us 1515 :UBC 0 : ExecuteSqlStatement(AH, "SET row_security = on");
1516 : : else
3904 tgl@sss.pgh.pa.us 1517 :CBC 224 : ExecuteSqlStatement(AH, "SET row_security = off");
1518 : : }
1519 : :
1520 : : /*
1521 : : * For security reasons, we restrict the expansion of non-system views and
1522 : : * access to foreign tables during the pg_dump process. This restriction
1523 : : * is adjusted when dumping foreign table data.
1524 : : */
448 msawada@postgresql.o 1525 : 224 : set_restrict_relation_kind(AH, "view, foreign-table");
1526 : :
1527 : : /*
1528 : : * Initialize prepared-query state to "nothing prepared". We do this here
1529 : : * so that a parallel dump worker will have its own state.
1530 : : */
1421 tgl@sss.pgh.pa.us 1531 : 224 : AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
1532 : :
1533 : : /*
1534 : : * Start transaction-snapshot mode transaction to dump consistent data.
1535 : : */
4600 andrew@dunslane.net 1536 : 224 : ExecuteSqlStatement(AH, "BEGIN");
1537 : :
1538 : : /*
1539 : : * To support the combination of serializable_deferrable with the jobs
1540 : : * option we use REPEATABLE READ for the worker connections that are
1541 : : * passed a snapshot. As long as the snapshot is acquired in a
1542 : : * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1543 : : * REPEATABLE READ transaction provides the appropriate integrity
1544 : : * guarantees. This is a kluge, but safe for back-patching.
1545 : : */
1413 tgl@sss.pgh.pa.us 1546 [ - + - - ]: 224 : if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1413 tgl@sss.pgh.pa.us 1547 :UBC 0 : ExecuteSqlStatement(AH,
1548 : : "SET TRANSACTION ISOLATION LEVEL "
1549 : : "SERIALIZABLE, READ ONLY, DEFERRABLE");
1550 : : else
4600 andrew@dunslane.net 1551 :CBC 224 : ExecuteSqlStatement(AH,
1552 : : "SET TRANSACTION ISOLATION LEVEL "
1553 : : "REPEATABLE READ, READ ONLY");
1554 : :
1555 : : /*
1556 : : * If user specified a snapshot to use, select that. In a parallel dump
1557 : : * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1558 : : * is already set (if the server can handle it) and we should use that.
1559 : : */
3997 simon@2ndQuadrant.co 1560 [ - + ]: 224 : if (dumpsnapshot)
3435 tgl@sss.pgh.pa.us 1561 :UBC 0 : AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1562 : :
3997 simon@2ndQuadrant.co 1563 [ + + ]:CBC 224 : if (AH->sync_snapshot_id)
1564 : : {
1565 : 18 : PQExpBuffer query = createPQExpBuffer();
1566 : :
2307 drowley@postgresql.o 1567 : 18 : appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
3997 simon@2ndQuadrant.co 1568 : 18 : appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1569 : 18 : ExecuteSqlStatement(AH, query->data);
1570 : 18 : destroyPQExpBuffer(query);
1571 : : }
1412 tgl@sss.pgh.pa.us 1572 [ + + ]: 206 : else if (AH->numWorkers > 1)
1573 : : {
2994 peter_e@gmx.net 1574 [ - + - - ]: 9 : if (AH->isStandby && AH->remoteVersion < 100000)
1298 tgl@sss.pgh.pa.us 1575 :UBC 0 : pg_fatal("parallel dumps from standby servers are not supported by this server version");
3997 simon@2ndQuadrant.co 1576 :CBC 9 : AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1577 : : }
4600 andrew@dunslane.net 1578 : 224 : }
1579 : :
1580 : : /* Set up connection for a parallel worker process */
1581 : : static void
3435 tgl@sss.pgh.pa.us 1582 : 18 : setupDumpWorker(Archive *AH)
1583 : : {
1584 : : /*
1585 : : * We want to re-select all the same values the leader connection is
1586 : : * using. We'll have inherited directly-usable values in
1587 : : * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1588 : : * inherited encoding value back to a string to pass to setup_connection.
1589 : : */
1590 : 18 : setup_connection(AH,
1591 : : pg_encoding_to_char(AH->encoding),
1592 : : NULL,
1593 : : NULL);
4600 andrew@dunslane.net 1594 : 18 : }
1595 : :
1596 : : static char *
1597 : 9 : get_synchronized_snapshot(Archive *fout)
1598 : : {
3435 tgl@sss.pgh.pa.us 1599 : 9 : char *query = "SELECT pg_catalog.pg_export_snapshot()";
1600 : : char *result;
1601 : : PGresult *res;
1602 : :
4600 andrew@dunslane.net 1603 : 9 : res = ExecuteSqlQueryForSingleRow(fout, query);
3435 tgl@sss.pgh.pa.us 1604 : 9 : result = pg_strdup(PQgetvalue(res, 0, 0));
4600 andrew@dunslane.net 1605 : 9 : PQclear(res);
1606 : :
1607 : 9 : return result;
1608 : : }
1609 : :
1610 : : static ArchiveFormat
5391 heikki.linnakangas@i 1611 : 215 : parseArchiveFormat(const char *format, ArchiveMode *mode)
1612 : : {
1613 : : ArchiveFormat archiveFormat;
1614 : :
1615 : 215 : *mode = archModeWrite;
1616 : :
1617 [ + + - + ]: 215 : if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1618 : : {
1619 : : /* This is used by pg_dumpall, and is not documented */
1620 : 43 : archiveFormat = archNull;
1621 : 43 : *mode = archModeAppend;
1622 : : }
1623 [ - + ]: 172 : else if (pg_strcasecmp(format, "c") == 0)
5391 heikki.linnakangas@i 1624 :UBC 0 : archiveFormat = archCustom;
5391 heikki.linnakangas@i 1625 [ + + ]:CBC 172 : else if (pg_strcasecmp(format, "custom") == 0)
1626 : 45 : archiveFormat = archCustom;
1627 [ - + ]: 127 : else if (pg_strcasecmp(format, "d") == 0)
5391 heikki.linnakangas@i 1628 :UBC 0 : archiveFormat = archDirectory;
5391 heikki.linnakangas@i 1629 [ + + ]:CBC 127 : else if (pg_strcasecmp(format, "directory") == 0)
1630 : 11 : archiveFormat = archDirectory;
1631 [ + + ]: 116 : else if (pg_strcasecmp(format, "p") == 0)
1632 : 108 : archiveFormat = archNull;
1633 [ + + ]: 8 : else if (pg_strcasecmp(format, "plain") == 0)
1634 : 4 : archiveFormat = archNull;
1635 [ - + ]: 4 : else if (pg_strcasecmp(format, "t") == 0)
5391 heikki.linnakangas@i 1636 :UBC 0 : archiveFormat = archTar;
5391 heikki.linnakangas@i 1637 [ + + ]:CBC 4 : else if (pg_strcasecmp(format, "tar") == 0)
1638 : 3 : archiveFormat = archTar;
1639 : : else
1298 tgl@sss.pgh.pa.us 1640 : 1 : pg_fatal("invalid output format \"%s\" specified", format);
5391 heikki.linnakangas@i 1641 : 214 : return archiveFormat;
1642 : : }
1643 : :
1644 : : /*
1645 : : * Find the OIDs of all schemas matching the given list of patterns,
1646 : : * and append them to the given OID list.
1647 : : */
1648 : : static void
5012 rhaas@postgresql.org 1649 : 217 : expand_schema_name_patterns(Archive *fout,
1650 : : SimpleStringList *patterns,
1651 : : SimpleOidList *oids,
1652 : : bool strict_names)
1653 : : {
1654 : : PQExpBuffer query;
1655 : : PGresult *res;
1656 : : SimpleStringListCell *cell;
1657 : : int i;
1658 : :
6958 tgl@sss.pgh.pa.us 1659 [ + + ]: 217 : if (patterns->head == NULL)
1660 : 196 : return; /* nothing to do */
1661 : :
1662 : 21 : query = createPQExpBuffer();
1663 : :
1664 : : /*
1665 : : * The loop below runs multiple SELECTs might sometimes result in
1666 : : * duplicate entries in the OID list, but we don't care.
1667 : : */
1668 : :
1669 [ + + ]: 36 : for (cell = patterns->head; cell; cell = cell->next)
1670 : : {
1671 : : PQExpBufferData dbbuf;
1672 : : int dotcnt;
1673 : :
2307 drowley@postgresql.o 1674 : 21 : appendPQExpBufferStr(query,
1675 : : "SELECT oid FROM pg_catalog.pg_namespace n\n");
1286 rhaas@postgresql.org 1676 : 21 : initPQExpBuffer(&dbbuf);
5002 1677 : 21 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1678 : : false, NULL, "n.nspname", NULL, NULL, &dbbuf,
1679 : : &dotcnt);
1286 1680 [ + + ]: 21 : if (dotcnt > 1)
1681 : 2 : pg_fatal("improper qualified name (too many dotted names): %s",
1682 : : cell->val);
1683 [ + + ]: 19 : else if (dotcnt == 1)
1684 : 3 : prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
1685 : 16 : termPQExpBuffer(&dbbuf);
1686 : :
3696 teodor@sigaev.ru 1687 : 16 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1688 [ + + + - ]: 16 : if (strict_names && PQntuples(res) == 0)
1298 tgl@sss.pgh.pa.us 1689 : 1 : pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
1690 : :
3696 teodor@sigaev.ru 1691 [ + + ]: 29 : for (i = 0; i < PQntuples(res); i++)
1692 : : {
1693 : 14 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1694 : : }
1695 : :
1696 : 15 : PQclear(res);
1697 : 15 : resetPQExpBuffer(query);
1698 : : }
1699 : :
6958 tgl@sss.pgh.pa.us 1700 : 15 : destroyPQExpBuffer(query);
1701 : : }
1702 : :
1703 : : /*
1704 : : * Find the OIDs of all extensions matching the given list of patterns,
1705 : : * and append them to the given OID list.
1706 : : */
1707 : : static void
1671 michael@paquier.xyz 1708 : 195 : expand_extension_name_patterns(Archive *fout,
1709 : : SimpleStringList *patterns,
1710 : : SimpleOidList *oids,
1711 : : bool strict_names)
1712 : : {
1713 : : PQExpBuffer query;
1714 : : PGresult *res;
1715 : : SimpleStringListCell *cell;
1716 : : int i;
1717 : :
1718 [ + + ]: 195 : if (patterns->head == NULL)
1719 : 188 : return; /* nothing to do */
1720 : :
1721 : 7 : query = createPQExpBuffer();
1722 : :
1723 : : /*
1724 : : * The loop below runs multiple SELECTs might sometimes result in
1725 : : * duplicate entries in the OID list, but we don't care.
1726 : : */
1727 [ + + ]: 14 : for (cell = patterns->head; cell; cell = cell->next)
1728 : : {
1729 : : int dotcnt;
1730 : :
1731 : 7 : appendPQExpBufferStr(query,
1732 : : "SELECT oid FROM pg_catalog.pg_extension e\n");
1733 : 7 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1734 : : false, NULL, "e.extname", NULL, NULL, NULL,
1735 : : &dotcnt);
1286 rhaas@postgresql.org 1736 [ - + ]: 7 : if (dotcnt > 0)
1286 rhaas@postgresql.org 1737 :UBC 0 : pg_fatal("improper qualified name (too many dotted names): %s",
1738 : : cell->val);
1739 : :
1671 michael@paquier.xyz 1740 :CBC 7 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1741 [ - + - - ]: 7 : if (strict_names && PQntuples(res) == 0)
1298 tgl@sss.pgh.pa.us 1742 :UBC 0 : pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
1743 : :
1671 michael@paquier.xyz 1744 [ + + ]:CBC 13 : for (i = 0; i < PQntuples(res); i++)
1745 : : {
1746 : 6 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1747 : : }
1748 : :
1749 : 7 : PQclear(res);
1750 : 7 : resetPQExpBuffer(query);
1751 : : }
1752 : :
1753 : 7 : destroyPQExpBuffer(query);
1754 : : }
1755 : :
1756 : : /*
1757 : : * Find the OIDs of all foreign servers matching the given list of patterns,
1758 : : * and append them to the given OID list.
1759 : : */
1760 : : static void
2042 alvherre@alvh.no-ip. 1761 : 192 : expand_foreign_server_name_patterns(Archive *fout,
1762 : : SimpleStringList *patterns,
1763 : : SimpleOidList *oids)
1764 : : {
1765 : : PQExpBuffer query;
1766 : : PGresult *res;
1767 : : SimpleStringListCell *cell;
1768 : : int i;
1769 : :
1770 [ + + ]: 192 : if (patterns->head == NULL)
1771 : 189 : return; /* nothing to do */
1772 : :
1773 : 3 : query = createPQExpBuffer();
1774 : :
1775 : : /*
1776 : : * The loop below runs multiple SELECTs might sometimes result in
1777 : : * duplicate entries in the OID list, but we don't care.
1778 : : */
1779 : :
1780 [ + + ]: 5 : for (cell = patterns->head; cell; cell = cell->next)
1781 : : {
1782 : : int dotcnt;
1783 : :
1838 drowley@postgresql.o 1784 : 3 : appendPQExpBufferStr(query,
1785 : : "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
2042 alvherre@alvh.no-ip. 1786 : 3 : processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1787 : : false, NULL, "s.srvname", NULL, NULL, NULL,
1788 : : &dotcnt);
1286 rhaas@postgresql.org 1789 [ - + ]: 3 : if (dotcnt > 0)
1286 rhaas@postgresql.org 1790 :UBC 0 : pg_fatal("improper qualified name (too many dotted names): %s",
1791 : : cell->val);
1792 : :
2042 alvherre@alvh.no-ip. 1793 :CBC 3 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1794 [ + + ]: 3 : if (PQntuples(res) == 0)
1298 tgl@sss.pgh.pa.us 1795 : 1 : pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
1796 : :
2042 alvherre@alvh.no-ip. 1797 [ + + ]: 4 : for (i = 0; i < PQntuples(res); i++)
1798 : 2 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1799 : :
1800 : 2 : PQclear(res);
1801 : 2 : resetPQExpBuffer(query);
1802 : : }
1803 : :
1804 : 2 : destroyPQExpBuffer(query);
1805 : : }
1806 : :
1807 : : /*
1808 : : * Find the OIDs of all tables matching the given list of patterns,
1809 : : * and append them to the given OID list. See also expand_dbname_patterns()
1810 : : * in pg_dumpall.c
1811 : : */
1812 : : static void
5011 rhaas@postgresql.org 1813 : 1161 : expand_table_name_patterns(Archive *fout,
1814 : : SimpleStringList *patterns, SimpleOidList *oids,
1815 : : bool strict_names, bool with_child_tables)
1816 : : {
1817 : : PQExpBuffer query;
1818 : : PGresult *res;
1819 : : SimpleStringListCell *cell;
1820 : : int i;
1821 : :
6958 tgl@sss.pgh.pa.us 1822 [ + + ]: 1161 : if (patterns->head == NULL)
1823 : 1132 : return; /* nothing to do */
1824 : :
1825 : 29 : query = createPQExpBuffer();
1826 : :
1827 : : /*
1828 : : * this might sometimes result in duplicate entries in the OID list, but
1829 : : * we don't care.
1830 : : */
1831 : :
1832 [ + + ]: 59 : for (cell = patterns->head; cell; cell = cell->next)
1833 : : {
1834 : : PQExpBufferData dbbuf;
1835 : : int dotcnt;
1836 : :
1837 : : /*
1838 : : * Query must remain ABSOLUTELY devoid of unqualified names. This
1839 : : * would be unnecessary given a pg_table_is_visible() variant taking a
1840 : : * search_path argument.
1841 : : *
1842 : : * For with_child_tables, we start with the basic query's results and
1843 : : * recursively search the inheritance tree to add child tables.
1844 : : */
958 1845 [ + + ]: 35 : if (with_child_tables)
1846 : : {
192 drowley@postgresql.o 1847 : 6 : appendPQExpBufferStr(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
1848 : : }
1849 : :
6958 tgl@sss.pgh.pa.us 1850 : 35 : appendPQExpBuffer(query,
1851 : : "SELECT c.oid"
1852 : : "\nFROM pg_catalog.pg_class c"
1853 : : "\n LEFT JOIN pg_catalog.pg_namespace n"
1854 : : "\n ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1855 : : "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1856 : : "\n (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1857 : : RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1858 : : RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1859 : : RELKIND_PARTITIONED_TABLE);
1286 rhaas@postgresql.org 1860 : 35 : initPQExpBuffer(&dbbuf);
5002 1861 : 35 : processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1862 : : false, "n.nspname", "c.relname", NULL,
1863 : : "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
1864 : : &dotcnt);
1286 1865 [ + + ]: 35 : if (dotcnt > 2)
1866 : 1 : pg_fatal("improper relation name (too many dotted names): %s",
1867 : : cell->val);
1868 [ + + ]: 34 : else if (dotcnt == 2)
1869 : 2 : prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
1870 : 32 : termPQExpBuffer(&dbbuf);
1871 : :
958 tgl@sss.pgh.pa.us 1872 [ + + ]: 32 : if (with_child_tables)
1873 : : {
192 drowley@postgresql.o 1874 : 6 : appendPQExpBufferStr(query, "UNION"
1875 : : "\nSELECT i.inhrelid"
1876 : : "\nFROM partition_tree p"
1877 : : "\n JOIN pg_catalog.pg_inherits i"
1878 : : "\n ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
1879 : : "\n)"
1880 : : "\nSELECT relid FROM partition_tree");
1881 : : }
1882 : :
2800 noah@leadboat.com 1883 : 32 : ExecuteSqlStatement(fout, "RESET search_path");
3696 teodor@sigaev.ru 1884 : 32 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2800 noah@leadboat.com 1885 : 32 : PQclear(ExecuteSqlQueryForSingleRow(fout,
1886 : : ALWAYS_SECURE_SEARCH_PATH_SQL));
3696 teodor@sigaev.ru 1887 [ + + + + ]: 32 : if (strict_names && PQntuples(res) == 0)
1298 tgl@sss.pgh.pa.us 1888 : 2 : pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
1889 : :
3696 teodor@sigaev.ru 1890 [ + + ]: 74 : for (i = 0; i < PQntuples(res); i++)
1891 : : {
1892 : 44 : simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1893 : : }
1894 : :
1895 : 30 : PQclear(res);
1896 : 30 : resetPQExpBuffer(query);
1897 : : }
1898 : :
6958 tgl@sss.pgh.pa.us 1899 : 24 : destroyPQExpBuffer(query);
1900 : : }
1901 : :
1902 : : /*
1903 : : * Verifies that the connected database name matches the given database name,
1904 : : * and if not, dies with an error about the given pattern.
1905 : : *
1906 : : * The 'dbname' argument should be a literal name parsed from 'pattern'.
1907 : : */
1908 : : static void
1286 rhaas@postgresql.org 1909 : 5 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
1910 : : {
1911 : : const char *db;
1912 : :
1913 : 5 : db = PQdb(conn);
1914 [ - + ]: 5 : if (db == NULL)
1286 rhaas@postgresql.org 1915 :UBC 0 : pg_fatal("You are currently not connected to a database.");
1916 : :
1286 rhaas@postgresql.org 1917 [ + - ]:CBC 5 : if (strcmp(db, dbname) != 0)
1918 : 5 : pg_fatal("cross-database references are not implemented: %s",
1919 : : pattern);
1286 rhaas@postgresql.org 1920 :UBC 0 : }
1921 : :
1922 : : /*
1923 : : * checkExtensionMembership
1924 : : * Determine whether object is an extension member, and if so,
1925 : : * record an appropriate dependency and set the object's dump flag.
1926 : : *
1927 : : * It's important to call this for each object that could be an extension
1928 : : * member. Generally, we integrate this with determining the object's
1929 : : * to-be-dumped-ness, since extension membership overrides other rules for that.
1930 : : *
1931 : : * Returns true if object is an extension member, else false.
1932 : : */
1933 : : static bool
3491 sfrost@snowman.net 1934 :CBC 728421 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1935 : : {
3575 tgl@sss.pgh.pa.us 1936 : 728421 : ExtensionInfo *ext = findOwningExtension(dobj->catId);
1937 : :
1938 [ + + ]: 728421 : if (ext == NULL)
1939 : 727619 : return false;
1940 : :
1941 : 802 : dobj->ext_member = true;
1942 : :
1943 : : /* Record dependency so that getDependencies needn't deal with that */
1944 : 802 : addObjectDependency(dobj, ext->dobj.dumpId);
1945 : :
1946 : : /*
1947 : : * In 9.6 and above, mark the member object to have any non-initial ACLs
1948 : : * dumped. (Any initial ACLs will be removed later, using data from
1949 : : * pg_init_privs, so that we'll dump only the delta from the extension's
1950 : : * initial setup.)
1951 : : *
1952 : : * Prior to 9.6, we do not include any extension member components.
1953 : : *
1954 : : * In binary upgrades, we still dump all components of the members
1955 : : * individually, since the idea is to exactly reproduce the database
1956 : : * contents rather than replace the extension contents with something
1957 : : * different.
1958 : : *
1959 : : * Note: it might be interesting someday to implement storage and delta
1960 : : * dumping of extension members' RLS policies and/or security labels.
1961 : : * However there is a pitfall for RLS policies: trying to dump them
1962 : : * requires getting a lock on their tables, and the calling user might not
1963 : : * have privileges for that. We need no lock to examine a table's ACLs,
1964 : : * so the current feature doesn't have a problem of that sort.
1965 : : */
3461 sfrost@snowman.net 1966 [ + + ]: 802 : if (fout->dopt->binary_upgrade)
3575 tgl@sss.pgh.pa.us 1967 : 169 : dobj->dump = ext->dobj.dump;
1968 : : else
1969 : : {
3461 sfrost@snowman.net 1970 [ - + ]: 633 : if (fout->remoteVersion < 90600)
3461 sfrost@snowman.net 1971 :UBC 0 : dobj->dump = DUMP_COMPONENT_NONE;
1972 : : else
714 tgl@sss.pgh.pa.us 1973 :CBC 633 : dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
1974 : : }
1975 : :
3575 1976 : 802 : return true;
1977 : : }
1978 : :
1979 : : /*
1980 : : * selectDumpableNamespace: policy-setting subroutine
1981 : : * Mark a namespace as to be dumped or not
1982 : : */
1983 : : static void
3491 sfrost@snowman.net 1984 : 1430 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1985 : : {
1986 : : /*
1987 : : * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
1988 : : * and (for --clean) a DROP SCHEMA statement. (In the absence of
1989 : : * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
1990 : : */
1582 noah@leadboat.com 1991 : 1430 : nsinfo->create = true;
1992 : :
1993 : : /*
1994 : : * If specific tables are being dumped, do not dump any complete
1995 : : * namespaces. If specific namespaces are being dumped, dump just those
1996 : : * namespaces. Otherwise, dump all non-system namespaces.
1997 : : */
6958 tgl@sss.pgh.pa.us 1998 [ + + ]: 1430 : if (table_include_oids.head != NULL)
3491 sfrost@snowman.net 1999 : 50 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
6958 tgl@sss.pgh.pa.us 2000 [ + + ]: 1380 : else if (schema_include_oids.head != NULL)
3491 sfrost@snowman.net 2001 : 187 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
2002 : 187 : simple_oid_list_member(&schema_include_oids,
2003 : : nsinfo->dobj.catId.oid) ?
2004 [ + + ]: 187 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2005 [ + - ]: 1193 : else if (fout->remoteVersion >= 90600 &&
3336 tgl@sss.pgh.pa.us 2006 [ + + ]: 1193 : strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
2007 : : {
2008 : : /*
2009 : : * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
2010 : : * they are interesting (and not the original ACLs which were set at
2011 : : * initdb time, see pg_init_privs).
2012 : : */
3491 sfrost@snowman.net 2013 : 168 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
2014 : : }
6958 tgl@sss.pgh.pa.us 2015 [ + + ]: 1025 : else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
2016 [ + + ]: 509 : strcmp(nsinfo->dobj.name, "information_schema") == 0)
2017 : : {
2018 : : /* Other system schemas don't get dumped */
3491 sfrost@snowman.net 2019 : 684 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
2020 : : }
2832 tgl@sss.pgh.pa.us 2021 [ + + ]: 341 : else if (strcmp(nsinfo->dobj.name, "public") == 0)
2022 : : {
2023 : : /*
2024 : : * The public schema is a strange beast that sits in a sort of
2025 : : * no-mans-land between being a system object and a user object.
2026 : : * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
2027 : : * a comment and an indication of ownership. If the owner is the
2028 : : * default, omit that superfluous DUMP_COMPONENT_DEFINITION. Before
2029 : : * v15, the default owner was BOOTSTRAP_SUPERUSERID.
2030 : : */
1582 noah@leadboat.com 2031 : 164 : nsinfo->create = false;
2032 : 164 : nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1509 2033 [ + + ]: 164 : if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
1582 2034 : 122 : nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
2832 tgl@sss.pgh.pa.us 2035 : 164 : nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
2036 : :
2037 : : /*
2038 : : * Also, make like it has a comment even if it doesn't; this is so
2039 : : * that we'll emit a command to drop the comment, if appropriate.
2040 : : * (Without this, we'd not call dumpCommentExtended for it.)
2041 : : */
1421 2042 : 164 : nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
2043 : : }
2044 : : else
3491 sfrost@snowman.net 2045 : 177 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
2046 : :
2047 : : /*
2048 : : * In any case, a namespace can be excluded by an exclusion switch
2049 : : */
2050 [ + + + + ]: 1950 : if (nsinfo->dobj.dump_contains &&
6958 tgl@sss.pgh.pa.us 2051 : 520 : simple_oid_list_member(&schema_exclude_oids,
2052 : : nsinfo->dobj.catId.oid))
3491 sfrost@snowman.net 2053 : 3 : nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
2054 : :
2055 : : /*
2056 : : * If the schema belongs to an extension, allow extension membership to
2057 : : * override the dump decision for the schema itself. However, this does
2058 : : * not change dump_contains, so this won't change what we do with objects
2059 : : * within the schema. (If they belong to the extension, they'll get
2060 : : * suppressed by it, otherwise not.)
2061 : : */
3336 tgl@sss.pgh.pa.us 2062 : 1430 : (void) checkExtensionMembership(&nsinfo->dobj, fout);
6958 2063 : 1430 : }
2064 : :
2065 : : /*
2066 : : * selectDumpableTable: policy-setting subroutine
2067 : : * Mark a table as to be dumped or not
2068 : : */
2069 : : static void
3491 sfrost@snowman.net 2070 : 49729 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
2071 : : {
2072 [ + + ]: 49729 : if (checkExtensionMembership(&tbinfo->dobj, fout))
3575 tgl@sss.pgh.pa.us 2073 : 225 : return; /* extension membership overrides all else */
2074 : :
2075 : : /*
2076 : : * If specific tables are being dumped, dump just those tables; else, dump
2077 : : * according to the parent namespace's dump flag.
2078 : : */
6958 2079 [ + + ]: 49504 : if (table_include_oids.head != NULL)
2080 : 5182 : tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
2081 : : tbinfo->dobj.catId.oid) ?
3491 sfrost@snowman.net 2082 [ + + ]: 2591 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2083 : : else
2084 : 46913 : tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
2085 : :
2086 : : /*
2087 : : * In any case, a table can be excluded by an exclusion switch
2088 : : */
6958 tgl@sss.pgh.pa.us 2089 [ + + + + ]: 81006 : if (tbinfo->dobj.dump &&
2090 : 31502 : simple_oid_list_member(&table_exclude_oids,
2091 : : tbinfo->dobj.catId.oid))
3491 sfrost@snowman.net 2092 : 12 : tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
2093 : : }
2094 : :
2095 : : /*
2096 : : * selectDumpableType: policy-setting subroutine
2097 : : * Mark a type as to be dumped or not
2098 : : *
2099 : : * If it's a table's rowtype or an autogenerated array type, we also apply a
2100 : : * special type code to facilitate sorting into the desired order. (We don't
2101 : : * want to consider those to be ordinary types because that would bring tables
2102 : : * up into the datatype part of the dump order.) We still set the object's
2103 : : * dump flag; that's not going to cause the dummy type to be dumped, but we
2104 : : * need it so that casts involving such types will be dumped correctly -- see
2105 : : * dumpCast. This means the flag should be set the same as for the underlying
2106 : : * object (the table or base type).
2107 : : */
2108 : : static void
2109 : 136675 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
2110 : : {
2111 : : /* skip complex types, except for standalone composite types */
5787 bruce@momjian.us 2112 [ + + ]: 136675 : if (OidIsValid(tyinfo->typrelid) &&
2113 [ + + ]: 49004 : tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
2114 : : {
5123 tgl@sss.pgh.pa.us 2115 : 48822 : TableInfo *tytable = findTableByOid(tyinfo->typrelid);
2116 : :
5787 bruce@momjian.us 2117 : 48822 : tyinfo->dobj.objType = DO_DUMMY_TYPE;
5123 tgl@sss.pgh.pa.us 2118 [ + - ]: 48822 : if (tytable != NULL)
2119 : 48822 : tyinfo->dobj.dump = tytable->dobj.dump;
2120 : : else
3491 sfrost@snowman.net 2121 :UBC 0 : tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
5123 tgl@sss.pgh.pa.us 2122 :CBC 48822 : return;
2123 : : }
2124 : :
2125 : : /* skip auto-generated array and multirange types */
1772 akorotkov@postgresql 2126 [ + + + + ]: 87853 : if (tyinfo->isArray || tyinfo->isMultirange)
2127 : : {
5787 bruce@momjian.us 2128 : 66837 : tyinfo->dobj.objType = DO_DUMMY_TYPE;
2129 : :
2130 : : /*
2131 : : * Fall through to set the dump flag; we assume that the subsequent
2132 : : * rules will do the same thing as they would for the array's base
2133 : : * type or multirange's range type. (We cannot reliably look up the
2134 : : * base type here, since getTypes may not have processed it yet.)
2135 : : */
2136 : : }
2137 : :
3491 sfrost@snowman.net 2138 [ + + ]: 87853 : if (checkExtensionMembership(&tyinfo->dobj, fout))
3575 tgl@sss.pgh.pa.us 2139 : 150 : return; /* extension membership overrides all else */
2140 : :
2141 : : /* Dump based on if the contents of the namespace are being dumped */
3491 sfrost@snowman.net 2142 : 87703 : tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
2143 : : }
2144 : :
2145 : : /*
2146 : : * selectDumpableDefaultACL: policy-setting subroutine
2147 : : * Mark a default ACL as to be dumped or not
2148 : : *
2149 : : * For per-schema default ACLs, dump if the schema is to be dumped.
2150 : : * Otherwise dump if we are dumping "everything". Note that dumpSchema
2151 : : * and aclsSkip are checked separately.
2152 : : */
2153 : : static void
3575 tgl@sss.pgh.pa.us 2154 : 194 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
2155 : : {
2156 : : /* Default ACLs can't be extension members */
2157 : :
5866 2158 [ + + ]: 194 : if (dinfo->dobj.namespace)
2159 : : /* default ACLs are considered part of the namespace */
3461 sfrost@snowman.net 2160 : 90 : dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
2161 : : else
3491 2162 : 104 : dinfo->dobj.dump = dopt->include_everything ?
2163 [ + + ]: 104 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
5866 tgl@sss.pgh.pa.us 2164 : 194 : }
2165 : :
2166 : : /*
2167 : : * selectDumpableCast: policy-setting subroutine
2168 : : * Mark a cast as to be dumped or not
2169 : : *
2170 : : * Casts do not belong to any particular namespace (since they haven't got
2171 : : * names), nor do they have identifiable owners. To distinguish user-defined
2172 : : * casts from built-in ones, we must resort to checking whether the cast's
2173 : : * OID is in the range reserved for initdb.
2174 : : */
2175 : : static void
3491 sfrost@snowman.net 2176 : 44691 : selectDumpableCast(CastInfo *cast, Archive *fout)
2177 : : {
2178 [ - + ]: 44691 : if (checkExtensionMembership(&cast->dobj, fout))
3575 tgl@sss.pgh.pa.us 2179 :UBC 0 : return; /* extension membership overrides all else */
2180 : :
2181 : : /*
2182 : : * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
2183 : : * support ACLs currently.
2184 : : */
3232 sfrost@snowman.net 2185 [ + + ]:CBC 44691 : if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
3491 2186 : 44604 : cast->dobj.dump = DUMP_COMPONENT_NONE;
2187 : : else
2188 : 87 : cast->dobj.dump = fout->dopt->include_everything ?
2189 [ + + ]: 87 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2190 : : }
2191 : :
2192 : : /*
2193 : : * selectDumpableProcLang: policy-setting subroutine
2194 : : * Mark a procedural language as to be dumped or not
2195 : : *
2196 : : * Procedural languages do not belong to any particular namespace. To
2197 : : * identify built-in languages, we must resort to checking whether the
2198 : : * language's OID is in the range reserved for initdb.
2199 : : */
2200 : : static void
2201 : 234 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
2202 : : {
2203 [ + + ]: 234 : if (checkExtensionMembership(&plang->dobj, fout))
3575 tgl@sss.pgh.pa.us 2204 : 189 : return; /* extension membership overrides all else */
2205 : :
2206 : : /*
2207 : : * Only include procedural languages when we are dumping everything.
2208 : : *
2209 : : * For from-initdb procedural languages, only include ACLs, as we do for
2210 : : * the pg_catalog namespace. We need this because procedural languages do
2211 : : * not live in any namespace.
2212 : : */
3461 sfrost@snowman.net 2213 [ + + ]: 45 : if (!fout->dopt->include_everything)
3491 2214 : 8 : plang->dobj.dump = DUMP_COMPONENT_NONE;
2215 : : else
2216 : : {
3232 2217 [ - + ]: 37 : if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
3461 sfrost@snowman.net 2218 :UBC 0 : plang->dobj.dump = fout->remoteVersion < 90600 ?
2219 [ # # ]: 0 : DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
2220 : : else
3461 sfrost@snowman.net 2221 :CBC 37 : plang->dobj.dump = DUMP_COMPONENT_ALL;
2222 : : }
2223 : : }
2224 : :
2225 : : /*
2226 : : * selectDumpableAccessMethod: policy-setting subroutine
2227 : : * Mark an access method as to be dumped or not
2228 : : *
2229 : : * Access methods do not belong to any particular namespace. To identify
2230 : : * built-in access methods, we must resort to checking whether the
2231 : : * method's OID is in the range reserved for initdb.
2232 : : */
2233 : : static void
3491 2234 : 1445 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
2235 : : {
2236 : : /* see getAccessMethods() comment about v9.6. */
88 noah@leadboat.com 2237 [ - + ]: 1445 : if (fout->remoteVersion < 90600)
2238 : : {
88 noah@leadboat.com 2239 :UBC 0 : method->dobj.dump = DUMP_COMPONENT_NONE;
2240 : 0 : return;
2241 : : }
2242 : :
3491 sfrost@snowman.net 2243 [ + + ]:CBC 1445 : if (checkExtensionMembership(&method->dobj, fout))
3505 alvherre@alvh.no-ip. 2244 : 25 : return; /* extension membership overrides all else */
2245 : :
2246 : : /*
2247 : : * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
2248 : : * they do not support ACLs currently.
2249 : : */
3232 sfrost@snowman.net 2250 [ + + ]: 1420 : if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
3491 2251 : 1323 : method->dobj.dump = DUMP_COMPONENT_NONE;
2252 : : else
2253 : 97 : method->dobj.dump = fout->dopt->include_everything ?
2254 [ + + ]: 97 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2255 : : }
2256 : :
2257 : : /*
2258 : : * selectDumpableExtension: policy-setting subroutine
2259 : : * Mark an extension as to be dumped or not
2260 : : *
2261 : : * Built-in extensions should be skipped except for checking ACLs, since we
2262 : : * assume those will already be installed in the target database. We identify
2263 : : * such extensions by their having OIDs in the range reserved for initdb.
2264 : : * We dump all user-added extensions by default. No extensions are dumped
2265 : : * if include_everything is false (i.e., a --schema or --table switch was
2266 : : * given), except if --extension specifies a list of extensions to dump.
2267 : : */
2268 : : static void
3575 tgl@sss.pgh.pa.us 2269 : 220 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
2270 : : {
2271 : : /*
2272 : : * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
2273 : : * change permissions on their member objects, if they wish to, and have
2274 : : * those changes preserved.
2275 : : */
2832 2276 [ + + ]: 220 : if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
3461 sfrost@snowman.net 2277 : 190 : extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
2278 : : else
2279 : : {
2280 : : /* check if there is a list of extensions to dump */
1671 michael@paquier.xyz 2281 [ + + ]: 30 : if (extension_include_oids.head != NULL)
2282 : 4 : extinfo->dobj.dump = extinfo->dobj.dump_contains =
2283 : 4 : simple_oid_list_member(&extension_include_oids,
2284 : : extinfo->dobj.catId.oid) ?
2285 [ + + ]: 4 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2286 : : else
2287 : 26 : extinfo->dobj.dump = extinfo->dobj.dump_contains =
2288 : 26 : dopt->include_everything ?
2289 [ + + ]: 26 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2290 : :
2291 : : /* check that the extension is not explicitly excluded */
586 dean.a.rasheed@gmail 2292 [ + + + + ]: 56 : if (extinfo->dobj.dump &&
2293 : 26 : simple_oid_list_member(&extension_exclude_oids,
2294 : : extinfo->dobj.catId.oid))
2295 : 2 : extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
2296 : : }
5351 tgl@sss.pgh.pa.us 2297 : 220 : }
2298 : :
2299 : : /*
2300 : : * selectDumpablePublicationObject: policy-setting subroutine
2301 : : * Mark a publication object as to be dumped or not
2302 : : *
2303 : : * A publication can have schemas and tables which have schemas, but those are
2304 : : * ignored in decision making, because publications are only dumped when we are
2305 : : * dumping everything.
2306 : : */
2307 : : static void
1461 akapila@postgresql.o 2308 : 475 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
2309 : : {
3142 peter_e@gmx.net 2310 [ - + ]: 475 : if (checkExtensionMembership(dobj, fout))
3142 peter_e@gmx.net 2311 :UBC 0 : return; /* extension membership overrides all else */
2312 : :
3142 peter_e@gmx.net 2313 :CBC 475 : dobj->dump = fout->dopt->include_everything ?
2314 [ + + ]: 475 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2315 : : }
2316 : :
2317 : : /*
2318 : : * selectDumpableStatisticsObject: policy-setting subroutine
2319 : : * Mark an extended statistics object as to be dumped or not
2320 : : *
2321 : : * We dump an extended statistics object if the schema it's in and the table
2322 : : * it's for are being dumped. (This'll need more thought if statistics
2323 : : * objects ever support cross-table stats.)
2324 : : */
2325 : : static void
668 tgl@sss.pgh.pa.us 2326 : 163 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
2327 : : {
2328 [ - + ]: 163 : if (checkExtensionMembership(&sobj->dobj, fout))
668 tgl@sss.pgh.pa.us 2329 :UBC 0 : return; /* extension membership overrides all else */
2330 : :
668 tgl@sss.pgh.pa.us 2331 :CBC 163 : sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
2332 [ + - ]: 163 : if (sobj->stattable == NULL ||
2333 [ + + ]: 163 : !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
2334 : 28 : sobj->dobj.dump = DUMP_COMPONENT_NONE;
2335 : : }
2336 : :
2337 : : /*
2338 : : * selectDumpableObject: policy-setting subroutine
2339 : : * Mark a generic dumpable object as to be dumped or not
2340 : : *
2341 : : * Use this only for object types without a special-case routine above.
2342 : : */
2343 : : static void
3491 sfrost@snowman.net 2344 : 542401 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
2345 : : {
2346 [ + + ]: 542401 : if (checkExtensionMembership(dobj, fout))
3575 tgl@sss.pgh.pa.us 2347 : 188 : return; /* extension membership overrides all else */
2348 : :
2349 : : /*
2350 : : * Default policy is to dump if parent namespace is dumpable, or for
2351 : : * non-namespace-associated items, dump if we're dumping "everything".
2352 : : */
7179 2353 [ + + ]: 542213 : if (dobj->namespace)
3491 sfrost@snowman.net 2354 : 541482 : dobj->dump = dobj->namespace->dobj.dump_contains;
2355 : : else
2356 : 731 : dobj->dump = fout->dopt->include_everything ?
2357 [ + + ]: 731 : DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
2358 : : }
2359 : :
2360 : : /*
2361 : : * Dump a table's contents for loading using the COPY command
2362 : : * - this routine is called by the Archiver when it wants the table
2363 : : * to be dumped.
2364 : : */
2365 : : static int
1720 peter@eisentraut.org 2366 : 4063 : dumpTableData_copy(Archive *fout, const void *dcontext)
2367 : : {
7996 tgl@sss.pgh.pa.us 2368 : 4063 : TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2369 : 4063 : TableInfo *tbinfo = tdinfo->tdtable;
7908 2370 : 4063 : const char *classname = tbinfo->dobj.name;
8571 2371 : 4063 : PQExpBuffer q = createPQExpBuffer();
2372 : :
2373 : : /*
2374 : : * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
2375 : : * which uses it already.
2376 : : */
4600 andrew@dunslane.net 2377 : 4063 : PQExpBuffer clistBuf = createPQExpBuffer();
5002 rhaas@postgresql.org 2378 : 4063 : PGconn *conn = GetConnection(fout);
2379 : : PGresult *res;
2380 : : int ret;
2381 : : char *copybuf;
2382 : : const char *column_list;
2383 : :
2401 peter@eisentraut.org 2384 : 4063 : pg_log_info("dumping contents of table \"%s.%s\"",
2385 : : tbinfo->dobj.namespace->dobj.name, classname);
2386 : :
2387 : : /*
2388 : : * Specify the column list explicitly so that we have no possibility of
2389 : : * retrieving data in the wrong column order. (The default column
2390 : : * ordering of COPY will not be what we want in certain corner cases
2391 : : * involving ADD COLUMN and inheritance.)
2392 : : */
3302 tgl@sss.pgh.pa.us 2393 : 4063 : column_list = fmtCopyColumnList(tbinfo, clistBuf);
2394 : :
2395 : : /*
2396 : : * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
2397 : : * a filter condition was specified. For other cases a simple COPY
2398 : : * suffices.
2399 : : */
2042 alvherre@alvh.no-ip. 2400 [ + + + + ]: 4063 : if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2401 : : {
2402 : : /* Temporary allows to access to foreign tables to dump data */
448 msawada@postgresql.o 2403 [ + + ]: 73 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2404 : 1 : set_restrict_relation_kind(fout, "view");
2405 : :
5375 tgl@sss.pgh.pa.us 2406 : 73 : appendPQExpBufferStr(q, "COPY (SELECT ");
2407 : : /* klugery to get rid of parens in column list */
2408 [ + - ]: 73 : if (strlen(column_list) > 2)
2409 : : {
2410 : 73 : appendPQExpBufferStr(q, column_list + 1);
2411 : 73 : q->data[q->len - 1] = ' ';
2412 : : }
2413 : : else
5375 tgl@sss.pgh.pa.us 2414 :UBC 0 : appendPQExpBufferStr(q, "* ");
2415 : :
5375 tgl@sss.pgh.pa.us 2416 :CBC 146 : appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
2800 2417 : 73 : fmtQualifiedDumpable(tbinfo),
2042 alvherre@alvh.no-ip. 2418 [ + + ]: 73 : tdinfo->filtercond ? tdinfo->filtercond : "");
2419 : : }
2420 : : else
2421 : : {
8502 bruce@momjian.us 2422 : 3990 : appendPQExpBuffer(q, "COPY %s %s TO stdout;",
2800 tgl@sss.pgh.pa.us 2423 : 3990 : fmtQualifiedDumpable(tbinfo),
2424 : : column_list);
2425 : : }
5011 rhaas@postgresql.org 2426 : 4063 : res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
7178 tgl@sss.pgh.pa.us 2427 : 4062 : PQclear(res);
4600 andrew@dunslane.net 2428 : 4062 : destroyPQExpBuffer(clistBuf);
2429 : :
2430 : : for (;;)
2431 : : {
5002 rhaas@postgresql.org 2432 : 1812308 : ret = PQgetCopyData(conn, ©buf, 0);
2433 : :
7178 tgl@sss.pgh.pa.us 2434 [ + + ]: 1812308 : if (ret < 0)
2435 : 4062 : break; /* done or error */
2436 : :
2437 [ + - ]: 1808246 : if (copybuf)
2438 : : {
2439 : 1808246 : WriteData(fout, copybuf, ret);
2440 : 1808246 : PQfreemem(copybuf);
2441 : : }
2442 : :
2443 : : /* ----------
2444 : : * THROTTLE:
2445 : : *
2446 : : * There was considerable discussion in late July, 2000 regarding
2447 : : * slowing down pg_dump when backing up large tables. Users with both
2448 : : * slow & fast (multi-processor) machines experienced performance
2449 : : * degradation when doing a backup.
2450 : : *
2451 : : * Initial attempts based on sleeping for a number of ms for each ms
2452 : : * of work were deemed too complex, then a simple 'sleep in each loop'
2453 : : * implementation was suggested. The latter failed because the loop
2454 : : * was too tight. Finally, the following was implemented:
2455 : : *
2456 : : * If throttle is non-zero, then
2457 : : * See how long since the last sleep.
2458 : : * Work out how long to sleep (based on ratio).
2459 : : * If sleep is more than 100ms, then
2460 : : * sleep
2461 : : * reset timer
2462 : : * EndIf
2463 : : * EndIf
2464 : : *
2465 : : * where the throttle value was the number of ms to sleep per ms of
2466 : : * work. The calculation was done in each loop.
2467 : : *
2468 : : * Most of the hard work is done in the backend, and this solution
2469 : : * still did not work particularly well: on slow machines, the ratio
2470 : : * was 50:1, and on medium paced machines, 1:1, and on fast
2471 : : * multi-processor machines, it had little or no effect, for reasons
2472 : : * that were unclear.
2473 : : *
2474 : : * Further discussion ensued, and the proposal was dropped.
2475 : : *
2476 : : * For those people who want this feature, it can be implemented using
2477 : : * gettimeofday in each loop, calculating the time since last sleep,
2478 : : * multiplying that by the sleep ratio, then if the result is more
2479 : : * than a preset 'minimum sleep time' (say 100ms), call the 'select'
2480 : : * function to sleep for a subsecond period ie.
2481 : : *
2482 : : * select(0, NULL, NULL, NULL, &tvi);
2483 : : *
2484 : : * This will return after the interval specified in the structure tvi.
2485 : : * Finally, call gettimeofday again to save the 'last sleep time'.
2486 : : * ----------
2487 : : */
2488 : : }
8471 peter_e@gmx.net 2489 : 4062 : archprintf(fout, "\\.\n\n\n");
2490 : :
7178 tgl@sss.pgh.pa.us 2491 [ - + ]: 4062 : if (ret == -2)
2492 : : {
2493 : : /* copy data transfer failed */
2401 peter@eisentraut.org 2494 :UBC 0 : pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
1298 tgl@sss.pgh.pa.us 2495 : 0 : pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2496 : 0 : pg_log_error_detail("Command was: %s", q->data);
5002 rhaas@postgresql.org 2497 : 0 : exit_nicely(1);
2498 : : }
2499 : :
2500 : : /* Check command status and return to normal libpq state */
5002 rhaas@postgresql.org 2501 :CBC 4062 : res = PQgetResult(conn);
5011 2502 [ - + ]: 4062 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
2503 : : {
2401 peter@eisentraut.org 2504 :UBC 0 : pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
1298 tgl@sss.pgh.pa.us 2505 : 0 : pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2506 : 0 : pg_log_error_detail("Command was: %s", q->data);
5002 rhaas@postgresql.org 2507 : 0 : exit_nicely(1);
2508 : : }
8518 bruce@momjian.us 2509 :CBC 4062 : PQclear(res);
2510 : :
2511 : : /* Do this to ensure we've pumped libpq back to idle state */
3434 tgl@sss.pgh.pa.us 2512 [ - + ]: 4062 : if (PQgetResult(conn) != NULL)
2401 peter@eisentraut.org 2513 :UBC 0 : pg_log_warning("unexpected extra results during COPY of table \"%s\"",
2514 : : classname);
2515 : :
8571 tgl@sss.pgh.pa.us 2516 :CBC 4062 : destroyPQExpBuffer(q);
2517 : :
2518 : : /* Revert back the setting */
448 msawada@postgresql.o 2519 [ - + ]: 4062 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
448 msawada@postgresql.o 2520 :UBC 0 : set_restrict_relation_kind(fout, "view, foreign-table");
2521 : :
8571 tgl@sss.pgh.pa.us 2522 :CBC 4062 : return 1;
2523 : : }
2524 : :
2525 : : /*
2526 : : * Dump table data using INSERT commands.
2527 : : *
2528 : : * Caution: when we restore from an archive file direct to database, the
2529 : : * INSERT commands emitted by this function have to be parsed by
2530 : : * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
2531 : : * E'' strings, or dollar-quoted strings. So don't emit anything like that.
2532 : : */
2533 : : static int
1720 peter@eisentraut.org 2534 : 81 : dumpTableData_insert(Archive *fout, const void *dcontext)
2535 : : {
7996 tgl@sss.pgh.pa.us 2536 : 81 : TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2537 : 81 : TableInfo *tbinfo = tdinfo->tdtable;
3575 2538 : 81 : DumpOptions *dopt = fout->dopt;
8571 2539 : 81 : PQExpBuffer q = createPQExpBuffer();
4364 2540 : 81 : PQExpBuffer insertStmt = NULL;
2541 : : char *attgenerated;
2542 : : PGresult *res;
2543 : : int nfields,
2544 : : i;
2426 alvherre@alvh.no-ip. 2545 : 81 : int rows_per_statement = dopt->dump_inserts;
2546 : 81 : int rows_this_statement = 0;
2547 : :
2548 : : /* Temporary allows to access to foreign tables to dump data */
448 msawada@postgresql.o 2549 [ - + ]: 81 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
448 msawada@postgresql.o 2550 :UBC 0 : set_restrict_relation_kind(fout, "view");
2551 : :
2552 : : /*
2553 : : * If we're going to emit INSERTs with column names, the most efficient
2554 : : * way to deal with generated columns is to exclude them entirely. For
2555 : : * INSERTs without column names, we have to emit DEFAULT rather than the
2556 : : * actual column value --- but we can save a few cycles by fetching nulls
2557 : : * rather than the uninteresting-to-us value.
2558 : : */
1435 tgl@sss.pgh.pa.us 2559 :CBC 81 : attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
2560 : 81 : appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
2561 : 81 : nfields = 0;
2562 [ + + ]: 251 : for (i = 0; i < tbinfo->numatts; i++)
2563 : : {
2564 [ + + ]: 170 : if (tbinfo->attisdropped[i])
2565 : 2 : continue;
2566 [ + + + + ]: 168 : if (tbinfo->attgenerated[i] && dopt->column_inserts)
2567 : 8 : continue;
2568 [ + + ]: 160 : if (nfields > 0)
2569 : 86 : appendPQExpBufferStr(q, ", ");
2570 [ + + ]: 160 : if (tbinfo->attgenerated[i])
2571 : 8 : appendPQExpBufferStr(q, "NULL");
2572 : : else
2573 : 152 : appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
2574 : 160 : attgenerated[nfields] = tbinfo->attgenerated[i];
2575 : 160 : nfields++;
2576 : : }
2577 : : /* Servers before 9.4 will complain about zero-column SELECT */
2578 [ + + ]: 81 : if (nfields == 0)
2579 : 7 : appendPQExpBufferStr(q, "NULL");
2580 : 81 : appendPQExpBuffer(q, " FROM ONLY %s",
2800 2581 : 81 : fmtQualifiedDumpable(tbinfo));
5375 2582 [ - + ]: 81 : if (tdinfo->filtercond)
5375 tgl@sss.pgh.pa.us 2583 :UBC 0 : appendPQExpBuffer(q, " %s", tdinfo->filtercond);
2584 : :
5011 rhaas@postgresql.org 2585 :CBC 81 : ExecuteSqlStatement(fout, q->data);
2586 : :
2587 : : while (1)
2588 : : {
2589 : 131 : res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
2590 : : PGRES_TUPLES_OK);
2591 : :
2592 : : /* cross-check field count, allowing for dummy NULL if any */
1435 tgl@sss.pgh.pa.us 2593 [ + + + - ]: 131 : if (nfields != PQnfields(res) &&
2594 [ - + ]: 10 : !(nfields == 0 && PQnfields(res) == 1))
1298 tgl@sss.pgh.pa.us 2595 :UBC 0 : pg_fatal("wrong number of fields retrieved from table \"%s\"",
2596 : : tbinfo->dobj.name);
2597 : :
2598 : : /*
2599 : : * First time through, we build as much of the INSERT statement as
2600 : : * possible in "insertStmt", which we can then just print for each
2601 : : * statement. If the table happens to have zero dumpable columns then
2602 : : * this will be a complete statement, otherwise it will end in
2603 : : * "VALUES" and be ready to have the row's column values printed.
2604 : : */
2426 alvherre@alvh.no-ip. 2605 [ + + ]:CBC 131 : if (insertStmt == NULL)
2606 : : {
2607 : : TableInfo *targettab;
2608 : :
2609 : 81 : insertStmt = createPQExpBuffer();
2610 : :
2611 : : /*
2612 : : * When load-via-partition-root is set or forced, get the root
2613 : : * table name for the partition table, so that we can reload data
2614 : : * through the root table.
2615 : : */
955 tgl@sss.pgh.pa.us 2616 [ + + ]: 81 : if (tbinfo->ispartition &&
2617 [ + - + + ]: 48 : (dopt->load_via_partition_root ||
2618 : 24 : forcePartitionRootLoad(tbinfo)))
2426 alvherre@alvh.no-ip. 2619 : 7 : targettab = getRootTableInfo(tbinfo);
2620 : : else
2621 : 74 : targettab = tbinfo;
2622 : :
2623 : 81 : appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
2624 : 81 : fmtQualifiedDumpable(targettab));
2625 : :
2626 : : /* corner case for zero-column table */
2627 [ + + ]: 81 : if (nfields == 0)
2628 : : {
2629 : 7 : appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
2630 : : }
2631 : : else
2632 : : {
2633 : : /* append the list of column names if required */
2634 [ + + ]: 74 : if (dopt->column_inserts)
2635 : : {
2636 : 33 : appendPQExpBufferChar(insertStmt, '(');
2637 [ + + ]: 100 : for (int field = 0; field < nfields; field++)
2638 : : {
2639 [ + + ]: 67 : if (field > 0)
2640 : 34 : appendPQExpBufferStr(insertStmt, ", ");
2641 : 67 : appendPQExpBufferStr(insertStmt,
2642 : 67 : fmtId(PQfname(res, field)));
2643 : : }
2644 : 33 : appendPQExpBufferStr(insertStmt, ") ");
2645 : : }
2646 : :
2647 [ + + ]: 74 : if (tbinfo->needs_override)
2648 : 2 : appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
2649 : :
2650 : 74 : appendPQExpBufferStr(insertStmt, "VALUES");
2651 : : }
2652 : : }
2653 : :
2654 [ + + ]: 3400 : for (int tuple = 0; tuple < PQntuples(res); tuple++)
2655 : : {
2656 : : /* Write the INSERT if not in the middle of a multi-row INSERT. */
2657 [ + + ]: 3269 : if (rows_this_statement == 0)
2658 : 3263 : archputs(insertStmt->data, fout);
2659 : :
2660 : : /*
2661 : : * If it is zero-column table then we've already written the
2662 : : * complete statement, which will mean we've disobeyed
2663 : : * --rows-per-insert when it's set greater than 1. We do support
2664 : : * a way to make this multi-row with: SELECT UNION ALL SELECT
2665 : : * UNION ALL ... but that's non-standard so we should avoid it
2666 : : * given that using INSERTs is mostly only ever needed for
2667 : : * cross-database exports.
2668 : : */
4364 tgl@sss.pgh.pa.us 2669 [ + + ]: 3269 : if (nfields == 0)
2670 : 6 : continue;
2671 : :
2672 : : /* Emit a row heading */
2426 alvherre@alvh.no-ip. 2673 [ + + ]: 3263 : if (rows_per_statement == 1)
2674 : 3254 : archputs(" (", fout);
2675 [ + + ]: 9 : else if (rows_this_statement > 0)
2676 : 6 : archputs(",\n\t(", fout);
2677 : : else
2678 : 3 : archputs("\n\t(", fout);
2679 : :
2680 [ + + ]: 9845 : for (int field = 0; field < nfields; field++)
2681 : : {
8571 tgl@sss.pgh.pa.us 2682 [ + + ]: 6582 : if (field > 0)
4364 2683 : 3319 : archputs(", ", fout);
1435 2684 [ + + ]: 6582 : if (attgenerated[field])
2685 : : {
2403 peter@eisentraut.org 2686 : 2 : archputs("DEFAULT", fout);
2687 : 2 : continue;
2688 : : }
8571 tgl@sss.pgh.pa.us 2689 [ + + ]: 6580 : if (PQgetisnull(res, tuple, field))
2690 : : {
4364 2691 : 83 : archputs("NULL", fout);
8571 2692 : 83 : continue;
2693 : : }
2694 : :
2695 : : /* XXX This code is partially duplicated in ruleutils.c */
2696 [ + + + + ]: 6497 : switch (PQftype(res, field))
2697 : : {
2698 : 4469 : case INT2OID:
2699 : : case INT4OID:
2700 : : case INT8OID:
2701 : : case OIDOID:
2702 : : case FLOAT4OID:
2703 : : case FLOAT8OID:
2704 : : case NUMERICOID:
2705 : : {
2706 : : /*
2707 : : * These types are printed without quotes unless
2708 : : * they contain values that aren't accepted by the
2709 : : * scanner unquoted (e.g., 'NaN'). Note that
2710 : : * strtod() and friends might accept NaN, so we
2711 : : * can't use that to test.
2712 : : *
2713 : : * In reality we only need to defend against
2714 : : * infinity and NaN, so we need not get too crazy
2715 : : * about pattern matching here.
2716 : : */
8454 bruce@momjian.us 2717 : 4469 : const char *s = PQgetvalue(res, tuple, field);
2718 : :
2719 [ + + ]: 4469 : if (strspn(s, "0123456789 +-eE.") == strlen(s))
4364 tgl@sss.pgh.pa.us 2720 : 4467 : archputs(s, fout);
2721 : : else
8454 bruce@momjian.us 2722 : 2 : archprintf(fout, "'%s'", s);
2723 : : }
2724 : 4469 : break;
2725 : :
8571 tgl@sss.pgh.pa.us 2726 : 2 : case BITOID:
2727 : : case VARBITOID:
2728 : 2 : archprintf(fout, "B'%s'",
2729 : : PQgetvalue(res, tuple, field));
2730 : 2 : break;
2731 : :
8471 peter_e@gmx.net 2732 : 4 : case BOOLOID:
8454 bruce@momjian.us 2733 [ + + ]: 4 : if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
4364 tgl@sss.pgh.pa.us 2734 : 2 : archputs("true", fout);
2735 : : else
2736 : 2 : archputs("false", fout);
8471 peter_e@gmx.net 2737 : 4 : break;
2738 : :
2739 : 2022 : default:
2740 : : /* All other types are printed as string literals. */
8571 tgl@sss.pgh.pa.us 2741 : 2022 : resetPQExpBuffer(q);
7092 2742 : 2022 : appendStringLiteralAH(q,
2743 : : PQgetvalue(res, tuple, field),
2744 : : fout);
7579 2745 : 2022 : archputs(q->data, fout);
8571 2746 : 2022 : break;
2747 : : }
2748 : : }
2749 : :
2750 : : /* Terminate the row ... */
2426 alvherre@alvh.no-ip. 2751 : 3263 : archputs(")", fout);
2752 : :
2753 : : /* ... and the statement, if the target no. of rows is reached */
2754 [ + + ]: 3263 : if (++rows_this_statement >= rows_per_statement)
2755 : : {
2756 [ - + ]: 3256 : if (dopt->do_nothing)
2426 alvherre@alvh.no-ip. 2757 :UBC 0 : archputs(" ON CONFLICT DO NOTHING;\n", fout);
2758 : : else
2426 alvherre@alvh.no-ip. 2759 :CBC 3256 : archputs(";\n", fout);
2760 : : /* Reset the row counter */
2761 : 3256 : rows_this_statement = 0;
2762 : : }
2763 : : }
2764 : :
5011 rhaas@postgresql.org 2765 [ + + ]: 131 : if (PQntuples(res) <= 0)
2766 : : {
2767 : 81 : PQclear(res);
2768 : 81 : break;
2769 : : }
2770 : 50 : PQclear(res);
2771 : : }
2772 : :
2773 : : /* Terminate any statements that didn't make the row count. */
2426 alvherre@alvh.no-ip. 2774 [ + + ]: 81 : if (rows_this_statement > 0)
2775 : : {
2776 [ - + ]: 1 : if (dopt->do_nothing)
2426 alvherre@alvh.no-ip. 2777 :UBC 0 : archputs(" ON CONFLICT DO NOTHING;\n", fout);
2778 : : else
2426 alvherre@alvh.no-ip. 2779 :CBC 1 : archputs(";\n", fout);
2780 : : }
2781 : :
4364 tgl@sss.pgh.pa.us 2782 : 81 : archputs("\n\n", fout);
2783 : :
5011 rhaas@postgresql.org 2784 : 81 : ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2785 : :
8571 tgl@sss.pgh.pa.us 2786 : 81 : destroyPQExpBuffer(q);
4364 2787 [ + - ]: 81 : if (insertStmt != NULL)
2788 : 81 : destroyPQExpBuffer(insertStmt);
1435 2789 : 81 : free(attgenerated);
2790 : :
2791 : : /* Revert back the setting */
448 msawada@postgresql.o 2792 [ - + ]: 81 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
448 msawada@postgresql.o 2793 :UBC 0 : set_restrict_relation_kind(fout, "view, foreign-table");
2794 : :
8571 tgl@sss.pgh.pa.us 2795 :CBC 81 : return 1;
2796 : : }
2797 : :
2798 : : /*
2799 : : * getRootTableInfo:
2800 : : * get the root TableInfo for the given partition table.
2801 : : */
2802 : : static TableInfo *
1720 peter@eisentraut.org 2803 : 79 : getRootTableInfo(const TableInfo *tbinfo)
2804 : : {
2805 : : TableInfo *parentTbinfo;
2806 : :
2996 rhaas@postgresql.org 2807 [ - + ]: 79 : Assert(tbinfo->ispartition);
2808 [ - + ]: 79 : Assert(tbinfo->numParents == 1);
2809 : :
2810 : 79 : parentTbinfo = tbinfo->parents[0];
2811 [ - + ]: 79 : while (parentTbinfo->ispartition)
2812 : : {
2996 rhaas@postgresql.org 2813 [ # # ]:UBC 0 : Assert(parentTbinfo->numParents == 1);
2814 : 0 : parentTbinfo = parentTbinfo->parents[0];
2815 : : }
2816 : :
2996 rhaas@postgresql.org 2817 :CBC 79 : return parentTbinfo;
2818 : : }
2819 : :
2820 : : /*
2821 : : * forcePartitionRootLoad
2822 : : * Check if we must force load_via_partition_root for this partition.
2823 : : *
2824 : : * This is required if any level of ancestral partitioned table has an
2825 : : * unsafe partitioning scheme.
2826 : : */
2827 : : static bool
955 tgl@sss.pgh.pa.us 2828 : 1048 : forcePartitionRootLoad(const TableInfo *tbinfo)
2829 : : {
2830 : : TableInfo *parentTbinfo;
2831 : :
2832 [ - + ]: 1048 : Assert(tbinfo->ispartition);
2833 [ - + ]: 1048 : Assert(tbinfo->numParents == 1);
2834 : :
2835 : 1048 : parentTbinfo = tbinfo->parents[0];
2836 [ + + ]: 1048 : if (parentTbinfo->unsafe_partitions)
2837 : 79 : return true;
2838 [ + + ]: 1185 : while (parentTbinfo->ispartition)
2839 : : {
2840 [ - + ]: 216 : Assert(parentTbinfo->numParents == 1);
2841 : 216 : parentTbinfo = parentTbinfo->parents[0];
2842 [ - + ]: 216 : if (parentTbinfo->unsafe_partitions)
955 tgl@sss.pgh.pa.us 2843 :UBC 0 : return true;
2844 : : }
2845 : :
955 tgl@sss.pgh.pa.us 2846 :CBC 969 : return false;
2847 : : }
2848 : :
2849 : : /*
2850 : : * dumpTableData -
2851 : : * dump the contents of a single table
2852 : : *
2853 : : * Actually, this just makes an ArchiveEntry for the table contents.
2854 : : */
2855 : : static void
1720 peter@eisentraut.org 2856 : 4224 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
2857 : : {
3575 tgl@sss.pgh.pa.us 2858 : 4224 : DumpOptions *dopt = fout->dopt;
7996 2859 : 4224 : TableInfo *tbinfo = tdinfo->tdtable;
5374 2860 : 4224 : PQExpBuffer copyBuf = createPQExpBuffer();
4600 andrew@dunslane.net 2861 : 4224 : PQExpBuffer clistBuf = createPQExpBuffer();
2862 : : DataDumperPtr dumpFn;
955 tgl@sss.pgh.pa.us 2863 : 4224 : char *tdDefn = NULL;
2864 : : char *copyStmt;
2865 : : const char *copyFrom;
2866 : :
2867 : : /* We had better have loaded per-column details about this table */
1846 2868 [ - + ]: 4224 : Assert(tbinfo->interesting);
2869 : :
2870 : : /*
2871 : : * When load-via-partition-root is set or forced, get the root table name
2872 : : * for the partition table, so that we can reload data through the root
2873 : : * table. Then construct a comment to be inserted into the TOC entry's
2874 : : * defn field, so that such cases can be identified reliably.
2875 : : */
955 2876 [ + + ]: 4224 : if (tbinfo->ispartition &&
2877 [ + - + + ]: 2048 : (dopt->load_via_partition_root ||
2878 : 1024 : forcePartitionRootLoad(tbinfo)))
2879 : 72 : {
2880 : : TableInfo *parentTbinfo;
2881 : : char *sanitized;
2882 : :
2883 : 72 : parentTbinfo = getRootTableInfo(tbinfo);
2884 : 72 : copyFrom = fmtQualifiedDumpable(parentTbinfo);
77 noah@leadboat.com 2885 : 72 : sanitized = sanitize_line(copyFrom, true);
955 tgl@sss.pgh.pa.us 2886 : 72 : printfPQExpBuffer(copyBuf, "-- load via partition root %s",
2887 : : sanitized);
77 noah@leadboat.com 2888 : 72 : free(sanitized);
955 tgl@sss.pgh.pa.us 2889 : 72 : tdDefn = pg_strdup(copyBuf->data);
2890 : : }
2891 : : else
2892 : 4152 : copyFrom = fmtQualifiedDumpable(tbinfo);
2893 : :
1937 alvherre@alvh.no-ip. 2894 [ + + ]: 4224 : if (dopt->dump_inserts == 0)
2895 : : {
2896 : : /* Dump/restore using COPY */
7996 tgl@sss.pgh.pa.us 2897 : 4143 : dumpFn = dumpTableData_copy;
2898 : : /* must use 2 steps here 'cause fmtId is nonreentrant */
955 2899 : 4143 : printfPQExpBuffer(copyBuf, "COPY %s ",
2900 : : copyFrom);
2533 andres@anarazel.de 2901 : 4143 : appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2902 : : fmtCopyColumnList(tbinfo, clistBuf));
7996 tgl@sss.pgh.pa.us 2903 : 4143 : copyStmt = copyBuf->data;
2904 : : }
2905 : : else
2906 : : {
2907 : : /* Restore using INSERT */
2908 : 81 : dumpFn = dumpTableData_insert;
2909 : 81 : copyStmt = NULL;
2910 : : }
2911 : :
2912 : : /*
2913 : : * Note: although the TableDataInfo is a full DumpableObject, we treat its
2914 : : * dependency on its table as "special" and pass it to ArchiveEntry now.
2915 : : * See comments for BuildArchiveDependencies.
2916 : : */
3491 sfrost@snowman.net 2917 [ + - ]: 4224 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2918 : : {
2919 : : TocEntry *te;
2920 : :
2600 tgl@sss.pgh.pa.us 2921 : 4224 : te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 2922 : 4224 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2923 : : .namespace = tbinfo->dobj.namespace->dobj.name,
2924 : : .owner = tbinfo->rolname,
2925 : : .description = "TABLE DATA",
2926 : : .section = SECTION_DATA,
2927 : : .createStmt = tdDefn,
2928 : : .copyStmt = copyStmt,
2929 : : .deps = &(tbinfo->dobj.dumpId),
2930 : : .nDeps = 1,
2931 : : .dumpFn = dumpFn,
2932 : : .dumpArg = tdinfo));
2933 : :
2934 : : /*
2935 : : * Set the TocEntry's dataLength in case we are doing a parallel dump
2936 : : * and want to order dump jobs by table size. We choose to measure
2937 : : * dataLength in table pages (including TOAST pages) during dump, so
2938 : : * no scaling is needed.
2939 : : *
2940 : : * However, relpages is declared as "integer" in pg_class, and hence
2941 : : * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2942 : : * Cast so that we get the right interpretation of table sizes
2943 : : * exceeding INT_MAX pages.
2944 : : */
2600 tgl@sss.pgh.pa.us 2945 : 4224 : te->dataLength = (BlockNumber) tbinfo->relpages;
1421 2946 : 4224 : te->dataLength += (BlockNumber) tbinfo->toastpages;
2947 : :
2948 : : /*
2949 : : * If pgoff_t is only 32 bits wide, the above refinement is useless,
2950 : : * and instead we'd better worry about integer overflow. Clamp to
2951 : : * INT_MAX if the correct result exceeds that.
2952 : : */
2953 : : if (sizeof(te->dataLength) == 4 &&
2954 : : (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
2955 : : te->dataLength < 0))
2956 : : te->dataLength = INT_MAX;
2957 : : }
2958 : :
7996 2959 : 4224 : destroyPQExpBuffer(copyBuf);
4600 andrew@dunslane.net 2960 : 4224 : destroyPQExpBuffer(clistBuf);
7996 tgl@sss.pgh.pa.us 2961 : 4224 : }
2962 : :
2963 : : /*
2964 : : * refreshMatViewData -
2965 : : * load or refresh the contents of a single materialized view
2966 : : *
2967 : : * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2968 : : * statement.
2969 : : */
2970 : : static void
1720 peter@eisentraut.org 2971 : 348 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
2972 : : {
4621 kgrittn@postgresql.o 2973 : 348 : TableInfo *tbinfo = tdinfo->tdtable;
2974 : : PQExpBuffer q;
2975 : :
2976 : : /* If the materialized view is not flagged as populated, skip this. */
4557 tgl@sss.pgh.pa.us 2977 [ + + ]: 348 : if (!tbinfo->relispopulated)
4621 kgrittn@postgresql.o 2978 : 68 : return;
2979 : :
2980 : 280 : q = createPQExpBuffer();
2981 : :
2982 : 280 : appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2800 tgl@sss.pgh.pa.us 2983 : 280 : fmtQualifiedDumpable(tbinfo));
2984 : :
3491 sfrost@snowman.net 2985 [ + - ]: 280 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2986 : 280 : ArchiveEntry(fout,
2987 : : tdinfo->dobj.catId, /* catalog ID */
3050 tgl@sss.pgh.pa.us 2988 : 280 : tdinfo->dobj.dumpId, /* dump ID */
2460 alvherre@alvh.no-ip. 2989 : 280 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2990 : : .namespace = tbinfo->dobj.namespace->dobj.name,
2991 : : .owner = tbinfo->rolname,
2992 : : .description = "MATERIALIZED VIEW DATA",
2993 : : .section = SECTION_POST_DATA,
2994 : : .createStmt = q->data,
2995 : : .deps = tdinfo->dobj.dependencies,
2996 : : .nDeps = tdinfo->dobj.nDeps));
2997 : :
4621 kgrittn@postgresql.o 2998 : 280 : destroyPQExpBuffer(q);
2999 : : }
3000 : :
3001 : : /*
3002 : : * getTableData -
3003 : : * set up dumpable objects representing the contents of tables
3004 : : */
3005 : : static void
2533 andres@anarazel.de 3006 : 181 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
3007 : : {
3008 : : int i;
3009 : :
8571 tgl@sss.pgh.pa.us 3010 [ + + ]: 47921 : for (i = 0; i < numTables; i++)
3011 : : {
3352 peter_e@gmx.net 3012 [ + + + + ]: 47740 : if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
3013 [ + + ]: 927 : (!relkind || tblinfo[i].relkind == relkind))
2533 andres@anarazel.de 3014 : 5889 : makeTableDataInfo(dopt, &(tblinfo[i]));
3015 : : }
5375 tgl@sss.pgh.pa.us 3016 : 181 : }
3017 : :
3018 : : /*
3019 : : * Make a dumpable object for the data of this specific table
3020 : : *
3021 : : * Note: we make a TableDataInfo if and only if we are going to dump the
3022 : : * table data; the "dump" field in such objects isn't very interesting.
3023 : : */
3024 : : static void
2533 andres@anarazel.de 3025 : 6000 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
3026 : : {
3027 : : TableDataInfo *tdinfo;
3028 : :
3029 : : /*
3030 : : * Nothing to do if we already decided to dump the table. This will
3031 : : * happen for "config" tables.
3032 : : */
5010 tgl@sss.pgh.pa.us 3033 [ + + ]: 6000 : if (tbinfo->dataObj != NULL)
3034 : 1 : return;
3035 : :
3036 : : /* Skip VIEWs (no data to dump) */
3037 [ + + ]: 5999 : if (tbinfo->relkind == RELKIND_VIEW)
3038 : 484 : return;
3039 : : /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
2042 alvherre@alvh.no-ip. 3040 [ + + ]: 5515 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
3041 [ + + ]: 38 : (foreign_servers_include_oids.head == NULL ||
1992 tgl@sss.pgh.pa.us 3042 [ + + ]: 4 : !simple_oid_list_member(&foreign_servers_include_oids,
3043 : : tbinfo->foreign_server)))
5010 3044 : 37 : return;
3045 : : /* Skip partitioned tables (data in partitions) */
3246 rhaas@postgresql.org 3046 [ + + ]: 5478 : if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
3047 : 487 : return;
3048 : :
3049 : : /* Don't dump data in unlogged tables, if so requested */
5010 tgl@sss.pgh.pa.us 3050 [ + + ]: 4991 : if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
4031 alvherre@alvh.no-ip. 3051 [ + + ]: 41 : dopt->no_unlogged_table_data)
5010 tgl@sss.pgh.pa.us 3052 : 18 : return;
3053 : :
3054 : : /* Check that the data is not explicitly excluded */
3055 [ + + ]: 4973 : if (simple_oid_list_member(&tabledata_exclude_oids,
3056 : : tbinfo->dobj.catId.oid))
3057 : 8 : return;
3058 : :
3059 : : /* OK, let's dump it */
5085 bruce@momjian.us 3060 : 4965 : tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
3061 : :
4621 kgrittn@postgresql.o 3062 [ + + ]: 4965 : if (tbinfo->relkind == RELKIND_MATVIEW)
3063 : 348 : tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
3352 peter_e@gmx.net 3064 [ + + ]: 4617 : else if (tbinfo->relkind == RELKIND_SEQUENCE)
3065 : 393 : tdinfo->dobj.objType = DO_SEQUENCE_SET;
3066 : : else
4621 kgrittn@postgresql.o 3067 : 4224 : tdinfo->dobj.objType = DO_TABLE_DATA;
3068 : :
3069 : : /*
3070 : : * Note: use tableoid 0 so that this object won't be mistaken for
3071 : : * something that pg_depend entries apply to.
3072 : : */
5375 tgl@sss.pgh.pa.us 3073 : 4965 : tdinfo->dobj.catId.tableoid = 0;
3074 : 4965 : tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3075 : 4965 : AssignDumpId(&tdinfo->dobj);
3076 : 4965 : tdinfo->dobj.name = tbinfo->dobj.name;
3077 : 4965 : tdinfo->dobj.namespace = tbinfo->dobj.namespace;
3078 : 4965 : tdinfo->tdtable = tbinfo;
5314 bruce@momjian.us 3079 : 4965 : tdinfo->filtercond = NULL; /* might get set later */
5375 tgl@sss.pgh.pa.us 3080 : 4965 : addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
3081 : :
3082 : : /* A TableDataInfo contains data, of course */
1421 3083 : 4965 : tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
3084 : :
5375 3085 : 4965 : tbinfo->dataObj = tdinfo;
3086 : :
3087 : : /*
3088 : : * Materialized view statistics must be restored after the data, because
3089 : : * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
3090 : : *
3091 : : * The dependency is added here because the statistics objects are created
3092 : : * first.
3093 : : */
213 jdavis@postgresql.or 3094 [ + + + + ]: 4965 : if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
3095 : : {
3096 : 271 : tbinfo->stats->section = SECTION_POST_DATA;
3097 : 271 : addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
3098 : : }
3099 : :
3100 : : /* Make sure that we'll collect per-column info for this table. */
1846 tgl@sss.pgh.pa.us 3101 : 4965 : tbinfo->interesting = true;
3102 : : }
3103 : :
3104 : : /*
3105 : : * The refresh for a materialized view must be dependent on the refresh for
3106 : : * any materialized view that this one is dependent on.
3107 : : *
3108 : : * This must be called after all the objects are created, but before they are
3109 : : * sorted.
3110 : : */
3111 : : static void
4621 kgrittn@postgresql.o 3112 : 149 : buildMatViewRefreshDependencies(Archive *fout)
3113 : : {
3114 : : PQExpBuffer query;
3115 : : PGresult *res;
3116 : : int ntups,
3117 : : i;
3118 : : int i_classid,
3119 : : i_objid,
3120 : : i_refobjid;
3121 : :
3122 : : /* No Mat Views before 9.3. */
4611 3123 [ - + ]: 149 : if (fout->remoteVersion < 90300)
4611 kgrittn@postgresql.o 3124 :UBC 0 : return;
3125 : :
4611 kgrittn@postgresql.o 3126 :CBC 149 : query = createPQExpBuffer();
3127 : :
4361 heikki.linnakangas@i 3128 : 149 : appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
3129 : : "( "
3130 : : "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
3131 : : "FROM pg_depend d1 "
3132 : : "JOIN pg_class c1 ON c1.oid = d1.objid "
3133 : : "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
3134 : : " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
3135 : : "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
3136 : : "AND d2.objid = r1.oid "
3137 : : "AND d2.refobjid <> d1.objid "
3138 : : "JOIN pg_class c2 ON c2.oid = d2.refobjid "
3139 : : "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
3140 : : CppAsString2(RELKIND_VIEW) ") "
3141 : : "WHERE d1.classid = 'pg_class'::regclass "
3142 : : "UNION "
3143 : : "SELECT w.objid, d3.refobjid, c3.relkind "
3144 : : "FROM w "
3145 : : "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
3146 : : "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
3147 : : "AND d3.objid = r3.oid "
3148 : : "AND d3.refobjid <> w.refobjid "
3149 : : "JOIN pg_class c3 ON c3.oid = d3.refobjid "
3150 : : "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
3151 : : CppAsString2(RELKIND_VIEW) ") "
3152 : : ") "
3153 : : "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
3154 : : "FROM w "
3155 : : "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
3156 : :
4621 kgrittn@postgresql.o 3157 : 149 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3158 : :
3159 : 149 : ntups = PQntuples(res);
3160 : :
3161 : 149 : i_classid = PQfnumber(res, "classid");
3162 : 149 : i_objid = PQfnumber(res, "objid");
3163 : 149 : i_refobjid = PQfnumber(res, "refobjid");
3164 : :
3165 [ + + ]: 413 : for (i = 0; i < ntups; i++)
3166 : : {
3167 : : CatalogId objId;
3168 : : CatalogId refobjId;
3169 : : DumpableObject *dobj;
3170 : : DumpableObject *refdobj;
3171 : : TableInfo *tbinfo;
3172 : : TableInfo *reftbinfo;
3173 : :
3174 : 264 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
3175 : 264 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
3176 : 264 : refobjId.tableoid = objId.tableoid;
3177 : 264 : refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
3178 : :
3179 : 264 : dobj = findObjectByCatalogId(objId);
3180 [ - + ]: 264 : if (dobj == NULL)
3181 : 48 : continue;
3182 : :
3183 [ - + ]: 264 : Assert(dobj->objType == DO_TABLE);
3184 : 264 : tbinfo = (TableInfo *) dobj;
3185 [ - + ]: 264 : Assert(tbinfo->relkind == RELKIND_MATVIEW);
3186 : 264 : dobj = (DumpableObject *) tbinfo->dataObj;
3187 [ + + ]: 264 : if (dobj == NULL)
3188 : 48 : continue;
3189 [ - + ]: 216 : Assert(dobj->objType == DO_REFRESH_MATVIEW);
3190 : :
3191 : 216 : refdobj = findObjectByCatalogId(refobjId);
3192 [ - + ]: 216 : if (refdobj == NULL)
4621 kgrittn@postgresql.o 3193 :UBC 0 : continue;
3194 : :
4621 kgrittn@postgresql.o 3195 [ - + ]:CBC 216 : Assert(refdobj->objType == DO_TABLE);
3196 : 216 : reftbinfo = (TableInfo *) refdobj;
3197 [ - + ]: 216 : Assert(reftbinfo->relkind == RELKIND_MATVIEW);
3198 : 216 : refdobj = (DumpableObject *) reftbinfo->dataObj;
3199 [ - + ]: 216 : if (refdobj == NULL)
4621 kgrittn@postgresql.o 3200 :UBC 0 : continue;
4621 kgrittn@postgresql.o 3201 [ - + ]:CBC 216 : Assert(refdobj->objType == DO_REFRESH_MATVIEW);
3202 : :
3203 : 216 : addObjectDependency(dobj, refdobj->dumpId);
3204 : :
4557 tgl@sss.pgh.pa.us 3205 [ + + ]: 216 : if (!reftbinfo->relispopulated)
3206 : 34 : tbinfo->relispopulated = false;
3207 : : }
3208 : :
4621 kgrittn@postgresql.o 3209 : 149 : PQclear(res);
3210 : :
3211 : 149 : destroyPQExpBuffer(query);
3212 : : }
3213 : :
3214 : : /*
3215 : : * getTableDataFKConstraints -
3216 : : * add dump-order dependencies reflecting foreign key constraints
3217 : : *
3218 : : * This code is executed only in a data-only dump --- in schema+data dumps
3219 : : * we handle foreign key issues by not creating the FK constraints until
3220 : : * after the data is loaded. In a data-only dump, however, we want to
3221 : : * order the table data objects in such a way that a table's referenced
3222 : : * tables are restored first. (In the presence of circular references or
3223 : : * self-references this may be impossible; we'll detect and complain about
3224 : : * that during the dependency sorting step.)
3225 : : */
3226 : : static void
6258 tgl@sss.pgh.pa.us 3227 : 7 : getTableDataFKConstraints(void)
3228 : : {
3229 : : DumpableObject **dobjs;
3230 : : int numObjs;
3231 : : int i;
3232 : :
3233 : : /* Search through all the dumpable objects for FK constraints */
3234 : 7 : getDumpableObjects(&dobjs, &numObjs);
3235 [ + + ]: 30682 : for (i = 0; i < numObjs; i++)
3236 : : {
3237 [ + + ]: 30675 : if (dobjs[i]->objType == DO_FK_CONSTRAINT)
3238 : : {
3239 : 8 : ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
3240 : : TableInfo *ftable;
3241 : :
3242 : : /* Not interesting unless both tables are to be dumped */
3243 [ + - ]: 8 : if (cinfo->contable == NULL ||
3244 [ + + ]: 8 : cinfo->contable->dataObj == NULL)
3245 : 4 : continue;
3246 : 4 : ftable = findTableByOid(cinfo->confrelid);
3247 [ + - ]: 4 : if (ftable == NULL ||
3248 [ - + ]: 4 : ftable->dataObj == NULL)
6258 tgl@sss.pgh.pa.us 3249 :UBC 0 : continue;
3250 : :
3251 : : /*
3252 : : * Okay, make referencing table's TABLE_DATA object depend on the
3253 : : * referenced table's TABLE_DATA object.
3254 : : */
6258 tgl@sss.pgh.pa.us 3255 :CBC 4 : addObjectDependency(&cinfo->contable->dataObj->dobj,
3256 : 4 : ftable->dataObj->dobj.dumpId);
3257 : : }
3258 : : }
3259 : 7 : free(dobjs);
3260 : 7 : }
3261 : :
3262 : :
3263 : : /*
3264 : : * dumpDatabase:
3265 : : * dump the database definition
3266 : : */
3267 : : static void
3575 3268 : 87 : dumpDatabase(Archive *fout)
3269 : : {
3270 : 87 : DumpOptions *dopt = fout->dopt;
8985 bruce@momjian.us 3271 : 87 : PQExpBuffer dbQry = createPQExpBuffer();
3272 : 87 : PQExpBuffer delQry = createPQExpBuffer();
3273 : 87 : PQExpBuffer creaQry = createPQExpBuffer();
2835 tgl@sss.pgh.pa.us 3274 : 87 : PQExpBuffer labelq = createPQExpBuffer();
5002 rhaas@postgresql.org 3275 : 87 : PGconn *conn = GetConnection(fout);
3276 : : PGresult *res;
3277 : : int i_tableoid,
3278 : : i_oid,
3279 : : i_datname,
3280 : : i_datdba,
3281 : : i_encoding,
3282 : : i_datlocprovider,
3283 : : i_collate,
3284 : : i_ctype,
3285 : : i_datlocale,
3286 : : i_daticurules,
3287 : : i_frozenxid,
3288 : : i_minmxid,
3289 : : i_datacl,
3290 : : i_acldefault,
3291 : : i_datistemplate,
3292 : : i_datconnlimit,
3293 : : i_datcollversion,
3294 : : i_tablespace;
3295 : : CatalogId dbCatId;
3296 : : DumpId dbDumpId;
3297 : : DumpableAcl dbdacl;
3298 : : const char *datname,
3299 : : *dba,
3300 : : *encoding,
3301 : : *datlocprovider,
3302 : : *collate,
3303 : : *ctype,
3304 : : *locale,
3305 : : *icurules,
3306 : : *datistemplate,
3307 : : *datconnlimit,
3308 : : *tablespace;
3309 : : uint32 frozenxid,
3310 : : minmxid;
3311 : : char *qdatname;
3312 : :
2401 peter@eisentraut.org 3313 : 87 : pg_log_info("saving database definition");
3314 : :
3315 : : /*
3316 : : * Fetch the database-level properties for this database.
3317 : : */
1147 drowley@postgresql.o 3318 : 87 : appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
3319 : : "datdba, "
3320 : : "pg_encoding_to_char(encoding) AS encoding, "
3321 : : "datcollate, datctype, datfrozenxid, "
3322 : : "datacl, acldefault('d', datdba) AS acldefault, "
3323 : : "datistemplate, datconnlimit, ");
1421 tgl@sss.pgh.pa.us 3324 [ + - ]: 87 : if (fout->remoteVersion >= 90300)
1147 drowley@postgresql.o 3325 : 87 : appendPQExpBufferStr(dbQry, "datminmxid, ");
3326 : : else
1147 drowley@postgresql.o 3327 :UBC 0 : appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
597 jdavis@postgresql.or 3328 [ + - ]:CBC 87 : if (fout->remoteVersion >= 170000)
3329 : 87 : appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
597 jdavis@postgresql.or 3330 [ # # ]:UBC 0 : else if (fout->remoteVersion >= 150000)
3331 : 0 : appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
3332 : : else
3333 : 0 : appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
964 peter@eisentraut.org 3334 [ + - ]:CBC 87 : if (fout->remoteVersion >= 160000)
3335 : 87 : appendPQExpBufferStr(dbQry, "daticurules, ");
3336 : : else
964 peter@eisentraut.org 3337 :UBC 0 : appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
1147 drowley@postgresql.o 3338 :CBC 87 : appendPQExpBufferStr(dbQry,
3339 : : "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
3340 : : "shobj_description(oid, 'pg_database') AS description "
3341 : : "FROM pg_database "
3342 : : "WHERE datname = current_database()");
3343 : :
5002 rhaas@postgresql.org 3344 : 87 : res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
3345 : :
7996 tgl@sss.pgh.pa.us 3346 : 87 : i_tableoid = PQfnumber(res, "tableoid");
3347 : 87 : i_oid = PQfnumber(res, "oid");
2757 peter_e@gmx.net 3348 : 87 : i_datname = PQfnumber(res, "datname");
1396 tgl@sss.pgh.pa.us 3349 : 87 : i_datdba = PQfnumber(res, "datdba");
8659 3350 : 87 : i_encoding = PQfnumber(res, "encoding");
1320 peter@eisentraut.org 3351 : 87 : i_datlocprovider = PQfnumber(res, "datlocprovider");
6242 heikki.linnakangas@i 3352 : 87 : i_collate = PQfnumber(res, "datcollate");
3353 : 87 : i_ctype = PQfnumber(res, "datctype");
597 jdavis@postgresql.or 3354 : 87 : i_datlocale = PQfnumber(res, "datlocale");
964 peter@eisentraut.org 3355 : 87 : i_daticurules = PQfnumber(res, "daticurules");
6095 bruce@momjian.us 3356 : 87 : i_frozenxid = PQfnumber(res, "datfrozenxid");
4135 3357 : 87 : i_minmxid = PQfnumber(res, "datminmxid");
2835 tgl@sss.pgh.pa.us 3358 : 87 : i_datacl = PQfnumber(res, "datacl");
1421 3359 : 87 : i_acldefault = PQfnumber(res, "acldefault");
2835 3360 : 87 : i_datistemplate = PQfnumber(res, "datistemplate");
3361 : 87 : i_datconnlimit = PQfnumber(res, "datconnlimit");
1351 peter@eisentraut.org 3362 : 87 : i_datcollversion = PQfnumber(res, "datcollversion");
7801 tgl@sss.pgh.pa.us 3363 : 87 : i_tablespace = PQfnumber(res, "tablespace");
3364 : :
7996 3365 : 87 : dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
3366 : 87 : dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2757 peter_e@gmx.net 3367 : 87 : datname = PQgetvalue(res, 0, i_datname);
1396 tgl@sss.pgh.pa.us 3368 : 87 : dba = getRoleName(PQgetvalue(res, 0, i_datdba));
8659 3369 : 87 : encoding = PQgetvalue(res, 0, i_encoding);
1320 peter@eisentraut.org 3370 : 87 : datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
6243 heikki.linnakangas@i 3371 : 87 : collate = PQgetvalue(res, 0, i_collate);
3372 : 87 : ctype = PQgetvalue(res, 0, i_ctype);
597 jdavis@postgresql.or 3373 [ + + ]: 87 : if (!PQgetisnull(res, 0, i_datlocale))
3374 : 14 : locale = PQgetvalue(res, 0, i_datlocale);
3375 : : else
3376 : 73 : locale = NULL;
964 peter@eisentraut.org 3377 [ - + ]: 87 : if (!PQgetisnull(res, 0, i_daticurules))
964 peter@eisentraut.org 3378 :UBC 0 : icurules = PQgetvalue(res, 0, i_daticurules);
3379 : : else
964 peter@eisentraut.org 3380 :CBC 87 : icurules = NULL;
6095 bruce@momjian.us 3381 : 87 : frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
4135 3382 : 87 : minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
1421 tgl@sss.pgh.pa.us 3383 : 87 : dbdacl.acl = PQgetvalue(res, 0, i_datacl);
3384 : 87 : dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
2835 3385 : 87 : datistemplate = PQgetvalue(res, 0, i_datistemplate);
3386 : 87 : datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
7801 3387 : 87 : tablespace = PQgetvalue(res, 0, i_tablespace);
3388 : :
2757 peter_e@gmx.net 3389 : 87 : qdatname = pg_strdup(fmtId(datname));
3390 : :
3391 : : /*
3392 : : * Prepare the CREATE DATABASE command. We must specify OID (if we want
3393 : : * to preserve that), as well as the encoding, locale, and tablespace
3394 : : * since those can't be altered later. Other DB properties are left to
3395 : : * the DATABASE PROPERTIES entry, so that they can be applied after
3396 : : * reconnecting to the target DB.
3397 : : *
3398 : : * For binary upgrade, we use the FILE_COPY strategy because testing has
3399 : : * shown it to be faster. When the server is in binary upgrade mode, it
3400 : : * will also skip the checkpoints this strategy ordinarily performs.
3401 : : */
1372 rhaas@postgresql.org 3402 [ + + ]: 87 : if (dopt->binary_upgrade)
3403 : : {
476 nathan@postgresql.or 3404 : 35 : appendPQExpBuffer(creaQry,
3405 : : "CREATE DATABASE %s WITH TEMPLATE = template0 "
3406 : : "OID = %u STRATEGY = FILE_COPY",
3407 : : qdatname, dbCatId.oid);
3408 : : }
3409 : : else
3410 : : {
1372 rhaas@postgresql.org 3411 : 52 : appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
3412 : : qdatname);
3413 : : }
8346 tgl@sss.pgh.pa.us 3414 [ + - ]: 87 : if (strlen(encoding) > 0)
3415 : : {
4361 heikki.linnakangas@i 3416 : 87 : appendPQExpBufferStr(creaQry, " ENCODING = ");
5012 rhaas@postgresql.org 3417 : 87 : appendStringLiteralAH(creaQry, encoding, fout);
3418 : : }
3419 : :
1320 peter@eisentraut.org 3420 : 87 : appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
593 jdavis@postgresql.or 3421 [ + + ]: 87 : if (datlocprovider[0] == 'b')
3422 : 14 : appendPQExpBufferStr(creaQry, "builtin");
3423 [ + - ]: 73 : else if (datlocprovider[0] == 'c')
1320 peter@eisentraut.org 3424 : 73 : appendPQExpBufferStr(creaQry, "libc");
1320 peter@eisentraut.org 3425 [ # # ]:UBC 0 : else if (datlocprovider[0] == 'i')
3426 : 0 : appendPQExpBufferStr(creaQry, "icu");
3427 : : else
1298 tgl@sss.pgh.pa.us 3428 : 0 : pg_fatal("unrecognized locale provider: %s",
3429 : : datlocprovider);
3430 : :
2288 peter@eisentraut.org 3431 [ + - + - ]:CBC 87 : if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
3432 : : {
3433 : 87 : appendPQExpBufferStr(creaQry, " LOCALE = ");
5012 rhaas@postgresql.org 3434 : 87 : appendStringLiteralAH(creaQry, collate, fout);
3435 : : }
3436 : : else
3437 : : {
2288 peter@eisentraut.org 3438 [ # # ]:UBC 0 : if (strlen(collate) > 0)
3439 : : {
3440 : 0 : appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
3441 : 0 : appendStringLiteralAH(creaQry, collate, fout);
3442 : : }
3443 [ # # ]: 0 : if (strlen(ctype) > 0)
3444 : : {
3445 : 0 : appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
3446 : 0 : appendStringLiteralAH(creaQry, ctype, fout);
3447 : : }
3448 : : }
597 jdavis@postgresql.or 3449 [ + + ]:CBC 87 : if (locale)
3450 : : {
593 3451 [ + - ]: 14 : if (datlocprovider[0] == 'b')
3452 : 14 : appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
3453 : : else
593 jdavis@postgresql.or 3454 :UBC 0 : appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
3455 : :
597 jdavis@postgresql.or 3456 :CBC 14 : appendStringLiteralAH(creaQry, locale, fout);
3457 : : }
3458 : :
964 peter@eisentraut.org 3459 [ - + ]: 87 : if (icurules)
3460 : : {
964 peter@eisentraut.org 3461 :UBC 0 : appendPQExpBufferStr(creaQry, " ICU_RULES = ");
3462 : 0 : appendStringLiteralAH(creaQry, icurules, fout);
3463 : : }
3464 : :
3465 : : /*
3466 : : * For binary upgrade, carry over the collation version. For normal
3467 : : * dump/restore, omit the version, so that it is computed upon restore.
3468 : : */
1351 peter@eisentraut.org 3469 [ + + ]:CBC 87 : if (dopt->binary_upgrade)
3470 : : {
3471 [ + + ]: 35 : if (!PQgetisnull(res, 0, i_datcollversion))
3472 : : {
3473 : 6 : appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
3474 : 6 : appendStringLiteralAH(creaQry,
3475 : : PQgetvalue(res, 0, i_datcollversion),
3476 : : fout);
3477 : : }
3478 : : }
3479 : :
3480 : : /*
3481 : : * Note: looking at dopt->outputNoTablespaces here is completely the wrong
3482 : : * thing; the decision whether to specify a tablespace should be left till
3483 : : * pg_restore, so that pg_restore --no-tablespaces applies. Ideally we'd
3484 : : * label the DATABASE entry with the tablespace and let the normal
3485 : : * tablespace selection logic work ... but CREATE DATABASE doesn't pay
3486 : : * attention to default_tablespace, so that won't work.
3487 : : */
3336 tgl@sss.pgh.pa.us 3488 [ + - + + ]: 87 : if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
3336 tgl@sss.pgh.pa.us 3489 [ + - ]:GBC 5 : !dopt->outputNoTablespaces)
7679 3490 : 5 : appendPQExpBuffer(creaQry, " TABLESPACE = %s",
3491 : : fmtId(tablespace));
4361 heikki.linnakangas@i 3492 :CBC 87 : appendPQExpBufferStr(creaQry, ";\n");
3493 : :
8659 tgl@sss.pgh.pa.us 3494 : 87 : appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
3495 : : qdatname);
3496 : :
7996 3497 : 87 : dbDumpId = createDumpId();
3498 : :
5012 rhaas@postgresql.org 3499 : 87 : ArchiveEntry(fout,
3500 : : dbCatId, /* catalog ID */
3501 : : dbDumpId, /* dump ID */
2460 alvherre@alvh.no-ip. 3502 : 87 : ARCHIVE_OPTS(.tag = datname,
3503 : : .owner = dba,
3504 : : .description = "DATABASE",
3505 : : .section = SECTION_PRE_DATA,
3506 : : .createStmt = creaQry->data,
3507 : : .dropStmt = delQry->data));
3508 : :
3509 : : /* Compute correct tag for archive entry */
2835 tgl@sss.pgh.pa.us 3510 : 87 : appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
3511 : :
3512 : : /* Dump DB comment if any */
3513 : : {
3514 : : /*
3515 : : * 8.2 and up keep comments on shared objects in a shared table, so we
3516 : : * cannot use the dumpComment() code used for other database objects.
3517 : : * Be careful that the ArchiveEntry parameters match that function.
3518 : : */
3519 : 87 : char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
3520 : :
2832 3521 [ + - + + : 87 : if (comment && *comment && !dopt->no_comments)
+ - ]
3522 : : {
2835 3523 : 42 : resetPQExpBuffer(dbQry);
3524 : :
3525 : : /*
3526 : : * Generates warning when loaded into a differently-named
3527 : : * database.
3528 : : */
3529 : 42 : appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
3530 : 42 : appendStringLiteralAH(dbQry, comment, fout);
3531 : 42 : appendPQExpBufferStr(dbQry, ";\n");
3532 : :
3533 : 42 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 3534 : 42 : ARCHIVE_OPTS(.tag = labelq->data,
3535 : : .owner = dba,
3536 : : .description = "COMMENT",
3537 : : .section = SECTION_NONE,
3538 : : .createStmt = dbQry->data,
3539 : : .deps = &dbDumpId,
3540 : : .nDeps = 1));
3541 : : }
3542 : : }
3543 : :
3544 : : /* Dump DB security label, if enabled */
1413 tgl@sss.pgh.pa.us 3545 [ + - ]: 87 : if (!dopt->no_security_labels)
3546 : : {
3547 : : PGresult *shres;
3548 : : PQExpBuffer seclabelQry;
3549 : :
2835 3550 : 87 : seclabelQry = createPQExpBuffer();
3551 : :
1889 peter@eisentraut.org 3552 : 87 : buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
2835 tgl@sss.pgh.pa.us 3553 : 87 : shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
3554 : 87 : resetPQExpBuffer(seclabelQry);
3555 : 87 : emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
3556 [ - + ]: 87 : if (seclabelQry->len > 0)
2835 tgl@sss.pgh.pa.us 3557 :UBC 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 3558 : 0 : ARCHIVE_OPTS(.tag = labelq->data,
3559 : : .owner = dba,
3560 : : .description = "SECURITY LABEL",
3561 : : .section = SECTION_NONE,
3562 : : .createStmt = seclabelQry->data,
3563 : : .deps = &dbDumpId,
3564 : : .nDeps = 1));
2835 tgl@sss.pgh.pa.us 3565 :CBC 87 : destroyPQExpBuffer(seclabelQry);
3566 : 87 : PQclear(shres);
3567 : : }
3568 : :
3569 : : /*
3570 : : * Dump ACL if any. Note that we do not support initial privileges
3571 : : * (pg_init_privs) on databases.
3572 : : */
1421 3573 : 87 : dbdacl.privtype = 0;
3574 : 87 : dbdacl.initprivs = NULL;
3575 : :
1934 3576 : 87 : dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
3577 : : qdatname, NULL, NULL,
3578 : : NULL, dba, &dbdacl);
3579 : :
3580 : : /*
3581 : : * Now construct a DATABASE PROPERTIES archive entry to restore any
3582 : : * non-default database-level properties. (The reason this must be
3583 : : * separate is that we cannot put any additional commands into the TOC
3584 : : * entry that has CREATE DATABASE. pg_restore would execute such a group
3585 : : * in an implicit transaction block, and the backend won't allow CREATE
3586 : : * DATABASE in that context.)
3587 : : */
2835 3588 : 87 : resetPQExpBuffer(creaQry);
3589 : 87 : resetPQExpBuffer(delQry);
3590 : :
3591 [ + - - + ]: 87 : if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2835 tgl@sss.pgh.pa.us 3592 :UBC 0 : appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
3593 : : qdatname, datconnlimit);
3594 : :
2835 tgl@sss.pgh.pa.us 3595 [ + + ]:CBC 87 : if (strcmp(datistemplate, "t") == 0)
3596 : : {
3597 : 10 : appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
3598 : : qdatname);
3599 : :
3600 : : /*
3601 : : * The backend won't accept DROP DATABASE on a template database. We
3602 : : * can deal with that by removing the template marking before the DROP
3603 : : * gets issued. We'd prefer to use ALTER DATABASE IF EXISTS here, but
3604 : : * since no such command is currently supported, fake it with a direct
3605 : : * UPDATE on pg_database.
3606 : : */
3607 : 10 : appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
3608 : : "SET datistemplate = false WHERE datname = ");
3609 : 10 : appendStringLiteralAH(delQry, datname, fout);
3610 : 10 : appendPQExpBufferStr(delQry, ";\n");
3611 : : }
3612 : :
3613 : : /*
3614 : : * We do not restore pg_database.dathasloginevt because it is set
3615 : : * automatically on login event trigger creation.
3616 : : */
3617 : :
3618 : : /* Add database-specific SET options */
3619 : 87 : dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
3620 : :
3621 : : /*
3622 : : * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
3623 : : * entry, too, for lack of a better place.
3624 : : */
3625 [ + + ]: 87 : if (dopt->binary_upgrade)
3626 : : {
3627 : 35 : appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
3628 : 35 : appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
3629 : : "SET datfrozenxid = '%u', datminmxid = '%u'\n"
3630 : : "WHERE datname = ",
3631 : : frozenxid, minmxid);
3632 : 35 : appendStringLiteralAH(creaQry, datname, fout);
3633 : 35 : appendPQExpBufferStr(creaQry, ";\n");
3634 : : }
3635 : :
3636 [ + + ]: 87 : if (creaQry->len > 0)
3637 : 39 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 3638 : 39 : ARCHIVE_OPTS(.tag = datname,
3639 : : .owner = dba,
3640 : : .description = "DATABASE PROPERTIES",
3641 : : .section = SECTION_PRE_DATA,
3642 : : .createStmt = creaQry->data,
3643 : : .dropStmt = delQry->data,
3644 : : .deps = &dbDumpId));
3645 : :
3646 : : /*
3647 : : * pg_largeobject comes from the old system intact, so set its
3648 : : * relfrozenxids, relminmxids and relfilenode.
3649 : : *
3650 : : * pg_largeobject_metadata also comes from the old system intact for
3651 : : * upgrades from v16 and newer, so set its relfrozenxids, relminmxids, and
3652 : : * relfilenode, too. pg_upgrade can't copy/link the files from older
3653 : : * versions because aclitem (needed by pg_largeobject_metadata.lomacl)
3654 : : * changed its storage format in v16.
3655 : : */
4031 3656 [ + + ]: 87 : if (dopt->binary_upgrade)
3657 : : {
3658 : : PGresult *lo_res;
5943 bruce@momjian.us 3659 : 35 : PQExpBuffer loFrozenQry = createPQExpBuffer();
3660 : 35 : PQExpBuffer loOutQry = createPQExpBuffer();
49 nathan@postgresql.or 3661 :GNC 35 : PQExpBuffer lomOutQry = createPQExpBuffer();
1186 rhaas@postgresql.org 3662 :CBC 35 : PQExpBuffer loHorizonQry = createPQExpBuffer();
49 nathan@postgresql.or 3663 :GNC 35 : PQExpBuffer lomHorizonQry = createPQExpBuffer();
3664 : : int ii_relfrozenxid,
3665 : : ii_relfilenode,
3666 : : ii_oid,
3667 : : ii_relminmxid;
3668 : :
4135 bruce@momjian.us 3669 [ + - ]:CBC 35 : if (fout->remoteVersion >= 90300)
1207 rhaas@postgresql.org 3670 : 35 : appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
3671 : : "FROM pg_catalog.pg_class\n"
3672 : : "WHERE oid IN (%u, %u, %u, %u);\n",
3673 : : LargeObjectRelationId, LargeObjectLOidPNIndexId,
3674 : : LargeObjectMetadataRelationId, LargeObjectMetadataOidIndexId);
3675 : : else
1207 rhaas@postgresql.org 3676 :UBC 0 : appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
3677 : : "FROM pg_catalog.pg_class\n"
3678 : : "WHERE oid IN (%u, %u);\n",
3679 : : LargeObjectRelationId, LargeObjectLOidPNIndexId);
3680 : :
1207 rhaas@postgresql.org 3681 :CBC 35 : lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
3682 : :
1164 drowley@postgresql.o 3683 : 35 : ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
3684 : 35 : ii_relminmxid = PQfnumber(lo_res, "relminmxid");
3685 : 35 : ii_relfilenode = PQfnumber(lo_res, "relfilenode");
3686 : 35 : ii_oid = PQfnumber(lo_res, "oid");
3687 : :
1186 rhaas@postgresql.org 3688 : 35 : appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
49 nathan@postgresql.or 3689 :GNC 35 : appendPQExpBufferStr(lomHorizonQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
1186 rhaas@postgresql.org 3690 :CBC 35 : appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
49 nathan@postgresql.or 3691 :GNC 35 : appendPQExpBufferStr(lomOutQry, "\n-- For binary upgrade, preserve pg_largeobject_metadata and index relfilenodes\n");
1207 rhaas@postgresql.org 3692 [ + + ]:CBC 175 : for (int i = 0; i < PQntuples(lo_res); ++i)
3693 : : {
3694 : : Oid oid;
3695 : : RelFileNumber relfilenumber;
3696 : : PQExpBuffer horizonQry;
3697 : : PQExpBuffer outQry;
3698 : :
49 nathan@postgresql.or 3699 :GNC 140 : oid = atooid(PQgetvalue(lo_res, i, ii_oid));
3700 : 140 : relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
3701 : :
3702 [ + + + + ]: 140 : if (oid == LargeObjectRelationId ||
3703 : : oid == LargeObjectLOidPNIndexId)
3704 : : {
3705 : 70 : horizonQry = loHorizonQry;
3706 : 70 : outQry = loOutQry;
3707 : : }
3708 : : else
3709 : : {
3710 : 70 : horizonQry = lomHorizonQry;
3711 : 70 : outQry = lomOutQry;
3712 : : }
3713 : :
3714 : 140 : appendPQExpBuffer(horizonQry, "UPDATE pg_catalog.pg_class\n"
3715 : : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3716 : : "WHERE oid = %u;\n",
1164 drowley@postgresql.o 3717 :CBC 140 : atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
3718 : 140 : atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
3719 : 140 : atooid(PQgetvalue(lo_res, i, ii_oid)));
3720 : :
49 nathan@postgresql.or 3721 [ + + + + ]:GNC 140 : if (oid == LargeObjectRelationId ||
3722 : : oid == LargeObjectMetadataRelationId)
3723 : 70 : appendPQExpBuffer(outQry,
3724 : : "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
3725 : : relfilenumber);
3726 [ + + + - ]: 70 : else if (oid == LargeObjectLOidPNIndexId ||
3727 : : oid == LargeObjectMetadataOidIndexId)
3728 : 70 : appendPQExpBuffer(outQry,
3729 : : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
3730 : : relfilenumber);
3731 : : }
3732 : :
1186 rhaas@postgresql.org 3733 :CBC 35 : appendPQExpBufferStr(loOutQry,
3734 : : "TRUNCATE pg_catalog.pg_largeobject;\n");
49 nathan@postgresql.or 3735 :GNC 35 : appendPQExpBufferStr(lomOutQry,
3736 : : "TRUNCATE pg_catalog.pg_largeobject_metadata;\n");
3737 : :
1186 rhaas@postgresql.org 3738 :CBC 35 : appendPQExpBufferStr(loOutQry, loHorizonQry->data);
49 nathan@postgresql.or 3739 :GNC 35 : appendPQExpBufferStr(lomOutQry, lomHorizonQry->data);
3740 : :
5012 rhaas@postgresql.org 3741 :CBC 35 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 3742 : 35 : ARCHIVE_OPTS(.tag = "pg_largeobject",
3743 : : .description = "pg_largeobject",
3744 : : .section = SECTION_PRE_DATA,
3745 : : .createStmt = loOutQry->data));
3746 : :
49 nathan@postgresql.or 3747 [ + - ]:GNC 35 : if (fout->remoteVersion >= 160000)
3748 : 35 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
3749 : 35 : ARCHIVE_OPTS(.tag = "pg_largeobject_metadata",
3750 : : .description = "pg_largeobject_metadata",
3751 : : .section = SECTION_PRE_DATA,
3752 : : .createStmt = lomOutQry->data));
3753 : :
5943 bruce@momjian.us 3754 :CBC 35 : PQclear(lo_res);
3755 : :
3756 : 35 : destroyPQExpBuffer(loFrozenQry);
1186 rhaas@postgresql.org 3757 : 35 : destroyPQExpBuffer(loHorizonQry);
49 nathan@postgresql.or 3758 :GNC 35 : destroyPQExpBuffer(lomHorizonQry);
5943 bruce@momjian.us 3759 :CBC 35 : destroyPQExpBuffer(loOutQry);
49 nathan@postgresql.or 3760 :GNC 35 : destroyPQExpBuffer(lomOutQry);
3761 : : }
3762 : :
3935 andres@anarazel.de 3763 :CBC 87 : PQclear(res);
3764 : :
2835 tgl@sss.pgh.pa.us 3765 : 87 : free(qdatname);
8851 3766 : 87 : destroyPQExpBuffer(dbQry);
3767 : 87 : destroyPQExpBuffer(delQry);
3768 : 87 : destroyPQExpBuffer(creaQry);
2835 3769 : 87 : destroyPQExpBuffer(labelq);
9218 pjw@rhyme.com.au 3770 : 87 : }
3771 : :
3772 : : /*
3773 : : * Collect any database-specific or role-and-database-specific SET options
3774 : : * for this database, and append them to outbuf.
3775 : : */
3776 : : static void
2835 tgl@sss.pgh.pa.us 3777 : 87 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
3778 : : const char *dbname, Oid dboid)
3779 : : {
3780 : 87 : PGconn *conn = GetConnection(AH);
3781 : 87 : PQExpBuffer buf = createPQExpBuffer();
3782 : : PGresult *res;
3783 : :
3784 : : /* First collect database-specific options */
894 akorotkov@postgresql 3785 : 87 : printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
3786 : : "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3787 : : dboid);
3788 : :
1413 tgl@sss.pgh.pa.us 3789 : 87 : res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3790 : :
3791 [ + + ]: 117 : for (int i = 0; i < PQntuples(res); i++)
894 akorotkov@postgresql 3792 : 30 : makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
3793 : : "DATABASE", dbname, NULL, NULL,
3794 : : outbuf);
3795 : :
1413 tgl@sss.pgh.pa.us 3796 : 87 : PQclear(res);
3797 : :
3798 : : /* Now look for role-and-database-specific options */
894 akorotkov@postgresql 3799 : 87 : printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3800 : : "FROM pg_db_role_setting s, pg_roles r "
3801 : : "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3802 : : dboid);
3803 : :
1413 tgl@sss.pgh.pa.us 3804 : 87 : res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3805 : :
3806 [ - + ]: 87 : for (int i = 0; i < PQntuples(res); i++)
894 akorotkov@postgresql 3807 :UBC 0 : makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
1413 tgl@sss.pgh.pa.us 3808 : 0 : "ROLE", PQgetvalue(res, i, 0),
3809 : : "DATABASE", dbname,
3810 : : outbuf);
3811 : :
1413 tgl@sss.pgh.pa.us 3812 :CBC 87 : PQclear(res);
3813 : :
2835 3814 : 87 : destroyPQExpBuffer(buf);
3815 : 87 : }
3816 : :
3817 : : /*
3818 : : * dumpEncoding: put the correct encoding into the archive
3819 : : */
3820 : : static void
7916 3821 : 189 : dumpEncoding(Archive *AH)
3822 : : {
7092 3823 : 189 : const char *encname = pg_encoding_to_char(AH->encoding);
3824 : 189 : PQExpBuffer qry = createPQExpBuffer();
3825 : :
2401 peter@eisentraut.org 3826 : 189 : pg_log_info("saving encoding = %s", encname);
3827 : :
4361 heikki.linnakangas@i 3828 : 189 : appendPQExpBufferStr(qry, "SET client_encoding = ");
7092 tgl@sss.pgh.pa.us 3829 : 189 : appendStringLiteralAH(qry, encname, AH);
4361 heikki.linnakangas@i 3830 : 189 : appendPQExpBufferStr(qry, ";\n");
3831 : :
7916 tgl@sss.pgh.pa.us 3832 : 189 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 3833 : 189 : ARCHIVE_OPTS(.tag = "ENCODING",
3834 : : .description = "ENCODING",
3835 : : .section = SECTION_PRE_DATA,
3836 : : .createStmt = qry->data));
3837 : :
7916 tgl@sss.pgh.pa.us 3838 : 189 : destroyPQExpBuffer(qry);
3839 : 189 : }
3840 : :
3841 : :
3842 : : /*
3843 : : * dumpStdStrings: put the correct escape string behavior into the archive
3844 : : */
3845 : : static void
7094 bruce@momjian.us 3846 : 189 : dumpStdStrings(Archive *AH)
3847 : : {
7092 tgl@sss.pgh.pa.us 3848 [ + - ]: 189 : const char *stdstrings = AH->std_strings ? "on" : "off";
3849 : 189 : PQExpBuffer qry = createPQExpBuffer();
3850 : :
528 peter@eisentraut.org 3851 : 189 : pg_log_info("saving \"standard_conforming_strings = %s\"",
3852 : : stdstrings);
3853 : :
7092 tgl@sss.pgh.pa.us 3854 : 189 : appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3855 : : stdstrings);
3856 : :
7094 bruce@momjian.us 3857 : 189 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 3858 : 189 : ARCHIVE_OPTS(.tag = "STDSTRINGS",
3859 : : .description = "STDSTRINGS",
3860 : : .section = SECTION_PRE_DATA,
3861 : : .createStmt = qry->data));
3862 : :
7094 bruce@momjian.us 3863 : 189 : destroyPQExpBuffer(qry);
3864 : 189 : }
3865 : :
3866 : : /*
3867 : : * dumpSearchPath: record the active search_path in the archive
3868 : : */
3869 : : static void
2800 tgl@sss.pgh.pa.us 3870 : 189 : dumpSearchPath(Archive *AH)
3871 : : {
3872 : 189 : PQExpBuffer qry = createPQExpBuffer();
3873 : 189 : PQExpBuffer path = createPQExpBuffer();
3874 : : PGresult *res;
3875 : 189 : char **schemanames = NULL;
3876 : 189 : int nschemanames = 0;
3877 : : int i;
3878 : :
3879 : : /*
3880 : : * We use the result of current_schemas(), not the search_path GUC,
3881 : : * because that might contain wildcards such as "$user", which won't
3882 : : * necessarily have the same value during restore. Also, this way avoids
3883 : : * listing schemas that may appear in search_path but not actually exist,
3884 : : * which seems like a prudent exclusion.
3885 : : */
3886 : 189 : res = ExecuteSqlQueryForSingleRow(AH,
3887 : : "SELECT pg_catalog.current_schemas(false)");
3888 : :
3889 [ - + ]: 189 : if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
1298 tgl@sss.pgh.pa.us 3890 :UBC 0 : pg_fatal("could not parse result of current_schemas()");
3891 : :
3892 : : /*
3893 : : * We use set_config(), not a simple "SET search_path" command, because
3894 : : * the latter has less-clean behavior if the search path is empty. While
3895 : : * that's likely to get fixed at some point, it seems like a good idea to
3896 : : * be as backwards-compatible as possible in what we put into archives.
3897 : : */
2800 tgl@sss.pgh.pa.us 3898 [ - + ]:CBC 189 : for (i = 0; i < nschemanames; i++)
3899 : : {
2800 tgl@sss.pgh.pa.us 3900 [ # # ]:UBC 0 : if (i > 0)
3901 : 0 : appendPQExpBufferStr(path, ", ");
3902 : 0 : appendPQExpBufferStr(path, fmtId(schemanames[i]));
3903 : : }
3904 : :
2800 tgl@sss.pgh.pa.us 3905 :CBC 189 : appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3906 : 189 : appendStringLiteralAH(qry, path->data, AH);
3907 : 189 : appendPQExpBufferStr(qry, ", false);\n");
3908 : :
528 peter@eisentraut.org 3909 : 189 : pg_log_info("saving \"search_path = %s\"", path->data);
3910 : :
2800 tgl@sss.pgh.pa.us 3911 : 189 : ArchiveEntry(AH, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 3912 : 189 : ARCHIVE_OPTS(.tag = "SEARCHPATH",
3913 : : .description = "SEARCHPATH",
3914 : : .section = SECTION_PRE_DATA,
3915 : : .createStmt = qry->data));
3916 : :
3917 : : /* Also save it in AH->searchpath, in case we're doing plain text dump */
2800 tgl@sss.pgh.pa.us 3918 : 189 : AH->searchpath = pg_strdup(qry->data);
3919 : :
1229 peter@eisentraut.org 3920 : 189 : free(schemanames);
2800 tgl@sss.pgh.pa.us 3921 : 189 : PQclear(res);
3922 : 189 : destroyPQExpBuffer(qry);
3923 : 189 : destroyPQExpBuffer(path);
3924 : 189 : }
3925 : :
3926 : :
3927 : : /*
3928 : : * getLOs:
3929 : : * Collect schema-level data about large objects
3930 : : */
3931 : : static void
1057 peter@eisentraut.org 3932 : 161 : getLOs(Archive *fout)
3933 : : {
3491 sfrost@snowman.net 3934 : 161 : DumpOptions *dopt = fout->dopt;
1057 peter@eisentraut.org 3935 : 161 : PQExpBuffer loQry = createPQExpBuffer();
3936 : : PGresult *res;
3937 : : int ntups;
3938 : : int i;
3939 : : int n;
3940 : : int i_oid;
3941 : : int i_lomowner;
3942 : : int i_lomacl;
3943 : : int i_acldefault;
3944 : :
2401 3945 : 161 : pg_log_info("reading large objects");
3946 : :
3947 : : /*
3948 : : * Fetch LO OIDs and owner/ACL data. Order the data so that all the blobs
3949 : : * with the same owner/ACL appear together.
3950 : : */
1057 3951 : 161 : appendPQExpBufferStr(loQry,
3952 : : "SELECT oid, lomowner, lomacl, "
3953 : : "acldefault('L', lomowner) AS acldefault "
3954 : : "FROM pg_largeobject_metadata "
3955 : : "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
3956 : :
3957 : 161 : res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
3958 : :
3491 sfrost@snowman.net 3959 : 161 : i_oid = PQfnumber(res, "oid");
1396 tgl@sss.pgh.pa.us 3960 : 161 : i_lomowner = PQfnumber(res, "lomowner");
3491 sfrost@snowman.net 3961 : 161 : i_lomacl = PQfnumber(res, "lomacl");
1421 tgl@sss.pgh.pa.us 3962 : 161 : i_acldefault = PQfnumber(res, "acldefault");
3963 : :
5730 3964 : 161 : ntups = PQntuples(res);
3965 : :
3966 : : /*
3967 : : * Group the blobs into suitably-sized groups that have the same owner and
3968 : : * ACL setting, and build a metadata and a data DumpableObject for each
3969 : : * group. (If we supported initprivs for blobs, we'd have to insist that
3970 : : * groups also share initprivs settings, since the DumpableObject only has
3971 : : * room for one.) i is the index of the first tuple in the current group,
3972 : : * and n is the number of tuples we include in the group.
3973 : : */
574 3974 [ + + ]: 254 : for (i = 0; i < ntups; i += n)
3975 : : {
3976 : 93 : Oid thisoid = atooid(PQgetvalue(res, i, i_oid));
3977 : 93 : char *thisowner = PQgetvalue(res, i, i_lomowner);
3978 : 93 : char *thisacl = PQgetvalue(res, i, i_lomacl);
3979 : : LoInfo *loinfo;
3980 : : DumpableObject *lodata;
3981 : : char namebuf[64];
3982 : :
3983 : : /* Scan to find first tuple not to be included in group */
3984 : 93 : n = 1;
3985 [ + - + + ]: 108 : while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
3986 : : {
3987 [ + + ]: 54 : if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
3988 [ + + ]: 49 : strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
3989 : : break;
3990 : 15 : n++;
3991 : : }
3992 : :
3993 : : /* Build the metadata DumpableObject */
3994 : 93 : loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
3995 : :
3996 : 93 : loinfo->dobj.objType = DO_LARGE_OBJECT;
3997 : 93 : loinfo->dobj.catId.tableoid = LargeObjectRelationId;
3998 : 93 : loinfo->dobj.catId.oid = thisoid;
3999 : 93 : AssignDumpId(&loinfo->dobj);
4000 : :
4001 [ + + ]: 93 : if (n > 1)
4002 : 10 : snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
4003 : 10 : atooid(PQgetvalue(res, i + n - 1, i_oid)));
4004 : : else
4005 : 83 : snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
4006 : 93 : loinfo->dobj.name = pg_strdup(namebuf);
4007 : 93 : loinfo->dacl.acl = pg_strdup(thisacl);
4008 : 93 : loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
4009 : 93 : loinfo->dacl.privtype = 0;
4010 : 93 : loinfo->dacl.initprivs = NULL;
4011 : 93 : loinfo->rolname = getRoleName(thisowner);
4012 : 93 : loinfo->numlos = n;
4013 : 93 : loinfo->looids[0] = thisoid;
4014 : : /* Collect OIDs of the remaining blobs in this group */
4015 [ + + ]: 108 : for (int k = 1; k < n; k++)
4016 : : {
4017 : : CatalogId extraID;
4018 : :
4019 : 15 : loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
4020 : :
4021 : : /* Make sure we can look up loinfo by any of the blobs' OIDs */
4022 : 15 : extraID.tableoid = LargeObjectRelationId;
4023 : 15 : extraID.oid = loinfo->looids[k];
4024 : 15 : recordAdditionalCatalogID(extraID, &loinfo->dobj);
4025 : : }
4026 : :
4027 : : /* LOs have data */
4028 : 93 : loinfo->dobj.components |= DUMP_COMPONENT_DATA;
4029 : :
4030 : : /* Mark whether LO group has a non-empty ACL */
1421 4031 [ + + ]: 93 : if (!PQgetisnull(res, i, i_lomacl))
574 4032 : 39 : loinfo->dobj.components |= DUMP_COMPONENT_ACL;
4033 : :
4034 : : /*
4035 : : * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
4036 : : * as it will be copied by pg_upgrade, which simply copies the
4037 : : * pg_largeobject table. We *do* however dump out anything but the
4038 : : * data, as pg_upgrade copies just pg_largeobject, but not
4039 : : * pg_largeobject_metadata, after the dump is restored. In versions
4040 : : * before v12, this is done via proper large object commands. In
4041 : : * newer versions, we dump the content of pg_largeobject_metadata and
4042 : : * any associated pg_shdepend rows, which is faster to restore. (On
4043 : : * <v12, pg_largeobject_metadata was created WITH OIDS, so the OID
4044 : : * column is hidden and won't be dumped.)
4045 : : */
3157 sfrost@snowman.net 4046 [ + + ]: 93 : if (dopt->binary_upgrade)
4047 : : {
101 nathan@postgresql.or 4048 [ + - ]:GNC 13 : if (fout->remoteVersion >= 120000)
4049 : : {
4050 : : /*
4051 : : * We should've saved pg_largeobject_metadata's dump ID before
4052 : : * this point.
4053 : : */
4054 [ - + ]: 13 : Assert(lo_metadata_dumpId);
4055 : :
4056 : 13 : loinfo->dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL | DUMP_COMPONENT_DEFINITION);
4057 : :
4058 : : /*
4059 : : * Mark the large object as dependent on
4060 : : * pg_largeobject_metadata so that any large object
4061 : : * comments/seclables are dumped after it.
4062 : : */
4063 : 13 : loinfo->dobj.dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
4064 : 13 : loinfo->dobj.dependencies[0] = lo_metadata_dumpId;
4065 : 13 : loinfo->dobj.nDeps = loinfo->dobj.allocDeps = 1;
4066 : : }
4067 : : else
101 nathan@postgresql.or 4068 :UNC 0 : loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
4069 : : }
4070 : :
4071 : : /*
4072 : : * Create a "BLOBS" data item for the group, too. This is just a
4073 : : * placeholder for sorting; it carries no data now.
4074 : : */
1057 peter@eisentraut.org 4075 :CBC 93 : lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
4076 : 93 : lodata->objType = DO_LARGE_OBJECT_DATA;
4077 : 93 : lodata->catId = nilCatalogId;
4078 : 93 : AssignDumpId(lodata);
574 tgl@sss.pgh.pa.us 4079 : 93 : lodata->name = pg_strdup(namebuf);
1057 peter@eisentraut.org 4080 : 93 : lodata->components |= DUMP_COMPONENT_DATA;
4081 : : /* Set up explicit dependency from data to metadata */
574 tgl@sss.pgh.pa.us 4082 : 93 : lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
4083 : 93 : lodata->dependencies[0] = loinfo->dobj.dumpId;
4084 : 93 : lodata->nDeps = lodata->allocDeps = 1;
4085 : : }
4086 : :
7424 4087 : 161 : PQclear(res);
1057 peter@eisentraut.org 4088 : 161 : destroyPQExpBuffer(loQry);
5730 tgl@sss.pgh.pa.us 4089 : 161 : }
4090 : :
4091 : : /*
4092 : : * dumpLO
4093 : : *
4094 : : * dump the definition (metadata) of the given large object group
4095 : : */
4096 : : static void
1057 peter@eisentraut.org 4097 : 87 : dumpLO(Archive *fout, const LoInfo *loinfo)
4098 : : {
5722 bruce@momjian.us 4099 : 87 : PQExpBuffer cquery = createPQExpBuffer();
4100 : :
4101 : : /*
4102 : : * The "definition" is just a newline-separated list of OIDs. We need to
4103 : : * put something into the dropStmt too, but it can just be a comment.
4104 : : */
574 tgl@sss.pgh.pa.us 4105 [ + + ]: 189 : for (int i = 0; i < loinfo->numlos; i++)
4106 : 102 : appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
4107 : :
1057 peter@eisentraut.org 4108 [ + + ]: 87 : if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4109 : 80 : ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
4110 : 80 : ARCHIVE_OPTS(.tag = loinfo->dobj.name,
4111 : : .owner = loinfo->rolname,
4112 : : .description = "BLOB METADATA",
4113 : : .section = SECTION_DATA,
4114 : : .createStmt = cquery->data,
4115 : : .dropStmt = "-- dummy"));
4116 : :
4117 : : /*
4118 : : * Dump per-blob comments and seclabels if any. We assume these are rare
4119 : : * enough that it's okay to generate retail TOC entries for them.
4120 : : */
574 tgl@sss.pgh.pa.us 4121 [ + + ]: 87 : if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
4122 : : DUMP_COMPONENT_SECLABEL))
4123 : : {
4124 [ + + ]: 103 : for (int i = 0; i < loinfo->numlos; i++)
4125 : : {
4126 : : CatalogId catId;
4127 : : char namebuf[32];
4128 : :
4129 : : /* Build identifying info for this blob */
4130 : 59 : catId.tableoid = loinfo->dobj.catId.tableoid;
4131 : 59 : catId.oid = loinfo->looids[i];
4132 : 59 : snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
4133 : :
4134 [ + - ]: 59 : if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4135 : 59 : dumpComment(fout, "LARGE OBJECT", namebuf,
4136 : 59 : NULL, loinfo->rolname,
4137 : 59 : catId, 0, loinfo->dobj.dumpId);
4138 : :
4139 [ + + ]: 59 : if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
574 tgl@sss.pgh.pa.us 4140 :GBC 10 : dumpSecLabel(fout, "LARGE OBJECT", namebuf,
4141 : 10 : NULL, loinfo->rolname,
4142 : 10 : catId, 0, loinfo->dobj.dumpId);
4143 : : }
4144 : : }
4145 : :
4146 : : /*
4147 : : * Dump the ACLs if any (remember that all blobs in the group will have
4148 : : * the same ACL). If there's just one blob, dump a simple ACL entry; if
4149 : : * there's more, make a "LARGE OBJECTS" entry that really contains only
4150 : : * the ACL for the first blob. _printTocEntry() will be cued by the tag
4151 : : * string to emit a mutated version for each blob.
4152 : : */
1057 peter@eisentraut.org 4153 [ + + ]:CBC 87 : if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
4154 : : {
4155 : : char namebuf[32];
4156 : :
4157 : : /* Build identifying info for the first blob */
574 tgl@sss.pgh.pa.us 4158 : 33 : snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
4159 : :
4160 [ - + ]: 33 : if (loinfo->numlos > 1)
4161 : : {
4162 : : char tagbuf[64];
4163 : :
574 tgl@sss.pgh.pa.us 4164 :UBC 0 : snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
4165 : 0 : loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
4166 : :
4167 : 0 : dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
4168 : : "LARGE OBJECT", namebuf, NULL, NULL,
4169 : 0 : tagbuf, loinfo->rolname, &loinfo->dacl);
4170 : : }
4171 : : else
4172 : : {
574 tgl@sss.pgh.pa.us 4173 :CBC 33 : dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
4174 : : "LARGE OBJECT", namebuf, NULL, NULL,
4175 : 33 : NULL, loinfo->rolname, &loinfo->dacl);
4176 : : }
4177 : : }
4178 : :
5730 4179 : 87 : destroyPQExpBuffer(cquery);
7424 4180 : 87 : }
4181 : :
4182 : : /*
4183 : : * dumpLOs:
4184 : : * dump the data contents of the large objects in the given group
4185 : : */
4186 : : static int
1057 peter@eisentraut.org 4187 : 76 : dumpLOs(Archive *fout, const void *arg)
4188 : : {
574 tgl@sss.pgh.pa.us 4189 : 76 : const LoInfo *loinfo = (const LoInfo *) arg;
5002 rhaas@postgresql.org 4190 : 76 : PGconn *conn = GetConnection(fout);
4191 : : char buf[LOBBUFSIZE];
4192 : :
574 tgl@sss.pgh.pa.us 4193 : 76 : pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
4194 : :
4195 [ + + ]: 160 : for (int i = 0; i < loinfo->numlos; i++)
4196 : : {
4197 : 84 : Oid loOid = loinfo->looids[i];
4198 : : int loFd;
4199 : : int cnt;
4200 : :
4201 : : /* Open the LO */
4202 : 84 : loFd = lo_open(conn, loOid, INV_READ);
4203 [ - + ]: 84 : if (loFd == -1)
574 tgl@sss.pgh.pa.us 4204 :UBC 0 : pg_fatal("could not open large object %u: %s",
4205 : : loOid, PQerrorMessage(conn));
4206 : :
574 tgl@sss.pgh.pa.us 4207 :CBC 84 : StartLO(fout, loOid);
4208 : :
4209 : : /* Now read it in chunks, sending data to archive */
4210 : : do
4211 : : {
4212 : 133 : cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
4213 [ - + ]: 133 : if (cnt < 0)
574 tgl@sss.pgh.pa.us 4214 :UBC 0 : pg_fatal("error reading large object %u: %s",
4215 : : loOid, PQerrorMessage(conn));
4216 : :
574 tgl@sss.pgh.pa.us 4217 :CBC 133 : WriteData(fout, buf, cnt);
4218 [ + + ]: 133 : } while (cnt > 0);
4219 : :
4220 : 84 : lo_close(conn, loFd);
4221 : :
4222 : 84 : EndLO(fout, loOid);
4223 : : }
4224 : :
7424 4225 : 76 : return 1;
4226 : : }
4227 : :
4228 : : /*
4229 : : * getPolicies
4230 : : * get information about all RLS policies on dumpable tables.
4231 : : */
4232 : : void
3987 sfrost@snowman.net 4233 : 189 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
4234 : : {
225 tgl@sss.pgh.pa.us 4235 : 189 : DumpOptions *dopt = fout->dopt;
4236 : : PQExpBuffer query;
4237 : : PQExpBuffer tbloids;
4238 : : PGresult *res;
4239 : : PolicyInfo *polinfo;
4240 : : int i_oid;
4241 : : int i_tableoid;
4242 : : int i_polrelid;
4243 : : int i_polname;
4244 : : int i_polcmd;
4245 : : int i_polpermissive;
4246 : : int i_polroles;
4247 : : int i_polqual;
4248 : : int i_polwithcheck;
4249 : : int i,
4250 : : j,
4251 : : ntups;
4252 : :
4253 : : /* No policies before 9.5 */
4056 sfrost@snowman.net 4254 [ - + ]: 189 : if (fout->remoteVersion < 90500)
4056 sfrost@snowman.net 4255 :UBC 0 : return;
4256 : :
4257 : : /* Skip if --no-policies was specified */
225 tgl@sss.pgh.pa.us 4258 [ + + ]:CBC 189 : if (dopt->no_policies)
4259 : 1 : return;
4260 : :
4051 sfrost@snowman.net 4261 : 188 : query = createPQExpBuffer();
1396 tgl@sss.pgh.pa.us 4262 : 188 : tbloids = createPQExpBuffer();
4263 : :
4264 : : /*
4265 : : * Identify tables of interest, and check which ones have RLS enabled.
4266 : : */
4267 : 188 : appendPQExpBufferChar(tbloids, '{');
4056 sfrost@snowman.net 4268 [ + + ]: 49560 : for (i = 0; i < numTables; i++)
4269 : : {
4028 tgl@sss.pgh.pa.us 4270 : 49372 : TableInfo *tbinfo = &tblinfo[i];
4271 : :
4272 : : /* Ignore row security on tables not to be dumped */
3491 sfrost@snowman.net 4273 [ + + ]: 49372 : if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
4056 4274 : 42506 : continue;
4275 : :
4276 : : /* It can't have RLS or policies if it's not a table */
1396 tgl@sss.pgh.pa.us 4277 [ + + ]: 6866 : if (tbinfo->relkind != RELKIND_RELATION &&
4278 [ + + ]: 1939 : tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
4279 : 1353 : continue;
4280 : :
4281 : : /* Add it to the list of table OIDs to be probed below */
4282 [ + + ]: 5513 : if (tbloids->len > 1) /* do we have more than the '{'? */
4283 : 5389 : appendPQExpBufferChar(tbloids, ',');
4284 : 5513 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
4285 : :
4286 : : /* Is RLS enabled? (That's separate from whether it has policies) */
4051 sfrost@snowman.net 4287 [ + + ]: 5513 : if (tbinfo->rowsec)
4288 : : {
1421 tgl@sss.pgh.pa.us 4289 : 53 : tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
4290 : :
4291 : : /*
4292 : : * We represent RLS being enabled on a table by creating a
4293 : : * PolicyInfo object with null polname.
4294 : : *
4295 : : * Note: use tableoid 0 so that this object won't be mistaken for
4296 : : * something that pg_depend entries apply to.
4297 : : */
3987 sfrost@snowman.net 4298 : 53 : polinfo = pg_malloc(sizeof(PolicyInfo));
4299 : 53 : polinfo->dobj.objType = DO_POLICY;
4300 : 53 : polinfo->dobj.catId.tableoid = 0;
4301 : 53 : polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
4302 : 53 : AssignDumpId(&polinfo->dobj);
4303 : 53 : polinfo->dobj.namespace = tbinfo->dobj.namespace;
4304 : 53 : polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
4305 : 53 : polinfo->poltable = tbinfo;
4306 : 53 : polinfo->polname = NULL;
3248 4307 : 53 : polinfo->polcmd = '\0';
4308 : 53 : polinfo->polpermissive = 0;
3987 4309 : 53 : polinfo->polroles = NULL;
4310 : 53 : polinfo->polqual = NULL;
4311 : 53 : polinfo->polwithcheck = NULL;
4312 : : }
4313 : : }
1396 tgl@sss.pgh.pa.us 4314 : 188 : appendPQExpBufferChar(tbloids, '}');
4315 : :
4316 : : /*
4317 : : * Now, read all RLS policies belonging to the tables of interest, and
4318 : : * create PolicyInfo objects for them. (Note that we must filter the
4319 : : * results server-side not locally, because we dare not apply pg_get_expr
4320 : : * to tables we don't have lock on.)
4321 : : */
1518 4322 : 188 : pg_log_info("reading row-level security policies");
4323 : :
4324 : 188 : printfPQExpBuffer(query,
4325 : : "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
4326 [ + - ]: 188 : if (fout->remoteVersion >= 100000)
1147 drowley@postgresql.o 4327 : 188 : appendPQExpBufferStr(query, "pol.polpermissive, ");
4328 : : else
1147 drowley@postgresql.o 4329 :UBC 0 : appendPQExpBufferStr(query, "'t' as polpermissive, ");
1518 tgl@sss.pgh.pa.us 4330 :CBC 188 : appendPQExpBuffer(query,
4331 : : "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
4332 : : " 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, "
4333 : : "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
4334 : : "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
4335 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
4336 : : "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
4337 : : tbloids->data);
4338 : :
4339 : 188 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4340 : :
4341 : 188 : ntups = PQntuples(res);
4342 [ + + ]: 188 : if (ntups > 0)
4343 : : {
4056 sfrost@snowman.net 4344 : 43 : i_oid = PQfnumber(res, "oid");
4345 : 43 : i_tableoid = PQfnumber(res, "tableoid");
1518 tgl@sss.pgh.pa.us 4346 : 43 : i_polrelid = PQfnumber(res, "polrelid");
3987 sfrost@snowman.net 4347 : 43 : i_polname = PQfnumber(res, "polname");
4348 : 43 : i_polcmd = PQfnumber(res, "polcmd");
3248 4349 : 43 : i_polpermissive = PQfnumber(res, "polpermissive");
3987 4350 : 43 : i_polroles = PQfnumber(res, "polroles");
4351 : 43 : i_polqual = PQfnumber(res, "polqual");
4352 : 43 : i_polwithcheck = PQfnumber(res, "polwithcheck");
4353 : :
4354 : 43 : polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
4355 : :
4056 4356 [ + + ]: 316 : for (j = 0; j < ntups; j++)
4357 : : {
1518 tgl@sss.pgh.pa.us 4358 : 273 : Oid polrelid = atooid(PQgetvalue(res, j, i_polrelid));
4359 : 273 : TableInfo *tbinfo = findTableByOid(polrelid);
4360 : :
1421 4361 : 273 : tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
4362 : :
3987 sfrost@snowman.net 4363 : 273 : polinfo[j].dobj.objType = DO_POLICY;
4364 : 273 : polinfo[j].dobj.catId.tableoid =
4056 4365 : 273 : atooid(PQgetvalue(res, j, i_tableoid));
3987 4366 : 273 : polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4367 : 273 : AssignDumpId(&polinfo[j].dobj);
4368 : 273 : polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4369 : 273 : polinfo[j].poltable = tbinfo;
4370 : 273 : polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
4371 : 273 : polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
4372 : :
3248 4373 : 273 : polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
4374 : 273 : polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
4375 : :
4376 [ + + ]: 273 : if (PQgetisnull(res, j, i_polroles))
4377 : 121 : polinfo[j].polroles = NULL;
4378 : : else
4379 : 152 : polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
4380 : :
3987 4381 [ + + ]: 273 : if (PQgetisnull(res, j, i_polqual))
4382 : 38 : polinfo[j].polqual = NULL;
4383 : : else
4384 : 235 : polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
4385 : :
4386 [ + + ]: 273 : if (PQgetisnull(res, j, i_polwithcheck))
4387 : 144 : polinfo[j].polwithcheck = NULL;
4388 : : else
4389 : 129 : polinfo[j].polwithcheck
4390 : 129 : = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
4391 : : }
4392 : : }
4393 : :
1518 tgl@sss.pgh.pa.us 4394 : 188 : PQclear(res);
4395 : :
4056 sfrost@snowman.net 4396 : 188 : destroyPQExpBuffer(query);
1396 tgl@sss.pgh.pa.us 4397 : 188 : destroyPQExpBuffer(tbloids);
4398 : : }
4399 : :
4400 : : /*
4401 : : * dumpPolicy
4402 : : * dump the definition of the given policy
4403 : : */
4404 : : static void
1720 peter@eisentraut.org 4405 : 326 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
4406 : : {
3575 tgl@sss.pgh.pa.us 4407 : 326 : DumpOptions *dopt = fout->dopt;
3987 sfrost@snowman.net 4408 : 326 : TableInfo *tbinfo = polinfo->poltable;
4409 : : PQExpBuffer query;
4410 : : PQExpBuffer delqry;
4411 : : PQExpBuffer polprefix;
4412 : : char *qtabname;
4413 : : const char *cmd;
4414 : : char *tag;
4415 : :
4416 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 4417 [ + + ]: 326 : if (!dopt->dumpSchema)
4056 sfrost@snowman.net 4418 : 49 : return;
4419 : :
4420 : : /*
4421 : : * If polname is NULL, then this record is just indicating that ROW LEVEL
4422 : : * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
4423 : : * ROW LEVEL SECURITY.
4424 : : */
3987 4425 [ + + ]: 277 : if (polinfo->polname == NULL)
4426 : : {
4056 4427 : 46 : query = createPQExpBuffer();
4428 : :
4429 : 46 : appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
2618 tgl@sss.pgh.pa.us 4430 : 46 : fmtQualifiedDumpable(tbinfo));
4431 : :
4432 : : /*
4433 : : * We must emit the ROW SECURITY object's dependency on its table
4434 : : * explicitly, because it will not match anything in pg_depend (unlike
4435 : : * the case for other PolicyInfo objects).
4436 : : */
1421 4437 [ + - ]: 46 : if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3491 sfrost@snowman.net 4438 : 46 : ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 4439 : 46 : ARCHIVE_OPTS(.tag = polinfo->dobj.name,
4440 : : .namespace = polinfo->dobj.namespace->dobj.name,
4441 : : .owner = tbinfo->rolname,
4442 : : .description = "ROW SECURITY",
4443 : : .section = SECTION_POST_DATA,
4444 : : .createStmt = query->data,
4445 : : .deps = &(tbinfo->dobj.dumpId),
4446 : : .nDeps = 1));
4447 : :
4056 sfrost@snowman.net 4448 : 46 : destroyPQExpBuffer(query);
4449 : 46 : return;
4450 : : }
4451 : :
3248 4452 [ + + ]: 231 : if (polinfo->polcmd == '*')
4453 : 77 : cmd = "";
4454 [ + + ]: 154 : else if (polinfo->polcmd == 'r')
4455 : 41 : cmd = " FOR SELECT";
4456 [ + + ]: 113 : else if (polinfo->polcmd == 'a')
4457 : 31 : cmd = " FOR INSERT";
4458 [ + + ]: 82 : else if (polinfo->polcmd == 'w')
4459 : 41 : cmd = " FOR UPDATE";
4460 [ + - ]: 41 : else if (polinfo->polcmd == 'd')
4461 : 41 : cmd = " FOR DELETE";
4462 : : else
1298 tgl@sss.pgh.pa.us 4463 :UBC 0 : pg_fatal("unexpected policy command type: %c",
4464 : : polinfo->polcmd);
4465 : :
4056 sfrost@snowman.net 4466 :CBC 231 : query = createPQExpBuffer();
4467 : 231 : delqry = createPQExpBuffer();
2079 tgl@sss.pgh.pa.us 4468 : 231 : polprefix = createPQExpBuffer();
4469 : :
4470 : 231 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
4471 : :
3929 4472 : 231 : appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
4473 : :
2800 4474 : 231 : appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3248 sfrost@snowman.net 4475 [ + + ]: 231 : !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
4476 : :
3987 4477 [ + + ]: 231 : if (polinfo->polroles != NULL)
4478 : 124 : appendPQExpBuffer(query, " TO %s", polinfo->polroles);
4479 : :
4480 [ + + ]: 231 : if (polinfo->polqual != NULL)
3745 mail@joeconway.com 4481 : 200 : appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
4482 : :
3987 sfrost@snowman.net 4483 [ + + ]: 231 : if (polinfo->polwithcheck != NULL)
3745 mail@joeconway.com 4484 : 108 : appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
4485 : :
2307 drowley@postgresql.o 4486 : 231 : appendPQExpBufferStr(query, ";\n");
4487 : :
3929 tgl@sss.pgh.pa.us 4488 : 231 : appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
2800 4489 : 231 : appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
4490 : :
2079 4491 : 231 : appendPQExpBuffer(polprefix, "POLICY %s ON",
4492 : 231 : fmtId(polinfo->polname));
4493 : :
3532 peter_e@gmx.net 4494 : 231 : tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
4495 : :
1421 tgl@sss.pgh.pa.us 4496 [ + - ]: 231 : if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3491 sfrost@snowman.net 4497 : 231 : ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 4498 : 231 : ARCHIVE_OPTS(.tag = tag,
4499 : : .namespace = polinfo->dobj.namespace->dobj.name,
4500 : : .owner = tbinfo->rolname,
4501 : : .description = "POLICY",
4502 : : .section = SECTION_POST_DATA,
4503 : : .createStmt = query->data,
4504 : : .dropStmt = delqry->data));
4505 : :
2079 tgl@sss.pgh.pa.us 4506 [ + + ]: 231 : if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4507 : 31 : dumpComment(fout, polprefix->data, qtabname,
4508 : 31 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
4509 : 31 : polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
4510 : :
3532 peter_e@gmx.net 4511 : 231 : free(tag);
4056 sfrost@snowman.net 4512 : 231 : destroyPQExpBuffer(query);
4513 : 231 : destroyPQExpBuffer(delqry);
2079 tgl@sss.pgh.pa.us 4514 : 231 : destroyPQExpBuffer(polprefix);
4515 : 231 : free(qtabname);
4516 : : }
4517 : :
4518 : : /*
4519 : : * getPublications
4520 : : * get information about publications
4521 : : */
4522 : : void
482 nathan@postgresql.or 4523 : 189 : getPublications(Archive *fout)
4524 : : {
3090 peter_e@gmx.net 4525 : 189 : DumpOptions *dopt = fout->dopt;
4526 : : PQExpBuffer query;
4527 : : PGresult *res;
4528 : : PublicationInfo *pubinfo;
4529 : : int i_tableoid;
4530 : : int i_oid;
4531 : : int i_pubname;
4532 : : int i_pubowner;
4533 : : int i_puballtables;
4534 : : int i_puballsequences;
4535 : : int i_pubinsert;
4536 : : int i_pubupdate;
4537 : : int i_pubdelete;
4538 : : int i_pubtruncate;
4539 : : int i_pubviaroot;
4540 : : int i_pubgencols;
4541 : : int i,
4542 : : ntups;
4543 : :
4544 [ + - - + ]: 189 : if (dopt->no_publications || fout->remoteVersion < 100000)
482 nathan@postgresql.or 4545 :UBC 0 : return;
4546 : :
3203 peter_e@gmx.net 4547 :CBC 189 : query = createPQExpBuffer();
4548 : :
4549 : : /* Get the publications. */
354 akapila@postgresql.o 4550 : 189 : appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
4551 : : "p.pubowner, p.puballtables, p.pubinsert, "
4552 : : "p.pubupdate, p.pubdelete, ");
4553 : :
4554 [ + - ]: 189 : if (fout->remoteVersion >= 110000)
4555 : 189 : appendPQExpBufferStr(query, "p.pubtruncate, ");
4556 : : else
354 akapila@postgresql.o 4557 :UBC 0 : appendPQExpBufferStr(query, "false AS pubtruncate, ");
4558 : :
1299 tomas.vondra@postgre 4559 [ + - ]:CBC 189 : if (fout->remoteVersion >= 130000)
354 akapila@postgresql.o 4560 : 189 : appendPQExpBufferStr(query, "p.pubviaroot, ");
4561 : : else
354 akapila@postgresql.o 4562 :UBC 0 : appendPQExpBufferStr(query, "false AS pubviaroot, ");
4563 : :
354 akapila@postgresql.o 4564 [ + - ]:CBC 189 : if (fout->remoteVersion >= 180000)
18 akapila@postgresql.o 4565 :GNC 189 : appendPQExpBufferStr(query, "p.pubgencols, ");
4566 : : else
18 akapila@postgresql.o 4567 :UNC 0 : appendPQExpBuffer(query, "'%c' AS pubgencols, ", PUBLISH_GENCOLS_NONE);
4568 : :
18 akapila@postgresql.o 4569 [ + - ]:GNC 189 : if (fout->remoteVersion >= 190000)
4570 : 189 : appendPQExpBufferStr(query, "p.puballsequences ");
4571 : : else
18 akapila@postgresql.o 4572 :UNC 0 : appendPQExpBufferStr(query, "false AS puballsequences ");
4573 : :
354 akapila@postgresql.o 4574 :CBC 189 : appendPQExpBufferStr(query, "FROM pg_publication p");
4575 : :
3203 peter_e@gmx.net 4576 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4577 : :
4578 : 189 : ntups = PQntuples(res);
4579 : :
390 dgustafsson@postgres 4580 [ + + ]: 189 : if (ntups == 0)
4581 : 136 : goto cleanup;
4582 : :
3203 peter_e@gmx.net 4583 : 53 : i_tableoid = PQfnumber(res, "tableoid");
4584 : 53 : i_oid = PQfnumber(res, "oid");
4585 : 53 : i_pubname = PQfnumber(res, "pubname");
1396 tgl@sss.pgh.pa.us 4586 : 53 : i_pubowner = PQfnumber(res, "pubowner");
3203 peter_e@gmx.net 4587 : 53 : i_puballtables = PQfnumber(res, "puballtables");
18 akapila@postgresql.o 4588 :GNC 53 : i_puballsequences = PQfnumber(res, "puballsequences");
3203 peter_e@gmx.net 4589 :CBC 53 : i_pubinsert = PQfnumber(res, "pubinsert");
4590 : 53 : i_pubupdate = PQfnumber(res, "pubupdate");
4591 : 53 : i_pubdelete = PQfnumber(res, "pubdelete");
2760 4592 : 53 : i_pubtruncate = PQfnumber(res, "pubtruncate");
2028 peter@eisentraut.org 4593 : 53 : i_pubviaroot = PQfnumber(res, "pubviaroot");
272 akapila@postgresql.o 4594 : 53 : i_pubgencols = PQfnumber(res, "pubgencols");
4595 : :
3203 peter_e@gmx.net 4596 : 53 : pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
4597 : :
4598 [ + + ]: 404 : for (i = 0; i < ntups; i++)
4599 : : {
4600 : 351 : pubinfo[i].dobj.objType = DO_PUBLICATION;
4601 : 351 : pubinfo[i].dobj.catId.tableoid =
4602 : 351 : atooid(PQgetvalue(res, i, i_tableoid));
4603 : 351 : pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4604 : 351 : AssignDumpId(&pubinfo[i].dobj);
4605 : 351 : pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
1396 tgl@sss.pgh.pa.us 4606 : 351 : pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
3203 peter_e@gmx.net 4607 : 351 : pubinfo[i].puballtables =
4608 : 351 : (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
18 akapila@postgresql.o 4609 :GNC 351 : pubinfo[i].puballsequences =
4610 : 351 : (strcmp(PQgetvalue(res, i, i_puballsequences), "t") == 0);
3203 peter_e@gmx.net 4611 :CBC 351 : pubinfo[i].pubinsert =
4612 : 351 : (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
4613 : 351 : pubinfo[i].pubupdate =
4614 : 351 : (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
4615 : 351 : pubinfo[i].pubdelete =
4616 : 351 : (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
2760 4617 : 351 : pubinfo[i].pubtruncate =
4618 : 351 : (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
2028 peter@eisentraut.org 4619 : 351 : pubinfo[i].pubviaroot =
4620 : 351 : (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
277 akapila@postgresql.o 4621 : 351 : pubinfo[i].pubgencols_type =
272 4622 : 351 : *(PQgetvalue(res, i, i_pubgencols));
4623 : :
4624 : : /* Decide whether we want to dump it */
3142 peter_e@gmx.net 4625 : 351 : selectDumpableObject(&(pubinfo[i].dobj), fout);
4626 : : }
4627 : :
390 dgustafsson@postgres 4628 : 53 : cleanup:
3203 peter_e@gmx.net 4629 : 189 : PQclear(res);
4630 : :
4631 : 189 : destroyPQExpBuffer(query);
4632 : : }
4633 : :
4634 : : /*
4635 : : * dumpPublication
4636 : : * dump the definition of the given publication
4637 : : */
4638 : : static void
1720 peter@eisentraut.org 4639 : 285 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
4640 : : {
1397 tgl@sss.pgh.pa.us 4641 : 285 : DumpOptions *dopt = fout->dopt;
4642 : : PQExpBuffer delq;
4643 : : PQExpBuffer query;
4644 : : char *qpubname;
3090 peter_e@gmx.net 4645 : 285 : bool first = true;
4646 : :
4647 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 4648 [ + + ]: 285 : if (!dopt->dumpSchema)
1397 tgl@sss.pgh.pa.us 4649 : 42 : return;
4650 : :
3203 peter_e@gmx.net 4651 : 243 : delq = createPQExpBuffer();
4652 : 243 : query = createPQExpBuffer();
4653 : :
2800 tgl@sss.pgh.pa.us 4654 : 243 : qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
4655 : :
3203 peter_e@gmx.net 4656 : 243 : appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
4657 : : qpubname);
4658 : :
4659 : 243 : appendPQExpBuffer(query, "CREATE PUBLICATION %s",
4660 : : qpubname);
4661 : :
18 akapila@postgresql.o 4662 [ + + + + ]:GNC 243 : if (pubinfo->puballtables && pubinfo->puballsequences)
4663 : 31 : appendPQExpBufferStr(query, " FOR ALL TABLES, ALL SEQUENCES");
4664 [ + + ]: 212 : else if (pubinfo->puballtables)
3203 peter_e@gmx.net 4665 :CBC 32 : appendPQExpBufferStr(query, " FOR ALL TABLES");
18 akapila@postgresql.o 4666 [ + + ]:GNC 180 : else if (pubinfo->puballsequences)
4667 : 31 : appendPQExpBufferStr(query, " FOR ALL SEQUENCES");
4668 : :
3090 peter_e@gmx.net 4669 :CBC 243 : appendPQExpBufferStr(query, " WITH (publish = '");
3203 4670 [ + + ]: 243 : if (pubinfo->pubinsert)
4671 : : {
3090 4672 : 181 : appendPQExpBufferStr(query, "insert");
4673 : 181 : first = false;
4674 : : }
4675 : :
3203 4676 [ + + ]: 243 : if (pubinfo->pubupdate)
4677 : : {
3087 tgl@sss.pgh.pa.us 4678 [ + - ]: 181 : if (!first)
4679 : 181 : appendPQExpBufferStr(query, ", ");
4680 : :
3090 peter_e@gmx.net 4681 : 181 : appendPQExpBufferStr(query, "update");
4682 : 181 : first = false;
4683 : : }
4684 : :
3203 4685 [ + + ]: 243 : if (pubinfo->pubdelete)
4686 : : {
3087 tgl@sss.pgh.pa.us 4687 [ + - ]: 181 : if (!first)
4688 : 181 : appendPQExpBufferStr(query, ", ");
4689 : :
3090 peter_e@gmx.net 4690 : 181 : appendPQExpBufferStr(query, "delete");
4691 : 181 : first = false;
4692 : : }
4693 : :
2760 4694 [ + + ]: 243 : if (pubinfo->pubtruncate)
4695 : : {
4696 [ + - ]: 181 : if (!first)
4697 : 181 : appendPQExpBufferStr(query, ", ");
4698 : :
4699 : 181 : appendPQExpBufferStr(query, "truncate");
4700 : 181 : first = false;
4701 : : }
4702 : :
1147 drowley@postgresql.o 4703 : 243 : appendPQExpBufferChar(query, '\'');
4704 : :
2028 peter@eisentraut.org 4705 [ + + ]: 243 : if (pubinfo->pubviaroot)
4706 : 5 : appendPQExpBufferStr(query, ", publish_via_partition_root = true");
4707 : :
277 akapila@postgresql.o 4708 [ + + ]: 243 : if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
4709 : 31 : appendPQExpBufferStr(query, ", publish_generated_columns = stored");
4710 : :
2028 peter@eisentraut.org 4711 : 243 : appendPQExpBufferStr(query, ");\n");
4712 : :
1421 tgl@sss.pgh.pa.us 4713 [ + - ]: 243 : if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4714 : 243 : ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
4715 : 243 : ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
4716 : : .owner = pubinfo->rolname,
4717 : : .description = "PUBLICATION",
4718 : : .section = SECTION_POST_DATA,
4719 : : .createStmt = query->data,
4720 : : .dropStmt = delq->data));
4721 : :
3119 peter_e@gmx.net 4722 [ + + ]: 243 : if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 4723 : 31 : dumpComment(fout, "PUBLICATION", qpubname,
3119 peter_e@gmx.net 4724 : 31 : NULL, pubinfo->rolname,
4725 : 31 : pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4726 : :
4727 [ - + ]: 243 : if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 4728 :UBC 0 : dumpSecLabel(fout, "PUBLICATION", qpubname,
3119 peter_e@gmx.net 4729 : 0 : NULL, pubinfo->rolname,
4730 : 0 : pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4731 : :
3203 peter_e@gmx.net 4732 :CBC 243 : destroyPQExpBuffer(delq);
4733 : 243 : destroyPQExpBuffer(query);
2800 tgl@sss.pgh.pa.us 4734 : 243 : free(qpubname);
4735 : : }
4736 : :
4737 : : /*
4738 : : * getPublicationNamespaces
4739 : : * get information about publication membership for dumpable schemas.
4740 : : */
4741 : : void
1461 akapila@postgresql.o 4742 : 189 : getPublicationNamespaces(Archive *fout)
4743 : : {
4744 : : PQExpBuffer query;
4745 : : PGresult *res;
4746 : : PublicationSchemaInfo *pubsinfo;
4747 : 189 : DumpOptions *dopt = fout->dopt;
4748 : : int i_tableoid;
4749 : : int i_oid;
4750 : : int i_pnpubid;
4751 : : int i_pnnspid;
4752 : : int i,
4753 : : j,
4754 : : ntups;
4755 : :
4756 [ + - - + ]: 189 : if (dopt->no_publications || fout->remoteVersion < 150000)
1461 akapila@postgresql.o 4757 :UBC 0 : return;
4758 : :
1461 akapila@postgresql.o 4759 :CBC 189 : query = createPQExpBuffer();
4760 : :
4761 : : /* Collect all publication membership info. */
4762 : 189 : appendPQExpBufferStr(query,
4763 : : "SELECT tableoid, oid, pnpubid, pnnspid "
4764 : : "FROM pg_catalog.pg_publication_namespace");
4765 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4766 : :
4767 : 189 : ntups = PQntuples(res);
4768 : :
4769 : 189 : i_tableoid = PQfnumber(res, "tableoid");
4770 : 189 : i_oid = PQfnumber(res, "oid");
4771 : 189 : i_pnpubid = PQfnumber(res, "pnpubid");
4772 : 189 : i_pnnspid = PQfnumber(res, "pnnspid");
4773 : :
4774 : : /* this allocation may be more than we need */
4775 : 189 : pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
4776 : 189 : j = 0;
4777 : :
4778 [ + + ]: 314 : for (i = 0; i < ntups; i++)
4779 : : {
4780 : 125 : Oid pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
4781 : 125 : Oid pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
4782 : : PublicationInfo *pubinfo;
4783 : : NamespaceInfo *nspinfo;
4784 : :
4785 : : /*
4786 : : * Ignore any entries for which we aren't interested in either the
4787 : : * publication or the rel.
4788 : : */
4789 : 125 : pubinfo = findPublicationByOid(pnpubid);
4790 [ - + ]: 125 : if (pubinfo == NULL)
1461 akapila@postgresql.o 4791 :UBC 0 : continue;
1461 akapila@postgresql.o 4792 :CBC 125 : nspinfo = findNamespaceByOid(pnnspid);
4793 [ - + ]: 125 : if (nspinfo == NULL)
1461 akapila@postgresql.o 4794 :UBC 0 : continue;
4795 : :
4796 : : /* OK, make a DumpableObject for this relationship */
1448 akapila@postgresql.o 4797 :CBC 125 : pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
1461 4798 : 125 : pubsinfo[j].dobj.catId.tableoid =
4799 : 125 : atooid(PQgetvalue(res, i, i_tableoid));
4800 : 125 : pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4801 : 125 : AssignDumpId(&pubsinfo[j].dobj);
4802 : 125 : pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
4803 : 125 : pubsinfo[j].dobj.name = nspinfo->dobj.name;
4804 : 125 : pubsinfo[j].publication = pubinfo;
4805 : 125 : pubsinfo[j].pubschema = nspinfo;
4806 : :
4807 : : /* Decide whether we want to dump it */
4808 : 125 : selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
4809 : :
4810 : 125 : j++;
4811 : : }
4812 : :
4813 : 189 : PQclear(res);
4814 : 189 : destroyPQExpBuffer(query);
4815 : : }
4816 : :
4817 : : /*
4818 : : * getPublicationTables
4819 : : * get information about publication membership for dumpable tables.
4820 : : */
4821 : : void
3203 peter_e@gmx.net 4822 : 189 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
4823 : : {
4824 : : PQExpBuffer query;
4825 : : PGresult *res;
4826 : : PublicationRelInfo *pubrinfo;
2589 michael@paquier.xyz 4827 : 189 : DumpOptions *dopt = fout->dopt;
4828 : : int i_tableoid;
4829 : : int i_oid;
4830 : : int i_prpubid;
4831 : : int i_prrelid;
4832 : : int i_prrelqual;
4833 : : int i_prattrs;
4834 : : int i,
4835 : : j,
4836 : : ntups;
4837 : :
4838 [ + - - + ]: 189 : if (dopt->no_publications || fout->remoteVersion < 100000)
3203 peter_e@gmx.net 4839 :UBC 0 : return;
4840 : :
3203 peter_e@gmx.net 4841 :CBC 189 : query = createPQExpBuffer();
4842 : :
4843 : : /* Collect all publication membership info. */
1343 akapila@postgresql.o 4844 [ + - ]: 189 : if (fout->remoteVersion >= 150000)
4845 : 189 : appendPQExpBufferStr(query,
4846 : : "SELECT tableoid, oid, prpubid, prrelid, "
4847 : : "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
4848 : : "(CASE\n"
4849 : : " WHEN pr.prattrs IS NOT NULL THEN\n"
4850 : : " (SELECT array_agg(attname)\n"
4851 : : " FROM\n"
4852 : : " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
4853 : : " pg_catalog.pg_attribute\n"
4854 : : " WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
4855 : : " ELSE NULL END) prattrs "
4856 : : "FROM pg_catalog.pg_publication_rel pr");
4857 : : else
1343 akapila@postgresql.o 4858 :UBC 0 : appendPQExpBufferStr(query,
4859 : : "SELECT tableoid, oid, prpubid, prrelid, "
4860 : : "NULL AS prrelqual, NULL AS prattrs "
4861 : : "FROM pg_catalog.pg_publication_rel");
1747 tgl@sss.pgh.pa.us 4862 :CBC 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4863 : :
4864 : 189 : ntups = PQntuples(res);
4865 : :
4866 : 189 : i_tableoid = PQfnumber(res, "tableoid");
4867 : 189 : i_oid = PQfnumber(res, "oid");
4868 : 189 : i_prpubid = PQfnumber(res, "prpubid");
4869 : 189 : i_prrelid = PQfnumber(res, "prrelid");
1343 akapila@postgresql.o 4870 : 189 : i_prrelqual = PQfnumber(res, "prrelqual");
1311 tomas.vondra@postgre 4871 : 189 : i_prattrs = PQfnumber(res, "prattrs");
4872 : :
4873 : : /* this allocation may be more than we need */
1747 tgl@sss.pgh.pa.us 4874 : 189 : pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
4875 : 189 : j = 0;
4876 : :
4877 [ + + ]: 539 : for (i = 0; i < ntups; i++)
4878 : : {
4879 : 350 : Oid prpubid = atooid(PQgetvalue(res, i, i_prpubid));
4880 : 350 : Oid prrelid = atooid(PQgetvalue(res, i, i_prrelid));
4881 : : PublicationInfo *pubinfo;
4882 : : TableInfo *tbinfo;
4883 : :
4884 : : /*
4885 : : * Ignore any entries for which we aren't interested in either the
4886 : : * publication or the rel.
4887 : : */
4888 : 350 : pubinfo = findPublicationByOid(prpubid);
4889 [ - + ]: 350 : if (pubinfo == NULL)
1747 tgl@sss.pgh.pa.us 4890 :UBC 0 : continue;
1747 tgl@sss.pgh.pa.us 4891 :CBC 350 : tbinfo = findTableByOid(prrelid);
4892 [ - + ]: 350 : if (tbinfo == NULL)
3203 peter_e@gmx.net 4893 :UBC 0 : continue;
4894 : :
4895 : : /* OK, make a DumpableObject for this relationship */
1747 tgl@sss.pgh.pa.us 4896 :CBC 350 : pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
4897 : 350 : pubrinfo[j].dobj.catId.tableoid =
4898 : 350 : atooid(PQgetvalue(res, i, i_tableoid));
4899 : 350 : pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4900 : 350 : AssignDumpId(&pubrinfo[j].dobj);
4901 : 350 : pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4902 : 350 : pubrinfo[j].dobj.name = tbinfo->dobj.name;
4903 : 350 : pubrinfo[j].publication = pubinfo;
4904 : 350 : pubrinfo[j].pubtable = tbinfo;
1343 akapila@postgresql.o 4905 [ + + ]: 350 : if (PQgetisnull(res, i, i_prrelqual))
4906 : 194 : pubrinfo[j].pubrelqual = NULL;
4907 : : else
4908 : 156 : pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
4909 : :
1311 tomas.vondra@postgre 4910 [ + + ]: 350 : if (!PQgetisnull(res, i, i_prattrs))
4911 : : {
4912 : : char **attnames;
4913 : : int nattnames;
4914 : : PQExpBuffer attribs;
4915 : :
4916 [ - + ]: 111 : if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
4917 : : &attnames, &nattnames))
1298 tgl@sss.pgh.pa.us 4918 :UBC 0 : pg_fatal("could not parse %s array", "prattrs");
1311 tomas.vondra@postgre 4919 :CBC 111 : attribs = createPQExpBuffer();
4920 [ + + ]: 319 : for (int k = 0; k < nattnames; k++)
4921 : : {
4922 [ + + ]: 208 : if (k > 0)
4923 : 97 : appendPQExpBufferStr(attribs, ", ");
4924 : :
4925 : 208 : appendPQExpBufferStr(attribs, fmtId(attnames[k]));
4926 : : }
4927 : 111 : pubrinfo[j].pubrattrs = attribs->data;
257 tgl@sss.pgh.pa.us 4928 : 111 : free(attribs); /* but not attribs->data */
4929 : 111 : free(attnames);
4930 : : }
4931 : : else
1311 tomas.vondra@postgre 4932 : 239 : pubrinfo[j].pubrattrs = NULL;
4933 : :
4934 : : /* Decide whether we want to dump it */
1461 akapila@postgresql.o 4935 : 350 : selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
4936 : :
1747 tgl@sss.pgh.pa.us 4937 : 350 : j++;
4938 : : }
4939 : :
4940 : 189 : PQclear(res);
3203 peter_e@gmx.net 4941 : 189 : destroyPQExpBuffer(query);
4942 : : }
4943 : :
4944 : : /*
4945 : : * dumpPublicationNamespace
4946 : : * dump the definition of the given publication schema mapping.
4947 : : */
4948 : : static void
1461 akapila@postgresql.o 4949 : 99 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
4950 : : {
1397 tgl@sss.pgh.pa.us 4951 : 99 : DumpOptions *dopt = fout->dopt;
1461 akapila@postgresql.o 4952 : 99 : NamespaceInfo *schemainfo = pubsinfo->pubschema;
4953 : 99 : PublicationInfo *pubinfo = pubsinfo->publication;
4954 : : PQExpBuffer query;
4955 : : char *tag;
4956 : :
4957 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 4958 [ + + ]: 99 : if (!dopt->dumpSchema)
1461 akapila@postgresql.o 4959 : 12 : return;
4960 : :
4961 : 87 : tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
4962 : :
4963 : 87 : query = createPQExpBuffer();
4964 : :
4965 : 87 : appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
1131 alvherre@alvh.no-ip. 4966 : 87 : appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
4967 : :
4968 : : /*
4969 : : * There is no point in creating drop query as the drop is done by schema
4970 : : * drop.
4971 : : */
1397 tgl@sss.pgh.pa.us 4972 [ + - ]: 87 : if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4973 : 87 : ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
4974 : 87 : ARCHIVE_OPTS(.tag = tag,
4975 : : .namespace = schemainfo->dobj.name,
4976 : : .owner = pubinfo->rolname,
4977 : : .description = "PUBLICATION TABLES IN SCHEMA",
4978 : : .section = SECTION_POST_DATA,
4979 : : .createStmt = query->data));
4980 : :
4981 : : /* These objects can't currently have comments or seclabels */
4982 : :
1461 akapila@postgresql.o 4983 : 87 : free(tag);
4984 : 87 : destroyPQExpBuffer(query);
4985 : : }
4986 : :
4987 : : /*
4988 : : * dumpPublicationTable
4989 : : * dump the definition of the given publication table mapping
4990 : : */
4991 : : static void
1720 peter@eisentraut.org 4992 : 284 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
4993 : : {
1397 tgl@sss.pgh.pa.us 4994 : 284 : DumpOptions *dopt = fout->dopt;
1747 4995 : 284 : PublicationInfo *pubinfo = pubrinfo->publication;
3203 peter_e@gmx.net 4996 : 284 : TableInfo *tbinfo = pubrinfo->pubtable;
4997 : : PQExpBuffer query;
4998 : : char *tag;
4999 : :
5000 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 5001 [ + + ]: 284 : if (!dopt->dumpSchema)
1397 tgl@sss.pgh.pa.us 5002 : 42 : return;
5003 : :
1747 5004 : 242 : tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
5005 : :
3203 peter_e@gmx.net 5006 : 242 : query = createPQExpBuffer();
5007 : :
1299 tomas.vondra@postgre 5008 : 242 : appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
5009 : 242 : fmtId(pubinfo->dobj.name));
1343 akapila@postgresql.o 5010 : 242 : appendPQExpBuffer(query, " %s",
2800 tgl@sss.pgh.pa.us 5011 : 242 : fmtQualifiedDumpable(tbinfo));
5012 : :
1311 tomas.vondra@postgre 5013 [ + + ]: 242 : if (pubrinfo->pubrattrs)
5014 : 77 : appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
5015 : :
1343 akapila@postgresql.o 5016 [ + + ]: 242 : if (pubrinfo->pubrelqual)
5017 : : {
5018 : : /*
5019 : : * It's necessary to add parentheses around the expression because
5020 : : * pg_get_expr won't supply the parentheses for things like WHERE
5021 : : * TRUE.
5022 : : */
5023 : 108 : appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
5024 : : }
5025 : 242 : appendPQExpBufferStr(query, ";\n");
5026 : :
5027 : : /*
5028 : : * There is no point in creating a drop query as the drop is done by table
5029 : : * drop. (If you think to change this, see also _printTocEntry().)
5030 : : * Although this object doesn't really have ownership as such, set the
5031 : : * owner field anyway to ensure that the command is run by the correct
5032 : : * role at restore time.
5033 : : */
1421 tgl@sss.pgh.pa.us 5034 [ + - ]: 242 : if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5035 : 242 : ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
5036 : 242 : ARCHIVE_OPTS(.tag = tag,
5037 : : .namespace = tbinfo->dobj.namespace->dobj.name,
5038 : : .owner = pubinfo->rolname,
5039 : : .description = "PUBLICATION TABLE",
5040 : : .section = SECTION_POST_DATA,
5041 : : .createStmt = query->data));
5042 : :
5043 : : /* These objects can't currently have comments or seclabels */
5044 : :
3203 peter_e@gmx.net 5045 : 242 : free(tag);
5046 : 242 : destroyPQExpBuffer(query);
5047 : : }
5048 : :
5049 : : /*
5050 : : * Is the currently connected user a superuser?
5051 : : */
5052 : : static bool
3121 5053 : 188 : is_superuser(Archive *fout)
5054 : : {
5055 : 188 : ArchiveHandle *AH = (ArchiveHandle *) fout;
5056 : : const char *val;
5057 : :
5058 : 188 : val = PQparameterStatus(AH->connection, "is_superuser");
5059 : :
5060 [ + - + + ]: 188 : if (val && strcmp(val, "on") == 0)
5061 : 185 : return true;
5062 : :
5063 : 3 : return false;
5064 : : }
5065 : :
5066 : : /*
5067 : : * Set the given value to restrict_nonsystem_relation_kind value. Since
5068 : : * restrict_nonsystem_relation_kind is introduced in minor version releases,
5069 : : * the setting query is effective only where available.
5070 : : */
5071 : : static void
448 msawada@postgresql.o 5072 : 225 : set_restrict_relation_kind(Archive *AH, const char *value)
5073 : : {
5074 : 225 : PQExpBuffer query = createPQExpBuffer();
5075 : : PGresult *res;
5076 : :
5077 : 225 : appendPQExpBuffer(query,
5078 : : "SELECT set_config(name, '%s', false) "
5079 : : "FROM pg_settings "
5080 : : "WHERE name = 'restrict_nonsystem_relation_kind'",
5081 : : value);
5082 : 225 : res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
5083 : :
5084 : 225 : PQclear(res);
5085 : 225 : destroyPQExpBuffer(query);
5086 : 225 : }
5087 : :
5088 : : /*
5089 : : * getSubscriptions
5090 : : * get information about subscriptions
5091 : : */
5092 : : void
3203 peter_e@gmx.net 5093 : 189 : getSubscriptions(Archive *fout)
5094 : : {
3093 5095 : 189 : DumpOptions *dopt = fout->dopt;
5096 : : PQExpBuffer query;
5097 : : PGresult *res;
5098 : : SubscriptionInfo *subinfo;
5099 : : int i_tableoid;
5100 : : int i_oid;
5101 : : int i_subname;
5102 : : int i_subowner;
5103 : : int i_subbinary;
5104 : : int i_substream;
5105 : : int i_subtwophasestate;
5106 : : int i_subdisableonerr;
5107 : : int i_subpasswordrequired;
5108 : : int i_subrunasowner;
5109 : : int i_subconninfo;
5110 : : int i_subslotname;
5111 : : int i_subsynccommit;
5112 : : int i_subpublications;
5113 : : int i_suborigin;
5114 : : int i_suboriginremotelsn;
5115 : : int i_subenabled;
5116 : : int i_subfailover;
5117 : : int i_subretaindeadtuples;
5118 : : int i_submaxretention;
5119 : : int i,
5120 : : ntups;
5121 : :
5122 [ + + - + ]: 189 : if (dopt->no_subscriptions || fout->remoteVersion < 100000)
3121 5123 : 1 : return;
5124 : :
5125 [ + + ]: 188 : if (!is_superuser(fout))
5126 : : {
5127 : : int n;
5128 : :
5129 : 3 : res = ExecuteSqlQuery(fout,
5130 : : "SELECT count(*) FROM pg_subscription "
5131 : : "WHERE subdbid = (SELECT oid FROM pg_database"
5132 : : " WHERE datname = current_database())",
5133 : : PGRES_TUPLES_OK);
5134 : 3 : n = atoi(PQgetvalue(res, 0, 0));
5135 [ + + ]: 3 : if (n > 0)
2401 peter@eisentraut.org 5136 : 2 : pg_log_warning("subscriptions not dumped because current user is not a superuser");
3121 peter_e@gmx.net 5137 : 3 : PQclear(res);
3203 5138 : 3 : return;
5139 : : }
5140 : :
5141 : 185 : query = createPQExpBuffer();
5142 : :
5143 : : /* Get the subscriptions in current database. */
1147 drowley@postgresql.o 5144 : 185 : appendPQExpBufferStr(query,
5145 : : "SELECT s.tableoid, s.oid, s.subname,\n"
5146 : : " s.subowner,\n"
5147 : : " s.subconninfo, s.subslotname, s.subsynccommit,\n"
5148 : : " s.subpublications,\n");
5149 : :
1927 tgl@sss.pgh.pa.us 5150 [ + - ]: 185 : if (fout->remoteVersion >= 140000)
1838 drowley@postgresql.o 5151 : 185 : appendPQExpBufferStr(query, " s.subbinary,\n");
5152 : : else
1838 drowley@postgresql.o 5153 :UBC 0 : appendPQExpBufferStr(query, " false AS subbinary,\n");
5154 : :
1880 akapila@postgresql.o 5155 [ + - ]:CBC 185 : if (fout->remoteVersion >= 140000)
1566 5156 : 185 : appendPQExpBufferStr(query, " s.substream,\n");
5157 : : else
1022 akapila@postgresql.o 5158 :UBC 0 : appendPQExpBufferStr(query, " 'f' AS substream,\n");
5159 : :
1566 akapila@postgresql.o 5160 [ + - ]:CBC 185 : if (fout->remoteVersion >= 150000)
1323 5161 : 185 : appendPQExpBufferStr(query,
5162 : : " s.subtwophasestate,\n"
5163 : : " s.subdisableonerr,\n");
5164 : : else
1566 akapila@postgresql.o 5165 :UBC 0 : appendPQExpBuffer(query,
5166 : : " '%c' AS subtwophasestate,\n"
5167 : : " false AS subdisableonerr,\n",
5168 : : LOGICALREP_TWOPHASE_STATE_DISABLED);
5169 : :
1194 akapila@postgresql.o 5170 [ + - ]:CBC 185 : if (fout->remoteVersion >= 160000)
942 rhaas@postgresql.org 5171 : 185 : appendPQExpBufferStr(query,
5172 : : " s.subpasswordrequired,\n"
5173 : : " s.subrunasowner,\n"
5174 : : " s.suborigin,\n");
5175 : : else
942 rhaas@postgresql.org 5176 :UBC 0 : appendPQExpBuffer(query,
5177 : : " 't' AS subpasswordrequired,\n"
5178 : : " 't' AS subrunasowner,\n"
5179 : : " '%s' AS suborigin,\n",
5180 : : LOGICALREP_ORIGIN_ANY);
5181 : :
664 akapila@postgresql.o 5182 [ + + + - ]:CBC 185 : if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5183 : 36 : appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
5184 : : " s.subenabled,\n");
5185 : : else
5186 : 149 : appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
5187 : : " false AS subenabled,\n");
5188 : :
552 5189 [ + - ]: 185 : if (fout->remoteVersion >= 170000)
5190 : 185 : appendPQExpBufferStr(query,
5191 : : " s.subfailover,\n");
5192 : : else
192 drowley@postgresql.o 5193 :UNC 0 : appendPQExpBufferStr(query,
5194 : : " false AS subfailover,\n");
5195 : :
96 akapila@postgresql.o 5196 [ + - ]:GNC 185 : if (fout->remoteVersion >= 190000)
5197 : 185 : appendPQExpBufferStr(query,
5198 : : " s.subretaindeadtuples,\n");
5199 : : else
96 akapila@postgresql.o 5200 :UBC 0 : appendPQExpBufferStr(query,
5201 : : " false AS subretaindeadtuples,\n");
5202 : :
55 akapila@postgresql.o 5203 [ + - ]:GNC 185 : if (fout->remoteVersion >= 190000)
5204 : 185 : appendPQExpBufferStr(query,
5205 : : " s.submaxretention\n");
5206 : : else
55 akapila@postgresql.o 5207 :UNC 0 : appendPQExpBuffer(query,
5208 : : " 0 AS submaxretention\n");
5209 : :
664 akapila@postgresql.o 5210 :CBC 185 : appendPQExpBufferStr(query,
5211 : : "FROM pg_subscription s\n");
5212 : :
5213 [ + + + - ]: 185 : if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5214 : 36 : appendPQExpBufferStr(query,
5215 : : "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
5216 : : " ON o.external_id = 'pg_' || s.oid::text \n");
5217 : :
1838 drowley@postgresql.o 5218 : 185 : appendPQExpBufferStr(query,
5219 : : "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
5220 : : " WHERE datname = current_database())");
5221 : :
3203 peter_e@gmx.net 5222 : 185 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5223 : :
5224 : 185 : ntups = PQntuples(res);
5225 : :
5226 : : /*
5227 : : * Get subscription fields. We don't include subskiplsn in the dump as
5228 : : * after restoring the dump this value may no longer be relevant.
5229 : : */
5230 : 185 : i_tableoid = PQfnumber(res, "tableoid");
5231 : 185 : i_oid = PQfnumber(res, "oid");
5232 : 185 : i_subname = PQfnumber(res, "subname");
1396 tgl@sss.pgh.pa.us 5233 : 185 : i_subowner = PQfnumber(res, "subowner");
328 michael@paquier.xyz 5234 : 185 : i_subenabled = PQfnumber(res, "subenabled");
1927 tgl@sss.pgh.pa.us 5235 : 185 : i_subbinary = PQfnumber(res, "subbinary");
1880 akapila@postgresql.o 5236 : 185 : i_substream = PQfnumber(res, "substream");
1566 5237 : 185 : i_subtwophasestate = PQfnumber(res, "subtwophasestate");
1323 5238 : 185 : i_subdisableonerr = PQfnumber(res, "subdisableonerr");
942 rhaas@postgresql.org 5239 : 185 : i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
729 tgl@sss.pgh.pa.us 5240 : 185 : i_subrunasowner = PQfnumber(res, "subrunasowner");
328 michael@paquier.xyz 5241 : 185 : i_subfailover = PQfnumber(res, "subfailover");
96 akapila@postgresql.o 5242 :GNC 185 : i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
55 5243 : 185 : i_submaxretention = PQfnumber(res, "submaxretention");
729 tgl@sss.pgh.pa.us 5244 :CBC 185 : i_subconninfo = PQfnumber(res, "subconninfo");
5245 : 185 : i_subslotname = PQfnumber(res, "subslotname");
5246 : 185 : i_subsynccommit = PQfnumber(res, "subsynccommit");
5247 : 185 : i_subpublications = PQfnumber(res, "subpublications");
5248 : 185 : i_suborigin = PQfnumber(res, "suborigin");
664 akapila@postgresql.o 5249 : 185 : i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
5250 : :
3203 peter_e@gmx.net 5251 : 185 : subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
5252 : :
5253 [ + + ]: 313 : for (i = 0; i < ntups; i++)
5254 : : {
5255 : 128 : subinfo[i].dobj.objType = DO_SUBSCRIPTION;
5256 : 128 : subinfo[i].dobj.catId.tableoid =
5257 : 128 : atooid(PQgetvalue(res, i, i_tableoid));
5258 : 128 : subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5259 : 128 : AssignDumpId(&subinfo[i].dobj);
5260 : 128 : subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
1396 tgl@sss.pgh.pa.us 5261 : 128 : subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
5262 : :
328 michael@paquier.xyz 5263 : 128 : subinfo[i].subenabled =
5264 : 128 : (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
1927 tgl@sss.pgh.pa.us 5265 : 128 : subinfo[i].subbinary =
328 michael@paquier.xyz 5266 : 128 : (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
5267 : 128 : subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
5268 : 128 : subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
1323 akapila@postgresql.o 5269 : 128 : subinfo[i].subdisableonerr =
328 michael@paquier.xyz 5270 : 128 : (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
942 rhaas@postgresql.org 5271 : 128 : subinfo[i].subpasswordrequired =
328 michael@paquier.xyz 5272 : 128 : (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
729 tgl@sss.pgh.pa.us 5273 : 128 : subinfo[i].subrunasowner =
328 michael@paquier.xyz 5274 : 128 : (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
5275 : 128 : subinfo[i].subfailover =
5276 : 128 : (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
96 akapila@postgresql.o 5277 :GNC 128 : subinfo[i].subretaindeadtuples =
5278 : 128 : (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
55 5279 : 128 : subinfo[i].submaxretention =
5280 : 128 : atoi(PQgetvalue(res, i, i_submaxretention));
729 tgl@sss.pgh.pa.us 5281 :CBC 256 : subinfo[i].subconninfo =
5282 : 128 : pg_strdup(PQgetvalue(res, i, i_subconninfo));
5283 [ - + ]: 128 : if (PQgetisnull(res, i, i_subslotname))
729 tgl@sss.pgh.pa.us 5284 :UBC 0 : subinfo[i].subslotname = NULL;
5285 : : else
729 tgl@sss.pgh.pa.us 5286 :CBC 128 : subinfo[i].subslotname =
5287 : 128 : pg_strdup(PQgetvalue(res, i, i_subslotname));
5288 : 256 : subinfo[i].subsynccommit =
5289 : 128 : pg_strdup(PQgetvalue(res, i, i_subsynccommit));
5290 : 256 : subinfo[i].subpublications =
5291 : 128 : pg_strdup(PQgetvalue(res, i, i_subpublications));
5292 : 128 : subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
664 akapila@postgresql.o 5293 [ + + ]: 128 : if (PQgetisnull(res, i, i_suboriginremotelsn))
5294 : 127 : subinfo[i].suboriginremotelsn = NULL;
5295 : : else
5296 : 1 : subinfo[i].suboriginremotelsn =
5297 : 1 : pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
5298 : :
5299 : : /* Decide whether we want to dump it */
3121 peter_e@gmx.net 5300 : 128 : selectDumpableObject(&(subinfo[i].dobj), fout);
5301 : : }
3203 5302 : 185 : PQclear(res);
5303 : :
5304 : 185 : destroyPQExpBuffer(query);
5305 : : }
5306 : :
5307 : : /*
5308 : : * getSubscriptionRelations
5309 : : * Get information about subscription membership for dumpable relations. This
5310 : : * will be used only in binary-upgrade mode for PG17 or later versions.
5311 : : */
5312 : : void
11 akapila@postgresql.o 5313 :GNC 189 : getSubscriptionRelations(Archive *fout)
5314 : : {
664 akapila@postgresql.o 5315 :CBC 189 : DumpOptions *dopt = fout->dopt;
5316 : 189 : SubscriptionInfo *subinfo = NULL;
5317 : : SubRelInfo *subrinfo;
5318 : : PGresult *res;
5319 : : int i_srsubid;
5320 : : int i_srrelid;
5321 : : int i_srsubstate;
5322 : : int i_srsublsn;
5323 : : int ntups;
5324 : 189 : Oid last_srsubid = InvalidOid;
5325 : :
5326 [ + + + + ]: 189 : if (dopt->no_subscriptions || !dopt->binary_upgrade ||
5327 [ - + ]: 36 : fout->remoteVersion < 170000)
5328 : 153 : return;
5329 : :
5330 : 36 : res = ExecuteSqlQuery(fout,
5331 : : "SELECT srsubid, srrelid, srsubstate, srsublsn "
5332 : : "FROM pg_catalog.pg_subscription_rel "
5333 : : "ORDER BY srsubid",
5334 : : PGRES_TUPLES_OK);
5335 : 36 : ntups = PQntuples(res);
5336 [ + + ]: 36 : if (ntups == 0)
5337 : 35 : goto cleanup;
5338 : :
5339 : : /* Get pg_subscription_rel attributes */
5340 : 1 : i_srsubid = PQfnumber(res, "srsubid");
5341 : 1 : i_srrelid = PQfnumber(res, "srrelid");
5342 : 1 : i_srsubstate = PQfnumber(res, "srsubstate");
5343 : 1 : i_srsublsn = PQfnumber(res, "srsublsn");
5344 : :
5345 : 1 : subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
5346 [ + + ]: 3 : for (int i = 0; i < ntups; i++)
5347 : : {
5348 : 2 : Oid cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
5349 : 2 : Oid relid = atooid(PQgetvalue(res, i, i_srrelid));
5350 : : TableInfo *tblinfo;
5351 : :
5352 : : /*
5353 : : * If we switched to a new subscription, check if the subscription
5354 : : * exists.
5355 : : */
5356 [ + - ]: 2 : if (cur_srsubid != last_srsubid)
5357 : : {
5358 : 2 : subinfo = findSubscriptionByOid(cur_srsubid);
5359 [ - + ]: 2 : if (subinfo == NULL)
664 akapila@postgresql.o 5360 :UBC 0 : pg_fatal("subscription with OID %u does not exist", cur_srsubid);
5361 : :
664 akapila@postgresql.o 5362 :CBC 2 : last_srsubid = cur_srsubid;
5363 : : }
5364 : :
5365 : 2 : tblinfo = findTableByOid(relid);
5366 [ - + ]: 2 : if (tblinfo == NULL)
11 akapila@postgresql.o 5367 :UNC 0 : pg_fatal("failed sanity check, relation with OID %u not found",
5368 : : relid);
5369 : :
5370 : : /* OK, make a DumpableObject for this relationship */
664 akapila@postgresql.o 5371 :CBC 2 : subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
5372 : 2 : subrinfo[i].dobj.catId.tableoid = relid;
5373 : 2 : subrinfo[i].dobj.catId.oid = cur_srsubid;
5374 : 2 : AssignDumpId(&subrinfo[i].dobj);
5375 : 2 : subrinfo[i].dobj.name = pg_strdup(subinfo->dobj.name);
5376 : 2 : subrinfo[i].tblinfo = tblinfo;
5377 : 2 : subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
5378 [ + + ]: 2 : if (PQgetisnull(res, i, i_srsublsn))
5379 : 1 : subrinfo[i].srsublsn = NULL;
5380 : : else
5381 : 1 : subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
5382 : :
5383 : 2 : subrinfo[i].subinfo = subinfo;
5384 : :
5385 : : /* Decide whether we want to dump it */
5386 : 2 : selectDumpableObject(&(subrinfo[i].dobj), fout);
5387 : : }
5388 : :
5389 : 1 : cleanup:
5390 : 36 : PQclear(res);
5391 : : }
5392 : :
5393 : : /*
5394 : : * dumpSubscriptionTable
5395 : : * Dump the definition of the given subscription table mapping. This will be
5396 : : * used only in binary-upgrade mode for PG17 or later versions.
5397 : : */
5398 : : static void
5399 : 2 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
5400 : : {
5401 : 2 : DumpOptions *dopt = fout->dopt;
5402 : 2 : SubscriptionInfo *subinfo = subrinfo->subinfo;
5403 : : PQExpBuffer query;
5404 : : char *tag;
5405 : :
5406 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 5407 [ - + ]: 2 : if (!dopt->dumpSchema)
664 akapila@postgresql.o 5408 :UBC 0 : return;
5409 : :
664 akapila@postgresql.o 5410 [ + - + - ]:CBC 2 : Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
5411 : :
5412 : 2 : tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->dobj.name);
5413 : :
5414 : 2 : query = createPQExpBuffer();
5415 : :
5416 [ + - ]: 2 : if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5417 : : {
5418 : : /*
5419 : : * binary_upgrade_add_sub_rel_state will add the subscription relation
5420 : : * to pg_subscription_rel table. This will be used only in
5421 : : * binary-upgrade mode.
5422 : : */
5423 : 2 : appendPQExpBufferStr(query,
5424 : : "\n-- For binary upgrade, must preserve the subscriber table.\n");
5425 : 2 : appendPQExpBufferStr(query,
5426 : : "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
5427 : 2 : appendStringLiteralAH(query, subrinfo->dobj.name, fout);
5428 : 2 : appendPQExpBuffer(query,
5429 : : ", %u, '%c'",
5430 : 2 : subrinfo->tblinfo->dobj.catId.oid,
5431 : 2 : subrinfo->srsubstate);
5432 : :
5433 [ + + + - ]: 2 : if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
5434 : 1 : appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
5435 : : else
192 drowley@postgresql.o 5436 : 1 : appendPQExpBufferStr(query, ", NULL");
5437 : :
664 akapila@postgresql.o 5438 : 2 : appendPQExpBufferStr(query, ");\n");
5439 : : }
5440 : :
5441 : : /*
5442 : : * There is no point in creating a drop query as the drop is done by table
5443 : : * drop. (If you think to change this, see also _printTocEntry().)
5444 : : * Although this object doesn't really have ownership as such, set the
5445 : : * owner field anyway to ensure that the command is run by the correct
5446 : : * role at restore time.
5447 : : */
5448 [ + - ]: 2 : if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5449 : 2 : ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
5450 : 2 : ARCHIVE_OPTS(.tag = tag,
5451 : : .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
5452 : : .owner = subinfo->rolname,
5453 : : .description = "SUBSCRIPTION TABLE",
5454 : : .section = SECTION_POST_DATA,
5455 : : .createStmt = query->data));
5456 : :
5457 : : /* These objects can't currently have comments or seclabels */
5458 : :
5459 : 2 : free(tag);
5460 : 2 : destroyPQExpBuffer(query);
5461 : : }
5462 : :
5463 : : /*
5464 : : * dumpSubscription
5465 : : * dump the definition of the given subscription
5466 : : */
5467 : : static void
1720 peter@eisentraut.org 5468 : 110 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
5469 : : {
1397 tgl@sss.pgh.pa.us 5470 : 110 : DumpOptions *dopt = fout->dopt;
5471 : : PQExpBuffer delq;
5472 : : PQExpBuffer query;
5473 : : PQExpBuffer publications;
5474 : : char *qsubname;
3203 peter_e@gmx.net 5475 : 110 : char **pubnames = NULL;
5476 : 110 : int npubnames = 0;
5477 : : int i;
5478 : :
5479 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 5480 [ + + ]: 110 : if (!dopt->dumpSchema)
1397 tgl@sss.pgh.pa.us 5481 : 18 : return;
5482 : :
3203 peter_e@gmx.net 5483 : 92 : delq = createPQExpBuffer();
5484 : 92 : query = createPQExpBuffer();
5485 : :
2800 tgl@sss.pgh.pa.us 5486 : 92 : qsubname = pg_strdup(fmtId(subinfo->dobj.name));
5487 : :
3203 peter_e@gmx.net 5488 : 92 : appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
5489 : : qsubname);
5490 : :
5491 : 92 : appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
5492 : : qsubname);
5493 : 92 : appendStringLiteralAH(query, subinfo->subconninfo, fout);
5494 : :
5495 : : /* Build list of quoted publications and append them to query. */
5496 [ - + ]: 92 : if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
1298 tgl@sss.pgh.pa.us 5497 :UBC 0 : pg_fatal("could not parse %s array", "subpublications");
5498 : :
3203 peter_e@gmx.net 5499 :CBC 92 : publications = createPQExpBuffer();
5500 [ + + ]: 184 : for (i = 0; i < npubnames; i++)
5501 : : {
5502 [ - + ]: 92 : if (i > 0)
3203 peter_e@gmx.net 5503 :UBC 0 : appendPQExpBufferStr(publications, ", ");
5504 : :
3203 peter_e@gmx.net 5505 :CBC 92 : appendPQExpBufferStr(publications, fmtId(pubnames[i]));
5506 : : }
5507 : :
3090 5508 : 92 : appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
3085 5509 [ + - ]: 92 : if (subinfo->subslotname)
5510 : 92 : appendStringLiteralAH(query, subinfo->subslotname, fout);
5511 : : else
3085 peter_e@gmx.net 5512 :UBC 0 : appendPQExpBufferStr(query, "NONE");
5513 : :
328 michael@paquier.xyz 5514 [ - + ]:CBC 92 : if (subinfo->subbinary)
1838 drowley@postgresql.o 5515 :UBC 0 : appendPQExpBufferStr(query, ", binary = true");
5516 : :
328 michael@paquier.xyz 5517 [ + + ]:CBC 92 : if (subinfo->substream == LOGICALREP_STREAM_ON)
1838 drowley@postgresql.o 5518 : 30 : appendPQExpBufferStr(query, ", streaming = on");
328 michael@paquier.xyz 5519 [ + + ]: 62 : else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
1022 akapila@postgresql.o 5520 : 32 : appendPQExpBufferStr(query, ", streaming = parallel");
5521 : : else
364 5522 : 30 : appendPQExpBufferStr(query, ", streaming = off");
5523 : :
328 michael@paquier.xyz 5524 [ - + ]: 92 : if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
1566 akapila@postgresql.o 5525 :UBC 0 : appendPQExpBufferStr(query, ", two_phase = on");
5526 : :
328 michael@paquier.xyz 5527 [ - + ]:CBC 92 : if (subinfo->subdisableonerr)
1323 akapila@postgresql.o 5528 :UBC 0 : appendPQExpBufferStr(query, ", disable_on_error = true");
5529 : :
328 michael@paquier.xyz 5530 [ - + ]:CBC 92 : if (!subinfo->subpasswordrequired)
192 drowley@postgresql.o 5531 :UBC 0 : appendPQExpBufferStr(query, ", password_required = false");
5532 : :
328 michael@paquier.xyz 5533 [ - + ]:CBC 92 : if (subinfo->subrunasowner)
729 tgl@sss.pgh.pa.us 5534 :UBC 0 : appendPQExpBufferStr(query, ", run_as_owner = true");
5535 : :
328 michael@paquier.xyz 5536 [ + + ]:CBC 92 : if (subinfo->subfailover)
552 akapila@postgresql.o 5537 : 1 : appendPQExpBufferStr(query, ", failover = true");
5538 : :
96 akapila@postgresql.o 5539 [ + + ]:GNC 92 : if (subinfo->subretaindeadtuples)
5540 : 1 : appendPQExpBufferStr(query, ", retain_dead_tuples = true");
5541 : :
55 5542 [ - + ]: 92 : if (subinfo->submaxretention)
55 akapila@postgresql.o 5543 :UNC 0 : appendPQExpBuffer(query, ", max_retention_duration = %d", subinfo->submaxretention);
5544 : :
3118 peter_e@gmx.net 5545 [ - + ]:CBC 92 : if (strcmp(subinfo->subsynccommit, "off") != 0)
3090 peter_e@gmx.net 5546 :UBC 0 : appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
5547 : :
729 tgl@sss.pgh.pa.us 5548 [ + + ]:CBC 92 : if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
5549 : 30 : appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
5550 : :
3203 peter_e@gmx.net 5551 : 92 : appendPQExpBufferStr(query, ");\n");
5552 : :
5553 : : /*
5554 : : * In binary-upgrade mode, we allow the replication to continue after the
5555 : : * upgrade.
5556 : : */
664 akapila@postgresql.o 5557 [ + + + - ]: 92 : if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5558 : : {
5559 [ + + ]: 5 : if (subinfo->suboriginremotelsn)
5560 : : {
5561 : : /*
5562 : : * Preserve the remote_lsn for the subscriber's replication
5563 : : * origin. This value is required to start the replication from
5564 : : * the position before the upgrade. This value will be stale if
5565 : : * the publisher gets upgraded before the subscriber node.
5566 : : * However, this shouldn't be a problem as the upgrade of the
5567 : : * publisher ensures that all the transactions were replicated
5568 : : * before upgrading it.
5569 : : */
5570 : 1 : appendPQExpBufferStr(query,
5571 : : "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
5572 : 1 : appendPQExpBufferStr(query,
5573 : : "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
5574 : 1 : appendStringLiteralAH(query, subinfo->dobj.name, fout);
5575 : 1 : appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
5576 : : }
5577 : :
328 michael@paquier.xyz 5578 [ + + ]: 5 : if (subinfo->subenabled)
5579 : : {
5580 : : /*
5581 : : * Enable the subscription to allow the replication to continue
5582 : : * after the upgrade.
5583 : : */
664 akapila@postgresql.o 5584 : 1 : appendPQExpBufferStr(query,
5585 : : "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
5586 : 1 : appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
5587 : : }
5588 : : }
5589 : :
1421 tgl@sss.pgh.pa.us 5590 [ + - ]: 92 : if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5591 : 92 : ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
5592 : 92 : ARCHIVE_OPTS(.tag = subinfo->dobj.name,
5593 : : .owner = subinfo->rolname,
5594 : : .description = "SUBSCRIPTION",
5595 : : .section = SECTION_POST_DATA,
5596 : : .createStmt = query->data,
5597 : : .dropStmt = delq->data));
5598 : :
3119 peter_e@gmx.net 5599 [ + + ]: 92 : if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 5600 : 30 : dumpComment(fout, "SUBSCRIPTION", qsubname,
3119 peter_e@gmx.net 5601 : 30 : NULL, subinfo->rolname,
5602 : 30 : subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5603 : :
5604 [ - + ]: 92 : if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 5605 :UBC 0 : dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
3119 peter_e@gmx.net 5606 : 0 : NULL, subinfo->rolname,
5607 : 0 : subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5608 : :
3203 peter_e@gmx.net 5609 :CBC 92 : destroyPQExpBuffer(publications);
1229 peter@eisentraut.org 5610 : 92 : free(pubnames);
5611 : :
3203 peter_e@gmx.net 5612 : 92 : destroyPQExpBuffer(delq);
5613 : 92 : destroyPQExpBuffer(query);
2800 tgl@sss.pgh.pa.us 5614 : 92 : free(qsubname);
5615 : : }
5616 : :
5617 : : /*
5618 : : * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
5619 : : * the object needs.
5620 : : */
5621 : : static void
2056 alvherre@alvh.no-ip. 5622 : 5043 : append_depends_on_extension(Archive *fout,
5623 : : PQExpBuffer create,
5624 : : const DumpableObject *dobj,
5625 : : const char *catalog,
5626 : : const char *keyword,
5627 : : const char *objname)
5628 : : {
5629 [ + + ]: 5043 : if (dobj->depends_on_ext)
5630 : : {
5631 : : char *nm;
5632 : : PGresult *res;
5633 : : PQExpBuffer query;
5634 : : int ntups;
5635 : : int i_extname;
5636 : : int i;
5637 : :
5638 : : /* dodge fmtId() non-reentrancy */
5639 : 42 : nm = pg_strdup(objname);
5640 : :
5641 : 42 : query = createPQExpBuffer();
5642 : 42 : appendPQExpBuffer(query,
5643 : : "SELECT e.extname "
5644 : : "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
5645 : : "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
5646 : : "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
5647 : : "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
5648 : : catalog,
5649 : 42 : dobj->catId.oid);
5650 : 42 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5651 : 42 : ntups = PQntuples(res);
5652 : 42 : i_extname = PQfnumber(res, "extname");
5653 [ + + ]: 84 : for (i = 0; i < ntups; i++)
5654 : : {
794 5655 : 42 : appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
5656 : : keyword, nm,
2056 5657 : 42 : fmtId(PQgetvalue(res, i, i_extname)));
5658 : : }
5659 : :
5660 : 42 : PQclear(res);
2051 5661 : 42 : destroyPQExpBuffer(query);
2056 5662 : 42 : pg_free(nm);
5663 : : }
5664 : 5043 : }
5665 : :
5666 : : static Oid
1772 akorotkov@postgresql 5667 :UBC 0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
5668 : : {
5669 : : /*
5670 : : * If the old version didn't assign an array type, but the new version
5671 : : * does, we must select an unused type OID to assign. This currently only
5672 : : * happens for domains, when upgrading pre-v11 to v11 and up.
5673 : : *
5674 : : * Note: local state here is kind of ugly, but we must have some, since we
5675 : : * mustn't choose the same unused OID more than once.
5676 : : */
5677 : : static Oid next_possible_free_oid = FirstNormalObjectId;
5678 : : PGresult *res;
5679 : : bool is_dup;
5680 : :
5681 : : do
5682 : : {
5683 : 0 : ++next_possible_free_oid;
5684 : 0 : printfPQExpBuffer(upgrade_query,
5685 : : "SELECT EXISTS(SELECT 1 "
5686 : : "FROM pg_catalog.pg_type "
5687 : : "WHERE oid = '%u'::pg_catalog.oid);",
5688 : : next_possible_free_oid);
5689 : 0 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5690 : 0 : is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
5691 : 0 : PQclear(res);
5692 [ # # ]: 0 : } while (is_dup);
5693 : :
5694 : 0 : return next_possible_free_oid;
5695 : : }
5696 : :
5697 : : static void
5011 rhaas@postgresql.org 5698 :CBC 941 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
5699 : : PQExpBuffer upgrade_buffer,
5700 : : Oid pg_type_oid,
5701 : : bool force_array_type,
5702 : : bool include_multirange_type)
5703 : : {
5786 bruce@momjian.us 5704 : 941 : PQExpBuffer upgrade_query = createPQExpBuffer();
5705 : : PGresult *res;
5706 : : Oid pg_type_array_oid;
5707 : : Oid pg_type_multirange_oid;
5708 : : Oid pg_type_multirange_array_oid;
5709 : : TypeInfo *tinfo;
5710 : :
4361 heikki.linnakangas@i 5711 : 941 : appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
5786 bruce@momjian.us 5712 : 941 : appendPQExpBuffer(upgrade_buffer,
5713 : : "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5714 : : pg_type_oid);
5715 : :
420 dgustafsson@postgres 5716 : 941 : tinfo = findTypeByOid(pg_type_oid);
417 5717 [ + - ]: 941 : if (tinfo)
5718 : 941 : pg_type_array_oid = tinfo->typarray;
5719 : : else
417 dgustafsson@postgres 5720 :UBC 0 : pg_type_array_oid = InvalidOid;
5721 : :
2949 tgl@sss.pgh.pa.us 5722 [ + + - + ]:CBC 941 : if (!OidIsValid(pg_type_array_oid) && force_array_type)
1772 akorotkov@postgresql 5723 :UBC 0 : pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5724 : :
5786 bruce@momjian.us 5725 [ + + ]:CBC 941 : if (OidIsValid(pg_type_array_oid))
5726 : : {
4361 heikki.linnakangas@i 5727 : 939 : appendPQExpBufferStr(upgrade_buffer,
5728 : : "\n-- For binary upgrade, must preserve pg_type array oid\n");
5786 bruce@momjian.us 5729 : 939 : appendPQExpBuffer(upgrade_buffer,
5730 : : "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5731 : : pg_type_array_oid);
5732 : : }
5733 : :
5734 : : /*
5735 : : * Pre-set the multirange type oid and its own array type oid.
5736 : : */
1772 akorotkov@postgresql 5737 [ + + ]: 941 : if (include_multirange_type)
5738 : : {
5739 [ + - ]: 8 : if (fout->remoteVersion >= 140000)
5740 : : {
1373 tgl@sss.pgh.pa.us 5741 : 8 : printfPQExpBuffer(upgrade_query,
5742 : : "SELECT t.oid, t.typarray "
5743 : : "FROM pg_catalog.pg_type t "
5744 : : "JOIN pg_catalog.pg_range r "
5745 : : "ON t.oid = r.rngmultitypid "
5746 : : "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
5747 : : pg_type_oid);
5748 : :
1772 akorotkov@postgresql 5749 : 8 : res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5750 : :
5751 : 8 : pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
5752 : 8 : pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
5753 : :
5754 : 8 : PQclear(res);
5755 : : }
5756 : : else
5757 : : {
1772 akorotkov@postgresql 5758 :UBC 0 : pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5759 : 0 : pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5760 : : }
5761 : :
1772 akorotkov@postgresql 5762 :CBC 8 : appendPQExpBufferStr(upgrade_buffer,
5763 : : "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
5764 : 8 : appendPQExpBuffer(upgrade_buffer,
5765 : : "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5766 : : pg_type_multirange_oid);
5767 : 8 : appendPQExpBufferStr(upgrade_buffer,
5768 : : "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
5769 : 8 : appendPQExpBuffer(upgrade_buffer,
5770 : : "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5771 : : pg_type_multirange_array_oid);
5772 : : }
5773 : :
5786 bruce@momjian.us 5774 : 941 : destroyPQExpBuffer(upgrade_query);
5775 : 941 : }
5776 : :
5777 : : static void
1421 tgl@sss.pgh.pa.us 5778 : 866 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
5779 : : PQExpBuffer upgrade_buffer,
5780 : : const TableInfo *tbinfo)
5781 : : {
5782 : 866 : Oid pg_type_oid = tbinfo->reltype;
5783 : :
1938 5784 [ + - ]: 866 : if (OidIsValid(pg_type_oid))
5785 : 866 : binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
5786 : : pg_type_oid, false, false);
5786 bruce@momjian.us 5787 : 866 : }
5788 : :
5789 : : /*
5790 : : * bsearch() comparator for BinaryUpgradeClassOidItem
5791 : : */
5792 : : static int
481 nathan@postgresql.or 5793 : 12363 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
5794 : : {
5795 : 12363 : BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
5796 : 12363 : BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
5797 : :
5798 : 12363 : return pg_cmp_u32(v1.oid, v2.oid);
5799 : : }
5800 : :
5801 : : /*
5802 : : * collectBinaryUpgradeClassOids
5803 : : *
5804 : : * Construct a table of pg_class information required for
5805 : : * binary_upgrade_set_pg_class_oids(). The table is sorted by OID for speed in
5806 : : * lookup.
5807 : : */
5808 : : static void
5809 : 36 : collectBinaryUpgradeClassOids(Archive *fout)
5810 : : {
5811 : : PGresult *res;
5812 : : const char *query;
5813 : :
5814 : 36 : query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
5815 : : "ct.relfilenode, i.indexrelid, cti.relfilenode "
5816 : : "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
5817 : : "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
5818 : : "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
5819 : : "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
5820 : : "ORDER BY c.oid;";
5821 : :
5822 : 36 : res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
5823 : :
5824 : 36 : nbinaryUpgradeClassOids = PQntuples(res);
5825 : 36 : binaryUpgradeClassOids = (BinaryUpgradeClassOidItem *)
5826 : 36 : pg_malloc(nbinaryUpgradeClassOids * sizeof(BinaryUpgradeClassOidItem));
5827 : :
5828 [ + + ]: 16854 : for (int i = 0; i < nbinaryUpgradeClassOids; i++)
5829 : : {
5830 : 16818 : binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
5831 : 16818 : binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
5832 : 16818 : binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
5833 : 16818 : binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
5834 : 16818 : binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
5835 : 16818 : binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
5836 : 16818 : binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
5837 : : }
5838 : :
5839 : 36 : PQclear(res);
5840 : 36 : }
5841 : :
5842 : : static void
5011 rhaas@postgresql.org 5843 : 1252 : binary_upgrade_set_pg_class_oids(Archive *fout,
5844 : : PQExpBuffer upgrade_buffer, Oid pg_class_oid)
5845 : : {
481 nathan@postgresql.or 5846 : 1252 : BinaryUpgradeClassOidItem key = {0};
5847 : : BinaryUpgradeClassOidItem *entry;
5848 : :
5849 [ - + ]: 1252 : Assert(binaryUpgradeClassOids);
5850 : :
5851 : : /*
5852 : : * Preserve the OID and relfilenumber of the table, table's index, table's
5853 : : * toast table and toast table's index if any.
5854 : : *
5855 : : * One complexity is that the current table definition might not require
5856 : : * the creation of a TOAST table, but the old database might have a TOAST
5857 : : * table that was created earlier, before some wide columns were dropped.
5858 : : * By setting the TOAST oid we force creation of the TOAST heap and index
5859 : : * by the new backend, so we can copy the files during binary upgrade
5860 : : * without worrying about this case.
5861 : : */
5862 : 1252 : key.oid = pg_class_oid;
5863 : 1252 : entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
5864 : : sizeof(BinaryUpgradeClassOidItem),
5865 : : BinaryUpgradeClassOidItemCmp);
5866 : :
4361 heikki.linnakangas@i 5867 : 1252 : appendPQExpBufferStr(upgrade_buffer,
5868 : : "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
5869 : :
481 nathan@postgresql.or 5870 [ + + ]: 1252 : if (entry->relkind != RELKIND_INDEX &&
5871 [ + + ]: 975 : entry->relkind != RELKIND_PARTITIONED_INDEX)
5872 : : {
5773 bruce@momjian.us 5873 : 950 : appendPQExpBuffer(upgrade_buffer,
5874 : : "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
5875 : : pg_class_oid);
5876 : :
5877 : : /*
5878 : : * Not every relation has storage. Also, in a pre-v12 database,
5879 : : * partitioned tables have a relfilenumber, which should not be
5880 : : * preserved when upgrading.
5881 : : */
481 nathan@postgresql.or 5882 [ + + ]: 950 : if (RelFileNumberIsValid(entry->relfilenumber) &&
5883 [ + - ]: 788 : entry->relkind != RELKIND_PARTITIONED_TABLE)
1379 rhaas@postgresql.org 5884 : 788 : appendPQExpBuffer(upgrade_buffer,
5885 : : "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
5886 : : entry->relfilenumber);
5887 : :
5888 : : /*
5889 : : * In a pre-v12 database, partitioned tables might be marked as having
5890 : : * toast tables, but we should ignore them if so.
5891 : : */
481 nathan@postgresql.or 5892 [ + + ]: 950 : if (OidIsValid(entry->toast_oid) &&
5893 [ + - ]: 277 : entry->relkind != RELKIND_PARTITIONED_TABLE)
5894 : : {
5409 bruce@momjian.us 5895 : 277 : appendPQExpBuffer(upgrade_buffer,
5896 : : "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
5897 : : entry->toast_oid);
1379 rhaas@postgresql.org 5898 : 277 : appendPQExpBuffer(upgrade_buffer,
5899 : : "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
5900 : : entry->toast_relfilenumber);
5901 : :
5902 : : /* every toast table has an index */
5409 bruce@momjian.us 5903 : 277 : appendPQExpBuffer(upgrade_buffer,
5904 : : "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5905 : : entry->toast_index_oid);
1379 rhaas@postgresql.org 5906 : 277 : appendPQExpBuffer(upgrade_buffer,
5907 : : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5908 : : entry->toast_index_relfilenumber);
5909 : : }
5910 : : }
5911 : : else
5912 : : {
5913 : : /* Preserve the OID and relfilenumber of the index */
5773 bruce@momjian.us 5914 : 302 : appendPQExpBuffer(upgrade_buffer,
5915 : : "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5916 : : pg_class_oid);
1379 rhaas@postgresql.org 5917 : 302 : appendPQExpBuffer(upgrade_buffer,
5918 : : "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5919 : : entry->relfilenumber);
5920 : : }
5921 : :
4361 heikki.linnakangas@i 5922 : 1252 : appendPQExpBufferChar(upgrade_buffer, '\n');
5786 bruce@momjian.us 5923 : 1252 : }
5924 : :
5925 : : /*
5926 : : * If the DumpableObject is a member of an extension, add a suitable
5927 : : * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
5928 : : *
5929 : : * For somewhat historical reasons, objname should already be quoted,
5930 : : * but not objnamespace (if any).
5931 : : */
5932 : : static void
5374 tgl@sss.pgh.pa.us 5933 : 1502 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
5934 : : const DumpableObject *dobj,
5935 : : const char *objtype,
5936 : : const char *objname,
5937 : : const char *objnamespace)
5938 : : {
5939 : 1502 : DumpableObject *extobj = NULL;
5940 : : int i;
5941 : :
5942 [ + + ]: 1502 : if (!dobj->ext_member)
5943 : 1481 : return;
5944 : :
5945 : : /*
5946 : : * Find the parent extension. We could avoid this search if we wanted to
5947 : : * add a link field to DumpableObject, but the space costs of that would
5948 : : * be considerable. We assume that member objects could only have a
5949 : : * direct dependency on their own extension, not any others.
5950 : : */
5951 [ + - ]: 21 : for (i = 0; i < dobj->nDeps; i++)
5952 : : {
5953 : 21 : extobj = findObjectByDumpId(dobj->dependencies[i]);
5954 [ + - + - ]: 21 : if (extobj && extobj->objType == DO_EXTENSION)
5955 : 21 : break;
5374 tgl@sss.pgh.pa.us 5956 :UBC 0 : extobj = NULL;
5957 : : }
5374 tgl@sss.pgh.pa.us 5958 [ - + ]:CBC 21 : if (extobj == NULL)
1298 tgl@sss.pgh.pa.us 5959 :UBC 0 : pg_fatal("could not find parent extension for %s %s",
5960 : : objtype, objname);
5961 : :
4361 heikki.linnakangas@i 5962 :CBC 21 : appendPQExpBufferStr(upgrade_buffer,
5963 : : "\n-- For binary upgrade, handle extension membership the hard way\n");
2800 tgl@sss.pgh.pa.us 5964 : 21 : appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
5374 5965 : 21 : fmtId(extobj->name),
5966 : : objtype);
2800 5967 [ + + + - ]: 21 : if (objnamespace && *objnamespace)
5968 : 18 : appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
5969 : 21 : appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
5970 : : }
5971 : :
5972 : : /*
5973 : : * getNamespaces:
5974 : : * get information about all namespaces in the system catalogs
5975 : : */
5976 : : void
482 nathan@postgresql.or 5977 : 190 : getNamespaces(Archive *fout)
5978 : : {
5979 : : PGresult *res;
5980 : : int ntups;
5981 : : int i;
5982 : : PQExpBuffer query;
5983 : : NamespaceInfo *nsinfo;
5984 : : int i_tableoid;
5985 : : int i_oid;
5986 : : int i_nspname;
5987 : : int i_nspowner;
5988 : : int i_nspacl;
5989 : : int i_acldefault;
5990 : :
8571 tgl@sss.pgh.pa.us 5991 : 190 : query = createPQExpBuffer();
5992 : :
5993 : : /*
5994 : : * we fetch all namespaces including system ones, so that every object we
5995 : : * read in can be linked to a containing namespace.
5996 : : */
1147 drowley@postgresql.o 5997 : 190 : appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
5998 : : "n.nspowner, "
5999 : : "n.nspacl, "
6000 : : "acldefault('n', n.nspowner) AS acldefault "
6001 : : "FROM pg_namespace n");
6002 : :
5011 rhaas@postgresql.org 6003 : 190 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6004 : :
10277 bruce@momjian.us 6005 : 190 : ntups = PQntuples(res);
6006 : :
5085 6007 : 190 : nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
6008 : :
7996 tgl@sss.pgh.pa.us 6009 : 190 : i_tableoid = PQfnumber(res, "tableoid");
10277 bruce@momjian.us 6010 : 190 : i_oid = PQfnumber(res, "oid");
8571 tgl@sss.pgh.pa.us 6011 : 190 : i_nspname = PQfnumber(res, "nspname");
1582 noah@leadboat.com 6012 : 190 : i_nspowner = PQfnumber(res, "nspowner");
8571 tgl@sss.pgh.pa.us 6013 : 190 : i_nspacl = PQfnumber(res, "nspacl");
1421 6014 : 190 : i_acldefault = PQfnumber(res, "acldefault");
6015 : :
10277 bruce@momjian.us 6016 [ + + ]: 1620 : for (i = 0; i < ntups; i++)
6017 : : {
6018 : : const char *nspowner;
6019 : :
7996 tgl@sss.pgh.pa.us 6020 : 1430 : nsinfo[i].dobj.objType = DO_NAMESPACE;
6021 : 1430 : nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6022 : 1430 : nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6023 : 1430 : AssignDumpId(&nsinfo[i].dobj);
5085 bruce@momjian.us 6024 : 1430 : nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
1421 tgl@sss.pgh.pa.us 6025 : 1430 : nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
6026 : 1430 : nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6027 : 1430 : nsinfo[i].dacl.privtype = 0;
6028 : 1430 : nsinfo[i].dacl.initprivs = NULL;
1396 6029 : 1430 : nspowner = PQgetvalue(res, i, i_nspowner);
6030 : 1430 : nsinfo[i].nspowner = atooid(nspowner);
6031 : 1430 : nsinfo[i].rolname = getRoleName(nspowner);
6032 : :
6033 : : /* Decide whether to dump this namespace */
3491 sfrost@snowman.net 6034 : 1430 : selectDumpableNamespace(&nsinfo[i], fout);
6035 : :
6036 : : /* Mark whether namespace has an ACL */
1421 tgl@sss.pgh.pa.us 6037 [ + + ]: 1430 : if (!PQgetisnull(res, i, i_nspacl))
6038 : 632 : nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6039 : :
6040 : : /*
6041 : : * We ignore any pg_init_privs.initprivs entry for the public schema
6042 : : * and assume a predetermined default, for several reasons. First,
6043 : : * dropping and recreating the schema removes its pg_init_privs entry,
6044 : : * but an empty destination database starts with this ACL nonetheless.
6045 : : * Second, we support dump/reload of public schema ownership changes.
6046 : : * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
6047 : : * initprivs continues to reflect the initial owner. Hence,
6048 : : * synthesize the value that nspacl will have after the restore's
6049 : : * ALTER SCHEMA OWNER. Third, this makes the destination database
6050 : : * match the source's ACL, even if the latter was an initdb-default
6051 : : * ACL, which changed in v15. An upgrade pulls in changes to most
6052 : : * system object ACLs that the DBA had not customized. We've made the
6053 : : * public schema depart from that, because changing its ACL so easily
6054 : : * breaks applications.
6055 : : */
6056 [ + + ]: 1430 : if (strcmp(nsinfo[i].dobj.name, "public") == 0)
6057 : : {
6058 : 186 : PQExpBuffer aclarray = createPQExpBuffer();
6059 : 186 : PQExpBuffer aclitem = createPQExpBuffer();
6060 : :
6061 : : /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
6062 : 186 : appendPQExpBufferChar(aclarray, '{');
6063 : 186 : quoteAclUserName(aclitem, nsinfo[i].rolname);
6064 : 186 : appendPQExpBufferStr(aclitem, "=UC/");
6065 : 186 : quoteAclUserName(aclitem, nsinfo[i].rolname);
6066 : 186 : appendPGArray(aclarray, aclitem->data);
6067 : 186 : resetPQExpBuffer(aclitem);
6068 : 186 : appendPQExpBufferStr(aclitem, "=U/");
6069 : 186 : quoteAclUserName(aclitem, nsinfo[i].rolname);
6070 : 186 : appendPGArray(aclarray, aclitem->data);
6071 : 186 : appendPQExpBufferChar(aclarray, '}');
6072 : :
6073 : 186 : nsinfo[i].dacl.privtype = 'i';
6074 : 186 : nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
6075 : 186 : nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6076 : :
6077 : 186 : destroyPQExpBuffer(aclarray);
6078 : 186 : destroyPQExpBuffer(aclitem);
6079 : : }
6080 : : }
6081 : :
10277 bruce@momjian.us 6082 : 190 : PQclear(res);
8851 tgl@sss.pgh.pa.us 6083 : 190 : destroyPQExpBuffer(query);
10374 scrappy@hub.org 6084 : 190 : }
6085 : :
6086 : : /*
6087 : : * findNamespace:
6088 : : * given a namespace OID, look up the info read by getNamespaces
6089 : : */
6090 : : static NamespaceInfo *
1889 peter@eisentraut.org 6091 : 728510 : findNamespace(Oid nsoid)
6092 : : {
6093 : : NamespaceInfo *nsinfo;
6094 : :
3302 tgl@sss.pgh.pa.us 6095 : 728510 : nsinfo = findNamespaceByOid(nsoid);
4903 6096 [ - + ]: 728510 : if (nsinfo == NULL)
1298 tgl@sss.pgh.pa.us 6097 :UBC 0 : pg_fatal("schema with OID %u does not exist", nsoid);
4903 tgl@sss.pgh.pa.us 6098 :CBC 728510 : return nsinfo;
6099 : : }
6100 : :
6101 : : /*
6102 : : * getExtensions:
6103 : : * read all extensions in the system catalogs and return them in the
6104 : : * ExtensionInfo* structure
6105 : : *
6106 : : * numExtensions is set to the number of extensions read in
6107 : : */
6108 : : ExtensionInfo *
3575 6109 : 190 : getExtensions(Archive *fout, int *numExtensions)
6110 : : {
6111 : 190 : DumpOptions *dopt = fout->dopt;
6112 : : PGresult *res;
6113 : : int ntups;
6114 : : int i;
6115 : : PQExpBuffer query;
390 dgustafsson@postgres 6116 : 190 : ExtensionInfo *extinfo = NULL;
6117 : : int i_tableoid;
6118 : : int i_oid;
6119 : : int i_extname;
6120 : : int i_nspname;
6121 : : int i_extrelocatable;
6122 : : int i_extversion;
6123 : : int i_extconfig;
6124 : : int i_extcondition;
6125 : :
5375 tgl@sss.pgh.pa.us 6126 : 190 : query = createPQExpBuffer();
6127 : :
4361 heikki.linnakangas@i 6128 : 190 : appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
6129 : : "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
6130 : : "FROM pg_extension x "
6131 : : "JOIN pg_namespace n ON n.oid = x.extnamespace");
6132 : :
5011 rhaas@postgresql.org 6133 : 190 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6134 : :
5375 tgl@sss.pgh.pa.us 6135 : 190 : ntups = PQntuples(res);
390 dgustafsson@postgres 6136 [ - + ]: 190 : if (ntups == 0)
390 dgustafsson@postgres 6137 :UBC 0 : goto cleanup;
6138 : :
5085 bruce@momjian.us 6139 :CBC 190 : extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
6140 : :
5375 tgl@sss.pgh.pa.us 6141 : 190 : i_tableoid = PQfnumber(res, "tableoid");
6142 : 190 : i_oid = PQfnumber(res, "oid");
6143 : 190 : i_extname = PQfnumber(res, "extname");
6144 : 190 : i_nspname = PQfnumber(res, "nspname");
5374 6145 : 190 : i_extrelocatable = PQfnumber(res, "extrelocatable");
6146 : 190 : i_extversion = PQfnumber(res, "extversion");
5375 6147 : 190 : i_extconfig = PQfnumber(res, "extconfig");
6148 : 190 : i_extcondition = PQfnumber(res, "extcondition");
6149 : :
6150 [ + + ]: 410 : for (i = 0; i < ntups; i++)
6151 : : {
6152 : 220 : extinfo[i].dobj.objType = DO_EXTENSION;
6153 : 220 : extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6154 : 220 : extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6155 : 220 : AssignDumpId(&extinfo[i].dobj);
5085 bruce@momjian.us 6156 : 220 : extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
6157 : 220 : extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
5374 tgl@sss.pgh.pa.us 6158 : 220 : extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
5085 bruce@momjian.us 6159 : 220 : extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
6160 : 220 : extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
6161 : 220 : extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
6162 : :
6163 : : /* Decide whether we want to dump it */
3575 tgl@sss.pgh.pa.us 6164 : 220 : selectDumpableExtension(&(extinfo[i]), dopt);
6165 : : }
6166 : :
390 dgustafsson@postgres 6167 : 190 : cleanup:
5375 tgl@sss.pgh.pa.us 6168 : 190 : PQclear(res);
6169 : 190 : destroyPQExpBuffer(query);
6170 : :
6171 : 190 : *numExtensions = ntups;
6172 : :
6173 : 190 : return extinfo;
6174 : : }
6175 : :
6176 : : /*
6177 : : * getTypes:
6178 : : * get information about all types in the system catalogs
6179 : : *
6180 : : * NB: this must run after getFuncs() because we assume we can do
6181 : : * findFuncByOid().
6182 : : */
6183 : : void
482 nathan@postgresql.or 6184 : 189 : getTypes(Archive *fout)
6185 : : {
6186 : : PGresult *res;
6187 : : int ntups;
6188 : : int i;
9329 bruce@momjian.us 6189 : 189 : PQExpBuffer query = createPQExpBuffer();
6190 : : TypeInfo *tyinfo;
6191 : : ShellTypeInfo *stinfo;
6192 : : int i_tableoid;
6193 : : int i_oid;
6194 : : int i_typname;
6195 : : int i_typnamespace;
6196 : : int i_typacl;
6197 : : int i_acldefault;
6198 : : int i_typowner;
6199 : : int i_typelem;
6200 : : int i_typrelid;
6201 : : int i_typrelkind;
6202 : : int i_typtype;
6203 : : int i_typisdefined;
6204 : : int i_isarray;
6205 : : int i_typarray;
6206 : :
6207 : : /*
6208 : : * we include even the built-in types because those may be used as array
6209 : : * elements by user-defined types
6210 : : *
6211 : : * we filter out the built-in types when we dump out the types
6212 : : *
6213 : : * same approach for undefined (shell) types and array types
6214 : : *
6215 : : * Note: as of 8.3 we can reliably detect whether a type is an
6216 : : * auto-generated array type by checking the element type's typarray.
6217 : : * (Before that the test is capable of generating false positives.) We
6218 : : * still check for name beginning with '_', though, so as to avoid the
6219 : : * cost of the subselect probe for all standard types. This would have to
6220 : : * be revisited if the backend ever allows renaming of array types.
6221 : : */
1147 drowley@postgresql.o 6222 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
6223 : : "typnamespace, typacl, "
6224 : : "acldefault('T', typowner) AS acldefault, "
6225 : : "typowner, "
6226 : : "typelem, typrelid, typarray, "
6227 : : "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
6228 : : "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
6229 : : "typtype, typisdefined, "
6230 : : "typname[0] = '_' AND typelem != 0 AND "
6231 : : "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
6232 : : "FROM pg_type");
6233 : :
5011 rhaas@postgresql.org 6234 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6235 : :
10277 bruce@momjian.us 6236 : 189 : ntups = PQntuples(res);
6237 : :
5085 6238 : 189 : tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
6239 : :
7996 tgl@sss.pgh.pa.us 6240 : 189 : i_tableoid = PQfnumber(res, "tableoid");
10277 bruce@momjian.us 6241 : 189 : i_oid = PQfnumber(res, "oid");
8571 tgl@sss.pgh.pa.us 6242 : 189 : i_typname = PQfnumber(res, "typname");
6243 : 189 : i_typnamespace = PQfnumber(res, "typnamespace");
4705 6244 : 189 : i_typacl = PQfnumber(res, "typacl");
1421 6245 : 189 : i_acldefault = PQfnumber(res, "acldefault");
1396 6246 : 189 : i_typowner = PQfnumber(res, "typowner");
8571 6247 : 189 : i_typelem = PQfnumber(res, "typelem");
6248 : 189 : i_typrelid = PQfnumber(res, "typrelid");
8474 bruce@momjian.us 6249 : 189 : i_typrelkind = PQfnumber(res, "typrelkind");
8571 tgl@sss.pgh.pa.us 6250 : 189 : i_typtype = PQfnumber(res, "typtype");
6251 : 189 : i_typisdefined = PQfnumber(res, "typisdefined");
6744 6252 : 189 : i_isarray = PQfnumber(res, "isarray");
420 dgustafsson@postgres 6253 : 189 : i_typarray = PQfnumber(res, "typarray");
6254 : :
10277 bruce@momjian.us 6255 [ + + ]: 136864 : for (i = 0; i < ntups; i++)
6256 : : {
5787 6257 : 136675 : tyinfo[i].dobj.objType = DO_TYPE;
6258 : 136675 : tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6259 : 136675 : tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6260 : 136675 : AssignDumpId(&tyinfo[i].dobj);
5085 6261 : 136675 : tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
5012 rhaas@postgresql.org 6262 : 273350 : tyinfo[i].dobj.namespace =
1889 peter@eisentraut.org 6263 : 136675 : findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
1421 tgl@sss.pgh.pa.us 6264 : 136675 : tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
6265 : 136675 : tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6266 : 136675 : tyinfo[i].dacl.privtype = 0;
6267 : 136675 : tyinfo[i].dacl.initprivs = NULL;
1518 6268 : 136675 : tyinfo[i].ftypname = NULL; /* may get filled later */
1396 6269 : 136675 : tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
5787 bruce@momjian.us 6270 : 136675 : tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
6271 : 136675 : tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
6272 : 136675 : tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
6273 : 136675 : tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
6274 : 136675 : tyinfo[i].shellType = NULL;
6275 : :
8571 tgl@sss.pgh.pa.us 6276 [ + + ]: 136675 : if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
5787 bruce@momjian.us 6277 : 136623 : tyinfo[i].isDefined = true;
6278 : : else
6279 : 52 : tyinfo[i].isDefined = false;
6280 : :
6744 tgl@sss.pgh.pa.us 6281 [ + + ]: 136675 : if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
5787 bruce@momjian.us 6282 : 65571 : tyinfo[i].isArray = true;
6283 : : else
6284 : 71104 : tyinfo[i].isArray = false;
6285 : :
420 dgustafsson@postgres 6286 : 136675 : tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
6287 : :
621 tgl@sss.pgh.pa.us 6288 [ + + ]: 136675 : if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
1772 akorotkov@postgresql 6289 : 1266 : tyinfo[i].isMultirange = true;
6290 : : else
6291 : 135409 : tyinfo[i].isMultirange = false;
6292 : :
6293 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 6294 : 136675 : selectDumpableType(&tyinfo[i], fout);
6295 : :
6296 : : /* Mark whether type has an ACL */
1421 tgl@sss.pgh.pa.us 6297 [ + + ]: 136675 : if (!PQgetisnull(res, i, i_typacl))
6298 : 205 : tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6299 : :
6300 : : /*
6301 : : * If it's a domain, fetch info about its constraints, if any
6302 : : */
5787 bruce@momjian.us 6303 : 136675 : tyinfo[i].nDomChecks = 0;
6304 : 136675 : tyinfo[i].domChecks = NULL;
98 alvherre@kurilemu.de 6305 : 136675 : tyinfo[i].notnull = NULL;
3491 sfrost@snowman.net 6306 [ + + ]: 136675 : if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6307 [ + + ]: 14965 : tyinfo[i].typtype == TYPTYPE_DOMAIN)
5012 rhaas@postgresql.org 6308 : 158 : getDomainConstraints(fout, &(tyinfo[i]));
6309 : :
6310 : : /*
6311 : : * If it's a base type, make a DumpableObject representing a shell
6312 : : * definition of the type. We will need to dump that ahead of the I/O
6313 : : * functions for the type. Similarly, range types need a shell
6314 : : * definition in case they have a canonicalize function.
6315 : : *
6316 : : * Note: the shell type doesn't have a catId. You might think it
6317 : : * should copy the base type's catId, but then it might capture the
6318 : : * pg_depend entries for the type, which we don't want.
6319 : : */
3491 sfrost@snowman.net 6320 [ + + ]: 136675 : if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6321 [ + + ]: 14965 : (tyinfo[i].typtype == TYPTYPE_BASE ||
6322 [ + + ]: 7269 : tyinfo[i].typtype == TYPTYPE_RANGE))
6323 : : {
5085 bruce@momjian.us 6324 : 7820 : stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
7179 tgl@sss.pgh.pa.us 6325 : 7820 : stinfo->dobj.objType = DO_SHELL_TYPE;
6326 : 7820 : stinfo->dobj.catId = nilCatalogId;
6327 : 7820 : AssignDumpId(&stinfo->dobj);
5085 bruce@momjian.us 6328 : 7820 : stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
5787 6329 : 7820 : stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
6330 : 7820 : stinfo->baseType = &(tyinfo[i]);
6331 : 7820 : tyinfo[i].shellType = stinfo;
6332 : :
6333 : : /*
6334 : : * Initially mark the shell type as not to be dumped. We'll only
6335 : : * dump it if the I/O or canonicalize functions need to be dumped;
6336 : : * this is taken care of while sorting dependencies.
6337 : : */
3491 sfrost@snowman.net 6338 : 7820 : stinfo->dobj.dump = DUMP_COMPONENT_NONE;
6339 : : }
6340 : : }
6341 : :
10277 bruce@momjian.us 6342 : 189 : PQclear(res);
6343 : :
8851 tgl@sss.pgh.pa.us 6344 : 189 : destroyPQExpBuffer(query);
10702 scrappy@hub.org 6345 : 189 : }
6346 : :
6347 : : /*
6348 : : * getOperators:
6349 : : * get information about all operators in the system catalogs
6350 : : */
6351 : : void
482 nathan@postgresql.or 6352 : 189 : getOperators(Archive *fout)
6353 : : {
6354 : : PGresult *res;
6355 : : int ntups;
6356 : : int i;
9329 bruce@momjian.us 6357 : 189 : PQExpBuffer query = createPQExpBuffer();
6358 : : OprInfo *oprinfo;
6359 : : int i_tableoid;
6360 : : int i_oid;
6361 : : int i_oprname;
6362 : : int i_oprnamespace;
6363 : : int i_oprowner;
6364 : : int i_oprkind;
6365 : : int i_oprleft;
6366 : : int i_oprright;
6367 : : int i_oprcode;
6368 : :
6369 : : /*
6370 : : * find all operators, including builtin operators; we filter out
6371 : : * system-defined operators at dump-out time.
6372 : : */
6373 : :
1147 drowley@postgresql.o 6374 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
6375 : : "oprnamespace, "
6376 : : "oprowner, "
6377 : : "oprkind, "
6378 : : "oprleft, "
6379 : : "oprright, "
6380 : : "oprcode::oid AS oprcode "
6381 : : "FROM pg_operator");
6382 : :
5011 rhaas@postgresql.org 6383 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6384 : :
10277 bruce@momjian.us 6385 : 189 : ntups = PQntuples(res);
6386 : :
5085 6387 : 189 : oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
6388 : :
7996 tgl@sss.pgh.pa.us 6389 : 189 : i_tableoid = PQfnumber(res, "tableoid");
10277 bruce@momjian.us 6390 : 189 : i_oid = PQfnumber(res, "oid");
8571 tgl@sss.pgh.pa.us 6391 : 189 : i_oprname = PQfnumber(res, "oprname");
6392 : 189 : i_oprnamespace = PQfnumber(res, "oprnamespace");
1396 6393 : 189 : i_oprowner = PQfnumber(res, "oprowner");
5044 peter_e@gmx.net 6394 : 189 : i_oprkind = PQfnumber(res, "oprkind");
88 noah@leadboat.com 6395 : 189 : i_oprleft = PQfnumber(res, "oprleft");
6396 : 189 : i_oprright = PQfnumber(res, "oprright");
8571 tgl@sss.pgh.pa.us 6397 : 189 : i_oprcode = PQfnumber(res, "oprcode");
6398 : :
10277 bruce@momjian.us 6399 [ + + ]: 151342 : for (i = 0; i < ntups; i++)
6400 : : {
7996 tgl@sss.pgh.pa.us 6401 : 151153 : oprinfo[i].dobj.objType = DO_OPERATOR;
6402 : 151153 : oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6403 : 151153 : oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6404 : 151153 : AssignDumpId(&oprinfo[i].dobj);
5085 bruce@momjian.us 6405 : 151153 : oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
5012 rhaas@postgresql.org 6406 : 302306 : oprinfo[i].dobj.namespace =
1889 peter@eisentraut.org 6407 : 151153 : findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
1396 tgl@sss.pgh.pa.us 6408 : 151153 : oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
5044 peter_e@gmx.net 6409 : 151153 : oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
88 noah@leadboat.com 6410 : 151153 : oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
6411 : 151153 : oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
7996 tgl@sss.pgh.pa.us 6412 : 151153 : oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
6413 : :
6414 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 6415 : 151153 : selectDumpableObject(&(oprinfo[i].dobj), fout);
6416 : : }
6417 : :
10277 bruce@momjian.us 6418 : 189 : PQclear(res);
6419 : :
8851 tgl@sss.pgh.pa.us 6420 : 189 : destroyPQExpBuffer(query);
10702 scrappy@hub.org 6421 : 189 : }
6422 : :
6423 : : /*
6424 : : * getCollations:
6425 : : * get information about all collations in the system catalogs
6426 : : */
6427 : : void
482 nathan@postgresql.or 6428 : 189 : getCollations(Archive *fout)
6429 : : {
6430 : : PGresult *res;
6431 : : int ntups;
6432 : : int i;
6433 : : PQExpBuffer query;
6434 : : CollInfo *collinfo;
6435 : : int i_tableoid;
6436 : : int i_oid;
6437 : : int i_collname;
6438 : : int i_collnamespace;
6439 : : int i_collowner;
6440 : : int i_collencoding;
6441 : :
4976 peter_e@gmx.net 6442 : 189 : query = createPQExpBuffer();
6443 : :
6444 : : /*
6445 : : * find all collations, including builtin collations; we filter out
6446 : : * system-defined collations at dump-out time.
6447 : : */
6448 : :
1147 drowley@postgresql.o 6449 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
6450 : : "collnamespace, "
6451 : : "collowner, "
6452 : : "collencoding "
6453 : : "FROM pg_collation");
6454 : :
5011 rhaas@postgresql.org 6455 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6456 : :
5371 peter_e@gmx.net 6457 : 189 : ntups = PQntuples(res);
6458 : :
5085 bruce@momjian.us 6459 : 189 : collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
6460 : :
5371 peter_e@gmx.net 6461 : 189 : i_tableoid = PQfnumber(res, "tableoid");
6462 : 189 : i_oid = PQfnumber(res, "oid");
6463 : 189 : i_collname = PQfnumber(res, "collname");
6464 : 189 : i_collnamespace = PQfnumber(res, "collnamespace");
1396 tgl@sss.pgh.pa.us 6465 : 189 : i_collowner = PQfnumber(res, "collowner");
88 noah@leadboat.com 6466 : 189 : i_collencoding = PQfnumber(res, "collencoding");
6467 : :
5371 peter_e@gmx.net 6468 [ + + ]: 287202 : for (i = 0; i < ntups; i++)
6469 : : {
6470 : 287013 : collinfo[i].dobj.objType = DO_COLLATION;
6471 : 287013 : collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6472 : 287013 : collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6473 : 287013 : AssignDumpId(&collinfo[i].dobj);
5085 bruce@momjian.us 6474 : 287013 : collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5012 rhaas@postgresql.org 6475 : 574026 : collinfo[i].dobj.namespace =
1889 peter@eisentraut.org 6476 : 287013 : findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
1396 tgl@sss.pgh.pa.us 6477 : 287013 : collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
88 noah@leadboat.com 6478 : 287013 : collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
6479 : :
6480 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 6481 : 287013 : selectDumpableObject(&(collinfo[i].dobj), fout);
6482 : : }
6483 : :
5371 peter_e@gmx.net 6484 : 189 : PQclear(res);
6485 : :
6486 : 189 : destroyPQExpBuffer(query);
6487 : 189 : }
6488 : :
6489 : : /*
6490 : : * getConversions:
6491 : : * get information about all conversions in the system catalogs
6492 : : */
6493 : : void
482 nathan@postgresql.or 6494 : 189 : getConversions(Archive *fout)
6495 : : {
6496 : : PGresult *res;
6497 : : int ntups;
6498 : : int i;
6499 : : PQExpBuffer query;
6500 : : ConvInfo *convinfo;
6501 : : int i_tableoid;
6502 : : int i_oid;
6503 : : int i_conname;
6504 : : int i_connamespace;
6505 : : int i_conowner;
6506 : :
4292 sfrost@snowman.net 6507 : 189 : query = createPQExpBuffer();
6508 : :
6509 : : /*
6510 : : * find all conversions, including builtin conversions; we filter out
6511 : : * system-defined conversions at dump-out time.
6512 : : */
6513 : :
1147 drowley@postgresql.o 6514 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
6515 : : "connamespace, "
6516 : : "conowner "
6517 : : "FROM pg_conversion");
6518 : :
5011 rhaas@postgresql.org 6519 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6520 : :
8011 tgl@sss.pgh.pa.us 6521 : 189 : ntups = PQntuples(res);
6522 : :
5085 bruce@momjian.us 6523 : 189 : convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
6524 : :
7996 tgl@sss.pgh.pa.us 6525 : 189 : i_tableoid = PQfnumber(res, "tableoid");
8011 6526 : 189 : i_oid = PQfnumber(res, "oid");
6527 : 189 : i_conname = PQfnumber(res, "conname");
6528 : 189 : i_connamespace = PQfnumber(res, "connamespace");
1396 6529 : 189 : i_conowner = PQfnumber(res, "conowner");
6530 : :
8011 6531 [ + + ]: 24426 : for (i = 0; i < ntups; i++)
6532 : : {
7996 6533 : 24237 : convinfo[i].dobj.objType = DO_CONVERSION;
6534 : 24237 : convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6535 : 24237 : convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6536 : 24237 : AssignDumpId(&convinfo[i].dobj);
5085 bruce@momjian.us 6537 : 24237 : convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5012 rhaas@postgresql.org 6538 : 48474 : convinfo[i].dobj.namespace =
1889 peter@eisentraut.org 6539 : 24237 : findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
1396 tgl@sss.pgh.pa.us 6540 : 24237 : convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
6541 : :
6542 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 6543 : 24237 : selectDumpableObject(&(convinfo[i].dobj), fout);
6544 : : }
6545 : :
8011 tgl@sss.pgh.pa.us 6546 : 189 : PQclear(res);
6547 : :
6548 : 189 : destroyPQExpBuffer(query);
6549 : 189 : }
6550 : :
6551 : : /*
6552 : : * getAccessMethods:
6553 : : * get information about all user-defined access methods
6554 : : */
6555 : : void
482 nathan@postgresql.or 6556 : 189 : getAccessMethods(Archive *fout)
6557 : : {
6558 : : PGresult *res;
6559 : : int ntups;
6560 : : int i;
6561 : : PQExpBuffer query;
6562 : : AccessMethodInfo *aminfo;
6563 : : int i_tableoid;
6564 : : int i_oid;
6565 : : int i_amname;
6566 : : int i_amhandler;
6567 : : int i_amtype;
6568 : :
3505 alvherre@alvh.no-ip. 6569 : 189 : query = createPQExpBuffer();
6570 : :
6571 : : /*
6572 : : * Select all access methods from pg_am table. v9.6 introduced CREATE
6573 : : * ACCESS METHOD, so earlier versions usually have only built-in access
6574 : : * methods. v9.6 also changed the access method API, replacing dozens of
6575 : : * pg_am columns with amhandler. Even if a user created an access method
6576 : : * by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am
6577 : : * columns to a v9.6+ CREATE ACCESS METHOD. Hence, before v9.6, read
6578 : : * pg_am just to facilitate findAccessMethodByOid() providing the
6579 : : * OID-to-name mapping.
6580 : : */
88 noah@leadboat.com 6581 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
6582 [ + - ]: 189 : if (fout->remoteVersion >= 90600)
6583 : 189 : appendPQExpBufferStr(query,
6584 : : "amtype, "
6585 : : "amhandler::pg_catalog.regproc AS amhandler ");
6586 : : else
88 noah@leadboat.com 6587 :UBC 0 : appendPQExpBufferStr(query,
6588 : : "'i'::pg_catalog.\"char\" AS amtype, "
6589 : : "'-'::pg_catalog.regproc AS amhandler ");
88 noah@leadboat.com 6590 :CBC 189 : appendPQExpBufferStr(query, "FROM pg_am");
6591 : :
3505 alvherre@alvh.no-ip. 6592 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6593 : :
6594 : 189 : ntups = PQntuples(res);
6595 : :
6596 : 189 : aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
6597 : :
6598 : 189 : i_tableoid = PQfnumber(res, "tableoid");
6599 : 189 : i_oid = PQfnumber(res, "oid");
6600 : 189 : i_amname = PQfnumber(res, "amname");
6601 : 189 : i_amhandler = PQfnumber(res, "amhandler");
6602 : 189 : i_amtype = PQfnumber(res, "amtype");
6603 : :
6604 [ + + ]: 1634 : for (i = 0; i < ntups; i++)
6605 : : {
6606 : 1445 : aminfo[i].dobj.objType = DO_ACCESS_METHOD;
6607 : 1445 : aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6608 : 1445 : aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6609 : 1445 : AssignDumpId(&aminfo[i].dobj);
6610 : 1445 : aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
6611 : 1445 : aminfo[i].dobj.namespace = NULL;
6612 : 1445 : aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
6613 : 1445 : aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
6614 : :
6615 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 6616 : 1445 : selectDumpableAccessMethod(&(aminfo[i]), fout);
6617 : : }
6618 : :
3505 alvherre@alvh.no-ip. 6619 : 189 : PQclear(res);
6620 : :
6621 : 189 : destroyPQExpBuffer(query);
6622 : 189 : }
6623 : :
6624 : :
6625 : : /*
6626 : : * getOpclasses:
6627 : : * get information about all opclasses in the system catalogs
6628 : : */
6629 : : void
482 nathan@postgresql.or 6630 : 189 : getOpclasses(Archive *fout)
6631 : : {
6632 : : PGresult *res;
6633 : : int ntups;
6634 : : int i;
8490 tgl@sss.pgh.pa.us 6635 : 189 : PQExpBuffer query = createPQExpBuffer();
6636 : : OpclassInfo *opcinfo;
6637 : : int i_tableoid;
6638 : : int i_oid;
6639 : : int i_opcmethod;
6640 : : int i_opcname;
6641 : : int i_opcnamespace;
6642 : : int i_opcowner;
6643 : :
6644 : : /*
6645 : : * find all opclasses, including builtin opclasses; we filter out
6646 : : * system-defined opclasses at dump-out time.
6647 : : */
6648 : :
88 noah@leadboat.com 6649 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
6650 : : "opcnamespace, "
6651 : : "opcowner "
6652 : : "FROM pg_opclass");
6653 : :
5011 rhaas@postgresql.org 6654 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6655 : :
8490 tgl@sss.pgh.pa.us 6656 : 189 : ntups = PQntuples(res);
6657 : :
5085 bruce@momjian.us 6658 : 189 : opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
6659 : :
7996 tgl@sss.pgh.pa.us 6660 : 189 : i_tableoid = PQfnumber(res, "tableoid");
8490 6661 : 189 : i_oid = PQfnumber(res, "oid");
88 noah@leadboat.com 6662 : 189 : i_opcmethod = PQfnumber(res, "opcmethod");
8490 tgl@sss.pgh.pa.us 6663 : 189 : i_opcname = PQfnumber(res, "opcname");
6664 : 189 : i_opcnamespace = PQfnumber(res, "opcnamespace");
1396 6665 : 189 : i_opcowner = PQfnumber(res, "opcowner");
6666 : :
8490 6667 [ + + ]: 33798 : for (i = 0; i < ntups; i++)
6668 : : {
7996 6669 : 33609 : opcinfo[i].dobj.objType = DO_OPCLASS;
6670 : 33609 : opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6671 : 33609 : opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6672 : 33609 : AssignDumpId(&opcinfo[i].dobj);
5085 bruce@momjian.us 6673 : 33609 : opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5012 rhaas@postgresql.org 6674 : 67218 : opcinfo[i].dobj.namespace =
1889 peter@eisentraut.org 6675 : 33609 : findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
88 noah@leadboat.com 6676 : 33609 : opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
1396 tgl@sss.pgh.pa.us 6677 : 33609 : opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
6678 : :
6679 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 6680 : 33609 : selectDumpableObject(&(opcinfo[i].dobj), fout);
6681 : : }
6682 : :
8490 tgl@sss.pgh.pa.us 6683 : 189 : PQclear(res);
6684 : :
6685 : 189 : destroyPQExpBuffer(query);
6686 : 189 : }
6687 : :
6688 : : /*
6689 : : * getOpfamilies:
6690 : : * get information about all opfamilies in the system catalogs
6691 : : */
6692 : : void
482 nathan@postgresql.or 6693 : 189 : getOpfamilies(Archive *fout)
6694 : : {
6695 : : PGresult *res;
6696 : : int ntups;
6697 : : int i;
6698 : : PQExpBuffer query;
6699 : : OpfamilyInfo *opfinfo;
6700 : : int i_tableoid;
6701 : : int i_oid;
6702 : : int i_opfmethod;
6703 : : int i_opfname;
6704 : : int i_opfnamespace;
6705 : : int i_opfowner;
6706 : :
6852 tgl@sss.pgh.pa.us 6707 : 189 : query = createPQExpBuffer();
6708 : :
6709 : : /*
6710 : : * find all opfamilies, including builtin opfamilies; we filter out
6711 : : * system-defined opfamilies at dump-out time.
6712 : : */
6713 : :
88 noah@leadboat.com 6714 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
6715 : : "opfnamespace, "
6716 : : "opfowner "
6717 : : "FROM pg_opfamily");
6718 : :
5011 rhaas@postgresql.org 6719 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6720 : :
6852 tgl@sss.pgh.pa.us 6721 : 189 : ntups = PQntuples(res);
6722 : :
5085 bruce@momjian.us 6723 : 189 : opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
6724 : :
6852 tgl@sss.pgh.pa.us 6725 : 189 : i_tableoid = PQfnumber(res, "tableoid");
6726 : 189 : i_oid = PQfnumber(res, "oid");
6727 : 189 : i_opfname = PQfnumber(res, "opfname");
88 noah@leadboat.com 6728 : 189 : i_opfmethod = PQfnumber(res, "opfmethod");
6852 tgl@sss.pgh.pa.us 6729 : 189 : i_opfnamespace = PQfnumber(res, "opfnamespace");
1396 6730 : 189 : i_opfowner = PQfnumber(res, "opfowner");
6731 : :
6852 6732 [ + + ]: 27922 : for (i = 0; i < ntups; i++)
6733 : : {
6734 : 27733 : opfinfo[i].dobj.objType = DO_OPFAMILY;
6735 : 27733 : opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6736 : 27733 : opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6737 : 27733 : AssignDumpId(&opfinfo[i].dobj);
5085 bruce@momjian.us 6738 : 27733 : opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5012 rhaas@postgresql.org 6739 : 55466 : opfinfo[i].dobj.namespace =
1889 peter@eisentraut.org 6740 : 27733 : findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
88 noah@leadboat.com 6741 : 27733 : opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
1396 tgl@sss.pgh.pa.us 6742 : 27733 : opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
6743 : :
6744 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 6745 : 27733 : selectDumpableObject(&(opfinfo[i].dobj), fout);
6746 : : }
6747 : :
6852 tgl@sss.pgh.pa.us 6748 : 189 : PQclear(res);
6749 : :
6750 : 189 : destroyPQExpBuffer(query);
6751 : 189 : }
6752 : :
6753 : : /*
6754 : : * getAggregates:
6755 : : * get information about all user-defined aggregates in the system catalogs
6756 : : */
6757 : : void
482 nathan@postgresql.or 6758 : 189 : getAggregates(Archive *fout)
6759 : : {
3575 tgl@sss.pgh.pa.us 6760 : 189 : DumpOptions *dopt = fout->dopt;
6761 : : PGresult *res;
6762 : : int ntups;
6763 : : int i;
9329 bruce@momjian.us 6764 : 189 : PQExpBuffer query = createPQExpBuffer();
6765 : : AggInfo *agginfo;
6766 : : int i_tableoid;
6767 : : int i_oid;
6768 : : int i_aggname;
6769 : : int i_aggnamespace;
6770 : : int i_pronargs;
6771 : : int i_proargtypes;
6772 : : int i_proowner;
6773 : : int i_aggacl;
6774 : : int i_acldefault;
6775 : :
6776 : : /*
6777 : : * Find all interesting aggregates. See comment in getFuncs() for the
6778 : : * rationale behind the filtering logic.
6779 : : */
3491 sfrost@snowman.net 6780 [ + - ]: 189 : if (fout->remoteVersion >= 90600)
6781 : : {
6782 : : const char *agg_check;
6783 : :
2796 peter_e@gmx.net 6784 : 378 : agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
6785 [ + - ]: 189 : : "p.proisagg");
6786 : :
3491 sfrost@snowman.net 6787 : 189 : appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
6788 : : "p.proname AS aggname, "
6789 : : "p.pronamespace AS aggnamespace, "
6790 : : "p.pronargs, p.proargtypes, "
6791 : : "p.proowner, "
6792 : : "p.proacl AS aggacl, "
6793 : : "acldefault('f', p.proowner) AS acldefault "
6794 : : "FROM pg_proc p "
6795 : : "LEFT JOIN pg_init_privs pip ON "
6796 : : "(p.oid = pip.objoid "
6797 : : "AND pip.classoid = 'pg_proc'::regclass "
6798 : : "AND pip.objsubid = 0) "
6799 : : "WHERE %s AND ("
6800 : : "p.pronamespace != "
6801 : : "(SELECT oid FROM pg_namespace "
6802 : : "WHERE nspname = 'pg_catalog') OR "
6803 : : "p.proacl IS DISTINCT FROM pip.initprivs",
6804 : : agg_check);
6805 [ + + ]: 189 : if (dopt->binary_upgrade)
6806 : 36 : appendPQExpBufferStr(query,
6807 : : " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6808 : : "classid = 'pg_proc'::regclass AND "
6809 : : "objid = p.oid AND "
6810 : : "refclassid = 'pg_extension'::regclass AND "
6811 : : "deptype = 'e')");
6812 : 189 : appendPQExpBufferChar(query, ')');
6813 : : }
6814 : : else
6815 : : {
1147 drowley@postgresql.o 6816 :UBC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
6817 : : "pronamespace AS aggnamespace, "
6818 : : "pronargs, proargtypes, "
6819 : : "proowner, "
6820 : : "proacl AS aggacl, "
6821 : : "acldefault('f', proowner) AS acldefault "
6822 : : "FROM pg_proc p "
6823 : : "WHERE proisagg AND ("
6824 : : "pronamespace != "
6825 : : "(SELECT oid FROM pg_namespace "
6826 : : "WHERE nspname = 'pg_catalog')");
1421 tgl@sss.pgh.pa.us 6827 [ # # ]: 0 : if (dopt->binary_upgrade)
6828 : 0 : appendPQExpBufferStr(query,
6829 : : " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6830 : : "classid = 'pg_proc'::regclass AND "
6831 : : "objid = p.oid AND "
6832 : : "refclassid = 'pg_extension'::regclass AND "
6833 : : "deptype = 'e')");
6834 : 0 : appendPQExpBufferChar(query, ')');
6835 : : }
6836 : :
5011 rhaas@postgresql.org 6837 :CBC 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6838 : :
10277 bruce@momjian.us 6839 : 189 : ntups = PQntuples(res);
6840 : :
5085 6841 : 189 : agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
6842 : :
7996 tgl@sss.pgh.pa.us 6843 : 189 : i_tableoid = PQfnumber(res, "tableoid");
8571 6844 : 189 : i_oid = PQfnumber(res, "oid");
6845 : 189 : i_aggname = PQfnumber(res, "aggname");
6846 : 189 : i_aggnamespace = PQfnumber(res, "aggnamespace");
7032 6847 : 189 : i_pronargs = PQfnumber(res, "pronargs");
6848 : 189 : i_proargtypes = PQfnumber(res, "proargtypes");
1396 6849 : 189 : i_proowner = PQfnumber(res, "proowner");
8562 peter_e@gmx.net 6850 : 189 : i_aggacl = PQfnumber(res, "aggacl");
1421 tgl@sss.pgh.pa.us 6851 : 189 : i_acldefault = PQfnumber(res, "acldefault");
6852 : :
10277 bruce@momjian.us 6853 [ + + ]: 588 : for (i = 0; i < ntups; i++)
6854 : : {
7996 tgl@sss.pgh.pa.us 6855 : 399 : agginfo[i].aggfn.dobj.objType = DO_AGG;
6856 : 399 : agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6857 : 399 : agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6858 : 399 : AssignDumpId(&agginfo[i].aggfn.dobj);
5085 bruce@momjian.us 6859 : 399 : agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5012 rhaas@postgresql.org 6860 : 798 : agginfo[i].aggfn.dobj.namespace =
1889 peter@eisentraut.org 6861 : 399 : findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
1421 tgl@sss.pgh.pa.us 6862 : 399 : agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
6863 : 399 : agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6864 : 399 : agginfo[i].aggfn.dacl.privtype = 0;
6865 : 399 : agginfo[i].aggfn.dacl.initprivs = NULL;
1396 6866 : 399 : agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
3050 6867 : 399 : agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
6868 : 399 : agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
7032 6869 : 399 : agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
6870 [ + + ]: 399 : if (agginfo[i].aggfn.nargs == 0)
6871 : 56 : agginfo[i].aggfn.argtypes = NULL;
6872 : : else
6873 : : {
5085 bruce@momjian.us 6874 : 343 : agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
3302 tgl@sss.pgh.pa.us 6875 : 343 : parseOidArray(PQgetvalue(res, i, i_proargtypes),
6876 : 343 : agginfo[i].aggfn.argtypes,
6877 : 343 : agginfo[i].aggfn.nargs);
6878 : : }
876 6879 : 399 : agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
6880 : :
6881 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 6882 : 399 : selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
6883 : :
6884 : : /* Mark whether aggregate has an ACL */
1421 tgl@sss.pgh.pa.us 6885 [ + + ]: 399 : if (!PQgetisnull(res, i, i_aggacl))
6886 : 25 : agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
6887 : : }
6888 : :
8571 6889 : 189 : PQclear(res);
6890 : :
6891 : 189 : destroyPQExpBuffer(query);
6892 : 189 : }
6893 : :
6894 : : /*
6895 : : * getFuncs:
6896 : : * get information about all user-defined functions in the system catalogs
6897 : : */
6898 : : void
482 nathan@postgresql.or 6899 : 189 : getFuncs(Archive *fout)
6900 : : {
3575 tgl@sss.pgh.pa.us 6901 : 189 : DumpOptions *dopt = fout->dopt;
6902 : : PGresult *res;
6903 : : int ntups;
6904 : : int i;
8571 6905 : 189 : PQExpBuffer query = createPQExpBuffer();
6906 : : FuncInfo *finfo;
6907 : : int i_tableoid;
6908 : : int i_oid;
6909 : : int i_proname;
6910 : : int i_pronamespace;
6911 : : int i_proowner;
6912 : : int i_prolang;
6913 : : int i_pronargs;
6914 : : int i_proargtypes;
6915 : : int i_prorettype;
6916 : : int i_proacl;
6917 : : int i_acldefault;
6918 : :
6919 : : /*
6920 : : * Find all interesting functions. This is a bit complicated:
6921 : : *
6922 : : * 1. Always exclude aggregates; those are handled elsewhere.
6923 : : *
6924 : : * 2. Always exclude functions that are internally dependent on something
6925 : : * else, since presumably those will be created as a result of creating
6926 : : * the something else. This currently acts only to suppress constructor
6927 : : * functions for range types. Note this is OK only because the
6928 : : * constructors don't have any dependencies the range type doesn't have;
6929 : : * otherwise we might not get creation ordering correct.
6930 : : *
6931 : : * 3. Otherwise, we normally exclude functions in pg_catalog. However, if
6932 : : * they're members of extensions and we are in binary-upgrade mode then
6933 : : * include them, since we want to dump extension members individually in
6934 : : * that mode. Also, if they are used by casts or transforms then we need
6935 : : * to gather the information about them, though they won't be dumped if
6936 : : * they are built-in. Also, in 9.6 and up, include functions in
6937 : : * pg_catalog if they have an ACL different from what's shown in
6938 : : * pg_init_privs (so we have to join to pg_init_privs; annoying).
6939 : : */
3491 sfrost@snowman.net 6940 [ + - ]: 189 : if (fout->remoteVersion >= 90600)
6941 : : {
6942 : : const char *not_agg_check;
6943 : :
2796 peter_e@gmx.net 6944 : 378 : not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
6945 [ + - ]: 189 : : "NOT p.proisagg");
6946 : :
3491 sfrost@snowman.net 6947 : 189 : appendPQExpBuffer(query,
6948 : : "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
6949 : : "p.pronargs, p.proargtypes, p.prorettype, "
6950 : : "p.proacl, "
6951 : : "acldefault('f', p.proowner) AS acldefault, "
6952 : : "p.pronamespace, "
6953 : : "p.proowner "
6954 : : "FROM pg_proc p "
6955 : : "LEFT JOIN pg_init_privs pip ON "
6956 : : "(p.oid = pip.objoid "
6957 : : "AND pip.classoid = 'pg_proc'::regclass "
6958 : : "AND pip.objsubid = 0) "
6959 : : "WHERE %s"
6960 : : "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6961 : : "WHERE classid = 'pg_proc'::regclass AND "
6962 : : "objid = p.oid AND deptype = 'i')"
6963 : : "\n AND ("
6964 : : "\n pronamespace != "
6965 : : "(SELECT oid FROM pg_namespace "
6966 : : "WHERE nspname = 'pg_catalog')"
6967 : : "\n OR EXISTS (SELECT 1 FROM pg_cast"
6968 : : "\n WHERE pg_cast.oid > %u "
6969 : : "\n AND p.oid = pg_cast.castfunc)"
6970 : : "\n OR EXISTS (SELECT 1 FROM pg_transform"
6971 : : "\n WHERE pg_transform.oid > %u AND "
6972 : : "\n (p.oid = pg_transform.trffromsql"
6973 : : "\n OR p.oid = pg_transform.trftosql))",
6974 : : not_agg_check,
6975 : : g_last_builtin_oid,
6976 : : g_last_builtin_oid);
6977 [ + + ]: 189 : if (dopt->binary_upgrade)
6978 : 36 : appendPQExpBufferStr(query,
6979 : : "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6980 : : "classid = 'pg_proc'::regclass AND "
6981 : : "objid = p.oid AND "
6982 : : "refclassid = 'pg_extension'::regclass AND "
6983 : : "deptype = 'e')");
3321 tgl@sss.pgh.pa.us 6984 : 189 : appendPQExpBufferStr(query,
6985 : : "\n OR p.proacl IS DISTINCT FROM pip.initprivs");
3491 sfrost@snowman.net 6986 : 189 : appendPQExpBufferChar(query, ')');
6987 : : }
6988 : : else
6989 : : {
8571 tgl@sss.pgh.pa.us 6990 :UBC 0 : appendPQExpBuffer(query,
6991 : : "SELECT tableoid, oid, proname, prolang, "
6992 : : "pronargs, proargtypes, prorettype, proacl, "
6993 : : "acldefault('f', proowner) AS acldefault, "
6994 : : "pronamespace, "
6995 : : "proowner "
6996 : : "FROM pg_proc p "
6997 : : "WHERE NOT proisagg"
6998 : : "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6999 : : "WHERE classid = 'pg_proc'::regclass AND "
7000 : : "objid = p.oid AND deptype = 'i')"
7001 : : "\n AND ("
7002 : : "\n pronamespace != "
7003 : : "(SELECT oid FROM pg_namespace "
7004 : : "WHERE nspname = 'pg_catalog')"
7005 : : "\n OR EXISTS (SELECT 1 FROM pg_cast"
7006 : : "\n WHERE pg_cast.oid > '%u'::oid"
7007 : : "\n AND p.oid = pg_cast.castfunc)",
7008 : : g_last_builtin_oid);
7009 : :
3232 sfrost@snowman.net 7010 [ # # ]: 0 : if (fout->remoteVersion >= 90500)
7011 : 0 : appendPQExpBuffer(query,
7012 : : "\n OR EXISTS (SELECT 1 FROM pg_transform"
7013 : : "\n WHERE pg_transform.oid > '%u'::oid"
7014 : : "\n AND (p.oid = pg_transform.trffromsql"
7015 : : "\n OR p.oid = pg_transform.trftosql))",
7016 : : g_last_builtin_oid);
7017 : :
1413 tgl@sss.pgh.pa.us 7018 [ # # ]: 0 : if (dopt->binary_upgrade)
4361 heikki.linnakangas@i 7019 : 0 : appendPQExpBufferStr(query,
7020 : : "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
7021 : : "classid = 'pg_proc'::regclass AND "
7022 : : "objid = p.oid AND "
7023 : : "refclassid = 'pg_extension'::regclass AND "
7024 : : "deptype = 'e')");
7025 : 0 : appendPQExpBufferChar(query, ')');
7026 : : }
7027 : :
5011 rhaas@postgresql.org 7028 :CBC 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7029 : :
8571 tgl@sss.pgh.pa.us 7030 : 189 : ntups = PQntuples(res);
7031 : :
4773 7032 : 189 : finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
7033 : :
7996 7034 : 189 : i_tableoid = PQfnumber(res, "tableoid");
8571 7035 : 189 : i_oid = PQfnumber(res, "oid");
7036 : 189 : i_proname = PQfnumber(res, "proname");
7037 : 189 : i_pronamespace = PQfnumber(res, "pronamespace");
1396 7038 : 189 : i_proowner = PQfnumber(res, "proowner");
8571 7039 : 189 : i_prolang = PQfnumber(res, "prolang");
7040 : 189 : i_pronargs = PQfnumber(res, "pronargs");
7041 : 189 : i_proargtypes = PQfnumber(res, "proargtypes");
7042 : 189 : i_prorettype = PQfnumber(res, "prorettype");
8562 peter_e@gmx.net 7043 : 189 : i_proacl = PQfnumber(res, "proacl");
1421 tgl@sss.pgh.pa.us 7044 : 189 : i_acldefault = PQfnumber(res, "acldefault");
7045 : :
8571 7046 [ + + ]: 4970 : for (i = 0; i < ntups; i++)
7047 : : {
7996 7048 : 4781 : finfo[i].dobj.objType = DO_FUNC;
7049 : 4781 : finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7050 : 4781 : finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7051 : 4781 : AssignDumpId(&finfo[i].dobj);
5085 bruce@momjian.us 7052 : 4781 : finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
7317 7053 : 9562 : finfo[i].dobj.namespace =
1889 peter@eisentraut.org 7054 : 4781 : findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
1421 tgl@sss.pgh.pa.us 7055 : 4781 : finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
7056 : 4781 : finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
7057 : 4781 : finfo[i].dacl.privtype = 0;
7058 : 4781 : finfo[i].dacl.initprivs = NULL;
1396 7059 : 4781 : finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
8571 7060 : 4781 : finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
7996 7061 : 4781 : finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
8571 7062 : 4781 : finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
7063 [ + + ]: 4781 : if (finfo[i].nargs == 0)
7064 : 1063 : finfo[i].argtypes = NULL;
7065 : : else
7066 : : {
5085 bruce@momjian.us 7067 : 3718 : finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
7996 tgl@sss.pgh.pa.us 7068 : 3718 : parseOidArray(PQgetvalue(res, i, i_proargtypes),
7069 : 3718 : finfo[i].argtypes, finfo[i].nargs);
7070 : : }
876 7071 : 4781 : finfo[i].postponed_def = false; /* might get set during sort */
7072 : :
7073 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 7074 : 4781 : selectDumpableObject(&(finfo[i].dobj), fout);
7075 : :
7076 : : /* Mark whether function has an ACL */
1421 tgl@sss.pgh.pa.us 7077 [ + + ]: 4781 : if (!PQgetisnull(res, i, i_proacl))
7078 : 140 : finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
7079 : : }
7080 : :
8571 7081 : 189 : PQclear(res);
7082 : :
7083 : 189 : destroyPQExpBuffer(query);
7084 : 189 : }
7085 : :
7086 : : /*
7087 : : * getRelationStatistics
7088 : : * register the statistics object as a dependent of the relation.
7089 : : *
7090 : : * reltuples is passed as a string to avoid complexities in converting from/to
7091 : : * floating point.
7092 : : */
7093 : : static RelStatsInfo *
244 jdavis@postgresql.or 7094 : 9554 : getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
7095 : : char *reltuples, int32 relallvisible,
7096 : : int32 relallfrozen, char relkind,
7097 : : char **indAttNames, int nindAttNames)
7098 : : {
249 7099 [ + + ]: 9554 : if (!fout->dopt->dumpStatistics)
7100 : 6022 : return NULL;
7101 : :
7102 [ + + + + ]: 3532 : if ((relkind == RELKIND_RELATION) ||
7103 [ + + ]: 1481 : (relkind == RELKIND_PARTITIONED_TABLE) ||
7104 [ + + ]: 887 : (relkind == RELKIND_INDEX) ||
7105 [ + + ]: 575 : (relkind == RELKIND_PARTITIONED_INDEX) ||
131 fujii@postgresql.org 7106 [ + + ]: 269 : (relkind == RELKIND_MATVIEW ||
7107 : : relkind == RELKIND_FOREIGN_TABLE))
7108 : : {
249 jdavis@postgresql.or 7109 : 3295 : RelStatsInfo *info = pg_malloc0(sizeof(RelStatsInfo));
7110 : 3295 : DumpableObject *dobj = &info->dobj;
7111 : :
7112 : 3295 : dobj->objType = DO_REL_STATS;
7113 : 3295 : dobj->catId.tableoid = 0;
7114 : 3295 : dobj->catId.oid = 0;
7115 : 3295 : AssignDumpId(dobj);
7116 : 3295 : dobj->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
7117 : 3295 : dobj->dependencies[0] = rel->dumpId;
7118 : 3295 : dobj->nDeps = 1;
7119 : 3295 : dobj->allocDeps = 1;
7120 : 3295 : dobj->components |= DUMP_COMPONENT_STATISTICS;
7121 : 3295 : dobj->name = pg_strdup(rel->name);
7122 : 3295 : dobj->namespace = rel->namespace;
244 7123 : 3295 : info->relpages = relpages;
233 7124 : 3295 : info->reltuples = pstrdup(reltuples);
244 7125 : 3295 : info->relallvisible = relallvisible;
211 7126 : 3295 : info->relallfrozen = relallfrozen;
249 7127 : 3295 : info->relkind = relkind;
243 tgl@sss.pgh.pa.us 7128 : 3295 : info->indAttNames = indAttNames;
7129 : 3295 : info->nindAttNames = nindAttNames;
7130 : :
7131 : : /*
7132 : : * Ordinarily, stats go in SECTION_DATA for tables and
7133 : : * SECTION_POST_DATA for indexes.
7134 : : *
7135 : : * However, the section may be updated later for materialized view
7136 : : * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
7137 : : * the stats, so the stats must be restored after the data. Also, the
7138 : : * materialized view definition may be postponed to SECTION_POST_DATA
7139 : : * (see repairMatViewBoundaryMultiLoop()).
7140 : : */
213 jdavis@postgresql.or 7141 [ + + - ]: 3295 : switch (info->relkind)
7142 : : {
7143 : 2389 : case RELKIND_RELATION:
7144 : : case RELKIND_PARTITIONED_TABLE:
7145 : : case RELKIND_MATVIEW:
7146 : : case RELKIND_FOREIGN_TABLE:
7147 : 2389 : info->section = SECTION_DATA;
7148 : 2389 : break;
7149 : 906 : case RELKIND_INDEX:
7150 : : case RELKIND_PARTITIONED_INDEX:
7151 : 906 : info->section = SECTION_POST_DATA;
7152 : 906 : break;
213 jdavis@postgresql.or 7153 :UBC 0 : default:
133 peter@eisentraut.org 7154 : 0 : pg_fatal("cannot dump statistics for relation kind \"%c\"",
7155 : : info->relkind);
7156 : : }
7157 : :
249 jdavis@postgresql.or 7158 :CBC 3295 : return info;
7159 : : }
7160 : 237 : return NULL;
7161 : : }
7162 : :
7163 : : /*
7164 : : * getTables
7165 : : * read all the tables (no indexes) in the system catalogs,
7166 : : * and return them as an array of TableInfo structures
7167 : : *
7168 : : * *numTables is set to the number of tables read in
7169 : : */
7170 : : TableInfo *
3575 tgl@sss.pgh.pa.us 7171 : 190 : getTables(Archive *fout, int *numTables)
7172 : : {
7173 : 190 : DumpOptions *dopt = fout->dopt;
7174 : : PGresult *res;
7175 : : int ntups;
7176 : : int i;
8571 7177 : 190 : PQExpBuffer query = createPQExpBuffer();
7178 : : TableInfo *tblinfo;
7179 : : int i_reltableoid;
7180 : : int i_reloid;
7181 : : int i_relname;
7182 : : int i_relnamespace;
7183 : : int i_relkind;
7184 : : int i_reltype;
7185 : : int i_relowner;
7186 : : int i_relchecks;
7187 : : int i_relhasindex;
7188 : : int i_relhasrules;
7189 : : int i_relpages;
7190 : : int i_reltuples;
7191 : : int i_relallvisible;
7192 : : int i_relallfrozen;
7193 : : int i_toastpages;
7194 : : int i_owning_tab;
7195 : : int i_owning_col;
7196 : : int i_reltablespace;
7197 : : int i_relhasoids;
7198 : : int i_relhastriggers;
7199 : : int i_relpersistence;
7200 : : int i_relispopulated;
7201 : : int i_relreplident;
7202 : : int i_relrowsec;
7203 : : int i_relforcerowsec;
7204 : : int i_relfrozenxid;
7205 : : int i_toastfrozenxid;
7206 : : int i_toastoid;
7207 : : int i_relminmxid;
7208 : : int i_toastminmxid;
7209 : : int i_reloptions;
7210 : : int i_checkoption;
7211 : : int i_toastreloptions;
7212 : : int i_reloftype;
7213 : : int i_foreignserver;
7214 : : int i_amname;
7215 : : int i_is_identity_sequence;
7216 : : int i_relacl;
7217 : : int i_acldefault;
7218 : : int i_ispartition;
7219 : :
7220 : : /*
7221 : : * Find all the tables and table-like objects.
7222 : : *
7223 : : * We must fetch all tables in this phase because otherwise we cannot
7224 : : * correctly identify inherited columns, owned sequences, etc.
7225 : : *
7226 : : * We include system catalogs, so that we can work if a user table is
7227 : : * defined to inherit from a system catalog (pretty weird, but...)
7228 : : *
7229 : : * Note: in this phase we should collect only a minimal amount of
7230 : : * information about each table, basically just enough to decide if it is
7231 : : * interesting. In particular, since we do not yet have lock on any user
7232 : : * table, we MUST NOT invoke any server-side data collection functions
7233 : : * (for instance, pg_get_partkeydef()). Those are likely to fail or give
7234 : : * wrong answers if any concurrent DDL is happening.
7235 : : */
7236 : :
1147 drowley@postgresql.o 7237 : 190 : appendPQExpBufferStr(query,
7238 : : "SELECT c.tableoid, c.oid, c.relname, "
7239 : : "c.relnamespace, c.relkind, c.reltype, "
7240 : : "c.relowner, "
7241 : : "c.relchecks, "
7242 : : "c.relhasindex, c.relhasrules, c.relpages, "
7243 : : "c.reltuples, c.relallvisible, ");
7244 : :
211 jdavis@postgresql.or 7245 [ + - ]: 190 : if (fout->remoteVersion >= 180000)
7246 : 190 : appendPQExpBufferStr(query, "c.relallfrozen, ");
7247 : : else
211 jdavis@postgresql.or 7248 :UBC 0 : appendPQExpBufferStr(query, "0 AS relallfrozen, ");
7249 : :
211 jdavis@postgresql.or 7250 :CBC 190 : appendPQExpBufferStr(query,
7251 : : "c.relhastriggers, c.relpersistence, "
7252 : : "c.reloftype, "
7253 : : "c.relacl, "
7254 : : "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
7255 : : " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
7256 : : "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
7257 : : "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
7258 : : "ELSE 0 END AS foreignserver, "
7259 : : "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
7260 : : "tc.oid AS toid, "
7261 : : "tc.relpages AS toastpages, "
7262 : : "tc.reloptions AS toast_reloptions, "
7263 : : "d.refobjid AS owning_tab, "
7264 : : "d.refobjsubid AS owning_col, "
7265 : : "tsp.spcname AS reltablespace, ");
7266 : :
1469 tgl@sss.pgh.pa.us 7267 [ + - ]: 190 : if (fout->remoteVersion >= 120000)
7268 : 190 : appendPQExpBufferStr(query,
7269 : : "false AS relhasoids, ");
7270 : : else
1469 tgl@sss.pgh.pa.us 7271 :UBC 0 : appendPQExpBufferStr(query,
7272 : : "c.relhasoids, ");
7273 : :
1469 tgl@sss.pgh.pa.us 7274 [ + - ]:CBC 190 : if (fout->remoteVersion >= 90300)
7275 : 190 : appendPQExpBufferStr(query,
7276 : : "c.relispopulated, ");
7277 : : else
1469 tgl@sss.pgh.pa.us 7278 :UBC 0 : appendPQExpBufferStr(query,
7279 : : "'t' as relispopulated, ");
7280 : :
1469 tgl@sss.pgh.pa.us 7281 [ + - ]:CBC 190 : if (fout->remoteVersion >= 90400)
7282 : 190 : appendPQExpBufferStr(query,
7283 : : "c.relreplident, ");
7284 : : else
1469 tgl@sss.pgh.pa.us 7285 :UBC 0 : appendPQExpBufferStr(query,
7286 : : "'d' AS relreplident, ");
7287 : :
1469 tgl@sss.pgh.pa.us 7288 [ + - ]:CBC 190 : if (fout->remoteVersion >= 90500)
7289 : 190 : appendPQExpBufferStr(query,
7290 : : "c.relrowsecurity, c.relforcerowsecurity, ");
7291 : : else
1469 tgl@sss.pgh.pa.us 7292 :UBC 0 : appendPQExpBufferStr(query,
7293 : : "false AS relrowsecurity, "
7294 : : "false AS relforcerowsecurity, ");
7295 : :
1469 tgl@sss.pgh.pa.us 7296 [ + - ]:CBC 190 : if (fout->remoteVersion >= 90300)
7297 : 190 : appendPQExpBufferStr(query,
7298 : : "c.relminmxid, tc.relminmxid AS tminmxid, ");
7299 : : else
1469 tgl@sss.pgh.pa.us 7300 :UBC 0 : appendPQExpBufferStr(query,
7301 : : "0 AS relminmxid, 0 AS tminmxid, ");
7302 : :
1469 tgl@sss.pgh.pa.us 7303 [ + - ]:CBC 190 : if (fout->remoteVersion >= 90300)
7304 : 190 : appendPQExpBufferStr(query,
7305 : : "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
7306 : : "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
7307 : : "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
7308 : : else
1469 tgl@sss.pgh.pa.us 7309 :UBC 0 : appendPQExpBufferStr(query,
7310 : : "c.reloptions, NULL AS checkoption, ");
7311 : :
3491 sfrost@snowman.net 7312 [ + - ]:CBC 190 : if (fout->remoteVersion >= 90600)
1469 tgl@sss.pgh.pa.us 7313 : 190 : appendPQExpBufferStr(query,
7314 : : "am.amname, ");
7315 : : else
1469 tgl@sss.pgh.pa.us 7316 :UBC 0 : appendPQExpBufferStr(query,
7317 : : "NULL AS amname, ");
7318 : :
1469 tgl@sss.pgh.pa.us 7319 [ + - ]:CBC 190 : if (fout->remoteVersion >= 90600)
7320 : 190 : appendPQExpBufferStr(query,
7321 : : "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
7322 : : else
1469 tgl@sss.pgh.pa.us 7323 :UBC 0 : appendPQExpBufferStr(query,
7324 : : "false AS is_identity_sequence, ");
7325 : :
1469 tgl@sss.pgh.pa.us 7326 [ + - ]:CBC 190 : if (fout->remoteVersion >= 100000)
7327 : 190 : appendPQExpBufferStr(query,
7328 : : "c.relispartition AS ispartition ");
7329 : : else
1469 tgl@sss.pgh.pa.us 7330 :UBC 0 : appendPQExpBufferStr(query,
7331 : : "false AS ispartition ");
7332 : :
7333 : : /*
7334 : : * Left join to pg_depend to pick up dependency info linking sequences to
7335 : : * their owning column, if any (note this dependency is AUTO except for
7336 : : * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
7337 : : * collect the spcname.
7338 : : */
1469 tgl@sss.pgh.pa.us 7339 :CBC 190 : appendPQExpBufferStr(query,
7340 : : "\nFROM pg_class c\n"
7341 : : "LEFT JOIN pg_depend d ON "
7342 : : "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
7343 : : "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
7344 : : "d.objsubid = 0 AND "
7345 : : "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
7346 : : "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
7347 : :
7348 : : /*
7349 : : * In 9.6 and up, left join to pg_am to pick up the amname.
7350 : : */
7351 [ + - ]: 190 : if (fout->remoteVersion >= 90600)
7352 : 190 : appendPQExpBufferStr(query,
7353 : : "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
7354 : :
7355 : : /*
7356 : : * We purposefully ignore toast OIDs for partitioned tables; the reason is
7357 : : * that versions 10 and 11 have them, but later versions do not, so
7358 : : * emitting them causes the upgrade to fail.
7359 : : */
1421 7360 : 190 : appendPQExpBufferStr(query,
7361 : : "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
7362 : : " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
7363 : : " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
7364 : :
7365 : : /*
7366 : : * Restrict to interesting relkinds (in particular, not indexes). Not all
7367 : : * relkinds are possible in older servers, but it's not worth the trouble
7368 : : * to emit a version-dependent list.
7369 : : *
7370 : : * Composite-type table entries won't be dumped as such, but we have to
7371 : : * make a DumpableObject for them so that we can track dependencies of the
7372 : : * composite type (pg_depend entries for columns of the composite type
7373 : : * link to the pg_class entry not the pg_type entry).
7374 : : */
1469 7375 : 190 : appendPQExpBufferStr(query,
7376 : : "WHERE c.relkind IN ("
7377 : : CppAsString2(RELKIND_RELATION) ", "
7378 : : CppAsString2(RELKIND_SEQUENCE) ", "
7379 : : CppAsString2(RELKIND_VIEW) ", "
7380 : : CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
7381 : : CppAsString2(RELKIND_MATVIEW) ", "
7382 : : CppAsString2(RELKIND_FOREIGN_TABLE) ", "
7383 : : CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
7384 : : "ORDER BY c.oid");
7385 : :
5011 rhaas@postgresql.org 7386 : 190 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7387 : :
8571 tgl@sss.pgh.pa.us 7388 : 190 : ntups = PQntuples(res);
7389 : :
7390 : 190 : *numTables = ntups;
7391 : :
7392 : : /*
7393 : : * Extract data from result and lock dumpable tables. We do the locking
7394 : : * before anything else, to minimize the window wherein a table could
7395 : : * disappear under us.
7396 : : *
7397 : : * Note that we have to save info about all tables here, even when dumping
7398 : : * only one, because we don't yet know which tables might be inheritance
7399 : : * ancestors of the target table.
7400 : : */
4773 7401 : 190 : tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
7402 : :
7996 7403 : 190 : i_reltableoid = PQfnumber(res, "tableoid");
8571 7404 : 190 : i_reloid = PQfnumber(res, "oid");
7405 : 190 : i_relname = PQfnumber(res, "relname");
7406 : 190 : i_relnamespace = PQfnumber(res, "relnamespace");
7407 : 190 : i_relkind = PQfnumber(res, "relkind");
1421 7408 : 190 : i_reltype = PQfnumber(res, "reltype");
1396 7409 : 190 : i_relowner = PQfnumber(res, "relowner");
8571 7410 : 190 : i_relchecks = PQfnumber(res, "relchecks");
7411 : 190 : i_relhasindex = PQfnumber(res, "relhasindex");
7412 : 190 : i_relhasrules = PQfnumber(res, "relhasrules");
1469 7413 : 190 : i_relpages = PQfnumber(res, "relpages");
244 jdavis@postgresql.or 7414 : 190 : i_reltuples = PQfnumber(res, "reltuples");
7415 : 190 : i_relallvisible = PQfnumber(res, "relallvisible");
211 7416 : 190 : i_relallfrozen = PQfnumber(res, "relallfrozen");
1421 tgl@sss.pgh.pa.us 7417 : 190 : i_toastpages = PQfnumber(res, "toastpages");
1469 7418 : 190 : i_owning_tab = PQfnumber(res, "owning_tab");
7419 : 190 : i_owning_col = PQfnumber(res, "owning_col");
7420 : 190 : i_reltablespace = PQfnumber(res, "reltablespace");
7421 : 190 : i_relhasoids = PQfnumber(res, "relhasoids");
7422 : 190 : i_relhastriggers = PQfnumber(res, "relhastriggers");
7423 : 190 : i_relpersistence = PQfnumber(res, "relpersistence");
7424 : 190 : i_relispopulated = PQfnumber(res, "relispopulated");
7425 : 190 : i_relreplident = PQfnumber(res, "relreplident");
4051 sfrost@snowman.net 7426 : 190 : i_relrowsec = PQfnumber(res, "relrowsecurity");
3676 7427 : 190 : i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6095 bruce@momjian.us 7428 : 190 : i_relfrozenxid = PQfnumber(res, "relfrozenxid");
5316 7429 : 190 : i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
1469 tgl@sss.pgh.pa.us 7430 : 190 : i_toastoid = PQfnumber(res, "toid");
7431 : 190 : i_relminmxid = PQfnumber(res, "relminmxid");
4135 bruce@momjian.us 7432 : 190 : i_toastminmxid = PQfnumber(res, "tminmxid");
7057 7433 : 190 : i_reloptions = PQfnumber(res, "reloptions");
4484 sfrost@snowman.net 7434 : 190 : i_checkoption = PQfnumber(res, "checkoption");
6111 alvherre@alvh.no-ip. 7435 : 190 : i_toastreloptions = PQfnumber(res, "toast_reloptions");
5751 peter_e@gmx.net 7436 : 190 : i_reloftype = PQfnumber(res, "reloftype");
1469 tgl@sss.pgh.pa.us 7437 : 190 : i_foreignserver = PQfnumber(res, "foreignserver");
7438 : 190 : i_amname = PQfnumber(res, "amname");
3126 peter_e@gmx.net 7439 : 190 : i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
1469 tgl@sss.pgh.pa.us 7440 : 190 : i_relacl = PQfnumber(res, "relacl");
1421 7441 : 190 : i_acldefault = PQfnumber(res, "acldefault");
3098 sfrost@snowman.net 7442 : 190 : i_ispartition = PQfnumber(res, "ispartition");
7443 : :
3302 tgl@sss.pgh.pa.us 7444 [ + + ]: 190 : if (dopt->lockWaitTimeout)
7445 : : {
7446 : : /*
7447 : : * Arrange to fail instead of waiting forever for a table lock.
7448 : : *
7449 : : * NB: this coding assumes that the only queries issued within the
7450 : : * following loop are LOCK TABLEs; else the timeout may be undesirably
7451 : : * applied to other things too.
7452 : : */
6308 7453 : 2 : resetPQExpBuffer(query);
4361 heikki.linnakangas@i 7454 : 2 : appendPQExpBufferStr(query, "SET statement_timeout = ");
4031 alvherre@alvh.no-ip. 7455 : 2 : appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
5011 rhaas@postgresql.org 7456 : 2 : ExecuteSqlStatement(fout, query->data);
7457 : : }
7458 : :
1028 tgl@sss.pgh.pa.us 7459 : 190 : resetPQExpBuffer(query);
7460 : :
8571 7461 [ + + ]: 50102 : for (i = 0; i < ntups; i++)
7462 : : {
244 jdavis@postgresql.or 7463 : 49912 : int32 relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
211 7464 : 49912 : int32 relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
7465 : :
7996 tgl@sss.pgh.pa.us 7466 : 49912 : tblinfo[i].dobj.objType = DO_TABLE;
7467 : 49912 : tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
7468 : 49912 : tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
7469 : 49912 : AssignDumpId(&tblinfo[i].dobj);
5085 bruce@momjian.us 7470 : 49912 : tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
5012 rhaas@postgresql.org 7471 : 99824 : tblinfo[i].dobj.namespace =
1889 peter@eisentraut.org 7472 : 49912 : findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
1421 tgl@sss.pgh.pa.us 7473 : 49912 : tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
7474 : 49912 : tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
7475 : 49912 : tblinfo[i].dacl.privtype = 0;
7476 : 49912 : tblinfo[i].dacl.initprivs = NULL;
8571 7477 : 49912 : tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
1421 7478 : 49912 : tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
1396 7479 : 49912 : tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
1469 7480 : 49912 : tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
8571 7481 : 49912 : tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
7482 : 49912 : tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4600 andrew@dunslane.net 7483 : 49912 : tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
1421 tgl@sss.pgh.pa.us 7484 [ + + ]: 49912 : if (PQgetisnull(res, i, i_toastpages))
7485 : 40123 : tblinfo[i].toastpages = 0;
7486 : : else
7487 : 9789 : tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
8470 7488 [ + + ]: 49912 : if (PQgetisnull(res, i, i_owning_tab))
7489 : : {
7996 7490 : 49497 : tblinfo[i].owning_tab = InvalidOid;
8470 7491 : 49497 : tblinfo[i].owning_col = 0;
7492 : : }
7493 : : else
7494 : : {
7996 7495 : 415 : tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
8470 7496 : 415 : tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
7497 : : }
5085 bruce@momjian.us 7498 : 49912 : tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
1469 tgl@sss.pgh.pa.us 7499 : 49912 : tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
7500 : 49912 : tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
7501 : 49912 : tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
7502 : 49912 : tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
7503 : 49912 : tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
7504 : 49912 : tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
7505 : 49912 : tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
7506 : 49912 : tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
7507 : 49912 : tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
7508 : 49912 : tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
7509 : 49912 : tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
7510 : 49912 : tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
5085 bruce@momjian.us 7511 : 49912 : tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
1469 tgl@sss.pgh.pa.us 7512 [ + + ]: 49912 : if (PQgetisnull(res, i, i_checkoption))
4484 sfrost@snowman.net 7513 : 49866 : tblinfo[i].checkoption = NULL;
7514 : : else
7515 : 46 : tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
5085 bruce@momjian.us 7516 : 49912 : tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
1421 tgl@sss.pgh.pa.us 7517 : 49912 : tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
1469 7518 : 49912 : tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
2427 andres@anarazel.de 7519 [ + + ]: 49912 : if (PQgetisnull(res, i, i_amname))
7520 : 29958 : tblinfo[i].amname = NULL;
7521 : : else
7522 : 19954 : tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
1469 tgl@sss.pgh.pa.us 7523 : 49912 : tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
7524 : 49912 : tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
7525 : :
7526 : : /* other fields were zeroed above */
7527 : :
7528 : : /*
7529 : : * Decide whether we want to dump this table.
7530 : : */
7594 7531 [ + + ]: 49912 : if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
3491 sfrost@snowman.net 7532 : 183 : tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
7533 : : else
7534 : 49729 : selectDumpableTable(&tblinfo[i], fout);
7535 : :
7536 : : /*
7537 : : * Now, consider the table "interesting" if we need to dump its
7538 : : * definition, data or its statistics. Later on, we'll skip a lot of
7539 : : * data collection for uninteresting tables.
7540 : : *
7541 : : * Note: the "interesting" flag will also be set by flagInhTables for
7542 : : * parents of interesting tables, so that we collect necessary
7543 : : * inheritance info even when the parents are not themselves being
7544 : : * dumped. This is the main reason why we need an "interesting" flag
7545 : : * that's separate from the components-to-dump bitmask.
7546 : : */
1421 tgl@sss.pgh.pa.us 7547 : 49912 : tblinfo[i].interesting = (tblinfo[i].dobj.dump &
7548 : : (DUMP_COMPONENT_DEFINITION |
7549 : : DUMP_COMPONENT_DATA |
249 jdavis@postgresql.or 7550 : 49912 : DUMP_COMPONENT_STATISTICS)) != 0;
7551 : :
1469 tgl@sss.pgh.pa.us 7552 : 49912 : tblinfo[i].dummy_view = false; /* might get set during sort */
7553 : 49912 : tblinfo[i].postponed_def = false; /* might get set during sort */
7554 : :
7555 : : /* Tables have data */
1421 7556 : 49912 : tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
7557 : :
7558 : : /* Mark whether table has an ACL */
7559 [ + + ]: 49912 : if (!PQgetisnull(res, i, i_relacl))
7560 : 40088 : tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
7561 : 49912 : tblinfo[i].hascolumnACLs = false; /* may get set later */
7562 : :
7563 : : /* Add statistics */
249 jdavis@postgresql.or 7564 [ + + ]: 49912 : if (tblinfo[i].interesting)
7565 : : {
7566 : : RelStatsInfo *stats;
7567 : :
213 7568 : 13942 : stats = getRelationStatistics(fout, &tblinfo[i].dobj,
7569 : 6971 : tblinfo[i].relpages,
7570 : : PQgetvalue(res, i, i_reltuples),
7571 : : relallvisible, relallfrozen,
7572 : 6971 : tblinfo[i].relkind, NULL, 0);
7573 [ + + ]: 6971 : if (tblinfo[i].relkind == RELKIND_MATVIEW)
7574 : 401 : tblinfo[i].stats = stats;
7575 : : }
7576 : :
7577 : : /*
7578 : : * Read-lock target tables to make sure they aren't DROPPED or altered
7579 : : * in schema before we get around to dumping them.
7580 : : *
7581 : : * Note that we don't explicitly lock parents of the target tables; we
7582 : : * assume our lock on the child is enough to prevent schema
7583 : : * alterations to parent tables.
7584 : : *
7585 : : * NOTE: it'd be kinda nice to lock other relations too, not only
7586 : : * plain or partitioned tables, but the backend doesn't presently
7587 : : * allow that.
7588 : : *
7589 : : * We only need to lock the table for certain components; see
7590 : : * pg_dump.h
7591 : : */
1421 tgl@sss.pgh.pa.us 7592 [ + + ]: 49912 : if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
1816 7593 [ + + ]: 6971 : (tblinfo[i].relkind == RELKIND_RELATION ||
1421 7594 [ + + ]: 1972 : tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
7595 : : {
7596 : : /*
7597 : : * Tables are locked in batches. When dumping from a remote
7598 : : * server this can save a significant amount of time by reducing
7599 : : * the number of round trips.
7600 : : */
1028 7601 [ + + ]: 5593 : if (query->len == 0)
7602 : 126 : appendPQExpBuffer(query, "LOCK TABLE %s",
7603 : 126 : fmtQualifiedDumpable(&tblinfo[i]));
7604 : : else
7605 : : {
7606 : 5467 : appendPQExpBuffer(query, ", %s",
7607 : 5467 : fmtQualifiedDumpable(&tblinfo[i]));
7608 : :
7609 : : /* Arbitrarily end a batch when query length reaches 100K. */
7610 [ - + ]: 5467 : if (query->len >= 100000)
7611 : : {
7612 : : /* Lock another batch of tables. */
1028 tgl@sss.pgh.pa.us 7613 :UBC 0 : appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7614 : 0 : ExecuteSqlStatement(fout, query->data);
7615 : 0 : resetPQExpBuffer(query);
7616 : : }
7617 : : }
7618 : : }
7619 : : }
7620 : :
1028 tgl@sss.pgh.pa.us 7621 [ + + ]:CBC 190 : if (query->len != 0)
7622 : : {
7623 : : /* Lock the tables in the last batch. */
7624 : 126 : appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7625 : 126 : ExecuteSqlStatement(fout, query->data);
7626 : : }
7627 : :
3302 7628 [ + + ]: 189 : if (dopt->lockWaitTimeout)
7629 : : {
5011 rhaas@postgresql.org 7630 : 2 : ExecuteSqlStatement(fout, "SET statement_timeout = 0");
7631 : : }
7632 : :
8571 tgl@sss.pgh.pa.us 7633 : 189 : PQclear(res);
7634 : :
4958 7635 : 189 : destroyPQExpBuffer(query);
7636 : :
7637 : 189 : return tblinfo;
7638 : : }
7639 : :
7640 : : /*
7641 : : * getOwnedSeqs
7642 : : * identify owned sequences and mark them as dumpable if owning table is
7643 : : *
7644 : : * We used to do this in getTables(), but it's better to do it after the
7645 : : * index used by findTableByOid() has been set up.
7646 : : */
7647 : : void
7648 : 189 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
7649 : : {
7650 : : int i;
7651 : :
7652 : : /*
7653 : : * Force sequences that are "owned" by table columns to be dumped whenever
7654 : : * their owning table is being dumped.
7655 : : */
7656 [ + + ]: 49831 : for (i = 0; i < numTables; i++)
7657 : : {
7007 7658 : 49642 : TableInfo *seqinfo = &tblinfo[i];
7659 : : TableInfo *owning_tab;
7660 : :
7661 [ + + ]: 49642 : if (!OidIsValid(seqinfo->owning_tab))
7662 : 49230 : continue; /* not an owned sequence */
7663 : :
4958 7664 : 412 : owning_tab = findTableByOid(seqinfo->owning_tab);
3216 sfrost@snowman.net 7665 [ - + ]: 412 : if (owning_tab == NULL)
1298 tgl@sss.pgh.pa.us 7666 :UBC 0 : pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
7667 : : seqinfo->owning_tab, seqinfo->dobj.catId.oid);
7668 : :
7669 : : /*
7670 : : * For an identity sequence, dump exactly the same components for the
7671 : : * sequence as for the owning table. This is important because we
7672 : : * treat the identity sequence as an integral part of the table. For
7673 : : * example, there is not any DDL command that allows creation of such
7674 : : * a sequence independently of the table.
7675 : : *
7676 : : * For other owned sequences such as serial sequences, we need to dump
7677 : : * the components that are being dumped for the table and any
7678 : : * components that the sequence is explicitly marked with.
7679 : : *
7680 : : * We can't simply use the set of components which are being dumped
7681 : : * for the table as the table might be in an extension (and only the
7682 : : * non-extension components, eg: ACLs if changed, security labels, and
7683 : : * policies, are being dumped) while the sequence is not (and
7684 : : * therefore the definition and other components should also be
7685 : : * dumped).
7686 : : *
7687 : : * If the sequence is part of the extension then it should be properly
7688 : : * marked by checkExtensionMembership() and this will be a no-op as
7689 : : * the table will be equivalently marked.
7690 : : */
318 tgl@sss.pgh.pa.us 7691 [ + + ]:CBC 412 : if (seqinfo->is_identity_sequence)
7692 : 199 : seqinfo->dobj.dump = owning_tab->dobj.dump;
7693 : : else
7694 : 213 : seqinfo->dobj.dump |= owning_tab->dobj.dump;
7695 : :
7696 : : /* Make sure that necessary data is available if we're dumping it */
3375 sfrost@snowman.net 7697 [ + + ]: 412 : if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
7698 : : {
4958 tgl@sss.pgh.pa.us 7699 : 316 : seqinfo->interesting = true;
318 7700 : 316 : owning_tab->interesting = true;
7701 : : }
7702 : : }
10702 scrappy@hub.org 7703 : 189 : }
7704 : :
7705 : : /*
7706 : : * getInherits
7707 : : * read all the inheritance information
7708 : : * from the system catalogs return them in the InhInfo* structure
7709 : : *
7710 : : * numInherits is set to the number of pairs read in
7711 : : */
7712 : : InhInfo *
5012 rhaas@postgresql.org 7713 : 189 : getInherits(Archive *fout, int *numInherits)
7714 : : {
7715 : : PGresult *res;
7716 : : int ntups;
7717 : : int i;
9329 bruce@momjian.us 7718 : 189 : PQExpBuffer query = createPQExpBuffer();
7719 : : InhInfo *inhinfo;
7720 : :
7721 : : int i_inhrelid;
7722 : : int i_inhparent;
7723 : :
7724 : : /* find all the inheritance information */
3098 sfrost@snowman.net 7725 : 189 : appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
7726 : :
5011 rhaas@postgresql.org 7727 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7728 : :
10277 bruce@momjian.us 7729 : 189 : ntups = PQntuples(res);
7730 : :
7731 : 189 : *numInherits = ntups;
7732 : :
5085 7733 : 189 : inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
7734 : :
9471 7735 : 189 : i_inhrelid = PQfnumber(res, "inhrelid");
10277 7736 : 189 : i_inhparent = PQfnumber(res, "inhparent");
7737 : :
7738 [ + + ]: 3557 : for (i = 0; i < ntups; i++)
7739 : : {
7996 tgl@sss.pgh.pa.us 7740 : 3368 : inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
7741 : 3368 : inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
7742 : : }
7743 : :
10277 bruce@momjian.us 7744 : 189 : PQclear(res);
7745 : :
8851 tgl@sss.pgh.pa.us 7746 : 189 : destroyPQExpBuffer(query);
7747 : :
10277 bruce@momjian.us 7748 : 189 : return inhinfo;
7749 : : }
7750 : :
7751 : : /*
7752 : : * getPartitioningInfo
7753 : : * get information about partitioning
7754 : : *
7755 : : * For the most part, we only collect partitioning info about tables we
7756 : : * intend to dump. However, this function has to consider all partitioned
7757 : : * tables in the database, because we need to know about parents of partitions
7758 : : * we are going to dump even if the parents themselves won't be dumped.
7759 : : *
7760 : : * Specifically, what we need to know is whether each partitioned table
7761 : : * has an "unsafe" partitioning scheme that requires us to force
7762 : : * load-via-partition-root mode for its children. Currently the only case
7763 : : * for which we force that is hash partitioning on enum columns, since the
7764 : : * hash codes depend on enum value OIDs which won't be replicated across
7765 : : * dump-and-reload. There are other cases in which load-via-partition-root
7766 : : * might be necessary, but we expect users to cope with them.
7767 : : */
7768 : : void
955 tgl@sss.pgh.pa.us 7769 : 189 : getPartitioningInfo(Archive *fout)
7770 : : {
7771 : : PQExpBuffer query;
7772 : : PGresult *res;
7773 : : int ntups;
7774 : :
7775 : : /* hash partitioning didn't exist before v11 */
7776 [ - + ]: 189 : if (fout->remoteVersion < 110000)
955 tgl@sss.pgh.pa.us 7777 :UBC 0 : return;
7778 : : /* needn't bother if not dumping data */
336 nathan@postgresql.or 7779 [ + + ]:CBC 189 : if (!fout->dopt->dumpData)
955 tgl@sss.pgh.pa.us 7780 : 40 : return;
7781 : :
7782 : 149 : query = createPQExpBuffer();
7783 : :
7784 : : /*
7785 : : * Unsafe partitioning schemes are exactly those for which hash enum_ops
7786 : : * appears among the partition opclasses. We needn't check partstrat.
7787 : : *
7788 : : * Note that this query may well retrieve info about tables we aren't
7789 : : * going to dump and hence have no lock on. That's okay since we need not
7790 : : * invoke any unsafe server-side functions.
7791 : : */
7792 : 149 : appendPQExpBufferStr(query,
7793 : : "SELECT partrelid FROM pg_partitioned_table WHERE\n"
7794 : : "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
7795 : : "ON c.opcmethod = a.oid\n"
7796 : : "WHERE opcname = 'enum_ops' "
7797 : : "AND opcnamespace = 'pg_catalog'::regnamespace "
7798 : : "AND amname = 'hash') = ANY(partclass)");
7799 : :
7800 : 149 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7801 : :
7802 : 149 : ntups = PQntuples(res);
7803 : :
7804 [ + + ]: 192 : for (int i = 0; i < ntups; i++)
7805 : : {
7806 : 43 : Oid tabrelid = atooid(PQgetvalue(res, i, 0));
7807 : : TableInfo *tbinfo;
7808 : :
7809 : 43 : tbinfo = findTableByOid(tabrelid);
7810 [ - + ]: 43 : if (tbinfo == NULL)
955 tgl@sss.pgh.pa.us 7811 :UBC 0 : pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
7812 : : tabrelid);
955 tgl@sss.pgh.pa.us 7813 :CBC 43 : tbinfo->unsafe_partitions = true;
7814 : : }
7815 : :
7816 : 149 : PQclear(res);
7817 : :
7818 : 149 : destroyPQExpBuffer(query);
7819 : : }
7820 : :
7821 : : /*
7822 : : * getIndexes
7823 : : * get information about every index on a dumpable table
7824 : : *
7825 : : * Note: index data is not returned directly to the caller, but it
7826 : : * does get entered into the DumpableObject tables.
7827 : : */
7828 : : void
5012 rhaas@postgresql.org 7829 : 189 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
7830 : : {
7996 tgl@sss.pgh.pa.us 7831 : 189 : PQExpBuffer query = createPQExpBuffer();
1421 7832 : 189 : PQExpBuffer tbloids = createPQExpBuffer();
7833 : : PGresult *res;
7834 : : int ntups;
7835 : : int curtblindx;
7836 : : IndxInfo *indxinfo;
7837 : : int i_tableoid,
7838 : : i_oid,
7839 : : i_indrelid,
7840 : : i_indexname,
7841 : : i_relpages,
7842 : : i_reltuples,
7843 : : i_relallvisible,
7844 : : i_relallfrozen,
7845 : : i_parentidx,
7846 : : i_indexdef,
7847 : : i_indnkeyatts,
7848 : : i_indnatts,
7849 : : i_indkey,
7850 : : i_indisclustered,
7851 : : i_indisreplident,
7852 : : i_indnullsnotdistinct,
7853 : : i_contype,
7854 : : i_conname,
7855 : : i_condeferrable,
7856 : : i_condeferred,
7857 : : i_conperiod,
7858 : : i_contableoid,
7859 : : i_conoid,
7860 : : i_condef,
7861 : : i_indattnames,
7862 : : i_tablespace,
7863 : : i_indreloptions,
7864 : : i_indstatcols,
7865 : : i_indstatvals;
7866 : :
7867 : : /*
7868 : : * We want to perform just one query against pg_index. However, we
7869 : : * mustn't try to select every row of the catalog and then sort it out on
7870 : : * the client side, because some of the server-side functions we need
7871 : : * would be unsafe to apply to tables we don't have lock on. Hence, we
7872 : : * build an array of the OIDs of tables we care about (and now have lock
7873 : : * on!), and use a WHERE clause to constrain which rows are selected.
7874 : : */
7875 : 189 : appendPQExpBufferChar(tbloids, '{');
7876 [ + + ]: 49831 : for (int i = 0; i < numTables; i++)
7877 : : {
7996 7878 : 49642 : TableInfo *tbinfo = &tblinfo[i];
7879 : :
4621 kgrittn@postgresql.o 7880 [ + + ]: 49642 : if (!tbinfo->hasindex)
7996 tgl@sss.pgh.pa.us 7881 : 35168 : continue;
7882 : :
7883 : : /*
7884 : : * We can ignore indexes of uninteresting tables.
7885 : : */
1421 7886 [ + + ]: 14474 : if (!tbinfo->interesting)
7996 7887 : 12483 : continue;
7888 : :
7889 : : /* OK, we need info for this table */
1421 7890 [ + + ]: 1991 : if (tbloids->len > 1) /* do we have more than the '{'? */
7891 : 1913 : appendPQExpBufferChar(tbloids, ',');
7892 : 1991 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
7893 : : }
7894 : 189 : appendPQExpBufferChar(tbloids, '}');
7895 : :
1147 drowley@postgresql.o 7896 : 189 : appendPQExpBufferStr(query,
7897 : : "SELECT t.tableoid, t.oid, i.indrelid, "
7898 : : "t.relname AS indexname, "
7899 : : "t.relpages, t.reltuples, t.relallvisible, ");
7900 : :
211 jdavis@postgresql.or 7901 [ + - ]: 189 : if (fout->remoteVersion >= 180000)
7902 : 189 : appendPQExpBufferStr(query, "t.relallfrozen, ");
7903 : : else
211 jdavis@postgresql.or 7904 :UBC 0 : appendPQExpBufferStr(query, "0 AS relallfrozen, ");
7905 : :
211 jdavis@postgresql.or 7906 :CBC 189 : appendPQExpBufferStr(query,
7907 : : "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7908 : : "i.indkey, i.indisclustered, "
7909 : : "c.contype, c.conname, "
7910 : : "c.condeferrable, c.condeferred, "
7911 : : "c.tableoid AS contableoid, "
7912 : : "c.oid AS conoid, "
7913 : : "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
7914 : : "CASE WHEN i.indexprs IS NOT NULL THEN "
7915 : : "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
7916 : : " FROM pg_catalog.pg_attribute "
7917 : : " WHERE attrelid = i.indexrelid) "
7918 : : "ELSE NULL END AS indattnames, "
7919 : : "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7920 : : "t.reloptions AS indreloptions, ");
7921 : :
7922 : :
1407 peter@eisentraut.org 7923 [ + - ]: 189 : if (fout->remoteVersion >= 90400)
1147 drowley@postgresql.o 7924 : 189 : appendPQExpBufferStr(query,
7925 : : "i.indisreplident, ");
7926 : : else
1147 drowley@postgresql.o 7927 :UBC 0 : appendPQExpBufferStr(query,
7928 : : "false AS indisreplident, ");
7929 : :
1407 peter@eisentraut.org 7930 [ + - ]:CBC 189 : if (fout->remoteVersion >= 110000)
1147 drowley@postgresql.o 7931 : 189 : appendPQExpBufferStr(query,
7932 : : "inh.inhparent AS parentidx, "
7933 : : "i.indnkeyatts AS indnkeyatts, "
7934 : : "i.indnatts AS indnatts, "
7935 : : "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
7936 : : " FROM pg_catalog.pg_attribute "
7937 : : " WHERE attrelid = i.indexrelid AND "
7938 : : " attstattarget >= 0) AS indstatcols, "
7939 : : "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
7940 : : " FROM pg_catalog.pg_attribute "
7941 : : " WHERE attrelid = i.indexrelid AND "
7942 : : " attstattarget >= 0) AS indstatvals, ");
7943 : : else
1147 drowley@postgresql.o 7944 :UBC 0 : appendPQExpBufferStr(query,
7945 : : "0 AS parentidx, "
7946 : : "i.indnatts AS indnkeyatts, "
7947 : : "i.indnatts AS indnatts, "
7948 : : "'' AS indstatcols, "
7949 : : "'' AS indstatvals, ");
7950 : :
1362 peter@eisentraut.org 7951 [ + - ]:CBC 189 : if (fout->remoteVersion >= 150000)
1147 drowley@postgresql.o 7952 : 189 : appendPQExpBufferStr(query,
7953 : : "i.indnullsnotdistinct, ");
7954 : : else
1147 drowley@postgresql.o 7955 :UBC 0 : appendPQExpBufferStr(query,
7956 : : "false AS indnullsnotdistinct, ");
7957 : :
405 peter@eisentraut.org 7958 [ + - ]:CBC 189 : if (fout->remoteVersion >= 180000)
7959 : 189 : appendPQExpBufferStr(query,
7960 : : "c.conperiod ");
7961 : : else
405 peter@eisentraut.org 7962 :UBC 0 : appendPQExpBufferStr(query,
7963 : : "NULL AS conperiod ");
7964 : :
7965 : : /*
7966 : : * The point of the messy-looking outer join is to find a constraint that
7967 : : * is related by an internal dependency link to the index. If we find one,
7968 : : * create a CONSTRAINT entry linked to the INDEX entry. We assume an
7969 : : * index won't have more than one internal dependency.
7970 : : *
7971 : : * Note: the check on conrelid is redundant, but useful because that
7972 : : * column is indexed while conindid is not.
7973 : : */
1421 tgl@sss.pgh.pa.us 7974 [ + - ]:CBC 189 : if (fout->remoteVersion >= 110000)
7975 : : {
7976 : 189 : appendPQExpBuffer(query,
7977 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7978 : : "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7979 : : "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7980 : : "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
7981 : : "LEFT JOIN pg_catalog.pg_constraint c "
7982 : : "ON (i.indrelid = c.conrelid AND "
7983 : : "i.indexrelid = c.conindid AND "
7984 : : "c.contype IN ('p','u','x')) "
7985 : : "LEFT JOIN pg_catalog.pg_inherits inh "
7986 : : "ON (inh.inhrelid = indexrelid) "
7987 : : "WHERE (i.indisvalid OR t2.relkind = 'p') "
7988 : : "AND i.indisready "
7989 : : "ORDER BY i.indrelid, indexname",
7990 : : tbloids->data);
7991 : : }
7992 : : else
7993 : : {
7994 : : /*
7995 : : * the test on indisready is necessary in 9.2, and harmless in
7996 : : * earlier/later versions
7997 : : */
1421 tgl@sss.pgh.pa.us 7998 :UBC 0 : appendPQExpBuffer(query,
7999 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8000 : : "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
8001 : : "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
8002 : : "LEFT JOIN pg_catalog.pg_constraint c "
8003 : : "ON (i.indrelid = c.conrelid AND "
8004 : : "i.indexrelid = c.conindid AND "
8005 : : "c.contype IN ('p','u','x')) "
8006 : : "WHERE i.indisvalid AND i.indisready "
8007 : : "ORDER BY i.indrelid, indexname",
8008 : : tbloids->data);
8009 : : }
8010 : :
1421 tgl@sss.pgh.pa.us 8011 :CBC 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8012 : :
8013 : 189 : ntups = PQntuples(res);
8014 : :
8015 : 189 : i_tableoid = PQfnumber(res, "tableoid");
8016 : 189 : i_oid = PQfnumber(res, "oid");
8017 : 189 : i_indrelid = PQfnumber(res, "indrelid");
8018 : 189 : i_indexname = PQfnumber(res, "indexname");
244 jdavis@postgresql.or 8019 : 189 : i_relpages = PQfnumber(res, "relpages");
8020 : 189 : i_reltuples = PQfnumber(res, "reltuples");
8021 : 189 : i_relallvisible = PQfnumber(res, "relallvisible");
211 8022 : 189 : i_relallfrozen = PQfnumber(res, "relallfrozen");
1421 tgl@sss.pgh.pa.us 8023 : 189 : i_parentidx = PQfnumber(res, "parentidx");
8024 : 189 : i_indexdef = PQfnumber(res, "indexdef");
8025 : 189 : i_indnkeyatts = PQfnumber(res, "indnkeyatts");
8026 : 189 : i_indnatts = PQfnumber(res, "indnatts");
8027 : 189 : i_indkey = PQfnumber(res, "indkey");
8028 : 189 : i_indisclustered = PQfnumber(res, "indisclustered");
8029 : 189 : i_indisreplident = PQfnumber(res, "indisreplident");
1362 peter@eisentraut.org 8030 : 189 : i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
1421 tgl@sss.pgh.pa.us 8031 : 189 : i_contype = PQfnumber(res, "contype");
8032 : 189 : i_conname = PQfnumber(res, "conname");
8033 : 189 : i_condeferrable = PQfnumber(res, "condeferrable");
8034 : 189 : i_condeferred = PQfnumber(res, "condeferred");
405 peter@eisentraut.org 8035 : 189 : i_conperiod = PQfnumber(res, "conperiod");
1421 tgl@sss.pgh.pa.us 8036 : 189 : i_contableoid = PQfnumber(res, "contableoid");
8037 : 189 : i_conoid = PQfnumber(res, "conoid");
8038 : 189 : i_condef = PQfnumber(res, "condef");
243 8039 : 189 : i_indattnames = PQfnumber(res, "indattnames");
1421 8040 : 189 : i_tablespace = PQfnumber(res, "tablespace");
8041 : 189 : i_indreloptions = PQfnumber(res, "indreloptions");
8042 : 189 : i_indstatcols = PQfnumber(res, "indstatcols");
8043 : 189 : i_indstatvals = PQfnumber(res, "indstatvals");
8044 : :
8045 : 189 : indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
8046 : :
8047 : : /*
8048 : : * Outer loop iterates once per table, not once per row. Incrementing of
8049 : : * j is handled by the inner loop.
8050 : : */
8051 : 189 : curtblindx = -1;
8052 [ + + ]: 2160 : for (int j = 0; j < ntups;)
8053 : : {
8054 : 1971 : Oid indrelid = atooid(PQgetvalue(res, j, i_indrelid));
8055 : 1971 : TableInfo *tbinfo = NULL;
243 8056 : 1971 : char **indAttNames = NULL;
8057 : 1971 : int nindAttNames = 0;
8058 : : int numinds;
8059 : :
8060 : : /* Count rows for this table */
1421 8061 [ + + ]: 2583 : for (numinds = 1; numinds < ntups - j; numinds++)
8062 [ + + ]: 2505 : if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
8063 : 1893 : break;
8064 : :
8065 : : /*
8066 : : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8067 : : * order.
8068 : : */
8069 [ + - ]: 23103 : while (++curtblindx < numTables)
8070 : : {
8071 : 23103 : tbinfo = &tblinfo[curtblindx];
8072 [ + + ]: 23103 : if (tbinfo->dobj.catId.oid == indrelid)
8073 : 1971 : break;
8074 : : }
8075 [ - + ]: 1971 : if (curtblindx >= numTables)
1298 tgl@sss.pgh.pa.us 8076 :UBC 0 : pg_fatal("unrecognized table OID %u", indrelid);
8077 : : /* cross-check that we only got requested tables */
1421 tgl@sss.pgh.pa.us 8078 [ + - ]:CBC 1971 : if (!tbinfo->hasindex ||
8079 [ - + ]: 1971 : !tbinfo->interesting)
1298 tgl@sss.pgh.pa.us 8080 :UBC 0 : pg_fatal("unexpected index data for table \"%s\"",
8081 : : tbinfo->dobj.name);
8082 : :
8083 : : /* Save data for this table */
1421 tgl@sss.pgh.pa.us 8084 :CBC 1971 : tbinfo->indexes = indxinfo + j;
8085 : 1971 : tbinfo->numIndexes = numinds;
8086 : :
8087 [ + + ]: 4554 : for (int c = 0; c < numinds; c++, j++)
8088 : : {
8089 : : char contype;
8090 : : char indexkind;
8091 : : RelStatsInfo *relstats;
244 jdavis@postgresql.or 8092 : 2583 : int32 relpages = atoi(PQgetvalue(res, j, i_relpages));
8093 : 2583 : int32 relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
211 8094 : 2583 : int32 relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
8095 : :
7996 tgl@sss.pgh.pa.us 8096 : 2583 : indxinfo[j].dobj.objType = DO_INDEX;
8097 : 2583 : indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8098 : 2583 : indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8099 : 2583 : AssignDumpId(&indxinfo[j].dobj);
2838 alvherre@alvh.no-ip. 8100 : 2583 : indxinfo[j].dobj.dump = tbinfo->dobj.dump;
5085 bruce@momjian.us 8101 : 2583 : indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7908 tgl@sss.pgh.pa.us 8102 : 2583 : indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7996 8103 : 2583 : indxinfo[j].indextable = tbinfo;
5085 bruce@momjian.us 8104 : 2583 : indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
2750 heikki.linnakangas@i 8105 : 2583 : indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
2760 teodor@sigaev.ru 8106 : 2583 : indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
5085 bruce@momjian.us 8107 : 2583 : indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
3586 tgl@sss.pgh.pa.us 8108 : 2583 : indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
2505 michael@paquier.xyz 8109 : 2583 : indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
8110 : 2583 : indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
2760 teodor@sigaev.ru 8111 : 2583 : indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7996 tgl@sss.pgh.pa.us 8112 : 2583 : parseOidArray(PQgetvalue(res, j, i_indkey),
2760 teodor@sigaev.ru 8113 : 2583 : indxinfo[j].indkeys, indxinfo[j].indnattrs);
7996 tgl@sss.pgh.pa.us 8114 : 2583 : indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
4371 rhaas@postgresql.org 8115 : 2583 : indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
1362 peter@eisentraut.org 8116 : 2583 : indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
2838 alvherre@alvh.no-ip. 8117 : 2583 : indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
1992 tgl@sss.pgh.pa.us 8118 : 2583 : indxinfo[j].partattaches = (SimplePtrList)
8119 : : {
8120 : : NULL, NULL
8121 : : };
8122 : :
249 jdavis@postgresql.or 8123 [ + + ]: 2583 : if (indxinfo[j].parentidx == 0)
8124 : 2019 : indexkind = RELKIND_INDEX;
8125 : : else
8126 : 564 : indexkind = RELKIND_PARTITIONED_INDEX;
8127 : :
243 tgl@sss.pgh.pa.us 8128 [ + + ]: 2583 : if (!PQgetisnull(res, j, i_indattnames))
8129 : : {
8130 [ - + ]: 146 : if (!parsePGArray(PQgetvalue(res, j, i_indattnames),
8131 : : &indAttNames, &nindAttNames))
243 tgl@sss.pgh.pa.us 8132 :UBC 0 : pg_fatal("could not parse %s array", "indattnames");
8133 : : }
8134 : :
244 jdavis@postgresql.or 8135 :CBC 2583 : relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
8136 : : PQgetvalue(res, j, i_reltuples),
8137 : : relallvisible, relallfrozen, indexkind,
8138 : : indAttNames, nindAttNames);
8139 : :
243 tgl@sss.pgh.pa.us 8140 : 2583 : contype = *(PQgetvalue(res, j, i_contype));
5803 8141 [ + + + + : 2583 : if (contype == 'p' || contype == 'u' || contype == 'x')
+ + ]
7996 8142 : 1501 : {
8143 : : /*
8144 : : * If we found a constraint matching the index, create an
8145 : : * entry for it.
8146 : : */
8147 : : ConstraintInfo *constrinfo;
8148 : :
1464 8149 : 1501 : constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
8150 : 1501 : constrinfo->dobj.objType = DO_CONSTRAINT;
8151 : 1501 : constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
8152 : 1501 : constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
8153 : 1501 : AssignDumpId(&constrinfo->dobj);
8154 : 1501 : constrinfo->dobj.dump = tbinfo->dobj.dump;
8155 : 1501 : constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
8156 : 1501 : constrinfo->dobj.namespace = tbinfo->dobj.namespace;
8157 : 1501 : constrinfo->contable = tbinfo;
8158 : 1501 : constrinfo->condomain = NULL;
8159 : 1501 : constrinfo->contype = contype;
5803 8160 [ + + ]: 1501 : if (contype == 'x')
1464 8161 : 10 : constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
8162 : : else
8163 : 1491 : constrinfo->condef = NULL;
8164 : 1501 : constrinfo->confrelid = InvalidOid;
8165 : 1501 : constrinfo->conindex = indxinfo[j].dobj.dumpId;
8166 : 1501 : constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
8167 : 1501 : constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
405 peter@eisentraut.org 8168 : 1501 : constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
1464 tgl@sss.pgh.pa.us 8169 : 1501 : constrinfo->conislocal = true;
8170 : 1501 : constrinfo->separate = true;
8171 : :
8172 : 1501 : indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
249 jdavis@postgresql.or 8173 [ + + ]: 1501 : if (relstats != NULL)
8174 : 526 : addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
8175 : : }
8176 : : else
8177 : : {
8178 : : /* Plain secondary index */
7996 tgl@sss.pgh.pa.us 8179 : 1082 : indxinfo[j].indexconstraint = 0;
8180 : : }
8181 : : }
8182 : : }
8183 : :
1421 8184 : 189 : PQclear(res);
8185 : :
7996 8186 : 189 : destroyPQExpBuffer(query);
1421 8187 : 189 : destroyPQExpBuffer(tbloids);
7996 8188 : 189 : }
8189 : :
8190 : : /*
8191 : : * getExtendedStatistics
8192 : : * get information about extended-statistics objects.
8193 : : *
8194 : : * Note: extended statistics data is not returned directly to the caller, but
8195 : : * it does get entered into the DumpableObject tables.
8196 : : */
8197 : : void
2815 8198 : 189 : getExtendedStatistics(Archive *fout)
8199 : : {
8200 : : PQExpBuffer query;
8201 : : PGresult *res;
8202 : : StatsExtInfo *statsextinfo;
8203 : : int ntups;
8204 : : int i_tableoid;
8205 : : int i_oid;
8206 : : int i_stxname;
8207 : : int i_stxnamespace;
8208 : : int i_stxowner;
8209 : : int i_stxrelid;
8210 : : int i_stattarget;
8211 : : int i;
8212 : :
8213 : : /* Extended statistics were new in v10 */
3139 alvherre@alvh.no-ip. 8214 [ - + ]: 189 : if (fout->remoteVersion < 100000)
3139 alvherre@alvh.no-ip. 8215 :UBC 0 : return;
8216 : :
3139 alvherre@alvh.no-ip. 8217 :CBC 189 : query = createPQExpBuffer();
8218 : :
2239 tomas.vondra@postgre 8219 [ - + ]: 189 : if (fout->remoteVersion < 130000)
1147 drowley@postgresql.o 8220 :UBC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
8221 : : "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
8222 : : "FROM pg_catalog.pg_statistic_ext");
8223 : : else
1147 drowley@postgresql.o 8224 :CBC 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
8225 : : "stxnamespace, stxowner, stxrelid, stxstattarget "
8226 : : "FROM pg_catalog.pg_statistic_ext");
8227 : :
2815 tgl@sss.pgh.pa.us 8228 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8229 : :
8230 : 189 : ntups = PQntuples(res);
8231 : :
8232 : 189 : i_tableoid = PQfnumber(res, "tableoid");
8233 : 189 : i_oid = PQfnumber(res, "oid");
8234 : 189 : i_stxname = PQfnumber(res, "stxname");
8235 : 189 : i_stxnamespace = PQfnumber(res, "stxnamespace");
1396 8236 : 189 : i_stxowner = PQfnumber(res, "stxowner");
668 8237 : 189 : i_stxrelid = PQfnumber(res, "stxrelid");
2239 tomas.vondra@postgre 8238 : 189 : i_stattarget = PQfnumber(res, "stxstattarget");
8239 : :
2815 tgl@sss.pgh.pa.us 8240 : 189 : statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
8241 : :
8242 [ + + ]: 352 : for (i = 0; i < ntups; i++)
8243 : : {
8244 : 163 : statsextinfo[i].dobj.objType = DO_STATSEXT;
8245 : 163 : statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8246 : 163 : statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8247 : 163 : AssignDumpId(&statsextinfo[i].dobj);
8248 : 163 : statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
8249 : 326 : statsextinfo[i].dobj.namespace =
1889 peter@eisentraut.org 8250 : 163 : findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
1396 tgl@sss.pgh.pa.us 8251 : 163 : statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
668 8252 : 326 : statsextinfo[i].stattable =
8253 : 163 : findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
589 peter@eisentraut.org 8254 [ + + ]: 163 : if (PQgetisnull(res, i, i_stattarget))
8255 : 118 : statsextinfo[i].stattarget = -1;
8256 : : else
8257 : 45 : statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
8258 : :
8259 : : /* Decide whether we want to dump it */
668 tgl@sss.pgh.pa.us 8260 : 163 : selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
8261 : : }
8262 : :
2815 8263 : 189 : PQclear(res);
3139 alvherre@alvh.no-ip. 8264 : 189 : destroyPQExpBuffer(query);
8265 : : }
8266 : :
8267 : : /*
8268 : : * getConstraints
8269 : : *
8270 : : * Get info about constraints on dumpable tables.
8271 : : *
8272 : : * Currently handles foreign keys only.
8273 : : * Unique and primary key constraints are handled with indexes,
8274 : : * while check constraints are processed in getTableAttrs().
8275 : : */
8276 : : void
5012 rhaas@postgresql.org 8277 : 189 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
8278 : : {
1421 tgl@sss.pgh.pa.us 8279 : 189 : PQExpBuffer query = createPQExpBuffer();
8280 : 189 : PQExpBuffer tbloids = createPQExpBuffer();
8281 : : PGresult *res;
8282 : : int ntups;
8283 : : int curtblindx;
8284 : 189 : TableInfo *tbinfo = NULL;
8285 : : ConstraintInfo *constrinfo;
8286 : : int i_contableoid,
8287 : : i_conoid,
8288 : : i_conrelid,
8289 : : i_conname,
8290 : : i_confrelid,
8291 : : i_conindid,
8292 : : i_condef;
8293 : :
8294 : : /*
8295 : : * We want to perform just one query against pg_constraint. However, we
8296 : : * mustn't try to select every row of the catalog and then sort it out on
8297 : : * the client side, because some of the server-side functions we need
8298 : : * would be unsafe to apply to tables we don't have lock on. Hence, we
8299 : : * build an array of the OIDs of tables we care about (and now have lock
8300 : : * on!), and use a WHERE clause to constrain which rows are selected.
8301 : : */
8302 : 189 : appendPQExpBufferChar(tbloids, '{');
8303 [ + + ]: 49831 : for (int i = 0; i < numTables; i++)
8304 : : {
1164 drowley@postgresql.o 8305 : 49642 : TableInfo *tinfo = &tblinfo[i];
8306 : :
208 peter@eisentraut.org 8307 [ + + ]: 49642 : if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7996 tgl@sss.pgh.pa.us 8308 : 42722 : continue;
8309 : :
8310 : : /* OK, we need info for this table */
1421 8311 [ + + ]: 6920 : if (tbloids->len > 1) /* do we have more than the '{'? */
8312 : 6793 : appendPQExpBufferChar(tbloids, ',');
1164 drowley@postgresql.o 8313 : 6920 : appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
8314 : : }
1421 tgl@sss.pgh.pa.us 8315 : 189 : appendPQExpBufferChar(tbloids, '}');
8316 : :
8317 : 189 : appendPQExpBufferStr(query,
8318 : : "SELECT c.tableoid, c.oid, "
8319 : : "conrelid, conname, confrelid, ");
8320 [ + - ]: 189 : if (fout->remoteVersion >= 110000)
8321 : 189 : appendPQExpBufferStr(query, "conindid, ");
8322 : : else
1421 tgl@sss.pgh.pa.us 8323 :UBC 0 : appendPQExpBufferStr(query, "0 AS conindid, ");
1421 tgl@sss.pgh.pa.us 8324 :CBC 189 : appendPQExpBuffer(query,
8325 : : "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
8326 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8327 : : "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
8328 : : "WHERE contype = 'f' ",
8329 : : tbloids->data);
8330 [ + - ]: 189 : if (fout->remoteVersion >= 110000)
8331 : 189 : appendPQExpBufferStr(query,
8332 : : "AND conparentid = 0 ");
8333 : 189 : appendPQExpBufferStr(query,
8334 : : "ORDER BY conrelid, conname");
8335 : :
8336 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8337 : :
8338 : 189 : ntups = PQntuples(res);
8339 : :
8340 : 189 : i_contableoid = PQfnumber(res, "tableoid");
8341 : 189 : i_conoid = PQfnumber(res, "oid");
8342 : 189 : i_conrelid = PQfnumber(res, "conrelid");
8343 : 189 : i_conname = PQfnumber(res, "conname");
8344 : 189 : i_confrelid = PQfnumber(res, "confrelid");
8345 : 189 : i_conindid = PQfnumber(res, "conindid");
8346 : 189 : i_condef = PQfnumber(res, "condef");
8347 : :
8348 : 189 : constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
8349 : :
8350 : 189 : curtblindx = -1;
8351 [ + + ]: 360 : for (int j = 0; j < ntups; j++)
8352 : : {
8353 : 171 : Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
8354 : : TableInfo *reftable;
8355 : :
8356 : : /*
8357 : : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8358 : : * order.
8359 : : */
8360 [ + + + + ]: 171 : if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
8361 : : {
8362 [ + - ]: 13533 : while (++curtblindx < numTables)
8363 : : {
8364 : 13533 : tbinfo = &tblinfo[curtblindx];
8365 [ + + ]: 13533 : if (tbinfo->dobj.catId.oid == conrelid)
8366 : 161 : break;
8367 : : }
8368 [ - + ]: 161 : if (curtblindx >= numTables)
1298 tgl@sss.pgh.pa.us 8369 :UBC 0 : pg_fatal("unrecognized table OID %u", conrelid);
8370 : : }
8371 : :
1421 tgl@sss.pgh.pa.us 8372 :CBC 171 : constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
8373 : 171 : constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
8374 : 171 : constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
8375 : 171 : AssignDumpId(&constrinfo[j].dobj);
8376 : 171 : constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
8377 : 171 : constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
8378 : 171 : constrinfo[j].contable = tbinfo;
8379 : 171 : constrinfo[j].condomain = NULL;
8380 : 171 : constrinfo[j].contype = 'f';
8381 : 171 : constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
8382 : 171 : constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
8383 : 171 : constrinfo[j].conindex = 0;
8384 : 171 : constrinfo[j].condeferrable = false;
8385 : 171 : constrinfo[j].condeferred = false;
8386 : 171 : constrinfo[j].conislocal = true;
8387 : 171 : constrinfo[j].separate = true;
8388 : :
8389 : : /*
8390 : : * Restoring an FK that points to a partitioned table requires that
8391 : : * all partition indexes have been attached beforehand. Ensure that
8392 : : * happens by making the constraint depend on each index partition
8393 : : * attach object.
8394 : : */
8395 : 171 : reftable = findTableByOid(constrinfo[j].confrelid);
8396 [ + - + + ]: 171 : if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
8397 : : {
8398 : 20 : Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));
8399 : :
8400 [ + - ]: 20 : if (indexOid != InvalidOid)
8401 : : {
8402 [ + - ]: 20 : for (int k = 0; k < reftable->numIndexes; k++)
8403 : : {
8404 : : IndxInfo *refidx;
8405 : :
8406 : : /* not our index? */
8407 [ - + ]: 20 : if (reftable->indexes[k].dobj.catId.oid != indexOid)
1421 tgl@sss.pgh.pa.us 8408 :UBC 0 : continue;
8409 : :
1421 tgl@sss.pgh.pa.us 8410 :CBC 20 : refidx = &reftable->indexes[k];
8411 : 20 : addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
8412 : 20 : break;
8413 : : }
8414 : : }
8415 : : }
8416 : : }
8417 : :
8418 : 189 : PQclear(res);
8419 : :
7996 8420 : 189 : destroyPQExpBuffer(query);
1421 8421 : 189 : destroyPQExpBuffer(tbloids);
7996 8422 : 189 : }
8423 : :
8424 : : /*
8425 : : * addConstrChildIdxDeps
8426 : : *
8427 : : * Recursive subroutine for getConstraints
8428 : : *
8429 : : * Given an object representing a foreign key constraint and an index on the
8430 : : * partitioned table it references, mark the constraint object as dependent
8431 : : * on the DO_INDEX_ATTACH object of each index partition, recursively
8432 : : * drilling down to their partitions if any. This ensures that the FK is not
8433 : : * restored until the index is fully marked valid.
8434 : : */
8435 : : static void
1720 peter@eisentraut.org 8436 : 45 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
8437 : : {
8438 : : SimplePtrListCell *cell;
8439 : :
1900 alvherre@alvh.no-ip. 8440 [ - + ]: 45 : Assert(dobj->objType == DO_FK_CONSTRAINT);
8441 : :
8442 [ + + ]: 155 : for (cell = refidx->partattaches.head; cell; cell = cell->next)
8443 : : {
8444 : 110 : IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
8445 : :
8446 : 110 : addObjectDependency(dobj, attach->dobj.dumpId);
8447 : :
8448 [ + + ]: 110 : if (attach->partitionIdx->partattaches.head != NULL)
8449 : 25 : addConstrChildIdxDeps(dobj, attach->partitionIdx);
8450 : : }
8451 : 45 : }
8452 : :
8453 : : /*
8454 : : * getDomainConstraints
8455 : : *
8456 : : * Get info about constraints on a domain.
8457 : : */
8458 : : static void
5012 rhaas@postgresql.org 8459 : 158 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
8460 : : {
8461 : : ConstraintInfo *constrinfo;
1421 tgl@sss.pgh.pa.us 8462 : 158 : PQExpBuffer query = createPQExpBuffer();
8463 : : PGresult *res;
8464 : : int i_tableoid,
8465 : : i_oid,
8466 : : i_conname,
8467 : : i_consrc,
8468 : : i_convalidated,
8469 : : i_contype;
8470 : : int ntups;
8471 : :
8472 [ + + ]: 158 : if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
8473 : : {
8474 : : /*
8475 : : * Set up query for constraint-specific details. For servers 17 and
8476 : : * up, domains have constraints of type 'n' as well as 'c', otherwise
8477 : : * just the latter.
8478 : : */
98 alvherre@kurilemu.de 8479 : 43 : appendPQExpBuffer(query,
8480 : : "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
8481 : : "SELECT tableoid, oid, conname, "
8482 : : "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8483 : : "convalidated, contype "
8484 : : "FROM pg_catalog.pg_constraint "
8485 : : "WHERE contypid = $1 AND contype IN (%s) "
8486 : : "ORDER BY conname",
8487 [ - + ]: 43 : fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
8488 : :
1421 tgl@sss.pgh.pa.us 8489 : 43 : ExecuteSqlStatement(fout, query->data);
8490 : :
8491 : 43 : fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
8492 : : }
8493 : :
8494 : 158 : printfPQExpBuffer(query,
8495 : : "EXECUTE getDomainConstraints('%u')",
8496 : : tyinfo->dobj.catId.oid);
8497 : :
5011 rhaas@postgresql.org 8498 : 158 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8499 : :
7996 tgl@sss.pgh.pa.us 8500 : 158 : ntups = PQntuples(res);
8501 : :
8502 : 158 : i_tableoid = PQfnumber(res, "tableoid");
8503 : 158 : i_oid = PQfnumber(res, "oid");
8504 : 158 : i_conname = PQfnumber(res, "conname");
8505 : 158 : i_consrc = PQfnumber(res, "consrc");
98 alvherre@kurilemu.de 8506 : 158 : i_convalidated = PQfnumber(res, "convalidated");
8507 : 158 : i_contype = PQfnumber(res, "contype");
8508 : :
5085 bruce@momjian.us 8509 : 158 : constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5787 8510 : 158 : tyinfo->domChecks = constrinfo;
8511 : :
8512 : : /* 'i' tracks result rows; 'j' counts CHECK constraints */
98 alvherre@kurilemu.de 8513 [ + + ]: 324 : for (int i = 0, j = 0; i < ntups; i++)
8514 : : {
8515 : 166 : bool validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
8516 : 166 : char contype = (PQgetvalue(res, i, i_contype))[0];
8517 : : ConstraintInfo *constraint;
8518 : :
8519 [ + + ]: 166 : if (contype == CONSTRAINT_CHECK)
8520 : : {
8521 : 113 : constraint = &constrinfo[j++];
8522 : 113 : tyinfo->nDomChecks++;
8523 : : }
8524 : : else
8525 : : {
8526 [ - + ]: 53 : Assert(contype == CONSTRAINT_NOTNULL);
8527 [ - + ]: 53 : Assert(tyinfo->notnull == NULL);
8528 : : /* use last item in array for the not-null constraint */
8529 : 53 : tyinfo->notnull = &(constrinfo[ntups - 1]);
8530 : 53 : constraint = tyinfo->notnull;
8531 : : }
8532 : :
8533 : 166 : constraint->dobj.objType = DO_CONSTRAINT;
8534 : 166 : constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8535 : 166 : constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8536 : 166 : AssignDumpId(&(constraint->dobj));
8537 : 166 : constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
8538 : 166 : constraint->dobj.namespace = tyinfo->dobj.namespace;
8539 : 166 : constraint->contable = NULL;
8540 : 166 : constraint->condomain = tyinfo;
8541 : 166 : constraint->contype = contype;
8542 : 166 : constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
8543 : 166 : constraint->confrelid = InvalidOid;
8544 : 166 : constraint->conindex = 0;
8545 : 166 : constraint->condeferrable = false;
8546 : 166 : constraint->condeferred = false;
8547 : 166 : constraint->conislocal = true;
8548 : :
8549 : 166 : constraint->separate = !validated;
8550 : :
8551 : : /*
8552 : : * Make the domain depend on the constraint, ensuring it won't be
8553 : : * output till any constraint dependencies are OK. If the constraint
8554 : : * has not been validated, it's going to be dumped after the domain
8555 : : * anyway, so this doesn't matter.
8556 : : */
5085 alvherre@alvh.no-ip. 8557 [ + + ]: 166 : if (validated)
98 alvherre@kurilemu.de 8558 : 161 : addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
8559 : : }
8560 : :
7996 tgl@sss.pgh.pa.us 8561 : 158 : PQclear(res);
8562 : :
8563 : 158 : destroyPQExpBuffer(query);
8564 : 158 : }
8565 : :
8566 : : /*
8567 : : * getRules
8568 : : * get basic information about every rule in the system
8569 : : */
8570 : : void
482 nathan@postgresql.or 8571 : 189 : getRules(Archive *fout)
8572 : : {
8573 : : PGresult *res;
8574 : : int ntups;
8575 : : int i;
7996 tgl@sss.pgh.pa.us 8576 : 189 : PQExpBuffer query = createPQExpBuffer();
8577 : : RuleInfo *ruleinfo;
8578 : : int i_tableoid;
8579 : : int i_oid;
8580 : : int i_rulename;
8581 : : int i_ruletable;
8582 : : int i_ev_type;
8583 : : int i_is_instead;
8584 : : int i_ev_enabled;
8585 : :
1413 8586 : 189 : appendPQExpBufferStr(query, "SELECT "
8587 : : "tableoid, oid, rulename, "
8588 : : "ev_class AS ruletable, ev_type, is_instead, "
8589 : : "ev_enabled "
8590 : : "FROM pg_rewrite "
8591 : : "ORDER BY oid");
8592 : :
5011 rhaas@postgresql.org 8593 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8594 : :
7996 tgl@sss.pgh.pa.us 8595 : 189 : ntups = PQntuples(res);
8596 : :
5085 bruce@momjian.us 8597 : 189 : ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
8598 : :
7996 tgl@sss.pgh.pa.us 8599 : 189 : i_tableoid = PQfnumber(res, "tableoid");
8600 : 189 : i_oid = PQfnumber(res, "oid");
8601 : 189 : i_rulename = PQfnumber(res, "rulename");
8602 : 189 : i_ruletable = PQfnumber(res, "ruletable");
8603 : 189 : i_ev_type = PQfnumber(res, "ev_type");
8604 : 189 : i_is_instead = PQfnumber(res, "is_instead");
6797 JanWieck@Yahoo.com 8605 : 189 : i_ev_enabled = PQfnumber(res, "ev_enabled");
8606 : :
7996 tgl@sss.pgh.pa.us 8607 [ + + ]: 29496 : for (i = 0; i < ntups; i++)
8608 : : {
8609 : : Oid ruletableoid;
8610 : :
8611 : 29307 : ruleinfo[i].dobj.objType = DO_RULE;
8612 : 29307 : ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8613 : 29307 : ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8614 : 29307 : AssignDumpId(&ruleinfo[i].dobj);
5085 bruce@momjian.us 8615 : 29307 : ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7996 tgl@sss.pgh.pa.us 8616 : 29307 : ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
8617 : 29307 : ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7532 8618 [ - + ]: 29307 : if (ruleinfo[i].ruletable == NULL)
1298 tgl@sss.pgh.pa.us 8619 :UBC 0 : pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
8620 : : ruletableoid, ruleinfo[i].dobj.catId.oid);
7908 tgl@sss.pgh.pa.us 8621 :CBC 29307 : ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7179 8622 : 29307 : ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7996 8623 : 29307 : ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
8624 : 29307 : ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
6797 JanWieck@Yahoo.com 8625 : 29307 : ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7996 tgl@sss.pgh.pa.us 8626 [ + - ]: 29307 : if (ruleinfo[i].ruletable)
8627 : : {
8628 : : /*
8629 : : * If the table is a view or materialized view, force its ON
8630 : : * SELECT rule to be sorted before the view itself --- this
8631 : : * ensures that any dependencies for the rule affect the table's
8632 : : * positioning. Other rules are forced to appear after their
8633 : : * table.
8634 : : */
4621 kgrittn@postgresql.o 8635 [ + + ]: 29307 : if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
4600 andrew@dunslane.net 8636 [ + + ]: 702 : ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7996 tgl@sss.pgh.pa.us 8637 [ + + + - ]: 29076 : ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
8638 : : {
8639 : 28656 : addObjectDependency(&ruleinfo[i].ruletable->dobj,
8640 : 28656 : ruleinfo[i].dobj.dumpId);
8641 : : /* We'll merge the rule into CREATE VIEW, if possible */
7622 8642 : 28656 : ruleinfo[i].separate = false;
8643 : : }
8644 : : else
8645 : : {
7996 8646 : 651 : addObjectDependency(&ruleinfo[i].dobj,
8647 : 651 : ruleinfo[i].ruletable->dobj.dumpId);
7622 8648 : 651 : ruleinfo[i].separate = true;
8649 : : }
8650 : : }
8651 : : else
7622 tgl@sss.pgh.pa.us 8652 :UBC 0 : ruleinfo[i].separate = true;
8653 : : }
8654 : :
7996 tgl@sss.pgh.pa.us 8655 :CBC 189 : PQclear(res);
8656 : :
8657 : 189 : destroyPQExpBuffer(query);
8658 : 189 : }
8659 : :
8660 : : /*
8661 : : * getTriggers
8662 : : * get information about every trigger on a dumpable table
8663 : : *
8664 : : * Note: trigger data is not returned directly to the caller, but it
8665 : : * does get entered into the DumpableObject tables.
8666 : : */
8667 : : void
5012 rhaas@postgresql.org 8668 : 189 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
8669 : : {
7996 tgl@sss.pgh.pa.us 8670 : 189 : PQExpBuffer query = createPQExpBuffer();
1421 8671 : 189 : PQExpBuffer tbloids = createPQExpBuffer();
8672 : : PGresult *res;
8673 : : int ntups;
8674 : : int curtblindx;
8675 : : TriggerInfo *tginfo;
8676 : : int i_tableoid,
8677 : : i_oid,
8678 : : i_tgrelid,
8679 : : i_tgname,
8680 : : i_tgenabled,
8681 : : i_tgispartition,
8682 : : i_tgdef;
8683 : :
8684 : : /*
8685 : : * We want to perform just one query against pg_trigger. However, we
8686 : : * mustn't try to select every row of the catalog and then sort it out on
8687 : : * the client side, because some of the server-side functions we need
8688 : : * would be unsafe to apply to tables we don't have lock on. Hence, we
8689 : : * build an array of the OIDs of tables we care about (and now have lock
8690 : : * on!), and use a WHERE clause to constrain which rows are selected.
8691 : : */
8692 : 189 : appendPQExpBufferChar(tbloids, '{');
8693 [ + + ]: 49831 : for (int i = 0; i < numTables; i++)
8694 : : {
7996 8695 : 49642 : TableInfo *tbinfo = &tblinfo[i];
8696 : :
3491 sfrost@snowman.net 8697 [ + + ]: 49642 : if (!tbinfo->hastriggers ||
8698 [ + + ]: 1114 : !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7996 tgl@sss.pgh.pa.us 8699 : 48790 : continue;
8700 : :
8701 : : /* OK, we need info for this table */
1421 8702 [ + + ]: 852 : if (tbloids->len > 1) /* do we have more than the '{'? */
8703 : 801 : appendPQExpBufferChar(tbloids, ',');
8704 : 852 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8705 : : }
8706 : 189 : appendPQExpBufferChar(tbloids, '}');
8707 : :
1391 alvherre@alvh.no-ip. 8708 [ + - ]: 189 : if (fout->remoteVersion >= 150000)
8709 : : {
8710 : : /*
8711 : : * NB: think not to use pretty=true in pg_get_triggerdef. It could
8712 : : * result in non-forward-compatible dumps of WHEN clauses due to
8713 : : * under-parenthesization.
8714 : : *
8715 : : * NB: We need to see partition triggers in case the tgenabled flag
8716 : : * has been changed from the parent.
8717 : : */
8718 : 189 : appendPQExpBuffer(query,
8719 : : "SELECT t.tgrelid, t.tgname, "
8720 : : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8721 : : "t.tgenabled, t.tableoid, t.oid, "
8722 : : "t.tgparentid <> 0 AS tgispartition\n"
8723 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8724 : : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8725 : : "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8726 : : "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
8727 : : "OR t.tgenabled != u.tgenabled) "
8728 : : "ORDER BY t.tgrelid, t.tgname",
8729 : : tbloids->data);
8730 : : }
1391 alvherre@alvh.no-ip. 8731 [ # # ]:UBC 0 : else if (fout->remoteVersion >= 130000)
8732 : : {
8733 : : /*
8734 : : * NB: think not to use pretty=true in pg_get_triggerdef. It could
8735 : : * result in non-forward-compatible dumps of WHEN clauses due to
8736 : : * under-parenthesization.
8737 : : *
8738 : : * NB: We need to see tgisinternal triggers in partitions, in case the
8739 : : * tgenabled flag has been changed from the parent.
8740 : : */
1421 tgl@sss.pgh.pa.us 8741 : 0 : appendPQExpBuffer(query,
8742 : : "SELECT t.tgrelid, t.tgname, "
8743 : : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8744 : : "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
8745 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8746 : : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8747 : : "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8748 : : "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
8749 : : "ORDER BY t.tgrelid, t.tgname",
8750 : : tbloids->data);
8751 : : }
8752 [ # # ]: 0 : else if (fout->remoteVersion >= 110000)
8753 : : {
8754 : : /*
8755 : : * NB: We need to see tgisinternal triggers in partitions, in case the
8756 : : * tgenabled flag has been changed from the parent. No tgparentid in
8757 : : * version 11-12, so we have to match them via pg_depend.
8758 : : *
8759 : : * See above about pretty=true in pg_get_triggerdef.
8760 : : */
8761 : 0 : appendPQExpBuffer(query,
8762 : : "SELECT t.tgrelid, t.tgname, "
8763 : : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8764 : : "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
8765 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8766 : : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8767 : : "LEFT JOIN pg_catalog.pg_depend AS d ON "
8768 : : " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8769 : : " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8770 : : " d.objid = t.oid "
8771 : : "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
8772 : : "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
8773 : : "ORDER BY t.tgrelid, t.tgname",
8774 : : tbloids->data);
8775 : : }
8776 : : else
8777 : : {
8778 : : /* See above about pretty=true in pg_get_triggerdef */
8779 : 0 : appendPQExpBuffer(query,
8780 : : "SELECT t.tgrelid, t.tgname, "
8781 : : "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8782 : : "t.tgenabled, false as tgispartition, "
8783 : : "t.tableoid, t.oid "
8784 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8785 : : "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8786 : : "WHERE NOT tgisinternal "
8787 : : "ORDER BY t.tgrelid, t.tgname",
8788 : : tbloids->data);
8789 : : }
8790 : :
1421 tgl@sss.pgh.pa.us 8791 :CBC 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8792 : :
8793 : 189 : ntups = PQntuples(res);
8794 : :
8795 : 189 : i_tableoid = PQfnumber(res, "tableoid");
8796 : 189 : i_oid = PQfnumber(res, "oid");
8797 : 189 : i_tgrelid = PQfnumber(res, "tgrelid");
8798 : 189 : i_tgname = PQfnumber(res, "tgname");
8799 : 189 : i_tgenabled = PQfnumber(res, "tgenabled");
1391 alvherre@alvh.no-ip. 8800 : 189 : i_tgispartition = PQfnumber(res, "tgispartition");
1421 tgl@sss.pgh.pa.us 8801 : 189 : i_tgdef = PQfnumber(res, "tgdef");
8802 : :
8803 : 189 : tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
8804 : :
8805 : : /*
8806 : : * Outer loop iterates once per table, not once per row. Incrementing of
8807 : : * j is handled by the inner loop.
8808 : : */
8809 : 189 : curtblindx = -1;
8810 [ + + ]: 495 : for (int j = 0; j < ntups;)
8811 : : {
8812 : 306 : Oid tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
8813 : 306 : TableInfo *tbinfo = NULL;
8814 : : int numtrigs;
8815 : :
8816 : : /* Count rows for this table */
8817 [ + + ]: 523 : for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
8818 [ + + ]: 472 : if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
8819 : 255 : break;
8820 : :
8821 : : /*
8822 : : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8823 : : * order.
8824 : : */
8825 [ + - ]: 16042 : while (++curtblindx < numTables)
8826 : : {
8827 : 16042 : tbinfo = &tblinfo[curtblindx];
8828 [ + + ]: 16042 : if (tbinfo->dobj.catId.oid == tgrelid)
8829 : 306 : break;
8830 : : }
8831 [ - + ]: 306 : if (curtblindx >= numTables)
1298 tgl@sss.pgh.pa.us 8832 :UBC 0 : pg_fatal("unrecognized table OID %u", tgrelid);
8833 : :
8834 : : /* Save data for this table */
1421 tgl@sss.pgh.pa.us 8835 :CBC 306 : tbinfo->triggers = tginfo + j;
8836 : 306 : tbinfo->numTriggers = numtrigs;
8837 : :
8838 [ + + ]: 829 : for (int c = 0; c < numtrigs; c++, j++)
8839 : : {
7996 8840 : 523 : tginfo[j].dobj.objType = DO_TRIGGER;
8841 : 523 : tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8842 : 523 : tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8843 : 523 : AssignDumpId(&tginfo[j].dobj);
5085 bruce@momjian.us 8844 : 523 : tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7908 tgl@sss.pgh.pa.us 8845 : 523 : tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7996 8846 : 523 : tginfo[j].tgtable = tbinfo;
6797 JanWieck@Yahoo.com 8847 : 523 : tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
1391 alvherre@alvh.no-ip. 8848 : 523 : tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
652 peter@eisentraut.org 8849 : 523 : tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
8850 : : }
8851 : : }
8852 : :
1421 tgl@sss.pgh.pa.us 8853 : 189 : PQclear(res);
8854 : :
7996 8855 : 189 : destroyPQExpBuffer(query);
1421 8856 : 189 : destroyPQExpBuffer(tbloids);
7996 8857 : 189 : }
8858 : :
8859 : : /*
8860 : : * getEventTriggers
8861 : : * get information about event triggers
8862 : : */
8863 : : void
482 nathan@postgresql.or 8864 : 189 : getEventTriggers(Archive *fout)
8865 : : {
8866 : : int i;
8867 : : PQExpBuffer query;
8868 : : PGresult *res;
8869 : : EventTriggerInfo *evtinfo;
8870 : : int i_tableoid,
8871 : : i_oid,
8872 : : i_evtname,
8873 : : i_evtevent,
8874 : : i_evtowner,
8875 : : i_evttags,
8876 : : i_evtfname,
8877 : : i_evtenabled;
8878 : : int ntups;
8879 : :
8880 : : /* Before 9.3, there are no event triggers */
4849 rhaas@postgresql.org 8881 [ - + ]: 189 : if (fout->remoteVersion < 90300)
482 nathan@postgresql.or 8882 :UBC 0 : return;
8883 : :
4488 sfrost@snowman.net 8884 :CBC 189 : query = createPQExpBuffer();
8885 : :
1147 drowley@postgresql.o 8886 : 189 : appendPQExpBufferStr(query,
8887 : : "SELECT e.tableoid, e.oid, evtname, evtenabled, "
8888 : : "evtevent, evtowner, "
8889 : : "array_to_string(array("
8890 : : "select quote_literal(x) "
8891 : : " from unnest(evttags) as t(x)), ', ') as evttags, "
8892 : : "e.evtfoid::regproc as evtfname "
8893 : : "FROM pg_event_trigger e "
8894 : : "ORDER BY e.oid");
8895 : :
4849 rhaas@postgresql.org 8896 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8897 : :
8898 : 189 : ntups = PQntuples(res);
8899 : :
8900 : 189 : evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
8901 : :
8902 : 189 : i_tableoid = PQfnumber(res, "tableoid");
8903 : 189 : i_oid = PQfnumber(res, "oid");
8904 : 189 : i_evtname = PQfnumber(res, "evtname");
8905 : 189 : i_evtevent = PQfnumber(res, "evtevent");
8906 : 189 : i_evtowner = PQfnumber(res, "evtowner");
8907 : 189 : i_evttags = PQfnumber(res, "evttags");
8908 : 189 : i_evtfname = PQfnumber(res, "evtfname");
8909 : 189 : i_evtenabled = PQfnumber(res, "evtenabled");
8910 : :
8911 [ + + ]: 241 : for (i = 0; i < ntups; i++)
8912 : : {
8913 : 52 : evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
8914 : 52 : evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8915 : 52 : evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8916 : 52 : AssignDumpId(&evtinfo[i].dobj);
8917 : 52 : evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
8918 : 52 : evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
8919 : 52 : evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
1396 tgl@sss.pgh.pa.us 8920 : 52 : evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
4849 rhaas@postgresql.org 8921 : 52 : evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
8922 : 52 : evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
8923 : 52 : evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
8924 : :
8925 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 8926 : 52 : selectDumpableObject(&(evtinfo[i].dobj), fout);
8927 : : }
8928 : :
4849 rhaas@postgresql.org 8929 : 189 : PQclear(res);
8930 : :
8931 : 189 : destroyPQExpBuffer(query);
8932 : : }
8933 : :
8934 : : /*
8935 : : * getProcLangs
8936 : : * get basic information about every procedural language in the system
8937 : : *
8938 : : * NB: this must run after getFuncs() because we assume we can do
8939 : : * findFuncByOid().
8940 : : */
8941 : : void
482 nathan@postgresql.or 8942 : 189 : getProcLangs(Archive *fout)
8943 : : {
8944 : : PGresult *res;
8945 : : int ntups;
8946 : : int i;
7996 tgl@sss.pgh.pa.us 8947 : 189 : PQExpBuffer query = createPQExpBuffer();
8948 : : ProcLangInfo *planginfo;
8949 : : int i_tableoid;
8950 : : int i_oid;
8951 : : int i_lanname;
8952 : : int i_lanpltrusted;
8953 : : int i_lanplcallfoid;
8954 : : int i_laninline;
8955 : : int i_lanvalidator;
8956 : : int i_lanacl;
8957 : : int i_acldefault;
8958 : : int i_lanowner;
8959 : :
1147 drowley@postgresql.o 8960 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8961 : : "lanname, lanpltrusted, lanplcallfoid, "
8962 : : "laninline, lanvalidator, "
8963 : : "lanacl, "
8964 : : "acldefault('l', lanowner) AS acldefault, "
8965 : : "lanowner "
8966 : : "FROM pg_language "
8967 : : "WHERE lanispl "
8968 : : "ORDER BY oid");
8969 : :
5011 rhaas@postgresql.org 8970 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8971 : :
7996 tgl@sss.pgh.pa.us 8972 : 189 : ntups = PQntuples(res);
8973 : :
5085 bruce@momjian.us 8974 : 189 : planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
8975 : :
7996 tgl@sss.pgh.pa.us 8976 : 189 : i_tableoid = PQfnumber(res, "tableoid");
8977 : 189 : i_oid = PQfnumber(res, "oid");
8978 : 189 : i_lanname = PQfnumber(res, "lanname");
8979 : 189 : i_lanpltrusted = PQfnumber(res, "lanpltrusted");
8980 : 189 : i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
5879 8981 : 189 : i_laninline = PQfnumber(res, "laninline");
7268 8982 : 189 : i_lanvalidator = PQfnumber(res, "lanvalidator");
8983 : 189 : i_lanacl = PQfnumber(res, "lanacl");
1421 8984 : 189 : i_acldefault = PQfnumber(res, "acldefault");
7268 8985 : 189 : i_lanowner = PQfnumber(res, "lanowner");
8986 : :
7996 8987 [ + + ]: 423 : for (i = 0; i < ntups; i++)
8988 : : {
8989 : 234 : planginfo[i].dobj.objType = DO_PROCLANG;
8990 : 234 : planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8991 : 234 : planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8992 : 234 : AssignDumpId(&planginfo[i].dobj);
8993 : :
5085 bruce@momjian.us 8994 : 234 : planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
1421 tgl@sss.pgh.pa.us 8995 : 234 : planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
8996 : 234 : planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
8997 : 234 : planginfo[i].dacl.privtype = 0;
8998 : 234 : planginfo[i].dacl.initprivs = NULL;
7996 8999 : 234 : planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
9000 : 234 : planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
3731 9001 : 234 : planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
9002 : 234 : planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
1396 9003 : 234 : planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
9004 : :
9005 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 9006 : 234 : selectDumpableProcLang(&(planginfo[i]), fout);
9007 : :
9008 : : /* Mark whether language has an ACL */
1421 tgl@sss.pgh.pa.us 9009 [ + + ]: 234 : if (!PQgetisnull(res, i, i_lanacl))
9010 : 45 : planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9011 : : }
9012 : :
7996 9013 : 189 : PQclear(res);
9014 : :
9015 : 189 : destroyPQExpBuffer(query);
9016 : 189 : }
9017 : :
9018 : : /*
9019 : : * getCasts
9020 : : * get basic information about most casts in the system
9021 : : *
9022 : : * Skip casts from a range to its multirange, since we'll create those
9023 : : * automatically.
9024 : : */
9025 : : void
482 nathan@postgresql.or 9026 : 189 : getCasts(Archive *fout)
9027 : : {
9028 : : PGresult *res;
9029 : : int ntups;
9030 : : int i;
7996 tgl@sss.pgh.pa.us 9031 : 189 : PQExpBuffer query = createPQExpBuffer();
9032 : : CastInfo *castinfo;
9033 : : int i_tableoid;
9034 : : int i_oid;
9035 : : int i_castsource;
9036 : : int i_casttarget;
9037 : : int i_castfunc;
9038 : : int i_castcontext;
9039 : : int i_castmethod;
9040 : :
1772 akorotkov@postgresql 9041 [ + - ]: 189 : if (fout->remoteVersion >= 140000)
9042 : : {
9043 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9044 : : "castsource, casttarget, castfunc, castcontext, "
9045 : : "castmethod "
9046 : : "FROM pg_cast c "
9047 : : "WHERE NOT EXISTS ( "
9048 : : "SELECT 1 FROM pg_range r "
9049 : : "WHERE c.castsource = r.rngtypid "
9050 : : "AND c.casttarget = r.rngmultitypid "
9051 : : ") "
9052 : : "ORDER BY 3,4");
9053 : : }
9054 : : else
9055 : : {
4361 heikki.linnakangas@i 9056 :UBC 0 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9057 : : "castsource, casttarget, castfunc, castcontext, "
9058 : : "castmethod "
9059 : : "FROM pg_cast ORDER BY 3,4");
9060 : : }
9061 : :
5011 rhaas@postgresql.org 9062 :CBC 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9063 : :
7996 tgl@sss.pgh.pa.us 9064 : 189 : ntups = PQntuples(res);
9065 : :
5085 bruce@momjian.us 9066 : 189 : castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
9067 : :
7996 tgl@sss.pgh.pa.us 9068 : 189 : i_tableoid = PQfnumber(res, "tableoid");
9069 : 189 : i_oid = PQfnumber(res, "oid");
9070 : 189 : i_castsource = PQfnumber(res, "castsource");
9071 : 189 : i_casttarget = PQfnumber(res, "casttarget");
9072 : 189 : i_castfunc = PQfnumber(res, "castfunc");
9073 : 189 : i_castcontext = PQfnumber(res, "castcontext");
6205 heikki.linnakangas@i 9074 : 189 : i_castmethod = PQfnumber(res, "castmethod");
9075 : :
7996 tgl@sss.pgh.pa.us 9076 [ + + ]: 44880 : for (i = 0; i < ntups; i++)
9077 : : {
9078 : : PQExpBufferData namebuf;
9079 : : TypeInfo *sTypeInfo;
9080 : : TypeInfo *tTypeInfo;
9081 : :
9082 : 44691 : castinfo[i].dobj.objType = DO_CAST;
9083 : 44691 : castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9084 : 44691 : castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9085 : 44691 : AssignDumpId(&castinfo[i].dobj);
9086 : 44691 : castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
9087 : 44691 : castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
9088 : 44691 : castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
9089 : 44691 : castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
6205 heikki.linnakangas@i 9090 : 44691 : castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
9091 : :
9092 : : /*
9093 : : * Try to name cast as concatenation of typnames. This is only used
9094 : : * for purposes of sorting. If we fail to find either type, the name
9095 : : * will be an empty string.
9096 : : */
7908 tgl@sss.pgh.pa.us 9097 : 44691 : initPQExpBuffer(&namebuf);
9098 : 44691 : sTypeInfo = findTypeByOid(castinfo[i].castsource);
9099 : 44691 : tTypeInfo = findTypeByOid(castinfo[i].casttarget);
9100 [ + - + - ]: 44691 : if (sTypeInfo && tTypeInfo)
9101 : 44691 : appendPQExpBuffer(&namebuf, "%s %s",
9102 : : sTypeInfo->dobj.name, tTypeInfo->dobj.name);
9103 : 44691 : castinfo[i].dobj.name = namebuf.data;
9104 : :
9105 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 9106 : 44691 : selectDumpableCast(&(castinfo[i]), fout);
9107 : : }
9108 : :
7996 tgl@sss.pgh.pa.us 9109 : 189 : PQclear(res);
9110 : :
9111 : 189 : destroyPQExpBuffer(query);
9112 : 189 : }
9113 : :
9114 : : static char *
3837 peter_e@gmx.net 9115 : 88 : get_language_name(Archive *fout, Oid langid)
9116 : : {
9117 : : PQExpBuffer query;
9118 : : PGresult *res;
9119 : : char *lanname;
9120 : :
9121 : 88 : query = createPQExpBuffer();
9122 : 88 : appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
9123 : 88 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
9124 : 88 : lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
9125 : 88 : destroyPQExpBuffer(query);
9126 : 88 : PQclear(res);
9127 : :
9128 : 88 : return lanname;
9129 : : }
9130 : :
9131 : : /*
9132 : : * getTransforms
9133 : : * get basic information about every transform in the system
9134 : : */
9135 : : void
482 nathan@postgresql.or 9136 : 189 : getTransforms(Archive *fout)
9137 : : {
9138 : : PGresult *res;
9139 : : int ntups;
9140 : : int i;
9141 : : PQExpBuffer query;
9142 : : TransformInfo *transforminfo;
9143 : : int i_tableoid;
9144 : : int i_oid;
9145 : : int i_trftype;
9146 : : int i_trflang;
9147 : : int i_trffromsql;
9148 : : int i_trftosql;
9149 : :
9150 : : /* Transforms didn't exist pre-9.5 */
3837 peter_e@gmx.net 9151 [ - + ]: 189 : if (fout->remoteVersion < 90500)
482 nathan@postgresql.or 9152 :UBC 0 : return;
9153 : :
3826 magnus@hagander.net 9154 :CBC 189 : query = createPQExpBuffer();
9155 : :
2307 drowley@postgresql.o 9156 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, "
9157 : : "trftype, trflang, trffromsql::oid, trftosql::oid "
9158 : : "FROM pg_transform "
9159 : : "ORDER BY 3,4");
9160 : :
3837 peter_e@gmx.net 9161 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9162 : :
9163 : 189 : ntups = PQntuples(res);
9164 : :
9165 : 189 : transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
9166 : :
9167 : 189 : i_tableoid = PQfnumber(res, "tableoid");
9168 : 189 : i_oid = PQfnumber(res, "oid");
9169 : 189 : i_trftype = PQfnumber(res, "trftype");
9170 : 189 : i_trflang = PQfnumber(res, "trflang");
9171 : 189 : i_trffromsql = PQfnumber(res, "trffromsql");
9172 : 189 : i_trftosql = PQfnumber(res, "trftosql");
9173 : :
9174 [ + + ]: 241 : for (i = 0; i < ntups; i++)
9175 : : {
9176 : : PQExpBufferData namebuf;
9177 : : TypeInfo *typeInfo;
9178 : : char *lanname;
9179 : :
9180 : 52 : transforminfo[i].dobj.objType = DO_TRANSFORM;
9181 : 52 : transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9182 : 52 : transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9183 : 52 : AssignDumpId(&transforminfo[i].dobj);
9184 : 52 : transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
9185 : 52 : transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
9186 : 52 : transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
9187 : 52 : transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
9188 : :
9189 : : /*
9190 : : * Try to name transform as concatenation of type and language name.
9191 : : * This is only used for purposes of sorting. If we fail to find
9192 : : * either, the name will be an empty string.
9193 : : */
9194 : 52 : initPQExpBuffer(&namebuf);
9195 : 52 : typeInfo = findTypeByOid(transforminfo[i].trftype);
9196 : 52 : lanname = get_language_name(fout, transforminfo[i].trflang);
9197 [ + - + - ]: 52 : if (typeInfo && lanname)
9198 : 52 : appendPQExpBuffer(&namebuf, "%s %s",
9199 : : typeInfo->dobj.name, lanname);
9200 : 52 : transforminfo[i].dobj.name = namebuf.data;
3760 tgl@sss.pgh.pa.us 9201 : 52 : free(lanname);
9202 : :
9203 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 9204 : 52 : selectDumpableObject(&(transforminfo[i].dobj), fout);
9205 : : }
9206 : :
3837 peter_e@gmx.net 9207 : 189 : PQclear(res);
9208 : :
9209 : 189 : destroyPQExpBuffer(query);
9210 : : }
9211 : :
9212 : : /*
9213 : : * getTableAttrs -
9214 : : * for each interesting table, read info about its attributes
9215 : : * (names, types, default values, CHECK constraints, etc)
9216 : : *
9217 : : * modifies tblinfo
9218 : : */
9219 : : void
3575 tgl@sss.pgh.pa.us 9220 : 189 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
9221 : : {
9222 : 189 : DumpOptions *dopt = fout->dopt;
7996 9223 : 189 : PQExpBuffer q = createPQExpBuffer();
1421 9224 : 189 : PQExpBuffer tbloids = createPQExpBuffer();
9225 : 189 : PQExpBuffer checkoids = createPQExpBuffer();
203 alvherre@alvh.no-ip. 9226 : 189 : PQExpBuffer invalidnotnulloids = NULL;
9227 : : PGresult *res;
9228 : : int ntups;
9229 : : int curtblindx;
9230 : : int i_attrelid;
9231 : : int i_attnum;
9232 : : int i_attname;
9233 : : int i_atttypname;
9234 : : int i_attstattarget;
9235 : : int i_attstorage;
9236 : : int i_typstorage;
9237 : : int i_attidentity;
9238 : : int i_attgenerated;
9239 : : int i_attisdropped;
9240 : : int i_attlen;
9241 : : int i_attalign;
9242 : : int i_attislocal;
9243 : : int i_notnull_name;
9244 : : int i_notnull_comment;
9245 : : int i_notnull_noinherit;
9246 : : int i_notnull_islocal;
9247 : : int i_notnull_invalidoid;
9248 : : int i_attoptions;
9249 : : int i_attcollation;
9250 : : int i_attcompression;
9251 : : int i_attfdwoptions;
9252 : : int i_attmissingval;
9253 : : int i_atthasdef;
9254 : :
9255 : : /*
9256 : : * We want to perform just one query against pg_attribute, and then just
9257 : : * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
9258 : : * (for CHECK constraints and for NOT NULL constraints). However, we
9259 : : * mustn't try to select every row of those catalogs and then sort it out
9260 : : * on the client side, because some of the server-side functions we need
9261 : : * would be unsafe to apply to tables we don't have lock on. Hence, we
9262 : : * build an array of the OIDs of tables we care about (and now have lock
9263 : : * on!), and use a WHERE clause to constrain which rows are selected.
9264 : : */
1421 tgl@sss.pgh.pa.us 9265 : 189 : appendPQExpBufferChar(tbloids, '{');
9266 : 189 : appendPQExpBufferChar(checkoids, '{');
1936 peter@eisentraut.org 9267 [ + + ]: 49831 : for (int i = 0; i < numTables; i++)
9268 : : {
8454 bruce@momjian.us 9269 : 49642 : TableInfo *tbinfo = &tblinfo[i];
9270 : :
9271 : : /* Don't bother to collect info for sequences */
8470 tgl@sss.pgh.pa.us 9272 [ + + ]: 49642 : if (tbinfo->relkind == RELKIND_SEQUENCE)
10277 bruce@momjian.us 9273 : 638 : continue;
9274 : :
9275 : : /*
9276 : : * Don't bother with uninteresting tables, either. For binary
9277 : : * upgrades, this is bypassed for pg_largeobject_metadata and
9278 : : * pg_shdepend so that the columns names are collected for the
9279 : : * corresponding COPY commands. Restoring the data for those catalogs
9280 : : * is faster than restoring the equivalent set of large object
9281 : : * commands. We can only do this for upgrades from v12 and newer; in
9282 : : * older versions, pg_largeobject_metadata was created WITH OIDS, so
9283 : : * the OID column is hidden and won't be dumped.
9284 : : */
101 nathan@postgresql.or 9285 [ + + ]:GNC 49004 : if (!tbinfo->interesting &&
9286 [ + + + - ]: 42437 : !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
9287 [ + + ]: 7758 : (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
9288 [ + + ]: 7722 : tbinfo->dobj.catId.oid == SharedDependRelationId)))
8571 tgl@sss.pgh.pa.us 9289 :CBC 42365 : continue;
9290 : :
9291 : : /* OK, we need info for this table */
1421 9292 [ + + ]: 6639 : if (tbloids->len > 1) /* do we have more than the '{'? */
9293 : 6494 : appendPQExpBufferChar(tbloids, ',');
9294 : 6639 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
9295 : :
9296 [ + + ]: 6639 : if (tbinfo->ncheck > 0)
9297 : : {
9298 : : /* Also make a list of the ones with check constraints */
9299 [ + + ]: 528 : if (checkoids->len > 1) /* do we have more than the '{'? */
9300 : 459 : appendPQExpBufferChar(checkoids, ',');
9301 : 528 : appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
9302 : : }
9303 : : }
9304 : 189 : appendPQExpBufferChar(tbloids, '}');
9305 : 189 : appendPQExpBufferChar(checkoids, '}');
9306 : :
9307 : : /*
9308 : : * Find all the user attributes and their types.
9309 : : *
9310 : : * Since we only want to dump COLLATE clauses for attributes whose
9311 : : * collation is different from their type's default, we use a CASE here to
9312 : : * suppress uninteresting attcollations cheaply.
9313 : : */
9314 : 189 : appendPQExpBufferStr(q,
9315 : : "SELECT\n"
9316 : : "a.attrelid,\n"
9317 : : "a.attnum,\n"
9318 : : "a.attname,\n"
9319 : : "a.attstattarget,\n"
9320 : : "a.attstorage,\n"
9321 : : "t.typstorage,\n"
9322 : : "a.atthasdef,\n"
9323 : : "a.attisdropped,\n"
9324 : : "a.attlen,\n"
9325 : : "a.attalign,\n"
9326 : : "a.attislocal,\n"
9327 : : "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
9328 : : "array_to_string(a.attoptions, ', ') AS attoptions,\n"
9329 : : "CASE WHEN a.attcollation <> t.typcollation "
9330 : : "THEN a.attcollation ELSE 0 END AS attcollation,\n"
9331 : : "pg_catalog.array_to_string(ARRAY("
9332 : : "SELECT pg_catalog.quote_ident(option_name) || "
9333 : : "' ' || pg_catalog.quote_literal(option_value) "
9334 : : "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
9335 : : "ORDER BY option_name"
9336 : : "), E',\n ') AS attfdwoptions,\n");
9337 : :
9338 : : /*
9339 : : * Find out any NOT NULL markings for each column. In 18 and up we read
9340 : : * pg_constraint to obtain the constraint name, and for valid constraints
9341 : : * also pg_description to obtain its comment. notnull_noinherit is set
9342 : : * according to the NO INHERIT property. For versions prior to 18, we
9343 : : * store an empty string as the name when a constraint is marked as
9344 : : * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
9345 : : * without a name); also, such cases are never NO INHERIT.
9346 : : *
9347 : : * For invalid constraints, we need to store their OIDs for processing
9348 : : * elsewhere, so we bring the pg_constraint.oid value when the constraint
9349 : : * is invalid, and NULL otherwise. Their comments are handled not here
9350 : : * but by collectComments, because they're their own dumpable object.
9351 : : *
9352 : : * We track in notnull_islocal whether the constraint was defined directly
9353 : : * in this table or via an ancestor, for binary upgrade. flagInhAttrs
9354 : : * might modify this later.
9355 : : */
353 alvherre@alvh.no-ip. 9356 [ + - ]: 189 : if (fout->remoteVersion >= 180000)
9357 : 189 : appendPQExpBufferStr(q,
9358 : : "co.conname AS notnull_name,\n"
9359 : : "CASE WHEN co.convalidated THEN pt.description"
9360 : : " ELSE NULL END AS notnull_comment,\n"
9361 : : "CASE WHEN NOT co.convalidated THEN co.oid "
9362 : : "ELSE NULL END AS notnull_invalidoid,\n"
9363 : : "co.connoinherit AS notnull_noinherit,\n"
9364 : : "co.conislocal AS notnull_islocal,\n");
9365 : : else
353 alvherre@alvh.no-ip. 9366 :UBC 0 : appendPQExpBufferStr(q,
9367 : : "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
9368 : : "NULL AS notnull_comment,\n"
9369 : : "NULL AS notnull_invalidoid,\n"
9370 : : "false AS notnull_noinherit,\n"
9371 : : "CASE WHEN a.attislocal THEN true\n"
9372 : : " WHEN a.attnotnull AND NOT a.attislocal THEN true\n"
9373 : : " ELSE false\n"
9374 : : "END AS notnull_islocal,\n");
9375 : :
1421 tgl@sss.pgh.pa.us 9376 [ + - ]:CBC 189 : if (fout->remoteVersion >= 140000)
9377 : 189 : appendPQExpBufferStr(q,
9378 : : "a.attcompression AS attcompression,\n");
9379 : : else
1421 tgl@sss.pgh.pa.us 9380 :UBC 0 : appendPQExpBufferStr(q,
9381 : : "'' AS attcompression,\n");
9382 : :
1421 tgl@sss.pgh.pa.us 9383 [ + - ]:CBC 189 : if (fout->remoteVersion >= 100000)
9384 : 189 : appendPQExpBufferStr(q,
9385 : : "a.attidentity,\n");
9386 : : else
1421 tgl@sss.pgh.pa.us 9387 :UBC 0 : appendPQExpBufferStr(q,
9388 : : "'' AS attidentity,\n");
9389 : :
1421 tgl@sss.pgh.pa.us 9390 [ + - ]:CBC 189 : if (fout->remoteVersion >= 110000)
9391 : 189 : appendPQExpBufferStr(q,
9392 : : "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
9393 : : "THEN a.attmissingval ELSE null END AS attmissingval,\n");
9394 : : else
1421 tgl@sss.pgh.pa.us 9395 :UBC 0 : appendPQExpBufferStr(q,
9396 : : "NULL AS attmissingval,\n");
9397 : :
1421 tgl@sss.pgh.pa.us 9398 [ + - ]:CBC 189 : if (fout->remoteVersion >= 120000)
9399 : 189 : appendPQExpBufferStr(q,
9400 : : "a.attgenerated\n");
9401 : : else
1421 tgl@sss.pgh.pa.us 9402 :UBC 0 : appendPQExpBufferStr(q,
9403 : : "'' AS attgenerated\n");
9404 : :
9405 : : /* need left join to pg_type to not fail on dropped columns ... */
1421 tgl@sss.pgh.pa.us 9406 :CBC 189 : appendPQExpBuffer(q,
9407 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9408 : : "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
9409 : : "LEFT JOIN pg_catalog.pg_type t "
9410 : : "ON (a.atttypid = t.oid)\n",
9411 : : tbloids->data);
9412 : :
9413 : : /*
9414 : : * In versions 18 and up, we need pg_constraint for explicit NOT NULL
9415 : : * entries and pg_description to get their comments.
9416 : : */
353 alvherre@alvh.no-ip. 9417 [ + - ]: 189 : if (fout->remoteVersion >= 180000)
9418 : 189 : appendPQExpBufferStr(q,
9419 : : " LEFT JOIN pg_catalog.pg_constraint co ON "
9420 : : "(a.attrelid = co.conrelid\n"
9421 : : " AND co.contype = 'n' AND "
9422 : : "co.conkey = array[a.attnum])\n"
9423 : : " LEFT JOIN pg_catalog.pg_description pt ON "
9424 : : "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
9425 : :
9426 : 189 : appendPQExpBufferStr(q,
9427 : : "WHERE a.attnum > 0::pg_catalog.int2\n"
9428 : : "ORDER BY a.attrelid, a.attnum");
9429 : :
1421 tgl@sss.pgh.pa.us 9430 : 189 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9431 : :
9432 : 189 : ntups = PQntuples(res);
9433 : :
9434 : 189 : i_attrelid = PQfnumber(res, "attrelid");
9435 : 189 : i_attnum = PQfnumber(res, "attnum");
9436 : 189 : i_attname = PQfnumber(res, "attname");
9437 : 189 : i_atttypname = PQfnumber(res, "atttypname");
9438 : 189 : i_attstattarget = PQfnumber(res, "attstattarget");
9439 : 189 : i_attstorage = PQfnumber(res, "attstorage");
9440 : 189 : i_typstorage = PQfnumber(res, "typstorage");
9441 : 189 : i_attidentity = PQfnumber(res, "attidentity");
9442 : 189 : i_attgenerated = PQfnumber(res, "attgenerated");
9443 : 189 : i_attisdropped = PQfnumber(res, "attisdropped");
9444 : 189 : i_attlen = PQfnumber(res, "attlen");
9445 : 189 : i_attalign = PQfnumber(res, "attalign");
9446 : 189 : i_attislocal = PQfnumber(res, "attislocal");
353 alvherre@alvh.no-ip. 9447 : 189 : i_notnull_name = PQfnumber(res, "notnull_name");
123 alvherre@kurilemu.de 9448 : 189 : i_notnull_comment = PQfnumber(res, "notnull_comment");
203 alvherre@alvh.no-ip. 9449 : 189 : i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
353 9450 : 189 : i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
9451 : 189 : i_notnull_islocal = PQfnumber(res, "notnull_islocal");
1421 tgl@sss.pgh.pa.us 9452 : 189 : i_attoptions = PQfnumber(res, "attoptions");
9453 : 189 : i_attcollation = PQfnumber(res, "attcollation");
9454 : 189 : i_attcompression = PQfnumber(res, "attcompression");
9455 : 189 : i_attfdwoptions = PQfnumber(res, "attfdwoptions");
9456 : 189 : i_attmissingval = PQfnumber(res, "attmissingval");
9457 : 189 : i_atthasdef = PQfnumber(res, "atthasdef");
9458 : :
9459 : : /* Within the next loop, we'll accumulate OIDs of tables with defaults */
929 alvherre@alvh.no-ip. 9460 : 189 : resetPQExpBuffer(tbloids);
9461 : 189 : appendPQExpBufferChar(tbloids, '{');
9462 : :
9463 : : /*
9464 : : * Outer loop iterates once per table, not once per row. Incrementing of
9465 : : * r is handled by the inner loop.
9466 : : */
1421 tgl@sss.pgh.pa.us 9467 : 189 : curtblindx = -1;
9468 [ + + ]: 6690 : for (int r = 0; r < ntups;)
9469 : : {
9470 : 6501 : Oid attrelid = atooid(PQgetvalue(res, r, i_attrelid));
9471 : 6501 : TableInfo *tbinfo = NULL;
9472 : : int numatts;
9473 : : bool hasdefaults;
9474 : :
9475 : : /* Count rows for this table */
9476 [ + + ]: 24625 : for (numatts = 1; numatts < ntups - r; numatts++)
9477 [ + + ]: 24483 : if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
9478 : 6359 : break;
9479 : :
9480 : : /*
9481 : : * Locate the associated TableInfo; we rely on tblinfo[] being in OID
9482 : : * order.
9483 : : */
9484 [ + - ]: 34508 : while (++curtblindx < numTables)
9485 : : {
9486 : 34508 : tbinfo = &tblinfo[curtblindx];
9487 [ + + ]: 34508 : if (tbinfo->dobj.catId.oid == attrelid)
9488 : 6501 : break;
9489 : : }
9490 [ - + ]: 6501 : if (curtblindx >= numTables)
1298 tgl@sss.pgh.pa.us 9491 :UBC 0 : pg_fatal("unrecognized table OID %u", attrelid);
9492 : : /* cross-check that we only got requested tables */
1421 tgl@sss.pgh.pa.us 9493 [ + - ]:CBC 6501 : if (tbinfo->relkind == RELKIND_SEQUENCE ||
101 nathan@postgresql.or 9494 [ + + ]:GNC 6501 : (!tbinfo->interesting &&
9495 [ + - + - ]: 72 : !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
9496 [ + + ]: 72 : (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
9497 [ - + ]: 36 : tbinfo->dobj.catId.oid == SharedDependRelationId))))
1298 tgl@sss.pgh.pa.us 9498 :UBC 0 : pg_fatal("unexpected column data for table \"%s\"",
9499 : : tbinfo->dobj.name);
9500 : :
9501 : : /* Save data for this table */
1421 tgl@sss.pgh.pa.us 9502 :CBC 6501 : tbinfo->numatts = numatts;
9503 : 6501 : tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
9504 : 6501 : tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
9505 : 6501 : tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
9506 : 6501 : tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
9507 : 6501 : tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
9508 : 6501 : tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
9509 : 6501 : tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
9510 : 6501 : tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
9511 : 6501 : tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
9512 : 6501 : tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
9513 : 6501 : tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
9514 : 6501 : tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
9515 : 6501 : tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
9516 : 6501 : tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
9517 : 6501 : tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
9518 : 6501 : tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
353 alvherre@alvh.no-ip. 9519 : 6501 : tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
123 alvherre@kurilemu.de 9520 : 6501 : tbinfo->notnull_comment = (char **) pg_malloc(numatts * sizeof(char *));
182 9521 : 6501 : tbinfo->notnull_invalid = (bool *) pg_malloc(numatts * sizeof(bool));
353 alvherre@alvh.no-ip. 9522 : 6501 : tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
9523 : 6501 : tbinfo->notnull_islocal = (bool *) pg_malloc(numatts * sizeof(bool));
1421 tgl@sss.pgh.pa.us 9524 : 6501 : tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
8571 9525 : 6501 : hasdefaults = false;
9526 : :
1421 9527 [ + + ]: 31126 : for (int j = 0; j < numatts; j++, r++)
9528 : : {
9529 [ - + ]: 24625 : if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
1298 tgl@sss.pgh.pa.us 9530 :UBC 0 : pg_fatal("invalid column numbering in table \"%s\"",
9531 : : tbinfo->dobj.name);
1421 tgl@sss.pgh.pa.us 9532 :CBC 24625 : tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
9533 : 24625 : tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
653 peter@eisentraut.org 9534 [ + + ]: 24625 : if (PQgetisnull(res, r, i_attstattarget))
9535 : 24585 : tbinfo->attstattarget[j] = -1;
9536 : : else
9537 : 40 : tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
1421 tgl@sss.pgh.pa.us 9538 : 24625 : tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
9539 : 24625 : tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
9540 : 24625 : tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
9541 : 24625 : tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
3126 peter_e@gmx.net 9542 [ + + + + ]: 24625 : tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
1421 tgl@sss.pgh.pa.us 9543 : 24625 : tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
9544 : 24625 : tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
9545 : 24625 : tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
9546 : 24625 : tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
9547 : :
9548 : : /* Handle not-null constraint name and flags */
353 alvherre@alvh.no-ip. 9549 : 24625 : determineNotNullFlags(fout, res, r,
9550 : : tbinfo, j,
9551 : : i_notnull_name,
9552 : : i_notnull_comment,
9553 : : i_notnull_invalidoid,
9554 : : i_notnull_noinherit,
9555 : : i_notnull_islocal,
9556 : : &invalidnotnulloids);
9557 : :
123 alvherre@kurilemu.de 9558 : 24625 : tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
9559 [ + + ]: 24625 : NULL : pg_strdup(PQgetvalue(res, r, i_notnull_comment));
1421 tgl@sss.pgh.pa.us 9560 : 24625 : tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
9561 : 24625 : tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
9562 : 24625 : tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
9563 : 24625 : tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
9564 : 24625 : tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
7729 bruce@momjian.us 9565 : 24625 : tbinfo->attrdefs[j] = NULL; /* fix below */
1421 tgl@sss.pgh.pa.us 9566 [ + + ]: 24625 : if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
8571 9567 : 1268 : hasdefaults = true;
9568 : : }
9569 : :
1421 9570 [ + + ]: 6501 : if (hasdefaults)
9571 : : {
9572 : : /* Collect OIDs of interesting tables that have defaults */
929 alvherre@alvh.no-ip. 9573 [ + + ]: 952 : if (tbloids->len > 1) /* do we have more than the '{'? */
9574 : 884 : appendPQExpBufferChar(tbloids, ',');
9575 : 952 : appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
9576 : : }
9577 : : }
9578 : :
9579 : : /* If invalidnotnulloids has any data, finalize it */
203 9580 [ + + ]: 189 : if (invalidnotnulloids != NULL)
9581 : 43 : appendPQExpBufferChar(invalidnotnulloids, '}');
9582 : :
1421 tgl@sss.pgh.pa.us 9583 : 189 : PQclear(res);
9584 : :
9585 : : /*
9586 : : * Now get info about column defaults. This is skipped for a data-only
9587 : : * dump, as it is only needed for table schemas.
9588 : : */
336 nathan@postgresql.or 9589 [ + + + + ]: 189 : if (dopt->dumpSchema && tbloids->len > 1)
9590 : : {
9591 : : AttrDefInfo *attrdefs;
9592 : : int numDefaults;
1421 tgl@sss.pgh.pa.us 9593 : 60 : TableInfo *tbinfo = NULL;
9594 : :
9595 : 60 : pg_log_info("finding table default expressions");
9596 : :
929 alvherre@alvh.no-ip. 9597 : 60 : appendPQExpBufferChar(tbloids, '}');
9598 : :
1421 tgl@sss.pgh.pa.us 9599 : 60 : printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
9600 : : "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
9601 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9602 : : "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
9603 : : "ORDER BY a.adrelid, a.adnum",
9604 : : tbloids->data);
9605 : :
9606 : 60 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9607 : :
9608 : 60 : numDefaults = PQntuples(res);
9609 : 60 : attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
9610 : :
9611 : 60 : curtblindx = -1;
9612 [ + + ]: 1230 : for (int j = 0; j < numDefaults; j++)
9613 : : {
9614 : 1170 : Oid adtableoid = atooid(PQgetvalue(res, j, 0));
9615 : 1170 : Oid adoid = atooid(PQgetvalue(res, j, 1));
9616 : 1170 : Oid adrelid = atooid(PQgetvalue(res, j, 2));
9617 : 1170 : int adnum = atoi(PQgetvalue(res, j, 3));
9618 : 1170 : char *adsrc = PQgetvalue(res, j, 4);
9619 : :
9620 : : /*
9621 : : * Locate the associated TableInfo; we rely on tblinfo[] being in
9622 : : * OID order.
9623 : : */
9624 [ + + + + ]: 1170 : if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
9625 : : {
9626 [ + - ]: 18712 : while (++curtblindx < numTables)
9627 : : {
9628 : 18712 : tbinfo = &tblinfo[curtblindx];
9629 [ + + ]: 18712 : if (tbinfo->dobj.catId.oid == adrelid)
9630 : 884 : break;
9631 : : }
9632 [ - + ]: 884 : if (curtblindx >= numTables)
1298 tgl@sss.pgh.pa.us 9633 :UBC 0 : pg_fatal("unrecognized table OID %u", adrelid);
9634 : : }
9635 : :
1421 tgl@sss.pgh.pa.us 9636 [ + - - + ]:CBC 1170 : if (adnum <= 0 || adnum > tbinfo->numatts)
1298 tgl@sss.pgh.pa.us 9637 :UBC 0 : pg_fatal("invalid adnum value %d for table \"%s\"",
9638 : : adnum, tbinfo->dobj.name);
9639 : :
9640 : : /*
9641 : : * dropped columns shouldn't have defaults, but just in case,
9642 : : * ignore 'em
9643 : : */
1421 tgl@sss.pgh.pa.us 9644 [ - + ]:CBC 1170 : if (tbinfo->attisdropped[adnum - 1])
1421 tgl@sss.pgh.pa.us 9645 :UBC 0 : continue;
9646 : :
1421 tgl@sss.pgh.pa.us 9647 :CBC 1170 : attrdefs[j].dobj.objType = DO_ATTRDEF;
9648 : 1170 : attrdefs[j].dobj.catId.tableoid = adtableoid;
9649 : 1170 : attrdefs[j].dobj.catId.oid = adoid;
9650 : 1170 : AssignDumpId(&attrdefs[j].dobj);
9651 : 1170 : attrdefs[j].adtable = tbinfo;
9652 : 1170 : attrdefs[j].adnum = adnum;
9653 : 1170 : attrdefs[j].adef_expr = pg_strdup(adsrc);
9654 : :
9655 : 1170 : attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
9656 : 1170 : attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
9657 : :
9658 : 1170 : attrdefs[j].dobj.dump = tbinfo->dobj.dump;
9659 : :
9660 : : /*
9661 : : * Figure out whether the default/generation expression should be
9662 : : * dumped as part of the main CREATE TABLE (or similar) command or
9663 : : * as a separate ALTER TABLE (or similar) command. The preference
9664 : : * is to put it into the CREATE command, but in some cases that's
9665 : : * not possible.
9666 : : */
9667 [ + + ]: 1170 : if (tbinfo->attgenerated[adnum - 1])
9668 : : {
9669 : : /*
9670 : : * Column generation expressions cannot be dumped separately,
9671 : : * because there is no syntax for it. By setting separate to
9672 : : * false here we prevent the "default" from being processed as
9673 : : * its own dumpable object. Later, flagInhAttrs() will mark
9674 : : * it as not to be dumped at all, if possible (that is, if it
9675 : : * can be inherited from a parent).
9676 : : */
9677 : 656 : attrdefs[j].separate = false;
9678 : : }
9679 [ + + ]: 514 : else if (tbinfo->relkind == RELKIND_VIEW)
9680 : : {
9681 : : /*
9682 : : * Defaults on a VIEW must always be dumped as separate ALTER
9683 : : * TABLE commands.
9684 : : */
9685 : 32 : attrdefs[j].separate = true;
9686 : : }
9687 [ + + ]: 482 : else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
9688 : : {
9689 : : /* column will be suppressed, print default separately */
9690 : 4 : attrdefs[j].separate = true;
9691 : : }
9692 : : else
9693 : : {
9694 : 478 : attrdefs[j].separate = false;
9695 : : }
9696 : :
9697 [ + + ]: 1170 : if (!attrdefs[j].separate)
9698 : : {
9699 : : /*
9700 : : * Mark the default as needing to appear before the table, so
9701 : : * that any dependencies it has must be emitted before the
9702 : : * CREATE TABLE. If this is not possible, we'll change to
9703 : : * "separate" mode while sorting dependencies.
9704 : : */
9705 : 1134 : addObjectDependency(&tbinfo->dobj,
9706 : 1134 : attrdefs[j].dobj.dumpId);
9707 : : }
9708 : :
9709 : 1170 : tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
9710 : : }
9711 : :
9712 : 60 : PQclear(res);
9713 : : }
9714 : :
9715 : : /*
9716 : : * Get info about NOT NULL NOT VALID constraints. This is skipped for a
9717 : : * data-only dump, as it is only needed for table schemas.
9718 : : */
203 alvherre@alvh.no-ip. 9719 [ + + + + ]: 189 : if (dopt->dumpSchema && invalidnotnulloids)
9720 : : {
9721 : : ConstraintInfo *constrs;
9722 : : int numConstrs;
9723 : : int i_tableoid;
9724 : : int i_oid;
9725 : : int i_conrelid;
9726 : : int i_conname;
9727 : : int i_consrc;
9728 : : int i_conislocal;
9729 : :
133 peter@eisentraut.org 9730 : 37 : pg_log_info("finding invalid not-null constraints");
9731 : :
203 alvherre@alvh.no-ip. 9732 : 37 : resetPQExpBuffer(q);
9733 : 37 : appendPQExpBuffer(q,
9734 : : "SELECT c.tableoid, c.oid, conrelid, conname, "
9735 : : "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9736 : : "conislocal, convalidated "
9737 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(conoid)\n"
9738 : : "JOIN pg_catalog.pg_constraint c ON (src.conoid = c.oid)\n"
9739 : : "ORDER BY c.conrelid, c.conname",
9740 : 37 : invalidnotnulloids->data);
9741 : :
9742 : 37 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9743 : :
9744 : 37 : numConstrs = PQntuples(res);
9745 : 37 : constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
9746 : :
9747 : 37 : i_tableoid = PQfnumber(res, "tableoid");
9748 : 37 : i_oid = PQfnumber(res, "oid");
9749 : 37 : i_conrelid = PQfnumber(res, "conrelid");
9750 : 37 : i_conname = PQfnumber(res, "conname");
9751 : 37 : i_consrc = PQfnumber(res, "consrc");
9752 : 37 : i_conislocal = PQfnumber(res, "conislocal");
9753 : :
9754 : : /* As above, this loop iterates once per table, not once per row */
9755 : 37 : curtblindx = -1;
9756 [ + + ]: 104 : for (int j = 0; j < numConstrs;)
9757 : : {
9758 : 67 : Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9759 : 67 : TableInfo *tbinfo = NULL;
9760 : : int numcons;
9761 : :
9762 : : /* Count rows for this table */
9763 [ + + ]: 67 : for (numcons = 1; numcons < numConstrs - j; numcons++)
9764 [ + - ]: 30 : if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9765 : 30 : break;
9766 : :
9767 : : /*
9768 : : * Locate the associated TableInfo; we rely on tblinfo[] being in
9769 : : * OID order.
9770 : : */
9771 [ + - ]: 12534 : while (++curtblindx < numTables)
9772 : : {
9773 : 12534 : tbinfo = &tblinfo[curtblindx];
9774 [ + + ]: 12534 : if (tbinfo->dobj.catId.oid == conrelid)
9775 : 67 : break;
9776 : : }
9777 [ - + ]: 67 : if (curtblindx >= numTables)
203 alvherre@alvh.no-ip. 9778 :UBC 0 : pg_fatal("unrecognized table OID %u", conrelid);
9779 : :
203 alvherre@alvh.no-ip. 9780 [ + + ]:CBC 134 : for (int c = 0; c < numcons; c++, j++)
9781 : : {
9782 : 67 : constrs[j].dobj.objType = DO_CONSTRAINT;
9783 : 67 : constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9784 : 67 : constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
9785 : 67 : AssignDumpId(&constrs[j].dobj);
9786 : 67 : constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
9787 : 67 : constrs[j].dobj.namespace = tbinfo->dobj.namespace;
9788 : 67 : constrs[j].contable = tbinfo;
9789 : 67 : constrs[j].condomain = NULL;
9790 : 67 : constrs[j].contype = 'n';
9791 : 67 : constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
9792 : 67 : constrs[j].confrelid = InvalidOid;
9793 : 67 : constrs[j].conindex = 0;
9794 : 67 : constrs[j].condeferrable = false;
9795 : 67 : constrs[j].condeferred = false;
9796 : 67 : constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9797 : :
9798 : : /*
9799 : : * All invalid not-null constraints must be dumped separately,
9800 : : * because CREATE TABLE would not create them as invalid, and
9801 : : * also because they must be created after potentially
9802 : : * violating data has been loaded.
9803 : : */
9804 : 67 : constrs[j].separate = true;
9805 : :
9806 : 67 : constrs[j].dobj.dump = tbinfo->dobj.dump;
9807 : : }
9808 : : }
9809 : 37 : PQclear(res);
9810 : : }
9811 : :
9812 : : /*
9813 : : * Get info about table CHECK constraints. This is skipped for a
9814 : : * data-only dump, as it is only needed for table schemas.
9815 : : */
336 nathan@postgresql.or 9816 [ + + + + ]: 189 : if (dopt->dumpSchema && checkoids->len > 2)
9817 : : {
9818 : : ConstraintInfo *constrs;
9819 : : int numConstrs;
9820 : : int i_tableoid;
9821 : : int i_oid;
9822 : : int i_conrelid;
9823 : : int i_conname;
9824 : : int i_consrc;
9825 : : int i_conislocal;
9826 : : int i_convalidated;
9827 : :
1421 tgl@sss.pgh.pa.us 9828 : 61 : pg_log_info("finding table check constraints");
9829 : :
9830 : 61 : resetPQExpBuffer(q);
9831 : 61 : appendPQExpBuffer(q,
9832 : : "SELECT c.tableoid, c.oid, conrelid, conname, "
9833 : : "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9834 : : "conislocal, convalidated "
9835 : : "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9836 : : "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
9837 : : "WHERE contype = 'c' "
9838 : : "ORDER BY c.conrelid, c.conname",
9839 : : checkoids->data);
9840 : :
9841 : 61 : res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9842 : :
9843 : 61 : numConstrs = PQntuples(res);
9844 : 61 : constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
9845 : :
9846 : 61 : i_tableoid = PQfnumber(res, "tableoid");
9847 : 61 : i_oid = PQfnumber(res, "oid");
9848 : 61 : i_conrelid = PQfnumber(res, "conrelid");
9849 : 61 : i_conname = PQfnumber(res, "conname");
9850 : 61 : i_consrc = PQfnumber(res, "consrc");
9851 : 61 : i_conislocal = PQfnumber(res, "conislocal");
9852 : 61 : i_convalidated = PQfnumber(res, "convalidated");
9853 : :
9854 : : /* As above, this loop iterates once per table, not once per row */
9855 : 61 : curtblindx = -1;
9856 [ + + ]: 538 : for (int j = 0; j < numConstrs;)
9857 : : {
9858 : 477 : Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9859 : 477 : TableInfo *tbinfo = NULL;
9860 : : int numcons;
9861 : :
9862 : : /* Count rows for this table */
9863 [ + + ]: 612 : for (numcons = 1; numcons < numConstrs - j; numcons++)
9864 [ + + ]: 551 : if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9865 : 416 : break;
9866 : :
9867 : : /*
9868 : : * Locate the associated TableInfo; we rely on tblinfo[] being in
9869 : : * OID order.
9870 : : */
9871 [ + - ]: 18033 : while (++curtblindx < numTables)
9872 : : {
9873 : 18033 : tbinfo = &tblinfo[curtblindx];
9874 [ + + ]: 18033 : if (tbinfo->dobj.catId.oid == conrelid)
9875 : 477 : break;
9876 : : }
9877 [ - + ]: 477 : if (curtblindx >= numTables)
1298 tgl@sss.pgh.pa.us 9878 :UBC 0 : pg_fatal("unrecognized table OID %u", conrelid);
9879 : :
1421 tgl@sss.pgh.pa.us 9880 [ - + ]:CBC 477 : if (numcons != tbinfo->ncheck)
9881 : : {
2401 peter@eisentraut.org 9882 :UBC 0 : pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
9883 : : "expected %d check constraints on table \"%s\" but found %d",
9884 : : tbinfo->ncheck),
9885 : : tbinfo->ncheck, tbinfo->dobj.name, numcons);
1298 tgl@sss.pgh.pa.us 9886 : 0 : pg_log_error_hint("The system catalogs might be corrupted.");
5002 rhaas@postgresql.org 9887 : 0 : exit_nicely(1);
9888 : : }
9889 : :
1421 tgl@sss.pgh.pa.us 9890 :CBC 477 : tbinfo->checkexprs = constrs + j;
9891 : :
9892 [ + + ]: 1089 : for (int c = 0; c < numcons; c++, j++)
9893 : : {
9894 : 612 : bool validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
9895 : :
7996 9896 : 612 : constrs[j].dobj.objType = DO_CONSTRAINT;
1421 9897 : 612 : constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9898 : 612 : constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7996 9899 : 612 : AssignDumpId(&constrs[j].dobj);
1421 9900 : 612 : constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7908 9901 : 612 : constrs[j].dobj.namespace = tbinfo->dobj.namespace;
7996 9902 : 612 : constrs[j].contable = tbinfo;
9903 : 612 : constrs[j].condomain = NULL;
9904 : 612 : constrs[j].contype = 'c';
1421 9905 : 612 : constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
6258 9906 : 612 : constrs[j].confrelid = InvalidOid;
7996 9907 : 612 : constrs[j].conindex = 0;
5934 9908 : 612 : constrs[j].condeferrable = false;
9909 : 612 : constrs[j].condeferred = false;
1421 9910 : 612 : constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9911 : :
9912 : : /*
9913 : : * An unvalidated constraint needs to be dumped separately, so
9914 : : * that potentially-violating existing data is loaded before
9915 : : * the constraint.
9916 : : */
4938 alvherre@alvh.no-ip. 9917 : 612 : constrs[j].separate = !validated;
9918 : :
7179 tgl@sss.pgh.pa.us 9919 : 612 : constrs[j].dobj.dump = tbinfo->dobj.dump;
9920 : :
9921 : : /*
9922 : : * Mark the constraint as needing to appear before the table
9923 : : * --- this is so that any other dependencies of the
9924 : : * constraint will be emitted before we try to create the
9925 : : * table. If the constraint is to be dumped separately, it
9926 : : * will be dumped after data is loaded anyway, so don't do it.
9927 : : * (There's an automatic dependency in the opposite direction
9928 : : * anyway, so don't need to add one manually here.)
9929 : : */
5075 alvherre@alvh.no-ip. 9930 [ + + ]: 612 : if (!constrs[j].separate)
5086 9931 : 547 : addObjectDependency(&tbinfo->dobj,
9932 : 547 : constrs[j].dobj.dumpId);
9933 : :
9934 : : /*
9935 : : * We will detect later whether the constraint must be split
9936 : : * out from the table definition.
9937 : : */
9938 : : }
9939 : : }
9940 : :
1421 tgl@sss.pgh.pa.us 9941 : 61 : PQclear(res);
9942 : : }
9943 : :
8851 9944 : 189 : destroyPQExpBuffer(q);
1421 9945 : 189 : destroyPQExpBuffer(tbloids);
9946 : 189 : destroyPQExpBuffer(checkoids);
10702 scrappy@hub.org 9947 : 189 : }
9948 : :
9949 : : /*
9950 : : * Based on the getTableAttrs query's row corresponding to one column, set
9951 : : * the name and flags to handle a not-null constraint for that column in
9952 : : * the tbinfo struct.
9953 : : *
9954 : : * Result row 'r' is for tbinfo's attribute 'j'.
9955 : : *
9956 : : * There are four possibilities:
9957 : : * 1) the column has no not-null constraints. In that case, ->notnull_constrs
9958 : : * (the constraint name) remains NULL.
9959 : : * 2) The column has a constraint with no name (this is the case when
9960 : : * constraints come from pre-18 servers). In this case, ->notnull_constrs
9961 : : * is set to the empty string; dumpTableSchema will print just "NOT NULL".
9962 : : * 3) The column has an invalid not-null constraint. This must be treated
9963 : : * as a separate object (because it must be created after the table data
9964 : : * is loaded). So we add its OID to invalidnotnulloids for processing
9965 : : * elsewhere and do nothing further with it here. We distinguish this
9966 : : * case because the "notnull_invalidoid" column has been set to a non-NULL
9967 : : * value, which is the constraint OID. Valid constraints have a null OID.
9968 : : * 4) The column has a constraint with a known name; in that case
9969 : : * notnull_constrs carries that name and dumpTableSchema will print
9970 : : * "CONSTRAINT the_name NOT NULL". However, if the name is the default
9971 : : * (table_column_not_null) and there's no comment on the constraint,
9972 : : * there's no need to print that name in the dump, so notnull_constrs
9973 : : * is set to the empty string and it behaves as case 2.
9974 : : *
9975 : : * In a child table that inherits from a parent already containing NOT NULL
9976 : : * constraints and the columns in the child don't have their own NOT NULL
9977 : : * declarations, we suppress printing constraints in the child: the
9978 : : * constraints are acquired at the point where the child is attached to the
9979 : : * parent. This is tracked in ->notnull_islocal; for servers pre-18 this is
9980 : : * set not here but in flagInhAttrs. That flag is also used when the
9981 : : * constraint was validated in a child but all its parent have it as NOT
9982 : : * VALID.
9983 : : *
9984 : : * Any of these constraints might have the NO INHERIT bit. If so we set
9985 : : * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
9986 : : *
9987 : : * In case 4 above, the name comparison is a bit of a hack; it actually fails
9988 : : * to do the right thing in all but the trivial case. However, the downside
9989 : : * of getting it wrong is simply that the name is printed rather than
9990 : : * suppressed, so it's not a big deal.
9991 : : *
9992 : : * invalidnotnulloids is expected to be given as NULL; if any invalid not-null
9993 : : * constraints are found, it is initialized and filled with the array of
9994 : : * OIDs of such constraints, for later processing.
9995 : : */
9996 : : static void
353 alvherre@alvh.no-ip. 9997 : 24625 : determineNotNullFlags(Archive *fout, PGresult *res, int r,
9998 : : TableInfo *tbinfo, int j,
9999 : : int i_notnull_name,
10000 : : int i_notnull_comment,
10001 : : int i_notnull_invalidoid,
10002 : : int i_notnull_noinherit,
10003 : : int i_notnull_islocal,
10004 : : PQExpBuffer *invalidnotnulloids)
10005 : : {
10006 : 24625 : DumpOptions *dopt = fout->dopt;
10007 : :
10008 : : /*
10009 : : * If this not-null constraint is not valid, list its OID in
10010 : : * invalidnotnulloids and do nothing further. It'll be processed
10011 : : * elsewhere later.
10012 : : *
10013 : : * Because invalid not-null constraints are rare, we don't want to malloc
10014 : : * invalidnotnulloids until we're sure we're going it need it, which
10015 : : * happens here.
10016 : : */
203 10017 [ + + ]: 24625 : if (!PQgetisnull(res, r, i_notnull_invalidoid))
10018 : : {
10019 : 73 : char *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
10020 : :
10021 [ + + ]: 73 : if (*invalidnotnulloids == NULL)
10022 : : {
10023 : 43 : *invalidnotnulloids = createPQExpBuffer();
10024 : 43 : appendPQExpBufferChar(*invalidnotnulloids, '{');
193 drowley@postgresql.o 10025 : 43 : appendPQExpBufferStr(*invalidnotnulloids, constroid);
10026 : : }
10027 : : else
203 alvherre@alvh.no-ip. 10028 : 30 : appendPQExpBuffer(*invalidnotnulloids, ",%s", constroid);
10029 : :
10030 : : /*
10031 : : * Track when a parent constraint is invalid for the cases where a
10032 : : * child constraint has been validated independenly.
10033 : : */
182 alvherre@kurilemu.de 10034 : 73 : tbinfo->notnull_invalid[j] = true;
10035 : :
10036 : : /* nothing else to do */
203 alvherre@alvh.no-ip. 10037 : 73 : tbinfo->notnull_constrs[j] = NULL;
10038 : 73 : return;
10039 : : }
10040 : :
10041 : : /*
10042 : : * notnull_noinh is straight from the query result. notnull_islocal also,
10043 : : * though flagInhAttrs may change that one later.
10044 : : */
353 10045 : 24552 : tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
10046 : 24552 : tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
182 alvherre@kurilemu.de 10047 : 24552 : tbinfo->notnull_invalid[j] = false;
10048 : :
10049 : : /*
10050 : : * Determine a constraint name to use. If the column is not marked not-
10051 : : * null, we set NULL which cues ... to do nothing. An empty string says
10052 : : * to print an unnamed NOT NULL, and anything else is a constraint name to
10053 : : * use.
10054 : : */
353 alvherre@alvh.no-ip. 10055 [ - + ]: 24552 : if (fout->remoteVersion < 180000)
10056 : : {
10057 : : /*
10058 : : * < 18 doesn't have not-null names, so an unnamed constraint is
10059 : : * sufficient.
10060 : : */
353 alvherre@alvh.no-ip. 10061 [ # # ]:UBC 0 : if (PQgetisnull(res, r, i_notnull_name))
10062 : 0 : tbinfo->notnull_constrs[j] = NULL;
10063 : : else
10064 : 0 : tbinfo->notnull_constrs[j] = "";
10065 : : }
10066 : : else
10067 : : {
353 alvherre@alvh.no-ip. 10068 [ + + ]:CBC 24552 : if (PQgetisnull(res, r, i_notnull_name))
10069 : 21945 : tbinfo->notnull_constrs[j] = NULL;
10070 : : else
10071 : : {
10072 : : /*
10073 : : * In binary upgrade of inheritance child tables, must have a
10074 : : * constraint name that we can UPDATE later; same if there's a
10075 : : * comment on the constraint.
10076 : : */
123 alvherre@kurilemu.de 10077 [ + + ]: 2607 : if ((dopt->binary_upgrade &&
10078 [ + + ]: 327 : !tbinfo->ispartition &&
10079 [ + - + + ]: 2856 : !tbinfo->notnull_islocal) ||
10080 : 2607 : !PQgetisnull(res, r, i_notnull_comment))
10081 : : {
353 alvherre@alvh.no-ip. 10082 : 48 : tbinfo->notnull_constrs[j] =
10083 : 48 : pstrdup(PQgetvalue(res, r, i_notnull_name));
10084 : : }
10085 : : else
10086 : : {
10087 : : char *default_name;
10088 : :
10089 : : /* XXX should match ChooseConstraintName better */
10090 : 2559 : default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
10091 : 2559 : tbinfo->attnames[j]);
10092 [ + + ]: 2559 : if (strcmp(default_name,
10093 : 2559 : PQgetvalue(res, r, i_notnull_name)) == 0)
10094 : 1695 : tbinfo->notnull_constrs[j] = "";
10095 : : else
10096 : : {
10097 : 864 : tbinfo->notnull_constrs[j] =
10098 : 864 : pstrdup(PQgetvalue(res, r, i_notnull_name));
10099 : : }
257 tgl@sss.pgh.pa.us 10100 : 2559 : free(default_name);
10101 : : }
10102 : : }
10103 : : }
10104 : : }
10105 : :
10106 : : /*
10107 : : * Test whether a column should be printed as part of table's CREATE TABLE.
10108 : : * Column number is zero-based.
10109 : : *
10110 : : * Normally this is always true, but it's false for dropped columns, as well
10111 : : * as those that were inherited without any local definition. (If we print
10112 : : * such a column it will mistakenly get pg_attribute.attislocal set to true.)
10113 : : * For partitions, it's always true, because we want the partitions to be
10114 : : * created independently and ATTACH PARTITION used afterwards.
10115 : : *
10116 : : * In binary_upgrade mode, we must print all columns and fix the attislocal/
10117 : : * attisdropped state later, so as to keep control of the physical column
10118 : : * order.
10119 : : *
10120 : : * This function exists because there are scattered nonobvious places that
10121 : : * must be kept in sync with this decision.
10122 : : */
10123 : : bool
1720 peter@eisentraut.org 10124 : 40004 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
10125 : : {
4031 alvherre@alvh.no-ip. 10126 [ + + ]: 40004 : if (dopt->binary_upgrade)
5008 tgl@sss.pgh.pa.us 10127 : 6214 : return true;
2331 alvherre@alvh.no-ip. 10128 [ + + ]: 33790 : if (tbinfo->attisdropped[colno])
10129 : 726 : return false;
10130 [ + + + + ]: 33064 : return (tbinfo->attislocal[colno] || tbinfo->ispartition);
10131 : : }
10132 : :
10133 : :
10134 : : /*
10135 : : * getTSParsers:
10136 : : * get information about all text search parsers in the system catalogs
10137 : : */
10138 : : void
482 nathan@postgresql.or 10139 : 189 : getTSParsers(Archive *fout)
10140 : : {
10141 : : PGresult *res;
10142 : : int ntups;
10143 : : int i;
10144 : : PQExpBuffer query;
10145 : : TSParserInfo *prsinfo;
10146 : : int i_tableoid;
10147 : : int i_oid;
10148 : : int i_prsname;
10149 : : int i_prsnamespace;
10150 : : int i_prsstart;
10151 : : int i_prstoken;
10152 : : int i_prsend;
10153 : : int i_prsheadline;
10154 : : int i_prslextype;
10155 : :
4976 peter_e@gmx.net 10156 : 189 : query = createPQExpBuffer();
10157 : :
10158 : : /*
10159 : : * find all text search objects, including builtin ones; we filter out
10160 : : * system-defined objects at dump-out time.
10161 : : */
10162 : :
4361 heikki.linnakangas@i 10163 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
10164 : : "prsstart::oid, prstoken::oid, "
10165 : : "prsend::oid, prsheadline::oid, prslextype::oid "
10166 : : "FROM pg_ts_parser");
10167 : :
5011 rhaas@postgresql.org 10168 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10169 : :
6642 tgl@sss.pgh.pa.us 10170 : 189 : ntups = PQntuples(res);
10171 : :
5085 bruce@momjian.us 10172 : 189 : prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
10173 : :
6642 tgl@sss.pgh.pa.us 10174 : 189 : i_tableoid = PQfnumber(res, "tableoid");
10175 : 189 : i_oid = PQfnumber(res, "oid");
10176 : 189 : i_prsname = PQfnumber(res, "prsname");
10177 : 189 : i_prsnamespace = PQfnumber(res, "prsnamespace");
10178 : 189 : i_prsstart = PQfnumber(res, "prsstart");
10179 : 189 : i_prstoken = PQfnumber(res, "prstoken");
10180 : 189 : i_prsend = PQfnumber(res, "prsend");
10181 : 189 : i_prsheadline = PQfnumber(res, "prsheadline");
10182 : 189 : i_prslextype = PQfnumber(res, "prslextype");
10183 : :
10184 [ + + ]: 423 : for (i = 0; i < ntups; i++)
10185 : : {
10186 : 234 : prsinfo[i].dobj.objType = DO_TSPARSER;
10187 : 234 : prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10188 : 234 : prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10189 : 234 : AssignDumpId(&prsinfo[i].dobj);
5085 bruce@momjian.us 10190 : 234 : prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
5012 rhaas@postgresql.org 10191 : 468 : prsinfo[i].dobj.namespace =
1889 peter@eisentraut.org 10192 : 234 : findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
6642 tgl@sss.pgh.pa.us 10193 : 234 : prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
10194 : 234 : prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
10195 : 234 : prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
10196 : 234 : prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
10197 : 234 : prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
10198 : :
10199 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 10200 : 234 : selectDumpableObject(&(prsinfo[i].dobj), fout);
10201 : : }
10202 : :
6642 tgl@sss.pgh.pa.us 10203 : 189 : PQclear(res);
10204 : :
10205 : 189 : destroyPQExpBuffer(query);
10206 : 189 : }
10207 : :
10208 : : /*
10209 : : * getTSDictionaries:
10210 : : * get information about all text search dictionaries in the system catalogs
10211 : : */
10212 : : void
482 nathan@postgresql.or 10213 : 189 : getTSDictionaries(Archive *fout)
10214 : : {
10215 : : PGresult *res;
10216 : : int ntups;
10217 : : int i;
10218 : : PQExpBuffer query;
10219 : : TSDictInfo *dictinfo;
10220 : : int i_tableoid;
10221 : : int i_oid;
10222 : : int i_dictname;
10223 : : int i_dictnamespace;
10224 : : int i_dictowner;
10225 : : int i_dicttemplate;
10226 : : int i_dictinitoption;
10227 : :
4976 peter_e@gmx.net 10228 : 189 : query = createPQExpBuffer();
10229 : :
1147 drowley@postgresql.o 10230 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
10231 : : "dictnamespace, dictowner, "
10232 : : "dicttemplate, dictinitoption "
10233 : : "FROM pg_ts_dict");
10234 : :
5011 rhaas@postgresql.org 10235 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10236 : :
6642 tgl@sss.pgh.pa.us 10237 : 189 : ntups = PQntuples(res);
10238 : :
5085 bruce@momjian.us 10239 : 189 : dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
10240 : :
6642 tgl@sss.pgh.pa.us 10241 : 189 : i_tableoid = PQfnumber(res, "tableoid");
10242 : 189 : i_oid = PQfnumber(res, "oid");
10243 : 189 : i_dictname = PQfnumber(res, "dictname");
10244 : 189 : i_dictnamespace = PQfnumber(res, "dictnamespace");
1396 10245 : 189 : i_dictowner = PQfnumber(res, "dictowner");
6642 10246 : 189 : i_dictinitoption = PQfnumber(res, "dictinitoption");
10247 : 189 : i_dicttemplate = PQfnumber(res, "dicttemplate");
10248 : :
10249 [ + + ]: 5967 : for (i = 0; i < ntups; i++)
10250 : : {
10251 : 5778 : dictinfo[i].dobj.objType = DO_TSDICT;
10252 : 5778 : dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10253 : 5778 : dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10254 : 5778 : AssignDumpId(&dictinfo[i].dobj);
5085 bruce@momjian.us 10255 : 5778 : dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
5012 rhaas@postgresql.org 10256 : 11556 : dictinfo[i].dobj.namespace =
1889 peter@eisentraut.org 10257 : 5778 : findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
1396 tgl@sss.pgh.pa.us 10258 : 5778 : dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
6642 10259 : 5778 : dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
10260 [ + + ]: 5778 : if (PQgetisnull(res, i, i_dictinitoption))
10261 : 234 : dictinfo[i].dictinitoption = NULL;
10262 : : else
5085 bruce@momjian.us 10263 : 5544 : dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
10264 : :
10265 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 10266 : 5778 : selectDumpableObject(&(dictinfo[i].dobj), fout);
10267 : : }
10268 : :
6642 tgl@sss.pgh.pa.us 10269 : 189 : PQclear(res);
10270 : :
10271 : 189 : destroyPQExpBuffer(query);
10272 : 189 : }
10273 : :
10274 : : /*
10275 : : * getTSTemplates:
10276 : : * get information about all text search templates in the system catalogs
10277 : : */
10278 : : void
482 nathan@postgresql.or 10279 : 189 : getTSTemplates(Archive *fout)
10280 : : {
10281 : : PGresult *res;
10282 : : int ntups;
10283 : : int i;
10284 : : PQExpBuffer query;
10285 : : TSTemplateInfo *tmplinfo;
10286 : : int i_tableoid;
10287 : : int i_oid;
10288 : : int i_tmplname;
10289 : : int i_tmplnamespace;
10290 : : int i_tmplinit;
10291 : : int i_tmpllexize;
10292 : :
4976 peter_e@gmx.net 10293 : 189 : query = createPQExpBuffer();
10294 : :
4361 heikki.linnakangas@i 10295 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
10296 : : "tmplnamespace, tmplinit::oid, tmpllexize::oid "
10297 : : "FROM pg_ts_template");
10298 : :
5011 rhaas@postgresql.org 10299 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10300 : :
6642 tgl@sss.pgh.pa.us 10301 : 189 : ntups = PQntuples(res);
10302 : :
5085 bruce@momjian.us 10303 : 189 : tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
10304 : :
6642 tgl@sss.pgh.pa.us 10305 : 189 : i_tableoid = PQfnumber(res, "tableoid");
10306 : 189 : i_oid = PQfnumber(res, "oid");
10307 : 189 : i_tmplname = PQfnumber(res, "tmplname");
10308 : 189 : i_tmplnamespace = PQfnumber(res, "tmplnamespace");
10309 : 189 : i_tmplinit = PQfnumber(res, "tmplinit");
10310 : 189 : i_tmpllexize = PQfnumber(res, "tmpllexize");
10311 : :
10312 [ + + ]: 1179 : for (i = 0; i < ntups; i++)
10313 : : {
10314 : 990 : tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
10315 : 990 : tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10316 : 990 : tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10317 : 990 : AssignDumpId(&tmplinfo[i].dobj);
5085 bruce@momjian.us 10318 : 990 : tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
5012 rhaas@postgresql.org 10319 : 1980 : tmplinfo[i].dobj.namespace =
1889 peter@eisentraut.org 10320 : 990 : findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
6642 tgl@sss.pgh.pa.us 10321 : 990 : tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
10322 : 990 : tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
10323 : :
10324 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 10325 : 990 : selectDumpableObject(&(tmplinfo[i].dobj), fout);
10326 : : }
10327 : :
6642 tgl@sss.pgh.pa.us 10328 : 189 : PQclear(res);
10329 : :
10330 : 189 : destroyPQExpBuffer(query);
10331 : 189 : }
10332 : :
10333 : : /*
10334 : : * getTSConfigurations:
10335 : : * get information about all text search configurations
10336 : : */
10337 : : void
482 nathan@postgresql.or 10338 : 189 : getTSConfigurations(Archive *fout)
10339 : : {
10340 : : PGresult *res;
10341 : : int ntups;
10342 : : int i;
10343 : : PQExpBuffer query;
10344 : : TSConfigInfo *cfginfo;
10345 : : int i_tableoid;
10346 : : int i_oid;
10347 : : int i_cfgname;
10348 : : int i_cfgnamespace;
10349 : : int i_cfgowner;
10350 : : int i_cfgparser;
10351 : :
4976 peter_e@gmx.net 10352 : 189 : query = createPQExpBuffer();
10353 : :
1147 drowley@postgresql.o 10354 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
10355 : : "cfgnamespace, cfgowner, cfgparser "
10356 : : "FROM pg_ts_config");
10357 : :
5011 rhaas@postgresql.org 10358 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10359 : :
6642 tgl@sss.pgh.pa.us 10360 : 189 : ntups = PQntuples(res);
10361 : :
5085 bruce@momjian.us 10362 : 189 : cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
10363 : :
6642 tgl@sss.pgh.pa.us 10364 : 189 : i_tableoid = PQfnumber(res, "tableoid");
10365 : 189 : i_oid = PQfnumber(res, "oid");
10366 : 189 : i_cfgname = PQfnumber(res, "cfgname");
10367 : 189 : i_cfgnamespace = PQfnumber(res, "cfgnamespace");
1396 10368 : 189 : i_cfgowner = PQfnumber(res, "cfgowner");
6642 10369 : 189 : i_cfgparser = PQfnumber(res, "cfgparser");
10370 : :
10371 [ + + ]: 5932 : for (i = 0; i < ntups; i++)
10372 : : {
10373 : 5743 : cfginfo[i].dobj.objType = DO_TSCONFIG;
10374 : 5743 : cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10375 : 5743 : cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10376 : 5743 : AssignDumpId(&cfginfo[i].dobj);
5085 bruce@momjian.us 10377 : 5743 : cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
5012 rhaas@postgresql.org 10378 : 11486 : cfginfo[i].dobj.namespace =
1889 peter@eisentraut.org 10379 : 5743 : findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
1396 tgl@sss.pgh.pa.us 10380 : 5743 : cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
6642 10381 : 5743 : cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
10382 : :
10383 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 10384 : 5743 : selectDumpableObject(&(cfginfo[i].dobj), fout);
10385 : : }
10386 : :
6642 tgl@sss.pgh.pa.us 10387 : 189 : PQclear(res);
10388 : :
10389 : 189 : destroyPQExpBuffer(query);
10390 : 189 : }
10391 : :
10392 : : /*
10393 : : * getForeignDataWrappers:
10394 : : * get information about all foreign-data wrappers in the system catalogs
10395 : : */
10396 : : void
482 nathan@postgresql.or 10397 : 189 : getForeignDataWrappers(Archive *fout)
10398 : : {
10399 : : PGresult *res;
10400 : : int ntups;
10401 : : int i;
10402 : : PQExpBuffer query;
10403 : : FdwInfo *fdwinfo;
10404 : : int i_tableoid;
10405 : : int i_oid;
10406 : : int i_fdwname;
10407 : : int i_fdwowner;
10408 : : int i_fdwhandler;
10409 : : int i_fdwvalidator;
10410 : : int i_fdwacl;
10411 : : int i_acldefault;
10412 : : int i_fdwoptions;
10413 : :
4279 sfrost@snowman.net 10414 : 189 : query = createPQExpBuffer();
10415 : :
1147 drowley@postgresql.o 10416 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
10417 : : "fdwowner, "
10418 : : "fdwhandler::pg_catalog.regproc, "
10419 : : "fdwvalidator::pg_catalog.regproc, "
10420 : : "fdwacl, "
10421 : : "acldefault('F', fdwowner) AS acldefault, "
10422 : : "array_to_string(ARRAY("
10423 : : "SELECT quote_ident(option_name) || ' ' || "
10424 : : "quote_literal(option_value) "
10425 : : "FROM pg_options_to_table(fdwoptions) "
10426 : : "ORDER BY option_name"
10427 : : "), E',\n ') AS fdwoptions "
10428 : : "FROM pg_foreign_data_wrapper");
10429 : :
5011 rhaas@postgresql.org 10430 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10431 : :
6156 peter_e@gmx.net 10432 : 189 : ntups = PQntuples(res);
10433 : :
5085 bruce@momjian.us 10434 : 189 : fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
10435 : :
5513 heikki.linnakangas@i 10436 : 189 : i_tableoid = PQfnumber(res, "tableoid");
6156 peter_e@gmx.net 10437 : 189 : i_oid = PQfnumber(res, "oid");
10438 : 189 : i_fdwname = PQfnumber(res, "fdwname");
1396 tgl@sss.pgh.pa.us 10439 : 189 : i_fdwowner = PQfnumber(res, "fdwowner");
5364 10440 : 189 : i_fdwhandler = PQfnumber(res, "fdwhandler");
6089 peter_e@gmx.net 10441 : 189 : i_fdwvalidator = PQfnumber(res, "fdwvalidator");
6156 10442 : 189 : i_fdwacl = PQfnumber(res, "fdwacl");
1421 tgl@sss.pgh.pa.us 10443 : 189 : i_acldefault = PQfnumber(res, "acldefault");
6156 peter_e@gmx.net 10444 : 189 : i_fdwoptions = PQfnumber(res, "fdwoptions");
10445 : :
10446 [ + + ]: 260 : for (i = 0; i < ntups; i++)
10447 : : {
10448 : 71 : fdwinfo[i].dobj.objType = DO_FDW;
5513 heikki.linnakangas@i 10449 : 71 : fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6156 peter_e@gmx.net 10450 : 71 : fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10451 : 71 : AssignDumpId(&fdwinfo[i].dobj);
5085 bruce@momjian.us 10452 : 71 : fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
6156 peter_e@gmx.net 10453 : 71 : fdwinfo[i].dobj.namespace = NULL;
1421 tgl@sss.pgh.pa.us 10454 : 71 : fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
10455 : 71 : fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10456 : 71 : fdwinfo[i].dacl.privtype = 0;
10457 : 71 : fdwinfo[i].dacl.initprivs = NULL;
1396 10458 : 71 : fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
5085 bruce@momjian.us 10459 : 71 : fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
10460 : 71 : fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
10461 : 71 : fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
10462 : :
10463 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 10464 : 71 : selectDumpableObject(&(fdwinfo[i].dobj), fout);
10465 : :
10466 : : /* Mark whether FDW has an ACL */
1421 tgl@sss.pgh.pa.us 10467 [ + + ]: 71 : if (!PQgetisnull(res, i, i_fdwacl))
10468 : 45 : fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10469 : : }
10470 : :
6156 peter_e@gmx.net 10471 : 189 : PQclear(res);
10472 : :
10473 : 189 : destroyPQExpBuffer(query);
10474 : 189 : }
10475 : :
10476 : : /*
10477 : : * getForeignServers:
10478 : : * get information about all foreign servers in the system catalogs
10479 : : */
10480 : : void
482 nathan@postgresql.or 10481 : 189 : getForeignServers(Archive *fout)
10482 : : {
10483 : : PGresult *res;
10484 : : int ntups;
10485 : : int i;
10486 : : PQExpBuffer query;
10487 : : ForeignServerInfo *srvinfo;
10488 : : int i_tableoid;
10489 : : int i_oid;
10490 : : int i_srvname;
10491 : : int i_srvowner;
10492 : : int i_srvfdw;
10493 : : int i_srvtype;
10494 : : int i_srvversion;
10495 : : int i_srvacl;
10496 : : int i_acldefault;
10497 : : int i_srvoptions;
10498 : :
4279 sfrost@snowman.net 10499 : 189 : query = createPQExpBuffer();
10500 : :
1147 drowley@postgresql.o 10501 : 189 : appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
10502 : : "srvowner, "
10503 : : "srvfdw, srvtype, srvversion, srvacl, "
10504 : : "acldefault('S', srvowner) AS acldefault, "
10505 : : "array_to_string(ARRAY("
10506 : : "SELECT quote_ident(option_name) || ' ' || "
10507 : : "quote_literal(option_value) "
10508 : : "FROM pg_options_to_table(srvoptions) "
10509 : : "ORDER BY option_name"
10510 : : "), E',\n ') AS srvoptions "
10511 : : "FROM pg_foreign_server");
10512 : :
5011 rhaas@postgresql.org 10513 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10514 : :
6156 peter_e@gmx.net 10515 : 189 : ntups = PQntuples(res);
10516 : :
5085 bruce@momjian.us 10517 : 189 : srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
10518 : :
5513 heikki.linnakangas@i 10519 : 189 : i_tableoid = PQfnumber(res, "tableoid");
6156 peter_e@gmx.net 10520 : 189 : i_oid = PQfnumber(res, "oid");
10521 : 189 : i_srvname = PQfnumber(res, "srvname");
1396 tgl@sss.pgh.pa.us 10522 : 189 : i_srvowner = PQfnumber(res, "srvowner");
6156 peter_e@gmx.net 10523 : 189 : i_srvfdw = PQfnumber(res, "srvfdw");
10524 : 189 : i_srvtype = PQfnumber(res, "srvtype");
10525 : 189 : i_srvversion = PQfnumber(res, "srvversion");
10526 : 189 : i_srvacl = PQfnumber(res, "srvacl");
1421 tgl@sss.pgh.pa.us 10527 : 189 : i_acldefault = PQfnumber(res, "acldefault");
6156 peter_e@gmx.net 10528 : 189 : i_srvoptions = PQfnumber(res, "srvoptions");
10529 : :
10530 [ + + ]: 264 : for (i = 0; i < ntups; i++)
10531 : : {
10532 : 75 : srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
5513 heikki.linnakangas@i 10533 : 75 : srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6156 peter_e@gmx.net 10534 : 75 : srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10535 : 75 : AssignDumpId(&srvinfo[i].dobj);
5085 bruce@momjian.us 10536 : 75 : srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
6156 peter_e@gmx.net 10537 : 75 : srvinfo[i].dobj.namespace = NULL;
1421 tgl@sss.pgh.pa.us 10538 : 75 : srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
10539 : 75 : srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10540 : 75 : srvinfo[i].dacl.privtype = 0;
10541 : 75 : srvinfo[i].dacl.initprivs = NULL;
1396 10542 : 75 : srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
6156 peter_e@gmx.net 10543 : 75 : srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
5085 bruce@momjian.us 10544 : 75 : srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
10545 : 75 : srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
10546 : 75 : srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
10547 : :
10548 : : /* Decide whether we want to dump it */
3491 sfrost@snowman.net 10549 : 75 : selectDumpableObject(&(srvinfo[i].dobj), fout);
10550 : :
10551 : : /* Servers have user mappings */
1421 tgl@sss.pgh.pa.us 10552 : 75 : srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
10553 : :
10554 : : /* Mark whether server has an ACL */
10555 [ + + ]: 75 : if (!PQgetisnull(res, i, i_srvacl))
10556 : 45 : srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10557 : : }
10558 : :
6156 peter_e@gmx.net 10559 : 189 : PQclear(res);
10560 : :
10561 : 189 : destroyPQExpBuffer(query);
10562 : 189 : }
10563 : :
10564 : : /*
10565 : : * getDefaultACLs:
10566 : : * get information about all default ACL information in the system catalogs
10567 : : */
10568 : : void
482 nathan@postgresql.or 10569 : 189 : getDefaultACLs(Archive *fout)
10570 : : {
3575 tgl@sss.pgh.pa.us 10571 : 189 : DumpOptions *dopt = fout->dopt;
10572 : : DefaultACLInfo *daclinfo;
10573 : : PQExpBuffer query;
10574 : : PGresult *res;
10575 : : int i_oid;
10576 : : int i_tableoid;
10577 : : int i_defaclrole;
10578 : : int i_defaclnamespace;
10579 : : int i_defaclobjtype;
10580 : : int i_defaclacl;
10581 : : int i_acldefault;
10582 : : int i,
10583 : : ntups;
10584 : :
5866 10585 : 189 : query = createPQExpBuffer();
10586 : :
10587 : : /*
10588 : : * Global entries (with defaclnamespace=0) replace the hard-wired default
10589 : : * ACL for their object type. We should dump them as deltas from the
10590 : : * default ACL, since that will be used as a starting point for
10591 : : * interpreting the ALTER DEFAULT PRIVILEGES commands. On the other hand,
10592 : : * non-global entries can only add privileges not revoke them. We must
10593 : : * dump those as-is (i.e., as deltas from an empty ACL).
10594 : : *
10595 : : * We can use defaclobjtype as the object type for acldefault(), except
10596 : : * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
10597 : : * 's'.
10598 : : */
1147 drowley@postgresql.o 10599 : 189 : appendPQExpBufferStr(query,
10600 : : "SELECT oid, tableoid, "
10601 : : "defaclrole, "
10602 : : "defaclnamespace, "
10603 : : "defaclobjtype, "
10604 : : "defaclacl, "
10605 : : "CASE WHEN defaclnamespace = 0 THEN "
10606 : : "acldefault(CASE WHEN defaclobjtype = 'S' "
10607 : : "THEN 's'::\"char\" ELSE defaclobjtype END, "
10608 : : "defaclrole) ELSE '{}' END AS acldefault "
10609 : : "FROM pg_default_acl");
10610 : :
5011 rhaas@postgresql.org 10611 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10612 : :
5866 tgl@sss.pgh.pa.us 10613 : 189 : ntups = PQntuples(res);
10614 : :
5085 bruce@momjian.us 10615 : 189 : daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
10616 : :
5866 tgl@sss.pgh.pa.us 10617 : 189 : i_oid = PQfnumber(res, "oid");
10618 : 189 : i_tableoid = PQfnumber(res, "tableoid");
10619 : 189 : i_defaclrole = PQfnumber(res, "defaclrole");
10620 : 189 : i_defaclnamespace = PQfnumber(res, "defaclnamespace");
10621 : 189 : i_defaclobjtype = PQfnumber(res, "defaclobjtype");
10622 : 189 : i_defaclacl = PQfnumber(res, "defaclacl");
1421 10623 : 189 : i_acldefault = PQfnumber(res, "acldefault");
10624 : :
5866 10625 [ + + ]: 383 : for (i = 0; i < ntups; i++)
10626 : : {
5722 bruce@momjian.us 10627 : 194 : Oid nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
10628 : :
5866 tgl@sss.pgh.pa.us 10629 : 194 : daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
10630 : 194 : daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
10631 : 194 : daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
10632 : 194 : AssignDumpId(&daclinfo[i].dobj);
10633 : : /* cheesy ... is it worth coming up with a better object name? */
5085 bruce@momjian.us 10634 : 194 : daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
10635 : :
5866 tgl@sss.pgh.pa.us 10636 [ + + ]: 194 : if (nspid != InvalidOid)
1889 peter@eisentraut.org 10637 : 90 : daclinfo[i].dobj.namespace = findNamespace(nspid);
10638 : : else
5866 tgl@sss.pgh.pa.us 10639 : 104 : daclinfo[i].dobj.namespace = NULL;
10640 : :
1421 10641 : 194 : daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
10642 : 194 : daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
10643 : 194 : daclinfo[i].dacl.privtype = 0;
10644 : 194 : daclinfo[i].dacl.initprivs = NULL;
1396 10645 : 194 : daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
5866 10646 : 194 : daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
10647 : :
10648 : : /* Default ACLs are ACLs, of course */
1421 10649 : 194 : daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10650 : :
10651 : : /* Decide whether we want to dump it */
3575 10652 : 194 : selectDumpableDefaultACL(&(daclinfo[i]), dopt);
10653 : : }
10654 : :
5866 10655 : 189 : PQclear(res);
10656 : :
10657 : 189 : destroyPQExpBuffer(query);
10658 : 189 : }
10659 : :
10660 : : /*
10661 : : * getRoleName -- look up the name of a role, given its OID
10662 : : *
10663 : : * In current usage, we don't expect failures, so error out for a bad OID.
10664 : : */
10665 : : static const char *
1396 10666 : 729911 : getRoleName(const char *roleoid_str)
10667 : : {
10668 : 729911 : Oid roleoid = atooid(roleoid_str);
10669 : :
10670 : : /*
10671 : : * Do binary search to find the appropriate item.
10672 : : */
10673 [ + - ]: 729911 : if (nrolenames > 0)
10674 : : {
10675 : 729911 : RoleNameItem *low = &rolenames[0];
10676 : 729911 : RoleNameItem *high = &rolenames[nrolenames - 1];
10677 : :
10678 [ + - ]: 2919360 : while (low <= high)
10679 : : {
10680 : 2919360 : RoleNameItem *middle = low + (high - low) / 2;
10681 : :
10682 [ + + ]: 2919360 : if (roleoid < middle->roleoid)
10683 : 2188566 : high = middle - 1;
10684 [ + + ]: 730794 : else if (roleoid > middle->roleoid)
10685 : 883 : low = middle + 1;
10686 : : else
10687 : 729911 : return middle->rolename; /* found a match */
10688 : : }
10689 : : }
10690 : :
1298 tgl@sss.pgh.pa.us 10691 :UBC 0 : pg_fatal("role with OID %u does not exist", roleoid);
10692 : : return NULL; /* keep compiler quiet */
10693 : : }
10694 : :
10695 : : /*
10696 : : * collectRoleNames --
10697 : : *
10698 : : * Construct a table of all known roles.
10699 : : * The table is sorted by OID for speed in lookup.
10700 : : */
10701 : : static void
1396 tgl@sss.pgh.pa.us 10702 :CBC 190 : collectRoleNames(Archive *fout)
10703 : : {
10704 : : PGresult *res;
10705 : : const char *query;
10706 : : int i;
10707 : :
10708 : 190 : query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
10709 : :
10710 : 190 : res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
10711 : :
10712 : 190 : nrolenames = PQntuples(res);
10713 : :
10714 : 190 : rolenames = (RoleNameItem *) pg_malloc(nrolenames * sizeof(RoleNameItem));
10715 : :
10716 [ + + ]: 3725 : for (i = 0; i < nrolenames; i++)
10717 : : {
10718 : 3535 : rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
10719 : 3535 : rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
10720 : : }
10721 : :
10722 : 190 : PQclear(res);
10723 : 190 : }
10724 : :
10725 : : /*
10726 : : * getAdditionalACLs
10727 : : *
10728 : : * We have now created all the DumpableObjects, and collected the ACL data
10729 : : * that appears in the directly-associated catalog entries. However, there's
10730 : : * more ACL-related info to collect. If any of a table's columns have ACLs,
10731 : : * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
10732 : : * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
10733 : : * Also, in versions having the pg_init_privs catalog, read that and load the
10734 : : * information into the relevant DumpableObjects.
10735 : : */
10736 : : static void
1421 10737 : 187 : getAdditionalACLs(Archive *fout)
10738 : : {
10739 : 187 : PQExpBuffer query = createPQExpBuffer();
10740 : : PGresult *res;
10741 : : int ntups,
10742 : : i;
10743 : :
10744 : : /* Check for per-column ACLs */
1413 10745 : 187 : appendPQExpBufferStr(query,
10746 : : "SELECT DISTINCT attrelid FROM pg_attribute "
10747 : : "WHERE attacl IS NOT NULL");
10748 : :
10749 : 187 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10750 : :
10751 : 187 : ntups = PQntuples(res);
10752 [ + + ]: 544 : for (i = 0; i < ntups; i++)
10753 : : {
10754 : 357 : Oid relid = atooid(PQgetvalue(res, i, 0));
10755 : : TableInfo *tblinfo;
10756 : :
10757 : 357 : tblinfo = findTableByOid(relid);
10758 : : /* OK to ignore tables we haven't got a DumpableObject for */
10759 [ + - ]: 357 : if (tblinfo)
10760 : : {
10761 : 357 : tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
10762 : 357 : tblinfo->hascolumnACLs = true;
10763 : : }
10764 : : }
10765 : 187 : PQclear(res);
10766 : :
10767 : : /* Fetch initial-privileges data */
1421 10768 [ + - ]: 187 : if (fout->remoteVersion >= 90600)
10769 : : {
10770 : 187 : printfPQExpBuffer(query,
10771 : : "SELECT objoid, classoid, objsubid, privtype, initprivs "
10772 : : "FROM pg_init_privs");
10773 : :
10774 : 187 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10775 : :
10776 : 187 : ntups = PQntuples(res);
10777 [ + + ]: 44440 : for (i = 0; i < ntups; i++)
10778 : : {
10779 : 44253 : Oid objoid = atooid(PQgetvalue(res, i, 0));
10780 : 44253 : Oid classoid = atooid(PQgetvalue(res, i, 1));
10781 : 44253 : int objsubid = atoi(PQgetvalue(res, i, 2));
10782 : 44253 : char privtype = *(PQgetvalue(res, i, 3));
10783 : 44253 : char *initprivs = PQgetvalue(res, i, 4);
10784 : : CatalogId objId;
10785 : : DumpableObject *dobj;
10786 : :
10787 : 44253 : objId.tableoid = classoid;
10788 : 44253 : objId.oid = objoid;
10789 : 44253 : dobj = findObjectByCatalogId(objId);
10790 : : /* OK to ignore entries we haven't got a DumpableObject for */
10791 [ + + ]: 44253 : if (dobj)
10792 : : {
10793 : : /* Cope with sub-object initprivs */
10794 [ + + ]: 31768 : if (objsubid != 0)
10795 : : {
10796 [ + - ]: 3764 : if (dobj->objType == DO_TABLE)
10797 : : {
10798 : : /* For a column initprivs, set the table's ACL flags */
10799 : 3764 : dobj->components |= DUMP_COMPONENT_ACL;
10800 : 3764 : ((TableInfo *) dobj)->hascolumnACLs = true;
10801 : : }
10802 : : else
1421 tgl@sss.pgh.pa.us 10803 :UBC 0 : pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10804 : : classoid, objoid, objsubid);
1421 tgl@sss.pgh.pa.us 10805 :CBC 3947 : continue;
10806 : : }
10807 : :
10808 : : /*
10809 : : * We ignore any pg_init_privs.initprivs entry for the public
10810 : : * schema, as explained in getNamespaces().
10811 : : */
10812 [ + + ]: 28004 : if (dobj->objType == DO_NAMESPACE &&
10813 [ + + ]: 370 : strcmp(dobj->name, "public") == 0)
10814 : 183 : continue;
10815 : :
10816 : : /* Else it had better be of a type we think has ACLs */
10817 [ + + ]: 27821 : if (dobj->objType == DO_NAMESPACE ||
10818 [ + + ]: 27634 : dobj->objType == DO_TYPE ||
10819 [ + + ]: 27610 : dobj->objType == DO_FUNC ||
10820 [ + + ]: 27518 : dobj->objType == DO_AGG ||
10821 [ - + ]: 27494 : dobj->objType == DO_TABLE ||
1421 tgl@sss.pgh.pa.us 10822 [ # # ]:UBC 0 : dobj->objType == DO_PROCLANG ||
10823 [ # # ]: 0 : dobj->objType == DO_FDW ||
10824 [ # # ]: 0 : dobj->objType == DO_FOREIGN_SERVER)
1421 tgl@sss.pgh.pa.us 10825 :CBC 27821 : {
10826 : 27821 : DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
10827 : :
10828 : 27821 : daobj->dacl.privtype = privtype;
10829 : 27821 : daobj->dacl.initprivs = pstrdup(initprivs);
10830 : : }
10831 : : else
1421 tgl@sss.pgh.pa.us 10832 :UBC 0 : pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10833 : : classoid, objoid, objsubid);
10834 : : }
10835 : : }
1421 tgl@sss.pgh.pa.us 10836 :CBC 187 : PQclear(res);
10837 : : }
10838 : :
10839 : 187 : destroyPQExpBuffer(query);
10840 : 187 : }
10841 : :
10842 : : /*
10843 : : * dumpCommentExtended --
10844 : : *
10845 : : * This routine is used to dump any comments associated with the
10846 : : * object handed to this routine. The routine takes the object type
10847 : : * and object name (ready to print, except for schema decoration), plus
10848 : : * the namespace and owner of the object (for labeling the ArchiveEntry),
10849 : : * plus catalog ID and subid which are the lookup key for pg_description,
10850 : : * plus the dump ID for the object (for setting a dependency).
10851 : : * If a matching pg_description entry is found, it is dumped.
10852 : : *
10853 : : * Note: in some cases, such as comments for triggers and rules, the "type"
10854 : : * string really looks like, e.g., "TRIGGER name ON". This is a bit of a hack
10855 : : * but it doesn't seem worth complicating the API for all callers to make
10856 : : * it cleaner.
10857 : : *
10858 : : * Note: although this routine takes a dumpId for dependency purposes,
10859 : : * that purpose is just to mark the dependency in the emitted dump file
10860 : : * for possible future use by pg_restore. We do NOT use it for determining
10861 : : * ordering of the comment in the dump file, because this routine is called
10862 : : * after dependency sorting occurs. This routine should be called just after
10863 : : * calling ArchiveEntry() for the specified object.
10864 : : */
10865 : : static void
1582 noah@leadboat.com 10866 : 6607 : dumpCommentExtended(Archive *fout, const char *type,
10867 : : const char *name, const char *namespace,
10868 : : const char *owner, CatalogId catalogId,
10869 : : int subid, DumpId dumpId,
10870 : : const char *initdb_comment)
10871 : : {
3575 tgl@sss.pgh.pa.us 10872 : 6607 : DumpOptions *dopt = fout->dopt;
10873 : : CommentItem *comments;
10874 : : int ncomments;
10875 : :
10876 : : /* do nothing, if --no-comments is supplied */
2832 10877 [ - + ]: 6607 : if (dopt->no_comments)
2832 tgl@sss.pgh.pa.us 10878 :UBC 0 : return;
10879 : :
10880 : : /* Comments are schema not data ... except LO comments are data */
2800 tgl@sss.pgh.pa.us 10881 [ + + ]:CBC 6607 : if (strcmp(type, "LARGE OBJECT") != 0)
10882 : : {
336 nathan@postgresql.or 10883 [ - + ]: 6548 : if (!dopt->dumpSchema)
5730 tgl@sss.pgh.pa.us 10884 :UBC 0 : return;
10885 : : }
10886 : : else
10887 : : {
10888 : : /* We do dump LO comments in binary-upgrade mode */
336 nathan@postgresql.or 10889 [ + + - + ]:CBC 59 : if (!dopt->dumpData && !dopt->binary_upgrade)
5730 tgl@sss.pgh.pa.us 10890 :UBC 0 : return;
10891 : : }
10892 : :
10893 : : /* Search for comments associated with catalogId, using table */
1397 tgl@sss.pgh.pa.us 10894 :CBC 6607 : ncomments = findComments(catalogId.tableoid, catalogId.oid,
10895 : : &comments);
10896 : :
10897 : : /* Is there one matching the subid? */
7891 10898 [ + + ]: 6607 : while (ncomments > 0)
10899 : : {
10900 [ + - ]: 6561 : if (comments->objsubid == subid)
10901 : 6561 : break;
7891 tgl@sss.pgh.pa.us 10902 :UBC 0 : comments++;
10903 : 0 : ncomments--;
10904 : : }
10905 : :
1582 noah@leadboat.com 10906 [ + + ]:CBC 6607 : if (initdb_comment != NULL)
10907 : : {
10908 : : static CommentItem empty_comment = {.descr = ""};
10909 : :
10910 : : /*
10911 : : * initdb creates this object with a comment. Skip dumping the
10912 : : * initdb-provided comment, which would complicate matters for
10913 : : * non-superuser use of pg_dump. When the DBA has removed initdb's
10914 : : * comment, replicate that.
10915 : : */
10916 [ + + ]: 120 : if (ncomments == 0)
10917 : : {
10918 : 4 : comments = &empty_comment;
10919 : 4 : ncomments = 1;
10920 : : }
10921 [ + - ]: 116 : else if (strcmp(comments->descr, initdb_comment) == 0)
10922 : 116 : ncomments = 0;
10923 : : }
10924 : :
10925 : : /* If a comment exists, build COMMENT ON statement */
7891 tgl@sss.pgh.pa.us 10926 [ + + ]: 6607 : if (ncomments > 0)
10927 : : {
10928 : 6449 : PQExpBuffer query = createPQExpBuffer();
2800 10929 : 6449 : PQExpBuffer tag = createPQExpBuffer();
10930 : :
10931 : 6449 : appendPQExpBuffer(query, "COMMENT ON %s ", type);
10932 [ + + + - ]: 6449 : if (namespace && *namespace)
10933 : 6273 : appendPQExpBuffer(query, "%s.", fmtId(namespace));
10934 : 6449 : appendPQExpBuffer(query, "%s IS ", name);
7092 10935 : 6449 : appendStringLiteralAH(query, comments->descr, fout);
4361 heikki.linnakangas@i 10936 : 6449 : appendPQExpBufferStr(query, ";\n");
10937 : :
2800 tgl@sss.pgh.pa.us 10938 : 6449 : appendPQExpBuffer(tag, "%s %s", type, name);
10939 : :
10940 : : /*
10941 : : * We mark comments as SECTION_NONE because they really belong in the
10942 : : * same section as their parent, whether that is pre-data or
10943 : : * post-data.
10944 : : */
7996 10945 : 6449 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 10946 : 6449 : ARCHIVE_OPTS(.tag = tag->data,
10947 : : .namespace = namespace,
10948 : : .owner = owner,
10949 : : .description = "COMMENT",
10950 : : .section = SECTION_NONE,
10951 : : .createStmt = query->data,
10952 : : .deps = &dumpId,
10953 : : .nDeps = 1));
10954 : :
7891 tgl@sss.pgh.pa.us 10955 : 6449 : destroyPQExpBuffer(query);
2800 10956 : 6449 : destroyPQExpBuffer(tag);
10957 : : }
10958 : : }
10959 : :
10960 : : /*
10961 : : * dumpComment --
10962 : : *
10963 : : * Typical simplification of the above function.
10964 : : */
10965 : : static inline void
1582 noah@leadboat.com 10966 : 6448 : dumpComment(Archive *fout, const char *type,
10967 : : const char *name, const char *namespace,
10968 : : const char *owner, CatalogId catalogId,
10969 : : int subid, DumpId dumpId)
10970 : : {
10971 : 6448 : dumpCommentExtended(fout, type, name, namespace, owner,
10972 : : catalogId, subid, dumpId, NULL);
10973 : 6448 : }
10974 : :
10975 : : /*
10976 : : * appendNamedArgument --
10977 : : *
10978 : : * Convenience routine for constructing parameters of the form:
10979 : : * 'paraname', 'value'::type
10980 : : */
10981 : : static void
249 jdavis@postgresql.or 10982 : 5496 : appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
10983 : : const char *argtype, const char *argval)
10984 : : {
243 tgl@sss.pgh.pa.us 10985 : 5496 : appendPQExpBufferStr(out, ",\n\t");
10986 : :
249 jdavis@postgresql.or 10987 : 5496 : appendStringLiteralAH(out, argname, fout);
10988 : 5496 : appendPQExpBufferStr(out, ", ");
10989 : :
10990 : 5496 : appendStringLiteralAH(out, argval, fout);
10991 : 5496 : appendPQExpBuffer(out, "::%s", argtype);
10992 : 5496 : }
10993 : :
10994 : : /*
10995 : : * fetchAttributeStats --
10996 : : *
10997 : : * Fetch next batch of attribute statistics for dumpRelationStats_dumper().
10998 : : */
10999 : : static PGresult *
206 nathan@postgresql.or 11000 : 1037 : fetchAttributeStats(Archive *fout)
11001 : : {
11002 : 1037 : ArchiveHandle *AH = (ArchiveHandle *) fout;
11003 : 1037 : PQExpBuffer nspnames = createPQExpBuffer();
11004 : 1037 : PQExpBuffer relnames = createPQExpBuffer();
11005 : 1037 : int count = 0;
11006 : 1037 : PGresult *res = NULL;
11007 : : static TocEntry *te;
11008 : : static bool restarted;
11009 : 1037 : int max_rels = MAX_ATTR_STATS_RELS;
11010 : :
11011 : : /*
11012 : : * Our query for retrieving statistics for multiple relations uses WITH
11013 : : * ORDINALITY and multi-argument UNNEST(), both of which were introduced
11014 : : * in v9.4. For older versions, we resort to gathering statistics for a
11015 : : * single relation at a time.
11016 : : */
11017 [ - + ]: 1037 : if (fout->remoteVersion < 90400)
206 nathan@postgresql.or 11018 :UBC 0 : max_rels = 1;
11019 : :
11020 : : /* If we're just starting, set our TOC pointer. */
206 nathan@postgresql.or 11021 [ + + ]:CBC 1037 : if (!te)
11022 : 64 : te = AH->toc->next;
11023 : :
11024 : : /*
11025 : : * We can't easily avoid a second TOC scan for the tar format because it
11026 : : * writes restore.sql separately, which means we must execute the queries
11027 : : * twice. This feels risky, but there is no known reason it should
11028 : : * generate different output than the first pass. Even if it does, the
11029 : : * worst-case scenario is that restore.sql might have different statistics
11030 : : * data than the archive.
11031 : : */
11032 [ + + + + : 1037 : if (!restarted && te == AH->toc && AH->format == archTar)
+ + ]
11033 : : {
11034 : 1 : te = AH->toc->next;
11035 : 1 : restarted = true;
11036 : : }
11037 : :
160 11038 : 1037 : appendPQExpBufferChar(nspnames, '{');
11039 : 1037 : appendPQExpBufferChar(relnames, '{');
11040 : :
11041 : : /*
11042 : : * Scan the TOC for the next set of relevant stats entries. We assume
11043 : : * that statistics are dumped in the order they are listed in the TOC.
11044 : : * This is perhaps not the sturdiest assumption, so we verify it matches
11045 : : * reality in dumpRelationStats_dumper().
11046 : : */
206 11047 [ + + + + ]: 15668 : for (; te != AH->toc && count < max_rels; te = te->next)
11048 : : {
11049 [ + + ]: 14631 : if ((te->reqs & REQ_STATS) != 0 &&
11050 [ + - ]: 3226 : strcmp(te->desc, "STATISTICS DATA") == 0)
11051 : : {
160 11052 : 3226 : appendPGArray(nspnames, te->namespace);
11053 : 3226 : appendPGArray(relnames, te->tag);
206 11054 : 3226 : count++;
11055 : : }
11056 : : }
11057 : :
160 11058 : 1037 : appendPQExpBufferChar(nspnames, '}');
11059 : 1037 : appendPQExpBufferChar(relnames, '}');
11060 : :
11061 : : /* Execute the query for the next batch of relations. */
206 11062 [ + + ]: 1037 : if (count > 0)
11063 : : {
11064 : 107 : PQExpBuffer query = createPQExpBuffer();
11065 : :
160 11066 : 107 : appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
11067 : 107 : appendStringLiteralAH(query, nspnames->data, fout);
11068 : 107 : appendPQExpBufferStr(query, "::pg_catalog.name[],");
11069 : 107 : appendStringLiteralAH(query, relnames->data, fout);
11070 : 107 : appendPQExpBufferStr(query, "::pg_catalog.name[])");
206 11071 : 107 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11072 : 107 : destroyPQExpBuffer(query);
11073 : : }
11074 : :
11075 : 1037 : destroyPQExpBuffer(nspnames);
11076 : 1037 : destroyPQExpBuffer(relnames);
11077 : 1037 : return res;
11078 : : }
11079 : :
11080 : : /*
11081 : : * dumpRelationStats_dumper --
11082 : : *
11083 : : * Generate command to import stats into the relation on the new database.
11084 : : * This routine is called by the Archiver when it wants the statistics to be
11085 : : * dumped.
11086 : : */
11087 : : static char *
11088 : 3226 : dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
11089 : : {
11090 : 3226 : const RelStatsInfo *rsinfo = (RelStatsInfo *) userArg;
11091 : : static PGresult *res;
11092 : : static int rownum;
11093 : : PQExpBuffer query;
11094 : : PQExpBufferData out_data;
11095 : 3226 : PQExpBuffer out = &out_data;
11096 : : int i_schemaname;
11097 : : int i_tablename;
11098 : : int i_attname;
11099 : : int i_inherited;
11100 : : int i_null_frac;
11101 : : int i_avg_width;
11102 : : int i_n_distinct;
11103 : : int i_most_common_vals;
11104 : : int i_most_common_freqs;
11105 : : int i_histogram_bounds;
11106 : : int i_correlation;
11107 : : int i_most_common_elems;
11108 : : int i_most_common_elem_freqs;
11109 : : int i_elem_count_histogram;
11110 : : int i_range_length_histogram;
11111 : : int i_range_empty_frac;
11112 : : int i_range_bounds_histogram;
11113 : : static TocEntry *expected_te;
11114 : :
11115 : : /*
11116 : : * fetchAttributeStats() assumes that the statistics are dumped in the
11117 : : * order they are listed in the TOC. We verify that here for safety.
11118 : : */
11119 [ + + ]: 3226 : if (!expected_te)
11120 : 64 : expected_te = ((ArchiveHandle *) fout)->toc;
11121 : :
11122 : 3226 : expected_te = expected_te->next;
11123 [ + + ]: 12863 : while ((expected_te->reqs & REQ_STATS) == 0 ||
11124 [ - + ]: 3226 : strcmp(expected_te->desc, "STATISTICS DATA") != 0)
11125 : 9637 : expected_te = expected_te->next;
11126 : :
11127 [ - + ]: 3226 : if (te != expected_te)
133 peter@eisentraut.org 11128 :UBC 0 : pg_fatal("statistics dumped out of order (current: %d %s %s, expected: %d %s %s)",
11129 : : te->dumpId, te->desc, te->tag,
11130 : : expected_te->dumpId, expected_te->desc, expected_te->tag);
11131 : :
244 jdavis@postgresql.or 11132 :CBC 3226 : query = createPQExpBuffer();
11133 [ + + ]: 3226 : if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
11134 : : {
11135 : 64 : appendPQExpBufferStr(query,
11136 : : "PREPARE getAttributeStats(pg_catalog.name[], pg_catalog.name[]) AS\n"
11137 : : "SELECT s.schemaname, s.tablename, s.attname, s.inherited, "
11138 : : "s.null_frac, s.avg_width, s.n_distinct, "
11139 : : "s.most_common_vals, s.most_common_freqs, "
11140 : : "s.histogram_bounds, s.correlation, "
11141 : : "s.most_common_elems, s.most_common_elem_freqs, "
11142 : : "s.elem_count_histogram, ");
11143 : :
11144 [ + - ]: 64 : if (fout->remoteVersion >= 170000)
11145 : 64 : appendPQExpBufferStr(query,
11146 : : "s.range_length_histogram, "
11147 : : "s.range_empty_frac, "
11148 : : "s.range_bounds_histogram ");
11149 : : else
244 jdavis@postgresql.or 11150 :UBC 0 : appendPQExpBufferStr(query,
11151 : : "NULL AS range_length_histogram,"
11152 : : "NULL AS range_empty_frac,"
11153 : : "NULL AS range_bounds_histogram ");
11154 : :
11155 : : /*
11156 : : * The results must be in the order of the relations supplied in the
11157 : : * parameters to ensure we remain in sync as we walk through the TOC.
11158 : : * The redundant filter clause on s.tablename = ANY(...) seems
11159 : : * sufficient to convince the planner to use
11160 : : * pg_class_relname_nsp_index, which avoids a full scan of pg_stats.
11161 : : * This may not work for all versions.
11162 : : *
11163 : : * Our query for retrieving statistics for multiple relations uses
11164 : : * WITH ORDINALITY and multi-argument UNNEST(), both of which were
11165 : : * introduced in v9.4. For older versions, we resort to gathering
11166 : : * statistics for a single relation at a time.
11167 : : */
206 nathan@postgresql.or 11168 [ + - ]:CBC 64 : if (fout->remoteVersion >= 90400)
11169 : 64 : appendPQExpBufferStr(query,
11170 : : "FROM pg_catalog.pg_stats s "
11171 : : "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) "
11172 : : "ON s.schemaname = u.schemaname "
11173 : : "AND s.tablename = u.tablename "
11174 : : "WHERE s.tablename = ANY($2) "
11175 : : "ORDER BY u.ord, s.attname, s.inherited");
11176 : : else
206 nathan@postgresql.or 11177 :UBC 0 : appendPQExpBufferStr(query,
11178 : : "FROM pg_catalog.pg_stats s "
11179 : : "WHERE s.schemaname = $1[1] "
11180 : : "AND s.tablename = $2[1] "
11181 : : "ORDER BY s.attname, s.inherited");
11182 : :
244 jdavis@postgresql.or 11183 :CBC 64 : ExecuteSqlStatement(fout, query->data);
11184 : :
11185 : 64 : fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
11186 : 64 : resetPQExpBuffer(query);
11187 : : }
11188 : :
206 nathan@postgresql.or 11189 : 3226 : initPQExpBuffer(out);
11190 : :
11191 : : /* restore relation stats */
243 tgl@sss.pgh.pa.us 11192 : 3226 : appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
200 peter@eisentraut.org 11193 : 3226 : appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
11194 : : fout->remoteVersion);
216 jdavis@postgresql.or 11195 : 3226 : appendPQExpBufferStr(out, "\t'schemaname', ");
11196 : 3226 : appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
11197 : 3226 : appendPQExpBufferStr(out, ",\n");
11198 : 3226 : appendPQExpBufferStr(out, "\t'relname', ");
11199 : 3226 : appendStringLiteralAH(out, rsinfo->dobj.name, fout);
11200 : 3226 : appendPQExpBufferStr(out, ",\n");
243 tgl@sss.pgh.pa.us 11201 : 3226 : appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
11202 : :
11203 : : /*
11204 : : * Before v14, a reltuples value of 0 was ambiguous: it could either mean
11205 : : * the relation is empty, or it could mean that it hadn't yet been
11206 : : * vacuumed or analyzed. (Newer versions use -1 for the latter case.)
11207 : : * This ambiguity allegedly can cause the planner to choose inefficient
11208 : : * plans after restoring to v18 or newer. To deal with this, let's just
11209 : : * set reltuples to -1 in that case.
11210 : : */
158 nathan@postgresql.or 11211 [ - + - - ]: 3226 : if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
158 nathan@postgresql.or 11212 :UBC 0 : appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
11213 : : else
158 nathan@postgresql.or 11214 :CBC 3226 : appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
11215 : :
211 jdavis@postgresql.or 11216 : 3226 : appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
243 tgl@sss.pgh.pa.us 11217 : 3226 : rsinfo->relallvisible);
11218 : :
211 jdavis@postgresql.or 11219 [ + - ]: 3226 : if (fout->remoteVersion >= 180000)
11220 : 3226 : appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
11221 : :
11222 : 3226 : appendPQExpBufferStr(out, "\n);\n");
11223 : :
11224 : : /* Fetch the next batch of attribute statistics if needed. */
206 nathan@postgresql.or 11225 [ + + ]: 3226 : if (rownum >= PQntuples(res))
11226 : : {
11227 : 1037 : PQclear(res);
11228 : 1037 : res = fetchAttributeStats(fout);
11229 : 1037 : rownum = 0;
11230 : : }
11231 : :
11232 : 3226 : i_schemaname = PQfnumber(res, "schemaname");
11233 : 3226 : i_tablename = PQfnumber(res, "tablename");
243 tgl@sss.pgh.pa.us 11234 : 3226 : i_attname = PQfnumber(res, "attname");
11235 : 3226 : i_inherited = PQfnumber(res, "inherited");
11236 : 3226 : i_null_frac = PQfnumber(res, "null_frac");
11237 : 3226 : i_avg_width = PQfnumber(res, "avg_width");
11238 : 3226 : i_n_distinct = PQfnumber(res, "n_distinct");
11239 : 3226 : i_most_common_vals = PQfnumber(res, "most_common_vals");
11240 : 3226 : i_most_common_freqs = PQfnumber(res, "most_common_freqs");
11241 : 3226 : i_histogram_bounds = PQfnumber(res, "histogram_bounds");
11242 : 3226 : i_correlation = PQfnumber(res, "correlation");
11243 : 3226 : i_most_common_elems = PQfnumber(res, "most_common_elems");
11244 : 3226 : i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
11245 : 3226 : i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
11246 : 3226 : i_range_length_histogram = PQfnumber(res, "range_length_histogram");
11247 : 3226 : i_range_empty_frac = PQfnumber(res, "range_empty_frac");
11248 : 3226 : i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
11249 : :
11250 : : /* restore attribute stats */
206 nathan@postgresql.or 11251 [ + + ]: 4053 : for (; rownum < PQntuples(res); rownum++)
11252 : : {
11253 : : const char *attname;
11254 : :
11255 : : /* Stop if the next stat row in our cache isn't for this relation. */
11256 [ + + ]: 3016 : if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
11257 [ + - ]: 827 : strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
11258 : : break;
11259 : :
243 tgl@sss.pgh.pa.us 11260 : 827 : appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
200 peter@eisentraut.org 11261 : 827 : appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
11262 : : fout->remoteVersion);
216 jdavis@postgresql.or 11263 : 827 : appendPQExpBufferStr(out, "\t'schemaname', ");
11264 : 827 : appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
11265 : 827 : appendPQExpBufferStr(out, ",\n\t'relname', ");
11266 : 827 : appendStringLiteralAH(out, rsinfo->dobj.name, fout);
11267 : :
243 tgl@sss.pgh.pa.us 11268 [ - + ]: 827 : if (PQgetisnull(res, rownum, i_attname))
133 peter@eisentraut.org 11269 :UBC 0 : pg_fatal("unexpected null attname");
243 tgl@sss.pgh.pa.us 11270 :CBC 827 : attname = PQgetvalue(res, rownum, i_attname);
11271 : :
11272 : : /*
11273 : : * Indexes look up attname in indAttNames to derive attnum, all others
11274 : : * use attname directly. We must specify attnum for indexes, since
11275 : : * their attnames are not necessarily stable across dump/reload.
11276 : : */
11277 [ + + ]: 827 : if (rsinfo->nindAttNames == 0)
11278 : : {
193 drowley@postgresql.o 11279 : 792 : appendPQExpBufferStr(out, ",\n\t'attname', ");
216 jdavis@postgresql.or 11280 : 792 : appendStringLiteralAH(out, attname, fout);
11281 : : }
11282 : : else
11283 : : {
243 tgl@sss.pgh.pa.us 11284 : 35 : bool found = false;
11285 : :
11286 [ + - ]: 66 : for (int i = 0; i < rsinfo->nindAttNames; i++)
11287 : : {
11288 [ + + ]: 66 : if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
11289 : : {
11290 : 35 : appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
11291 : : i + 1);
11292 : 35 : found = true;
11293 : 35 : break;
11294 : : }
11295 : : }
11296 : :
11297 [ - + ]: 35 : if (!found)
243 tgl@sss.pgh.pa.us 11298 :UBC 0 : pg_fatal("could not find index attname \"%s\"", attname);
11299 : : }
11300 : :
243 tgl@sss.pgh.pa.us 11301 [ + - ]:CBC 827 : if (!PQgetisnull(res, rownum, i_inherited))
11302 : 827 : appendNamedArgument(out, fout, "inherited", "boolean",
11303 : 827 : PQgetvalue(res, rownum, i_inherited));
11304 [ + - ]: 827 : if (!PQgetisnull(res, rownum, i_null_frac))
11305 : 827 : appendNamedArgument(out, fout, "null_frac", "real",
11306 : 827 : PQgetvalue(res, rownum, i_null_frac));
11307 [ + - ]: 827 : if (!PQgetisnull(res, rownum, i_avg_width))
11308 : 827 : appendNamedArgument(out, fout, "avg_width", "integer",
11309 : 827 : PQgetvalue(res, rownum, i_avg_width));
11310 [ + - ]: 827 : if (!PQgetisnull(res, rownum, i_n_distinct))
11311 : 827 : appendNamedArgument(out, fout, "n_distinct", "real",
11312 : 827 : PQgetvalue(res, rownum, i_n_distinct));
11313 [ + + ]: 827 : if (!PQgetisnull(res, rownum, i_most_common_vals))
11314 : 429 : appendNamedArgument(out, fout, "most_common_vals", "text",
11315 : 429 : PQgetvalue(res, rownum, i_most_common_vals));
11316 [ + + ]: 827 : if (!PQgetisnull(res, rownum, i_most_common_freqs))
11317 : 429 : appendNamedArgument(out, fout, "most_common_freqs", "real[]",
11318 : 429 : PQgetvalue(res, rownum, i_most_common_freqs));
11319 [ + + ]: 827 : if (!PQgetisnull(res, rownum, i_histogram_bounds))
11320 : 508 : appendNamedArgument(out, fout, "histogram_bounds", "text",
11321 : 508 : PQgetvalue(res, rownum, i_histogram_bounds));
11322 [ + + ]: 827 : if (!PQgetisnull(res, rownum, i_correlation))
11323 : 787 : appendNamedArgument(out, fout, "correlation", "real",
11324 : 787 : PQgetvalue(res, rownum, i_correlation));
11325 [ + + ]: 827 : if (!PQgetisnull(res, rownum, i_most_common_elems))
11326 : 8 : appendNamedArgument(out, fout, "most_common_elems", "text",
11327 : 8 : PQgetvalue(res, rownum, i_most_common_elems));
11328 [ + + ]: 827 : if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
11329 : 8 : appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
11330 : 8 : PQgetvalue(res, rownum, i_most_common_elem_freqs));
11331 [ + + ]: 827 : if (!PQgetisnull(res, rownum, i_elem_count_histogram))
11332 : 7 : appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
11333 : 7 : PQgetvalue(res, rownum, i_elem_count_histogram));
11334 [ + - ]: 827 : if (fout->remoteVersion >= 170000)
11335 : : {
11336 [ + + ]: 827 : if (!PQgetisnull(res, rownum, i_range_length_histogram))
11337 : 4 : appendNamedArgument(out, fout, "range_length_histogram", "text",
11338 : 4 : PQgetvalue(res, rownum, i_range_length_histogram));
11339 [ + + ]: 827 : if (!PQgetisnull(res, rownum, i_range_empty_frac))
11340 : 4 : appendNamedArgument(out, fout, "range_empty_frac", "real",
11341 : 4 : PQgetvalue(res, rownum, i_range_empty_frac));
11342 [ + + ]: 827 : if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
11343 : 4 : appendNamedArgument(out, fout, "range_bounds_histogram", "text",
11344 : 4 : PQgetvalue(res, rownum, i_range_bounds_histogram));
11345 : : }
11346 : 827 : appendPQExpBufferStr(out, "\n);\n");
11347 : : }
11348 : :
206 nathan@postgresql.or 11349 : 3226 : destroyPQExpBuffer(query);
11350 : 3226 : return out->data;
11351 : : }
11352 : :
11353 : : /*
11354 : : * dumpRelationStats --
11355 : : *
11356 : : * Make an ArchiveEntry for the relation statistics. The Archiver will take
11357 : : * care of gathering the statistics and generating the restore commands when
11358 : : * they are needed.
11359 : : */
11360 : : static void
11361 : 3295 : dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
11362 : : {
11363 : 3295 : const DumpableObject *dobj = &rsinfo->dobj;
11364 : :
11365 : : /* nothing to do if we are not dumping statistics */
11366 [ - + ]: 3295 : if (!fout->dopt->dumpStatistics)
206 nathan@postgresql.or 11367 :UBC 0 : return;
11368 : :
249 jdavis@postgresql.or 11369 :CBC 3295 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
242 11370 : 3295 : ARCHIVE_OPTS(.tag = dobj->name,
11371 : : .namespace = dobj->namespace->dobj.name,
11372 : : .description = "STATISTICS DATA",
11373 : : .section = rsinfo->section,
11374 : : .defnFn = dumpRelationStats_dumper,
11375 : : .defnArg = rsinfo,
11376 : : .deps = dobj->dependencies,
11377 : : .nDeps = dobj->nDeps));
11378 : : }
11379 : :
11380 : : /*
11381 : : * dumpTableComment --
11382 : : *
11383 : : * As above, but dump comments for both the specified table (or view)
11384 : : * and its columns.
11385 : : */
11386 : : static void
1720 peter@eisentraut.org 11387 : 74 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
11388 : : const char *reltypename)
11389 : : {
3575 tgl@sss.pgh.pa.us 11390 : 74 : DumpOptions *dopt = fout->dopt;
11391 : : CommentItem *comments;
11392 : : int ncomments;
11393 : : PQExpBuffer query;
11394 : : PQExpBuffer tag;
11395 : :
11396 : : /* do nothing, if --no-comments is supplied */
2832 11397 [ - + ]: 74 : if (dopt->no_comments)
2832 tgl@sss.pgh.pa.us 11398 :UBC 0 : return;
11399 : :
11400 : : /* Comments are SCHEMA not data */
336 nathan@postgresql.or 11401 [ - + ]:CBC 74 : if (!dopt->dumpSchema)
8571 tgl@sss.pgh.pa.us 11402 :UBC 0 : return;
11403 : :
11404 : : /* Search for comments associated with relation, using table */
1397 tgl@sss.pgh.pa.us 11405 :CBC 74 : ncomments = findComments(tbinfo->dobj.catId.tableoid,
7891 11406 : 74 : tbinfo->dobj.catId.oid,
11407 : : &comments);
11408 : :
11409 : : /* If comments exist, build COMMENT ON statements */
11410 [ - + ]: 74 : if (ncomments <= 0)
7891 tgl@sss.pgh.pa.us 11411 :UBC 0 : return;
11412 : :
8571 tgl@sss.pgh.pa.us 11413 :CBC 74 : query = createPQExpBuffer();
2800 11414 : 74 : tag = createPQExpBuffer();
11415 : :
7891 11416 [ + + ]: 212 : while (ncomments > 0)
11417 : : {
11418 : 138 : const char *descr = comments->descr;
11419 : 138 : int objsubid = comments->objsubid;
11420 : :
8571 11421 [ + + ]: 138 : if (objsubid == 0)
11422 : : {
2800 11423 : 32 : resetPQExpBuffer(tag);
11424 : 32 : appendPQExpBuffer(tag, "%s %s", reltypename,
7908 11425 : 32 : fmtId(tbinfo->dobj.name));
11426 : :
8571 11427 : 32 : resetPQExpBuffer(query);
2800 11428 : 32 : appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
11429 : 32 : fmtQualifiedDumpable(tbinfo));
7092 11430 : 32 : appendStringLiteralAH(query, descr, fout);
4361 heikki.linnakangas@i 11431 : 32 : appendPQExpBufferStr(query, ";\n");
11432 : :
7996 tgl@sss.pgh.pa.us 11433 : 32 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 11434 : 32 : ARCHIVE_OPTS(.tag = tag->data,
11435 : : .namespace = tbinfo->dobj.namespace->dobj.name,
11436 : : .owner = tbinfo->rolname,
11437 : : .description = "COMMENT",
11438 : : .section = SECTION_NONE,
11439 : : .createStmt = query->data,
11440 : : .deps = &(tbinfo->dobj.dumpId),
11441 : : .nDeps = 1));
11442 : : }
8571 tgl@sss.pgh.pa.us 11443 [ + - + - ]: 106 : else if (objsubid > 0 && objsubid <= tbinfo->numatts)
11444 : : {
2800 11445 : 106 : resetPQExpBuffer(tag);
11446 : 106 : appendPQExpBuffer(tag, "COLUMN %s.",
7908 11447 : 106 : fmtId(tbinfo->dobj.name));
2800 11448 : 106 : appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
11449 : :
8571 11450 : 106 : resetPQExpBuffer(query);
2800 11451 : 106 : appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11452 : 106 : fmtQualifiedDumpable(tbinfo));
11453 : 106 : appendPQExpBuffer(query, "%s IS ",
11454 : 106 : fmtId(tbinfo->attnames[objsubid - 1]));
7092 11455 : 106 : appendStringLiteralAH(query, descr, fout);
4361 heikki.linnakangas@i 11456 : 106 : appendPQExpBufferStr(query, ";\n");
11457 : :
7996 tgl@sss.pgh.pa.us 11458 : 106 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 11459 : 106 : ARCHIVE_OPTS(.tag = tag->data,
11460 : : .namespace = tbinfo->dobj.namespace->dobj.name,
11461 : : .owner = tbinfo->rolname,
11462 : : .description = "COMMENT",
11463 : : .section = SECTION_NONE,
11464 : : .createStmt = query->data,
11465 : : .deps = &(tbinfo->dobj.dumpId),
11466 : : .nDeps = 1));
11467 : : }
11468 : :
7891 tgl@sss.pgh.pa.us 11469 : 138 : comments++;
11470 : 138 : ncomments--;
11471 : : }
11472 : :
8851 11473 : 74 : destroyPQExpBuffer(query);
2800 11474 : 74 : destroyPQExpBuffer(tag);
11475 : : }
11476 : :
11477 : : /*
11478 : : * findComments --
11479 : : *
11480 : : * Find the comment(s), if any, associated with the given object. All the
11481 : : * objsubid values associated with the given classoid/objoid are found with
11482 : : * one search.
11483 : : */
11484 : : static int
1397 11485 : 6713 : findComments(Oid classoid, Oid objoid, CommentItem **items)
11486 : : {
7891 11487 : 6713 : CommentItem *middle = NULL;
11488 : : CommentItem *low;
11489 : : CommentItem *high;
11490 : : int nmatch;
11491 : :
11492 : : /*
11493 : : * Do binary search to find some item matching the object.
11494 : : */
11495 : 6713 : low = &comments[0];
7729 bruce@momjian.us 11496 : 6713 : high = &comments[ncomments - 1];
7891 tgl@sss.pgh.pa.us 11497 [ + + ]: 67147 : while (low <= high)
11498 : : {
11499 : 67101 : middle = low + (high - low) / 2;
11500 : :
11501 [ + + ]: 67101 : if (classoid < middle->classoid)
11502 : 7533 : high = middle - 1;
11503 [ + + ]: 59568 : else if (classoid > middle->classoid)
11504 : 7177 : low = middle + 1;
11505 [ + + ]: 52391 : else if (objoid < middle->objoid)
11506 : 22497 : high = middle - 1;
11507 [ + + ]: 29894 : else if (objoid > middle->objoid)
11508 : 23227 : low = middle + 1;
11509 : : else
11510 : 6667 : break; /* found a match */
11511 : : }
11512 : :
11513 [ + + ]: 6713 : if (low > high) /* no matches */
11514 : : {
11515 : 46 : *items = NULL;
11516 : 46 : return 0;
11517 : : }
11518 : :
11519 : : /*
11520 : : * Now determine how many items match the object. The search loop
11521 : : * invariant still holds: only items between low and high inclusive could
11522 : : * match.
11523 : : */
11524 : 6667 : nmatch = 1;
11525 [ + + ]: 6679 : while (middle > low)
11526 : : {
11527 [ + + ]: 3231 : if (classoid != middle[-1].classoid ||
11528 [ + + ]: 3127 : objoid != middle[-1].objoid)
11529 : : break;
7891 tgl@sss.pgh.pa.us 11530 :GBC 12 : middle--;
11531 : 12 : nmatch++;
11532 : : }
11533 : :
7891 tgl@sss.pgh.pa.us 11534 :CBC 6667 : *items = middle;
11535 : :
11536 : 6667 : middle += nmatch;
11537 [ + + ]: 6719 : while (middle <= high)
11538 : : {
11539 [ + + ]: 3486 : if (classoid != middle->classoid ||
11540 [ + + ]: 3176 : objoid != middle->objoid)
11541 : : break;
11542 : 52 : middle++;
11543 : 52 : nmatch++;
11544 : : }
11545 : :
11546 : 6667 : return nmatch;
11547 : : }
11548 : :
11549 : : /*
11550 : : * collectComments --
11551 : : *
11552 : : * Construct a table of all comments available for database objects;
11553 : : * also set the has-comment component flag for each relevant object.
11554 : : *
11555 : : * We used to do per-object queries for the comments, but it's much faster
11556 : : * to pull them all over at once, and on most databases the memory cost
11557 : : * isn't high.
11558 : : *
11559 : : * The table is sorted by classoid/objid/objsubid for speed in lookup.
11560 : : */
11561 : : static void
1421 11562 : 189 : collectComments(Archive *fout)
11563 : : {
11564 : : PGresult *res;
11565 : : PQExpBuffer query;
11566 : : int i_description;
11567 : : int i_classoid;
11568 : : int i_objoid;
11569 : : int i_objsubid;
11570 : : int ntups;
11571 : : int i;
11572 : : DumpableObject *dobj;
11573 : :
7891 11574 : 189 : query = createPQExpBuffer();
11575 : :
3302 11576 : 189 : appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
11577 : : "FROM pg_catalog.pg_description "
11578 : : "ORDER BY classoid, objoid, objsubid");
11579 : :
5011 rhaas@postgresql.org 11580 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11581 : :
11582 : : /* Construct lookup table containing OIDs in numeric form */
11583 : :
7891 tgl@sss.pgh.pa.us 11584 : 189 : i_description = PQfnumber(res, "description");
11585 : 189 : i_classoid = PQfnumber(res, "classoid");
11586 : 189 : i_objoid = PQfnumber(res, "objoid");
11587 : 189 : i_objsubid = PQfnumber(res, "objsubid");
11588 : :
11589 : 189 : ntups = PQntuples(res);
11590 : :
5085 bruce@momjian.us 11591 : 189 : comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
1421 tgl@sss.pgh.pa.us 11592 : 189 : ncomments = 0;
11593 : 189 : dobj = NULL;
11594 : :
7891 11595 [ + + ]: 1016155 : for (i = 0; i < ntups; i++)
11596 : : {
11597 : : CatalogId objId;
11598 : : int subid;
11599 : :
1421 11600 : 1015966 : objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
11601 : 1015966 : objId.oid = atooid(PQgetvalue(res, i, i_objoid));
11602 : 1015966 : subid = atoi(PQgetvalue(res, i, i_objsubid));
11603 : :
11604 : : /* We needn't remember comments that don't match any dumpable object */
11605 [ + + ]: 1015966 : if (dobj == NULL ||
11606 [ + + ]: 370631 : dobj->catId.tableoid != objId.tableoid ||
11607 [ + + ]: 368315 : dobj->catId.oid != objId.oid)
11608 : 1015876 : dobj = findObjectByCatalogId(objId);
11609 [ + + ]: 1015966 : if (dobj == NULL)
11610 : 645152 : continue;
11611 : :
11612 : : /*
11613 : : * Comments on columns of composite types are linked to the type's
11614 : : * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
11615 : : * in the type's own DumpableObject.
11616 : : */
11617 [ + + + - ]: 370814 : if (subid != 0 && dobj->objType == DO_TABLE &&
11618 [ + + ]: 194 : ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
11619 : 45 : {
11620 : : TypeInfo *cTypeInfo;
11621 : :
11622 : 45 : cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
11623 [ + - ]: 45 : if (cTypeInfo)
11624 : 45 : cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
11625 : : }
11626 : : else
11627 : 370769 : dobj->components |= DUMP_COMPONENT_COMMENT;
11628 : :
11629 : 370814 : comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
11630 : 370814 : comments[ncomments].classoid = objId.tableoid;
11631 : 370814 : comments[ncomments].objoid = objId.oid;
11632 : 370814 : comments[ncomments].objsubid = subid;
11633 : 370814 : ncomments++;
11634 : : }
11635 : :
11636 : 189 : PQclear(res);
7891 11637 : 189 : destroyPQExpBuffer(query);
11638 : 189 : }
11639 : :
11640 : : /*
11641 : : * dumpDumpableObject
11642 : : *
11643 : : * This routine and its subsidiaries are responsible for creating
11644 : : * ArchiveEntries (TOC objects) for each object to be dumped.
11645 : : */
11646 : : static void
1421 11647 : 832618 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
11648 : : {
11649 : : /*
11650 : : * Clear any dump-request bits for components that don't exist for this
11651 : : * object. (This makes it safe to initially use DUMP_COMPONENT_ALL as the
11652 : : * request for every kind of object.)
11653 : : */
11654 : 832618 : dobj->dump &= dobj->components;
11655 : :
11656 : : /* Now, short-circuit if there's nothing to be done here. */
11657 [ + + ]: 832618 : if (dobj->dump == 0)
11658 : 753963 : return;
11659 : :
7996 11660 [ + + + + : 78655 : switch (dobj->objType)
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + - ]
11661 : : {
11662 : 491 : case DO_NAMESPACE:
1720 peter@eisentraut.org 11663 : 491 : dumpNamespace(fout, (const NamespaceInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11664 : 491 : break;
5375 11665 : 24 : case DO_EXTENSION:
1720 peter@eisentraut.org 11666 : 24 : dumpExtension(fout, (const ExtensionInfo *) dobj);
5375 tgl@sss.pgh.pa.us 11667 : 24 : break;
7996 11668 : 920 : case DO_TYPE:
1720 peter@eisentraut.org 11669 : 920 : dumpType(fout, (const TypeInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11670 : 920 : break;
7179 11671 : 73 : case DO_SHELL_TYPE:
1720 peter@eisentraut.org 11672 : 73 : dumpShellType(fout, (const ShellTypeInfo *) dobj);
7179 tgl@sss.pgh.pa.us 11673 : 73 : break;
7996 11674 : 1818 : case DO_FUNC:
1720 peter@eisentraut.org 11675 : 1818 : dumpFunc(fout, (const FuncInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11676 : 1818 : break;
11677 : 292 : case DO_AGG:
1720 peter@eisentraut.org 11678 : 292 : dumpAgg(fout, (const AggInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11679 : 292 : break;
11680 : 2504 : case DO_OPERATOR:
1720 peter@eisentraut.org 11681 : 2504 : dumpOpr(fout, (const OprInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11682 : 2504 : break;
3505 alvherre@alvh.no-ip. 11683 : 80 : case DO_ACCESS_METHOD:
1720 peter@eisentraut.org 11684 : 80 : dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
3505 alvherre@alvh.no-ip. 11685 : 80 : break;
7996 tgl@sss.pgh.pa.us 11686 : 660 : case DO_OPCLASS:
1720 peter@eisentraut.org 11687 : 660 : dumpOpclass(fout, (const OpclassInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11688 : 660 : break;
6852 11689 : 549 : case DO_OPFAMILY:
1720 peter@eisentraut.org 11690 : 549 : dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
6852 tgl@sss.pgh.pa.us 11691 : 549 : break;
5371 peter_e@gmx.net 11692 : 4643 : case DO_COLLATION:
1720 peter@eisentraut.org 11693 : 4643 : dumpCollation(fout, (const CollInfo *) dobj);
5371 peter_e@gmx.net 11694 : 4643 : break;
7996 tgl@sss.pgh.pa.us 11695 : 422 : case DO_CONVERSION:
1720 peter@eisentraut.org 11696 : 422 : dumpConversion(fout, (const ConvInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11697 : 422 : break;
11698 : 31464 : case DO_TABLE:
1720 peter@eisentraut.org 11699 : 31464 : dumpTable(fout, (const TableInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11700 : 31464 : break;
1750 11701 : 1381 : case DO_TABLE_ATTACH:
1720 peter@eisentraut.org 11702 : 1381 : dumpTableAttach(fout, (const TableAttachInfo *) dobj);
1750 tgl@sss.pgh.pa.us 11703 : 1381 : break;
7996 11704 : 1032 : case DO_ATTRDEF:
1720 peter@eisentraut.org 11705 : 1032 : dumpAttrDef(fout, (const AttrDefInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11706 : 1032 : break;
11707 : 2574 : case DO_INDEX:
1720 peter@eisentraut.org 11708 : 2574 : dumpIndex(fout, (const IndxInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11709 : 2574 : break;
2838 alvherre@alvh.no-ip. 11710 : 564 : case DO_INDEX_ATTACH:
1720 peter@eisentraut.org 11711 : 564 : dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
2838 alvherre@alvh.no-ip. 11712 : 564 : break;
3139 11713 : 133 : case DO_STATSEXT:
1720 peter@eisentraut.org 11714 : 133 : dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
3139 alvherre@alvh.no-ip. 11715 : 133 : break;
4621 kgrittn@postgresql.o 11716 : 348 : case DO_REFRESH_MATVIEW:
1720 peter@eisentraut.org 11717 : 348 : refreshMatViewData(fout, (const TableDataInfo *) dobj);
4621 kgrittn@postgresql.o 11718 : 348 : break;
7996 tgl@sss.pgh.pa.us 11719 : 1132 : case DO_RULE:
1720 peter@eisentraut.org 11720 : 1132 : dumpRule(fout, (const RuleInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11721 : 1132 : break;
11722 : 523 : case DO_TRIGGER:
1720 peter@eisentraut.org 11723 : 523 : dumpTrigger(fout, (const TriggerInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11724 : 523 : break;
4849 rhaas@postgresql.org 11725 : 42 : case DO_EVENT_TRIGGER:
1720 peter@eisentraut.org 11726 : 42 : dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
4849 rhaas@postgresql.org 11727 : 42 : break;
7996 tgl@sss.pgh.pa.us 11728 : 2302 : case DO_CONSTRAINT:
1720 peter@eisentraut.org 11729 : 2302 : dumpConstraint(fout, (const ConstraintInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11730 : 2302 : break;
11731 : 171 : case DO_FK_CONSTRAINT:
1720 peter@eisentraut.org 11732 : 171 : dumpConstraint(fout, (const ConstraintInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11733 : 171 : break;
11734 : 82 : case DO_PROCLANG:
1720 peter@eisentraut.org 11735 : 82 : dumpProcLang(fout, (const ProcLangInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11736 : 82 : break;
11737 : 67 : case DO_CAST:
1720 peter@eisentraut.org 11738 : 67 : dumpCast(fout, (const CastInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11739 : 67 : break;
3837 peter_e@gmx.net 11740 : 42 : case DO_TRANSFORM:
1720 peter@eisentraut.org 11741 : 42 : dumpTransform(fout, (const TransformInfo *) dobj);
3837 peter_e@gmx.net 11742 : 42 : break;
3352 11743 : 393 : case DO_SEQUENCE_SET:
1720 peter@eisentraut.org 11744 : 393 : dumpSequenceData(fout, (const TableDataInfo *) dobj);
3352 peter_e@gmx.net 11745 : 393 : break;
7996 tgl@sss.pgh.pa.us 11746 : 4224 : case DO_TABLE_DATA:
1720 peter@eisentraut.org 11747 : 4224 : dumpTableData(fout, (const TableDataInfo *) dobj);
7996 tgl@sss.pgh.pa.us 11748 : 4224 : break;
6126 11749 : 14063 : case DO_DUMMY_TYPE:
11750 : : /* table rowtypes and array types are never dumped separately */
7908 11751 : 14063 : break;
6642 11752 : 41 : case DO_TSPARSER:
1720 peter@eisentraut.org 11753 : 41 : dumpTSParser(fout, (const TSParserInfo *) dobj);
6642 tgl@sss.pgh.pa.us 11754 : 41 : break;
11755 : 173 : case DO_TSDICT:
1720 peter@eisentraut.org 11756 : 173 : dumpTSDictionary(fout, (const TSDictInfo *) dobj);
6642 tgl@sss.pgh.pa.us 11757 : 173 : break;
11758 : 53 : case DO_TSTEMPLATE:
1720 peter@eisentraut.org 11759 : 53 : dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
6642 tgl@sss.pgh.pa.us 11760 : 53 : break;
11761 : 148 : case DO_TSCONFIG:
1720 peter@eisentraut.org 11762 : 148 : dumpTSConfig(fout, (const TSConfigInfo *) dobj);
6642 tgl@sss.pgh.pa.us 11763 : 148 : break;
6156 peter_e@gmx.net 11764 : 52 : case DO_FDW:
1720 peter@eisentraut.org 11765 : 52 : dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
6156 peter_e@gmx.net 11766 : 52 : break;
11767 : 56 : case DO_FOREIGN_SERVER:
1720 peter@eisentraut.org 11768 : 56 : dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
6156 peter_e@gmx.net 11769 : 56 : break;
5866 tgl@sss.pgh.pa.us 11770 : 160 : case DO_DEFAULT_ACL:
1720 peter@eisentraut.org 11771 : 160 : dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
5866 tgl@sss.pgh.pa.us 11772 : 160 : break;
1057 peter@eisentraut.org 11773 : 87 : case DO_LARGE_OBJECT:
11774 : 87 : dumpLO(fout, (const LoInfo *) dobj);
5730 tgl@sss.pgh.pa.us 11775 : 87 : break;
1057 peter@eisentraut.org 11776 : 93 : case DO_LARGE_OBJECT_DATA:
3491 sfrost@snowman.net 11777 [ + - ]: 93 : if (dobj->dump & DUMP_COMPONENT_DATA)
11778 : : {
11779 : : LoInfo *loinfo;
11780 : : TocEntry *te;
11781 : :
574 tgl@sss.pgh.pa.us 11782 : 93 : loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
11783 [ - + ]: 93 : if (loinfo == NULL)
574 tgl@sss.pgh.pa.us 11784 :UBC 0 : pg_fatal("missing metadata for large objects \"%s\"",
11785 : : dobj->name);
11786 : :
2600 tgl@sss.pgh.pa.us 11787 :CBC 93 : te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
2460 alvherre@alvh.no-ip. 11788 : 93 : ARCHIVE_OPTS(.tag = dobj->name,
11789 : : .owner = loinfo->rolname,
11790 : : .description = "BLOBS",
11791 : : .section = SECTION_DATA,
11792 : : .deps = dobj->dependencies,
11793 : : .nDeps = dobj->nDeps,
11794 : : .dumpFn = dumpLOs,
11795 : : .dumpArg = loinfo));
11796 : :
11797 : : /*
11798 : : * Set the TocEntry's dataLength in case we are doing a
11799 : : * parallel dump and want to order dump jobs by table size.
11800 : : * (We need some size estimate for every TocEntry with a
11801 : : * DataDumper function.) We don't currently have any cheap
11802 : : * way to estimate the size of LOs, but fortunately it doesn't
11803 : : * matter too much as long as we get large batches of LOs
11804 : : * processed reasonably early. Assume 8K per blob.
11805 : : */
574 tgl@sss.pgh.pa.us 11806 : 93 : te->dataLength = loinfo->numlos * (pgoff_t) 8192;
11807 : : }
7908 11808 : 93 : break;
3987 sfrost@snowman.net 11809 : 326 : case DO_POLICY:
1720 peter@eisentraut.org 11810 : 326 : dumpPolicy(fout, (const PolicyInfo *) dobj);
4056 sfrost@snowman.net 11811 : 326 : break;
3203 peter_e@gmx.net 11812 : 285 : case DO_PUBLICATION:
1720 peter@eisentraut.org 11813 : 285 : dumpPublication(fout, (const PublicationInfo *) dobj);
3203 peter_e@gmx.net 11814 : 285 : break;
11815 : 284 : case DO_PUBLICATION_REL:
1720 peter@eisentraut.org 11816 : 284 : dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
3203 peter_e@gmx.net 11817 : 284 : break;
1448 akapila@postgresql.o 11818 : 99 : case DO_PUBLICATION_TABLE_IN_SCHEMA:
1461 11819 : 99 : dumpPublicationNamespace(fout,
11820 : : (const PublicationSchemaInfo *) dobj);
11821 : 99 : break;
3203 peter_e@gmx.net 11822 : 110 : case DO_SUBSCRIPTION:
1720 peter@eisentraut.org 11823 : 110 : dumpSubscription(fout, (const SubscriptionInfo *) dobj);
3203 peter_e@gmx.net 11824 : 110 : break;
664 akapila@postgresql.o 11825 : 2 : case DO_SUBSCRIPTION_REL:
11826 : 2 : dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
11827 : 2 : break;
249 jdavis@postgresql.or 11828 : 3295 : case DO_REL_STATS:
11829 : 3295 : dumpRelationStats(fout, (const RelStatsInfo *) dobj);
11830 : 3295 : break;
4872 tgl@sss.pgh.pa.us 11831 : 378 : case DO_PRE_DATA_BOUNDARY:
11832 : : case DO_POST_DATA_BOUNDARY:
11833 : : /* never dumped, nothing to do */
11834 : 378 : break;
11835 : : }
11836 : : }
11837 : :
11838 : : /*
11839 : : * dumpNamespace
11840 : : * writes out to fout the queries to recreate a user-defined namespace
11841 : : */
11842 : : static void
1720 peter@eisentraut.org 11843 : 491 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
11844 : : {
3575 tgl@sss.pgh.pa.us 11845 : 491 : DumpOptions *dopt = fout->dopt;
11846 : : PQExpBuffer q;
11847 : : PQExpBuffer delq;
11848 : : char *qnspname;
11849 : :
11850 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 11851 [ + + ]: 491 : if (!dopt->dumpSchema)
7996 tgl@sss.pgh.pa.us 11852 : 28 : return;
11853 : :
11854 : 463 : q = createPQExpBuffer();
11855 : 463 : delq = createPQExpBuffer();
11856 : :
5085 bruce@momjian.us 11857 : 463 : qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
11858 : :
1582 noah@leadboat.com 11859 [ + + ]: 463 : if (nspinfo->create)
11860 : : {
11861 : 309 : appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
11862 : 309 : appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
11863 : : }
11864 : : else
11865 : : {
11866 : : /* see selectDumpableNamespace() */
11867 : 154 : appendPQExpBufferStr(delq,
11868 : : "-- *not* dropping schema, since initdb creates it\n");
11869 : 154 : appendPQExpBufferStr(q,
11870 : : "-- *not* creating schema, since initdb creates it\n");
11871 : : }
11872 : :
4031 alvherre@alvh.no-ip. 11873 [ + + ]: 463 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 11874 : 90 : binary_upgrade_extension_member(q, &nspinfo->dobj,
11875 : : "SCHEMA", qnspname, NULL);
11876 : :
3491 sfrost@snowman.net 11877 [ + + ]: 463 : if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11878 : 185 : ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 11879 : 185 : ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
11880 : : .owner = nspinfo->rolname,
11881 : : .description = "SCHEMA",
11882 : : .section = SECTION_PRE_DATA,
11883 : : .createStmt = q->data,
11884 : : .dropStmt = delq->data));
11885 : :
11886 : : /* Dump Schema Comments and Security Labels */
3491 sfrost@snowman.net 11887 [ + + ]: 463 : if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11888 : : {
1582 noah@leadboat.com 11889 : 159 : const char *initdb_comment = NULL;
11890 : :
11891 [ + + + + ]: 159 : if (!nspinfo->create && strcmp(qnspname, "public") == 0)
1413 tgl@sss.pgh.pa.us 11892 : 120 : initdb_comment = "standard public schema";
1582 noah@leadboat.com 11893 : 159 : dumpCommentExtended(fout, "SCHEMA", qnspname,
11894 : 159 : NULL, nspinfo->rolname,
11895 : 159 : nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
11896 : : initdb_comment);
11897 : : }
11898 : :
3491 sfrost@snowman.net 11899 [ - + ]: 463 : if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 11900 :UBC 0 : dumpSecLabel(fout, "SCHEMA", qnspname,
3491 sfrost@snowman.net 11901 : 0 : NULL, nspinfo->rolname,
11902 : 0 : nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
11903 : :
3491 sfrost@snowman.net 11904 [ + + ]:CBC 463 : if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
1934 tgl@sss.pgh.pa.us 11905 : 361 : dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
11906 : : qnspname, NULL, NULL,
574 11907 : 361 : NULL, nspinfo->rolname, &nspinfo->dacl);
11908 : :
7996 11909 : 463 : free(qnspname);
11910 : :
8571 11911 : 463 : destroyPQExpBuffer(q);
11912 : 463 : destroyPQExpBuffer(delq);
11913 : : }
11914 : :
11915 : : /*
11916 : : * dumpExtension
11917 : : * writes out to fout the queries to recreate an extension
11918 : : */
11919 : : static void
1720 peter@eisentraut.org 11920 : 24 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
11921 : : {
3575 tgl@sss.pgh.pa.us 11922 : 24 : DumpOptions *dopt = fout->dopt;
11923 : : PQExpBuffer q;
11924 : : PQExpBuffer delq;
11925 : : char *qextname;
11926 : :
11927 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 11928 [ + + ]: 24 : if (!dopt->dumpSchema)
5375 tgl@sss.pgh.pa.us 11929 : 1 : return;
11930 : :
11931 : 23 : q = createPQExpBuffer();
11932 : 23 : delq = createPQExpBuffer();
11933 : :
5085 bruce@momjian.us 11934 : 23 : qextname = pg_strdup(fmtId(extinfo->dobj.name));
11935 : :
5375 tgl@sss.pgh.pa.us 11936 : 23 : appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
11937 : :
4031 alvherre@alvh.no-ip. 11938 [ + + ]: 23 : if (!dopt->binary_upgrade)
11939 : : {
11940 : : /*
11941 : : * In a regular dump, we simply create the extension, intentionally
11942 : : * not specifying a version, so that the destination installation's
11943 : : * default version is used.
11944 : : *
11945 : : * Use of IF NOT EXISTS here is unlike our behavior for other object
11946 : : * types; but there are various scenarios in which it's convenient to
11947 : : * manually create the desired extension before restoring, so we
11948 : : * prefer to allow it to exist already.
11949 : : */
5351 tgl@sss.pgh.pa.us 11950 : 17 : appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
5374 11951 : 17 : qextname, fmtId(extinfo->namespace));
11952 : : }
11953 : : else
11954 : : {
11955 : : /*
11956 : : * In binary-upgrade mode, it's critical to reproduce the state of the
11957 : : * database exactly, so our procedure is to create an empty extension,
11958 : : * restore all the contained objects normally, and add them to the
11959 : : * extension one by one. This function performs just the first of
11960 : : * those steps. binary_upgrade_extension_member() takes care of
11961 : : * adding member objects as they're created.
11962 : : */
11963 : : int i;
11964 : : int n;
11965 : :
4361 heikki.linnakangas@i 11966 : 6 : appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
11967 : :
11968 : : /*
11969 : : * We unconditionally create the extension, so we must drop it if it
11970 : : * exists. This could happen if the user deleted 'plpgsql' and then
11971 : : * readded it, causing its oid to be greater than g_last_builtin_oid.
11972 : : */
4863 bruce@momjian.us 11973 : 6 : appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
11974 : :
4361 heikki.linnakangas@i 11975 : 6 : appendPQExpBufferStr(q,
11976 : : "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
5374 tgl@sss.pgh.pa.us 11977 : 6 : appendStringLiteralAH(q, extinfo->dobj.name, fout);
4361 heikki.linnakangas@i 11978 : 6 : appendPQExpBufferStr(q, ", ");
5374 tgl@sss.pgh.pa.us 11979 : 6 : appendStringLiteralAH(q, extinfo->namespace, fout);
4361 heikki.linnakangas@i 11980 : 6 : appendPQExpBufferStr(q, ", ");
5374 tgl@sss.pgh.pa.us 11981 [ + - ]: 6 : appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
5372 11982 : 6 : appendStringLiteralAH(q, extinfo->extversion, fout);
4361 heikki.linnakangas@i 11983 : 6 : appendPQExpBufferStr(q, ", ");
11984 : :
11985 : : /*
11986 : : * Note that we're pushing extconfig (an OID array) back into
11987 : : * pg_extension exactly as-is. This is OK because pg_class OIDs are
11988 : : * preserved in binary upgrade.
11989 : : */
5374 tgl@sss.pgh.pa.us 11990 [ + + ]: 6 : if (strlen(extinfo->extconfig) > 2)
11991 : 1 : appendStringLiteralAH(q, extinfo->extconfig, fout);
11992 : : else
4361 heikki.linnakangas@i 11993 :GBC 5 : appendPQExpBufferStr(q, "NULL");
4361 heikki.linnakangas@i 11994 :CBC 6 : appendPQExpBufferStr(q, ", ");
5374 tgl@sss.pgh.pa.us 11995 [ + + ]: 6 : if (strlen(extinfo->extcondition) > 2)
11996 : 1 : appendStringLiteralAH(q, extinfo->extcondition, fout);
11997 : : else
4361 heikki.linnakangas@i 11998 :GBC 5 : appendPQExpBufferStr(q, "NULL");
4361 heikki.linnakangas@i 11999 :CBC 6 : appendPQExpBufferStr(q, ", ");
12000 : 6 : appendPQExpBufferStr(q, "ARRAY[");
5374 tgl@sss.pgh.pa.us 12001 : 6 : n = 0;
12002 [ + + ]: 12 : for (i = 0; i < extinfo->dobj.nDeps; i++)
12003 : : {
12004 : : DumpableObject *extobj;
12005 : :
12006 : 6 : extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
12007 [ + - - + ]: 6 : if (extobj && extobj->objType == DO_EXTENSION)
12008 : : {
5374 tgl@sss.pgh.pa.us 12009 [ # # ]:UBC 0 : if (n++ > 0)
4361 heikki.linnakangas@i 12010 : 0 : appendPQExpBufferChar(q, ',');
5374 tgl@sss.pgh.pa.us 12011 : 0 : appendStringLiteralAH(q, extobj->name, fout);
12012 : : }
12013 : : }
4361 heikki.linnakangas@i 12014 :CBC 6 : appendPQExpBufferStr(q, "]::pg_catalog.text[]");
12015 : 6 : appendPQExpBufferStr(q, ");\n");
12016 : : }
12017 : :
3491 sfrost@snowman.net 12018 [ + - ]: 23 : if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12019 : 23 : ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 12020 : 23 : ARCHIVE_OPTS(.tag = extinfo->dobj.name,
12021 : : .description = "EXTENSION",
12022 : : .section = SECTION_PRE_DATA,
12023 : : .createStmt = q->data,
12024 : : .dropStmt = delq->data));
12025 : :
12026 : : /* Dump Extension Comments */
3491 sfrost@snowman.net 12027 [ + - ]: 23 : if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 12028 : 23 : dumpComment(fout, "EXTENSION", qextname,
12029 : : NULL, "",
3491 sfrost@snowman.net 12030 : 23 : extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
12031 : :
5375 tgl@sss.pgh.pa.us 12032 : 23 : free(qextname);
12033 : :
12034 : 23 : destroyPQExpBuffer(q);
12035 : 23 : destroyPQExpBuffer(delq);
12036 : : }
12037 : :
12038 : : /*
12039 : : * dumpType
12040 : : * writes out to fout the queries to recreate a user-defined type
12041 : : */
12042 : : static void
1720 peter@eisentraut.org 12043 : 920 : dumpType(Archive *fout, const TypeInfo *tyinfo)
12044 : : {
3575 tgl@sss.pgh.pa.us 12045 : 920 : DumpOptions *dopt = fout->dopt;
12046 : :
12047 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 12048 [ + + ]: 920 : if (!dopt->dumpSchema)
7996 tgl@sss.pgh.pa.us 12049 : 49 : return;
12050 : :
12051 : : /* Dump out in proper style */
5787 bruce@momjian.us 12052 [ + + ]: 871 : if (tyinfo->typtype == TYPTYPE_BASE)
3575 tgl@sss.pgh.pa.us 12053 : 280 : dumpBaseType(fout, tyinfo);
5787 bruce@momjian.us 12054 [ + + ]: 591 : else if (tyinfo->typtype == TYPTYPE_DOMAIN)
3575 tgl@sss.pgh.pa.us 12055 : 152 : dumpDomain(fout, tyinfo);
5787 bruce@momjian.us 12056 [ + + ]: 439 : else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
3575 tgl@sss.pgh.pa.us 12057 : 130 : dumpCompositeType(fout, tyinfo);
5787 bruce@momjian.us 12058 [ + + ]: 309 : else if (tyinfo->typtype == TYPTYPE_ENUM)
3575 tgl@sss.pgh.pa.us 12059 : 85 : dumpEnumType(fout, tyinfo);
5107 heikki.linnakangas@i 12060 [ + + ]: 224 : else if (tyinfo->typtype == TYPTYPE_RANGE)
3575 tgl@sss.pgh.pa.us 12061 : 112 : dumpRangeType(fout, tyinfo);
3737 12062 [ + - + + ]: 112 : else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
3575 12063 : 37 : dumpUndefinedType(fout, tyinfo);
12064 : : else
2401 peter@eisentraut.org 12065 : 75 : pg_log_warning("typtype of data type \"%s\" appears to be invalid",
12066 : : tyinfo->dobj.name);
12067 : : }
12068 : :
12069 : : /*
12070 : : * dumpEnumType
12071 : : * writes out to fout the queries to recreate a user-defined enum type
12072 : : */
12073 : : static void
1720 12074 : 85 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
12075 : : {
3575 tgl@sss.pgh.pa.us 12076 : 85 : DumpOptions *dopt = fout->dopt;
6783 12077 : 85 : PQExpBuffer q = createPQExpBuffer();
12078 : 85 : PQExpBuffer delq = createPQExpBuffer();
12079 : 85 : PQExpBuffer query = createPQExpBuffer();
12080 : : PGresult *res;
12081 : : int num,
12082 : : i;
12083 : : Oid enum_oid;
12084 : : char *qtypname;
12085 : : char *qualtypname;
12086 : : char *label;
12087 : : int i_enumlabel;
12088 : : int i_oid;
12089 : :
1421 12090 [ + + ]: 85 : if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
12091 : : {
12092 : : /* Set up query for enum-specific details */
12093 : 40 : appendPQExpBufferStr(query,
12094 : : "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
12095 : : "SELECT oid, enumlabel "
12096 : : "FROM pg_catalog.pg_enum "
12097 : : "WHERE enumtypid = $1 "
12098 : : "ORDER BY enumsortorder");
12099 : :
12100 : 40 : ExecuteSqlStatement(fout, query->data);
12101 : :
12102 : 40 : fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
12103 : : }
12104 : :
12105 : 85 : printfPQExpBuffer(query,
12106 : : "EXECUTE dumpEnumType('%u')",
12107 : 85 : tyinfo->dobj.catId.oid);
12108 : :
5011 rhaas@postgresql.org 12109 : 85 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12110 : :
6783 tgl@sss.pgh.pa.us 12111 : 85 : num = PQntuples(res);
12112 : :
4705 12113 : 85 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2800 12114 : 85 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
12115 : :
12116 : : /*
12117 : : * CASCADE shouldn't be required here as for normal types since the I/O
12118 : : * functions are generic and do not get dropped.
12119 : : */
12120 : 85 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12121 : :
4031 alvherre@alvh.no-ip. 12122 [ + + ]: 85 : if (dopt->binary_upgrade)
5011 rhaas@postgresql.org 12123 : 6 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2949 tgl@sss.pgh.pa.us 12124 : 6 : tyinfo->dobj.catId.oid,
12125 : : false, false);
12126 : :
5783 bruce@momjian.us 12127 : 85 : appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
12128 : : qualtypname);
12129 : :
4031 alvherre@alvh.no-ip. 12130 [ + + ]: 85 : if (!dopt->binary_upgrade)
12131 : : {
1522 dgustafsson@postgres 12132 : 79 : i_enumlabel = PQfnumber(res, "enumlabel");
12133 : :
12134 : : /* Labels with server-assigned oids */
5783 bruce@momjian.us 12135 [ + + ]: 482 : for (i = 0; i < num; i++)
12136 : : {
1522 dgustafsson@postgres 12137 : 403 : label = PQgetvalue(res, i, i_enumlabel);
5783 bruce@momjian.us 12138 [ + + ]: 403 : if (i > 0)
4361 heikki.linnakangas@i 12139 : 324 : appendPQExpBufferChar(q, ',');
12140 : 403 : appendPQExpBufferStr(q, "\n ");
5783 bruce@momjian.us 12141 : 403 : appendStringLiteralAH(q, label, fout);
12142 : : }
12143 : : }
12144 : :
4361 heikki.linnakangas@i 12145 : 85 : appendPQExpBufferStr(q, "\n);\n");
12146 : :
4031 alvherre@alvh.no-ip. 12147 [ + + ]: 85 : if (dopt->binary_upgrade)
12148 : : {
1522 dgustafsson@postgres 12149 : 6 : i_oid = PQfnumber(res, "oid");
12150 : 6 : i_enumlabel = PQfnumber(res, "enumlabel");
12151 : :
12152 : : /* Labels with dump-assigned (preserved) oids */
5783 bruce@momjian.us 12153 [ + + ]: 62 : for (i = 0; i < num; i++)
12154 : : {
1522 dgustafsson@postgres 12155 : 56 : enum_oid = atooid(PQgetvalue(res, i, i_oid));
12156 : 56 : label = PQgetvalue(res, i, i_enumlabel);
12157 : :
5783 bruce@momjian.us 12158 [ + + ]: 56 : if (i == 0)
4361 heikki.linnakangas@i 12159 : 6 : appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
5783 bruce@momjian.us 12160 : 56 : appendPQExpBuffer(q,
12161 : : "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
12162 : : enum_oid);
2800 tgl@sss.pgh.pa.us 12163 : 56 : appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
5783 bruce@momjian.us 12164 : 56 : appendStringLiteralAH(q, label, fout);
4361 heikki.linnakangas@i 12165 : 56 : appendPQExpBufferStr(q, ";\n\n");
12166 : : }
12167 : : }
12168 : :
4031 alvherre@alvh.no-ip. 12169 [ + + ]: 85 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 12170 : 6 : binary_upgrade_extension_member(q, &tyinfo->dobj,
12171 : : "TYPE", qtypname,
12172 : 6 : tyinfo->dobj.namespace->dobj.name);
12173 : :
3491 sfrost@snowman.net 12174 [ + - ]: 85 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12175 : 85 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 12176 : 85 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12177 : : .namespace = tyinfo->dobj.namespace->dobj.name,
12178 : : .owner = tyinfo->rolname,
12179 : : .description = "TYPE",
12180 : : .section = SECTION_PRE_DATA,
12181 : : .createStmt = q->data,
12182 : : .dropStmt = delq->data));
12183 : :
12184 : : /* Dump Type Comments and Security Labels */
3491 sfrost@snowman.net 12185 [ + + ]: 85 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 12186 : 32 : dumpComment(fout, "TYPE", qtypname,
3491 sfrost@snowman.net 12187 : 32 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12188 : 32 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12189 : :
12190 [ - + ]: 85 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 12191 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
3491 sfrost@snowman.net 12192 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12193 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12194 : :
3491 sfrost@snowman.net 12195 [ + + ]:CBC 85 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1934 tgl@sss.pgh.pa.us 12196 : 32 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12197 : : qtypname, NULL,
3491 sfrost@snowman.net 12198 : 32 : tyinfo->dobj.namespace->dobj.name,
574 tgl@sss.pgh.pa.us 12199 : 32 : NULL, tyinfo->rolname, &tyinfo->dacl);
12200 : :
5107 heikki.linnakangas@i 12201 : 85 : PQclear(res);
12202 : 85 : destroyPQExpBuffer(q);
12203 : 85 : destroyPQExpBuffer(delq);
12204 : 85 : destroyPQExpBuffer(query);
2800 tgl@sss.pgh.pa.us 12205 : 85 : free(qtypname);
12206 : 85 : free(qualtypname);
5107 heikki.linnakangas@i 12207 : 85 : }
12208 : :
12209 : : /*
12210 : : * dumpRangeType
12211 : : * writes out to fout the queries to recreate a user-defined range type
12212 : : */
12213 : : static void
1720 peter@eisentraut.org 12214 : 112 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
12215 : : {
3575 tgl@sss.pgh.pa.us 12216 : 112 : DumpOptions *dopt = fout->dopt;
5107 heikki.linnakangas@i 12217 : 112 : PQExpBuffer q = createPQExpBuffer();
12218 : 112 : PQExpBuffer delq = createPQExpBuffer();
12219 : 112 : PQExpBuffer query = createPQExpBuffer();
12220 : : PGresult *res;
12221 : : Oid collationOid;
12222 : : char *qtypname;
12223 : : char *qualtypname;
12224 : : char *procname;
12225 : :
1421 tgl@sss.pgh.pa.us 12226 [ + + ]: 112 : if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
12227 : : {
12228 : : /* Set up query for range-specific details */
12229 : 40 : appendPQExpBufferStr(query,
12230 : : "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
12231 : :
12232 : 40 : appendPQExpBufferStr(query,
12233 : : "SELECT ");
12234 : :
12235 [ + - ]: 40 : if (fout->remoteVersion >= 140000)
12236 : 40 : appendPQExpBufferStr(query,
12237 : : "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
12238 : : else
1421 tgl@sss.pgh.pa.us 12239 :UBC 0 : appendPQExpBufferStr(query,
12240 : : "NULL AS rngmultitype, ");
12241 : :
1421 tgl@sss.pgh.pa.us 12242 :CBC 40 : appendPQExpBufferStr(query,
12243 : : "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
12244 : : "opc.opcname AS opcname, "
12245 : : "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
12246 : : " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
12247 : : "opc.opcdefault, "
12248 : : "CASE WHEN rngcollation = st.typcollation THEN 0 "
12249 : : " ELSE rngcollation END AS collation, "
12250 : : "rngcanonical, rngsubdiff "
12251 : : "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
12252 : : " pg_catalog.pg_opclass opc "
12253 : : "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
12254 : : "rngtypid = $1");
12255 : :
12256 : 40 : ExecuteSqlStatement(fout, query->data);
12257 : :
12258 : 40 : fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
12259 : : }
12260 : :
12261 : 112 : printfPQExpBuffer(query,
12262 : : "EXECUTE dumpRangeType('%u')",
5107 heikki.linnakangas@i 12263 : 112 : tyinfo->dobj.catId.oid);
12264 : :
5002 rhaas@postgresql.org 12265 : 112 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
12266 : :
4705 tgl@sss.pgh.pa.us 12267 : 112 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2800 12268 : 112 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
12269 : :
12270 : : /*
12271 : : * CASCADE shouldn't be required here as for normal types since the I/O
12272 : : * functions are generic and do not get dropped.
12273 : : */
12274 : 112 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12275 : :
4031 alvherre@alvh.no-ip. 12276 [ + + ]: 112 : if (dopt->binary_upgrade)
2949 tgl@sss.pgh.pa.us 12277 : 8 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
12278 : 8 : tyinfo->dobj.catId.oid,
12279 : : false, true);
12280 : :
5107 heikki.linnakangas@i 12281 : 112 : appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
12282 : : qualtypname);
12283 : :
5090 tgl@sss.pgh.pa.us 12284 : 112 : appendPQExpBuffer(q, "\n subtype = %s",
12285 : : PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
12286 : :
1772 akorotkov@postgresql 12287 [ + - ]: 112 : if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
12288 : 112 : appendPQExpBuffer(q, ",\n multirange_type_name = %s",
12289 : : PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
12290 : :
12291 : : /* print subtype_opclass only if not default for subtype */
5090 tgl@sss.pgh.pa.us 12292 [ + + ]: 112 : if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
12293 : : {
4887 bruce@momjian.us 12294 : 32 : char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
12295 : 32 : char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
12296 : :
5090 tgl@sss.pgh.pa.us 12297 : 32 : appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
12298 : : fmtId(nspname));
4361 heikki.linnakangas@i 12299 : 32 : appendPQExpBufferStr(q, fmtId(opcname));
12300 : : }
12301 : :
5090 tgl@sss.pgh.pa.us 12302 : 112 : collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
5107 heikki.linnakangas@i 12303 [ + + ]: 112 : if (OidIsValid(collationOid))
12304 : : {
5090 tgl@sss.pgh.pa.us 12305 : 37 : CollInfo *coll = findCollationByOid(collationOid);
12306 : :
5107 heikki.linnakangas@i 12307 [ + - ]: 37 : if (coll)
2800 tgl@sss.pgh.pa.us 12308 : 37 : appendPQExpBuffer(q, ",\n collation = %s",
12309 : 37 : fmtQualifiedDumpable(coll));
12310 : : }
12311 : :
5090 12312 : 112 : procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
12313 [ + + ]: 112 : if (strcmp(procname, "-") != 0)
12314 : 9 : appendPQExpBuffer(q, ",\n canonical = %s", procname);
12315 : :
12316 : 112 : procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
12317 [ + + ]: 112 : if (strcmp(procname, "-") != 0)
12318 : 23 : appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
12319 : :
4361 heikki.linnakangas@i 12320 : 112 : appendPQExpBufferStr(q, "\n);\n");
12321 : :
4031 alvherre@alvh.no-ip. 12322 [ + + ]: 112 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 12323 : 8 : binary_upgrade_extension_member(q, &tyinfo->dobj,
12324 : : "TYPE", qtypname,
12325 : 8 : tyinfo->dobj.namespace->dobj.name);
12326 : :
3491 sfrost@snowman.net 12327 [ + - ]: 112 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12328 : 112 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 12329 : 112 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12330 : : .namespace = tyinfo->dobj.namespace->dobj.name,
12331 : : .owner = tyinfo->rolname,
12332 : : .description = "TYPE",
12333 : : .section = SECTION_PRE_DATA,
12334 : : .createStmt = q->data,
12335 : : .dropStmt = delq->data));
12336 : :
12337 : : /* Dump Type Comments and Security Labels */
3491 sfrost@snowman.net 12338 [ + + ]: 112 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 12339 : 50 : dumpComment(fout, "TYPE", qtypname,
3491 sfrost@snowman.net 12340 : 50 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12341 : 50 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12342 : :
12343 [ - + ]: 112 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 12344 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
3491 sfrost@snowman.net 12345 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12346 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12347 : :
3491 sfrost@snowman.net 12348 [ + + ]:CBC 112 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1934 tgl@sss.pgh.pa.us 12349 : 32 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12350 : : qtypname, NULL,
3491 sfrost@snowman.net 12351 : 32 : tyinfo->dobj.namespace->dobj.name,
574 tgl@sss.pgh.pa.us 12352 : 32 : NULL, tyinfo->rolname, &tyinfo->dacl);
12353 : :
6783 12354 : 112 : PQclear(res);
12355 : 112 : destroyPQExpBuffer(q);
12356 : 112 : destroyPQExpBuffer(delq);
12357 : 112 : destroyPQExpBuffer(query);
2800 12358 : 112 : free(qtypname);
12359 : 112 : free(qualtypname);
7996 12360 : 112 : }
12361 : :
12362 : : /*
12363 : : * dumpUndefinedType
12364 : : * writes out to fout the queries to recreate a !typisdefined type
12365 : : *
12366 : : * This is a shell type, but we use different terminology to distinguish
12367 : : * this case from where we have to emit a shell type definition to break
12368 : : * circular dependencies. An undefined type shouldn't ever have anything
12369 : : * depending on it.
12370 : : */
12371 : : static void
1720 peter@eisentraut.org 12372 : 37 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
12373 : : {
3575 tgl@sss.pgh.pa.us 12374 : 37 : DumpOptions *dopt = fout->dopt;
3737 12375 : 37 : PQExpBuffer q = createPQExpBuffer();
12376 : 37 : PQExpBuffer delq = createPQExpBuffer();
12377 : : char *qtypname;
12378 : : char *qualtypname;
12379 : :
12380 : 37 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2800 12381 : 37 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
12382 : :
12383 : 37 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
12384 : :
3737 12385 [ + + ]: 37 : if (dopt->binary_upgrade)
2949 12386 : 2 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
12387 : 2 : tyinfo->dobj.catId.oid,
12388 : : false, false);
12389 : :
3737 12390 : 37 : appendPQExpBuffer(q, "CREATE TYPE %s;\n",
12391 : : qualtypname);
12392 : :
12393 [ + + ]: 37 : if (dopt->binary_upgrade)
2800 12394 : 2 : binary_upgrade_extension_member(q, &tyinfo->dobj,
12395 : : "TYPE", qtypname,
12396 : 2 : tyinfo->dobj.namespace->dobj.name);
12397 : :
3491 sfrost@snowman.net 12398 [ + - ]: 37 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12399 : 37 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 12400 : 37 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12401 : : .namespace = tyinfo->dobj.namespace->dobj.name,
12402 : : .owner = tyinfo->rolname,
12403 : : .description = "TYPE",
12404 : : .section = SECTION_PRE_DATA,
12405 : : .createStmt = q->data,
12406 : : .dropStmt = delq->data));
12407 : :
12408 : : /* Dump Type Comments and Security Labels */
3491 sfrost@snowman.net 12409 [ + + ]: 37 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 12410 : 32 : dumpComment(fout, "TYPE", qtypname,
3491 sfrost@snowman.net 12411 : 32 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12412 : 32 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12413 : :
12414 [ - + ]: 37 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 12415 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
3491 sfrost@snowman.net 12416 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12417 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12418 : :
3491 sfrost@snowman.net 12419 [ - + ]:CBC 37 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1934 tgl@sss.pgh.pa.us 12420 :UBC 0 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12421 : : qtypname, NULL,
3491 sfrost@snowman.net 12422 : 0 : tyinfo->dobj.namespace->dobj.name,
574 tgl@sss.pgh.pa.us 12423 : 0 : NULL, tyinfo->rolname, &tyinfo->dacl);
12424 : :
3737 tgl@sss.pgh.pa.us 12425 :CBC 37 : destroyPQExpBuffer(q);
12426 : 37 : destroyPQExpBuffer(delq);
2800 12427 : 37 : free(qtypname);
12428 : 37 : free(qualtypname);
3737 12429 : 37 : }
12430 : :
12431 : : /*
12432 : : * dumpBaseType
12433 : : * writes out to fout the queries to recreate a user-defined base type
12434 : : */
12435 : : static void
1720 peter@eisentraut.org 12436 : 280 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
12437 : : {
3575 tgl@sss.pgh.pa.us 12438 : 280 : DumpOptions *dopt = fout->dopt;
8571 12439 : 280 : PQExpBuffer q = createPQExpBuffer();
12440 : 280 : PQExpBuffer delq = createPQExpBuffer();
12441 : 280 : PQExpBuffer query = createPQExpBuffer();
12442 : : PGresult *res;
12443 : : char *qtypname;
12444 : : char *qualtypname;
12445 : : char *typlen;
12446 : : char *typinput;
12447 : : char *typoutput;
12448 : : char *typreceive;
12449 : : char *typsend;
12450 : : char *typmodin;
12451 : : char *typmodout;
12452 : : char *typanalyze;
12453 : : char *typsubscript;
12454 : : Oid typreceiveoid;
12455 : : Oid typsendoid;
12456 : : Oid typmodinoid;
12457 : : Oid typmodoutoid;
12458 : : Oid typanalyzeoid;
12459 : : Oid typsubscriptoid;
12460 : : char *typcategory;
12461 : : char *typispreferred;
12462 : : char *typdelim;
12463 : : char *typbyval;
12464 : : char *typalign;
12465 : : char *typstorage;
12466 : : char *typcollatable;
12467 : : char *typdefault;
7188 12468 : 280 : bool typdefault_is_literal = false;
12469 : :
1421 12470 [ + + ]: 280 : if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
12471 : : {
12472 : : /* Set up query for type-specific details */
1786 12473 : 40 : appendPQExpBufferStr(query,
12474 : : "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
12475 : : "SELECT typlen, "
12476 : : "typinput, typoutput, typreceive, typsend, "
12477 : : "typreceive::pg_catalog.oid AS typreceiveoid, "
12478 : : "typsend::pg_catalog.oid AS typsendoid, "
12479 : : "typanalyze, "
12480 : : "typanalyze::pg_catalog.oid AS typanalyzeoid, "
12481 : : "typdelim, typbyval, typalign, typstorage, "
12482 : : "typmodin, typmodout, "
12483 : : "typmodin::pg_catalog.oid AS typmodinoid, "
12484 : : "typmodout::pg_catalog.oid AS typmodoutoid, "
12485 : : "typcategory, typispreferred, "
12486 : : "(typcollation <> 0) AS typcollatable, "
12487 : : "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
12488 : :
1421 12489 [ + - ]: 40 : if (fout->remoteVersion >= 140000)
12490 : 40 : appendPQExpBufferStr(query,
12491 : : "typsubscript, "
12492 : : "typsubscript::pg_catalog.oid AS typsubscriptoid ");
12493 : : else
1421 tgl@sss.pgh.pa.us 12494 :UBC 0 : appendPQExpBufferStr(query,
12495 : : "'-' AS typsubscript, 0 AS typsubscriptoid ");
12496 : :
1421 tgl@sss.pgh.pa.us 12497 :CBC 40 : appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
12498 : : "WHERE oid = $1");
12499 : :
12500 : 40 : ExecuteSqlStatement(fout, query->data);
12501 : :
12502 : 40 : fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
12503 : : }
12504 : :
12505 : 280 : printfPQExpBuffer(query,
12506 : : "EXECUTE dumpBaseType('%u')",
1786 12507 : 280 : tyinfo->dobj.catId.oid);
12508 : :
5002 rhaas@postgresql.org 12509 : 280 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
12510 : :
8571 tgl@sss.pgh.pa.us 12511 : 280 : typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
12512 : 280 : typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
12513 : 280 : typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
8208 12514 : 280 : typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
12515 : 280 : typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
6876 12516 : 280 : typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
12517 : 280 : typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
7928 12518 : 280 : typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
1783 12519 : 280 : typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
7996 12520 : 280 : typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
12521 : 280 : typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
6876 12522 : 280 : typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
12523 : 280 : typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
7928 12524 : 280 : typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
1783 12525 : 280 : typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
6298 12526 : 280 : typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
12527 : 280 : typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
8571 12528 : 280 : typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
12529 : 280 : typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
12530 : 280 : typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
12531 : 280 : typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
5354 peter_e@gmx.net 12532 : 280 : typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
7188 tgl@sss.pgh.pa.us 12533 [ - + ]: 280 : if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
7188 tgl@sss.pgh.pa.us 12534 :UBC 0 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
7188 tgl@sss.pgh.pa.us 12535 [ + + ]:CBC 280 : else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
12536 : : {
12537 : 42 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6963 bruce@momjian.us 12538 : 42 : typdefault_is_literal = true; /* it needs quotes */
12539 : : }
12540 : : else
7188 tgl@sss.pgh.pa.us 12541 : 238 : typdefault = NULL;
12542 : :
4705 12543 : 280 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2800 12544 : 280 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
12545 : :
12546 : : /*
12547 : : * The reason we include CASCADE is that the circular dependency between
12548 : : * the type and its I/O functions makes it impossible to drop the type any
12549 : : * other way.
12550 : : */
12551 : 280 : appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
12552 : :
12553 : : /*
12554 : : * We might already have a shell type, but setting pg_type_oid is
12555 : : * harmless, and in any case we'd better set the array type OID.
12556 : : */
4031 alvherre@alvh.no-ip. 12557 [ + + ]: 280 : if (dopt->binary_upgrade)
5011 rhaas@postgresql.org 12558 : 8 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2949 tgl@sss.pgh.pa.us 12559 : 8 : tyinfo->dobj.catId.oid,
12560 : : false, false);
12561 : :
8571 12562 : 280 : appendPQExpBuffer(q,
12563 : : "CREATE TYPE %s (\n"
12564 : : " INTERNALLENGTH = %s",
12565 : : qualtypname,
8496 peter_e@gmx.net 12566 [ + + ]: 280 : (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
12567 : :
12568 : : /* regproc result is sufficiently quoted already */
3302 tgl@sss.pgh.pa.us 12569 : 280 : appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
12570 : 280 : appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
12571 [ + + ]: 280 : if (OidIsValid(typreceiveoid))
12572 : 207 : appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
12573 [ + + ]: 280 : if (OidIsValid(typsendoid))
12574 : 207 : appendPQExpBuffer(q, ",\n SEND = %s", typsend);
12575 [ + + ]: 280 : if (OidIsValid(typmodinoid))
12576 : 35 : appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
12577 [ + + ]: 280 : if (OidIsValid(typmodoutoid))
12578 : 35 : appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
12579 [ + + ]: 280 : if (OidIsValid(typanalyzeoid))
12580 : 3 : appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
12581 : :
5354 peter_e@gmx.net 12582 [ + + ]: 280 : if (strcmp(typcollatable, "t") == 0)
4361 heikki.linnakangas@i 12583 : 30 : appendPQExpBufferStr(q, ",\n COLLATABLE = true");
12584 : :
8571 tgl@sss.pgh.pa.us 12585 [ + + ]: 280 : if (typdefault != NULL)
12586 : : {
4361 heikki.linnakangas@i 12587 : 42 : appendPQExpBufferStr(q, ",\n DEFAULT = ");
7188 tgl@sss.pgh.pa.us 12588 [ + - ]: 42 : if (typdefault_is_literal)
7092 12589 : 42 : appendStringLiteralAH(q, typdefault, fout);
12590 : : else
7188 tgl@sss.pgh.pa.us 12591 :UBC 0 : appendPQExpBufferStr(q, typdefault);
12592 : : }
12593 : :
1783 tgl@sss.pgh.pa.us 12594 [ + + ]:CBC 280 : if (OidIsValid(typsubscriptoid))
12595 : 29 : appendPQExpBuffer(q, ",\n SUBSCRIPT = %s", typsubscript);
12596 : :
5787 bruce@momjian.us 12597 [ + + ]: 280 : if (OidIsValid(tyinfo->typelem))
1510 tgl@sss.pgh.pa.us 12598 : 26 : appendPQExpBuffer(q, ",\n ELEMENT = %s",
12599 : 26 : getFormattedTypeName(fout, tyinfo->typelem,
12600 : : zeroIsError));
12601 : :
6298 12602 [ + + ]: 280 : if (strcmp(typcategory, "U") != 0)
12603 : : {
4361 heikki.linnakangas@i 12604 : 158 : appendPQExpBufferStr(q, ",\n CATEGORY = ");
6298 tgl@sss.pgh.pa.us 12605 : 158 : appendStringLiteralAH(q, typcategory, fout);
12606 : : }
12607 : :
12608 [ + + ]: 280 : if (strcmp(typispreferred, "t") == 0)
4361 heikki.linnakangas@i 12609 : 29 : appendPQExpBufferStr(q, ",\n PREFERRED = true");
12610 : :
8208 tgl@sss.pgh.pa.us 12611 [ + - + + ]: 280 : if (typdelim && strcmp(typdelim, ",") != 0)
12612 : : {
4361 heikki.linnakangas@i 12613 : 3 : appendPQExpBufferStr(q, ",\n DELIMITER = ");
7092 tgl@sss.pgh.pa.us 12614 : 3 : appendStringLiteralAH(q, typdelim, fout);
12615 : : }
12616 : :
2063 12617 [ + + ]: 280 : if (*typalign == TYPALIGN_CHAR)
4361 heikki.linnakangas@i 12618 : 12 : appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
2063 tgl@sss.pgh.pa.us 12619 [ + + ]: 268 : else if (*typalign == TYPALIGN_SHORT)
4361 heikki.linnakangas@i 12620 : 6 : appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
2063 tgl@sss.pgh.pa.us 12621 [ + + ]: 262 : else if (*typalign == TYPALIGN_INT)
4361 heikki.linnakangas@i 12622 : 187 : appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
2063 tgl@sss.pgh.pa.us 12623 [ + - ]: 75 : else if (*typalign == TYPALIGN_DOUBLE)
4361 heikki.linnakangas@i 12624 : 75 : appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
12625 : :
2063 tgl@sss.pgh.pa.us 12626 [ + + ]: 280 : if (*typstorage == TYPSTORAGE_PLAIN)
4361 heikki.linnakangas@i 12627 : 205 : appendPQExpBufferStr(q, ",\n STORAGE = plain");
2063 tgl@sss.pgh.pa.us 12628 [ - + ]: 75 : else if (*typstorage == TYPSTORAGE_EXTERNAL)
4361 heikki.linnakangas@i 12629 :UBC 0 : appendPQExpBufferStr(q, ",\n STORAGE = external");
2063 tgl@sss.pgh.pa.us 12630 [ + + ]:CBC 75 : else if (*typstorage == TYPSTORAGE_EXTENDED)
4361 heikki.linnakangas@i 12631 : 66 : appendPQExpBufferStr(q, ",\n STORAGE = extended");
2063 tgl@sss.pgh.pa.us 12632 [ + - ]: 9 : else if (*typstorage == TYPSTORAGE_MAIN)
4361 heikki.linnakangas@i 12633 : 9 : appendPQExpBufferStr(q, ",\n STORAGE = main");
12634 : :
8571 tgl@sss.pgh.pa.us 12635 [ + + ]: 280 : if (strcmp(typbyval, "t") == 0)
4361 heikki.linnakangas@i 12636 : 134 : appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
12637 : :
12638 : 280 : appendPQExpBufferStr(q, "\n);\n");
12639 : :
4031 alvherre@alvh.no-ip. 12640 [ + + ]: 280 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 12641 : 8 : binary_upgrade_extension_member(q, &tyinfo->dobj,
12642 : : "TYPE", qtypname,
12643 : 8 : tyinfo->dobj.namespace->dobj.name);
12644 : :
3491 sfrost@snowman.net 12645 [ + - ]: 280 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12646 : 280 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 12647 : 280 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12648 : : .namespace = tyinfo->dobj.namespace->dobj.name,
12649 : : .owner = tyinfo->rolname,
12650 : : .description = "TYPE",
12651 : : .section = SECTION_PRE_DATA,
12652 : : .createStmt = q->data,
12653 : : .dropStmt = delq->data));
12654 : :
12655 : : /* Dump Type Comments and Security Labels */
3491 sfrost@snowman.net 12656 [ + + ]: 280 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 12657 : 245 : dumpComment(fout, "TYPE", qtypname,
3491 sfrost@snowman.net 12658 : 245 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12659 : 245 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12660 : :
12661 [ - + ]: 280 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 12662 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
3491 sfrost@snowman.net 12663 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12664 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12665 : :
3491 sfrost@snowman.net 12666 [ + + ]:CBC 280 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1934 tgl@sss.pgh.pa.us 12667 : 32 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12668 : : qtypname, NULL,
3491 sfrost@snowman.net 12669 : 32 : tyinfo->dobj.namespace->dobj.name,
574 tgl@sss.pgh.pa.us 12670 : 32 : NULL, tyinfo->rolname, &tyinfo->dacl);
12671 : :
9414 bruce@momjian.us 12672 : 280 : PQclear(res);
8571 tgl@sss.pgh.pa.us 12673 : 280 : destroyPQExpBuffer(q);
12674 : 280 : destroyPQExpBuffer(delq);
8851 12675 : 280 : destroyPQExpBuffer(query);
2800 12676 : 280 : free(qtypname);
12677 : 280 : free(qualtypname);
9414 bruce@momjian.us 12678 : 280 : }
12679 : :
12680 : : /*
12681 : : * dumpDomain
12682 : : * writes out to fout the queries to recreate a user-defined domain
12683 : : */
12684 : : static void
1720 peter@eisentraut.org 12685 : 152 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
12686 : : {
3575 tgl@sss.pgh.pa.us 12687 : 152 : DumpOptions *dopt = fout->dopt;
8606 bruce@momjian.us 12688 : 152 : PQExpBuffer q = createPQExpBuffer();
12689 : 152 : PQExpBuffer delq = createPQExpBuffer();
12690 : 152 : PQExpBuffer query = createPQExpBuffer();
12691 : : PGresult *res;
12692 : : int i;
12693 : : char *qtypname;
12694 : : char *qualtypname;
12695 : : char *typnotnull;
12696 : : char *typdefn;
12697 : : char *typdefault;
12698 : : Oid typcollation;
7188 tgl@sss.pgh.pa.us 12699 : 152 : bool typdefault_is_literal = false;
12700 : :
1421 12701 [ + + ]: 152 : if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
12702 : : {
12703 : : /* Set up query for domain-specific details */
12704 : 37 : appendPQExpBufferStr(query,
12705 : : "PREPARE dumpDomain(pg_catalog.oid) AS\n");
12706 : :
1413 12707 : 37 : appendPQExpBufferStr(query, "SELECT t.typnotnull, "
12708 : : "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
12709 : : "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
12710 : : "t.typdefault, "
12711 : : "CASE WHEN t.typcollation <> u.typcollation "
12712 : : "THEN t.typcollation ELSE 0 END AS typcollation "
12713 : : "FROM pg_catalog.pg_type t "
12714 : : "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
12715 : : "WHERE t.oid = $1");
12716 : :
1421 12717 : 37 : ExecuteSqlStatement(fout, query->data);
12718 : :
12719 : 37 : fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
12720 : : }
12721 : :
12722 : 152 : printfPQExpBuffer(query,
12723 : : "EXECUTE dumpDomain('%u')",
12724 : 152 : tyinfo->dobj.catId.oid);
12725 : :
5002 rhaas@postgresql.org 12726 : 152 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
12727 : :
8571 tgl@sss.pgh.pa.us 12728 : 152 : typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
12729 : 152 : typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
7188 12730 [ + + ]: 152 : if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
12731 : 37 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
12732 [ - + ]: 115 : else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
12733 : : {
8553 tgl@sss.pgh.pa.us 12734 :UBC 0 : typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6963 bruce@momjian.us 12735 : 0 : typdefault_is_literal = true; /* it needs quotes */
12736 : : }
12737 : : else
7188 tgl@sss.pgh.pa.us 12738 :CBC 115 : typdefault = NULL;
5345 12739 : 152 : typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
12740 : :
4031 alvherre@alvh.no-ip. 12741 [ + + ]: 152 : if (dopt->binary_upgrade)
5011 rhaas@postgresql.org 12742 : 25 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2949 tgl@sss.pgh.pa.us 12743 : 25 : tyinfo->dobj.catId.oid,
12744 : : true, /* force array type */
12745 : : false); /* force multirange type */
12746 : :
4705 12747 : 152 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2800 12748 : 152 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
12749 : :
8606 bruce@momjian.us 12750 : 152 : appendPQExpBuffer(q,
12751 : : "CREATE DOMAIN %s AS %s",
12752 : : qualtypname,
12753 : : typdefn);
12754 : :
12755 : : /* Print collation only if different from base type's collation */
5345 tgl@sss.pgh.pa.us 12756 [ + + ]: 152 : if (OidIsValid(typcollation))
12757 : : {
12758 : : CollInfo *coll;
12759 : :
12760 : 32 : coll = findCollationByOid(typcollation);
12761 [ + - ]: 32 : if (coll)
2800 12762 : 32 : appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
12763 : : }
12764 : :
12765 : : /*
12766 : : * Print a not-null constraint if there's one. In servers older than 17
12767 : : * these don't have names, so just print it unadorned; in newer ones they
12768 : : * do, but most of the time it's going to be the standard generated one,
12769 : : * so omit the name in that case also.
12770 : : */
8571 12771 [ + + ]: 152 : if (typnotnull[0] == 't')
12772 : : {
98 alvherre@kurilemu.de 12773 [ + - - + ]: 47 : if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
98 alvherre@kurilemu.de 12774 :UBC 0 : appendPQExpBufferStr(q, " NOT NULL");
12775 : : else
12776 : : {
98 alvherre@kurilemu.de 12777 :CBC 47 : ConstraintInfo *notnull = tyinfo->notnull;
12778 : :
12779 [ + - ]: 47 : if (!notnull->separate)
12780 : : {
12781 : : char *default_name;
12782 : :
12783 : : /* XXX should match ChooseConstraintName better */
12784 : 47 : default_name = psprintf("%s_not_null", tyinfo->dobj.name);
12785 : :
12786 [ + + ]: 47 : if (strcmp(default_name, notnull->dobj.name) == 0)
12787 : 15 : appendPQExpBufferStr(q, " NOT NULL");
12788 : : else
12789 : 32 : appendPQExpBuffer(q, " CONSTRAINT %s %s",
12790 : 32 : fmtId(notnull->dobj.name), notnull->condef);
12791 : 47 : free(default_name);
12792 : : }
12793 : : }
12794 : : }
12795 : :
7188 tgl@sss.pgh.pa.us 12796 [ + + ]: 152 : if (typdefault != NULL)
12797 : : {
4361 heikki.linnakangas@i 12798 : 37 : appendPQExpBufferStr(q, " DEFAULT ");
7188 tgl@sss.pgh.pa.us 12799 [ - + ]: 37 : if (typdefault_is_literal)
7092 tgl@sss.pgh.pa.us 12800 :UBC 0 : appendStringLiteralAH(q, typdefault, fout);
12801 : : else
7188 tgl@sss.pgh.pa.us 12802 :CBC 37 : appendPQExpBufferStr(q, typdefault);
12803 : : }
12804 : :
8355 12805 : 152 : PQclear(res);
12806 : :
12807 : : /*
12808 : : * Add any CHECK constraints for the domain
12809 : : */
5787 bruce@momjian.us 12810 [ + + ]: 259 : for (i = 0; i < tyinfo->nDomChecks; i++)
12811 : : {
12812 : 107 : ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
12813 : :
98 alvherre@kurilemu.de 12814 [ + + + - ]: 107 : if (!domcheck->separate && domcheck->contype == 'c')
7996 tgl@sss.pgh.pa.us 12815 : 102 : appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
7317 bruce@momjian.us 12816 : 102 : fmtId(domcheck->dobj.name), domcheck->condef);
12817 : : }
12818 : :
4361 heikki.linnakangas@i 12819 : 152 : appendPQExpBufferStr(q, ";\n");
12820 : :
2800 tgl@sss.pgh.pa.us 12821 : 152 : appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
12822 : :
4031 alvherre@alvh.no-ip. 12823 [ + + ]: 152 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 12824 : 25 : binary_upgrade_extension_member(q, &tyinfo->dobj,
12825 : : "DOMAIN", qtypname,
12826 : 25 : tyinfo->dobj.namespace->dobj.name);
12827 : :
3491 sfrost@snowman.net 12828 [ + - ]: 152 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12829 : 152 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 12830 : 152 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
12831 : : .namespace = tyinfo->dobj.namespace->dobj.name,
12832 : : .owner = tyinfo->rolname,
12833 : : .description = "DOMAIN",
12834 : : .section = SECTION_PRE_DATA,
12835 : : .createStmt = q->data,
12836 : : .dropStmt = delq->data));
12837 : :
12838 : : /* Dump Domain Comments and Security Labels */
3491 sfrost@snowman.net 12839 [ - + ]: 152 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 12840 :UBC 0 : dumpComment(fout, "DOMAIN", qtypname,
3491 sfrost@snowman.net 12841 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12842 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12843 : :
3491 sfrost@snowman.net 12844 [ - + ]:CBC 152 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 12845 :UBC 0 : dumpSecLabel(fout, "DOMAIN", qtypname,
3491 sfrost@snowman.net 12846 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
12847 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
12848 : :
3491 sfrost@snowman.net 12849 [ + + ]:CBC 152 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1934 tgl@sss.pgh.pa.us 12850 : 32 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
12851 : : qtypname, NULL,
3491 sfrost@snowman.net 12852 : 32 : tyinfo->dobj.namespace->dobj.name,
574 tgl@sss.pgh.pa.us 12853 : 32 : NULL, tyinfo->rolname, &tyinfo->dacl);
12854 : :
12855 : : /* Dump any per-constraint comments */
3961 alvherre@alvh.no-ip. 12856 [ + + ]: 259 : for (i = 0; i < tyinfo->nDomChecks; i++)
12857 : : {
12858 : 107 : ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
12859 : : PQExpBuffer conprefix;
12860 : :
12861 : : /* but only if the constraint itself was dumped here */
103 alvherre@kurilemu.de 12862 [ + + ]: 107 : if (domcheck->separate)
12863 : 5 : continue;
12864 : :
12865 : 102 : conprefix = createPQExpBuffer();
2800 tgl@sss.pgh.pa.us 12866 : 102 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
3961 alvherre@alvh.no-ip. 12867 : 102 : fmtId(domcheck->dobj.name));
12868 : :
1090 tgl@sss.pgh.pa.us 12869 [ + + ]: 102 : if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 12870 : 32 : dumpComment(fout, conprefix->data, qtypname,
3491 sfrost@snowman.net 12871 : 32 : tyinfo->dobj.namespace->dobj.name,
12872 : 32 : tyinfo->rolname,
12873 : 32 : domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
12874 : :
2800 tgl@sss.pgh.pa.us 12875 : 102 : destroyPQExpBuffer(conprefix);
12876 : : }
12877 : :
12878 : : /*
12879 : : * And a comment on the not-null constraint, if there's one -- but only if
12880 : : * the constraint itself was dumped here
12881 : : */
98 alvherre@kurilemu.de 12882 [ + + + - ]: 152 : if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
12883 : : {
12884 : 47 : PQExpBuffer conprefix = createPQExpBuffer();
12885 : :
12886 : 47 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
12887 : 47 : fmtId(tyinfo->notnull->dobj.name));
12888 : :
12889 [ + + ]: 47 : if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
12890 : 32 : dumpComment(fout, conprefix->data, qtypname,
12891 : 32 : tyinfo->dobj.namespace->dobj.name,
12892 : 32 : tyinfo->rolname,
12893 : 32 : tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
12894 : 47 : destroyPQExpBuffer(conprefix);
12895 : : }
12896 : :
8571 tgl@sss.pgh.pa.us 12897 : 152 : destroyPQExpBuffer(q);
12898 : 152 : destroyPQExpBuffer(delq);
12899 : 152 : destroyPQExpBuffer(query);
2800 12900 : 152 : free(qtypname);
12901 : 152 : free(qualtypname);
8606 bruce@momjian.us 12902 : 152 : }
12903 : :
12904 : : /*
12905 : : * dumpCompositeType
12906 : : * writes out to fout the queries to recreate a user-defined stand-alone
12907 : : * composite type
12908 : : */
12909 : : static void
1720 peter@eisentraut.org 12910 : 130 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
12911 : : {
3575 tgl@sss.pgh.pa.us 12912 : 130 : DumpOptions *dopt = fout->dopt;
8474 bruce@momjian.us 12913 : 130 : PQExpBuffer q = createPQExpBuffer();
5273 heikki.linnakangas@i 12914 : 130 : PQExpBuffer dropped = createPQExpBuffer();
8474 bruce@momjian.us 12915 : 130 : PQExpBuffer delq = createPQExpBuffer();
12916 : 130 : PQExpBuffer query = createPQExpBuffer();
12917 : : PGresult *res;
12918 : : char *qtypname;
12919 : : char *qualtypname;
12920 : : int ntups;
12921 : : int i_attname;
12922 : : int i_atttypdefn;
12923 : : int i_attlen;
12924 : : int i_attalign;
12925 : : int i_attisdropped;
12926 : : int i_attcollation;
12927 : : int i;
12928 : : int actual_atts;
12929 : :
1421 tgl@sss.pgh.pa.us 12930 [ + + ]: 130 : if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
12931 : : {
12932 : : /*
12933 : : * Set up query for type-specific details.
12934 : : *
12935 : : * Since we only want to dump COLLATE clauses for attributes whose
12936 : : * collation is different from their type's default, we use a CASE
12937 : : * here to suppress uninteresting attcollations cheaply. atttypid
12938 : : * will be 0 for dropped columns; collation does not matter for those.
12939 : : */
12940 : 55 : appendPQExpBufferStr(query,
12941 : : "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
12942 : : "SELECT a.attname, a.attnum, "
12943 : : "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
12944 : : "a.attlen, a.attalign, a.attisdropped, "
12945 : : "CASE WHEN a.attcollation <> at.typcollation "
12946 : : "THEN a.attcollation ELSE 0 END AS attcollation "
12947 : : "FROM pg_catalog.pg_type ct "
12948 : : "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
12949 : : "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
12950 : : "WHERE ct.oid = $1 "
12951 : : "ORDER BY a.attnum");
12952 : :
12953 : 55 : ExecuteSqlStatement(fout, query->data);
12954 : :
12955 : 55 : fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
12956 : : }
12957 : :
12958 : 130 : printfPQExpBuffer(query,
12959 : : "EXECUTE dumpCompositeType('%u')",
12960 : 130 : tyinfo->dobj.catId.oid);
12961 : :
5011 rhaas@postgresql.org 12962 : 130 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12963 : :
8474 bruce@momjian.us 12964 : 130 : ntups = PQntuples(res);
12965 : :
8460 tgl@sss.pgh.pa.us 12966 : 130 : i_attname = PQfnumber(res, "attname");
12967 : 130 : i_atttypdefn = PQfnumber(res, "atttypdefn");
5273 heikki.linnakangas@i 12968 : 130 : i_attlen = PQfnumber(res, "attlen");
12969 : 130 : i_attalign = PQfnumber(res, "attalign");
12970 : 130 : i_attisdropped = PQfnumber(res, "attisdropped");
5307 tgl@sss.pgh.pa.us 12971 : 130 : i_attcollation = PQfnumber(res, "attcollation");
12972 : :
4031 alvherre@alvh.no-ip. 12973 [ + + ]: 130 : if (dopt->binary_upgrade)
12974 : : {
5011 rhaas@postgresql.org 12975 : 18 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2949 tgl@sss.pgh.pa.us 12976 : 18 : tyinfo->dobj.catId.oid,
12977 : : false, false);
481 nathan@postgresql.or 12978 : 18 : binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
12979 : : }
12980 : :
4705 tgl@sss.pgh.pa.us 12981 : 130 : qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
2800 12982 : 130 : qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
12983 : :
8460 12984 : 130 : appendPQExpBuffer(q, "CREATE TYPE %s AS (",
12985 : : qualtypname);
12986 : :
5273 heikki.linnakangas@i 12987 : 130 : actual_atts = 0;
8474 bruce@momjian.us 12988 [ + + ]: 412 : for (i = 0; i < ntups; i++)
12989 : : {
12990 : : char *attname;
12991 : : char *atttypdefn;
12992 : : char *attlen;
12993 : : char *attalign;
12994 : : bool attisdropped;
12995 : : Oid attcollation;
12996 : :
8460 tgl@sss.pgh.pa.us 12997 : 282 : attname = PQgetvalue(res, i, i_attname);
12998 : 282 : atttypdefn = PQgetvalue(res, i, i_atttypdefn);
5273 heikki.linnakangas@i 12999 : 282 : attlen = PQgetvalue(res, i, i_attlen);
13000 : 282 : attalign = PQgetvalue(res, i, i_attalign);
13001 : 282 : attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
5307 tgl@sss.pgh.pa.us 13002 : 282 : attcollation = atooid(PQgetvalue(res, i, i_attcollation));
13003 : :
4031 alvherre@alvh.no-ip. 13004 [ + + + + ]: 282 : if (attisdropped && !dopt->binary_upgrade)
5273 heikki.linnakangas@i 13005 : 8 : continue;
13006 : :
13007 : : /* Format properly if not first attr */
13008 [ + + ]: 274 : if (actual_atts++ > 0)
4361 13009 : 144 : appendPQExpBufferChar(q, ',');
13010 : 274 : appendPQExpBufferStr(q, "\n\t");
13011 : :
5273 13012 [ + + ]: 274 : if (!attisdropped)
13013 : : {
13014 : 272 : appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
13015 : :
13016 : : /* Add collation if not default for the column type */
13017 [ - + ]: 272 : if (OidIsValid(attcollation))
13018 : : {
13019 : : CollInfo *coll;
13020 : :
5273 heikki.linnakangas@i 13021 :UBC 0 : coll = findCollationByOid(attcollation);
13022 [ # # ]: 0 : if (coll)
2800 tgl@sss.pgh.pa.us 13023 : 0 : appendPQExpBuffer(q, " COLLATE %s",
13024 : 0 : fmtQualifiedDumpable(coll));
13025 : : }
13026 : : }
13027 : : else
13028 : : {
13029 : : /*
13030 : : * This is a dropped attribute and we're in binary_upgrade mode.
13031 : : * Insert a placeholder for it in the CREATE TYPE command, and set
13032 : : * length and alignment with direct UPDATE to the catalogs
13033 : : * afterwards. See similar code in dumpTableSchema().
13034 : : */
5273 heikki.linnakangas@i 13035 :CBC 2 : appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
13036 : :
13037 : : /* stash separately for insertion after the CREATE TYPE */
4361 13038 : 2 : appendPQExpBufferStr(dropped,
13039 : : "\n-- For binary upgrade, recreate dropped column.\n");
5273 13040 : 2 : appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
13041 : : "SET attlen = %s, "
13042 : : "attalign = '%s', attbyval = false\n"
13043 : : "WHERE attname = ", attlen, attalign);
13044 : 2 : appendStringLiteralAH(dropped, attname, fout);
4361 13045 : 2 : appendPQExpBufferStr(dropped, "\n AND attrelid = ");
2800 tgl@sss.pgh.pa.us 13046 : 2 : appendStringLiteralAH(dropped, qualtypname, fout);
4361 heikki.linnakangas@i 13047 : 2 : appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
13048 : :
5273 13049 : 2 : appendPQExpBuffer(dropped, "ALTER TYPE %s ",
13050 : : qualtypname);
13051 : 2 : appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
13052 : : fmtId(attname));
13053 : : }
13054 : : }
4361 13055 : 130 : appendPQExpBufferStr(q, "\n);\n");
5273 13056 : 130 : appendPQExpBufferStr(q, dropped->data);
13057 : :
2800 tgl@sss.pgh.pa.us 13058 : 130 : appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
13059 : :
4031 alvherre@alvh.no-ip. 13060 [ + + ]: 130 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 13061 : 18 : binary_upgrade_extension_member(q, &tyinfo->dobj,
13062 : : "TYPE", qtypname,
13063 : 18 : tyinfo->dobj.namespace->dobj.name);
13064 : :
3491 sfrost@snowman.net 13065 [ + + ]: 130 : if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13066 : 113 : ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 13067 : 113 : ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
13068 : : .namespace = tyinfo->dobj.namespace->dobj.name,
13069 : : .owner = tyinfo->rolname,
13070 : : .description = "TYPE",
13071 : : .section = SECTION_PRE_DATA,
13072 : : .createStmt = q->data,
13073 : : .dropStmt = delq->data));
13074 : :
13075 : :
13076 : : /* Dump Type Comments and Security Labels */
3491 sfrost@snowman.net 13077 [ + + ]: 130 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 13078 : 32 : dumpComment(fout, "TYPE", qtypname,
3491 sfrost@snowman.net 13079 : 32 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
13080 : 32 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
13081 : :
13082 [ - + ]: 130 : if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 13083 :UBC 0 : dumpSecLabel(fout, "TYPE", qtypname,
3491 sfrost@snowman.net 13084 : 0 : tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
13085 : 0 : tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
13086 : :
3491 sfrost@snowman.net 13087 [ + + ]:CBC 130 : if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
1934 tgl@sss.pgh.pa.us 13088 : 18 : dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
13089 : : qtypname, NULL,
3491 sfrost@snowman.net 13090 : 18 : tyinfo->dobj.namespace->dobj.name,
574 tgl@sss.pgh.pa.us 13091 : 18 : NULL, tyinfo->rolname, &tyinfo->dacl);
13092 : :
13093 : : /* Dump any per-column comments */
1397 13094 [ + + ]: 130 : if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13095 : 32 : dumpCompositeTypeColComments(fout, tyinfo, res);
13096 : :
7996 13097 : 130 : PQclear(res);
13098 : 130 : destroyPQExpBuffer(q);
5273 heikki.linnakangas@i 13099 : 130 : destroyPQExpBuffer(dropped);
7996 tgl@sss.pgh.pa.us 13100 : 130 : destroyPQExpBuffer(delq);
13101 : 130 : destroyPQExpBuffer(query);
2800 13102 : 130 : free(qtypname);
13103 : 130 : free(qualtypname);
5940 13104 : 130 : }
13105 : :
13106 : : /*
13107 : : * dumpCompositeTypeColComments
13108 : : * writes out to fout the queries to recreate comments on the columns of
13109 : : * a user-defined stand-alone composite type.
13110 : : *
13111 : : * The caller has already made a query to collect the names and attnums
13112 : : * of the type's columns, so we just pass that result into here rather
13113 : : * than reading them again.
13114 : : */
13115 : : static void
1397 13116 : 32 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
13117 : : PGresult *res)
13118 : : {
13119 : : CommentItem *comments;
13120 : : int ncomments;
13121 : : PQExpBuffer query;
13122 : : PQExpBuffer target;
13123 : : int i;
13124 : : int ntups;
13125 : : int i_attname;
13126 : : int i_attnum;
13127 : : int i_attisdropped;
13128 : :
13129 : : /* do nothing, if --no-comments is supplied */
2832 13130 [ - + ]: 32 : if (fout->dopt->no_comments)
2832 tgl@sss.pgh.pa.us 13131 :UBC 0 : return;
13132 : :
13133 : : /* Search for comments associated with type's pg_class OID */
1397 tgl@sss.pgh.pa.us 13134 :CBC 32 : ncomments = findComments(RelationRelationId, tyinfo->typrelid,
13135 : : &comments);
13136 : :
13137 : : /* If no comments exist, we're done */
5940 13138 [ - + ]: 32 : if (ncomments <= 0)
5940 tgl@sss.pgh.pa.us 13139 :UBC 0 : return;
13140 : :
13141 : : /* Build COMMENT ON statements */
1397 tgl@sss.pgh.pa.us 13142 :CBC 32 : query = createPQExpBuffer();
5940 13143 : 32 : target = createPQExpBuffer();
13144 : :
1397 13145 : 32 : ntups = PQntuples(res);
5940 13146 : 32 : i_attnum = PQfnumber(res, "attnum");
13147 : 32 : i_attname = PQfnumber(res, "attname");
1397 13148 : 32 : i_attisdropped = PQfnumber(res, "attisdropped");
5940 13149 [ + + ]: 64 : while (ncomments > 0)
13150 : : {
13151 : : const char *attname;
13152 : :
13153 : 32 : attname = NULL;
13154 [ + - ]: 32 : for (i = 0; i < ntups; i++)
13155 : : {
1397 13156 [ + - ]: 32 : if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
13157 [ + - ]: 32 : PQgetvalue(res, i, i_attisdropped)[0] != 't')
13158 : : {
5940 13159 : 32 : attname = PQgetvalue(res, i, i_attname);
13160 : 32 : break;
13161 : : }
13162 : : }
13163 [ + - ]: 32 : if (attname) /* just in case we don't find it */
13164 : : {
13165 : 32 : const char *descr = comments->descr;
13166 : :
13167 : 32 : resetPQExpBuffer(target);
13168 : 32 : appendPQExpBuffer(target, "COLUMN %s.",
5787 bruce@momjian.us 13169 : 32 : fmtId(tyinfo->dobj.name));
4361 heikki.linnakangas@i 13170 : 32 : appendPQExpBufferStr(target, fmtId(attname));
13171 : :
5940 tgl@sss.pgh.pa.us 13172 : 32 : resetPQExpBuffer(query);
2800 13173 : 32 : appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
13174 : 32 : fmtQualifiedDumpable(tyinfo));
13175 : 32 : appendPQExpBuffer(query, "%s IS ", fmtId(attname));
5940 13176 : 32 : appendStringLiteralAH(query, descr, fout);
4361 heikki.linnakangas@i 13177 : 32 : appendPQExpBufferStr(query, ";\n");
13178 : :
5940 tgl@sss.pgh.pa.us 13179 : 32 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 13180 : 32 : ARCHIVE_OPTS(.tag = target->data,
13181 : : .namespace = tyinfo->dobj.namespace->dobj.name,
13182 : : .owner = tyinfo->rolname,
13183 : : .description = "COMMENT",
13184 : : .section = SECTION_NONE,
13185 : : .createStmt = query->data,
13186 : : .deps = &(tyinfo->dobj.dumpId),
13187 : : .nDeps = 1));
13188 : : }
13189 : :
5940 tgl@sss.pgh.pa.us 13190 : 32 : comments++;
13191 : 32 : ncomments--;
13192 : : }
13193 : :
13194 : 32 : destroyPQExpBuffer(query);
13195 : 32 : destroyPQExpBuffer(target);
13196 : : }
13197 : :
13198 : : /*
13199 : : * dumpShellType
13200 : : * writes out to fout the queries to create a shell type
13201 : : *
13202 : : * We dump a shell definition in advance of the I/O functions for the type.
13203 : : */
13204 : : static void
1720 peter@eisentraut.org 13205 : 73 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
13206 : : {
3575 tgl@sss.pgh.pa.us 13207 : 73 : DumpOptions *dopt = fout->dopt;
13208 : : PQExpBuffer q;
13209 : :
13210 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 13211 [ + + ]: 73 : if (!dopt->dumpSchema)
7179 tgl@sss.pgh.pa.us 13212 : 6 : return;
13213 : :
13214 : 67 : q = createPQExpBuffer();
13215 : :
13216 : : /*
13217 : : * Note the lack of a DROP command for the shell type; any required DROP
13218 : : * is driven off the base type entry, instead. This interacts with
13219 : : * _printTocEntry()'s use of the presence of a DROP command to decide
13220 : : * whether an entry needs an ALTER OWNER command. We don't want to alter
13221 : : * the shell type's owner immediately on creation; that should happen only
13222 : : * after it's filled in, otherwise the backend complains.
13223 : : */
13224 : :
4031 alvherre@alvh.no-ip. 13225 [ + + ]: 67 : if (dopt->binary_upgrade)
5011 rhaas@postgresql.org 13226 : 8 : binary_upgrade_set_type_oids_by_type_oid(fout, q,
2949 tgl@sss.pgh.pa.us 13227 : 8 : stinfo->baseType->dobj.catId.oid,
13228 : : false, false);
13229 : :
7179 13230 : 67 : appendPQExpBuffer(q, "CREATE TYPE %s;\n",
2800 13231 : 67 : fmtQualifiedDumpable(stinfo));
13232 : :
3491 sfrost@snowman.net 13233 [ + - ]: 67 : if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13234 : 67 : ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 13235 : 67 : ARCHIVE_OPTS(.tag = stinfo->dobj.name,
13236 : : .namespace = stinfo->dobj.namespace->dobj.name,
13237 : : .owner = stinfo->baseType->rolname,
13238 : : .description = "SHELL TYPE",
13239 : : .section = SECTION_PRE_DATA,
13240 : : .createStmt = q->data));
13241 : :
7179 tgl@sss.pgh.pa.us 13242 : 67 : destroyPQExpBuffer(q);
13243 : : }
13244 : :
13245 : : /*
13246 : : * dumpProcLang
13247 : : * writes out to fout the queries to recreate a user-defined
13248 : : * procedural language
13249 : : */
13250 : : static void
1720 peter@eisentraut.org 13251 : 82 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
13252 : : {
3575 tgl@sss.pgh.pa.us 13253 : 82 : DumpOptions *dopt = fout->dopt;
13254 : : PQExpBuffer defqry;
13255 : : PQExpBuffer delqry;
13256 : : bool useParams;
13257 : : char *qlanname;
13258 : : FuncInfo *funcInfo;
5879 13259 : 82 : FuncInfo *inlineInfo = NULL;
7996 13260 : 82 : FuncInfo *validatorInfo = NULL;
13261 : :
13262 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 13263 [ + + ]: 82 : if (!dopt->dumpSchema)
7996 tgl@sss.pgh.pa.us 13264 : 13 : return;
13265 : :
13266 : : /*
13267 : : * Try to find the support function(s). It is not an error if we don't
13268 : : * find them --- if the functions are in the pg_catalog schema, as is
13269 : : * standard in 8.1 and up, then we won't have loaded them. (In this case
13270 : : * we will emit a parameterless CREATE LANGUAGE command, which will
13271 : : * require PL template knowledge in the backend to reload.)
13272 : : */
13273 : :
13274 : 69 : funcInfo = findFuncByOid(plang->lanplcallfoid);
7179 13275 [ + + + + ]: 69 : if (funcInfo != NULL && !funcInfo->dobj.dump)
7357 13276 : 2 : funcInfo = NULL; /* treat not-dumped same as not-found */
13277 : :
5879 13278 [ + + ]: 69 : if (OidIsValid(plang->laninline))
13279 : : {
13280 : 38 : inlineInfo = findFuncByOid(plang->laninline);
13281 [ + + + - ]: 38 : if (inlineInfo != NULL && !inlineInfo->dobj.dump)
13282 : 1 : inlineInfo = NULL;
13283 : : }
13284 : :
7996 13285 [ + + ]: 69 : if (OidIsValid(plang->lanvalidator))
13286 : : {
13287 : 38 : validatorInfo = findFuncByOid(plang->lanvalidator);
7179 13288 [ + + + - ]: 38 : if (validatorInfo != NULL && !validatorInfo->dobj.dump)
7357 13289 : 1 : validatorInfo = NULL;
13290 : : }
13291 : :
13292 : : /*
13293 : : * If the functions are dumpable then emit a complete CREATE LANGUAGE with
13294 : : * parameters. Otherwise, we'll write a parameterless command, which will
13295 : : * be interpreted as CREATE EXTENSION.
13296 : : */
13297 [ + - ]: 30 : useParams = (funcInfo != NULL &&
5879 13298 [ + + + - : 129 : (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
+ - ]
7357 13299 [ + - ]: 30 : (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
13300 : :
7996 13301 : 69 : defqry = createPQExpBuffer();
13302 : 69 : delqry = createPQExpBuffer();
13303 : :
5085 bruce@momjian.us 13304 : 69 : qlanname = pg_strdup(fmtId(plang->dobj.name));
13305 : :
7996 tgl@sss.pgh.pa.us 13306 : 69 : appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
13307 : : qlanname);
13308 : :
7357 13309 [ + + ]: 69 : if (useParams)
13310 : : {
5724 13311 : 30 : appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
13312 [ - + ]: 30 : plang->lanpltrusted ? "TRUSTED " : "",
13313 : : qlanname);
7357 13314 : 30 : appendPQExpBuffer(defqry, " HANDLER %s",
2800 13315 : 30 : fmtQualifiedDumpable(funcInfo));
5879 13316 [ - + ]: 30 : if (OidIsValid(plang->laninline))
2800 tgl@sss.pgh.pa.us 13317 :UBC 0 : appendPQExpBuffer(defqry, " INLINE %s",
13318 : 0 : fmtQualifiedDumpable(inlineInfo));
7357 tgl@sss.pgh.pa.us 13319 [ - + ]:CBC 30 : if (OidIsValid(plang->lanvalidator))
2800 tgl@sss.pgh.pa.us 13320 :UBC 0 : appendPQExpBuffer(defqry, " VALIDATOR %s",
13321 : 0 : fmtQualifiedDumpable(validatorInfo));
13322 : : }
13323 : : else
13324 : : {
13325 : : /*
13326 : : * If not dumping parameters, then use CREATE OR REPLACE so that the
13327 : : * command will not fail if the language is preinstalled in the target
13328 : : * database.
13329 : : *
13330 : : * Modern servers will interpret this as CREATE EXTENSION IF NOT
13331 : : * EXISTS; perhaps we should emit that instead? But it might just add
13332 : : * confusion.
13333 : : */
5724 tgl@sss.pgh.pa.us 13334 :CBC 39 : appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
13335 : : qlanname);
13336 : : }
4361 heikki.linnakangas@i 13337 : 69 : appendPQExpBufferStr(defqry, ";\n");
13338 : :
4031 alvherre@alvh.no-ip. 13339 [ + + ]: 69 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 13340 : 2 : binary_upgrade_extension_member(defqry, &plang->dobj,
13341 : : "LANGUAGE", qlanname, NULL);
13342 : :
3491 sfrost@snowman.net 13343 [ + + ]: 69 : if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
13344 : 31 : ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
2460 alvherre@alvh.no-ip. 13345 : 31 : ARCHIVE_OPTS(.tag = plang->dobj.name,
13346 : : .owner = plang->lanowner,
13347 : : .description = "PROCEDURAL LANGUAGE",
13348 : : .section = SECTION_PRE_DATA,
13349 : : .createStmt = defqry->data,
13350 : : .dropStmt = delqry->data,
13351 : : ));
13352 : :
13353 : : /* Dump Proc Lang Comments and Security Labels */
3491 sfrost@snowman.net 13354 [ - + ]: 69 : if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 13355 :UBC 0 : dumpComment(fout, "LANGUAGE", qlanname,
13356 : 0 : NULL, plang->lanowner,
3491 sfrost@snowman.net 13357 : 0 : plang->dobj.catId, 0, plang->dobj.dumpId);
13358 : :
3491 sfrost@snowman.net 13359 [ - + ]:CBC 69 : if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 13360 :UBC 0 : dumpSecLabel(fout, "LANGUAGE", qlanname,
13361 : 0 : NULL, plang->lanowner,
3491 sfrost@snowman.net 13362 : 0 : plang->dobj.catId, 0, plang->dobj.dumpId);
13363 : :
3491 sfrost@snowman.net 13364 [ + + + - ]:CBC 69 : if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
1934 tgl@sss.pgh.pa.us 13365 : 38 : dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
13366 : : qlanname, NULL, NULL,
574 13367 : 38 : NULL, plang->lanowner, &plang->dacl);
13368 : :
7996 13369 : 69 : free(qlanname);
13370 : :
13371 : 69 : destroyPQExpBuffer(defqry);
13372 : 69 : destroyPQExpBuffer(delqry);
13373 : : }
13374 : :
13375 : : /*
13376 : : * format_function_arguments: generate function name and argument list
13377 : : *
13378 : : * This is used when we can rely on pg_get_function_arguments to format
13379 : : * the argument list. Note, however, that pg_get_function_arguments
13380 : : * does not special-case zero-argument aggregates.
13381 : : */
13382 : : static char *
1720 peter@eisentraut.org 13383 : 4082 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
13384 : : {
13385 : : PQExpBufferData fn;
13386 : :
6310 tgl@sss.pgh.pa.us 13387 : 4082 : initPQExpBuffer(&fn);
4361 heikki.linnakangas@i 13388 : 4082 : appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
4437 tgl@sss.pgh.pa.us 13389 [ + + + + ]: 4082 : if (is_agg && finfo->nargs == 0)
4361 heikki.linnakangas@i 13390 : 80 : appendPQExpBufferStr(&fn, "(*)");
13391 : : else
4437 tgl@sss.pgh.pa.us 13392 : 4002 : appendPQExpBuffer(&fn, "(%s)", funcargs);
6310 13393 : 4082 : return fn.data;
13394 : : }
13395 : :
13396 : : /*
13397 : : * format_function_signature: generate function name and argument list
13398 : : *
13399 : : * Only a minimal list of input argument types is generated; this is
13400 : : * sufficient to reference the function, but not to define it.
13401 : : *
13402 : : * If honor_quotes is false then the function name is never quoted.
13403 : : * This is appropriate for use in TOC tags, but not in SQL commands.
13404 : : */
13405 : : static char *
1720 peter@eisentraut.org 13406 : 2149 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
13407 : : {
13408 : : PQExpBufferData fn;
13409 : : int j;
13410 : :
7514 tgl@sss.pgh.pa.us 13411 : 2149 : initPQExpBuffer(&fn);
13412 [ + + ]: 2149 : if (honor_quotes)
13413 : 393 : appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
13414 : : else
13415 : 1756 : appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
13416 [ + + ]: 3945 : for (j = 0; j < finfo->nargs; j++)
13417 : : {
4361 heikki.linnakangas@i 13418 [ + + ]: 1796 : if (j > 0)
13419 : 422 : appendPQExpBufferStr(&fn, ", ");
13420 : :
1510 tgl@sss.pgh.pa.us 13421 : 1796 : appendPQExpBufferStr(&fn,
13422 : 1796 : getFormattedTypeName(fout, finfo->argtypes[j],
13423 : : zeroIsError));
13424 : : }
4361 heikki.linnakangas@i 13425 : 2149 : appendPQExpBufferChar(&fn, ')');
7514 tgl@sss.pgh.pa.us 13426 : 2149 : return fn.data;
13427 : : }
13428 : :
13429 : :
13430 : : /*
13431 : : * dumpFunc:
13432 : : * dump out one function
13433 : : */
13434 : : static void
1720 peter@eisentraut.org 13435 : 1818 : dumpFunc(Archive *fout, const FuncInfo *finfo)
13436 : : {
3575 tgl@sss.pgh.pa.us 13437 : 1818 : DumpOptions *dopt = fout->dopt;
13438 : : PQExpBuffer query;
13439 : : PQExpBuffer q;
13440 : : PQExpBuffer delqry;
13441 : : PQExpBuffer asPart;
13442 : : PGresult *res;
13443 : : char *funcsig; /* identity signature */
3050 13444 : 1818 : char *funcfullsig = NULL; /* full signature */
13445 : : char *funcsig_tag;
13446 : : char *qual_funcsig;
13447 : : char *proretset;
13448 : : char *prosrc;
13449 : : char *probin;
13450 : : char *prosqlbody;
13451 : : char *funcargs;
13452 : : char *funciargs;
13453 : : char *funcresult;
13454 : : char *protrftypes;
13455 : : char *prokind;
13456 : : char *provolatile;
13457 : : char *proisstrict;
13458 : : char *prosecdef;
13459 : : char *proleakproof;
13460 : : char *proconfig;
13461 : : char *procost;
13462 : : char *prorows;
13463 : : char *prosupport;
13464 : : char *proparallel;
13465 : : char *lanname;
6629 13466 : 1818 : char **configitems = NULL;
13467 : 1818 : int nconfigitems = 0;
13468 : : const char *keyword;
13469 : :
13470 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 13471 [ + + ]: 1818 : if (!dopt->dumpSchema)
7378 tgl@sss.pgh.pa.us 13472 : 62 : return;
13473 : :
7996 13474 : 1756 : query = createPQExpBuffer();
13475 : 1756 : q = createPQExpBuffer();
13476 : 1756 : delqry = createPQExpBuffer();
13477 : 1756 : asPart = createPQExpBuffer();
13478 : :
1421 13479 [ + + ]: 1756 : if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
13480 : : {
13481 : : /* Set up query for function-specific details */
1838 drowley@postgresql.o 13482 : 66 : appendPQExpBufferStr(query,
13483 : : "PREPARE dumpFunc(pg_catalog.oid) AS\n");
13484 : :
13485 : 66 : appendPQExpBufferStr(query,
13486 : : "SELECT\n"
13487 : : "proretset,\n"
13488 : : "prosrc,\n"
13489 : : "probin,\n"
13490 : : "provolatile,\n"
13491 : : "proisstrict,\n"
13492 : : "prosecdef,\n"
13493 : : "lanname,\n"
13494 : : "proconfig,\n"
13495 : : "procost,\n"
13496 : : "prorows,\n"
13497 : : "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
13498 : : "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
13499 : : "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
13500 : : "proleakproof,\n");
13501 : :
1421 tgl@sss.pgh.pa.us 13502 [ + - ]: 66 : if (fout->remoteVersion >= 90500)
13503 : 66 : appendPQExpBufferStr(query,
13504 : : "array_to_string(protrftypes, ' ') AS protrftypes,\n");
13505 : : else
1408 tgl@sss.pgh.pa.us 13506 :UBC 0 : appendPQExpBufferStr(query,
13507 : : "NULL AS protrftypes,\n");
13508 : :
1421 tgl@sss.pgh.pa.us 13509 [ + - ]:CBC 66 : if (fout->remoteVersion >= 90600)
13510 : 66 : appendPQExpBufferStr(query,
13511 : : "proparallel,\n");
13512 : : else
1421 tgl@sss.pgh.pa.us 13513 :UBC 0 : appendPQExpBufferStr(query,
13514 : : "'u' AS proparallel,\n");
13515 : :
1421 tgl@sss.pgh.pa.us 13516 [ + - ]:CBC 66 : if (fout->remoteVersion >= 110000)
13517 : 66 : appendPQExpBufferStr(query,
13518 : : "prokind,\n");
13519 : : else
1421 tgl@sss.pgh.pa.us 13520 :UBC 0 : appendPQExpBufferStr(query,
13521 : : "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
13522 : :
1421 tgl@sss.pgh.pa.us 13523 [ + - ]:CBC 66 : if (fout->remoteVersion >= 120000)
13524 : 66 : appendPQExpBufferStr(query,
13525 : : "prosupport,\n");
13526 : : else
1421 tgl@sss.pgh.pa.us 13527 :UBC 0 : appendPQExpBufferStr(query,
13528 : : "'-' AS prosupport,\n");
13529 : :
1421 tgl@sss.pgh.pa.us 13530 [ + - ]:CBC 66 : if (fout->remoteVersion >= 140000)
13531 : 66 : appendPQExpBufferStr(query,
13532 : : "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
13533 : : else
1421 tgl@sss.pgh.pa.us 13534 :UBC 0 : appendPQExpBufferStr(query,
13535 : : "NULL AS prosqlbody\n");
13536 : :
1664 peter@eisentraut.org 13537 :CBC 66 : appendPQExpBufferStr(query,
13538 : : "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
13539 : : "WHERE p.oid = $1 "
13540 : : "AND l.oid = p.prolang");
13541 : :
1421 tgl@sss.pgh.pa.us 13542 : 66 : ExecuteSqlStatement(fout, query->data);
13543 : :
13544 : 66 : fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
13545 : : }
13546 : :
13547 : 1756 : printfPQExpBuffer(query,
13548 : : "EXECUTE dumpFunc('%u')",
1930 peter@eisentraut.org 13549 : 1756 : finfo->dobj.catId.oid);
13550 : :
5002 rhaas@postgresql.org 13551 : 1756 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
13552 : :
8571 tgl@sss.pgh.pa.us 13553 : 1756 : proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
1664 peter@eisentraut.org 13554 [ + + ]: 1756 : if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
13555 : : {
13556 : 1708 : prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
13557 : 1708 : probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
13558 : 1708 : prosqlbody = NULL;
13559 : : }
13560 : : else
13561 : : {
13562 : 48 : prosrc = NULL;
13563 : 48 : probin = NULL;
13564 : 48 : prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
13565 : : }
1413 tgl@sss.pgh.pa.us 13566 : 1756 : funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13567 : 1756 : funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13568 : 1756 : funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
1408 13569 : 1756 : protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
2796 peter_e@gmx.net 13570 : 1756 : prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
8571 tgl@sss.pgh.pa.us 13571 : 1756 : provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
13572 : 1756 : proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
8563 peter_e@gmx.net 13573 : 1756 : prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
5005 rhaas@postgresql.org 13574 : 1756 : proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
6629 tgl@sss.pgh.pa.us 13575 : 1756 : proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
6853 13576 : 1756 : procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
13577 : 1756 : prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
2452 13578 : 1756 : prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
1930 peter@eisentraut.org 13579 : 1756 : proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
8571 tgl@sss.pgh.pa.us 13580 : 1756 : lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
13581 : :
13582 : : /*
13583 : : * See backend/commands/functioncmds.c for details of how the 'AS' clause
13584 : : * is used.
13585 : : */
1664 peter@eisentraut.org 13586 [ + + ]: 1756 : if (prosqlbody)
13587 : : {
13588 : 48 : appendPQExpBufferStr(asPart, prosqlbody);
13589 : : }
1411 tgl@sss.pgh.pa.us 13590 [ + + ]: 1708 : else if (probin[0] != '\0')
13591 : : {
4361 heikki.linnakangas@i 13592 : 137 : appendPQExpBufferStr(asPart, "AS ");
7092 tgl@sss.pgh.pa.us 13593 : 137 : appendStringLiteralAH(asPart, probin, fout);
1411 13594 [ + - ]: 137 : if (prosrc[0] != '\0')
13595 : : {
4361 heikki.linnakangas@i 13596 : 137 : appendPQExpBufferStr(asPart, ", ");
13597 : :
13598 : : /*
13599 : : * where we have bin, use dollar quoting if allowed and src
13600 : : * contains quote or backslash; else use regular quoting.
13601 : : */
4031 alvherre@alvh.no-ip. 13602 [ + - ]: 137 : if (dopt->disable_dollar_quoting ||
3050 tgl@sss.pgh.pa.us 13603 [ + - + - ]: 137 : (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
7092 13604 : 137 : appendStringLiteralAH(asPart, prosrc, fout);
13605 : : else
7092 tgl@sss.pgh.pa.us 13606 :UBC 0 : appendStringLiteralDQ(asPart, prosrc, NULL);
13607 : : }
13608 : : }
13609 : : else
13610 : : {
1411 tgl@sss.pgh.pa.us 13611 :CBC 1571 : appendPQExpBufferStr(asPart, "AS ");
13612 : : /* with no bin, dollar quote src unconditionally if allowed */
13613 [ - + ]: 1571 : if (dopt->disable_dollar_quoting)
1411 tgl@sss.pgh.pa.us 13614 :UBC 0 : appendStringLiteralAH(asPart, prosrc, fout);
13615 : : else
1411 tgl@sss.pgh.pa.us 13616 :CBC 1571 : appendStringLiteralDQ(asPart, prosrc, NULL);
13617 : : }
13618 : :
1408 13619 [ + + ]: 1756 : if (*proconfig)
13620 : : {
6629 13621 [ - + ]: 15 : if (!parsePGArray(proconfig, &configitems, &nconfigitems))
1298 tgl@sss.pgh.pa.us 13622 :UBC 0 : pg_fatal("could not parse %s array", "proconfig");
13623 : : }
13624 : : else
13625 : : {
1803 michael@paquier.xyz 13626 :CBC 1741 : configitems = NULL;
13627 : 1741 : nconfigitems = 0;
13628 : : }
13629 : :
1413 tgl@sss.pgh.pa.us 13630 : 1756 : funcfullsig = format_function_arguments(finfo, funcargs, false);
13631 : 1756 : funcsig = format_function_arguments(finfo, funciargs, false);
13632 : :
5012 rhaas@postgresql.org 13633 : 1756 : funcsig_tag = format_function_signature(fout, finfo, false);
13634 : :
1464 tgl@sss.pgh.pa.us 13635 : 1756 : qual_funcsig = psprintf("%s.%s",
13636 : 1756 : fmtId(finfo->dobj.namespace->dobj.name),
13637 : : funcsig);
13638 : :
2796 peter_e@gmx.net 13639 [ + + ]: 1756 : if (prokind[0] == PROKIND_PROCEDURE)
13640 : 92 : keyword = "PROCEDURE";
13641 : : else
13642 : 1664 : keyword = "FUNCTION"; /* works for window functions too */
13643 : :
1464 tgl@sss.pgh.pa.us 13644 : 1756 : appendPQExpBuffer(delqry, "DROP %s %s;\n",
13645 : : keyword, qual_funcsig);
13646 : :
2800 13647 [ + - ]: 3512 : appendPQExpBuffer(q, "CREATE %s %s.%s",
13648 : : keyword,
13649 : 1756 : fmtId(finfo->dobj.namespace->dobj.name),
13650 : : funcfullsig ? funcfullsig :
13651 : : funcsig);
13652 : :
2796 peter_e@gmx.net 13653 [ + + ]: 1756 : if (prokind[0] == PROKIND_PROCEDURE)
13654 : : /* no result type to output */ ;
2888 13655 [ + - ]: 1664 : else if (funcresult)
13656 : 1664 : appendPQExpBuffer(q, " RETURNS %s", funcresult);
13657 : : else
2888 peter_e@gmx.net 13658 :UBC 0 : appendPQExpBuffer(q, " RETURNS %s%s",
6310 tgl@sss.pgh.pa.us 13659 [ # # ]: 0 : (proretset[0] == 't') ? "SETOF " : "",
1510 13660 : 0 : getFormattedTypeName(fout, finfo->prorettype,
13661 : : zeroIsError));
13662 : :
6327 heikki.linnakangas@i 13663 :CBC 1756 : appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
13664 : :
1408 tgl@sss.pgh.pa.us 13665 [ - + ]: 1756 : if (*protrftypes)
13666 : : {
320 dgustafsson@postgres 13667 :UBC 0 : Oid *typeids = pg_malloc(FUNC_MAX_ARGS * sizeof(Oid));
13668 : : int i;
13669 : :
3837 peter_e@gmx.net 13670 : 0 : appendPQExpBufferStr(q, " TRANSFORM ");
13671 : 0 : parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
13672 [ # # ]: 0 : for (i = 0; typeids[i]; i++)
13673 : : {
13674 [ # # ]: 0 : if (i != 0)
13675 : 0 : appendPQExpBufferStr(q, ", ");
13676 : 0 : appendPQExpBuffer(q, "FOR TYPE %s",
3050 tgl@sss.pgh.pa.us 13677 : 0 : getFormattedTypeName(fout, typeids[i], zeroAsNone));
13678 : : }
13679 : :
320 dgustafsson@postgres 13680 : 0 : free(typeids);
13681 : : }
13682 : :
2796 peter_e@gmx.net 13683 [ + + ]:CBC 1756 : if (prokind[0] == PROKIND_WINDOW)
4361 heikki.linnakangas@i 13684 : 5 : appendPQExpBufferStr(q, " WINDOW");
13685 : :
8564 peter_e@gmx.net 13686 [ + + ]: 1756 : if (provolatile[0] != PROVOLATILE_VOLATILE)
13687 : : {
8571 tgl@sss.pgh.pa.us 13688 [ + + ]: 351 : if (provolatile[0] == PROVOLATILE_IMMUTABLE)
4361 heikki.linnakangas@i 13689 : 330 : appendPQExpBufferStr(q, " IMMUTABLE");
8571 tgl@sss.pgh.pa.us 13690 [ + - ]: 21 : else if (provolatile[0] == PROVOLATILE_STABLE)
4361 heikki.linnakangas@i 13691 : 21 : appendPQExpBufferStr(q, " STABLE");
8571 tgl@sss.pgh.pa.us 13692 [ # # ]:UBC 0 : else if (provolatile[0] != PROVOLATILE_VOLATILE)
1298 13693 : 0 : pg_fatal("unrecognized provolatile value for function \"%s\"",
13694 : : finfo->dobj.name);
13695 : : }
13696 : :
8564 peter_e@gmx.net 13697 [ + + ]:CBC 1756 : if (proisstrict[0] == 't')
4361 heikki.linnakangas@i 13698 : 353 : appendPQExpBufferStr(q, " STRICT");
13699 : :
8563 peter_e@gmx.net 13700 [ - + ]: 1756 : if (prosecdef[0] == 't')
4361 heikki.linnakangas@i 13701 :UBC 0 : appendPQExpBufferStr(q, " SECURITY DEFINER");
13702 : :
5005 rhaas@postgresql.org 13703 [ + + ]:CBC 1756 : if (proleakproof[0] == 't')
4361 heikki.linnakangas@i 13704 : 10 : appendPQExpBufferStr(q, " LEAKPROOF");
13705 : :
13706 : : /*
13707 : : * COST and ROWS are emitted only if present and not default, so as not to
13708 : : * break backwards-compatibility of the dump without need. Keep this code
13709 : : * in sync with the defaults in functioncmds.c.
13710 : : */
6853 tgl@sss.pgh.pa.us 13711 [ + - ]: 1756 : if (strcmp(procost, "0") != 0)
13712 : : {
13713 [ + + + + ]: 1756 : if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
13714 : : {
13715 : : /* default cost is 1 */
13716 [ - + ]: 366 : if (strcmp(procost, "1") != 0)
6853 tgl@sss.pgh.pa.us 13717 :UBC 0 : appendPQExpBuffer(q, " COST %s", procost);
13718 : : }
13719 : : else
13720 : : {
13721 : : /* default cost is 100 */
6853 tgl@sss.pgh.pa.us 13722 [ + + ]:CBC 1390 : if (strcmp(procost, "100") != 0)
13723 : 6 : appendPQExpBuffer(q, " COST %s", procost);
13724 : : }
13725 : : }
13726 [ + + ]: 1756 : if (proretset[0] == 't' &&
13727 [ + - - + ]: 187 : strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
6853 tgl@sss.pgh.pa.us 13728 :UBC 0 : appendPQExpBuffer(q, " ROWS %s", prorows);
13729 : :
2452 tgl@sss.pgh.pa.us 13730 [ + + ]:CBC 1756 : if (strcmp(prosupport, "-") != 0)
13731 : : {
13732 : : /* We rely on regprocout to provide quoting and qualification */
13733 : 42 : appendPQExpBuffer(q, " SUPPORT %s", prosupport);
13734 : : }
13735 : :
1930 peter@eisentraut.org 13736 [ + + ]: 1756 : if (proparallel[0] != PROPARALLEL_UNSAFE)
13737 : : {
3694 rhaas@postgresql.org 13738 [ + + ]: 116 : if (proparallel[0] == PROPARALLEL_SAFE)
13739 : 111 : appendPQExpBufferStr(q, " PARALLEL SAFE");
13740 [ + - ]: 5 : else if (proparallel[0] == PROPARALLEL_RESTRICTED)
13741 : 5 : appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
3694 rhaas@postgresql.org 13742 [ # # ]:UBC 0 : else if (proparallel[0] != PROPARALLEL_UNSAFE)
1298 tgl@sss.pgh.pa.us 13743 : 0 : pg_fatal("unrecognized proparallel value for function \"%s\"",
13744 : : finfo->dobj.name);
13745 : : }
13746 : :
1160 drowley@postgresql.o 13747 [ + + ]:CBC 1791 : for (int i = 0; i < nconfigitems; i++)
13748 : : {
13749 : : /* we feel free to scribble on configitems[] here */
6629 tgl@sss.pgh.pa.us 13750 : 35 : char *configitem = configitems[i];
13751 : : char *pos;
13752 : :
13753 : 35 : pos = strchr(configitem, '=');
13754 [ - + ]: 35 : if (pos == NULL)
6629 tgl@sss.pgh.pa.us 13755 :UBC 0 : continue;
6629 tgl@sss.pgh.pa.us 13756 :CBC 35 : *pos++ = '\0';
13757 : 35 : appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
13758 : :
13759 : : /*
13760 : : * Variables that are marked GUC_LIST_QUOTE were already fully quoted
13761 : : * by flatten_set_variable_args() before they were put into the
13762 : : * proconfig array. However, because the quoting rules used there
13763 : : * aren't exactly like SQL's, we have to break the list value apart
13764 : : * and then quote the elements as string literals. (The elements may
13765 : : * be double-quoted as-is, but we can't just feed them to the SQL
13766 : : * parser; it would do the wrong thing with elements that are
13767 : : * zero-length or longer than NAMEDATALEN.)
13768 : : *
13769 : : * Variables that are not so marked should just be emitted as simple
13770 : : * string literals. If the variable is not known to
13771 : : * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
13772 : : * to use GUC_LIST_QUOTE for extension variables.
13773 : : */
2777 13774 [ + + ]: 35 : if (variable_is_guc_list_quote(configitem))
13775 : : {
13776 : : char **namelist;
13777 : : char **nameptr;
13778 : :
13779 : : /* Parse string into list of identifiers */
13780 : : /* this shouldn't fail really */
2645 13781 [ + - ]: 10 : if (SplitGUCList(pos, ',', &namelist))
13782 : : {
13783 [ + + ]: 35 : for (nameptr = namelist; *nameptr; nameptr++)
13784 : : {
13785 [ + + ]: 25 : if (nameptr != namelist)
13786 : 15 : appendPQExpBufferStr(q, ", ");
13787 : 25 : appendStringLiteralAH(q, *nameptr, fout);
13788 : : }
13789 : : }
13790 : 10 : pg_free(namelist);
13791 : : }
13792 : : else
6629 13793 : 25 : appendStringLiteralAH(q, pos, fout);
13794 : : }
13795 : :
6327 heikki.linnakangas@i 13796 : 1756 : appendPQExpBuffer(q, "\n %s;\n", asPart->data);
13797 : :
2056 alvherre@alvh.no-ip. 13798 : 1756 : append_depends_on_extension(fout, q, &finfo->dobj,
13799 : : "pg_catalog.pg_proc", keyword,
13800 : : qual_funcsig);
13801 : :
4031 13802 [ + + ]: 1756 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 13803 : 293 : binary_upgrade_extension_member(q, &finfo->dobj,
13804 : : keyword, funcsig,
13805 : 293 : finfo->dobj.namespace->dobj.name);
13806 : :
3491 sfrost@snowman.net 13807 [ + + ]: 1756 : if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13808 : 1660 : ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 13809 [ + + ]: 1660 : ARCHIVE_OPTS(.tag = funcsig_tag,
13810 : : .namespace = finfo->dobj.namespace->dobj.name,
13811 : : .owner = finfo->rolname,
13812 : : .description = keyword,
13813 : : .section = finfo->postponed_def ?
13814 : : SECTION_POST_DATA : SECTION_PRE_DATA,
13815 : : .createStmt = q->data,
13816 : : .dropStmt = delqry->data));
13817 : :
13818 : : /* Dump Function Comments and Security Labels */
3491 sfrost@snowman.net 13819 [ + + ]: 1756 : if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 13820 : 9 : dumpComment(fout, keyword, funcsig,
3491 sfrost@snowman.net 13821 : 9 : finfo->dobj.namespace->dobj.name, finfo->rolname,
13822 : 9 : finfo->dobj.catId, 0, finfo->dobj.dumpId);
13823 : :
13824 [ - + ]: 1756 : if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 13825 :UBC 0 : dumpSecLabel(fout, keyword, funcsig,
3491 sfrost@snowman.net 13826 : 0 : finfo->dobj.namespace->dobj.name, finfo->rolname,
13827 : 0 : finfo->dobj.catId, 0, finfo->dobj.dumpId);
13828 : :
3491 sfrost@snowman.net 13829 [ + + ]:CBC 1756 : if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
1934 tgl@sss.pgh.pa.us 13830 : 100 : dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
13831 : : funcsig, NULL,
3491 sfrost@snowman.net 13832 : 100 : finfo->dobj.namespace->dobj.name,
574 tgl@sss.pgh.pa.us 13833 : 100 : NULL, finfo->rolname, &finfo->dacl);
13834 : :
8571 13835 : 1756 : PQclear(res);
13836 : :
13837 : 1756 : destroyPQExpBuffer(query);
8851 13838 : 1756 : destroyPQExpBuffer(q);
13839 : 1756 : destroyPQExpBuffer(delqry);
13840 : 1756 : destroyPQExpBuffer(asPart);
8562 peter_e@gmx.net 13841 : 1756 : free(funcsig);
1229 peter@eisentraut.org 13842 : 1756 : free(funcfullsig);
8516 bruce@momjian.us 13843 : 1756 : free(funcsig_tag);
1464 tgl@sss.pgh.pa.us 13844 : 1756 : free(qual_funcsig);
1229 peter@eisentraut.org 13845 : 1756 : free(configitems);
13846 : : }
13847 : :
13848 : :
13849 : : /*
13850 : : * Dump a user-defined cast
13851 : : */
13852 : : static void
1720 13853 : 67 : dumpCast(Archive *fout, const CastInfo *cast)
13854 : : {
3575 tgl@sss.pgh.pa.us 13855 : 67 : DumpOptions *dopt = fout->dopt;
13856 : : PQExpBuffer defqry;
13857 : : PQExpBuffer delqry;
13858 : : PQExpBuffer labelq;
13859 : : PQExpBuffer castargs;
7996 13860 : 67 : FuncInfo *funcInfo = NULL;
13861 : : const char *sourceType;
13862 : : const char *targetType;
13863 : :
13864 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 13865 [ + + ]: 67 : if (!dopt->dumpSchema)
7996 tgl@sss.pgh.pa.us 13866 : 6 : return;
13867 : :
13868 : : /* Cannot dump if we don't have the cast function's info */
13869 [ + + ]: 61 : if (OidIsValid(cast->castfunc))
13870 : : {
13871 : 36 : funcInfo = findFuncByOid(cast->castfunc);
13872 [ - + ]: 36 : if (funcInfo == NULL)
1298 tgl@sss.pgh.pa.us 13873 :UBC 0 : pg_fatal("could not find function definition for function with OID %u",
13874 : : cast->castfunc);
13875 : : }
13876 : :
7996 tgl@sss.pgh.pa.us 13877 :CBC 61 : defqry = createPQExpBuffer();
13878 : 61 : delqry = createPQExpBuffer();
5374 13879 : 61 : labelq = createPQExpBuffer();
2800 13880 : 61 : castargs = createPQExpBuffer();
13881 : :
3770 heikki.linnakangas@i 13882 : 61 : sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
13883 : 61 : targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
7996 tgl@sss.pgh.pa.us 13884 : 61 : appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
13885 : : sourceType, targetType);
13886 : :
13887 : 61 : appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
13888 : : sourceType, targetType);
13889 : :
5982 bruce@momjian.us 13890 [ + - + - ]: 61 : switch (cast->castmethod)
13891 : : {
6205 heikki.linnakangas@i 13892 : 25 : case COERCION_METHOD_BINARY:
4361 13893 : 25 : appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
6205 13894 : 25 : break;
6205 heikki.linnakangas@i 13895 :UBC 0 : case COERCION_METHOD_INOUT:
4361 13896 : 0 : appendPQExpBufferStr(defqry, "WITH INOUT");
6205 13897 : 0 : break;
6205 heikki.linnakangas@i 13898 :CBC 36 : case COERCION_METHOD_FUNCTION:
4973 peter_e@gmx.net 13899 [ + - ]: 36 : if (funcInfo)
13900 : : {
4887 bruce@momjian.us 13901 : 36 : char *fsig = format_function_signature(fout, funcInfo, true);
13902 : :
13903 : : /*
13904 : : * Always qualify the function name (format_function_signature
13905 : : * won't qualify it).
13906 : : */
4973 peter_e@gmx.net 13907 : 36 : appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
3050 tgl@sss.pgh.pa.us 13908 : 36 : fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
4973 peter_e@gmx.net 13909 : 36 : free(fsig);
13910 : : }
13911 : : else
2401 peter@eisentraut.org 13912 :UBC 0 : pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
6205 heikki.linnakangas@i 13913 :CBC 36 : break;
6205 heikki.linnakangas@i 13914 :UBC 0 : default:
2401 peter@eisentraut.org 13915 : 0 : pg_log_warning("bogus value in pg_cast.castmethod field");
13916 : : }
13917 : :
7996 tgl@sss.pgh.pa.us 13918 [ + + ]:CBC 61 : if (cast->castcontext == 'a')
4361 heikki.linnakangas@i 13919 : 31 : appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
7996 tgl@sss.pgh.pa.us 13920 [ + + ]: 30 : else if (cast->castcontext == 'i')
4361 heikki.linnakangas@i 13921 : 10 : appendPQExpBufferStr(defqry, " AS IMPLICIT");
13922 : 61 : appendPQExpBufferStr(defqry, ";\n");
13923 : :
5374 tgl@sss.pgh.pa.us 13924 : 61 : appendPQExpBuffer(labelq, "CAST (%s AS %s)",
13925 : : sourceType, targetType);
13926 : :
2800 13927 : 61 : appendPQExpBuffer(castargs, "(%s AS %s)",
13928 : : sourceType, targetType);
13929 : :
4031 alvherre@alvh.no-ip. 13930 [ + + ]: 61 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 13931 : 7 : binary_upgrade_extension_member(defqry, &cast->dobj,
13932 : 7 : "CAST", castargs->data, NULL);
13933 : :
3491 sfrost@snowman.net 13934 [ + - ]: 61 : if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
13935 : 61 : ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
2460 alvherre@alvh.no-ip. 13936 : 61 : ARCHIVE_OPTS(.tag = labelq->data,
13937 : : .description = "CAST",
13938 : : .section = SECTION_PRE_DATA,
13939 : : .createStmt = defqry->data,
13940 : : .dropStmt = delqry->data));
13941 : :
13942 : : /* Dump Cast Comments */
3491 sfrost@snowman.net 13943 [ - + ]: 61 : if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 13944 :UBC 0 : dumpComment(fout, "CAST", castargs->data,
13945 : : NULL, "",
3491 sfrost@snowman.net 13946 : 0 : cast->dobj.catId, 0, cast->dobj.dumpId);
13947 : :
8502 peter_e@gmx.net 13948 :CBC 61 : destroyPQExpBuffer(defqry);
13949 : 61 : destroyPQExpBuffer(delqry);
5374 tgl@sss.pgh.pa.us 13950 : 61 : destroyPQExpBuffer(labelq);
2800 13951 : 61 : destroyPQExpBuffer(castargs);
13952 : : }
13953 : :
13954 : : /*
13955 : : * Dump a transform
13956 : : */
13957 : : static void
1720 peter@eisentraut.org 13958 : 42 : dumpTransform(Archive *fout, const TransformInfo *transform)
13959 : : {
3575 tgl@sss.pgh.pa.us 13960 : 42 : DumpOptions *dopt = fout->dopt;
13961 : : PQExpBuffer defqry;
13962 : : PQExpBuffer delqry;
13963 : : PQExpBuffer labelq;
13964 : : PQExpBuffer transformargs;
3837 peter_e@gmx.net 13965 : 42 : FuncInfo *fromsqlFuncInfo = NULL;
13966 : 42 : FuncInfo *tosqlFuncInfo = NULL;
13967 : : char *lanname;
13968 : : const char *transformType;
13969 : :
13970 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 13971 [ + + ]: 42 : if (!dopt->dumpSchema)
3837 peter_e@gmx.net 13972 : 6 : return;
13973 : :
13974 : : /* Cannot dump if we don't have the transform functions' info */
13975 [ + - ]: 36 : if (OidIsValid(transform->trffromsql))
13976 : : {
13977 : 36 : fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
13978 [ - + ]: 36 : if (fromsqlFuncInfo == NULL)
1298 tgl@sss.pgh.pa.us 13979 :UBC 0 : pg_fatal("could not find function definition for function with OID %u",
13980 : : transform->trffromsql);
13981 : : }
3837 peter_e@gmx.net 13982 [ + - ]:CBC 36 : if (OidIsValid(transform->trftosql))
13983 : : {
13984 : 36 : tosqlFuncInfo = findFuncByOid(transform->trftosql);
13985 [ - + ]: 36 : if (tosqlFuncInfo == NULL)
1298 tgl@sss.pgh.pa.us 13986 :UBC 0 : pg_fatal("could not find function definition for function with OID %u",
13987 : : transform->trftosql);
13988 : : }
13989 : :
3837 peter_e@gmx.net 13990 :CBC 36 : defqry = createPQExpBuffer();
13991 : 36 : delqry = createPQExpBuffer();
13992 : 36 : labelq = createPQExpBuffer();
2800 tgl@sss.pgh.pa.us 13993 : 36 : transformargs = createPQExpBuffer();
13994 : :
3837 peter_e@gmx.net 13995 : 36 : lanname = get_language_name(fout, transform->trflang);
3770 heikki.linnakangas@i 13996 : 36 : transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
13997 : :
3837 peter_e@gmx.net 13998 : 36 : appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
13999 : : transformType, lanname);
14000 : :
14001 : 36 : appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
14002 : : transformType, lanname);
14003 : :
14004 [ - + - - ]: 36 : if (!transform->trffromsql && !transform->trftosql)
2401 peter@eisentraut.org 14005 :UBC 0 : pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
14006 : :
3837 peter_e@gmx.net 14007 [ + - ]:CBC 36 : if (transform->trffromsql)
14008 : : {
14009 [ + - ]: 36 : if (fromsqlFuncInfo)
14010 : : {
14011 : 36 : char *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
14012 : :
14013 : : /*
14014 : : * Always qualify the function name (format_function_signature
14015 : : * won't qualify it).
14016 : : */
14017 : 36 : appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
3050 tgl@sss.pgh.pa.us 14018 : 36 : fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
3837 peter_e@gmx.net 14019 : 36 : free(fsig);
14020 : : }
14021 : : else
2401 peter@eisentraut.org 14022 :UBC 0 : pg_log_warning("bogus value in pg_transform.trffromsql field");
14023 : : }
14024 : :
3837 peter_e@gmx.net 14025 [ + - ]:CBC 36 : if (transform->trftosql)
14026 : : {
14027 [ + - ]: 36 : if (transform->trffromsql)
2307 drowley@postgresql.o 14028 : 36 : appendPQExpBufferStr(defqry, ", ");
14029 : :
3837 peter_e@gmx.net 14030 [ + - ]: 36 : if (tosqlFuncInfo)
14031 : : {
14032 : 36 : char *fsig = format_function_signature(fout, tosqlFuncInfo, true);
14033 : :
14034 : : /*
14035 : : * Always qualify the function name (format_function_signature
14036 : : * won't qualify it).
14037 : : */
14038 : 36 : appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
3050 tgl@sss.pgh.pa.us 14039 : 36 : fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
3837 peter_e@gmx.net 14040 : 36 : free(fsig);
14041 : : }
14042 : : else
2401 peter@eisentraut.org 14043 :UBC 0 : pg_log_warning("bogus value in pg_transform.trftosql field");
14044 : : }
14045 : :
2307 drowley@postgresql.o 14046 :CBC 36 : appendPQExpBufferStr(defqry, ");\n");
14047 : :
3837 peter_e@gmx.net 14048 : 36 : appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
14049 : : transformType, lanname);
14050 : :
2800 tgl@sss.pgh.pa.us 14051 : 36 : appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
14052 : : transformType, lanname);
14053 : :
3837 peter_e@gmx.net 14054 [ + + ]: 36 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 14055 : 2 : binary_upgrade_extension_member(defqry, &transform->dobj,
14056 : 2 : "TRANSFORM", transformargs->data, NULL);
14057 : :
3491 sfrost@snowman.net 14058 [ + - ]: 36 : if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
14059 : 36 : ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
2460 alvherre@alvh.no-ip. 14060 : 36 : ARCHIVE_OPTS(.tag = labelq->data,
14061 : : .description = "TRANSFORM",
14062 : : .section = SECTION_PRE_DATA,
14063 : : .createStmt = defqry->data,
14064 : : .dropStmt = delqry->data,
14065 : : .deps = transform->dobj.dependencies,
14066 : : .nDeps = transform->dobj.nDeps));
14067 : :
14068 : : /* Dump Transform Comments */
3491 sfrost@snowman.net 14069 [ - + ]: 36 : if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 14070 :UBC 0 : dumpComment(fout, "TRANSFORM", transformargs->data,
14071 : : NULL, "",
3491 sfrost@snowman.net 14072 : 0 : transform->dobj.catId, 0, transform->dobj.dumpId);
14073 : :
3837 peter_e@gmx.net 14074 :CBC 36 : free(lanname);
14075 : 36 : destroyPQExpBuffer(defqry);
14076 : 36 : destroyPQExpBuffer(delqry);
14077 : 36 : destroyPQExpBuffer(labelq);
2800 tgl@sss.pgh.pa.us 14078 : 36 : destroyPQExpBuffer(transformargs);
14079 : : }
14080 : :
14081 : :
14082 : : /*
14083 : : * dumpOpr
14084 : : * write out a single operator definition
14085 : : */
14086 : : static void
1720 peter@eisentraut.org 14087 : 2504 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
14088 : : {
3575 tgl@sss.pgh.pa.us 14089 : 2504 : DumpOptions *dopt = fout->dopt;
14090 : : PQExpBuffer query;
14091 : : PQExpBuffer q;
14092 : : PQExpBuffer delq;
14093 : : PQExpBuffer oprid;
14094 : : PQExpBuffer details;
14095 : : PGresult *res;
14096 : : int i_oprkind;
14097 : : int i_oprcode;
14098 : : int i_oprleft;
14099 : : int i_oprright;
14100 : : int i_oprcom;
14101 : : int i_oprnegate;
14102 : : int i_oprrest;
14103 : : int i_oprjoin;
14104 : : int i_oprcanmerge;
14105 : : int i_oprcanhash;
14106 : : char *oprkind;
14107 : : char *oprcode;
14108 : : char *oprleft;
14109 : : char *oprright;
14110 : : char *oprcom;
14111 : : char *oprnegate;
14112 : : char *oprrest;
14113 : : char *oprjoin;
14114 : : char *oprcanmerge;
14115 : : char *oprcanhash;
14116 : : char *oprregproc;
14117 : : char *oprref;
14118 : :
14119 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 14120 [ + + ]: 2504 : if (!dopt->dumpSchema)
7996 tgl@sss.pgh.pa.us 14121 : 6 : return;
14122 : :
14123 : : /*
14124 : : * some operators are invalid because they were the result of user
14125 : : * defining operators before commutators exist
14126 : : */
14127 [ + + ]: 2498 : if (!OidIsValid(oprinfo->oprcode))
14128 : 14 : return;
14129 : :
14130 : 2484 : query = createPQExpBuffer();
14131 : 2484 : q = createPQExpBuffer();
14132 : 2484 : delq = createPQExpBuffer();
14133 : 2484 : oprid = createPQExpBuffer();
14134 : 2484 : details = createPQExpBuffer();
14135 : :
1421 14136 [ + + ]: 2484 : if (!fout->is_prepared[PREPQUERY_DUMPOPR])
14137 : : {
14138 : : /* Set up query for operator-specific details */
14139 : 40 : appendPQExpBufferStr(query,
14140 : : "PREPARE dumpOpr(pg_catalog.oid) AS\n"
14141 : : "SELECT oprkind, "
14142 : : "oprcode::pg_catalog.regprocedure, "
14143 : : "oprleft::pg_catalog.regtype, "
14144 : : "oprright::pg_catalog.regtype, "
14145 : : "oprcom, "
14146 : : "oprnegate, "
14147 : : "oprrest::pg_catalog.regprocedure, "
14148 : : "oprjoin::pg_catalog.regprocedure, "
14149 : : "oprcanmerge, oprcanhash "
14150 : : "FROM pg_catalog.pg_operator "
14151 : : "WHERE oid = $1");
14152 : :
14153 : 40 : ExecuteSqlStatement(fout, query->data);
14154 : :
14155 : 40 : fout->is_prepared[PREPQUERY_DUMPOPR] = true;
14156 : : }
14157 : :
14158 : 2484 : printfPQExpBuffer(query,
14159 : : "EXECUTE dumpOpr('%u')",
14160 : 2484 : oprinfo->dobj.catId.oid);
14161 : :
5002 rhaas@postgresql.org 14162 : 2484 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
14163 : :
8571 tgl@sss.pgh.pa.us 14164 : 2484 : i_oprkind = PQfnumber(res, "oprkind");
14165 : 2484 : i_oprcode = PQfnumber(res, "oprcode");
14166 : 2484 : i_oprleft = PQfnumber(res, "oprleft");
14167 : 2484 : i_oprright = PQfnumber(res, "oprright");
14168 : 2484 : i_oprcom = PQfnumber(res, "oprcom");
14169 : 2484 : i_oprnegate = PQfnumber(res, "oprnegate");
14170 : 2484 : i_oprrest = PQfnumber(res, "oprrest");
14171 : 2484 : i_oprjoin = PQfnumber(res, "oprjoin");
6883 14172 : 2484 : i_oprcanmerge = PQfnumber(res, "oprcanmerge");
8571 14173 : 2484 : i_oprcanhash = PQfnumber(res, "oprcanhash");
14174 : :
14175 : 2484 : oprkind = PQgetvalue(res, 0, i_oprkind);
14176 : 2484 : oprcode = PQgetvalue(res, 0, i_oprcode);
14177 : 2484 : oprleft = PQgetvalue(res, 0, i_oprleft);
14178 : 2484 : oprright = PQgetvalue(res, 0, i_oprright);
14179 : 2484 : oprcom = PQgetvalue(res, 0, i_oprcom);
14180 : 2484 : oprnegate = PQgetvalue(res, 0, i_oprnegate);
14181 : 2484 : oprrest = PQgetvalue(res, 0, i_oprrest);
14182 : 2484 : oprjoin = PQgetvalue(res, 0, i_oprjoin);
6883 14183 : 2484 : oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
8571 14184 : 2484 : oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
14185 : :
14186 : : /* In PG14 upwards postfix operator support does not exist anymore. */
1866 14187 [ - + ]: 2484 : if (strcmp(oprkind, "r") == 0)
1866 tgl@sss.pgh.pa.us 14188 :UBC 0 : pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
14189 : : oprcode);
14190 : :
1889 peter@eisentraut.org 14191 :CBC 2484 : oprregproc = convertRegProcReference(oprcode);
4258 sfrost@snowman.net 14192 [ + - ]: 2484 : if (oprregproc)
14193 : : {
2630 peter_e@gmx.net 14194 : 2484 : appendPQExpBuffer(details, " FUNCTION = %s", oprregproc);
4258 sfrost@snowman.net 14195 : 2484 : free(oprregproc);
14196 : : }
14197 : :
8571 tgl@sss.pgh.pa.us 14198 : 2484 : appendPQExpBuffer(oprid, "%s (",
7908 14199 : 2484 : oprinfo->dobj.name);
14200 : :
14201 : : /*
14202 : : * right unary means there's a left arg and left unary means there's a
14203 : : * right arg. (Although the "r" case is dead code for PG14 and later,
14204 : : * continue to support it in case we're dumping from an old server.)
14205 : : */
8571 14206 [ + - ]: 2484 : if (strcmp(oprkind, "r") == 0 ||
14207 [ + + ]: 2484 : strcmp(oprkind, "b") == 0)
14208 : : {
3302 14209 : 2341 : appendPQExpBuffer(details, ",\n LEFTARG = %s", oprleft);
14210 : 2341 : appendPQExpBufferStr(oprid, oprleft);
14211 : : }
14212 : : else
4361 heikki.linnakangas@i 14213 : 143 : appendPQExpBufferStr(oprid, "NONE");
14214 : :
8571 tgl@sss.pgh.pa.us 14215 [ + + ]: 2484 : if (strcmp(oprkind, "l") == 0 ||
14216 [ + - ]: 2341 : strcmp(oprkind, "b") == 0)
14217 : : {
3302 14218 : 2484 : appendPQExpBuffer(details, ",\n RIGHTARG = %s", oprright);
14219 : 2484 : appendPQExpBuffer(oprid, ", %s)", oprright);
14220 : : }
14221 : : else
4361 heikki.linnakangas@i 14222 :UBC 0 : appendPQExpBufferStr(oprid, ", NONE)");
14223 : :
1889 peter@eisentraut.org 14224 :CBC 2484 : oprref = getFormattedOperatorName(oprcom);
4258 sfrost@snowman.net 14225 [ + + ]: 2484 : if (oprref)
14226 : : {
14227 : 1661 : appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
14228 : 1661 : free(oprref);
14229 : : }
14230 : :
1889 peter@eisentraut.org 14231 : 2484 : oprref = getFormattedOperatorName(oprnegate);
4258 sfrost@snowman.net 14232 [ + + ]: 2484 : if (oprref)
14233 : : {
14234 : 1163 : appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
14235 : 1163 : free(oprref);
14236 : : }
14237 : :
6883 tgl@sss.pgh.pa.us 14238 [ + + ]: 2484 : if (strcmp(oprcanmerge, "t") == 0)
4361 heikki.linnakangas@i 14239 : 185 : appendPQExpBufferStr(details, ",\n MERGES");
14240 : :
8571 tgl@sss.pgh.pa.us 14241 [ + + ]: 2484 : if (strcmp(oprcanhash, "t") == 0)
4361 heikki.linnakangas@i 14242 : 138 : appendPQExpBufferStr(details, ",\n HASHES");
14243 : :
1889 peter@eisentraut.org 14244 : 2484 : oprregproc = convertRegProcReference(oprrest);
4258 sfrost@snowman.net 14245 [ + + ]: 2484 : if (oprregproc)
14246 : : {
14247 : 1514 : appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
14248 : 1514 : free(oprregproc);
14249 : : }
14250 : :
1889 peter@eisentraut.org 14251 : 2484 : oprregproc = convertRegProcReference(oprjoin);
4258 sfrost@snowman.net 14252 [ + + ]: 2484 : if (oprregproc)
14253 : : {
14254 : 1514 : appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
14255 : 1514 : free(oprregproc);
14256 : : }
14257 : :
8553 tgl@sss.pgh.pa.us 14258 : 2484 : appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
7908 14259 : 2484 : fmtId(oprinfo->dobj.namespace->dobj.name),
14260 : : oprid->data);
14261 : :
2800 14262 : 2484 : appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
14263 : 2484 : fmtId(oprinfo->dobj.namespace->dobj.name),
7908 14264 : 2484 : oprinfo->dobj.name, details->data);
14265 : :
4031 alvherre@alvh.no-ip. 14266 [ + + ]: 2484 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 14267 : 12 : binary_upgrade_extension_member(q, &oprinfo->dobj,
14268 : 12 : "OPERATOR", oprid->data,
14269 : 12 : oprinfo->dobj.namespace->dobj.name);
14270 : :
3491 sfrost@snowman.net 14271 [ + - ]: 2484 : if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14272 : 2484 : ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 14273 : 2484 : ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
14274 : : .namespace = oprinfo->dobj.namespace->dobj.name,
14275 : : .owner = oprinfo->rolname,
14276 : : .description = "OPERATOR",
14277 : : .section = SECTION_PRE_DATA,
14278 : : .createStmt = q->data,
14279 : : .dropStmt = delq->data));
14280 : :
14281 : : /* Dump Operator Comments */
3491 sfrost@snowman.net 14282 [ + + ]: 2484 : if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 14283 : 2397 : dumpComment(fout, "OPERATOR", oprid->data,
3491 sfrost@snowman.net 14284 : 2397 : oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
14285 : 2397 : oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
14286 : :
8571 tgl@sss.pgh.pa.us 14287 : 2484 : PQclear(res);
14288 : :
14289 : 2484 : destroyPQExpBuffer(query);
14290 : 2484 : destroyPQExpBuffer(q);
14291 : 2484 : destroyPQExpBuffer(delq);
14292 : 2484 : destroyPQExpBuffer(oprid);
14293 : 2484 : destroyPQExpBuffer(details);
14294 : : }
14295 : :
14296 : : /*
14297 : : * Convert a function reference obtained from pg_operator
14298 : : *
14299 : : * Returns allocated string of what to print, or NULL if function references
14300 : : * is InvalidOid. Returned string is expected to be free'd by the caller.
14301 : : *
14302 : : * The input is a REGPROCEDURE display; we have to strip the argument-types
14303 : : * part.
14304 : : */
14305 : : static char *
1889 peter@eisentraut.org 14306 : 7452 : convertRegProcReference(const char *proc)
14307 : : {
14308 : : char *name;
14309 : : char *paren;
14310 : : bool inquote;
14311 : :
14312 : : /* In all cases "-" means a null reference */
8571 tgl@sss.pgh.pa.us 14313 [ + + ]: 7452 : if (strcmp(proc, "-") == 0)
14314 : 1940 : return NULL;
14315 : :
3302 14316 : 5512 : name = pg_strdup(proc);
14317 : : /* find non-double-quoted left paren */
14318 : 5512 : inquote = false;
14319 [ + - ]: 66432 : for (paren = name; *paren; paren++)
14320 : : {
14321 [ + + + - ]: 66432 : if (*paren == '(' && !inquote)
14322 : : {
14323 : 5512 : *paren = '\0';
14324 : 5512 : break;
14325 : : }
14326 [ + + ]: 60920 : if (*paren == '"')
14327 : 50 : inquote = !inquote;
14328 : : }
14329 : 5512 : return name;
14330 : : }
14331 : :
14332 : : /*
14333 : : * getFormattedOperatorName - retrieve the operator name for the
14334 : : * given operator OID (presented in string form).
14335 : : *
14336 : : * Returns an allocated string, or NULL if the given OID is invalid.
14337 : : * Caller is responsible for free'ing result string.
14338 : : *
14339 : : * What we produce has the format "OPERATOR(schema.oprname)". This is only
14340 : : * useful in commands where the operator's argument types can be inferred from
14341 : : * context. We always schema-qualify the name, though. The predecessor to
14342 : : * this code tried to skip the schema qualification if possible, but that led
14343 : : * to wrong results in corner cases, such as if an operator and its negator
14344 : : * are in different schemas.
14345 : : */
14346 : : static char *
1889 peter@eisentraut.org 14347 : 5253 : getFormattedOperatorName(const char *oproid)
14348 : : {
14349 : : OprInfo *oprInfo;
14350 : :
14351 : : /* In all cases "0" means a null reference */
2800 tgl@sss.pgh.pa.us 14352 [ + + ]: 5253 : if (strcmp(oproid, "0") == 0)
8571 14353 : 2429 : return NULL;
14354 : :
2800 14355 : 2824 : oprInfo = findOprByOid(atooid(oproid));
14356 [ - + ]: 2824 : if (oprInfo == NULL)
14357 : : {
2401 peter@eisentraut.org 14358 :UBC 0 : pg_log_warning("could not find operator with OID %s",
14359 : : oproid);
2800 tgl@sss.pgh.pa.us 14360 : 0 : return NULL;
14361 : : }
14362 : :
2800 tgl@sss.pgh.pa.us 14363 :CBC 2824 : return psprintf("OPERATOR(%s.%s)",
14364 : 2824 : fmtId(oprInfo->dobj.namespace->dobj.name),
14365 : : oprInfo->dobj.name);
14366 : : }
14367 : :
14368 : : /*
14369 : : * Convert a function OID obtained from pg_ts_parser or pg_ts_template
14370 : : *
14371 : : * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
14372 : : * argument lists of these functions are predetermined. Note that the
14373 : : * caller should ensure we are in the proper schema, because the results
14374 : : * are search path dependent!
14375 : : */
14376 : : static char *
5011 rhaas@postgresql.org 14377 : 205 : convertTSFunction(Archive *fout, Oid funcOid)
14378 : : {
14379 : : char *result;
14380 : : char query[128];
14381 : : PGresult *res;
14382 : :
6642 tgl@sss.pgh.pa.us 14383 : 205 : snprintf(query, sizeof(query),
14384 : : "SELECT '%u'::pg_catalog.regproc", funcOid);
5002 rhaas@postgresql.org 14385 : 205 : res = ExecuteSqlQueryForSingleRow(fout, query);
14386 : :
5085 bruce@momjian.us 14387 : 205 : result = pg_strdup(PQgetvalue(res, 0, 0));
14388 : :
6642 tgl@sss.pgh.pa.us 14389 : 205 : PQclear(res);
14390 : :
14391 : 205 : return result;
14392 : : }
14393 : :
14394 : : /*
14395 : : * dumpAccessMethod
14396 : : * write out a single access method definition
14397 : : */
14398 : : static void
1720 peter@eisentraut.org 14399 : 80 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
14400 : : {
3505 alvherre@alvh.no-ip. 14401 : 80 : DumpOptions *dopt = fout->dopt;
14402 : : PQExpBuffer q;
14403 : : PQExpBuffer delq;
14404 : : char *qamname;
14405 : :
14406 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 14407 [ + + ]: 80 : if (!dopt->dumpSchema)
3505 alvherre@alvh.no-ip. 14408 : 12 : return;
14409 : :
14410 : 68 : q = createPQExpBuffer();
14411 : 68 : delq = createPQExpBuffer();
14412 : :
14413 : 68 : qamname = pg_strdup(fmtId(aminfo->dobj.name));
14414 : :
14415 : 68 : appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
14416 : :
14417 [ + + - ]: 68 : switch (aminfo->amtype)
14418 : : {
14419 : 32 : case AMTYPE_INDEX:
2307 drowley@postgresql.o 14420 : 32 : appendPQExpBufferStr(q, "TYPE INDEX ");
3505 alvherre@alvh.no-ip. 14421 : 32 : break;
2427 andres@anarazel.de 14422 : 36 : case AMTYPE_TABLE:
2307 drowley@postgresql.o 14423 : 36 : appendPQExpBufferStr(q, "TYPE TABLE ");
2427 andres@anarazel.de 14424 : 36 : break;
3505 alvherre@alvh.no-ip. 14425 :UBC 0 : default:
2401 peter@eisentraut.org 14426 : 0 : pg_log_warning("invalid type \"%c\" of access method \"%s\"",
14427 : : aminfo->amtype, qamname);
3505 alvherre@alvh.no-ip. 14428 : 0 : destroyPQExpBuffer(q);
14429 : 0 : destroyPQExpBuffer(delq);
2800 tgl@sss.pgh.pa.us 14430 : 0 : free(qamname);
3505 alvherre@alvh.no-ip. 14431 : 0 : return;
14432 : : }
14433 : :
3505 alvherre@alvh.no-ip. 14434 :CBC 68 : appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
14435 : :
14436 : 68 : appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
14437 : : qamname);
14438 : :
3312 tgl@sss.pgh.pa.us 14439 [ + + ]: 68 : if (dopt->binary_upgrade)
2800 14440 : 4 : binary_upgrade_extension_member(q, &aminfo->dobj,
14441 : : "ACCESS METHOD", qamname, NULL);
14442 : :
3429 sfrost@snowman.net 14443 [ + - ]: 68 : if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14444 : 68 : ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 14445 : 68 : ARCHIVE_OPTS(.tag = aminfo->dobj.name,
14446 : : .description = "ACCESS METHOD",
14447 : : .section = SECTION_PRE_DATA,
14448 : : .createStmt = q->data,
14449 : : .dropStmt = delq->data));
14450 : :
14451 : : /* Dump Access Method Comments */
3429 sfrost@snowman.net 14452 [ - + ]: 68 : if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 14453 :UBC 0 : dumpComment(fout, "ACCESS METHOD", qamname,
14454 : : NULL, "",
3429 sfrost@snowman.net 14455 : 0 : aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
14456 : :
3505 alvherre@alvh.no-ip. 14457 :CBC 68 : destroyPQExpBuffer(q);
14458 : 68 : destroyPQExpBuffer(delq);
2800 tgl@sss.pgh.pa.us 14459 : 68 : free(qamname);
14460 : : }
14461 : :
14462 : : /*
14463 : : * dumpOpclass
14464 : : * write out a single operator class definition
14465 : : */
14466 : : static void
1720 peter@eisentraut.org 14467 : 660 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
14468 : : {
3575 tgl@sss.pgh.pa.us 14469 : 660 : DumpOptions *dopt = fout->dopt;
14470 : : PQExpBuffer query;
14471 : : PQExpBuffer q;
14472 : : PQExpBuffer delq;
14473 : : PQExpBuffer nameusing;
14474 : : PGresult *res;
14475 : : int ntups;
14476 : : int i_opcintype;
14477 : : int i_opckeytype;
14478 : : int i_opcdefault;
14479 : : int i_opcfamily;
14480 : : int i_opcfamilyname;
14481 : : int i_opcfamilynsp;
14482 : : int i_amname;
14483 : : int i_amopstrategy;
14484 : : int i_amopopr;
14485 : : int i_sortfamily;
14486 : : int i_sortfamilynsp;
14487 : : int i_amprocnum;
14488 : : int i_amproc;
14489 : : int i_amproclefttype;
14490 : : int i_amprocrighttype;
14491 : : char *opcintype;
14492 : : char *opckeytype;
14493 : : char *opcdefault;
14494 : : char *opcfamily;
14495 : : char *opcfamilyname;
14496 : : char *opcfamilynsp;
14497 : : char *amname;
14498 : : char *amopstrategy;
14499 : : char *amopopr;
14500 : : char *sortfamily;
14501 : : char *sortfamilynsp;
14502 : : char *amprocnum;
14503 : : char *amproc;
14504 : : char *amproclefttype;
14505 : : char *amprocrighttype;
14506 : : bool needComma;
14507 : : int i;
14508 : :
14509 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 14510 [ + + ]: 660 : if (!dopt->dumpSchema)
7996 tgl@sss.pgh.pa.us 14511 : 18 : return;
14512 : :
14513 : 642 : query = createPQExpBuffer();
14514 : 642 : q = createPQExpBuffer();
14515 : 642 : delq = createPQExpBuffer();
2800 14516 : 642 : nameusing = createPQExpBuffer();
14517 : :
14518 : : /* Get additional fields from the pg_opclass row */
1413 14519 : 642 : appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
14520 : : "opckeytype::pg_catalog.regtype, "
14521 : : "opcdefault, opcfamily, "
14522 : : "opfname AS opcfamilyname, "
14523 : : "nspname AS opcfamilynsp, "
14524 : : "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
14525 : : "FROM pg_catalog.pg_opclass c "
14526 : : "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
14527 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14528 : : "WHERE c.oid = '%u'::pg_catalog.oid",
14529 : 642 : opcinfo->dobj.catId.oid);
14530 : :
5002 rhaas@postgresql.org 14531 : 642 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
14532 : :
8490 tgl@sss.pgh.pa.us 14533 : 642 : i_opcintype = PQfnumber(res, "opcintype");
14534 : 642 : i_opckeytype = PQfnumber(res, "opckeytype");
14535 : 642 : i_opcdefault = PQfnumber(res, "opcdefault");
6852 14536 : 642 : i_opcfamily = PQfnumber(res, "opcfamily");
5451 14537 : 642 : i_opcfamilyname = PQfnumber(res, "opcfamilyname");
6852 14538 : 642 : i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
8490 14539 : 642 : i_amname = PQfnumber(res, "amname");
14540 : :
14541 : : /* opcintype may still be needed after we PQclear res */
3076 14542 : 642 : opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
8490 14543 : 642 : opckeytype = PQgetvalue(res, 0, i_opckeytype);
14544 : 642 : opcdefault = PQgetvalue(res, 0, i_opcdefault);
14545 : : /* opcfamily will still be needed after we PQclear res */
5085 bruce@momjian.us 14546 : 642 : opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
5451 tgl@sss.pgh.pa.us 14547 : 642 : opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
6852 14548 : 642 : opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
14549 : : /* amname will still be needed after we PQclear res */
5085 bruce@momjian.us 14550 : 642 : amname = pg_strdup(PQgetvalue(res, 0, i_amname));
14551 : :
8490 tgl@sss.pgh.pa.us 14552 : 642 : appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
2800 14553 : 642 : fmtQualifiedDumpable(opcinfo));
8490 14554 : 642 : appendPQExpBuffer(delq, " USING %s;\n",
14555 : : fmtId(amname));
14556 : :
14557 : : /* Build the fixed portion of the CREATE command */
8471 peter_e@gmx.net 14558 : 642 : appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
2800 tgl@sss.pgh.pa.us 14559 : 642 : fmtQualifiedDumpable(opcinfo));
8490 14560 [ + + ]: 642 : if (strcmp(opcdefault, "t") == 0)
4361 heikki.linnakangas@i 14561 : 357 : appendPQExpBufferStr(q, "DEFAULT ");
6852 tgl@sss.pgh.pa.us 14562 : 642 : appendPQExpBuffer(q, "FOR TYPE %s USING %s",
14563 : : opcintype,
14564 : : fmtId(amname));
3484 14565 [ + - ]: 642 : if (strlen(opcfamilyname) > 0)
14566 : : {
4361 heikki.linnakangas@i 14567 : 642 : appendPQExpBufferStr(q, " FAMILY ");
2800 tgl@sss.pgh.pa.us 14568 : 642 : appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
3770 heikki.linnakangas@i 14569 : 642 : appendPQExpBufferStr(q, fmtId(opcfamilyname));
14570 : : }
4361 14571 : 642 : appendPQExpBufferStr(q, " AS\n ");
14572 : :
8490 tgl@sss.pgh.pa.us 14573 : 642 : needComma = false;
14574 : :
14575 [ + + ]: 642 : if (strcmp(opckeytype, "-") != 0)
14576 : : {
8471 peter_e@gmx.net 14577 : 252 : appendPQExpBuffer(q, "STORAGE %s",
14578 : : opckeytype);
8490 tgl@sss.pgh.pa.us 14579 : 252 : needComma = true;
14580 : : }
14581 : :
14582 : 642 : PQclear(res);
14583 : :
14584 : : /*
14585 : : * Now fetch and print the OPERATOR entries (pg_amop rows).
14586 : : *
14587 : : * Print only those opfamily members that are tied to the opclass by
14588 : : * pg_depend entries.
14589 : : */
14590 : 642 : resetPQExpBuffer(query);
1413 14591 : 642 : appendPQExpBuffer(query, "SELECT amopstrategy, "
14592 : : "amopopr::pg_catalog.regoperator, "
14593 : : "opfname AS sortfamily, "
14594 : : "nspname AS sortfamilynsp "
14595 : : "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
14596 : : "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
14597 : : "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
14598 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14599 : : "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
14600 : : "AND refobjid = '%u'::pg_catalog.oid "
14601 : : "AND amopfamily = '%s'::pg_catalog.oid "
14602 : : "ORDER BY amopstrategy",
14603 : 642 : opcinfo->dobj.catId.oid,
14604 : : opcfamily);
14605 : :
5011 rhaas@postgresql.org 14606 : 642 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14607 : :
8490 tgl@sss.pgh.pa.us 14608 : 642 : ntups = PQntuples(res);
14609 : :
14610 : 642 : i_amopstrategy = PQfnumber(res, "amopstrategy");
14611 : 642 : i_amopopr = PQfnumber(res, "amopopr");
5451 14612 : 642 : i_sortfamily = PQfnumber(res, "sortfamily");
14613 : 642 : i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
14614 : :
8490 14615 [ + + ]: 844 : for (i = 0; i < ntups; i++)
14616 : : {
14617 : 202 : amopstrategy = PQgetvalue(res, i, i_amopstrategy);
14618 : 202 : amopopr = PQgetvalue(res, i, i_amopopr);
5451 14619 : 202 : sortfamily = PQgetvalue(res, i, i_sortfamily);
14620 : 202 : sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
14621 : :
8490 14622 [ + + ]: 202 : if (needComma)
4361 heikki.linnakangas@i 14623 : 128 : appendPQExpBufferStr(q, " ,\n ");
14624 : :
8471 peter_e@gmx.net 14625 : 202 : appendPQExpBuffer(q, "OPERATOR %s %s",
14626 : : amopstrategy, amopopr);
14627 : :
5451 tgl@sss.pgh.pa.us 14628 [ - + ]: 202 : if (strlen(sortfamily) > 0)
14629 : : {
4361 heikki.linnakangas@i 14630 :UBC 0 : appendPQExpBufferStr(q, " FOR ORDER BY ");
2800 tgl@sss.pgh.pa.us 14631 : 0 : appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
4361 heikki.linnakangas@i 14632 : 0 : appendPQExpBufferStr(q, fmtId(sortfamily));
14633 : : }
14634 : :
8490 tgl@sss.pgh.pa.us 14635 :CBC 202 : needComma = true;
14636 : : }
14637 : :
14638 : 642 : PQclear(res);
14639 : :
14640 : : /*
14641 : : * Now fetch and print the FUNCTION entries (pg_amproc rows).
14642 : : *
14643 : : * Print only those opfamily members that are tied to the opclass by
14644 : : * pg_depend entries.
14645 : : *
14646 : : * We print the amproclefttype/amprocrighttype even though in most cases
14647 : : * the backend could deduce the right values, because of the corner case
14648 : : * of a btree sort support function for a cross-type comparison.
14649 : : */
14650 : 642 : resetPQExpBuffer(query);
14651 : :
1413 14652 : 642 : appendPQExpBuffer(query, "SELECT amprocnum, "
14653 : : "amproc::pg_catalog.regprocedure, "
14654 : : "amproclefttype::pg_catalog.regtype, "
14655 : : "amprocrighttype::pg_catalog.regtype "
14656 : : "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
14657 : : "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
14658 : : "AND refobjid = '%u'::pg_catalog.oid "
14659 : : "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
14660 : : "AND objid = ap.oid "
14661 : : "ORDER BY amprocnum",
14662 : 642 : opcinfo->dobj.catId.oid);
14663 : :
5011 rhaas@postgresql.org 14664 : 642 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14665 : :
8490 tgl@sss.pgh.pa.us 14666 : 642 : ntups = PQntuples(res);
14667 : :
14668 : 642 : i_amprocnum = PQfnumber(res, "amprocnum");
14669 : 642 : i_amproc = PQfnumber(res, "amproc");
5073 14670 : 642 : i_amproclefttype = PQfnumber(res, "amproclefttype");
14671 : 642 : i_amprocrighttype = PQfnumber(res, "amprocrighttype");
14672 : :
8490 14673 [ + + ]: 674 : for (i = 0; i < ntups; i++)
14674 : : {
14675 : 32 : amprocnum = PQgetvalue(res, i, i_amprocnum);
14676 : 32 : amproc = PQgetvalue(res, i, i_amproc);
5073 14677 : 32 : amproclefttype = PQgetvalue(res, i, i_amproclefttype);
14678 : 32 : amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
14679 : :
8490 14680 [ + - ]: 32 : if (needComma)
4361 heikki.linnakangas@i 14681 : 32 : appendPQExpBufferStr(q, " ,\n ");
14682 : :
5073 tgl@sss.pgh.pa.us 14683 : 32 : appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
14684 : :
14685 [ + - + - ]: 32 : if (*amproclefttype && *amprocrighttype)
14686 : 32 : appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
14687 : :
14688 : 32 : appendPQExpBuffer(q, " %s", amproc);
14689 : :
8490 14690 : 32 : needComma = true;
14691 : : }
14692 : :
14693 : 642 : PQclear(res);
14694 : :
14695 : : /*
14696 : : * If needComma is still false it means we haven't added anything after
14697 : : * the AS keyword. To avoid printing broken SQL, append a dummy STORAGE
14698 : : * clause with the same datatype. This isn't sanctioned by the
14699 : : * documentation, but actually DefineOpClass will treat it as a no-op.
14700 : : */
3076 14701 [ + + ]: 642 : if (!needComma)
14702 : 316 : appendPQExpBuffer(q, "STORAGE %s", opcintype);
14703 : :
4361 heikki.linnakangas@i 14704 : 642 : appendPQExpBufferStr(q, ";\n");
14705 : :
2800 tgl@sss.pgh.pa.us 14706 : 642 : appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
14707 : 642 : appendPQExpBuffer(nameusing, " USING %s",
14708 : : fmtId(amname));
14709 : :
4031 alvherre@alvh.no-ip. 14710 [ + + ]: 642 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 14711 : 6 : binary_upgrade_extension_member(q, &opcinfo->dobj,
14712 : 6 : "OPERATOR CLASS", nameusing->data,
14713 : 6 : opcinfo->dobj.namespace->dobj.name);
14714 : :
3491 sfrost@snowman.net 14715 [ + - ]: 642 : if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14716 : 642 : ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 14717 : 642 : ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
14718 : : .namespace = opcinfo->dobj.namespace->dobj.name,
14719 : : .owner = opcinfo->rolname,
14720 : : .description = "OPERATOR CLASS",
14721 : : .section = SECTION_PRE_DATA,
14722 : : .createStmt = q->data,
14723 : : .dropStmt = delq->data));
14724 : :
14725 : : /* Dump Operator Class Comments */
3491 sfrost@snowman.net 14726 [ - + ]: 642 : if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 14727 :UBC 0 : dumpComment(fout, "OPERATOR CLASS", nameusing->data,
3157 14728 : 0 : opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
3491 sfrost@snowman.net 14729 : 0 : opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
14730 : :
3076 tgl@sss.pgh.pa.us 14731 :CBC 642 : free(opcintype);
14732 : 642 : free(opcfamily);
8011 14733 : 642 : free(amname);
8490 14734 : 642 : destroyPQExpBuffer(query);
14735 : 642 : destroyPQExpBuffer(q);
14736 : 642 : destroyPQExpBuffer(delq);
2800 14737 : 642 : destroyPQExpBuffer(nameusing);
14738 : : }
14739 : :
14740 : : /*
14741 : : * dumpOpfamily
14742 : : * write out a single operator family definition
14743 : : *
14744 : : * Note: this also dumps any "loose" operator members that aren't bound to a
14745 : : * specific opclass within the opfamily.
14746 : : */
14747 : : static void
1720 peter@eisentraut.org 14748 : 549 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
14749 : : {
3575 tgl@sss.pgh.pa.us 14750 : 549 : DumpOptions *dopt = fout->dopt;
14751 : : PQExpBuffer query;
14752 : : PQExpBuffer q;
14753 : : PQExpBuffer delq;
14754 : : PQExpBuffer nameusing;
14755 : : PGresult *res;
14756 : : PGresult *res_ops;
14757 : : PGresult *res_procs;
14758 : : int ntups;
14759 : : int i_amname;
14760 : : int i_amopstrategy;
14761 : : int i_amopopr;
14762 : : int i_sortfamily;
14763 : : int i_sortfamilynsp;
14764 : : int i_amprocnum;
14765 : : int i_amproc;
14766 : : int i_amproclefttype;
14767 : : int i_amprocrighttype;
14768 : : char *amname;
14769 : : char *amopstrategy;
14770 : : char *amopopr;
14771 : : char *sortfamily;
14772 : : char *sortfamilynsp;
14773 : : char *amprocnum;
14774 : : char *amproc;
14775 : : char *amproclefttype;
14776 : : char *amprocrighttype;
14777 : : bool needComma;
14778 : : int i;
14779 : :
14780 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 14781 [ + + ]: 549 : if (!dopt->dumpSchema)
6852 tgl@sss.pgh.pa.us 14782 : 12 : return;
14783 : :
14784 : 537 : query = createPQExpBuffer();
14785 : 537 : q = createPQExpBuffer();
14786 : 537 : delq = createPQExpBuffer();
2800 14787 : 537 : nameusing = createPQExpBuffer();
14788 : :
14789 : : /*
14790 : : * Fetch only those opfamily members that are tied directly to the
14791 : : * opfamily by pg_depend entries.
14792 : : */
1413 14793 : 537 : appendPQExpBuffer(query, "SELECT amopstrategy, "
14794 : : "amopopr::pg_catalog.regoperator, "
14795 : : "opfname AS sortfamily, "
14796 : : "nspname AS sortfamilynsp "
14797 : : "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
14798 : : "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
14799 : : "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
14800 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
14801 : : "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
14802 : : "AND refobjid = '%u'::pg_catalog.oid "
14803 : : "AND amopfamily = '%u'::pg_catalog.oid "
14804 : : "ORDER BY amopstrategy",
14805 : 537 : opfinfo->dobj.catId.oid,
14806 : 537 : opfinfo->dobj.catId.oid);
14807 : :
5011 rhaas@postgresql.org 14808 : 537 : res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14809 : :
6852 tgl@sss.pgh.pa.us 14810 : 537 : resetPQExpBuffer(query);
14811 : :
14812 : 537 : appendPQExpBuffer(query, "SELECT amprocnum, "
14813 : : "amproc::pg_catalog.regprocedure, "
14814 : : "amproclefttype::pg_catalog.regtype, "
14815 : : "amprocrighttype::pg_catalog.regtype "
14816 : : "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
14817 : : "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
14818 : : "AND refobjid = '%u'::pg_catalog.oid "
14819 : : "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
14820 : : "AND objid = ap.oid "
14821 : : "ORDER BY amprocnum",
14822 : 537 : opfinfo->dobj.catId.oid);
14823 : :
5011 rhaas@postgresql.org 14824 : 537 : res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14825 : :
14826 : : /* Get additional fields from the pg_opfamily row */
6852 tgl@sss.pgh.pa.us 14827 : 537 : resetPQExpBuffer(query);
14828 : :
14829 : 537 : appendPQExpBuffer(query, "SELECT "
14830 : : "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
14831 : : "FROM pg_catalog.pg_opfamily "
14832 : : "WHERE oid = '%u'::pg_catalog.oid",
14833 : 537 : opfinfo->dobj.catId.oid);
14834 : :
5002 rhaas@postgresql.org 14835 : 537 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
14836 : :
6852 tgl@sss.pgh.pa.us 14837 : 537 : i_amname = PQfnumber(res, "amname");
14838 : :
14839 : : /* amname will still be needed after we PQclear res */
5085 bruce@momjian.us 14840 : 537 : amname = pg_strdup(PQgetvalue(res, 0, i_amname));
14841 : :
6852 tgl@sss.pgh.pa.us 14842 : 537 : appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
2800 14843 : 537 : fmtQualifiedDumpable(opfinfo));
6852 14844 : 537 : appendPQExpBuffer(delq, " USING %s;\n",
14845 : : fmtId(amname));
14846 : :
14847 : : /* Build the fixed portion of the CREATE command */
14848 : 537 : appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
2800 14849 : 537 : fmtQualifiedDumpable(opfinfo));
6852 14850 : 537 : appendPQExpBuffer(q, " USING %s;\n",
14851 : : fmtId(amname));
14852 : :
14853 : 537 : PQclear(res);
14854 : :
14855 : : /* Do we need an ALTER to add loose members? */
14856 [ + + + + ]: 537 : if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
14857 : : {
14858 : 47 : appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
2800 14859 : 47 : fmtQualifiedDumpable(opfinfo));
6852 14860 : 47 : appendPQExpBuffer(q, " USING %s ADD\n ",
14861 : : fmtId(amname));
14862 : :
14863 : 47 : needComma = false;
14864 : :
14865 : : /*
14866 : : * Now fetch and print the OPERATOR entries (pg_amop rows).
14867 : : */
14868 : 47 : ntups = PQntuples(res_ops);
14869 : :
14870 : 47 : i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
14871 : 47 : i_amopopr = PQfnumber(res_ops, "amopopr");
5451 14872 : 47 : i_sortfamily = PQfnumber(res_ops, "sortfamily");
14873 : 47 : i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
14874 : :
6852 14875 [ + + ]: 207 : for (i = 0; i < ntups; i++)
14876 : : {
14877 : 160 : amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
14878 : 160 : amopopr = PQgetvalue(res_ops, i, i_amopopr);
5451 14879 : 160 : sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
14880 : 160 : sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
14881 : :
6852 14882 [ + + ]: 160 : if (needComma)
4361 heikki.linnakangas@i 14883 : 128 : appendPQExpBufferStr(q, " ,\n ");
14884 : :
6852 tgl@sss.pgh.pa.us 14885 : 160 : appendPQExpBuffer(q, "OPERATOR %s %s",
14886 : : amopstrategy, amopopr);
14887 : :
5451 14888 [ - + ]: 160 : if (strlen(sortfamily) > 0)
14889 : : {
4361 heikki.linnakangas@i 14890 :UBC 0 : appendPQExpBufferStr(q, " FOR ORDER BY ");
2800 tgl@sss.pgh.pa.us 14891 : 0 : appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
4361 heikki.linnakangas@i 14892 : 0 : appendPQExpBufferStr(q, fmtId(sortfamily));
14893 : : }
14894 : :
6852 tgl@sss.pgh.pa.us 14895 :CBC 160 : needComma = true;
14896 : : }
14897 : :
14898 : : /*
14899 : : * Now fetch and print the FUNCTION entries (pg_amproc rows).
14900 : : */
14901 : 47 : ntups = PQntuples(res_procs);
14902 : :
14903 : 47 : i_amprocnum = PQfnumber(res_procs, "amprocnum");
14904 : 47 : i_amproc = PQfnumber(res_procs, "amproc");
14905 : 47 : i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
14906 : 47 : i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
14907 : :
14908 [ + + ]: 222 : for (i = 0; i < ntups; i++)
14909 : : {
14910 : 175 : amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
14911 : 175 : amproc = PQgetvalue(res_procs, i, i_amproc);
14912 : 175 : amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
14913 : 175 : amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
14914 : :
14915 [ + + ]: 175 : if (needComma)
4361 heikki.linnakangas@i 14916 : 160 : appendPQExpBufferStr(q, " ,\n ");
14917 : :
6852 tgl@sss.pgh.pa.us 14918 : 175 : appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
14919 : : amprocnum, amproclefttype, amprocrighttype,
14920 : : amproc);
14921 : :
14922 : 175 : needComma = true;
14923 : : }
14924 : :
4361 heikki.linnakangas@i 14925 : 47 : appendPQExpBufferStr(q, ";\n");
14926 : : }
14927 : :
2800 tgl@sss.pgh.pa.us 14928 : 537 : appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
14929 : 537 : appendPQExpBuffer(nameusing, " USING %s",
14930 : : fmtId(amname));
14931 : :
4031 alvherre@alvh.no-ip. 14932 [ + + ]: 537 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 14933 : 9 : binary_upgrade_extension_member(q, &opfinfo->dobj,
14934 : 9 : "OPERATOR FAMILY", nameusing->data,
14935 : 9 : opfinfo->dobj.namespace->dobj.name);
14936 : :
3491 sfrost@snowman.net 14937 [ + - ]: 537 : if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14938 : 537 : ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 14939 : 537 : ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
14940 : : .namespace = opfinfo->dobj.namespace->dobj.name,
14941 : : .owner = opfinfo->rolname,
14942 : : .description = "OPERATOR FAMILY",
14943 : : .section = SECTION_PRE_DATA,
14944 : : .createStmt = q->data,
14945 : : .dropStmt = delq->data));
14946 : :
14947 : : /* Dump Operator Family Comments */
3491 sfrost@snowman.net 14948 [ - + ]: 537 : if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 14949 :UBC 0 : dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
3157 14950 : 0 : opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
3491 sfrost@snowman.net 14951 : 0 : opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
14952 : :
6852 tgl@sss.pgh.pa.us 14953 :CBC 537 : free(amname);
14954 : 537 : PQclear(res_ops);
14955 : 537 : PQclear(res_procs);
14956 : 537 : destroyPQExpBuffer(query);
14957 : 537 : destroyPQExpBuffer(q);
14958 : 537 : destroyPQExpBuffer(delq);
2800 14959 : 537 : destroyPQExpBuffer(nameusing);
14960 : : }
14961 : :
14962 : : /*
14963 : : * dumpCollation
14964 : : * write out a single collation definition
14965 : : */
14966 : : static void
1720 peter@eisentraut.org 14967 : 4643 : dumpCollation(Archive *fout, const CollInfo *collinfo)
14968 : : {
3575 tgl@sss.pgh.pa.us 14969 : 4643 : DumpOptions *dopt = fout->dopt;
14970 : : PQExpBuffer query;
14971 : : PQExpBuffer q;
14972 : : PQExpBuffer delq;
14973 : : char *qcollname;
14974 : : PGresult *res;
14975 : : int i_collprovider;
14976 : : int i_collisdeterministic;
14977 : : int i_collcollate;
14978 : : int i_collctype;
14979 : : int i_colllocale;
14980 : : int i_collicurules;
14981 : : const char *collprovider;
14982 : : const char *collcollate;
14983 : : const char *collctype;
14984 : : const char *colllocale;
14985 : : const char *collicurules;
14986 : :
14987 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 14988 [ + + ]: 4643 : if (!dopt->dumpSchema)
5371 peter_e@gmx.net 14989 : 12 : return;
14990 : :
14991 : 4631 : query = createPQExpBuffer();
14992 : 4631 : q = createPQExpBuffer();
14993 : 4631 : delq = createPQExpBuffer();
14994 : :
2800 tgl@sss.pgh.pa.us 14995 : 4631 : qcollname = pg_strdup(fmtId(collinfo->dobj.name));
14996 : :
14997 : : /* Get collation-specific details */
2307 drowley@postgresql.o 14998 : 4631 : appendPQExpBufferStr(query, "SELECT ");
14999 : :
3140 peter_e@gmx.net 15000 [ + - ]: 4631 : if (fout->remoteVersion >= 100000)
2307 drowley@postgresql.o 15001 : 4631 : appendPQExpBufferStr(query,
15002 : : "collprovider, "
15003 : : "collversion, ");
15004 : : else
2307 drowley@postgresql.o 15005 :UBC 0 : appendPQExpBufferStr(query,
15006 : : "'c' AS collprovider, "
15007 : : "NULL AS collversion, ");
15008 : :
2411 peter@eisentraut.org 15009 [ + - ]:CBC 4631 : if (fout->remoteVersion >= 120000)
2307 drowley@postgresql.o 15010 : 4631 : appendPQExpBufferStr(query,
15011 : : "collisdeterministic, ");
15012 : : else
2307 drowley@postgresql.o 15013 :UBC 0 : appendPQExpBufferStr(query,
15014 : : "true AS collisdeterministic, ");
15015 : :
597 jdavis@postgresql.or 15016 [ + - ]:CBC 4631 : if (fout->remoteVersion >= 170000)
15017 : 4631 : appendPQExpBufferStr(query,
15018 : : "colllocale, ");
597 jdavis@postgresql.or 15019 [ # # ]:UBC 0 : else if (fout->remoteVersion >= 150000)
1160 peter@eisentraut.org 15020 : 0 : appendPQExpBufferStr(query,
15021 : : "colliculocale AS colllocale, ");
15022 : : else
15023 : 0 : appendPQExpBufferStr(query,
15024 : : "NULL AS colllocale, ");
15025 : :
964 peter@eisentraut.org 15026 [ + - ]:CBC 4631 : if (fout->remoteVersion >= 160000)
15027 : 4631 : appendPQExpBufferStr(query,
15028 : : "collicurules, ");
15029 : : else
964 peter@eisentraut.org 15030 :UBC 0 : appendPQExpBufferStr(query,
15031 : : "NULL AS collicurules, ");
15032 : :
2411 peter@eisentraut.org 15033 :CBC 4631 : appendPQExpBuffer(query,
15034 : : "collcollate, "
15035 : : "collctype "
15036 : : "FROM pg_catalog.pg_collation c "
15037 : : "WHERE c.oid = '%u'::pg_catalog.oid",
15038 : 4631 : collinfo->dobj.catId.oid);
15039 : :
5002 rhaas@postgresql.org 15040 : 4631 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
15041 : :
3140 peter_e@gmx.net 15042 : 4631 : i_collprovider = PQfnumber(res, "collprovider");
2411 peter@eisentraut.org 15043 : 4631 : i_collisdeterministic = PQfnumber(res, "collisdeterministic");
5371 peter_e@gmx.net 15044 : 4631 : i_collcollate = PQfnumber(res, "collcollate");
15045 : 4631 : i_collctype = PQfnumber(res, "collctype");
597 jdavis@postgresql.or 15046 : 4631 : i_colllocale = PQfnumber(res, "colllocale");
964 peter@eisentraut.org 15047 : 4631 : i_collicurules = PQfnumber(res, "collicurules");
15048 : :
3140 peter_e@gmx.net 15049 : 4631 : collprovider = PQgetvalue(res, 0, i_collprovider);
15050 : :
1160 peter@eisentraut.org 15051 [ + + ]: 4631 : if (!PQgetisnull(res, 0, i_collcollate))
15052 : 2014 : collcollate = PQgetvalue(res, 0, i_collcollate);
15053 : : else
15054 : 2617 : collcollate = NULL;
15055 : :
15056 [ + + ]: 4631 : if (!PQgetisnull(res, 0, i_collctype))
15057 : 2014 : collctype = PQgetvalue(res, 0, i_collctype);
15058 : : else
15059 : 2617 : collctype = NULL;
15060 : :
15061 : : /*
15062 : : * Before version 15, collcollate and collctype were of type NAME and
15063 : : * non-nullable. Treat empty strings as NULL for consistency.
15064 : : */
797 jdavis@postgresql.or 15065 [ - + ]: 4631 : if (fout->remoteVersion < 150000)
15066 : : {
797 jdavis@postgresql.or 15067 [ # # ]:UBC 0 : if (collcollate[0] == '\0')
15068 : 0 : collcollate = NULL;
15069 [ # # ]: 0 : if (collctype[0] == '\0')
15070 : 0 : collctype = NULL;
15071 : : }
15072 : :
597 jdavis@postgresql.or 15073 [ + + ]:CBC 4631 : if (!PQgetisnull(res, 0, i_colllocale))
15074 : 2614 : colllocale = PQgetvalue(res, 0, i_colllocale);
15075 : : else
15076 : 2017 : colllocale = NULL;
15077 : :
964 peter@eisentraut.org 15078 [ - + ]: 4631 : if (!PQgetisnull(res, 0, i_collicurules))
964 peter@eisentraut.org 15079 :UBC 0 : collicurules = PQgetvalue(res, 0, i_collicurules);
15080 : : else
964 peter@eisentraut.org 15081 :CBC 4631 : collicurules = NULL;
15082 : :
2800 tgl@sss.pgh.pa.us 15083 : 4631 : appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
15084 : 4631 : fmtQualifiedDumpable(collinfo));
15085 : :
3140 peter_e@gmx.net 15086 : 4631 : appendPQExpBuffer(q, "CREATE COLLATION %s (",
2800 tgl@sss.pgh.pa.us 15087 : 4631 : fmtQualifiedDumpable(collinfo));
15088 : :
3140 peter_e@gmx.net 15089 : 4631 : appendPQExpBufferStr(q, "provider = ");
593 jdavis@postgresql.or 15090 [ + + ]: 4631 : if (collprovider[0] == 'b')
15091 : 19 : appendPQExpBufferStr(q, "builtin");
15092 [ + + ]: 4612 : else if (collprovider[0] == 'c')
3140 peter_e@gmx.net 15093 : 2014 : appendPQExpBufferStr(q, "libc");
15094 [ + + ]: 2598 : else if (collprovider[0] == 'i')
15095 : 2595 : appendPQExpBufferStr(q, "icu");
3058 15096 [ + - ]: 3 : else if (collprovider[0] == 'd')
15097 : : /* to allow dumping pg_catalog; not accepted on input */
15098 : 3 : appendPQExpBufferStr(q, "default");
15099 : : else
1298 tgl@sss.pgh.pa.us 15100 :UBC 0 : pg_fatal("unrecognized collation provider: %s",
15101 : : collprovider);
15102 : :
2411 peter@eisentraut.org 15103 [ - + ]:CBC 4631 : if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
2411 peter@eisentraut.org 15104 :UBC 0 : appendPQExpBufferStr(q, ", deterministic = false");
15105 : :
797 jdavis@postgresql.or 15106 [ + + ]:CBC 4631 : if (collprovider[0] == 'd')
15107 : : {
597 15108 [ + - + - : 3 : if (collcollate || collctype || colllocale || collicurules)
+ - - + ]
797 jdavis@postgresql.or 15109 :UBC 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
15110 : :
15111 : : /* no locale -- the default collation cannot be reloaded anyway */
15112 : : }
593 jdavis@postgresql.or 15113 [ + + ]:CBC 4628 : else if (collprovider[0] == 'b')
15114 : : {
15115 [ + - + - : 19 : if (collcollate || collctype || !colllocale || collicurules)
+ - - + ]
593 jdavis@postgresql.or 15116 :UBC 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
15117 : :
593 jdavis@postgresql.or 15118 :CBC 19 : appendPQExpBufferStr(q, ", locale = ");
15119 [ + - ]: 19 : appendStringLiteralAH(q, colllocale ? colllocale : "",
15120 : : fout);
15121 : : }
797 15122 [ + + ]: 4609 : else if (collprovider[0] == 'i')
15123 : : {
15124 [ + - ]: 2595 : if (fout->remoteVersion >= 150000)
15125 : : {
597 15126 [ + - + - : 2595 : if (collcollate || collctype || !colllocale)
- + ]
797 jdavis@postgresql.or 15127 :UBC 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
15128 : :
797 jdavis@postgresql.or 15129 :CBC 2595 : appendPQExpBufferStr(q, ", locale = ");
597 15130 [ + - ]: 2595 : appendStringLiteralAH(q, colllocale ? colllocale : "",
15131 : : fout);
15132 : : }
15133 : : else
15134 : : {
597 jdavis@postgresql.or 15135 [ # # # # :UBC 0 : if (!collcollate || !collctype || colllocale ||
# # ]
797 15136 [ # # ]: 0 : strcmp(collcollate, collctype) != 0)
15137 : 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
15138 : :
1160 peter@eisentraut.org 15139 : 0 : appendPQExpBufferStr(q, ", locale = ");
797 jdavis@postgresql.or 15140 [ # # ]: 0 : appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
15141 : : }
15142 : :
797 jdavis@postgresql.or 15143 [ - + ]:CBC 2595 : if (collicurules)
15144 : : {
797 jdavis@postgresql.or 15145 :UBC 0 : appendPQExpBufferStr(q, ", rules = ");
15146 [ # # ]: 0 : appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
15147 : : }
15148 : : }
797 jdavis@postgresql.or 15149 [ + - ]:CBC 2014 : else if (collprovider[0] == 'c')
15150 : : {
597 15151 [ + - + - : 2014 : if (colllocale || collicurules || !collcollate || !collctype)
+ - - + ]
797 jdavis@postgresql.or 15152 :UBC 0 : pg_log_warning("invalid collation \"%s\"", qcollname);
15153 : :
797 jdavis@postgresql.or 15154 [ + - + - :CBC 2014 : if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
+ - ]
15155 : : {
15156 : 2014 : appendPQExpBufferStr(q, ", locale = ");
15157 [ + - ]: 2014 : appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
15158 : : }
15159 : : else
15160 : : {
1160 peter@eisentraut.org 15161 :UBC 0 : appendPQExpBufferStr(q, ", lc_collate = ");
797 jdavis@postgresql.or 15162 [ # # ]: 0 : appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
1160 peter@eisentraut.org 15163 : 0 : appendPQExpBufferStr(q, ", lc_ctype = ");
797 jdavis@postgresql.or 15164 [ # # ]: 0 : appendStringLiteralAH(q, collctype ? collctype : "", fout);
15165 : : }
15166 : : }
15167 : : else
783 peter@eisentraut.org 15168 : 0 : pg_fatal("unrecognized collation provider: %s", collprovider);
15169 : :
15170 : : /*
15171 : : * For binary upgrade, carry over the collation version. For normal
15172 : : * dump/restore, omit the version, so that it is computed upon restore.
15173 : : */
1634 tmunro@postgresql.or 15174 [ + + ]:CBC 4631 : if (dopt->binary_upgrade)
15175 : : {
15176 : : int i_collversion;
15177 : :
15178 : 5 : i_collversion = PQfnumber(res, "collversion");
15179 [ + + ]: 5 : if (!PQgetisnull(res, 0, i_collversion))
15180 : : {
15181 : 4 : appendPQExpBufferStr(q, ", version = ");
15182 : 4 : appendStringLiteralAH(q,
15183 : : PQgetvalue(res, 0, i_collversion),
15184 : : fout);
15185 : : }
15186 : : }
15187 : :
4361 heikki.linnakangas@i 15188 : 4631 : appendPQExpBufferStr(q, ");\n");
15189 : :
4031 alvherre@alvh.no-ip. 15190 [ + + ]: 4631 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 15191 : 5 : binary_upgrade_extension_member(q, &collinfo->dobj,
15192 : : "COLLATION", qcollname,
15193 : 5 : collinfo->dobj.namespace->dobj.name);
15194 : :
3491 sfrost@snowman.net 15195 [ + - ]: 4631 : if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15196 : 4631 : ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 15197 : 4631 : ARCHIVE_OPTS(.tag = collinfo->dobj.name,
15198 : : .namespace = collinfo->dobj.namespace->dobj.name,
15199 : : .owner = collinfo->rolname,
15200 : : .description = "COLLATION",
15201 : : .section = SECTION_PRE_DATA,
15202 : : .createStmt = q->data,
15203 : : .dropStmt = delq->data));
15204 : :
15205 : : /* Dump Collation Comments */
3491 sfrost@snowman.net 15206 [ + + ]: 4631 : if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 15207 : 2557 : dumpComment(fout, "COLLATION", qcollname,
3491 sfrost@snowman.net 15208 : 2557 : collinfo->dobj.namespace->dobj.name, collinfo->rolname,
15209 : 2557 : collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
15210 : :
5371 peter_e@gmx.net 15211 : 4631 : PQclear(res);
15212 : :
15213 : 4631 : destroyPQExpBuffer(query);
15214 : 4631 : destroyPQExpBuffer(q);
15215 : 4631 : destroyPQExpBuffer(delq);
2800 tgl@sss.pgh.pa.us 15216 : 4631 : free(qcollname);
15217 : : }
15218 : :
15219 : : /*
15220 : : * dumpConversion
15221 : : * write out a single conversion definition
15222 : : */
15223 : : static void
1720 peter@eisentraut.org 15224 : 422 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
15225 : : {
3575 tgl@sss.pgh.pa.us 15226 : 422 : DumpOptions *dopt = fout->dopt;
15227 : : PQExpBuffer query;
15228 : : PQExpBuffer q;
15229 : : PQExpBuffer delq;
15230 : : char *qconvname;
15231 : : PGresult *res;
15232 : : int i_conforencoding;
15233 : : int i_contoencoding;
15234 : : int i_conproc;
15235 : : int i_condefault;
15236 : : const char *conforencoding;
15237 : : const char *contoencoding;
15238 : : const char *conproc;
15239 : : bool condefault;
15240 : :
15241 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 15242 [ + + ]: 422 : if (!dopt->dumpSchema)
7996 tgl@sss.pgh.pa.us 15243 : 6 : return;
15244 : :
15245 : 416 : query = createPQExpBuffer();
15246 : 416 : q = createPQExpBuffer();
15247 : 416 : delq = createPQExpBuffer();
15248 : :
2800 15249 : 416 : qconvname = pg_strdup(fmtId(convinfo->dobj.name));
15250 : :
15251 : : /* Get conversion-specific details */
5313 peter_e@gmx.net 15252 : 416 : appendPQExpBuffer(query, "SELECT "
15253 : : "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
15254 : : "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
15255 : : "conproc, condefault "
15256 : : "FROM pg_catalog.pg_conversion c "
15257 : : "WHERE c.oid = '%u'::pg_catalog.oid",
7996 tgl@sss.pgh.pa.us 15258 : 416 : convinfo->dobj.catId.oid);
15259 : :
5002 rhaas@postgresql.org 15260 : 416 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
15261 : :
8011 tgl@sss.pgh.pa.us 15262 : 416 : i_conforencoding = PQfnumber(res, "conforencoding");
15263 : 416 : i_contoencoding = PQfnumber(res, "contoencoding");
15264 : 416 : i_conproc = PQfnumber(res, "conproc");
15265 : 416 : i_condefault = PQfnumber(res, "condefault");
15266 : :
15267 : 416 : conforencoding = PQgetvalue(res, 0, i_conforencoding);
15268 : 416 : contoencoding = PQgetvalue(res, 0, i_contoencoding);
15269 : 416 : conproc = PQgetvalue(res, 0, i_conproc);
15270 : 416 : condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
15271 : :
2800 15272 : 416 : appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
15273 : 416 : fmtQualifiedDumpable(convinfo));
15274 : :
8011 15275 [ + - ]: 416 : appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
15276 : : (condefault) ? "DEFAULT " : "",
2800 15277 : 416 : fmtQualifiedDumpable(convinfo));
7092 15278 : 416 : appendStringLiteralAH(q, conforencoding, fout);
4361 heikki.linnakangas@i 15279 : 416 : appendPQExpBufferStr(q, " TO ");
7092 tgl@sss.pgh.pa.us 15280 : 416 : appendStringLiteralAH(q, contoencoding, fout);
15281 : : /* regproc output is already sufficiently quoted */
8011 15282 : 416 : appendPQExpBuffer(q, " FROM %s;\n", conproc);
15283 : :
4031 alvherre@alvh.no-ip. 15284 [ + + ]: 416 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 15285 : 1 : binary_upgrade_extension_member(q, &convinfo->dobj,
15286 : : "CONVERSION", qconvname,
15287 : 1 : convinfo->dobj.namespace->dobj.name);
15288 : :
3491 sfrost@snowman.net 15289 [ + - ]: 416 : if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15290 : 416 : ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 15291 : 416 : ARCHIVE_OPTS(.tag = convinfo->dobj.name,
15292 : : .namespace = convinfo->dobj.namespace->dobj.name,
15293 : : .owner = convinfo->rolname,
15294 : : .description = "CONVERSION",
15295 : : .section = SECTION_PRE_DATA,
15296 : : .createStmt = q->data,
15297 : : .dropStmt = delq->data));
15298 : :
15299 : : /* Dump Conversion Comments */
3491 sfrost@snowman.net 15300 [ + - ]: 416 : if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 15301 : 416 : dumpComment(fout, "CONVERSION", qconvname,
3491 sfrost@snowman.net 15302 : 416 : convinfo->dobj.namespace->dobj.name, convinfo->rolname,
15303 : 416 : convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
15304 : :
7996 tgl@sss.pgh.pa.us 15305 : 416 : PQclear(res);
15306 : :
15307 : 416 : destroyPQExpBuffer(query);
15308 : 416 : destroyPQExpBuffer(q);
15309 : 416 : destroyPQExpBuffer(delq);
2800 15310 : 416 : free(qconvname);
15311 : : }
15312 : :
15313 : : /*
15314 : : * format_aggregate_signature: generate aggregate name and argument list
15315 : : *
15316 : : * The argument type names are qualified if needed. The aggregate name
15317 : : * is never qualified.
15318 : : */
15319 : : static char *
1720 peter@eisentraut.org 15320 : 285 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
15321 : : {
15322 : : PQExpBufferData buf;
15323 : : int j;
15324 : :
8562 peter_e@gmx.net 15325 : 285 : initPQExpBuffer(&buf);
8516 bruce@momjian.us 15326 [ - + ]: 285 : if (honor_quotes)
4361 heikki.linnakangas@i 15327 :UBC 0 : appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
15328 : : else
4361 heikki.linnakangas@i 15329 :CBC 285 : appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
15330 : :
7032 tgl@sss.pgh.pa.us 15331 [ + + ]: 285 : if (agginfo->aggfn.nargs == 0)
2307 drowley@postgresql.o 15332 : 40 : appendPQExpBufferStr(&buf, "(*)");
15333 : : else
15334 : : {
4361 heikki.linnakangas@i 15335 : 245 : appendPQExpBufferChar(&buf, '(');
7032 tgl@sss.pgh.pa.us 15336 [ + + ]: 535 : for (j = 0; j < agginfo->aggfn.nargs; j++)
15337 [ + + ]: 290 : appendPQExpBuffer(&buf, "%s%s",
15338 : : (j > 0) ? ", " : "",
15339 : : getFormattedTypeName(fout,
1510 15340 : 290 : agginfo->aggfn.argtypes[j],
15341 : : zeroIsError));
4361 heikki.linnakangas@i 15342 : 245 : appendPQExpBufferChar(&buf, ')');
15343 : : }
8562 peter_e@gmx.net 15344 : 285 : return buf.data;
15345 : : }
15346 : :
15347 : : /*
15348 : : * dumpAgg
15349 : : * write out a single aggregate definition
15350 : : */
15351 : : static void
1720 peter@eisentraut.org 15352 : 292 : dumpAgg(Archive *fout, const AggInfo *agginfo)
15353 : : {
3575 tgl@sss.pgh.pa.us 15354 : 292 : DumpOptions *dopt = fout->dopt;
15355 : : PQExpBuffer query;
15356 : : PQExpBuffer q;
15357 : : PQExpBuffer delq;
15358 : : PQExpBuffer details;
15359 : : char *aggsig; /* identity signature */
3050 15360 : 292 : char *aggfullsig = NULL; /* full signature */
15361 : : char *aggsig_tag;
15362 : : PGresult *res;
15363 : : int i_agginitval;
15364 : : int i_aggminitval;
15365 : : const char *aggtransfn;
15366 : : const char *aggfinalfn;
15367 : : const char *aggcombinefn;
15368 : : const char *aggserialfn;
15369 : : const char *aggdeserialfn;
15370 : : const char *aggmtransfn;
15371 : : const char *aggminvtransfn;
15372 : : const char *aggmfinalfn;
15373 : : bool aggfinalextra;
15374 : : bool aggmfinalextra;
15375 : : char aggfinalmodify;
15376 : : char aggmfinalmodify;
15377 : : const char *aggsortop;
15378 : : char *aggsortconvop;
15379 : : char aggkind;
15380 : : const char *aggtranstype;
15381 : : const char *aggtransspace;
15382 : : const char *aggmtranstype;
15383 : : const char *aggmtransspace;
15384 : : const char *agginitval;
15385 : : const char *aggminitval;
15386 : : const char *proparallel;
15387 : : char defaultfinalmodify;
15388 : :
15389 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 15390 [ + + ]: 292 : if (!dopt->dumpSchema)
7996 tgl@sss.pgh.pa.us 15391 : 7 : return;
15392 : :
15393 : 285 : query = createPQExpBuffer();
15394 : 285 : q = createPQExpBuffer();
15395 : 285 : delq = createPQExpBuffer();
15396 : 285 : details = createPQExpBuffer();
15397 : :
1421 15398 [ + + ]: 285 : if (!fout->is_prepared[PREPQUERY_DUMPAGG])
15399 : : {
15400 : : /* Set up query for aggregate-specific details */
1838 drowley@postgresql.o 15401 : 55 : appendPQExpBufferStr(query,
15402 : : "PREPARE dumpAgg(pg_catalog.oid) AS\n");
15403 : :
15404 : 55 : appendPQExpBufferStr(query,
15405 : : "SELECT "
15406 : : "aggtransfn,\n"
15407 : : "aggfinalfn,\n"
15408 : : "aggtranstype::pg_catalog.regtype,\n"
15409 : : "agginitval,\n"
15410 : : "aggsortop,\n"
15411 : : "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
15412 : : "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
15413 : :
1421 tgl@sss.pgh.pa.us 15414 [ + - ]: 55 : if (fout->remoteVersion >= 90400)
15415 : 55 : appendPQExpBufferStr(query,
15416 : : "aggkind,\n"
15417 : : "aggmtransfn,\n"
15418 : : "aggminvtransfn,\n"
15419 : : "aggmfinalfn,\n"
15420 : : "aggmtranstype::pg_catalog.regtype,\n"
15421 : : "aggfinalextra,\n"
15422 : : "aggmfinalextra,\n"
15423 : : "aggtransspace,\n"
15424 : : "aggmtransspace,\n"
15425 : : "aggminitval,\n");
15426 : : else
1421 tgl@sss.pgh.pa.us 15427 :UBC 0 : appendPQExpBufferStr(query,
15428 : : "'n' AS aggkind,\n"
15429 : : "'-' AS aggmtransfn,\n"
15430 : : "'-' AS aggminvtransfn,\n"
15431 : : "'-' AS aggmfinalfn,\n"
15432 : : "0 AS aggmtranstype,\n"
15433 : : "false AS aggfinalextra,\n"
15434 : : "false AS aggmfinalextra,\n"
15435 : : "0 AS aggtransspace,\n"
15436 : : "0 AS aggmtransspace,\n"
15437 : : "NULL AS aggminitval,\n");
15438 : :
1421 tgl@sss.pgh.pa.us 15439 [ + - ]:CBC 55 : if (fout->remoteVersion >= 90600)
15440 : 55 : appendPQExpBufferStr(query,
15441 : : "aggcombinefn,\n"
15442 : : "aggserialfn,\n"
15443 : : "aggdeserialfn,\n"
15444 : : "proparallel,\n");
15445 : : else
1421 tgl@sss.pgh.pa.us 15446 :UBC 0 : appendPQExpBufferStr(query,
15447 : : "'-' AS aggcombinefn,\n"
15448 : : "'-' AS aggserialfn,\n"
15449 : : "'-' AS aggdeserialfn,\n"
15450 : : "'u' AS proparallel,\n");
15451 : :
1421 tgl@sss.pgh.pa.us 15452 [ + - ]:CBC 55 : if (fout->remoteVersion >= 110000)
15453 : 55 : appendPQExpBufferStr(query,
15454 : : "aggfinalmodify,\n"
15455 : : "aggmfinalmodify\n");
15456 : : else
1421 tgl@sss.pgh.pa.us 15457 :UBC 0 : appendPQExpBufferStr(query,
15458 : : "'0' AS aggfinalmodify,\n"
15459 : : "'0' AS aggmfinalmodify\n");
15460 : :
1838 drowley@postgresql.o 15461 :CBC 55 : appendPQExpBufferStr(query,
15462 : : "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
15463 : : "WHERE a.aggfnoid = p.oid "
15464 : : "AND p.oid = $1");
15465 : :
1421 tgl@sss.pgh.pa.us 15466 : 55 : ExecuteSqlStatement(fout, query->data);
15467 : :
15468 : 55 : fout->is_prepared[PREPQUERY_DUMPAGG] = true;
15469 : : }
15470 : :
15471 : 285 : printfPQExpBuffer(query,
15472 : : "EXECUTE dumpAgg('%u')",
1930 peter@eisentraut.org 15473 : 285 : agginfo->aggfn.dobj.catId.oid);
15474 : :
5002 rhaas@postgresql.org 15475 : 285 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
15476 : :
8571 tgl@sss.pgh.pa.us 15477 : 285 : i_agginitval = PQfnumber(res, "agginitval");
4216 15478 : 285 : i_aggminitval = PQfnumber(res, "aggminitval");
15479 : :
1930 peter@eisentraut.org 15480 : 285 : aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
15481 : 285 : aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
15482 : 285 : aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
15483 : 285 : aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
15484 : 285 : aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
15485 : 285 : aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
15486 : 285 : aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
15487 : 285 : aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
15488 : 285 : aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
15489 : 285 : aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
15490 : 285 : aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
15491 : 285 : aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
15492 : 285 : aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
15493 : 285 : aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
15494 : 285 : aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
15495 : 285 : aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
15496 : 285 : aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
15497 : 285 : aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
8571 tgl@sss.pgh.pa.us 15498 : 285 : agginitval = PQgetvalue(res, 0, i_agginitval);
4216 15499 : 285 : aggminitval = PQgetvalue(res, 0, i_aggminitval);
1930 peter@eisentraut.org 15500 : 285 : proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
15501 : :
15502 : : {
15503 : : char *funcargs;
15504 : : char *funciargs;
15505 : :
4437 tgl@sss.pgh.pa.us 15506 : 285 : funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
15507 : 285 : funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
15508 : 285 : aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
15509 : 285 : aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
15510 : : }
15511 : :
7996 15512 : 285 : aggsig_tag = format_aggregate_signature(agginfo, fout, false);
15513 : :
15514 : : /* identify default modify flag for aggkind (must match DefineAggregate) */
2935 15515 [ + + ]: 285 : defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
15516 : : /* replace omitted flags for old versions */
15517 [ - + ]: 285 : if (aggfinalmodify == '0')
2935 tgl@sss.pgh.pa.us 15518 :UBC 0 : aggfinalmodify = defaultfinalmodify;
2935 tgl@sss.pgh.pa.us 15519 [ - + ]:CBC 285 : if (aggmfinalmodify == '0')
2935 tgl@sss.pgh.pa.us 15520 :UBC 0 : aggmfinalmodify = defaultfinalmodify;
15521 : :
15522 : : /* regproc and regtype output is already sufficiently quoted */
3302 tgl@sss.pgh.pa.us 15523 :CBC 285 : appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
15524 : : aggtransfn, aggtranstype);
15525 : :
4363 15526 [ + + ]: 285 : if (strcmp(aggtransspace, "0") != 0)
15527 : : {
15528 : 5 : appendPQExpBuffer(details, ",\n SSPACE = %s",
15529 : : aggtransspace);
15530 : : }
15531 : :
8571 15532 [ + + ]: 285 : if (!PQgetisnull(res, 0, i_agginitval))
15533 : : {
4361 heikki.linnakangas@i 15534 : 207 : appendPQExpBufferStr(details, ",\n INITCOND = ");
7092 tgl@sss.pgh.pa.us 15535 : 207 : appendStringLiteralAH(details, agginitval, fout);
15536 : : }
15537 : :
8571 15538 [ + + ]: 285 : if (strcmp(aggfinalfn, "-") != 0)
15539 : : {
8471 peter_e@gmx.net 15540 : 132 : appendPQExpBuffer(details, ",\n FINALFUNC = %s",
15541 : : aggfinalfn);
4205 tgl@sss.pgh.pa.us 15542 [ + + ]: 132 : if (aggfinalextra)
15543 : 10 : appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
2935 15544 [ + + ]: 132 : if (aggfinalmodify != defaultfinalmodify)
15545 : : {
15546 [ - + - - ]: 32 : switch (aggfinalmodify)
15547 : : {
2935 tgl@sss.pgh.pa.us 15548 :UBC 0 : case AGGMODIFY_READ_ONLY:
15549 : 0 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_ONLY");
15550 : 0 : break;
2716 tgl@sss.pgh.pa.us 15551 :CBC 32 : case AGGMODIFY_SHAREABLE:
15552 : 32 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = SHAREABLE");
2935 15553 : 32 : break;
2935 tgl@sss.pgh.pa.us 15554 :UBC 0 : case AGGMODIFY_READ_WRITE:
15555 : 0 : appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_WRITE");
15556 : 0 : break;
15557 : 0 : default:
1298 15558 : 0 : pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
15559 : : agginfo->aggfn.dobj.name);
15560 : : break;
15561 : : }
15562 : : }
15563 : : }
15564 : :
3568 rhaas@postgresql.org 15565 [ - + ]:CBC 285 : if (strcmp(aggcombinefn, "-") != 0)
3427 rhaas@postgresql.org 15566 :UBC 0 : appendPQExpBuffer(details, ",\n COMBINEFUNC = %s", aggcombinefn);
15567 : :
3499 rhaas@postgresql.org 15568 [ - + ]:CBC 285 : if (strcmp(aggserialfn, "-") != 0)
3427 rhaas@postgresql.org 15569 :UBC 0 : appendPQExpBuffer(details, ",\n SERIALFUNC = %s", aggserialfn);
15570 : :
3414 tgl@sss.pgh.pa.us 15571 [ - + ]:CBC 285 : if (strcmp(aggdeserialfn, "-") != 0)
3427 rhaas@postgresql.org 15572 :UBC 0 : appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
15573 : :
4216 tgl@sss.pgh.pa.us 15574 [ + + ]:CBC 285 : if (strcmp(aggmtransfn, "-") != 0)
15575 : : {
15576 : 30 : appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
15577 : : aggmtransfn,
15578 : : aggminvtransfn,
15579 : : aggmtranstype);
15580 : : }
15581 : :
15582 [ - + ]: 285 : if (strcmp(aggmtransspace, "0") != 0)
15583 : : {
4216 tgl@sss.pgh.pa.us 15584 :UBC 0 : appendPQExpBuffer(details, ",\n MSSPACE = %s",
15585 : : aggmtransspace);
15586 : : }
15587 : :
4216 tgl@sss.pgh.pa.us 15588 [ + + ]:CBC 285 : if (!PQgetisnull(res, 0, i_aggminitval))
15589 : : {
15590 : 10 : appendPQExpBufferStr(details, ",\n MINITCOND = ");
15591 : 10 : appendStringLiteralAH(details, aggminitval, fout);
15592 : : }
15593 : :
15594 [ - + ]: 285 : if (strcmp(aggmfinalfn, "-") != 0)
15595 : : {
4216 tgl@sss.pgh.pa.us 15596 :UBC 0 : appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
15597 : : aggmfinalfn);
4205 15598 [ # # ]: 0 : if (aggmfinalextra)
15599 : 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
2935 15600 [ # # ]: 0 : if (aggmfinalmodify != defaultfinalmodify)
15601 : : {
15602 [ # # # # ]: 0 : switch (aggmfinalmodify)
15603 : : {
15604 : 0 : case AGGMODIFY_READ_ONLY:
15605 : 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_ONLY");
15606 : 0 : break;
2716 15607 : 0 : case AGGMODIFY_SHAREABLE:
15608 : 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = SHAREABLE");
2935 15609 : 0 : break;
15610 : 0 : case AGGMODIFY_READ_WRITE:
15611 : 0 : appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_WRITE");
15612 : 0 : break;
15613 : 0 : default:
1298 15614 : 0 : pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
15615 : : agginfo->aggfn.dobj.name);
15616 : : break;
15617 : : }
15618 : : }
15619 : : }
15620 : :
1889 peter@eisentraut.org 15621 :CBC 285 : aggsortconvop = getFormattedOperatorName(aggsortop);
4258 sfrost@snowman.net 15622 [ - + ]: 285 : if (aggsortconvop)
15623 : : {
7503 tgl@sss.pgh.pa.us 15624 :UBC 0 : appendPQExpBuffer(details, ",\n SORTOP = %s",
15625 : : aggsortconvop);
4258 sfrost@snowman.net 15626 : 0 : free(aggsortconvop);
15627 : : }
15628 : :
2935 tgl@sss.pgh.pa.us 15629 [ + + ]:CBC 285 : if (aggkind == AGGKIND_HYPOTHETICAL)
4326 15630 : 5 : appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
15631 : :
1930 peter@eisentraut.org 15632 [ + + ]: 285 : if (proparallel[0] != PROPARALLEL_UNSAFE)
15633 : : {
3477 rhaas@postgresql.org 15634 [ + - ]: 5 : if (proparallel[0] == PROPARALLEL_SAFE)
15635 : 5 : appendPQExpBufferStr(details, ",\n PARALLEL = safe");
3477 rhaas@postgresql.org 15636 [ # # ]:UBC 0 : else if (proparallel[0] == PROPARALLEL_RESTRICTED)
15637 : 0 : appendPQExpBufferStr(details, ",\n PARALLEL = restricted");
15638 [ # # ]: 0 : else if (proparallel[0] != PROPARALLEL_UNSAFE)
1298 tgl@sss.pgh.pa.us 15639 : 0 : pg_fatal("unrecognized proparallel value for function \"%s\"",
15640 : : agginfo->aggfn.dobj.name);
15641 : : }
15642 : :
8553 tgl@sss.pgh.pa.us 15643 :CBC 285 : appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
7908 15644 : 285 : fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
15645 : : aggsig);
15646 : :
2800 15647 [ + - ]: 570 : appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
15648 : 285 : fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
15649 : : aggfullsig ? aggfullsig : aggsig, details->data);
15650 : :
4031 alvherre@alvh.no-ip. 15651 [ + + ]: 285 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 15652 : 49 : binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
15653 : : "AGGREGATE", aggsig,
15654 : 49 : agginfo->aggfn.dobj.namespace->dobj.name);
15655 : :
3491 sfrost@snowman.net 15656 [ + + ]: 285 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
15657 : 268 : ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
15658 : 268 : agginfo->aggfn.dobj.dumpId,
2460 alvherre@alvh.no-ip. 15659 : 268 : ARCHIVE_OPTS(.tag = aggsig_tag,
15660 : : .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
15661 : : .owner = agginfo->aggfn.rolname,
15662 : : .description = "AGGREGATE",
15663 : : .section = SECTION_PRE_DATA,
15664 : : .createStmt = q->data,
15665 : : .dropStmt = delq->data));
15666 : :
15667 : : /* Dump Aggregate Comments */
3491 sfrost@snowman.net 15668 [ + + ]: 285 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 15669 : 10 : dumpComment(fout, "AGGREGATE", aggsig,
3491 sfrost@snowman.net 15670 : 10 : agginfo->aggfn.dobj.namespace->dobj.name,
15671 : 10 : agginfo->aggfn.rolname,
15672 : 10 : agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
15673 : :
15674 [ - + ]: 285 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 15675 :UBC 0 : dumpSecLabel(fout, "AGGREGATE", aggsig,
3491 sfrost@snowman.net 15676 : 0 : agginfo->aggfn.dobj.namespace->dobj.name,
15677 : 0 : agginfo->aggfn.rolname,
3050 tgl@sss.pgh.pa.us 15678 : 0 : agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
15679 : :
15680 : : /*
15681 : : * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
15682 : : * command look like a function's GRANT; in particular this affects the
15683 : : * syntax for zero-argument aggregates and ordered-set aggregates.
15684 : : */
7996 tgl@sss.pgh.pa.us 15685 :CBC 285 : free(aggsig);
15686 : :
5012 rhaas@postgresql.org 15687 : 285 : aggsig = format_function_signature(fout, &agginfo->aggfn, true);
15688 : :
3491 sfrost@snowman.net 15689 [ + + ]: 285 : if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
1934 tgl@sss.pgh.pa.us 15690 : 18 : dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
15691 : : "FUNCTION", aggsig, NULL,
3491 sfrost@snowman.net 15692 : 18 : agginfo->aggfn.dobj.namespace->dobj.name,
574 tgl@sss.pgh.pa.us 15693 : 18 : NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
15694 : :
7996 15695 : 285 : free(aggsig);
1229 peter@eisentraut.org 15696 : 285 : free(aggfullsig);
7996 tgl@sss.pgh.pa.us 15697 : 285 : free(aggsig_tag);
15698 : :
8571 15699 : 285 : PQclear(res);
15700 : :
15701 : 285 : destroyPQExpBuffer(query);
8851 15702 : 285 : destroyPQExpBuffer(q);
15703 : 285 : destroyPQExpBuffer(delq);
15704 : 285 : destroyPQExpBuffer(details);
15705 : : }
15706 : :
15707 : : /*
15708 : : * dumpTSParser
15709 : : * write out a single text search parser
15710 : : */
15711 : : static void
1720 peter@eisentraut.org 15712 : 41 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
15713 : : {
3575 tgl@sss.pgh.pa.us 15714 : 41 : DumpOptions *dopt = fout->dopt;
15715 : : PQExpBuffer q;
15716 : : PQExpBuffer delq;
15717 : : char *qprsname;
15718 : :
15719 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 15720 [ + + ]: 41 : if (!dopt->dumpSchema)
6642 tgl@sss.pgh.pa.us 15721 : 6 : return;
15722 : :
15723 : 35 : q = createPQExpBuffer();
15724 : 35 : delq = createPQExpBuffer();
15725 : :
2800 15726 : 35 : qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
15727 : :
6642 15728 : 35 : appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
2800 15729 : 35 : fmtQualifiedDumpable(prsinfo));
15730 : :
6642 15731 : 35 : appendPQExpBuffer(q, " START = %s,\n",
5011 rhaas@postgresql.org 15732 : 35 : convertTSFunction(fout, prsinfo->prsstart));
6642 tgl@sss.pgh.pa.us 15733 : 35 : appendPQExpBuffer(q, " GETTOKEN = %s,\n",
5011 rhaas@postgresql.org 15734 : 35 : convertTSFunction(fout, prsinfo->prstoken));
6642 tgl@sss.pgh.pa.us 15735 : 35 : appendPQExpBuffer(q, " END = %s,\n",
5011 rhaas@postgresql.org 15736 : 35 : convertTSFunction(fout, prsinfo->prsend));
6642 tgl@sss.pgh.pa.us 15737 [ + + ]: 35 : if (prsinfo->prsheadline != InvalidOid)
15738 : 3 : appendPQExpBuffer(q, " HEADLINE = %s,\n",
5011 rhaas@postgresql.org 15739 : 3 : convertTSFunction(fout, prsinfo->prsheadline));
6642 tgl@sss.pgh.pa.us 15740 : 35 : appendPQExpBuffer(q, " LEXTYPES = %s );\n",
5011 rhaas@postgresql.org 15741 : 35 : convertTSFunction(fout, prsinfo->prslextype));
15742 : :
2800 tgl@sss.pgh.pa.us 15743 : 35 : appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
15744 : 35 : fmtQualifiedDumpable(prsinfo));
15745 : :
4031 alvherre@alvh.no-ip. 15746 [ + + ]: 35 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 15747 : 1 : binary_upgrade_extension_member(q, &prsinfo->dobj,
15748 : : "TEXT SEARCH PARSER", qprsname,
15749 : 1 : prsinfo->dobj.namespace->dobj.name);
15750 : :
3491 sfrost@snowman.net 15751 [ + - ]: 35 : if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15752 : 35 : ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 15753 : 35 : ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
15754 : : .namespace = prsinfo->dobj.namespace->dobj.name,
15755 : : .description = "TEXT SEARCH PARSER",
15756 : : .section = SECTION_PRE_DATA,
15757 : : .createStmt = q->data,
15758 : : .dropStmt = delq->data));
15759 : :
15760 : : /* Dump Parser Comments */
3491 sfrost@snowman.net 15761 [ + - ]: 35 : if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 15762 : 35 : dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
3157 15763 : 35 : prsinfo->dobj.namespace->dobj.name, "",
3491 sfrost@snowman.net 15764 : 35 : prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
15765 : :
6642 tgl@sss.pgh.pa.us 15766 : 35 : destroyPQExpBuffer(q);
15767 : 35 : destroyPQExpBuffer(delq);
2800 15768 : 35 : free(qprsname);
15769 : : }
15770 : :
15771 : : /*
15772 : : * dumpTSDictionary
15773 : : * write out a single text search dictionary
15774 : : */
15775 : : static void
1720 peter@eisentraut.org 15776 : 173 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
15777 : : {
3575 tgl@sss.pgh.pa.us 15778 : 173 : DumpOptions *dopt = fout->dopt;
15779 : : PQExpBuffer q;
15780 : : PQExpBuffer delq;
15781 : : PQExpBuffer query;
15782 : : char *qdictname;
15783 : : PGresult *res;
15784 : : char *nspname;
15785 : : char *tmplname;
15786 : :
15787 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 15788 [ + + ]: 173 : if (!dopt->dumpSchema)
6642 tgl@sss.pgh.pa.us 15789 : 6 : return;
15790 : :
15791 : 167 : q = createPQExpBuffer();
15792 : 167 : delq = createPQExpBuffer();
15793 : 167 : query = createPQExpBuffer();
15794 : :
2800 15795 : 167 : qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
15796 : :
15797 : : /* Fetch name and namespace of the dictionary's template */
6642 15798 : 167 : appendPQExpBuffer(query, "SELECT nspname, tmplname "
15799 : : "FROM pg_ts_template p, pg_namespace n "
15800 : : "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
15801 : 167 : dictinfo->dicttemplate);
5002 rhaas@postgresql.org 15802 : 167 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
6642 tgl@sss.pgh.pa.us 15803 : 167 : nspname = PQgetvalue(res, 0, 0);
15804 : 167 : tmplname = PQgetvalue(res, 0, 1);
15805 : :
15806 : 167 : appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
2800 15807 : 167 : fmtQualifiedDumpable(dictinfo));
15808 : :
4361 heikki.linnakangas@i 15809 : 167 : appendPQExpBufferStr(q, " TEMPLATE = ");
2800 tgl@sss.pgh.pa.us 15810 : 167 : appendPQExpBuffer(q, "%s.", fmtId(nspname));
4361 heikki.linnakangas@i 15811 : 167 : appendPQExpBufferStr(q, fmtId(tmplname));
15812 : :
6642 tgl@sss.pgh.pa.us 15813 : 167 : PQclear(res);
15814 : :
15815 : : /* the dictinitoption can be dumped straight into the command */
15816 [ + + ]: 167 : if (dictinfo->dictinitoption)
6641 15817 : 132 : appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
15818 : :
4361 heikki.linnakangas@i 15819 : 167 : appendPQExpBufferStr(q, " );\n");
15820 : :
2800 tgl@sss.pgh.pa.us 15821 : 167 : appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
15822 : 167 : fmtQualifiedDumpable(dictinfo));
15823 : :
4031 alvherre@alvh.no-ip. 15824 [ + + ]: 167 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 15825 : 10 : binary_upgrade_extension_member(q, &dictinfo->dobj,
15826 : : "TEXT SEARCH DICTIONARY", qdictname,
15827 : 10 : dictinfo->dobj.namespace->dobj.name);
15828 : :
3491 sfrost@snowman.net 15829 [ + - ]: 167 : if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15830 : 167 : ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 15831 : 167 : ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
15832 : : .namespace = dictinfo->dobj.namespace->dobj.name,
15833 : : .owner = dictinfo->rolname,
15834 : : .description = "TEXT SEARCH DICTIONARY",
15835 : : .section = SECTION_PRE_DATA,
15836 : : .createStmt = q->data,
15837 : : .dropStmt = delq->data));
15838 : :
15839 : : /* Dump Dictionary Comments */
3491 sfrost@snowman.net 15840 [ + + ]: 167 : if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 15841 : 122 : dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
3157 15842 : 122 : dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
3491 sfrost@snowman.net 15843 : 122 : dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
15844 : :
6642 tgl@sss.pgh.pa.us 15845 : 167 : destroyPQExpBuffer(q);
15846 : 167 : destroyPQExpBuffer(delq);
15847 : 167 : destroyPQExpBuffer(query);
2800 15848 : 167 : free(qdictname);
15849 : : }
15850 : :
15851 : : /*
15852 : : * dumpTSTemplate
15853 : : * write out a single text search template
15854 : : */
15855 : : static void
1720 peter@eisentraut.org 15856 : 53 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
15857 : : {
3575 tgl@sss.pgh.pa.us 15858 : 53 : DumpOptions *dopt = fout->dopt;
15859 : : PQExpBuffer q;
15860 : : PQExpBuffer delq;
15861 : : char *qtmplname;
15862 : :
15863 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 15864 [ + + ]: 53 : if (!dopt->dumpSchema)
6642 tgl@sss.pgh.pa.us 15865 : 6 : return;
15866 : :
15867 : 47 : q = createPQExpBuffer();
15868 : 47 : delq = createPQExpBuffer();
15869 : :
2800 15870 : 47 : qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
15871 : :
6642 15872 : 47 : appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
2800 15873 : 47 : fmtQualifiedDumpable(tmplinfo));
15874 : :
6642 15875 [ + + ]: 47 : if (tmplinfo->tmplinit != InvalidOid)
15876 : 15 : appendPQExpBuffer(q, " INIT = %s,\n",
5011 rhaas@postgresql.org 15877 : 15 : convertTSFunction(fout, tmplinfo->tmplinit));
6642 tgl@sss.pgh.pa.us 15878 : 47 : appendPQExpBuffer(q, " LEXIZE = %s );\n",
5011 rhaas@postgresql.org 15879 : 47 : convertTSFunction(fout, tmplinfo->tmpllexize));
15880 : :
2800 tgl@sss.pgh.pa.us 15881 : 47 : appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
15882 : 47 : fmtQualifiedDumpable(tmplinfo));
15883 : :
4031 alvherre@alvh.no-ip. 15884 [ + + ]: 47 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 15885 : 1 : binary_upgrade_extension_member(q, &tmplinfo->dobj,
15886 : : "TEXT SEARCH TEMPLATE", qtmplname,
15887 : 1 : tmplinfo->dobj.namespace->dobj.name);
15888 : :
3491 sfrost@snowman.net 15889 [ + - ]: 47 : if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15890 : 47 : ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 15891 : 47 : ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
15892 : : .namespace = tmplinfo->dobj.namespace->dobj.name,
15893 : : .description = "TEXT SEARCH TEMPLATE",
15894 : : .section = SECTION_PRE_DATA,
15895 : : .createStmt = q->data,
15896 : : .dropStmt = delq->data));
15897 : :
15898 : : /* Dump Template Comments */
3491 sfrost@snowman.net 15899 [ + - ]: 47 : if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 15900 : 47 : dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
3157 15901 : 47 : tmplinfo->dobj.namespace->dobj.name, "",
3491 sfrost@snowman.net 15902 : 47 : tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
15903 : :
6642 tgl@sss.pgh.pa.us 15904 : 47 : destroyPQExpBuffer(q);
15905 : 47 : destroyPQExpBuffer(delq);
2800 15906 : 47 : free(qtmplname);
15907 : : }
15908 : :
15909 : : /*
15910 : : * dumpTSConfig
15911 : : * write out a single text search configuration
15912 : : */
15913 : : static void
1720 peter@eisentraut.org 15914 : 148 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
15915 : : {
3575 tgl@sss.pgh.pa.us 15916 : 148 : DumpOptions *dopt = fout->dopt;
15917 : : PQExpBuffer q;
15918 : : PQExpBuffer delq;
15919 : : PQExpBuffer query;
15920 : : char *qcfgname;
15921 : : PGresult *res;
15922 : : char *nspname;
15923 : : char *prsname;
15924 : : int ntups,
15925 : : i;
15926 : : int i_tokenname;
15927 : : int i_dictname;
15928 : :
15929 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 15930 [ + + ]: 148 : if (!dopt->dumpSchema)
6642 tgl@sss.pgh.pa.us 15931 : 6 : return;
15932 : :
15933 : 142 : q = createPQExpBuffer();
15934 : 142 : delq = createPQExpBuffer();
15935 : 142 : query = createPQExpBuffer();
15936 : :
2800 15937 : 142 : qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
15938 : :
15939 : : /* Fetch name and namespace of the config's parser */
6642 15940 : 142 : appendPQExpBuffer(query, "SELECT nspname, prsname "
15941 : : "FROM pg_ts_parser p, pg_namespace n "
15942 : : "WHERE p.oid = '%u' AND n.oid = prsnamespace",
15943 : 142 : cfginfo->cfgparser);
5002 rhaas@postgresql.org 15944 : 142 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
6642 tgl@sss.pgh.pa.us 15945 : 142 : nspname = PQgetvalue(res, 0, 0);
15946 : 142 : prsname = PQgetvalue(res, 0, 1);
15947 : :
15948 : 142 : appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
2800 15949 : 142 : fmtQualifiedDumpable(cfginfo));
15950 : :
15951 : 142 : appendPQExpBuffer(q, " PARSER = %s.", fmtId(nspname));
6642 15952 : 142 : appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
15953 : :
15954 : 142 : PQclear(res);
15955 : :
15956 : 142 : resetPQExpBuffer(query);
15957 : 142 : appendPQExpBuffer(query,
15958 : : "SELECT\n"
15959 : : " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
15960 : : " WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
15961 : : " m.mapdict::pg_catalog.regdictionary AS dictname\n"
15962 : : "FROM pg_catalog.pg_ts_config_map AS m\n"
15963 : : "WHERE m.mapcfg = '%u'\n"
15964 : : "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
15965 : 142 : cfginfo->cfgparser, cfginfo->dobj.catId.oid);
15966 : :
5011 rhaas@postgresql.org 15967 : 142 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6642 tgl@sss.pgh.pa.us 15968 : 142 : ntups = PQntuples(res);
15969 : :
15970 : 142 : i_tokenname = PQfnumber(res, "tokenname");
15971 : 142 : i_dictname = PQfnumber(res, "dictname");
15972 : :
15973 [ + + ]: 2975 : for (i = 0; i < ntups; i++)
15974 : : {
6556 bruce@momjian.us 15975 : 2833 : char *tokenname = PQgetvalue(res, i, i_tokenname);
15976 : 2833 : char *dictname = PQgetvalue(res, i, i_dictname);
15977 : :
6642 tgl@sss.pgh.pa.us 15978 [ + + ]: 2833 : if (i == 0 ||
6556 bruce@momjian.us 15979 [ + + ]: 2691 : strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
15980 : : {
15981 : : /* starting a new token type, so start a new command */
6642 tgl@sss.pgh.pa.us 15982 [ + + ]: 2698 : if (i > 0)
4361 heikki.linnakangas@i 15983 : 2556 : appendPQExpBufferStr(q, ";\n");
6642 tgl@sss.pgh.pa.us 15984 : 2698 : appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
2800 15985 : 2698 : fmtQualifiedDumpable(cfginfo));
15986 : : /* tokenname needs quoting, dictname does NOT */
6642 15987 : 2698 : appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
15988 : : fmtId(tokenname), dictname);
15989 : : }
15990 : : else
15991 : 135 : appendPQExpBuffer(q, ", %s", dictname);
15992 : : }
15993 : :
15994 [ + - ]: 142 : if (ntups > 0)
4361 heikki.linnakangas@i 15995 : 142 : appendPQExpBufferStr(q, ";\n");
15996 : :
6642 tgl@sss.pgh.pa.us 15997 : 142 : PQclear(res);
15998 : :
2800 15999 : 142 : appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
16000 : 142 : fmtQualifiedDumpable(cfginfo));
16001 : :
4031 alvherre@alvh.no-ip. 16002 [ + + ]: 142 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 16003 : 5 : binary_upgrade_extension_member(q, &cfginfo->dobj,
16004 : : "TEXT SEARCH CONFIGURATION", qcfgname,
16005 : 5 : cfginfo->dobj.namespace->dobj.name);
16006 : :
3491 sfrost@snowman.net 16007 [ + - ]: 142 : if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16008 : 142 : ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 16009 : 142 : ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
16010 : : .namespace = cfginfo->dobj.namespace->dobj.name,
16011 : : .owner = cfginfo->rolname,
16012 : : .description = "TEXT SEARCH CONFIGURATION",
16013 : : .section = SECTION_PRE_DATA,
16014 : : .createStmt = q->data,
16015 : : .dropStmt = delq->data));
16016 : :
16017 : : /* Dump Configuration Comments */
3491 sfrost@snowman.net 16018 [ + + ]: 142 : if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 16019 : 122 : dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
3157 16020 : 122 : cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
3491 sfrost@snowman.net 16021 : 122 : cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
16022 : :
6642 tgl@sss.pgh.pa.us 16023 : 142 : destroyPQExpBuffer(q);
16024 : 142 : destroyPQExpBuffer(delq);
16025 : 142 : destroyPQExpBuffer(query);
2800 16026 : 142 : free(qcfgname);
16027 : : }
16028 : :
16029 : : /*
16030 : : * dumpForeignDataWrapper
16031 : : * write out a single foreign-data wrapper definition
16032 : : */
16033 : : static void
1720 peter@eisentraut.org 16034 : 52 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
16035 : : {
3575 tgl@sss.pgh.pa.us 16036 : 52 : DumpOptions *dopt = fout->dopt;
16037 : : PQExpBuffer q;
16038 : : PQExpBuffer delq;
16039 : : char *qfdwname;
16040 : :
16041 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 16042 [ + + ]: 52 : if (!dopt->dumpSchema)
6156 peter_e@gmx.net 16043 : 7 : return;
16044 : :
16045 : 45 : q = createPQExpBuffer();
16046 : 45 : delq = createPQExpBuffer();
16047 : :
5085 bruce@momjian.us 16048 : 45 : qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
16049 : :
6089 peter_e@gmx.net 16050 : 45 : appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
16051 : : qfdwname);
16052 : :
5364 tgl@sss.pgh.pa.us 16053 [ - + ]: 45 : if (strcmp(fdwinfo->fdwhandler, "-") != 0)
5364 tgl@sss.pgh.pa.us 16054 :UBC 0 : appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
16055 : :
5364 tgl@sss.pgh.pa.us 16056 [ - + ]:CBC 45 : if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
5364 tgl@sss.pgh.pa.us 16057 :UBC 0 : appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
16058 : :
5364 tgl@sss.pgh.pa.us 16059 [ - + ]:CBC 45 : if (strlen(fdwinfo->fdwoptions) > 0)
5044 peter_e@gmx.net 16060 :UBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
16061 : :
4361 heikki.linnakangas@i 16062 :CBC 45 : appendPQExpBufferStr(q, ";\n");
16063 : :
6156 peter_e@gmx.net 16064 : 45 : appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
16065 : : qfdwname);
16066 : :
4031 alvherre@alvh.no-ip. 16067 [ + + ]: 45 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 16068 : 2 : binary_upgrade_extension_member(q, &fdwinfo->dobj,
16069 : : "FOREIGN DATA WRAPPER", qfdwname,
16070 : : NULL);
16071 : :
3491 sfrost@snowman.net 16072 [ + - ]: 45 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16073 : 45 : ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 16074 : 45 : ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
16075 : : .owner = fdwinfo->rolname,
16076 : : .description = "FOREIGN DATA WRAPPER",
16077 : : .section = SECTION_PRE_DATA,
16078 : : .createStmt = q->data,
16079 : : .dropStmt = delq->data));
16080 : :
16081 : : /* Dump Foreign Data Wrapper Comments */
2835 tgl@sss.pgh.pa.us 16082 [ - + ]: 45 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 16083 :UBC 0 : dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
2835 16084 : 0 : NULL, fdwinfo->rolname,
16085 : 0 : fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
16086 : :
16087 : : /* Handle the ACL */
3491 sfrost@snowman.net 16088 [ + + ]:CBC 45 : if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
1934 tgl@sss.pgh.pa.us 16089 : 31 : dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
16090 : : "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
1421 16091 : 31 : NULL, fdwinfo->rolname, &fdwinfo->dacl);
16092 : :
5374 16093 : 45 : free(qfdwname);
16094 : :
6156 peter_e@gmx.net 16095 : 45 : destroyPQExpBuffer(q);
16096 : 45 : destroyPQExpBuffer(delq);
16097 : : }
16098 : :
16099 : : /*
16100 : : * dumpForeignServer
16101 : : * write out a foreign server definition
16102 : : */
16103 : : static void
1720 peter@eisentraut.org 16104 : 56 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
16105 : : {
3575 tgl@sss.pgh.pa.us 16106 : 56 : DumpOptions *dopt = fout->dopt;
16107 : : PQExpBuffer q;
16108 : : PQExpBuffer delq;
16109 : : PQExpBuffer query;
16110 : : PGresult *res;
16111 : : char *qsrvname;
16112 : : char *fdwname;
16113 : :
16114 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 16115 [ + + ]: 56 : if (!dopt->dumpSchema)
6156 peter_e@gmx.net 16116 : 9 : return;
16117 : :
16118 : 47 : q = createPQExpBuffer();
16119 : 47 : delq = createPQExpBuffer();
16120 : 47 : query = createPQExpBuffer();
16121 : :
5085 bruce@momjian.us 16122 : 47 : qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
16123 : :
16124 : : /* look up the foreign-data wrapper */
6156 peter_e@gmx.net 16125 : 47 : appendPQExpBuffer(query, "SELECT fdwname "
16126 : : "FROM pg_foreign_data_wrapper w "
16127 : : "WHERE w.oid = '%u'",
16128 : 47 : srvinfo->srvfdw);
5002 rhaas@postgresql.org 16129 : 47 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
6156 peter_e@gmx.net 16130 : 47 : fdwname = PQgetvalue(res, 0, 0);
16131 : :
5374 tgl@sss.pgh.pa.us 16132 : 47 : appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
6156 peter_e@gmx.net 16133 [ + - - + ]: 47 : if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
16134 : : {
4361 heikki.linnakangas@i 16135 :UBC 0 : appendPQExpBufferStr(q, " TYPE ");
6046 16136 : 0 : appendStringLiteralAH(q, srvinfo->srvtype, fout);
16137 : : }
6156 peter_e@gmx.net 16138 [ + - - + ]:CBC 47 : if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
16139 : : {
4361 heikki.linnakangas@i 16140 :UBC 0 : appendPQExpBufferStr(q, " VERSION ");
6046 16141 : 0 : appendStringLiteralAH(q, srvinfo->srvversion, fout);
16142 : : }
16143 : :
4361 heikki.linnakangas@i 16144 :CBC 47 : appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
16145 : 47 : appendPQExpBufferStr(q, fmtId(fdwname));
16146 : :
6156 peter_e@gmx.net 16147 [ + - - + ]: 47 : if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
5044 peter_e@gmx.net 16148 :UBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
16149 : :
4361 heikki.linnakangas@i 16150 :CBC 47 : appendPQExpBufferStr(q, ";\n");
16151 : :
6156 peter_e@gmx.net 16152 : 47 : appendPQExpBuffer(delq, "DROP SERVER %s;\n",
16153 : : qsrvname);
16154 : :
4031 alvherre@alvh.no-ip. 16155 [ + + ]: 47 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 16156 : 2 : binary_upgrade_extension_member(q, &srvinfo->dobj,
16157 : : "SERVER", qsrvname, NULL);
16158 : :
3491 sfrost@snowman.net 16159 [ + - ]: 47 : if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16160 : 47 : ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 16161 : 47 : ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
16162 : : .owner = srvinfo->rolname,
16163 : : .description = "SERVER",
16164 : : .section = SECTION_PRE_DATA,
16165 : : .createStmt = q->data,
16166 : : .dropStmt = delq->data));
16167 : :
16168 : : /* Dump Foreign Server Comments */
2835 tgl@sss.pgh.pa.us 16169 [ - + ]: 47 : if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 16170 :UBC 0 : dumpComment(fout, "SERVER", qsrvname,
2835 16171 : 0 : NULL, srvinfo->rolname,
16172 : 0 : srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
16173 : :
16174 : : /* Handle the ACL */
3491 sfrost@snowman.net 16175 [ + + ]:CBC 47 : if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
1934 tgl@sss.pgh.pa.us 16176 : 31 : dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
16177 : : "FOREIGN SERVER", qsrvname, NULL, NULL,
1421 16178 : 31 : NULL, srvinfo->rolname, &srvinfo->dacl);
16179 : :
16180 : : /* Dump user mappings */
3491 sfrost@snowman.net 16181 [ + - ]: 47 : if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
16182 : 47 : dumpUserMappings(fout,
16183 : 47 : srvinfo->dobj.name, NULL,
16184 : 47 : srvinfo->rolname,
16185 : 47 : srvinfo->dobj.catId, srvinfo->dobj.dumpId);
16186 : :
1464 tgl@sss.pgh.pa.us 16187 : 47 : PQclear(res);
16188 : :
5374 16189 : 47 : free(qsrvname);
16190 : :
6156 peter_e@gmx.net 16191 : 47 : destroyPQExpBuffer(q);
16192 : 47 : destroyPQExpBuffer(delq);
3486 tgl@sss.pgh.pa.us 16193 : 47 : destroyPQExpBuffer(query);
16194 : : }
16195 : :
16196 : : /*
16197 : : * dumpUserMappings
16198 : : *
16199 : : * This routine is used to dump any user mappings associated with the
16200 : : * server handed to this routine. Should be called after ArchiveEntry()
16201 : : * for the server.
16202 : : */
16203 : : static void
5584 16204 : 47 : dumpUserMappings(Archive *fout,
16205 : : const char *servername, const char *namespace,
16206 : : const char *owner,
16207 : : CatalogId catalogId, DumpId dumpId)
16208 : : {
16209 : : PQExpBuffer q;
16210 : : PQExpBuffer delq;
16211 : : PQExpBuffer query;
16212 : : PQExpBuffer tag;
16213 : : PGresult *res;
16214 : : int ntups;
16215 : : int i_usename;
16216 : : int i_umoptions;
16217 : : int i;
16218 : :
6156 peter_e@gmx.net 16219 : 47 : q = createPQExpBuffer();
16220 : 47 : tag = createPQExpBuffer();
16221 : 47 : delq = createPQExpBuffer();
16222 : 47 : query = createPQExpBuffer();
16223 : :
16224 : : /*
16225 : : * We read from the publicly accessible view pg_user_mappings, so as not
16226 : : * to fail if run by a non-superuser. Note that the view will show
16227 : : * umoptions as null if the user hasn't got privileges for the associated
16228 : : * server; this means that pg_dump will dump such a mapping, but with no
16229 : : * OPTIONS clause. A possible alternative is to skip such mappings
16230 : : * altogether, but it's not clear that that's an improvement.
16231 : : */
16232 : 47 : appendPQExpBuffer(query,
16233 : : "SELECT usename, "
16234 : : "array_to_string(ARRAY("
16235 : : "SELECT quote_ident(option_name) || ' ' || "
16236 : : "quote_literal(option_value) "
16237 : : "FROM pg_options_to_table(umoptions) "
16238 : : "ORDER BY option_name"
16239 : : "), E',\n ') AS umoptions "
16240 : : "FROM pg_user_mappings "
16241 : : "WHERE srvid = '%u' "
16242 : : "ORDER BY usename",
16243 : : catalogId.oid);
16244 : :
5011 rhaas@postgresql.org 16245 : 47 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16246 : :
6156 peter_e@gmx.net 16247 : 47 : ntups = PQntuples(res);
5584 tgl@sss.pgh.pa.us 16248 : 47 : i_usename = PQfnumber(res, "usename");
6156 peter_e@gmx.net 16249 : 47 : i_umoptions = PQfnumber(res, "umoptions");
16250 : :
16251 [ + + ]: 78 : for (i = 0; i < ntups; i++)
16252 : : {
16253 : : char *usename;
16254 : : char *umoptions;
16255 : :
5584 tgl@sss.pgh.pa.us 16256 : 31 : usename = PQgetvalue(res, i, i_usename);
6156 peter_e@gmx.net 16257 : 31 : umoptions = PQgetvalue(res, i, i_umoptions);
16258 : :
16259 : 31 : resetPQExpBuffer(q);
5584 tgl@sss.pgh.pa.us 16260 : 31 : appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
6156 peter_e@gmx.net 16261 : 31 : appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
16262 : :
16263 [ + - - + ]: 31 : if (umoptions && strlen(umoptions) > 0)
5044 peter_e@gmx.net 16264 :UBC 0 : appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
16265 : :
4361 heikki.linnakangas@i 16266 :CBC 31 : appendPQExpBufferStr(q, ";\n");
16267 : :
6156 peter_e@gmx.net 16268 : 31 : resetPQExpBuffer(delq);
5584 tgl@sss.pgh.pa.us 16269 : 31 : appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
16270 : 31 : appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
16271 : :
6156 peter_e@gmx.net 16272 : 31 : resetPQExpBuffer(tag);
5584 tgl@sss.pgh.pa.us 16273 : 31 : appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
16274 : : usename, servername);
16275 : :
6156 peter_e@gmx.net 16276 : 31 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 16277 : 31 : ARCHIVE_OPTS(.tag = tag->data,
16278 : : .namespace = namespace,
16279 : : .owner = owner,
16280 : : .description = "USER MAPPING",
16281 : : .section = SECTION_PRE_DATA,
16282 : : .createStmt = q->data,
16283 : : .dropStmt = delq->data));
16284 : : }
16285 : :
6156 peter_e@gmx.net 16286 : 47 : PQclear(res);
16287 : :
16288 : 47 : destroyPQExpBuffer(query);
16289 : 47 : destroyPQExpBuffer(delq);
4258 sfrost@snowman.net 16290 : 47 : destroyPQExpBuffer(tag);
6156 peter_e@gmx.net 16291 : 47 : destroyPQExpBuffer(q);
16292 : 47 : }
16293 : :
16294 : : /*
16295 : : * Write out default privileges information
16296 : : */
16297 : : static void
1720 peter@eisentraut.org 16298 : 160 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
16299 : : {
3575 tgl@sss.pgh.pa.us 16300 : 160 : DumpOptions *dopt = fout->dopt;
16301 : : PQExpBuffer q;
16302 : : PQExpBuffer tag;
16303 : : const char *type;
16304 : :
16305 : : /* Do nothing if not dumping schema, or if we're skipping ACLs */
336 nathan@postgresql.or 16306 [ + + + + ]: 160 : if (!dopt->dumpSchema || dopt->aclsSkip)
5866 tgl@sss.pgh.pa.us 16307 : 28 : return;
16308 : :
16309 : 132 : q = createPQExpBuffer();
16310 : 132 : tag = createPQExpBuffer();
16311 : :
16312 [ + - + + : 132 : switch (daclinfo->defaclobjtype)
- - - ]
16313 : : {
16314 : 61 : case DEFACLOBJ_RELATION:
5859 16315 : 61 : type = "TABLES";
5866 16316 : 61 : break;
5866 tgl@sss.pgh.pa.us 16317 :UBC 0 : case DEFACLOBJ_SEQUENCE:
5859 16318 : 0 : type = "SEQUENCES";
5866 16319 : 0 : break;
5866 tgl@sss.pgh.pa.us 16320 :CBC 61 : case DEFACLOBJ_FUNCTION:
5859 16321 : 61 : type = "FUNCTIONS";
5866 16322 : 61 : break;
4705 16323 : 10 : case DEFACLOBJ_TYPE:
16324 : 10 : type = "TYPES";
16325 : 10 : break;
3135 teodor@sigaev.ru 16326 :UBC 0 : case DEFACLOBJ_NAMESPACE:
16327 : 0 : type = "SCHEMAS";
16328 : 0 : break;
206 fujii@postgresql.org 16329 : 0 : case DEFACLOBJ_LARGEOBJECT:
16330 : 0 : type = "LARGE OBJECTS";
16331 : 0 : break;
5866 tgl@sss.pgh.pa.us 16332 : 0 : default:
16333 : : /* shouldn't get here */
1298 16334 : 0 : pg_fatal("unrecognized object type in default privileges: %d",
16335 : : (int) daclinfo->defaclobjtype);
16336 : : type = ""; /* keep compiler quiet */
16337 : : }
16338 : :
5859 tgl@sss.pgh.pa.us 16339 :CBC 132 : appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
16340 : :
16341 : : /* build the actual command(s) for this tuple */
5866 16342 [ - + ]: 132 : if (!buildDefaultACLCommands(type,
16343 : 132 : daclinfo->dobj.namespace != NULL ?
16344 : 62 : daclinfo->dobj.namespace->dobj.name : NULL,
1421 16345 : 132 : daclinfo->dacl.acl,
16346 : 132 : daclinfo->dacl.acldefault,
5866 16347 [ + + ]: 132 : daclinfo->defaclrole,
16348 : : fout->remoteVersion,
16349 : : q))
1298 tgl@sss.pgh.pa.us 16350 :UBC 0 : pg_fatal("could not parse default ACL list (%s)",
16351 : : daclinfo->dacl.acl);
16352 : :
3491 sfrost@snowman.net 16353 [ + - ]:CBC 132 : if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
16354 : 132 : ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 16355 [ + + ]: 132 : ARCHIVE_OPTS(.tag = tag->data,
16356 : : .namespace = daclinfo->dobj.namespace ?
16357 : : daclinfo->dobj.namespace->dobj.name : NULL,
16358 : : .owner = daclinfo->defaclrole,
16359 : : .description = "DEFAULT ACL",
16360 : : .section = SECTION_POST_DATA,
16361 : : .createStmt = q->data));
16362 : :
5866 tgl@sss.pgh.pa.us 16363 : 132 : destroyPQExpBuffer(tag);
16364 : 132 : destroyPQExpBuffer(q);
16365 : : }
16366 : :
16367 : : /*----------
16368 : : * Write out grant/revoke information
16369 : : *
16370 : : * 'objDumpId' is the dump ID of the underlying object.
16371 : : * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
16372 : : * or InvalidDumpId if there is no need for a second dependency.
16373 : : * 'type' must be one of
16374 : : * TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
16375 : : * FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
16376 : : * 'name' is the formatted name of the object. Must be quoted etc. already.
16377 : : * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
16378 : : * (Currently we assume that subname is only provided for table columns.)
16379 : : * 'nspname' is the namespace the object is in (NULL if none).
16380 : : * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
16381 : : * to use the default for the object type.
16382 : : * 'owner' is the owner, NULL if there is no owner (for languages).
16383 : : * 'dacl' is the DumpableAcl struct for the object.
16384 : : *
16385 : : * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
16386 : : * no ACL entry was created.
16387 : : *----------
16388 : : */
16389 : : static DumpId
1934 16390 : 29180 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
16391 : : const char *type, const char *name, const char *subname,
16392 : : const char *nspname, const char *tag, const char *owner,
16393 : : const DumpableAcl *dacl)
16394 : : {
16395 : 29180 : DumpId aclDumpId = InvalidDumpId;
3575 16396 : 29180 : DumpOptions *dopt = fout->dopt;
1421 16397 : 29180 : const char *acls = dacl->acl;
16398 : 29180 : const char *acldefault = dacl->acldefault;
16399 : 29180 : char privtype = dacl->privtype;
16400 : 29180 : const char *initprivs = dacl->initprivs;
16401 : : const char *baseacls;
16402 : : PQExpBuffer sql;
16403 : :
16404 : : /* Do nothing if ACL dump is not enabled */
4031 alvherre@alvh.no-ip. 16405 [ + + ]: 29180 : if (dopt->aclsSkip)
1934 tgl@sss.pgh.pa.us 16406 : 326 : return InvalidDumpId;
16407 : :
16408 : : /* --data-only skips ACLs *except* large object ACLs */
336 nathan@postgresql.or 16409 [ + + - + ]: 28854 : if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
1934 tgl@sss.pgh.pa.us 16410 :UBC 0 : return InvalidDumpId;
16411 : :
8575 tgl@sss.pgh.pa.us 16412 :CBC 28854 : sql = createPQExpBuffer();
16413 : :
16414 : : /*
16415 : : * In binary upgrade mode, we don't run an extension's script but instead
16416 : : * dump out the objects independently and then recreate them. To preserve
16417 : : * any initial privileges which were set on extension objects, we need to
16418 : : * compute the set of GRANT and REVOKE commands necessary to get from the
16419 : : * default privileges of an object to its initial privileges as recorded
16420 : : * in pg_init_privs.
16421 : : *
16422 : : * At restore time, we apply these commands after having called
16423 : : * binary_upgrade_set_record_init_privs(true). That tells the backend to
16424 : : * copy the results into pg_init_privs. This is how we preserve the
16425 : : * contents of that catalog across binary upgrades.
16426 : : */
1421 16427 [ + + + + : 28854 : if (dopt->binary_upgrade && privtype == 'e' &&
+ - ]
16428 [ + - ]: 13 : initprivs && *initprivs != '\0')
16429 : : {
2307 drowley@postgresql.o 16430 : 13 : appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
2800 tgl@sss.pgh.pa.us 16431 [ - + ]: 13 : if (!buildACLCommands(name, subname, nspname, type,
16432 : : initprivs, acldefault, owner,
16433 : : "", fout->remoteVersion, sql))
1298 tgl@sss.pgh.pa.us 16434 :UBC 0 : pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
16435 : : initprivs, acldefault, name, type);
2307 drowley@postgresql.o 16436 :CBC 13 : appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
16437 : : }
16438 : :
16439 : : /*
16440 : : * Now figure the GRANT and REVOKE commands needed to get to the object's
16441 : : * actual current ACL, starting from the initprivs if given, else from the
16442 : : * object-type-specific default. Also, while buildACLCommands will assume
16443 : : * that a NULL/empty acls string means it needn't do anything, what that
16444 : : * actually represents is the object-type-specific default; so we need to
16445 : : * substitute the acldefault string to get the right results in that case.
16446 : : */
1421 tgl@sss.pgh.pa.us 16447 [ + + + + ]: 28854 : if (initprivs && *initprivs != '\0')
16448 : : {
16449 : 27126 : baseacls = initprivs;
16450 [ + - + + ]: 27126 : if (acls == NULL || *acls == '\0')
16451 : 17 : acls = acldefault;
16452 : : }
16453 : : else
16454 : 1728 : baseacls = acldefault;
16455 : :
2800 16456 [ - + ]: 28854 : if (!buildACLCommands(name, subname, nspname, type,
16457 : : acls, baseacls, owner,
16458 : : "", fout->remoteVersion, sql))
1298 tgl@sss.pgh.pa.us 16459 :UBC 0 : pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
16460 : : acls, baseacls, name, type);
16461 : :
8186 tgl@sss.pgh.pa.us 16462 [ + + ]:CBC 28854 : if (sql->len > 0)
16463 : : {
574 16464 : 1784 : PQExpBuffer tagbuf = createPQExpBuffer();
16465 : : DumpId aclDeps[2];
1934 16466 : 1784 : int nDeps = 0;
16467 : :
574 16468 [ - + ]: 1784 : if (tag)
574 tgl@sss.pgh.pa.us 16469 :UBC 0 : appendPQExpBufferStr(tagbuf, tag);
574 tgl@sss.pgh.pa.us 16470 [ + + ]:CBC 1784 : else if (subname)
16471 : 1047 : appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
16472 : : else
16473 : 737 : appendPQExpBuffer(tagbuf, "%s %s", type, name);
16474 : :
1934 16475 : 1784 : aclDeps[nDeps++] = objDumpId;
16476 [ + + ]: 1784 : if (altDumpId != InvalidDumpId)
16477 : 963 : aclDeps[nDeps++] = altDumpId;
16478 : :
16479 : 1784 : aclDumpId = createDumpId();
16480 : :
16481 : 1784 : ArchiveEntry(fout, nilCatalogId, aclDumpId,
574 16482 : 1784 : ARCHIVE_OPTS(.tag = tagbuf->data,
16483 : : .namespace = nspname,
16484 : : .owner = owner,
16485 : : .description = "ACL",
16486 : : .section = SECTION_NONE,
16487 : : .createStmt = sql->data,
16488 : : .deps = aclDeps,
16489 : : .nDeps = nDeps));
16490 : :
16491 : 1784 : destroyPQExpBuffer(tagbuf);
16492 : : }
16493 : :
8575 16494 : 28854 : destroyPQExpBuffer(sql);
16495 : :
1934 16496 : 28854 : return aclDumpId;
16497 : : }
16498 : :
16499 : : /*
16500 : : * dumpSecLabel
16501 : : *
16502 : : * This routine is used to dump any security labels associated with the
16503 : : * object handed to this routine. The routine takes the object type
16504 : : * and object name (ready to print, except for schema decoration), plus
16505 : : * the namespace and owner of the object (for labeling the ArchiveEntry),
16506 : : * plus catalog ID and subid which are the lookup key for pg_seclabel,
16507 : : * plus the dump ID for the object (for setting a dependency).
16508 : : * If a matching pg_seclabel entry is found, it is dumped.
16509 : : *
16510 : : * Note: although this routine takes a dumpId for dependency purposes,
16511 : : * that purpose is just to mark the dependency in the emitted dump file
16512 : : * for possible future use by pg_restore. We do NOT use it for determining
16513 : : * ordering of the label in the dump file, because this routine is called
16514 : : * after dependency sorting occurs. This routine should be called just after
16515 : : * calling ArchiveEntry() for the specified object.
16516 : : */
16517 : : static void
2800 tgl@sss.pgh.pa.us 16518 :GBC 10 : dumpSecLabel(Archive *fout, const char *type, const char *name,
16519 : : const char *namespace, const char *owner,
16520 : : CatalogId catalogId, int subid, DumpId dumpId)
16521 : : {
3575 16522 : 10 : DumpOptions *dopt = fout->dopt;
16523 : : SecLabelItem *labels;
16524 : : int nlabels;
16525 : : int i;
16526 : : PQExpBuffer query;
16527 : :
16528 : : /* do nothing, if --no-security-labels is supplied */
4031 alvherre@alvh.no-ip. 16529 [ - + ]: 10 : if (dopt->no_security_labels)
5509 rhaas@postgresql.org 16530 :UBC 0 : return;
16531 : :
16532 : : /*
16533 : : * Security labels are schema not data ... except large object labels are
16534 : : * data
16535 : : */
2800 tgl@sss.pgh.pa.us 16536 [ - + ]:GBC 10 : if (strcmp(type, "LARGE OBJECT") != 0)
16537 : : {
336 nathan@postgresql.or 16538 [ # # ]:UBC 0 : if (!dopt->dumpSchema)
5509 rhaas@postgresql.org 16539 : 0 : return;
16540 : : }
16541 : : else
16542 : : {
16543 : : /* We do dump large object security labels in binary-upgrade mode */
336 nathan@postgresql.or 16544 [ + - - + ]:GBC 10 : if (!dopt->dumpData && !dopt->binary_upgrade)
5509 rhaas@postgresql.org 16545 :UBC 0 : return;
16546 : : }
16547 : :
16548 : : /* Search for security labels associated with catalogId, using table */
1397 tgl@sss.pgh.pa.us 16549 :GBC 10 : nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
16550 : :
5509 rhaas@postgresql.org 16551 : 10 : query = createPQExpBuffer();
16552 : :
16553 [ + + ]: 15 : for (i = 0; i < nlabels; i++)
16554 : : {
16555 : : /*
16556 : : * Ignore label entries for which the subid doesn't match.
16557 : : */
16558 [ - + ]: 5 : if (labels[i].objsubid != subid)
5509 rhaas@postgresql.org 16559 :UBC 0 : continue;
16560 : :
5509 rhaas@postgresql.org 16561 :GBC 5 : appendPQExpBuffer(query,
16562 : : "SECURITY LABEL FOR %s ON %s ",
2800 tgl@sss.pgh.pa.us 16563 : 5 : fmtId(labels[i].provider), type);
16564 [ - + - - ]: 5 : if (namespace && *namespace)
2800 tgl@sss.pgh.pa.us 16565 :UBC 0 : appendPQExpBuffer(query, "%s.", fmtId(namespace));
2800 tgl@sss.pgh.pa.us 16566 :GBC 5 : appendPQExpBuffer(query, "%s IS ", name);
5509 rhaas@postgresql.org 16567 : 5 : appendStringLiteralAH(query, labels[i].label, fout);
4361 heikki.linnakangas@i 16568 : 5 : appendPQExpBufferStr(query, ";\n");
16569 : : }
16570 : :
5509 rhaas@postgresql.org 16571 [ + + ]: 10 : if (query->len > 0)
16572 : : {
2800 tgl@sss.pgh.pa.us 16573 : 5 : PQExpBuffer tag = createPQExpBuffer();
16574 : :
16575 : 5 : appendPQExpBuffer(tag, "%s %s", type, name);
5509 rhaas@postgresql.org 16576 : 5 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 16577 : 5 : ARCHIVE_OPTS(.tag = tag->data,
16578 : : .namespace = namespace,
16579 : : .owner = owner,
16580 : : .description = "SECURITY LABEL",
16581 : : .section = SECTION_NONE,
16582 : : .createStmt = query->data,
16583 : : .deps = &dumpId,
16584 : : .nDeps = 1));
2800 tgl@sss.pgh.pa.us 16585 : 5 : destroyPQExpBuffer(tag);
16586 : : }
16587 : :
5509 rhaas@postgresql.org 16588 : 10 : destroyPQExpBuffer(query);
16589 : : }
16590 : :
16591 : : /*
16592 : : * dumpTableSecLabel
16593 : : *
16594 : : * As above, but dump security label for both the specified table (or view)
16595 : : * and its columns.
16596 : : */
16597 : : static void
1720 peter@eisentraut.org 16598 :UBC 0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
16599 : : {
3575 tgl@sss.pgh.pa.us 16600 : 0 : DumpOptions *dopt = fout->dopt;
16601 : : SecLabelItem *labels;
16602 : : int nlabels;
16603 : : int i;
16604 : : PQExpBuffer query;
16605 : : PQExpBuffer target;
16606 : :
16607 : : /* do nothing, if --no-security-labels is supplied */
4031 alvherre@alvh.no-ip. 16608 [ # # ]: 0 : if (dopt->no_security_labels)
5509 rhaas@postgresql.org 16609 : 0 : return;
16610 : :
16611 : : /* SecLabel are SCHEMA not data */
336 nathan@postgresql.or 16612 [ # # ]: 0 : if (!dopt->dumpSchema)
5509 rhaas@postgresql.org 16613 : 0 : return;
16614 : :
16615 : : /* Search for comments associated with relation, using table */
1397 tgl@sss.pgh.pa.us 16616 : 0 : nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
5509 rhaas@postgresql.org 16617 : 0 : tbinfo->dobj.catId.oid,
16618 : : &labels);
16619 : :
16620 : : /* If security labels exist, build SECURITY LABEL statements */
16621 [ # # ]: 0 : if (nlabels <= 0)
16622 : 0 : return;
16623 : :
16624 : 0 : query = createPQExpBuffer();
16625 : 0 : target = createPQExpBuffer();
16626 : :
16627 [ # # ]: 0 : for (i = 0; i < nlabels; i++)
16628 : : {
16629 : : const char *colname;
5314 bruce@momjian.us 16630 : 0 : const char *provider = labels[i].provider;
16631 : 0 : const char *label = labels[i].label;
16632 : 0 : int objsubid = labels[i].objsubid;
16633 : :
5509 rhaas@postgresql.org 16634 : 0 : resetPQExpBuffer(target);
16635 [ # # ]: 0 : if (objsubid == 0)
16636 : : {
16637 : 0 : appendPQExpBuffer(target, "%s %s", reltypename,
2800 tgl@sss.pgh.pa.us 16638 : 0 : fmtQualifiedDumpable(tbinfo));
16639 : : }
16640 : : else
16641 : : {
5509 rhaas@postgresql.org 16642 : 0 : colname = getAttrName(objsubid, tbinfo);
16643 : : /* first fmtXXX result must be consumed before calling again */
2800 tgl@sss.pgh.pa.us 16644 : 0 : appendPQExpBuffer(target, "COLUMN %s",
16645 : 0 : fmtQualifiedDumpable(tbinfo));
5413 rhaas@postgresql.org 16646 : 0 : appendPQExpBuffer(target, ".%s", fmtId(colname));
16647 : : }
5509 16648 : 0 : appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
16649 : : fmtId(provider), target->data);
16650 : 0 : appendStringLiteralAH(query, label, fout);
4361 heikki.linnakangas@i 16651 : 0 : appendPQExpBufferStr(query, ";\n");
16652 : : }
5509 rhaas@postgresql.org 16653 [ # # ]: 0 : if (query->len > 0)
16654 : : {
16655 : 0 : resetPQExpBuffer(target);
16656 : 0 : appendPQExpBuffer(target, "%s %s", reltypename,
16657 : 0 : fmtId(tbinfo->dobj.name));
16658 : 0 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 16659 : 0 : ARCHIVE_OPTS(.tag = target->data,
16660 : : .namespace = tbinfo->dobj.namespace->dobj.name,
16661 : : .owner = tbinfo->rolname,
16662 : : .description = "SECURITY LABEL",
16663 : : .section = SECTION_NONE,
16664 : : .createStmt = query->data,
16665 : : .deps = &(tbinfo->dobj.dumpId),
16666 : : .nDeps = 1));
16667 : : }
5509 rhaas@postgresql.org 16668 : 0 : destroyPQExpBuffer(query);
16669 : 0 : destroyPQExpBuffer(target);
16670 : : }
16671 : :
16672 : : /*
16673 : : * findSecLabels
16674 : : *
16675 : : * Find the security label(s), if any, associated with the given object.
16676 : : * All the objsubid values associated with the given classoid/objoid are
16677 : : * found with one search.
16678 : : */
16679 : : static int
1397 tgl@sss.pgh.pa.us 16680 :GBC 10 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
16681 : : {
5314 bruce@momjian.us 16682 : 10 : SecLabelItem *middle = NULL;
16683 : : SecLabelItem *low;
16684 : : SecLabelItem *high;
16685 : : int nmatch;
16686 : :
1421 tgl@sss.pgh.pa.us 16687 [ - + ]: 10 : if (nseclabels <= 0) /* no labels, so no match is possible */
16688 : : {
5100 tgl@sss.pgh.pa.us 16689 :UBC 0 : *items = NULL;
16690 : 0 : return 0;
16691 : : }
16692 : :
16693 : : /*
16694 : : * Do binary search to find some item matching the object.
16695 : : */
1421 tgl@sss.pgh.pa.us 16696 :GBC 10 : low = &seclabels[0];
16697 : 10 : high = &seclabels[nseclabels - 1];
5509 rhaas@postgresql.org 16698 [ + + ]: 15 : while (low <= high)
16699 : : {
16700 : 10 : middle = low + (high - low) / 2;
16701 : :
16702 [ - + ]: 10 : if (classoid < middle->classoid)
5509 rhaas@postgresql.org 16703 :UBC 0 : high = middle - 1;
5509 rhaas@postgresql.org 16704 [ - + ]:GBC 10 : else if (classoid > middle->classoid)
5509 rhaas@postgresql.org 16705 :UBC 0 : low = middle + 1;
5509 rhaas@postgresql.org 16706 [ + + ]:GBC 10 : else if (objoid < middle->objoid)
16707 : 5 : high = middle - 1;
16708 [ - + ]: 5 : else if (objoid > middle->objoid)
5509 rhaas@postgresql.org 16709 :UBC 0 : low = middle + 1;
16710 : : else
5314 bruce@momjian.us 16711 :GBC 5 : break; /* found a match */
16712 : : }
16713 : :
16714 [ + + ]: 10 : if (low > high) /* no matches */
16715 : : {
5509 rhaas@postgresql.org 16716 : 5 : *items = NULL;
16717 : 5 : return 0;
16718 : : }
16719 : :
16720 : : /*
16721 : : * Now determine how many items match the object. The search loop
16722 : : * invariant still holds: only items between low and high inclusive could
16723 : : * match.
16724 : : */
16725 : 5 : nmatch = 1;
16726 [ - + ]: 5 : while (middle > low)
16727 : : {
5509 rhaas@postgresql.org 16728 [ # # ]:UBC 0 : if (classoid != middle[-1].classoid ||
16729 [ # # ]: 0 : objoid != middle[-1].objoid)
16730 : : break;
16731 : 0 : middle--;
16732 : 0 : nmatch++;
16733 : : }
16734 : :
5509 rhaas@postgresql.org 16735 :GBC 5 : *items = middle;
16736 : :
16737 : 5 : middle += nmatch;
16738 [ - + ]: 5 : while (middle <= high)
16739 : : {
5509 rhaas@postgresql.org 16740 [ # # ]:UBC 0 : if (classoid != middle->classoid ||
16741 [ # # ]: 0 : objoid != middle->objoid)
16742 : : break;
16743 : 0 : middle++;
16744 : 0 : nmatch++;
16745 : : }
16746 : :
5509 rhaas@postgresql.org 16747 :GBC 5 : return nmatch;
16748 : : }
16749 : :
16750 : : /*
16751 : : * collectSecLabels
16752 : : *
16753 : : * Construct a table of all security labels available for database objects;
16754 : : * also set the has-seclabel component flag for each relevant object.
16755 : : *
16756 : : * The table is sorted by classoid/objid/objsubid for speed in lookup.
16757 : : */
16758 : : static void
1421 tgl@sss.pgh.pa.us 16759 :CBC 189 : collectSecLabels(Archive *fout)
16760 : : {
16761 : : PGresult *res;
16762 : : PQExpBuffer query;
16763 : : int i_label;
16764 : : int i_provider;
16765 : : int i_classoid;
16766 : : int i_objoid;
16767 : : int i_objsubid;
16768 : : int ntups;
16769 : : int i;
16770 : : DumpableObject *dobj;
16771 : :
5509 rhaas@postgresql.org 16772 : 189 : query = createPQExpBuffer();
16773 : :
4361 heikki.linnakangas@i 16774 : 189 : appendPQExpBufferStr(query,
16775 : : "SELECT label, provider, classoid, objoid, objsubid "
16776 : : "FROM pg_catalog.pg_seclabels "
16777 : : "ORDER BY classoid, objoid, objsubid");
16778 : :
5011 rhaas@postgresql.org 16779 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16780 : :
16781 : : /* Construct lookup table containing OIDs in numeric form */
5314 bruce@momjian.us 16782 : 189 : i_label = PQfnumber(res, "label");
16783 : 189 : i_provider = PQfnumber(res, "provider");
16784 : 189 : i_classoid = PQfnumber(res, "classoid");
16785 : 189 : i_objoid = PQfnumber(res, "objoid");
16786 : 189 : i_objsubid = PQfnumber(res, "objsubid");
16787 : :
5509 rhaas@postgresql.org 16788 : 189 : ntups = PQntuples(res);
16789 : :
1421 tgl@sss.pgh.pa.us 16790 : 189 : seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
16791 : 189 : nseclabels = 0;
16792 : 189 : dobj = NULL;
16793 : :
5509 rhaas@postgresql.org 16794 [ + + ]: 194 : for (i = 0; i < ntups; i++)
16795 : : {
16796 : : CatalogId objId;
16797 : : int subid;
16798 : :
1421 tgl@sss.pgh.pa.us 16799 :GBC 5 : objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
16800 : 5 : objId.oid = atooid(PQgetvalue(res, i, i_objoid));
16801 : 5 : subid = atoi(PQgetvalue(res, i, i_objsubid));
16802 : :
16803 : : /* We needn't remember labels that don't match any dumpable object */
16804 [ - + ]: 5 : if (dobj == NULL ||
1421 tgl@sss.pgh.pa.us 16805 [ # # ]:UBC 0 : dobj->catId.tableoid != objId.tableoid ||
16806 [ # # ]: 0 : dobj->catId.oid != objId.oid)
1421 tgl@sss.pgh.pa.us 16807 :GBC 5 : dobj = findObjectByCatalogId(objId);
16808 [ - + ]: 5 : if (dobj == NULL)
1421 tgl@sss.pgh.pa.us 16809 :UBC 0 : continue;
16810 : :
16811 : : /*
16812 : : * Labels on columns of composite types are linked to the type's
16813 : : * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
16814 : : * in the type's own DumpableObject.
16815 : : */
1421 tgl@sss.pgh.pa.us 16816 [ - + - - ]:GBC 5 : if (subid != 0 && dobj->objType == DO_TABLE &&
1421 tgl@sss.pgh.pa.us 16817 [ # # ]:UBC 0 : ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
16818 : 0 : {
16819 : : TypeInfo *cTypeInfo;
16820 : :
16821 : 0 : cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
16822 [ # # ]: 0 : if (cTypeInfo)
16823 : 0 : cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
16824 : : }
16825 : : else
1421 tgl@sss.pgh.pa.us 16826 :GBC 5 : dobj->components |= DUMP_COMPONENT_SECLABEL;
16827 : :
16828 : 5 : seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
16829 : 5 : seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
16830 : 5 : seclabels[nseclabels].classoid = objId.tableoid;
16831 : 5 : seclabels[nseclabels].objoid = objId.oid;
16832 : 5 : seclabels[nseclabels].objsubid = subid;
16833 : 5 : nseclabels++;
16834 : : }
16835 : :
1421 tgl@sss.pgh.pa.us 16836 :CBC 189 : PQclear(res);
5314 bruce@momjian.us 16837 : 189 : destroyPQExpBuffer(query);
5509 rhaas@postgresql.org 16838 : 189 : }
16839 : :
16840 : : /*
16841 : : * dumpTable
16842 : : * write out to fout the declarations (not data) of a user-defined table
16843 : : */
16844 : : static void
1720 peter@eisentraut.org 16845 : 31464 : dumpTable(Archive *fout, const TableInfo *tbinfo)
16846 : : {
3491 sfrost@snowman.net 16847 : 31464 : DumpOptions *dopt = fout->dopt;
1934 tgl@sss.pgh.pa.us 16848 : 31464 : DumpId tableAclDumpId = InvalidDumpId;
16849 : : char *namecopy;
16850 : :
16851 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 16852 [ + + ]: 31464 : if (!dopt->dumpSchema)
3489 sfrost@snowman.net 16853 : 1508 : return;
16854 : :
1421 tgl@sss.pgh.pa.us 16855 [ + + ]: 29956 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16856 : : {
16857 [ + + ]: 6589 : if (tbinfo->relkind == RELKIND_SEQUENCE)
16858 : 375 : dumpSequence(fout, tbinfo);
16859 : : else
16860 : 6214 : dumpTableSchema(fout, tbinfo);
16861 : : }
16862 : :
16863 : : /* Handle the ACL here */
3491 sfrost@snowman.net 16864 : 29956 : namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
16865 [ + + ]: 29956 : if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
16866 : : {
2835 tgl@sss.pgh.pa.us 16867 : 24088 : const char *objtype =
892 16868 [ + + ]: 24088 : (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
16869 : :
16870 : : tableAclDumpId =
1934 16871 : 24088 : dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
16872 : : objtype, namecopy, NULL,
574 16873 : 24088 : tbinfo->dobj.namespace->dobj.name,
16874 : 24088 : NULL, tbinfo->rolname, &tbinfo->dacl);
16875 : : }
16876 : :
16877 : : /*
16878 : : * Handle column ACLs, if any. Note: we pull these with a separate query
16879 : : * rather than trying to fetch them during getTableAttrs, so that we won't
16880 : : * miss ACLs on system columns. Doing it this way also allows us to dump
16881 : : * ACLs for catalogs that we didn't mark "interesting" back in getTables.
16882 : : */
1421 16883 [ + + + + ]: 29956 : if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
16884 : : {
3491 sfrost@snowman.net 16885 : 284 : PQExpBuffer query = createPQExpBuffer();
16886 : : PGresult *res;
16887 : : int i;
16888 : :
1421 tgl@sss.pgh.pa.us 16889 [ + + ]: 284 : if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
16890 : : {
16891 : : /* Set up query for column ACLs */
16892 : 163 : appendPQExpBufferStr(query,
16893 : : "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
16894 : :
16895 [ + - ]: 163 : if (fout->remoteVersion >= 90600)
16896 : : {
16897 : : /*
16898 : : * In principle we should call acldefault('c', relowner) to
16899 : : * get the default ACL for a column. However, we don't
16900 : : * currently store the numeric OID of the relowner in
16901 : : * TableInfo. We could convert the owner name using regrole,
16902 : : * but that creates a risk of failure due to concurrent role
16903 : : * renames. Given that the default ACL for columns is empty
16904 : : * and is likely to stay that way, it's not worth extra cycles
16905 : : * and risk to avoid hard-wiring that knowledge here.
16906 : : */
16907 : 163 : appendPQExpBufferStr(query,
16908 : : "SELECT at.attname, "
16909 : : "at.attacl, "
16910 : : "'{}' AS acldefault, "
16911 : : "pip.privtype, pip.initprivs "
16912 : : "FROM pg_catalog.pg_attribute at "
16913 : : "LEFT JOIN pg_catalog.pg_init_privs pip ON "
16914 : : "(at.attrelid = pip.objoid "
16915 : : "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
16916 : : "AND at.attnum = pip.objsubid) "
16917 : : "WHERE at.attrelid = $1 AND "
16918 : : "NOT at.attisdropped "
16919 : : "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
16920 : : "ORDER BY at.attnum");
16921 : : }
16922 : : else
16923 : : {
1421 tgl@sss.pgh.pa.us 16924 :UBC 0 : appendPQExpBufferStr(query,
16925 : : "SELECT attname, attacl, '{}' AS acldefault, "
16926 : : "NULL AS privtype, NULL AS initprivs "
16927 : : "FROM pg_catalog.pg_attribute "
16928 : : "WHERE attrelid = $1 AND NOT attisdropped "
16929 : : "AND attacl IS NOT NULL "
16930 : : "ORDER BY attnum");
16931 : : }
16932 : :
1421 tgl@sss.pgh.pa.us 16933 :CBC 163 : ExecuteSqlStatement(fout, query->data);
16934 : :
16935 : 163 : fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
16936 : : }
16937 : :
16938 : 284 : printfPQExpBuffer(query,
16939 : : "EXECUTE getColumnACLs('%u')",
16940 : 284 : tbinfo->dobj.catId.oid);
16941 : :
3491 sfrost@snowman.net 16942 : 284 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16943 : :
16944 [ + + ]: 4531 : for (i = 0; i < PQntuples(res); i++)
16945 : : {
16946 : 4247 : char *attname = PQgetvalue(res, i, 0);
16947 : 4247 : char *attacl = PQgetvalue(res, i, 1);
1421 tgl@sss.pgh.pa.us 16948 : 4247 : char *acldefault = PQgetvalue(res, i, 2);
16949 : 4247 : char privtype = *(PQgetvalue(res, i, 3));
16950 : 4247 : char *initprivs = PQgetvalue(res, i, 4);
16951 : : DumpableAcl coldacl;
16952 : : char *attnamecopy;
16953 : :
16954 : 4247 : coldacl.acl = attacl;
16955 : 4247 : coldacl.acldefault = acldefault;
16956 : 4247 : coldacl.privtype = privtype;
16957 : 4247 : coldacl.initprivs = initprivs;
3491 sfrost@snowman.net 16958 : 4247 : attnamecopy = pg_strdup(fmtId(attname));
16959 : :
16960 : : /*
16961 : : * Column's GRANT type is always TABLE. Each column ACL depends
16962 : : * on the table-level ACL, since we can restore column ACLs in
16963 : : * parallel but the table-level ACL has to be done first.
16964 : : */
1934 tgl@sss.pgh.pa.us 16965 : 4247 : dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
16966 : : "TABLE", namecopy, attnamecopy,
574 16967 : 4247 : tbinfo->dobj.namespace->dobj.name,
16968 : 4247 : NULL, tbinfo->rolname, &coldacl);
3491 sfrost@snowman.net 16969 : 4247 : free(attnamecopy);
16970 : : }
16971 : 284 : PQclear(res);
16972 : 284 : destroyPQExpBuffer(query);
16973 : : }
16974 : :
16975 : 29956 : free(namecopy);
16976 : : }
16977 : :
16978 : : /*
16979 : : * Create the AS clause for a view or materialized view. The semicolon is
16980 : : * stripped because a materialized view must add a WITH NO DATA clause.
16981 : : *
16982 : : * This returns a new buffer which must be freed by the caller.
16983 : : */
16984 : : static PQExpBuffer
1720 peter@eisentraut.org 16985 : 871 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
16986 : : {
4621 kgrittn@postgresql.o 16987 : 871 : PQExpBuffer query = createPQExpBuffer();
16988 : 871 : PQExpBuffer result = createPQExpBuffer();
16989 : : PGresult *res;
16990 : : int len;
16991 : :
16992 : : /* Fetch the view definition */
3302 tgl@sss.pgh.pa.us 16993 : 871 : appendPQExpBuffer(query,
16994 : : "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
16995 : 871 : tbinfo->dobj.catId.oid);
16996 : :
4621 kgrittn@postgresql.o 16997 : 871 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16998 : :
16999 [ - + ]: 871 : if (PQntuples(res) != 1)
17000 : : {
4621 kgrittn@postgresql.o 17001 [ # # ]:UBC 0 : if (PQntuples(res) < 1)
1298 tgl@sss.pgh.pa.us 17002 : 0 : pg_fatal("query to obtain definition of view \"%s\" returned no data",
17003 : : tbinfo->dobj.name);
17004 : : else
17005 : 0 : pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
17006 : : tbinfo->dobj.name);
17007 : : }
17008 : :
4621 kgrittn@postgresql.o 17009 :CBC 871 : len = PQgetlength(res, 0, 0);
17010 : :
17011 [ - + ]: 871 : if (len == 0)
1298 tgl@sss.pgh.pa.us 17012 :UBC 0 : pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
17013 : : tbinfo->dobj.name);
17014 : :
17015 : : /* Strip off the trailing semicolon so that other things may follow. */
4600 andrew@dunslane.net 17016 [ - + ]:CBC 871 : Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
4621 kgrittn@postgresql.o 17017 : 871 : appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
17018 : :
17019 : 871 : PQclear(res);
17020 : 871 : destroyPQExpBuffer(query);
17021 : :
17022 : 871 : return result;
17023 : : }
17024 : :
17025 : : /*
17026 : : * Create a dummy AS clause for a view. This is used when the real view
17027 : : * definition has to be postponed because of circular dependencies.
17028 : : * We must duplicate the view's external properties -- column names and types
17029 : : * (including collation) -- so that it works for subsequent references.
17030 : : *
17031 : : * This returns a new buffer which must be freed by the caller.
17032 : : */
17033 : : static PQExpBuffer
1720 peter@eisentraut.org 17034 : 20 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
17035 : : {
3266 tgl@sss.pgh.pa.us 17036 : 20 : PQExpBuffer result = createPQExpBuffer();
17037 : : int j;
17038 : :
17039 : 20 : appendPQExpBufferStr(result, "SELECT");
17040 : :
17041 [ + + ]: 40 : for (j = 0; j < tbinfo->numatts; j++)
17042 : : {
17043 [ + + ]: 20 : if (j > 0)
17044 : 10 : appendPQExpBufferChar(result, ',');
17045 : 20 : appendPQExpBufferStr(result, "\n ");
17046 : :
17047 : 20 : appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
17048 : :
17049 : : /*
17050 : : * Must add collation if not default for the type, because CREATE OR
17051 : : * REPLACE VIEW won't change it
17052 : : */
17053 [ - + ]: 20 : if (OidIsValid(tbinfo->attcollation[j]))
17054 : : {
17055 : : CollInfo *coll;
17056 : :
3266 tgl@sss.pgh.pa.us 17057 :UBC 0 : coll = findCollationByOid(tbinfo->attcollation[j]);
17058 [ # # ]: 0 : if (coll)
2800 17059 : 0 : appendPQExpBuffer(result, " COLLATE %s",
17060 : 0 : fmtQualifiedDumpable(coll));
17061 : : }
17062 : :
3266 tgl@sss.pgh.pa.us 17063 :CBC 20 : appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
17064 : : }
17065 : :
17066 : 20 : return result;
17067 : : }
17068 : :
17069 : : /*
17070 : : * dumpTableSchema
17071 : : * write the declaration (not data) of one user-defined table or view
17072 : : */
17073 : : static void
1720 peter@eisentraut.org 17074 : 6214 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
17075 : : {
3575 tgl@sss.pgh.pa.us 17076 : 6214 : DumpOptions *dopt = fout->dopt;
9329 bruce@momjian.us 17077 : 6214 : PQExpBuffer q = createPQExpBuffer();
9246 17078 : 6214 : PQExpBuffer delq = createPQExpBuffer();
455 tgl@sss.pgh.pa.us 17079 : 6214 : PQExpBuffer extra = createPQExpBuffer();
17080 : : char *qrelname;
17081 : : char *qualrelname;
17082 : : int numParents;
17083 : : TableInfo **parents;
17084 : : int actual_atts; /* number of attrs in this CREATE statement */
17085 : : const char *reltypename;
17086 : : char *storage;
17087 : : int j,
17088 : : k;
17089 : :
17090 : : /* We had better have loaded per-column details about this table */
1846 17091 [ - + ]: 6214 : Assert(tbinfo->interesting);
17092 : :
2800 17093 : 6214 : qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
17094 : 6214 : qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
17095 : :
2533 andres@anarazel.de 17096 [ - + ]: 6214 : if (tbinfo->hasoids)
2401 peter@eisentraut.org 17097 :UBC 0 : pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
17098 : : qrelname);
17099 : :
4031 alvherre@alvh.no-ip. 17100 [ + + ]:CBC 6214 : if (dopt->binary_upgrade)
1421 tgl@sss.pgh.pa.us 17101 : 866 : binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
17102 : :
17103 : : /* Is it a table or a view? */
8571 17104 [ + + ]: 6214 : if (tbinfo->relkind == RELKIND_VIEW)
17105 : : {
17106 : : PQExpBuffer result;
17107 : :
17108 : : /*
17109 : : * Note: keep this code in sync with the is_view case in dumpRule()
17110 : : */
17111 : :
17112 : 533 : reltypename = "VIEW";
17113 : :
2800 17114 : 533 : appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
17115 : :
4031 alvherre@alvh.no-ip. 17116 [ + + ]: 533 : if (dopt->binary_upgrade)
5011 rhaas@postgresql.org 17117 : 52 : binary_upgrade_set_pg_class_oids(fout, q,
481 nathan@postgresql.or 17118 : 52 : tbinfo->dobj.catId.oid);
17119 : :
2800 tgl@sss.pgh.pa.us 17120 : 533 : appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
17121 : :
3266 17122 [ + + ]: 533 : if (tbinfo->dummy_view)
17123 : 10 : result = createDummyViewAsClause(fout, tbinfo);
17124 : : else
17125 : : {
17126 [ + + ]: 523 : if (nonemptyReloptions(tbinfo->reloptions))
17127 : : {
17128 : 61 : appendPQExpBufferStr(q, " WITH (");
17129 : 61 : appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
17130 : 61 : appendPQExpBufferChar(q, ')');
17131 : : }
17132 : 523 : result = createViewAsClause(fout, tbinfo);
17133 : : }
4484 sfrost@snowman.net 17134 : 533 : appendPQExpBuffer(q, " AS\n%s", result->data);
4621 kgrittn@postgresql.o 17135 : 533 : destroyPQExpBuffer(result);
17136 : :
3266 tgl@sss.pgh.pa.us 17137 [ + + + - ]: 533 : if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
4484 sfrost@snowman.net 17138 : 32 : appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
4361 heikki.linnakangas@i 17139 : 533 : appendPQExpBufferStr(q, ";\n");
17140 : : }
17141 : : else
17142 : : {
1421 tgl@sss.pgh.pa.us 17143 : 5681 : char *partkeydef = NULL;
2517 sfrost@snowman.net 17144 : 5681 : char *ftoptions = NULL;
17145 : 5681 : char *srvname = NULL;
455 tgl@sss.pgh.pa.us 17146 : 5681 : const char *foreign = "";
17147 : :
17148 : : /*
17149 : : * Set reltypename, and collect any relkind-specific data that we
17150 : : * didn't fetch during getTables().
17151 : : */
4621 kgrittn@postgresql.o 17152 [ + + + + ]: 5681 : switch (tbinfo->relkind)
17153 : : {
1421 tgl@sss.pgh.pa.us 17154 : 566 : case RELKIND_PARTITIONED_TABLE:
17155 : : {
17156 : 566 : PQExpBuffer query = createPQExpBuffer();
17157 : : PGresult *res;
17158 : :
17159 : 566 : reltypename = "TABLE";
17160 : :
17161 : : /* retrieve partition key definition */
17162 : 566 : appendPQExpBuffer(query,
17163 : : "SELECT pg_get_partkeydef('%u')",
17164 : 566 : tbinfo->dobj.catId.oid);
17165 : 566 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
17166 : 566 : partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
17167 : 566 : PQclear(res);
17168 : 566 : destroyPQExpBuffer(query);
17169 : 566 : break;
17170 : : }
3154 17171 : 34 : case RELKIND_FOREIGN_TABLE:
17172 : : {
4600 andrew@dunslane.net 17173 : 34 : PQExpBuffer query = createPQExpBuffer();
17174 : : PGresult *res;
17175 : : int i_srvname;
17176 : : int i_ftoptions;
17177 : :
17178 : 34 : reltypename = "FOREIGN TABLE";
17179 : :
17180 : : /* retrieve name of foreign server and generic options */
17181 : 34 : appendPQExpBuffer(query,
17182 : : "SELECT fs.srvname, "
17183 : : "pg_catalog.array_to_string(ARRAY("
17184 : : "SELECT pg_catalog.quote_ident(option_name) || "
17185 : : "' ' || pg_catalog.quote_literal(option_value) "
17186 : : "FROM pg_catalog.pg_options_to_table(ftoptions) "
17187 : : "ORDER BY option_name"
17188 : : "), E',\n ') AS ftoptions "
17189 : : "FROM pg_catalog.pg_foreign_table ft "
17190 : : "JOIN pg_catalog.pg_foreign_server fs "
17191 : : "ON (fs.oid = ft.ftserver) "
17192 : : "WHERE ft.ftrelid = '%u'",
17193 : 34 : tbinfo->dobj.catId.oid);
17194 : 34 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
17195 : 34 : i_srvname = PQfnumber(res, "srvname");
17196 : 34 : i_ftoptions = PQfnumber(res, "ftoptions");
17197 : 34 : srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
17198 : 34 : ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
17199 : 34 : PQclear(res);
17200 : 34 : destroyPQExpBuffer(query);
17201 : :
2047 alvherre@alvh.no-ip. 17202 : 34 : foreign = "FOREIGN ";
4600 andrew@dunslane.net 17203 : 34 : break;
17204 : : }
3154 tgl@sss.pgh.pa.us 17205 : 338 : case RELKIND_MATVIEW:
4621 kgrittn@postgresql.o 17206 : 338 : reltypename = "MATERIALIZED VIEW";
17207 : 338 : break;
17208 : 4743 : default:
17209 : 4743 : reltypename = "TABLE";
1421 tgl@sss.pgh.pa.us 17210 : 4743 : break;
17211 : : }
17212 : :
8571 17213 : 5681 : numParents = tbinfo->numParents;
7996 17214 : 5681 : parents = tbinfo->parents;
17215 : :
2800 17216 : 5681 : appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
17217 : :
4031 alvherre@alvh.no-ip. 17218 [ + + ]: 5681 : if (dopt->binary_upgrade)
5011 rhaas@postgresql.org 17219 : 814 : binary_upgrade_set_pg_class_oids(fout, q,
481 nathan@postgresql.or 17220 : 814 : tbinfo->dobj.catId.oid);
17221 : :
17222 : : /*
17223 : : * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
17224 : : * ignore it when dumping if it was set in this case.
17225 : : */
5413 rhaas@postgresql.org 17226 : 5681 : appendPQExpBuffer(q, "CREATE %s%s %s",
389 michael@paquier.xyz 17227 [ + + ]: 5681 : (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
17228 [ + - ]: 20 : tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
17229 : : "UNLOGGED " : "",
17230 : : reltypename,
17231 : : qualrelname);
17232 : :
17233 : : /*
17234 : : * Attach to type, if reloftype; except in case of a binary upgrade,
17235 : : * we dump the table normally and attach it to the type afterward.
17236 : : */
1421 tgl@sss.pgh.pa.us 17237 [ + + + + ]: 5681 : if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
17238 : 24 : appendPQExpBuffer(q, " OF %s",
17239 : 24 : getFormattedTypeName(fout, tbinfo->reloftype,
17240 : : zeroIsError));
17241 : :
4621 kgrittn@postgresql.o 17242 [ + + ]: 5681 : if (tbinfo->relkind != RELKIND_MATVIEW)
17243 : : {
17244 : : /* Dump the attributes */
4600 andrew@dunslane.net 17245 : 5343 : actual_atts = 0;
17246 [ + + ]: 25138 : for (j = 0; j < tbinfo->numatts; j++)
17247 : : {
17248 : : /*
17249 : : * Normally, dump if it's locally defined in this table, and
17250 : : * not dropped. But for binary upgrade, we'll dump all the
17251 : : * columns, and then fix up the dropped and nonlocal cases
17252 : : * below.
17253 : : */
4031 alvherre@alvh.no-ip. 17254 [ + + ]: 19795 : if (shouldPrintColumn(dopt, tbinfo, j))
17255 : : {
17256 : : bool print_default;
17257 : : bool print_notnull;
17258 : :
17259 : : /*
17260 : : * Default value --- suppress if to be printed separately
17261 : : * or not at all.
17262 : : */
2331 17263 : 38667 : print_default = (tbinfo->attrdefs[j] != NULL &&
972 tgl@sss.pgh.pa.us 17264 [ + + + + ]: 19808 : tbinfo->attrdefs[j]->dobj.dump &&
2331 alvherre@alvh.no-ip. 17265 [ + + ]: 996 : !tbinfo->attrdefs[j]->separate);
17266 : :
17267 : : /*
17268 : : * Not Null constraint --- print it if it is locally
17269 : : * defined, or if binary upgrade. (In the latter case, we
17270 : : * reset conislocal below.)
17271 : : */
353 17272 [ + + ]: 21027 : print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
17273 [ + + ]: 2215 : (tbinfo->notnull_islocal[j] ||
17274 [ + + ]: 607 : dopt->binary_upgrade ||
17275 [ + + ]: 523 : tbinfo->ispartition));
17276 : :
17277 : : /*
17278 : : * Skip column if fully defined by reloftype, except in
17279 : : * binary upgrade
17280 : : */
1421 tgl@sss.pgh.pa.us 17281 [ + + ]: 18812 : if (OidIsValid(tbinfo->reloftype) &&
17282 [ + + + + ]: 50 : !print_default && !print_notnull &&
2331 alvherre@alvh.no-ip. 17283 [ + + ]: 30 : !dopt->binary_upgrade)
4600 andrew@dunslane.net 17284 : 24 : continue;
17285 : :
17286 : : /* Format properly if not first attr */
17287 [ + + ]: 18788 : if (actual_atts == 0)
4361 heikki.linnakangas@i 17288 : 5017 : appendPQExpBufferStr(q, " (");
17289 : : else
3770 17290 : 13771 : appendPQExpBufferChar(q, ',');
4361 17291 : 18788 : appendPQExpBufferStr(q, "\n ");
4600 andrew@dunslane.net 17292 : 18788 : actual_atts++;
17293 : :
17294 : : /* Attribute name */
4361 heikki.linnakangas@i 17295 : 18788 : appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
17296 : :
4600 andrew@dunslane.net 17297 [ + + ]: 18788 : if (tbinfo->attisdropped[j])
17298 : : {
17299 : : /*
17300 : : * ALTER TABLE DROP COLUMN clears
17301 : : * pg_attribute.atttypid, so we will not have gotten a
17302 : : * valid type name; insert INTEGER as a stopgap. We'll
17303 : : * clean things up later.
17304 : : */
4361 heikki.linnakangas@i 17305 : 84 : appendPQExpBufferStr(q, " INTEGER /* dummy */");
17306 : : /* and skip to the next column */
4600 andrew@dunslane.net 17307 : 84 : continue;
17308 : : }
17309 : :
17310 : : /*
17311 : : * Attribute type; print it except when creating a typed
17312 : : * table ('OF type_name'), but in binary-upgrade mode,
17313 : : * print it in that case too.
17314 : : */
1421 tgl@sss.pgh.pa.us 17315 [ + + + + ]: 18704 : if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
17316 : : {
4600 andrew@dunslane.net 17317 : 18688 : appendPQExpBuffer(q, " %s",
3302 tgl@sss.pgh.pa.us 17318 : 18688 : tbinfo->atttypnames[j]);
17319 : : }
17320 : :
2331 alvherre@alvh.no-ip. 17321 [ + + ]: 18704 : if (print_default)
17322 : : {
2403 peter@eisentraut.org 17323 [ + + ]: 866 : if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
17324 : 277 : appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
17325 : 277 : tbinfo->attrdefs[j]->adef_expr);
262 17326 [ + + ]: 589 : else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
17327 : 223 : appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
17328 : 223 : tbinfo->attrdefs[j]->adef_expr);
17329 : : else
2403 17330 : 366 : appendPQExpBuffer(q, " DEFAULT %s",
17331 : 366 : tbinfo->attrdefs[j]->adef_expr);
17332 : : }
17333 : :
2331 alvherre@alvh.no-ip. 17334 [ + + ]: 18704 : if (print_notnull)
17335 : : {
353 17336 [ + + ]: 2184 : if (tbinfo->notnull_constrs[j][0] == '\0')
17337 : 1550 : appendPQExpBufferStr(q, " NOT NULL");
17338 : : else
17339 : 634 : appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
17340 : 634 : fmtId(tbinfo->notnull_constrs[j]));
17341 : :
17342 [ - + ]: 2184 : if (tbinfo->notnull_noinh[j])
353 alvherre@alvh.no-ip. 17343 :UBC 0 : appendPQExpBufferStr(q, " NO INHERIT");
17344 : : }
17345 : :
17346 : : /* Add collation if not default for the type */
4600 andrew@dunslane.net 17347 [ + + ]:CBC 18704 : if (OidIsValid(tbinfo->attcollation[j]))
17348 : : {
17349 : : CollInfo *coll;
17350 : :
17351 : 197 : coll = findCollationByOid(tbinfo->attcollation[j]);
17352 [ + - ]: 197 : if (coll)
2800 tgl@sss.pgh.pa.us 17353 : 197 : appendPQExpBuffer(q, " COLLATE %s",
17354 : 197 : fmtQualifiedDumpable(coll));
17355 : : }
17356 : : }
17357 : :
17358 : : /*
17359 : : * On the other hand, if we choose not to print a column
17360 : : * (likely because it is created by inheritance), but the
17361 : : * column has a locally-defined not-null constraint, we need
17362 : : * to dump the constraint as a standalone object.
17363 : : *
17364 : : * This syntax isn't SQL-conforming, but if you wanted
17365 : : * standard output you wouldn't be creating non-standard
17366 : : * objects to begin with.
17367 : : */
318 alvherre@alvh.no-ip. 17368 [ + + ]: 19687 : if (!shouldPrintColumn(dopt, tbinfo, j) &&
17369 [ + + ]: 983 : !tbinfo->attisdropped[j] &&
17370 [ + + ]: 620 : tbinfo->notnull_constrs[j] != NULL &&
17371 [ + + ]: 177 : tbinfo->notnull_islocal[j])
17372 : : {
17373 : : /* Format properly if not first attr */
17374 [ + + ]: 59 : if (actual_atts == 0)
17375 : 55 : appendPQExpBufferStr(q, " (");
17376 : : else
17377 : 4 : appendPQExpBufferChar(q, ',');
17378 : 59 : appendPQExpBufferStr(q, "\n ");
17379 : 59 : actual_atts++;
17380 : :
17381 [ + + ]: 59 : if (tbinfo->notnull_constrs[j][0] == '\0')
17382 : 8 : appendPQExpBuffer(q, "NOT NULL %s",
17383 : 8 : fmtId(tbinfo->attnames[j]));
17384 : : else
17385 : 102 : appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
17386 : 51 : tbinfo->notnull_constrs[j],
17387 : 51 : fmtId(tbinfo->attnames[j]));
17388 : : }
17389 : : }
17390 : :
17391 : : /*
17392 : : * Add non-inherited CHECK constraints, if any.
17393 : : *
17394 : : * For partitions, we need to include check constraints even if
17395 : : * they're not defined locally, because the ALTER TABLE ATTACH
17396 : : * PARTITION that we'll emit later expects the constraint to be
17397 : : * there. (No need to fix conislocal: ATTACH PARTITION does that)
17398 : : */
4600 andrew@dunslane.net 17399 [ + + ]: 5916 : for (j = 0; j < tbinfo->ncheck; j++)
17400 : : {
17401 : 573 : ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
17402 : :
2331 alvherre@alvh.no-ip. 17403 [ + + ]: 573 : if (constr->separate ||
17404 [ + + + + ]: 503 : (!constr->conislocal && !tbinfo->ispartition))
4600 andrew@dunslane.net 17405 : 107 : continue;
17406 : :
17407 [ + + ]: 466 : if (actual_atts == 0)
4361 heikki.linnakangas@i 17408 : 16 : appendPQExpBufferStr(q, " (\n ");
17409 : : else
17410 : 450 : appendPQExpBufferStr(q, ",\n ");
17411 : :
4600 andrew@dunslane.net 17412 : 466 : appendPQExpBuffer(q, "CONSTRAINT %s ",
17413 : 466 : fmtId(constr->dobj.name));
4361 heikki.linnakangas@i 17414 : 466 : appendPQExpBufferStr(q, constr->condef);
17415 : :
4600 andrew@dunslane.net 17416 : 466 : actual_atts++;
17417 : : }
17418 : :
17419 [ + + ]: 5343 : if (actual_atts)
4361 heikki.linnakangas@i 17420 : 5088 : appendPQExpBufferStr(q, "\n)");
1421 tgl@sss.pgh.pa.us 17421 [ + + - + ]: 255 : else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
17422 : : {
17423 : : /*
17424 : : * No attributes? we must have a parenthesized attribute list,
17425 : : * even though empty, when not using the OF TYPE syntax.
17426 : : */
4361 heikki.linnakangas@i 17427 : 243 : appendPQExpBufferStr(q, " (\n)");
17428 : : }
17429 : :
17430 : : /*
17431 : : * Emit the INHERITS clause (not for partitions), except in
17432 : : * binary-upgrade mode.
17433 : : */
2331 alvherre@alvh.no-ip. 17434 [ + + + + ]: 5343 : if (numParents > 0 && !tbinfo->ispartition &&
3098 sfrost@snowman.net 17435 [ + + ]: 489 : !dopt->binary_upgrade)
17436 : : {
4361 heikki.linnakangas@i 17437 : 425 : appendPQExpBufferStr(q, "\nINHERITS (");
4600 andrew@dunslane.net 17438 [ + + ]: 921 : for (k = 0; k < numParents; k++)
17439 : : {
17440 : 496 : TableInfo *parentRel = parents[k];
17441 : :
17442 [ + + ]: 496 : if (k > 0)
4361 heikki.linnakangas@i 17443 : 71 : appendPQExpBufferStr(q, ", ");
2800 tgl@sss.pgh.pa.us 17444 : 496 : appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
17445 : : }
4361 heikki.linnakangas@i 17446 : 425 : appendPQExpBufferChar(q, ')');
17447 : : }
17448 : :
3246 rhaas@postgresql.org 17449 [ + + ]: 5343 : if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
1421 tgl@sss.pgh.pa.us 17450 : 566 : appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
17451 : :
4600 andrew@dunslane.net 17452 [ + + ]: 5343 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
17453 : 34 : appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
17454 : : }
17455 : :
3586 tgl@sss.pgh.pa.us 17456 [ + + - + ]: 11220 : if (nonemptyReloptions(tbinfo->reloptions) ||
17457 : 5539 : nonemptyReloptions(tbinfo->toast_reloptions))
17458 : : {
5982 bruce@momjian.us 17459 : 142 : bool addcomma = false;
17460 : :
4361 heikki.linnakangas@i 17461 : 142 : appendPQExpBufferStr(q, "\nWITH (");
3586 tgl@sss.pgh.pa.us 17462 [ + - ]: 142 : if (nonemptyReloptions(tbinfo->reloptions))
17463 : : {
6111 alvherre@alvh.no-ip. 17464 : 142 : addcomma = true;
3461 dean.a.rasheed@gmail 17465 : 142 : appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
17466 : : }
3586 tgl@sss.pgh.pa.us 17467 [ + + ]: 142 : if (nonemptyReloptions(tbinfo->toast_reloptions))
17468 : : {
17469 [ + - ]: 5 : if (addcomma)
17470 : 5 : appendPQExpBufferStr(q, ", ");
3461 dean.a.rasheed@gmail 17471 : 5 : appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
17472 : : fout);
17473 : : }
4361 heikki.linnakangas@i 17474 : 142 : appendPQExpBufferChar(q, ')');
17475 : : }
17476 : :
17477 : : /* Dump generic options if any */
5413 rhaas@postgresql.org 17478 [ + + + + ]: 5681 : if (ftoptions && ftoptions[0])
5044 peter_e@gmx.net 17479 : 32 : appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
17480 : :
17481 : : /*
17482 : : * For materialized views, create the AS clause just like a view. At
17483 : : * this point, we always mark the view as not populated.
17484 : : */
4621 kgrittn@postgresql.o 17485 [ + + ]: 5681 : if (tbinfo->relkind == RELKIND_MATVIEW)
17486 : : {
17487 : : PQExpBuffer result;
17488 : :
17489 : 338 : result = createViewAsClause(fout, tbinfo);
17490 : 338 : appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
17491 : : result->data);
17492 : 338 : destroyPQExpBuffer(result);
17493 : : }
17494 : : else
4361 heikki.linnakangas@i 17495 : 5343 : appendPQExpBufferStr(q, ";\n");
17496 : :
17497 : : /* Materialized views can depend on extensions */
2056 alvherre@alvh.no-ip. 17498 [ + + ]: 5681 : if (tbinfo->relkind == RELKIND_MATVIEW)
17499 : 338 : append_depends_on_extension(fout, q, &tbinfo->dobj,
17500 : : "pg_catalog.pg_class",
17501 : : "MATERIALIZED VIEW",
17502 : : qualrelname);
17503 : :
17504 : : /*
17505 : : * in binary upgrade mode, update the catalog with any missing values
17506 : : * that might be present.
17507 : : */
2684 andrew@dunslane.net 17508 [ + + ]: 5681 : if (dopt->binary_upgrade)
17509 : : {
17510 [ + + ]: 3953 : for (j = 0; j < tbinfo->numatts; j++)
17511 : : {
17512 [ + + ]: 3139 : if (tbinfo->attmissingval[j][0] != '\0')
17513 : : {
17514 : 2 : appendPQExpBufferStr(q, "\n-- set missing value.\n");
17515 : 2 : appendPQExpBufferStr(q,
17516 : : "SELECT pg_catalog.binary_upgrade_set_missing_value(");
17517 : 2 : appendStringLiteralAH(q, qualrelname, fout);
17518 : 2 : appendPQExpBufferStr(q, "::pg_catalog.regclass,");
17519 : 2 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
1147 drowley@postgresql.o 17520 : 2 : appendPQExpBufferChar(q, ',');
2684 andrew@dunslane.net 17521 : 2 : appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
17522 : 2 : appendPQExpBufferStr(q, ");\n\n");
17523 : : }
17524 : : }
17525 : : }
17526 : :
17527 : : /*
17528 : : * To create binary-compatible heap files, we have to ensure the same
17529 : : * physical column order, including dropped columns, as in the
17530 : : * original. Therefore, we create dropped columns above and drop them
17531 : : * here, also updating their attlen/attalign values so that the
17532 : : * dropped column can be skipped properly. (We do not bother with
17533 : : * restoring the original attbyval setting.) Also, inheritance
17534 : : * relationships are set up by doing ALTER TABLE INHERIT rather than
17535 : : * using an INHERITS clause --- the latter would possibly mess up the
17536 : : * column order. That also means we have to take care about setting
17537 : : * attislocal correctly, plus fix up any inherited CHECK constraints.
17538 : : * Analogously, we set up typed tables using ALTER TABLE / OF here.
17539 : : *
17540 : : * We process foreign and partitioned tables here, even though they
17541 : : * lack heap storage, because they can participate in inheritance
17542 : : * relationships and we want this stuff to be consistent across the
17543 : : * inheritance tree. We can exclude indexes, toast tables, sequences
17544 : : * and matviews, even though they have storage, because we don't
17545 : : * support altering or dropping columns in them, nor can they be part
17546 : : * of inheritance trees.
17547 : : */
3872 tgl@sss.pgh.pa.us 17548 [ + + ]: 5681 : if (dopt->binary_upgrade &&
17549 [ + + ]: 814 : (tbinfo->relkind == RELKIND_RELATION ||
3246 rhaas@postgresql.org 17550 [ + + ]: 109 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
17551 [ + + ]: 108 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
17552 : : {
17553 : : bool firstitem;
17554 : : bool firstitem_extra;
17555 : :
17556 : : /*
17557 : : * Drop any dropped columns. Merge the pg_attribute manipulations
17558 : : * into a single SQL command, so that we don't cause repeated
17559 : : * relcache flushes on the target table. Otherwise we risk O(N^2)
17560 : : * relcache bloat while dropping N columns.
17561 : : */
455 tgl@sss.pgh.pa.us 17562 : 797 : resetPQExpBuffer(extra);
17563 : 797 : firstitem = true;
6096 bruce@momjian.us 17564 [ + + ]: 3915 : for (j = 0; j < tbinfo->numatts; j++)
17565 : : {
17566 [ + + ]: 3118 : if (tbinfo->attisdropped[j])
17567 : : {
455 tgl@sss.pgh.pa.us 17568 [ + + ]: 84 : if (firstitem)
17569 : : {
17570 : 38 : appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
17571 : : "UPDATE pg_catalog.pg_attribute\n"
17572 : : "SET attlen = v.dlen, "
17573 : : "attalign = v.dalign, "
17574 : : "attbyval = false\n"
17575 : : "FROM (VALUES ");
17576 : 38 : firstitem = false;
17577 : : }
17578 : : else
17579 : 46 : appendPQExpBufferStr(q, ",\n ");
17580 : 84 : appendPQExpBufferChar(q, '(');
17581 : 84 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17582 : 84 : appendPQExpBuffer(q, ", %d, '%c')",
5961 17583 : 84 : tbinfo->attlen[j],
17584 : 84 : tbinfo->attalign[j]);
17585 : : /* The ALTER ... DROP COLUMN commands must come after */
455 17586 : 84 : appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
17587 : : foreign, qualrelname);
17588 : 84 : appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
6096 bruce@momjian.us 17589 : 84 : fmtId(tbinfo->attnames[j]));
17590 : : }
17591 : : }
455 tgl@sss.pgh.pa.us 17592 [ + + ]: 797 : if (!firstitem)
17593 : : {
17594 : 38 : appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
17595 : : "WHERE attrelid = ");
17596 : 38 : appendStringLiteralAH(q, qualrelname, fout);
17597 : 38 : appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
17598 : : " AND attname = v.dname;\n");
17599 : : /* Now we can issue the actual DROP COLUMN commands */
17600 : 38 : appendBinaryPQExpBuffer(q, extra->data, extra->len);
17601 : : }
17602 : :
17603 : : /*
17604 : : * Fix up inherited columns. As above, do the pg_attribute
17605 : : * manipulations in a single SQL command.
17606 : : */
17607 : 797 : firstitem = true;
17608 [ + + ]: 3915 : for (j = 0; j < tbinfo->numatts; j++)
17609 : : {
17610 [ + + ]: 3118 : if (!tbinfo->attisdropped[j] &&
17611 [ + + ]: 3034 : !tbinfo->attislocal[j])
17612 : : {
17613 [ + + ]: 604 : if (firstitem)
17614 : : {
17615 : 267 : appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
17616 : 267 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
17617 : : "SET attislocal = false\n"
17618 : : "WHERE attrelid = ");
17619 : 267 : appendStringLiteralAH(q, qualrelname, fout);
17620 : 267 : appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
17621 : : " AND attname IN (");
17622 : 267 : firstitem = false;
17623 : : }
17624 : : else
17625 : 337 : appendPQExpBufferStr(q, ", ");
5961 17626 : 604 : appendStringLiteralAH(q, tbinfo->attnames[j], fout);
17627 : : }
17628 : : }
455 17629 [ + + ]: 797 : if (!firstitem)
17630 : 267 : appendPQExpBufferStr(q, ");\n");
17631 : :
17632 : : /*
17633 : : * Fix up not-null constraints that come from inheritance. As
17634 : : * above, do the pg_constraint manipulations in a single SQL
17635 : : * command. (Actually, two in special cases, if we're doing an
17636 : : * upgrade from < 18).
17637 : : */
353 alvherre@alvh.no-ip. 17638 : 797 : firstitem = true;
17639 : 797 : firstitem_extra = true;
17640 : 797 : resetPQExpBuffer(extra);
17641 [ + + ]: 3915 : for (j = 0; j < tbinfo->numatts; j++)
17642 : : {
17643 : : /*
17644 : : * If a not-null constraint comes from inheritance, reset
17645 : : * conislocal. The inhcount is fixed by ALTER TABLE INHERIT,
17646 : : * below. Special hack: in versions < 18, columns with no
17647 : : * local definition need their constraint to be matched by
17648 : : * column number in conkeys instead of by constraint name,
17649 : : * because the latter is not available. (We distinguish the
17650 : : * case because the constraint name is the empty string.)
17651 : : */
17652 [ + + ]: 3118 : if (tbinfo->notnull_constrs[j] != NULL &&
17653 [ + + ]: 291 : !tbinfo->notnull_islocal[j])
17654 : : {
17655 [ + + ]: 84 : if (tbinfo->notnull_constrs[j][0] != '\0')
17656 : : {
17657 [ + + ]: 71 : if (firstitem)
17658 : : {
17659 : 61 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
17660 : : "SET conislocal = false\n"
17661 : : "WHERE contype = 'n' AND conrelid = ");
17662 : 61 : appendStringLiteralAH(q, qualrelname, fout);
17663 : 61 : appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
17664 : : "conname IN (");
17665 : 61 : firstitem = false;
17666 : : }
17667 : : else
17668 : 10 : appendPQExpBufferStr(q, ", ");
17669 : 71 : appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
17670 : : }
17671 : : else
17672 : : {
17673 [ + - ]: 13 : if (firstitem_extra)
17674 : : {
17675 : 13 : appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
17676 : : "SET conislocal = false\n"
17677 : : "WHERE contype = 'n' AND conrelid = ");
17678 : 13 : appendStringLiteralAH(extra, qualrelname, fout);
17679 : 13 : appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
17680 : : "conkey IN (");
17681 : 13 : firstitem_extra = false;
17682 : : }
17683 : : else
353 alvherre@alvh.no-ip. 17684 :UBC 0 : appendPQExpBufferStr(extra, ", ");
353 alvherre@alvh.no-ip. 17685 :CBC 13 : appendPQExpBuffer(extra, "'{%d}'", j + 1);
17686 : : }
17687 : : }
17688 : : }
17689 [ + + ]: 797 : if (!firstitem)
17690 : 61 : appendPQExpBufferStr(q, ");\n");
17691 [ + + ]: 797 : if (!firstitem_extra)
17692 : 13 : appendPQExpBufferStr(extra, ");\n");
17693 : :
17694 [ + + ]: 797 : if (extra->len > 0)
17695 : 13 : appendBinaryPQExpBuffer(q, extra->data, extra->len);
17696 : :
17697 : : /*
17698 : : * Add inherited CHECK constraints, if any.
17699 : : *
17700 : : * For partitions, they were already dumped, and conislocal
17701 : : * doesn't need fixing.
17702 : : *
17703 : : * As above, issue only one direct manipulation of pg_constraint.
17704 : : * Although it is tempting to merge the ALTER ADD CONSTRAINT
17705 : : * commands into one as well, refrain for now due to concern about
17706 : : * possible backend memory bloat if there are many such
17707 : : * constraints.
17708 : : */
455 tgl@sss.pgh.pa.us 17709 : 797 : resetPQExpBuffer(extra);
17710 : 797 : firstitem = true;
5961 17711 [ + + ]: 859 : for (k = 0; k < tbinfo->ncheck; k++)
17712 : : {
17713 : 62 : ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
17714 : :
2331 alvherre@alvh.no-ip. 17715 [ + + + + : 62 : if (constr->separate || constr->conislocal || tbinfo->ispartition)
+ + ]
5961 tgl@sss.pgh.pa.us 17716 : 60 : continue;
17717 : :
455 17718 [ + - ]: 2 : if (firstitem)
17719 : 2 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
2047 alvherre@alvh.no-ip. 17720 : 2 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
17721 : : foreign, qualrelname,
17722 : 2 : fmtId(constr->dobj.name),
17723 : : constr->condef);
17724 : : /* Update pg_constraint after all the ALTER TABLEs */
455 tgl@sss.pgh.pa.us 17725 [ + - ]: 2 : if (firstitem)
17726 : : {
17727 : 2 : appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
17728 : : "SET conislocal = false\n"
17729 : : "WHERE contype = 'c' AND conrelid = ");
17730 : 2 : appendStringLiteralAH(extra, qualrelname, fout);
17731 : 2 : appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
17732 : 2 : appendPQExpBufferStr(extra, " AND conname IN (");
17733 : 2 : firstitem = false;
17734 : : }
17735 : : else
455 tgl@sss.pgh.pa.us 17736 :UBC 0 : appendPQExpBufferStr(extra, ", ");
455 tgl@sss.pgh.pa.us 17737 :CBC 2 : appendStringLiteralAH(extra, constr->dobj.name, fout);
17738 : : }
17739 [ + + ]: 797 : if (!firstitem)
17740 : : {
17741 : 2 : appendPQExpBufferStr(extra, ");\n");
17742 : 2 : appendBinaryPQExpBuffer(q, extra->data, extra->len);
17743 : : }
17744 : :
2331 alvherre@alvh.no-ip. 17745 [ + + + + ]: 797 : if (numParents > 0 && !tbinfo->ispartition)
17746 : : {
17747 : 64 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
5961 tgl@sss.pgh.pa.us 17748 [ + + ]: 139 : for (k = 0; k < numParents; k++)
17749 : : {
17750 : 75 : TableInfo *parentRel = parents[k];
17751 : :
2047 alvherre@alvh.no-ip. 17752 : 75 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
17753 : : qualrelname,
2331 17754 : 75 : fmtQualifiedDumpable(parentRel));
17755 : : }
17756 : : }
17757 : :
1421 tgl@sss.pgh.pa.us 17758 [ + + ]: 797 : if (OidIsValid(tbinfo->reloftype))
17759 : : {
4361 heikki.linnakangas@i 17760 : 6 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
5297 peter_e@gmx.net 17761 : 6 : appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
17762 : : qualrelname,
1421 tgl@sss.pgh.pa.us 17763 : 6 : getFormattedTypeName(fout, tbinfo->reloftype,
17764 : : zeroIsError));
17765 : : }
17766 : : }
17767 : :
17768 : : /*
17769 : : * In binary_upgrade mode, arrange to restore the old relfrozenxid and
17770 : : * relminmxid of all vacuumable relations. (While vacuum.c processes
17771 : : * TOAST tables semi-independently, here we see them only as children
17772 : : * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
17773 : : * child toast table is handled below.)
17774 : : */
2805 17775 [ + + ]: 5681 : if (dopt->binary_upgrade &&
17776 [ + + ]: 814 : (tbinfo->relkind == RELKIND_RELATION ||
17777 [ + + ]: 109 : tbinfo->relkind == RELKIND_MATVIEW))
17778 : : {
4135 bruce@momjian.us 17779 : 722 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
5961 tgl@sss.pgh.pa.us 17780 : 722 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
17781 : : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
17782 : : "WHERE oid = ",
4135 bruce@momjian.us 17783 : 722 : tbinfo->frozenxid, tbinfo->minmxid);
2800 tgl@sss.pgh.pa.us 17784 : 722 : appendStringLiteralAH(q, qualrelname, fout);
4361 heikki.linnakangas@i 17785 : 722 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
17786 : :
5316 bruce@momjian.us 17787 [ + + ]: 722 : if (tbinfo->toast_oid)
17788 : : {
17789 : : /*
17790 : : * The toast table will have the same OID at restore, so we
17791 : : * can safely target it by OID.
17792 : : */
4135 17793 : 277 : appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
5316 17794 : 277 : appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
17795 : : "SET relfrozenxid = '%u', relminmxid = '%u'\n"
17796 : : "WHERE oid = '%u';\n",
4135 17797 : 277 : tbinfo->toast_frozenxid,
17798 : 277 : tbinfo->toast_minmxid, tbinfo->toast_oid);
17799 : : }
17800 : : }
17801 : :
17802 : : /*
17803 : : * In binary_upgrade mode, restore matviews' populated status by
17804 : : * poking pg_class directly. This is pretty ugly, but we can't use
17805 : : * REFRESH MATERIALIZED VIEW since it's possible that some underlying
17806 : : * matview is not populated even though this matview is; in any case,
17807 : : * we want to transfer the matview's heap storage, not run REFRESH.
17808 : : */
4031 alvherre@alvh.no-ip. 17809 [ + + + + ]: 5681 : if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
4557 tgl@sss.pgh.pa.us 17810 [ + + ]: 17 : tbinfo->relispopulated)
17811 : : {
4361 heikki.linnakangas@i 17812 : 15 : appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
17813 : 15 : appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
17814 : : "SET relispopulated = 't'\n"
17815 : : "WHERE oid = ");
2800 tgl@sss.pgh.pa.us 17816 : 15 : appendStringLiteralAH(q, qualrelname, fout);
4361 heikki.linnakangas@i 17817 : 15 : appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
17818 : : }
17819 : :
17820 : : /*
17821 : : * Dump additional per-column properties that we can't handle in the
17822 : : * main CREATE TABLE command.
17823 : : */
8454 bruce@momjian.us 17824 [ + + ]: 25888 : for (j = 0; j < tbinfo->numatts; j++)
17825 : : {
17826 : : /* None of this applies to dropped columns */
5008 tgl@sss.pgh.pa.us 17827 [ + + ]: 20207 : if (tbinfo->attisdropped[j])
17828 : 447 : continue;
17829 : :
17830 : : /*
17831 : : * Dump per-column statistics information. We only issue an ALTER
17832 : : * TABLE statement if the attstattarget entry for this column is
17833 : : * not the default value.
17834 : : */
17835 [ + + ]: 19760 : if (tbinfo->attstattarget[j] >= 0)
2047 alvherre@alvh.no-ip. 17836 : 32 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
17837 : : foreign, qualrelname,
17838 : 32 : fmtId(tbinfo->attnames[j]),
8489 tgl@sss.pgh.pa.us 17839 : 32 : tbinfo->attstattarget[j]);
17840 : :
17841 : : /*
17842 : : * Dump per-column storage information. The statement is only
17843 : : * dumped if the storage has been changed from the type's default.
17844 : : */
5008 17845 [ + + ]: 19760 : if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
17846 : : {
8120 bruce@momjian.us 17847 [ + + - + : 79 : switch (tbinfo->attstorage[j])
- ]
17848 : : {
2063 tgl@sss.pgh.pa.us 17849 : 10 : case TYPSTORAGE_PLAIN:
8257 bruce@momjian.us 17850 : 10 : storage = "PLAIN";
17851 : 10 : break;
2063 tgl@sss.pgh.pa.us 17852 : 37 : case TYPSTORAGE_EXTERNAL:
8257 bruce@momjian.us 17853 : 37 : storage = "EXTERNAL";
17854 : 37 : break;
2063 tgl@sss.pgh.pa.us 17855 :UBC 0 : case TYPSTORAGE_EXTENDED:
8257 bruce@momjian.us 17856 : 0 : storage = "EXTENDED";
17857 : 0 : break;
2063 tgl@sss.pgh.pa.us 17858 :CBC 32 : case TYPSTORAGE_MAIN:
17859 : 32 : storage = "MAIN";
17860 : 32 : break;
8257 bruce@momjian.us 17861 :UBC 0 : default:
17862 : 0 : storage = NULL;
17863 : : }
17864 : :
17865 : : /*
17866 : : * Only dump the statement if it's a storage type we recognize
17867 : : */
8120 bruce@momjian.us 17868 [ + - ]:CBC 79 : if (storage != NULL)
2047 alvherre@alvh.no-ip. 17869 : 79 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
17870 : : foreign, qualrelname,
17871 : 79 : fmtId(tbinfo->attnames[j]),
17872 : : storage);
17873 : : }
17874 : :
17875 : : /*
17876 : : * Dump per-column compression, if it's been set.
17877 : : */
1682 tgl@sss.pgh.pa.us 17878 [ + + ]: 19760 : if (!dopt->no_toast_compression)
17879 : : {
17880 : : const char *cmname;
17881 : :
17882 [ + + + ]: 19666 : switch (tbinfo->attcompression[j])
17883 : : {
17884 : 71 : case 'p':
17885 : 71 : cmname = "pglz";
17886 : 71 : break;
17887 : 45 : case 'l':
17888 : 45 : cmname = "lz4";
17889 : 45 : break;
17890 : 19550 : default:
17891 : 19550 : cmname = NULL;
17892 : 19550 : break;
17893 : : }
17894 : :
1614 17895 [ + + ]: 19666 : if (cmname != NULL)
1682 17896 : 116 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
17897 : : foreign, qualrelname,
17898 : 116 : fmtId(tbinfo->attnames[j]),
17899 : : cmname);
17900 : : }
17901 : :
17902 : : /*
17903 : : * Dump per-column attributes.
17904 : : */
1614 17905 [ + + ]: 19760 : if (tbinfo->attoptions[j][0] != '\0')
17906 : 32 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
17907 : : foreign, qualrelname,
17908 : 32 : fmtId(tbinfo->attnames[j]),
17909 : 32 : tbinfo->attoptions[j]);
17910 : :
17911 : : /*
17912 : : * Dump per-column fdw options.
17913 : : */
17914 [ + + ]: 19760 : if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
17915 [ + + ]: 34 : tbinfo->attfdwoptions[j][0] != '\0')
17916 : 32 : appendPQExpBuffer(q,
17917 : : "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
17918 : : " %s\n"
17919 : : ");\n",
17920 : : qualrelname,
17921 : 32 : fmtId(tbinfo->attnames[j]),
17922 : 32 : tbinfo->attfdwoptions[j]);
17923 : : } /* end loop over columns */
17924 : :
1229 peter@eisentraut.org 17925 : 5681 : free(partkeydef);
17926 : 5681 : free(ftoptions);
17927 : 5681 : free(srvname);
17928 : : }
17929 : :
17930 : : /*
17931 : : * dump properties we only have ALTER TABLE syntax for
17932 : : */
3872 tgl@sss.pgh.pa.us 17933 [ + + ]: 6214 : if ((tbinfo->relkind == RELKIND_RELATION ||
3246 rhaas@postgresql.org 17934 [ + + ]: 1471 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
3872 tgl@sss.pgh.pa.us 17935 [ + + ]: 905 : tbinfo->relkind == RELKIND_MATVIEW) &&
4369 peter_e@gmx.net 17936 [ + + ]: 5647 : tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
17937 : : {
4371 rhaas@postgresql.org 17938 [ + - ]: 192 : if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
17939 : : {
17940 : : /* nothing to do, will be set when the index is dumped */
17941 : : }
17942 [ + - ]: 192 : else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
17943 : : {
17944 : 192 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
17945 : : qualrelname);
17946 : : }
4371 rhaas@postgresql.org 17947 [ # # ]:UBC 0 : else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
17948 : : {
17949 : 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
17950 : : qualrelname);
17951 : : }
17952 : : }
17953 : :
3676 sfrost@snowman.net 17954 [ + + ]:CBC 6214 : if (tbinfo->forcerowsec)
17955 : 5 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
17956 : : qualrelname);
17957 : :
4031 alvherre@alvh.no-ip. 17958 [ + + ]: 6214 : if (dopt->binary_upgrade)
2800 tgl@sss.pgh.pa.us 17959 : 866 : binary_upgrade_extension_member(q, &tbinfo->dobj,
17960 : : reltypename, qrelname,
17961 : 866 : tbinfo->dobj.namespace->dobj.name);
17962 : :
3491 sfrost@snowman.net 17963 [ + - ]: 6214 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17964 : : {
1424 peter@eisentraut.org 17965 : 6214 : char *tablespace = NULL;
2350 tgl@sss.pgh.pa.us 17966 : 6214 : char *tableam = NULL;
17967 : :
17968 : : /*
17969 : : * _selectTablespace() relies on tablespace-enabled objects in the
17970 : : * default tablespace to have a tablespace of "" (empty string) versus
17971 : : * non-tablespace-enabled objects to have a tablespace of NULL.
17972 : : * getTables() sets tbinfo->reltablespace to "" for the default
17973 : : * tablespace (not NULL).
17974 : : */
1424 peter@eisentraut.org 17975 [ + + + - : 6214 : if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
+ - + - +
+ + + - +
+ - ]
17976 : 5647 : tablespace = tbinfo->reltablespace;
17977 : :
581 alvherre@alvh.no-ip. 17978 [ + + + - : 6214 : if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
+ + ]
17979 [ + + ]: 1133 : tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2427 andres@anarazel.de 17980 : 5647 : tableam = tbinfo->amname;
17981 : :
3491 sfrost@snowman.net 17982 : 6214 : ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 17983 [ + + ]: 6214 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17984 : : .namespace = tbinfo->dobj.namespace->dobj.name,
17985 : : .tablespace = tablespace,
17986 : : .tableam = tableam,
17987 : : .relkind = tbinfo->relkind,
17988 : : .owner = tbinfo->rolname,
17989 : : .description = reltypename,
17990 : : .section = tbinfo->postponed_def ?
17991 : : SECTION_POST_DATA : SECTION_PRE_DATA,
17992 : : .createStmt = q->data,
17993 : : .dropStmt = delq->data));
17994 : : }
17995 : :
17996 : : /* Dump Table Comments */
3491 sfrost@snowman.net 17997 [ + + ]: 6214 : if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17998 : 74 : dumpTableComment(fout, tbinfo, reltypename);
17999 : :
18000 : : /* Dump Table Security Labels */
18001 [ - + ]: 6214 : if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3491 sfrost@snowman.net 18002 :UBC 0 : dumpTableSecLabel(fout, tbinfo, reltypename);
18003 : :
18004 : : /*
18005 : : * Dump comments for not-null constraints that aren't to be dumped
18006 : : * separately (those are processed by collectComments/dumpComment).
18007 : : */
123 alvherre@kurilemu.de 18008 [ + - + - ]:CBC 6214 : if (!fout->dopt->no_comments && dopt->dumpSchema &&
18009 [ + - ]: 6214 : fout->remoteVersion >= 180000)
18010 : : {
18011 : 6214 : PQExpBuffer comment = NULL;
18012 : 6214 : PQExpBuffer tag = NULL;
18013 : :
18014 [ + + ]: 29820 : for (j = 0; j < tbinfo->numatts; j++)
18015 : : {
18016 [ + + ]: 23606 : if (tbinfo->notnull_constrs[j] != NULL &&
18017 [ + + ]: 2392 : tbinfo->notnull_comment[j] != NULL)
18018 : : {
18019 [ + - ]: 42 : if (comment == NULL)
18020 : : {
18021 : 42 : comment = createPQExpBuffer();
18022 : 42 : tag = createPQExpBuffer();
18023 : : }
18024 : : else
18025 : : {
123 alvherre@kurilemu.de 18026 :UBC 0 : resetPQExpBuffer(comment);
18027 : 0 : resetPQExpBuffer(tag);
18028 : : }
18029 : :
123 alvherre@kurilemu.de 18030 :CBC 42 : appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
18031 : 42 : fmtId(tbinfo->notnull_constrs[j]), qualrelname);
18032 : 42 : appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
18033 : 42 : appendPQExpBufferStr(comment, ";\n");
18034 : :
18035 : 42 : appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
18036 : 42 : fmtId(tbinfo->notnull_constrs[j]), qrelname);
18037 : :
18038 : 42 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
18039 : 42 : ARCHIVE_OPTS(.tag = tag->data,
18040 : : .namespace = tbinfo->dobj.namespace->dobj.name,
18041 : : .owner = tbinfo->rolname,
18042 : : .description = "COMMENT",
18043 : : .section = SECTION_NONE,
18044 : : .createStmt = comment->data,
18045 : : .deps = &(tbinfo->dobj.dumpId),
18046 : : .nDeps = 1));
18047 : : }
18048 : : }
18049 : :
18050 : 6214 : destroyPQExpBuffer(comment);
18051 : 6214 : destroyPQExpBuffer(tag);
18052 : : }
18053 : :
18054 : : /* Dump comments on inlined table constraints */
7622 tgl@sss.pgh.pa.us 18055 [ + + ]: 6787 : for (j = 0; j < tbinfo->ncheck; j++)
18056 : : {
18057 : 573 : ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
18058 : :
6380 18059 [ + + + + ]: 573 : if (constr->separate || !constr->conislocal)
7622 18060 : 244 : continue;
18061 : :
1090 18062 [ + + ]: 329 : if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
3491 sfrost@snowman.net 18063 : 37 : dumpTableConstraintComment(fout, constr);
18064 : : }
18065 : :
8571 tgl@sss.pgh.pa.us 18066 : 6214 : destroyPQExpBuffer(q);
18067 : 6214 : destroyPQExpBuffer(delq);
455 18068 : 6214 : destroyPQExpBuffer(extra);
2800 18069 : 6214 : free(qrelname);
18070 : 6214 : free(qualrelname);
9054 pjw@rhyme.com.au 18071 : 6214 : }
18072 : :
18073 : : /*
18074 : : * dumpTableAttach
18075 : : * write to fout the commands to attach a child partition
18076 : : *
18077 : : * Child partitions are always made by creating them separately
18078 : : * and then using ATTACH PARTITION, rather than using
18079 : : * CREATE TABLE ... PARTITION OF. This is important for preserving
18080 : : * any possible discrepancy in column layout, to allow assigning the
18081 : : * correct tablespace if different, and so that it's possible to restore
18082 : : * a partition without restoring its parent. (You'll get an error from
18083 : : * the ATTACH PARTITION command, but that can be ignored, or skipped
18084 : : * using "pg_restore -L" if you prefer.) The last point motivates
18085 : : * treating ATTACH PARTITION as a completely separate ArchiveEntry
18086 : : * rather than emitting it within the child partition's ArchiveEntry.
18087 : : */
18088 : : static void
1720 peter@eisentraut.org 18089 : 1381 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
18090 : : {
1750 tgl@sss.pgh.pa.us 18091 : 1381 : DumpOptions *dopt = fout->dopt;
18092 : : PQExpBuffer q;
18093 : : PGresult *res;
18094 : : char *partbound;
18095 : :
18096 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 18097 [ + + ]: 1381 : if (!dopt->dumpSchema)
1750 tgl@sss.pgh.pa.us 18098 : 54 : return;
18099 : :
18100 : 1327 : q = createPQExpBuffer();
18101 : :
1421 18102 [ + + ]: 1327 : if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
18103 : : {
18104 : : /* Set up query for partbound details */
18105 : 43 : appendPQExpBufferStr(q,
18106 : : "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
18107 : :
18108 : 43 : appendPQExpBufferStr(q,
18109 : : "SELECT pg_get_expr(c.relpartbound, c.oid) "
18110 : : "FROM pg_class c "
18111 : : "WHERE c.oid = $1");
18112 : :
18113 : 43 : ExecuteSqlStatement(fout, q->data);
18114 : :
18115 : 43 : fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
18116 : : }
18117 : :
18118 : 1327 : printfPQExpBuffer(q,
18119 : : "EXECUTE dumpTableAttach('%u')",
18120 : 1327 : attachinfo->partitionTbl->dobj.catId.oid);
18121 : :
18122 : 1327 : res = ExecuteSqlQueryForSingleRow(fout, q->data);
18123 : 1327 : partbound = PQgetvalue(res, 0, 0);
18124 : :
18125 : : /* Perform ALTER TABLE on the parent */
18126 : 1327 : printfPQExpBuffer(q,
18127 : : "ALTER TABLE ONLY %s ",
1750 18128 : 1327 : fmtQualifiedDumpable(attachinfo->parentTbl));
18129 : 1327 : appendPQExpBuffer(q,
18130 : : "ATTACH PARTITION %s %s;\n",
18131 : 1327 : fmtQualifiedDumpable(attachinfo->partitionTbl),
18132 : : partbound);
18133 : :
18134 : : /*
18135 : : * There is no point in creating a drop query as the drop is done by table
18136 : : * drop. (If you think to change this, see also _printTocEntry().)
18137 : : * Although this object doesn't really have ownership as such, set the
18138 : : * owner field anyway to ensure that the command is run by the correct
18139 : : * role at restore time.
18140 : : */
18141 : 1327 : ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
18142 : 1327 : ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
18143 : : .namespace = attachinfo->dobj.namespace->dobj.name,
18144 : : .owner = attachinfo->partitionTbl->rolname,
18145 : : .description = "TABLE ATTACH",
18146 : : .section = SECTION_PRE_DATA,
18147 : : .createStmt = q->data));
18148 : :
1421 18149 : 1327 : PQclear(res);
1750 18150 : 1327 : destroyPQExpBuffer(q);
18151 : : }
18152 : :
18153 : : /*
18154 : : * dumpAttrDef --- dump an attribute's default-value declaration
18155 : : */
18156 : : static void
1720 peter@eisentraut.org 18157 : 1032 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
18158 : : {
3575 tgl@sss.pgh.pa.us 18159 : 1032 : DumpOptions *dopt = fout->dopt;
7996 18160 : 1032 : TableInfo *tbinfo = adinfo->adtable;
18161 : 1032 : int adnum = adinfo->adnum;
18162 : : PQExpBuffer q;
18163 : : PQExpBuffer delq;
18164 : : char *qualrelname;
18165 : : char *tag;
18166 : : char *foreign;
18167 : :
18168 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 18169 [ - + ]: 1032 : if (!dopt->dumpSchema)
7996 tgl@sss.pgh.pa.us 18170 :UBC 0 : return;
18171 : :
18172 : : /* Skip if not "separate"; it was dumped in the table's definition */
5008 tgl@sss.pgh.pa.us 18173 [ + + ]:CBC 1032 : if (!adinfo->separate)
7996 18174 : 866 : return;
18175 : :
18176 : 166 : q = createPQExpBuffer();
18177 : 166 : delq = createPQExpBuffer();
18178 : :
2800 18179 : 166 : qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
18180 : :
2047 alvherre@alvh.no-ip. 18181 [ - + ]: 166 : foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
18182 : :
18183 : 166 : appendPQExpBuffer(q,
18184 : : "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
18185 : 166 : foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
7996 tgl@sss.pgh.pa.us 18186 : 166 : adinfo->adef_expr);
18187 : :
2047 alvherre@alvh.no-ip. 18188 : 166 : appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
18189 : : foreign, qualrelname,
7996 tgl@sss.pgh.pa.us 18190 : 166 : fmtId(tbinfo->attnames[adnum - 1]));
18191 : :
3532 peter_e@gmx.net 18192 : 166 : tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
18193 : :
3491 sfrost@snowman.net 18194 [ + - ]: 166 : if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18195 : 166 : ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 18196 : 166 : ARCHIVE_OPTS(.tag = tag,
18197 : : .namespace = tbinfo->dobj.namespace->dobj.name,
18198 : : .owner = tbinfo->rolname,
18199 : : .description = "DEFAULT",
18200 : : .section = SECTION_PRE_DATA,
18201 : : .createStmt = q->data,
18202 : : .dropStmt = delq->data));
18203 : :
3532 peter_e@gmx.net 18204 : 166 : free(tag);
7996 tgl@sss.pgh.pa.us 18205 : 166 : destroyPQExpBuffer(q);
18206 : 166 : destroyPQExpBuffer(delq);
2800 18207 : 166 : free(qualrelname);
18208 : : }
18209 : :
18210 : : /*
18211 : : * getAttrName: extract the correct name for an attribute
18212 : : *
18213 : : * The array tblInfo->attnames[] only provides names of user attributes;
18214 : : * if a system attribute number is supplied, we have to fake it.
18215 : : * We also do a little bit of bounds checking for safety's sake.
18216 : : */
18217 : : static const char *
1720 peter@eisentraut.org 18218 : 2039 : getAttrName(int attrnum, const TableInfo *tblInfo)
18219 : : {
8954 tgl@sss.pgh.pa.us 18220 [ + - + - ]: 2039 : if (attrnum > 0 && attrnum <= tblInfo->numatts)
8768 bruce@momjian.us 18221 : 2039 : return tblInfo->attnames[attrnum - 1];
8954 tgl@sss.pgh.pa.us 18222 [ # # # # :UBC 0 : switch (attrnum)
# # # ]
18223 : : {
18224 : 0 : case SelfItemPointerAttributeNumber:
18225 : 0 : return "ctid";
18226 : 0 : case MinTransactionIdAttributeNumber:
18227 : 0 : return "xmin";
18228 : 0 : case MinCommandIdAttributeNumber:
18229 : 0 : return "cmin";
18230 : 0 : case MaxTransactionIdAttributeNumber:
18231 : 0 : return "xmax";
18232 : 0 : case MaxCommandIdAttributeNumber:
18233 : 0 : return "cmax";
18234 : 0 : case TableOidAttributeNumber:
18235 : 0 : return "tableoid";
18236 : : }
1298 18237 : 0 : pg_fatal("invalid column number %d for table \"%s\"",
18238 : : attrnum, tblInfo->dobj.name);
18239 : : return NULL; /* keep compiler quiet */
18240 : : }
18241 : :
18242 : : /*
18243 : : * dumpIndex
18244 : : * write out to fout a user-defined index
18245 : : */
18246 : : static void
1720 peter@eisentraut.org 18247 :CBC 2574 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
18248 : : {
3575 tgl@sss.pgh.pa.us 18249 : 2574 : DumpOptions *dopt = fout->dopt;
7996 18250 : 2574 : TableInfo *tbinfo = indxinfo->indextable;
4505 18251 : 2574 : bool is_constraint = (indxinfo->indexconstraint != 0);
18252 : : PQExpBuffer q;
18253 : : PQExpBuffer delq;
18254 : : char *qindxname;
18255 : : char *qqindxname;
18256 : :
18257 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 18258 [ + + ]: 2574 : if (!dopt->dumpSchema)
7996 tgl@sss.pgh.pa.us 18259 : 117 : return;
18260 : :
18261 : 2457 : q = createPQExpBuffer();
18262 : 2457 : delq = createPQExpBuffer();
18263 : :
2800 18264 : 2457 : qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
2056 alvherre@alvh.no-ip. 18265 : 2457 : qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
18266 : :
18267 : : /*
18268 : : * If there's an associated constraint, don't dump the index per se, but
18269 : : * do dump any comment for it. (This is safe because dependency ordering
18270 : : * will have ensured the constraint is emitted first.) Note that the
18271 : : * emitted comment has to be shown as depending on the constraint, not the
18272 : : * index, in such cases.
18273 : : */
4505 tgl@sss.pgh.pa.us 18274 [ + + ]: 2457 : if (!is_constraint)
18275 : : {
2505 michael@paquier.xyz 18276 : 1035 : char *indstatcols = indxinfo->indstatcols;
18277 : 1035 : char *indstatvals = indxinfo->indstatvals;
18278 : 1035 : char **indstatcolsarray = NULL;
18279 : 1035 : char **indstatvalsarray = NULL;
1803 18280 : 1035 : int nstatcols = 0;
18281 : 1035 : int nstatvals = 0;
18282 : :
4031 alvherre@alvh.no-ip. 18283 [ + + ]: 1035 : if (dopt->binary_upgrade)
5011 rhaas@postgresql.org 18284 : 156 : binary_upgrade_set_pg_class_oids(fout, q,
481 nathan@postgresql.or 18285 : 156 : indxinfo->dobj.catId.oid);
18286 : :
18287 : : /* Plain secondary index */
7996 tgl@sss.pgh.pa.us 18288 : 1035 : appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
18289 : :
18290 : : /*
18291 : : * Append ALTER TABLE commands as needed to set properties that we
18292 : : * only have ALTER TABLE syntax for. Keep this in sync with the
18293 : : * similar code in dumpConstraint!
18294 : : */
18295 : :
18296 : : /* If the index is clustered, we need to record that. */
18297 [ - + ]: 1035 : if (indxinfo->indisclustered)
18298 : : {
7996 tgl@sss.pgh.pa.us 18299 :UBC 0 : appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
2800 18300 : 0 : fmtQualifiedDumpable(tbinfo));
18301 : : /* index name is not qualified in this syntax */
7996 18302 : 0 : appendPQExpBuffer(q, " ON %s;\n",
18303 : : qindxname);
18304 : : }
18305 : :
18306 : : /*
18307 : : * If the index has any statistics on some of its columns, generate
18308 : : * the associated ALTER INDEX queries.
18309 : : */
1803 michael@paquier.xyz 18310 [ + + - + ]:CBC 1035 : if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
18311 : : {
18312 : : int j;
18313 : :
18314 [ - + ]: 32 : if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
1298 tgl@sss.pgh.pa.us 18315 :UBC 0 : pg_fatal("could not parse index statistic columns");
1803 michael@paquier.xyz 18316 [ - + ]:CBC 32 : if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
1298 tgl@sss.pgh.pa.us 18317 :UBC 0 : pg_fatal("could not parse index statistic values");
1803 michael@paquier.xyz 18318 [ - + ]:CBC 32 : if (nstatcols != nstatvals)
1298 tgl@sss.pgh.pa.us 18319 :UBC 0 : pg_fatal("mismatched number of columns and values for index statistics");
18320 : :
2505 michael@paquier.xyz 18321 [ + + ]:CBC 96 : for (j = 0; j < nstatcols; j++)
18322 : : {
2056 alvherre@alvh.no-ip. 18323 : 64 : appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
18324 : :
18325 : : /*
18326 : : * Note that this is a column number, so no quotes should be
18327 : : * used.
18328 : : */
2505 michael@paquier.xyz 18329 : 64 : appendPQExpBuffer(q, "ALTER COLUMN %s ",
18330 : 64 : indstatcolsarray[j]);
18331 : 64 : appendPQExpBuffer(q, "SET STATISTICS %s;\n",
18332 : 64 : indstatvalsarray[j]);
18333 : : }
18334 : : }
18335 : :
18336 : : /* Indexes can depend on extensions */
2056 alvherre@alvh.no-ip. 18337 : 1035 : append_depends_on_extension(fout, q, &indxinfo->dobj,
18338 : : "pg_catalog.pg_class",
18339 : : "INDEX", qqindxname);
18340 : :
18341 : : /* If the index defines identity, we need to record that. */
4371 rhaas@postgresql.org 18342 [ - + ]: 1035 : if (indxinfo->indisreplident)
18343 : : {
4371 rhaas@postgresql.org 18344 :UBC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
2800 tgl@sss.pgh.pa.us 18345 : 0 : fmtQualifiedDumpable(tbinfo));
18346 : : /* index name is not qualified in this syntax */
4371 rhaas@postgresql.org 18347 : 0 : appendPQExpBuffer(q, " INDEX %s;\n",
18348 : : qindxname);
18349 : : }
18350 : :
18351 : : /*
18352 : : * If this index is a member of a partitioned index, the backend will
18353 : : * not allow us to drop it separately, so don't try. It will go away
18354 : : * automatically when we drop either the index's table or the
18355 : : * partitioned index. (If, in a selective restore with --clean, we
18356 : : * drop neither of those, then this index will not be dropped either.
18357 : : * But that's fine, and even if you think it's not, the backend won't
18358 : : * let us do differently.)
18359 : : */
194 tgl@sss.pgh.pa.us 18360 [ + + ]:CBC 1035 : if (indxinfo->parentidx == 0)
18361 : 853 : appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
18362 : :
3491 sfrost@snowman.net 18363 [ + - ]: 1035 : if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18364 : 1035 : ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 18365 : 1035 : ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
18366 : : .namespace = tbinfo->dobj.namespace->dobj.name,
18367 : : .tablespace = indxinfo->tablespace,
18368 : : .owner = tbinfo->rolname,
18369 : : .description = "INDEX",
18370 : : .section = SECTION_POST_DATA,
18371 : : .createStmt = q->data,
18372 : : .dropStmt = delq->data));
18373 : :
1229 peter@eisentraut.org 18374 : 1035 : free(indstatcolsarray);
18375 : 1035 : free(indstatvalsarray);
18376 : : }
18377 : :
18378 : : /* Dump Index Comments */
3491 sfrost@snowman.net 18379 [ + + ]: 2457 : if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 18380 [ + + ]: 15 : dumpComment(fout, "INDEX", qindxname,
3491 sfrost@snowman.net 18381 : 15 : tbinfo->dobj.namespace->dobj.name,
18382 : : tbinfo->rolname,
18383 : : indxinfo->dobj.catId, 0,
18384 : : is_constraint ? indxinfo->indexconstraint :
18385 : : indxinfo->dobj.dumpId);
18386 : :
7996 tgl@sss.pgh.pa.us 18387 : 2457 : destroyPQExpBuffer(q);
18388 : 2457 : destroyPQExpBuffer(delq);
2800 18389 : 2457 : free(qindxname);
2056 alvherre@alvh.no-ip. 18390 : 2457 : free(qqindxname);
18391 : : }
18392 : :
18393 : : /*
18394 : : * dumpIndexAttach
18395 : : * write out to fout a partitioned-index attachment clause
18396 : : */
18397 : : static void
1720 peter@eisentraut.org 18398 : 564 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
18399 : : {
18400 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 18401 [ + + ]: 564 : if (!fout->dopt->dumpSchema)
2838 alvherre@alvh.no-ip. 18402 : 48 : return;
18403 : :
18404 [ + - ]: 516 : if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
18405 : : {
2835 tgl@sss.pgh.pa.us 18406 : 516 : PQExpBuffer q = createPQExpBuffer();
18407 : :
2617 18408 : 516 : appendPQExpBuffer(q, "ALTER INDEX %s ",
2800 18409 : 516 : fmtQualifiedDumpable(attachinfo->parentIdx));
2838 alvherre@alvh.no-ip. 18410 : 516 : appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
2800 tgl@sss.pgh.pa.us 18411 : 516 : fmtQualifiedDumpable(attachinfo->partitionIdx));
18412 : :
18413 : : /*
18414 : : * There is no need for a dropStmt since the drop is done implicitly
18415 : : * when we drop either the index's table or the partitioned index.
18416 : : * Moreover, since there's no ALTER INDEX DETACH PARTITION command,
18417 : : * there's no way to do it anyway. (If you think to change this,
18418 : : * consider also what to do with --if-exists.)
18419 : : *
18420 : : * Although this object doesn't really have ownership as such, set the
18421 : : * owner field anyway to ensure that the command is run by the correct
18422 : : * role at restore time.
18423 : : */
2838 alvherre@alvh.no-ip. 18424 : 516 : ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
2460 18425 : 516 : ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
18426 : : .namespace = attachinfo->dobj.namespace->dobj.name,
18427 : : .owner = attachinfo->parentIdx->indextable->rolname,
18428 : : .description = "INDEX ATTACH",
18429 : : .section = SECTION_POST_DATA,
18430 : : .createStmt = q->data));
18431 : :
2838 18432 : 516 : destroyPQExpBuffer(q);
18433 : : }
18434 : : }
18435 : :
18436 : : /*
18437 : : * dumpStatisticsExt
18438 : : * write out to fout an extended statistics object
18439 : : */
18440 : : static void
1720 peter@eisentraut.org 18441 : 133 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
18442 : : {
3139 alvherre@alvh.no-ip. 18443 : 133 : DumpOptions *dopt = fout->dopt;
18444 : : PQExpBuffer q;
18445 : : PQExpBuffer delq;
18446 : : PQExpBuffer query;
18447 : : char *qstatsextname;
18448 : : PGresult *res;
18449 : : char *stxdef;
18450 : :
18451 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 18452 [ + + ]: 133 : if (!dopt->dumpSchema)
3139 alvherre@alvh.no-ip. 18453 : 18 : return;
18454 : :
18455 : 115 : q = createPQExpBuffer();
18456 : 115 : delq = createPQExpBuffer();
2815 tgl@sss.pgh.pa.us 18457 : 115 : query = createPQExpBuffer();
18458 : :
2800 18459 : 115 : qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
18460 : :
2815 18461 : 115 : appendPQExpBuffer(query, "SELECT "
18462 : : "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
18463 : 115 : statsextinfo->dobj.catId.oid);
18464 : :
18465 : 115 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
18466 : :
18467 : 115 : stxdef = PQgetvalue(res, 0, 0);
18468 : :
18469 : : /* Result of pg_get_statisticsobjdef is complete except for semicolon */
18470 : 115 : appendPQExpBuffer(q, "%s;\n", stxdef);
18471 : :
18472 : : /*
18473 : : * We only issue an ALTER STATISTICS statement if the stxstattarget entry
18474 : : * for this statistics object is not the default value.
18475 : : */
2239 tomas.vondra@postgre 18476 [ + + ]: 115 : if (statsextinfo->stattarget >= 0)
18477 : : {
18478 : 32 : appendPQExpBuffer(q, "ALTER STATISTICS %s ",
18479 : 32 : fmtQualifiedDumpable(statsextinfo));
18480 : 32 : appendPQExpBuffer(q, "SET STATISTICS %d;\n",
18481 : 32 : statsextinfo->stattarget);
18482 : : }
18483 : :
2800 tgl@sss.pgh.pa.us 18484 : 115 : appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
18485 : 115 : fmtQualifiedDumpable(statsextinfo));
18486 : :
3139 alvherre@alvh.no-ip. 18487 [ + - ]: 115 : if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3085 bruce@momjian.us 18488 : 115 : ArchiveEntry(fout, statsextinfo->dobj.catId,
18489 : 115 : statsextinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 18490 : 115 : ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
18491 : : .namespace = statsextinfo->dobj.namespace->dobj.name,
18492 : : .owner = statsextinfo->rolname,
18493 : : .description = "STATISTICS",
18494 : : .section = SECTION_POST_DATA,
18495 : : .createStmt = q->data,
18496 : : .dropStmt = delq->data));
18497 : :
18498 : : /* Dump Statistics Comments */
3139 18499 [ - + ]: 115 : if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 18500 :UBC 0 : dumpComment(fout, "STATISTICS", qstatsextname,
2815 18501 : 0 : statsextinfo->dobj.namespace->dobj.name,
18502 : 0 : statsextinfo->rolname,
18503 : : statsextinfo->dobj.catId, 0,
3139 alvherre@alvh.no-ip. 18504 : 0 : statsextinfo->dobj.dumpId);
18505 : :
2815 tgl@sss.pgh.pa.us 18506 :CBC 115 : PQclear(res);
3139 alvherre@alvh.no-ip. 18507 : 115 : destroyPQExpBuffer(q);
18508 : 115 : destroyPQExpBuffer(delq);
2815 tgl@sss.pgh.pa.us 18509 : 115 : destroyPQExpBuffer(query);
2800 18510 : 115 : free(qstatsextname);
18511 : : }
18512 : :
18513 : : /*
18514 : : * dumpConstraint
18515 : : * write out to fout a user-defined constraint
18516 : : */
18517 : : static void
1720 peter@eisentraut.org 18518 : 2473 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
18519 : : {
3575 tgl@sss.pgh.pa.us 18520 : 2473 : DumpOptions *dopt = fout->dopt;
7996 18521 : 2473 : TableInfo *tbinfo = coninfo->contable;
18522 : : PQExpBuffer q;
18523 : : PQExpBuffer delq;
3532 peter_e@gmx.net 18524 : 2473 : char *tag = NULL;
18525 : : char *foreign;
18526 : :
18527 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 18528 [ + + ]: 2473 : if (!dopt->dumpSchema)
7996 tgl@sss.pgh.pa.us 18529 : 98 : return;
18530 : :
18531 : 2375 : q = createPQExpBuffer();
18532 : 2375 : delq = createPQExpBuffer();
18533 : :
2047 alvherre@alvh.no-ip. 18534 : 4596 : foreign = tbinfo &&
1992 tgl@sss.pgh.pa.us 18535 [ + + - + ]: 2375 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
18536 : :
5803 18537 [ + + ]: 2375 : if (coninfo->contype == 'p' ||
18538 [ + + ]: 1192 : coninfo->contype == 'u' ||
18539 [ + + ]: 963 : coninfo->contype == 'x')
7996 18540 : 1422 : {
18541 : : /* Index-related constraint */
18542 : : IndxInfo *indxinfo;
18543 : : int k;
18544 : :
18545 : 1422 : indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
18546 : :
18547 [ - + ]: 1422 : if (indxinfo == NULL)
1298 tgl@sss.pgh.pa.us 18548 :UBC 0 : pg_fatal("missing index for constraint \"%s\"",
18549 : : coninfo->dobj.name);
18550 : :
4031 alvherre@alvh.no-ip. 18551 [ + + ]:CBC 1422 : if (dopt->binary_upgrade)
5011 rhaas@postgresql.org 18552 : 146 : binary_upgrade_set_pg_class_oids(fout, q,
18553 : : indxinfo->dobj.catId.oid);
18554 : :
2047 alvherre@alvh.no-ip. 18555 : 1422 : appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
2800 tgl@sss.pgh.pa.us 18556 : 1422 : fmtQualifiedDumpable(tbinfo));
5803 18557 : 1422 : appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
18558 : 1422 : fmtId(coninfo->dobj.name));
18559 : :
18560 [ + + ]: 1422 : if (coninfo->condef)
18561 : : {
18562 : : /* pg_get_constraintdef should have provided everything */
18563 : 10 : appendPQExpBuffer(q, "%s;\n", coninfo->condef);
18564 : : }
18565 : : else
18566 : : {
1147 drowley@postgresql.o 18567 : 1412 : appendPQExpBufferStr(q,
18568 [ + + ]: 1412 : coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
18569 : :
18570 : : /*
18571 : : * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
18572 : : * indexes. Being able to create this was fixed, but we need to
18573 : : * make the index distinct in order to be able to restore the
18574 : : * dump.
18575 : : */
976 dgustafsson@postgres 18576 [ - + - - ]: 1412 : if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
1147 drowley@postgresql.o 18577 :UBC 0 : appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
1147 drowley@postgresql.o 18578 :CBC 1412 : appendPQExpBufferStr(q, " (");
2760 teodor@sigaev.ru 18579 [ + + ]: 3411 : for (k = 0; k < indxinfo->indnkeyattrs; k++)
18580 : : {
5803 tgl@sss.pgh.pa.us 18581 : 1999 : int indkey = (int) indxinfo->indkeys[k];
18582 : : const char *attname;
18583 : :
18584 [ - + ]: 1999 : if (indkey == InvalidAttrNumber)
5803 tgl@sss.pgh.pa.us 18585 :UBC 0 : break;
5803 tgl@sss.pgh.pa.us 18586 :CBC 1999 : attname = getAttrName(indkey, tbinfo);
18587 : :
18588 [ + + ]: 1999 : appendPQExpBuffer(q, "%s%s",
18589 : : (k == 0) ? "" : ", ",
18590 : : fmtId(attname));
18591 : : }
405 peter@eisentraut.org 18592 [ + + ]: 1412 : if (coninfo->conperiod)
18593 : 104 : appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
18594 : :
2760 teodor@sigaev.ru 18595 [ + + ]: 1412 : if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
2307 drowley@postgresql.o 18596 : 20 : appendPQExpBufferStr(q, ") INCLUDE (");
18597 : :
2760 teodor@sigaev.ru 18598 [ + + ]: 1452 : for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
18599 : : {
18600 : 40 : int indkey = (int) indxinfo->indkeys[k];
18601 : : const char *attname;
18602 : :
18603 [ - + ]: 40 : if (indkey == InvalidAttrNumber)
2760 teodor@sigaev.ru 18604 :UBC 0 : break;
2760 teodor@sigaev.ru 18605 :CBC 40 : attname = getAttrName(indkey, tbinfo);
18606 : :
18607 : 80 : appendPQExpBuffer(q, "%s%s",
18608 [ + + ]: 40 : (k == indxinfo->indnkeyattrs) ? "" : ", ",
18609 : : fmtId(attname));
18610 : : }
18611 : :
4361 heikki.linnakangas@i 18612 : 1412 : appendPQExpBufferChar(q, ')');
18613 : :
3586 tgl@sss.pgh.pa.us 18614 [ - + ]: 1412 : if (nonemptyReloptions(indxinfo->indreloptions))
18615 : : {
3586 tgl@sss.pgh.pa.us 18616 :UBC 0 : appendPQExpBufferStr(q, " WITH (");
3461 dean.a.rasheed@gmail 18617 : 0 : appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
3586 tgl@sss.pgh.pa.us 18618 : 0 : appendPQExpBufferChar(q, ')');
18619 : : }
18620 : :
5803 tgl@sss.pgh.pa.us 18621 [ + + ]:CBC 1412 : if (coninfo->condeferrable)
18622 : : {
4361 heikki.linnakangas@i 18623 : 25 : appendPQExpBufferStr(q, " DEFERRABLE");
5803 tgl@sss.pgh.pa.us 18624 [ + + ]: 25 : if (coninfo->condeferred)
4361 heikki.linnakangas@i 18625 : 15 : appendPQExpBufferStr(q, " INITIALLY DEFERRED");
18626 : : }
18627 : :
18628 : 1412 : appendPQExpBufferStr(q, ";\n");
18629 : : }
18630 : :
18631 : : /*
18632 : : * Append ALTER TABLE commands as needed to set properties that we
18633 : : * only have ALTER TABLE syntax for. Keep this in sync with the
18634 : : * similar code in dumpIndex!
18635 : : */
18636 : :
18637 : : /* If the index is clustered, we need to record that. */
7996 tgl@sss.pgh.pa.us 18638 [ + + ]: 1422 : if (indxinfo->indisclustered)
18639 : : {
18640 : 32 : appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
2800 18641 : 32 : fmtQualifiedDumpable(tbinfo));
18642 : : /* index name is not qualified in this syntax */
7996 18643 : 32 : appendPQExpBuffer(q, " ON %s;\n",
7908 18644 : 32 : fmtId(indxinfo->dobj.name));
18645 : : }
18646 : :
18647 : : /* If the index defines identity, we need to record that. */
2646 18648 [ - + ]: 1422 : if (indxinfo->indisreplident)
18649 : : {
2646 tgl@sss.pgh.pa.us 18650 :UBC 0 : appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
18651 : 0 : fmtQualifiedDumpable(tbinfo));
18652 : : /* index name is not qualified in this syntax */
18653 : 0 : appendPQExpBuffer(q, " INDEX %s;\n",
18654 : 0 : fmtId(indxinfo->dobj.name));
18655 : : }
18656 : :
18657 : : /* Indexes can depend on extensions */
2056 alvherre@alvh.no-ip. 18658 :CBC 1422 : append_depends_on_extension(fout, q, &indxinfo->dobj,
18659 : : "pg_catalog.pg_class", "INDEX",
18660 : 1422 : fmtQualifiedDumpable(indxinfo));
18661 : :
2047 18662 : 1422 : appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
2800 tgl@sss.pgh.pa.us 18663 : 1422 : fmtQualifiedDumpable(tbinfo));
7996 18664 : 1422 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
7908 18665 : 1422 : fmtId(coninfo->dobj.name));
18666 : :
3532 peter_e@gmx.net 18667 : 1422 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18668 : :
3491 sfrost@snowman.net 18669 [ + - ]: 1422 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18670 : 1422 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 18671 : 1422 : ARCHIVE_OPTS(.tag = tag,
18672 : : .namespace = tbinfo->dobj.namespace->dobj.name,
18673 : : .tablespace = indxinfo->tablespace,
18674 : : .owner = tbinfo->rolname,
18675 : : .description = "CONSTRAINT",
18676 : : .section = SECTION_POST_DATA,
18677 : : .createStmt = q->data,
18678 : : .dropStmt = delq->data));
18679 : : }
7996 tgl@sss.pgh.pa.us 18680 [ + + ]: 953 : else if (coninfo->contype == 'f')
18681 : : {
18682 : : char *only;
18683 : :
18684 : : /*
18685 : : * Foreign keys on partitioned tables are always declared as
18686 : : * inheriting to partitions; for all other cases, emit them as
18687 : : * applying ONLY directly to the named table, because that's how they
18688 : : * work for regular inherited tables.
18689 : : */
2763 alvherre@alvh.no-ip. 18690 [ + + ]: 159 : only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
18691 : :
18692 : : /*
18693 : : * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
18694 : : * current table data is not processed
18695 : : */
2047 18696 : 159 : appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
2763 18697 : 159 : only, fmtQualifiedDumpable(tbinfo));
7996 tgl@sss.pgh.pa.us 18698 : 159 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
7908 18699 : 159 : fmtId(coninfo->dobj.name),
7996 18700 : 159 : coninfo->condef);
18701 : :
2047 alvherre@alvh.no-ip. 18702 : 159 : appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
2763 18703 : 159 : only, fmtQualifiedDumpable(tbinfo));
7996 tgl@sss.pgh.pa.us 18704 : 159 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
7908 18705 : 159 : fmtId(coninfo->dobj.name));
18706 : :
3532 peter_e@gmx.net 18707 : 159 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18708 : :
3491 sfrost@snowman.net 18709 [ + - ]: 159 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18710 : 159 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 18711 : 159 : ARCHIVE_OPTS(.tag = tag,
18712 : : .namespace = tbinfo->dobj.namespace->dobj.name,
18713 : : .owner = tbinfo->rolname,
18714 : : .description = "FK CONSTRAINT",
18715 : : .section = SECTION_POST_DATA,
18716 : : .createStmt = q->data,
18717 : : .dropStmt = delq->data));
18718 : : }
203 18719 [ + + + - : 794 : else if ((coninfo->contype == 'c' || coninfo->contype == 'n') && tbinfo)
+ + ]
18720 : : {
18721 : : /* CHECK or invalid not-null constraint on a table */
18722 : :
18723 : : /* Ignore if not to be dumped separately, or if it was inherited */
3679 tgl@sss.pgh.pa.us 18724 [ + + + + ]: 640 : if (coninfo->separate && coninfo->conislocal)
18725 : : {
18726 : : const char *keyword;
18727 : :
203 alvherre@alvh.no-ip. 18728 [ + + ]: 107 : if (coninfo->contype == 'c')
18729 : 45 : keyword = "CHECK CONSTRAINT";
18730 : : else
18731 : 62 : keyword = "CONSTRAINT";
18732 : :
18733 : : /* not ONLY since we want it to propagate to children */
2047 18734 : 107 : appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
2800 tgl@sss.pgh.pa.us 18735 : 107 : fmtQualifiedDumpable(tbinfo));
7996 18736 : 107 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
7908 18737 : 107 : fmtId(coninfo->dobj.name),
7996 18738 : 107 : coninfo->condef);
18739 : :
2047 alvherre@alvh.no-ip. 18740 : 107 : appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
2800 tgl@sss.pgh.pa.us 18741 : 107 : fmtQualifiedDumpable(tbinfo));
7996 18742 : 107 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
7908 18743 : 107 : fmtId(coninfo->dobj.name));
18744 : :
3532 peter_e@gmx.net 18745 : 107 : tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
18746 : :
3491 sfrost@snowman.net 18747 [ + - ]: 107 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18748 : 107 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 18749 : 107 : ARCHIVE_OPTS(.tag = tag,
18750 : : .namespace = tbinfo->dobj.namespace->dobj.name,
18751 : : .owner = tbinfo->rolname,
18752 : : .description = keyword,
18753 : : .section = SECTION_POST_DATA,
18754 : : .createStmt = q->data,
18755 : : .dropStmt = delq->data));
18756 : : }
18757 : : }
98 alvherre@kurilemu.de 18758 [ + - ]: 154 : else if (tbinfo == NULL)
18759 : : {
18760 : : /* CHECK, NOT NULL constraint on a domain */
5787 bruce@momjian.us 18761 : 154 : TypeInfo *tyinfo = coninfo->condomain;
18762 : :
98 alvherre@kurilemu.de 18763 [ + + - + ]: 154 : Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
18764 : :
18765 : : /* Ignore if not to be dumped separately */
7179 tgl@sss.pgh.pa.us 18766 [ + + ]: 154 : if (coninfo->separate)
18767 : : {
18768 : : const char *keyword;
18769 : :
98 alvherre@kurilemu.de 18770 [ + - ]: 5 : if (coninfo->contype == 'c')
18771 : 5 : keyword = "CHECK CONSTRAINT";
18772 : : else
98 alvherre@kurilemu.de 18773 :UBC 0 : keyword = "CONSTRAINT";
18774 : :
7996 tgl@sss.pgh.pa.us 18775 :CBC 5 : appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
2800 18776 : 5 : fmtQualifiedDumpable(tyinfo));
7996 18777 : 5 : appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
7908 18778 : 5 : fmtId(coninfo->dobj.name),
7996 18779 : 5 : coninfo->condef);
18780 : :
2800 18781 : 5 : appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
18782 : 5 : fmtQualifiedDumpable(tyinfo));
7996 18783 : 5 : appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
7908 18784 : 5 : fmtId(coninfo->dobj.name));
18785 : :
3532 peter_e@gmx.net 18786 : 5 : tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
18787 : :
3491 sfrost@snowman.net 18788 [ + - ]: 5 : if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18789 : 5 : ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 18790 : 5 : ARCHIVE_OPTS(.tag = tag,
18791 : : .namespace = tyinfo->dobj.namespace->dobj.name,
18792 : : .owner = tyinfo->rolname,
18793 : : .description = keyword,
18794 : : .section = SECTION_POST_DATA,
18795 : : .createStmt = q->data,
18796 : : .dropStmt = delq->data));
18797 : :
103 alvherre@kurilemu.de 18798 [ + - ]: 5 : if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18799 : : {
18800 : 5 : PQExpBuffer conprefix = createPQExpBuffer();
18801 : 5 : char *qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
18802 : :
18803 : 5 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
18804 : 5 : fmtId(coninfo->dobj.name));
18805 : :
18806 : 5 : dumpComment(fout, conprefix->data, qtypname,
18807 : 5 : tyinfo->dobj.namespace->dobj.name,
18808 : : tyinfo->rolname,
41 noah@leadboat.com 18809 : 5 : coninfo->dobj.catId, 0, coninfo->dobj.dumpId);
103 alvherre@kurilemu.de 18810 : 5 : destroyPQExpBuffer(conprefix);
18811 : 5 : free(qtypname);
18812 : : }
18813 : : }
18814 : : }
18815 : : else
18816 : : {
1298 tgl@sss.pgh.pa.us 18817 :UBC 0 : pg_fatal("unrecognized constraint type: %c",
18818 : : coninfo->contype);
18819 : : }
18820 : :
18821 : : /* Dump Constraint Comments --- only works for table constraints */
3491 sfrost@snowman.net 18822 [ + + + + ]:CBC 2375 : if (tbinfo && coninfo->separate &&
18823 [ + + ]: 1718 : coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3575 tgl@sss.pgh.pa.us 18824 : 47 : dumpTableConstraintComment(fout, coninfo);
18825 : :
3532 peter_e@gmx.net 18826 : 2375 : free(tag);
8571 tgl@sss.pgh.pa.us 18827 : 2375 : destroyPQExpBuffer(q);
18828 : 2375 : destroyPQExpBuffer(delq);
18829 : : }
18830 : :
18831 : : /*
18832 : : * dumpTableConstraintComment --- dump a constraint's comment if any
18833 : : *
18834 : : * This is split out because we need the function in two different places
18835 : : * depending on whether the constraint is dumped as part of CREATE TABLE
18836 : : * or as a separate ALTER command.
18837 : : */
18838 : : static void
1720 peter@eisentraut.org 18839 : 84 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
18840 : : {
7622 tgl@sss.pgh.pa.us 18841 : 84 : TableInfo *tbinfo = coninfo->contable;
2800 18842 : 84 : PQExpBuffer conprefix = createPQExpBuffer();
18843 : : char *qtabname;
18844 : :
18845 : 84 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
18846 : :
18847 : 84 : appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
7622 18848 : 84 : fmtId(coninfo->dobj.name));
18849 : :
3491 sfrost@snowman.net 18850 [ + - ]: 84 : if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 18851 : 84 : dumpComment(fout, conprefix->data, qtabname,
3491 sfrost@snowman.net 18852 : 84 : tbinfo->dobj.namespace->dobj.name,
18853 : : tbinfo->rolname,
18854 : : coninfo->dobj.catId, 0,
3050 tgl@sss.pgh.pa.us 18855 [ + + ]: 84 : coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
18856 : :
2800 18857 : 84 : destroyPQExpBuffer(conprefix);
18858 : 84 : free(qtabname);
7622 18859 : 84 : }
18860 : :
18861 : : static inline SeqType
453 nathan@postgresql.or 18862 : 638 : parse_sequence_type(const char *name)
18863 : : {
18864 [ + - ]: 1425 : for (int i = 0; i < lengthof(SeqTypeNames); i++)
18865 : : {
18866 [ + + ]: 1425 : if (strcmp(SeqTypeNames[i], name) == 0)
18867 : 638 : return (SeqType) i;
18868 : : }
18869 : :
453 nathan@postgresql.or 18870 :UBC 0 : pg_fatal("unrecognized sequence type: %s", name);
18871 : : return (SeqType) 0; /* keep compiler quiet */
18872 : : }
18873 : :
18874 : : /*
18875 : : * bsearch() comparator for SequenceItem
18876 : : */
18877 : : static int
453 nathan@postgresql.or 18878 :CBC 2954 : SequenceItemCmp(const void *p1, const void *p2)
18879 : : {
18880 : 2954 : SequenceItem v1 = *((const SequenceItem *) p1);
18881 : 2954 : SequenceItem v2 = *((const SequenceItem *) p2);
18882 : :
18883 : 2954 : return pg_cmp_u32(v1.oid, v2.oid);
18884 : : }
18885 : :
18886 : : /*
18887 : : * collectSequences
18888 : : *
18889 : : * Construct a table of sequence information. This table is sorted by OID for
18890 : : * speed in lookup.
18891 : : */
18892 : : static void
18893 : 189 : collectSequences(Archive *fout)
18894 : : {
18895 : : PGresult *res;
18896 : : const char *query;
18897 : :
18898 : : /*
18899 : : * Before Postgres 10, sequence metadata is in the sequence itself. With
18900 : : * some extra effort, we might be able to use the sorted table for those
18901 : : * versions, but for now it seems unlikely to be worth it.
18902 : : *
18903 : : * Since version 18, we can gather the sequence data in this query with
18904 : : * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
18905 : : */
18906 [ - + ]: 189 : if (fout->remoteVersion < 100000)
453 nathan@postgresql.or 18907 :UBC 0 : return;
453 nathan@postgresql.or 18908 [ + - ]:CBC 189 : else if (fout->remoteVersion < 180000 ||
336 18909 [ + + + + ]: 189 : (!fout->dopt->dumpData && !fout->dopt->sequence_data))
453 18910 : 8 : query = "SELECT seqrelid, format_type(seqtypid, NULL), "
18911 : : "seqstart, seqincrement, "
18912 : : "seqmax, seqmin, "
18913 : : "seqcache, seqcycle, "
18914 : : "NULL, 'f' "
18915 : : "FROM pg_catalog.pg_sequence "
18916 : : "ORDER BY seqrelid";
18917 : : else
18918 : 181 : query = "SELECT seqrelid, format_type(seqtypid, NULL), "
18919 : : "seqstart, seqincrement, "
18920 : : "seqmax, seqmin, "
18921 : : "seqcache, seqcycle, "
18922 : : "last_value, is_called "
18923 : : "FROM pg_catalog.pg_sequence, "
18924 : : "pg_get_sequence_data(seqrelid) "
18925 : : "ORDER BY seqrelid;";
18926 : :
18927 : 189 : res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
18928 : :
18929 : 189 : nsequences = PQntuples(res);
18930 : 189 : sequences = (SequenceItem *) pg_malloc(nsequences * sizeof(SequenceItem));
18931 : :
18932 [ + + ]: 827 : for (int i = 0; i < nsequences; i++)
18933 : : {
18934 : 638 : sequences[i].oid = atooid(PQgetvalue(res, i, 0));
18935 : 638 : sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
18936 : 638 : sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
18937 : 638 : sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
18938 : 638 : sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
18939 : 638 : sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
18940 : 638 : sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
18941 : 638 : sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
18942 : 638 : sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
18943 : 638 : sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
18944 : : }
18945 : :
18946 : 189 : PQclear(res);
18947 : : }
18948 : :
18949 : : /*
18950 : : * dumpSequence
18951 : : * write the declaration (not data) of one user-defined sequence
18952 : : */
18953 : : static void
1720 peter@eisentraut.org 18954 : 375 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
18955 : : {
3575 tgl@sss.pgh.pa.us 18956 : 375 : DumpOptions *dopt = fout->dopt;
18957 : : SequenceItem *seq;
18958 : : bool is_ascending;
18959 : : int64 default_minv,
18960 : : default_maxv;
9329 bruce@momjian.us 18961 : 375 : PQExpBuffer query = createPQExpBuffer();
9246 18962 : 375 : PQExpBuffer delqry = createPQExpBuffer();
18963 : : char *qseqname;
1299 peter@eisentraut.org 18964 : 375 : TableInfo *owning_tab = NULL;
18965 : :
2800 tgl@sss.pgh.pa.us 18966 : 375 : qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
18967 : :
18968 : : /*
18969 : : * For versions >= 10, the sequence information is gathered in a sorted
18970 : : * table before any calls to dumpSequence(). See collectSequences() for
18971 : : * more information.
18972 : : */
3233 peter_e@gmx.net 18973 [ + - ]: 375 : if (fout->remoteVersion >= 100000)
18974 : : {
453 nathan@postgresql.or 18975 : 375 : SequenceItem key = {0};
18976 : :
18977 [ - + ]: 375 : Assert(sequences);
18978 : :
18979 : 375 : key.oid = tbinfo->dobj.catId.oid;
18980 : 375 : seq = bsearch(&key, sequences, nsequences,
18981 : : sizeof(SequenceItem), SequenceItemCmp);
18982 : : }
18983 : : else
18984 : : {
18985 : : PGresult *res;
18986 : :
18987 : : /*
18988 : : * Before PostgreSQL 10, sequence metadata is in the sequence itself.
18989 : : *
18990 : : * Note: it might seem that 'bigint' potentially needs to be
18991 : : * schema-qualified, but actually that's a keyword.
18992 : : */
6373 tgl@sss.pgh.pa.us 18993 :UBC 0 : appendPQExpBuffer(query,
18994 : : "SELECT 'bigint' AS sequence_type, "
18995 : : "start_value, increment_by, max_value, min_value, "
18996 : : "cache_value, is_cycled FROM %s",
2800 18997 : 0 : fmtQualifiedDumpable(tbinfo));
18998 : :
453 nathan@postgresql.or 18999 : 0 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19000 : :
19001 [ # # ]: 0 : if (PQntuples(res) != 1)
19002 : 0 : pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
19003 : : "query to get data of sequence \"%s\" returned %d rows (expected 1)",
19004 : : PQntuples(res)),
19005 : : tbinfo->dobj.name, PQntuples(res));
19006 : :
19007 : 0 : seq = pg_malloc0(sizeof(SequenceItem));
19008 : 0 : seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
19009 : 0 : seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
19010 : 0 : seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
19011 : 0 : seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
19012 : 0 : seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
19013 : 0 : seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
19014 : 0 : seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
19015 : :
19016 : 0 : PQclear(res);
19017 : : }
19018 : :
19019 : : /* Calculate default limits for a sequence of this type */
453 nathan@postgresql.or 19020 :CBC 375 : is_ascending = (seq->incby >= 0);
19021 [ + + ]: 375 : if (seq->seqtype == SEQTYPE_SMALLINT)
19022 : : {
2806 tgl@sss.pgh.pa.us 19023 [ + + ]: 25 : default_minv = is_ascending ? 1 : PG_INT16_MIN;
19024 [ + + ]: 25 : default_maxv = is_ascending ? PG_INT16_MAX : -1;
19025 : : }
453 nathan@postgresql.or 19026 [ + + ]: 350 : else if (seq->seqtype == SEQTYPE_INTEGER)
19027 : : {
2806 tgl@sss.pgh.pa.us 19028 [ + + ]: 284 : default_minv = is_ascending ? 1 : PG_INT32_MIN;
19029 [ + + ]: 284 : default_maxv = is_ascending ? PG_INT32_MAX : -1;
19030 : : }
453 nathan@postgresql.or 19031 [ + - ]: 66 : else if (seq->seqtype == SEQTYPE_BIGINT)
19032 : : {
2806 tgl@sss.pgh.pa.us 19033 [ + + ]: 66 : default_minv = is_ascending ? 1 : PG_INT64_MIN;
19034 [ + + ]: 66 : default_maxv = is_ascending ? PG_INT64_MAX : -1;
19035 : : }
19036 : : else
19037 : : {
453 nathan@postgresql.or 19038 :UBC 0 : pg_fatal("unrecognized sequence type: %d", seq->seqtype);
19039 : : default_minv = default_maxv = 0; /* keep compiler quiet */
19040 : : }
19041 : :
19042 : : /*
19043 : : * Identity sequences are not to be dropped separately.
19044 : : */
3126 peter_e@gmx.net 19045 [ + + ]:CBC 375 : if (!tbinfo->is_identity_sequence)
19046 : : {
2800 tgl@sss.pgh.pa.us 19047 : 233 : appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
19048 : 233 : fmtQualifiedDumpable(tbinfo));
19049 : : }
19050 : :
4749 19051 : 375 : resetPQExpBuffer(query);
19052 : :
4031 alvherre@alvh.no-ip. 19053 [ + + ]: 375 : if (dopt->binary_upgrade)
19054 : : {
4749 tgl@sss.pgh.pa.us 19055 : 66 : binary_upgrade_set_pg_class_oids(fout, query,
481 nathan@postgresql.or 19056 : 66 : tbinfo->dobj.catId.oid);
19057 : :
19058 : : /*
19059 : : * In older PG versions a sequence will have a pg_type entry, but v14
19060 : : * and up don't use that, so don't attempt to preserve the type OID.
19061 : : */
19062 : : }
19063 : :
3126 peter_e@gmx.net 19064 [ + + ]: 375 : if (tbinfo->is_identity_sequence)
19065 : : {
1299 peter@eisentraut.org 19066 : 142 : owning_tab = findTableByOid(tbinfo->owning_tab);
19067 : :
3126 peter_e@gmx.net 19068 : 142 : appendPQExpBuffer(query,
19069 : : "ALTER TABLE %s ",
2800 tgl@sss.pgh.pa.us 19070 : 142 : fmtQualifiedDumpable(owning_tab));
3126 peter_e@gmx.net 19071 : 142 : appendPQExpBuffer(query,
19072 : : "ALTER COLUMN %s ADD GENERATED ",
3050 tgl@sss.pgh.pa.us 19073 : 142 : fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
3126 peter_e@gmx.net 19074 [ + + ]: 142 : if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
2307 drowley@postgresql.o 19075 : 102 : appendPQExpBufferStr(query, "ALWAYS");
3126 peter_e@gmx.net 19076 [ + - ]: 40 : else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
2307 drowley@postgresql.o 19077 : 40 : appendPQExpBufferStr(query, "BY DEFAULT");
3126 peter_e@gmx.net 19078 : 142 : appendPQExpBuffer(query, " AS IDENTITY (\n SEQUENCE NAME %s\n",
2800 tgl@sss.pgh.pa.us 19079 : 142 : fmtQualifiedDumpable(tbinfo));
19080 : :
19081 : : /*
19082 : : * Emit persistence option only if it's different from the owning
19083 : : * table's. This avoids using this new syntax unnecessarily.
19084 : : */
405 19085 [ + + ]: 142 : if (tbinfo->relpersistence != owning_tab->relpersistence)
19086 : 10 : appendPQExpBuffer(query, " %s\n",
19087 [ + + ]: 10 : tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
19088 : : "UNLOGGED" : "LOGGED");
19089 : : }
19090 : : else
19091 : : {
3126 peter_e@gmx.net 19092 : 233 : appendPQExpBuffer(query,
19093 : : "CREATE %sSEQUENCE %s\n",
1299 peter@eisentraut.org 19094 [ + + ]: 233 : tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
19095 : : "UNLOGGED " : "",
2800 tgl@sss.pgh.pa.us 19096 : 233 : fmtQualifiedDumpable(tbinfo));
19097 : :
453 nathan@postgresql.or 19098 [ + + ]: 233 : if (seq->seqtype != SEQTYPE_BIGINT)
19099 : 182 : appendPQExpBuffer(query, " AS %s\n", SeqTypeNames[seq->seqtype]);
19100 : : }
19101 : :
19102 : 375 : appendPQExpBuffer(query, " START WITH " INT64_FORMAT "\n", seq->startv);
19103 : :
19104 : 375 : appendPQExpBuffer(query, " INCREMENT BY " INT64_FORMAT "\n", seq->incby);
19105 : :
19106 [ + + ]: 375 : if (seq->minv != default_minv)
19107 : 15 : appendPQExpBuffer(query, " MINVALUE " INT64_FORMAT "\n", seq->minv);
19108 : : else
4361 heikki.linnakangas@i 19109 : 360 : appendPQExpBufferStr(query, " NO MINVALUE\n");
19110 : :
453 nathan@postgresql.or 19111 [ + + ]: 375 : if (seq->maxv != default_maxv)
19112 : 15 : appendPQExpBuffer(query, " MAXVALUE " INT64_FORMAT "\n", seq->maxv);
19113 : : else
4361 heikki.linnakangas@i 19114 : 360 : appendPQExpBufferStr(query, " NO MAXVALUE\n");
19115 : :
4749 tgl@sss.pgh.pa.us 19116 : 375 : appendPQExpBuffer(query,
19117 : : " CACHE " INT64_FORMAT "%s",
453 nathan@postgresql.or 19118 [ + + ]: 375 : seq->cache, (seq->cycled ? "\n CYCLE" : ""));
19119 : :
3126 peter_e@gmx.net 19120 [ + + ]: 375 : if (tbinfo->is_identity_sequence)
19121 : 142 : appendPQExpBufferStr(query, "\n);\n");
19122 : : else
19123 : 233 : appendPQExpBufferStr(query, ";\n");
19124 : :
19125 : : /* binary_upgrade: no need to clear TOAST table oid */
19126 : :
4031 alvherre@alvh.no-ip. 19127 [ + + ]: 375 : if (dopt->binary_upgrade)
4749 tgl@sss.pgh.pa.us 19128 : 66 : binary_upgrade_extension_member(query, &tbinfo->dobj,
19129 : : "SEQUENCE", qseqname,
2800 19130 : 66 : tbinfo->dobj.namespace->dobj.name);
19131 : :
3491 sfrost@snowman.net 19132 [ + - ]: 375 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19133 : 375 : ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 19134 : 375 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19135 : : .namespace = tbinfo->dobj.namespace->dobj.name,
19136 : : .owner = tbinfo->rolname,
19137 : : .description = "SEQUENCE",
19138 : : .section = SECTION_PRE_DATA,
19139 : : .createStmt = query->data,
19140 : : .dropStmt = delqry->data));
19141 : :
19142 : : /*
19143 : : * If the sequence is owned by a table column, emit the ALTER for it as a
19144 : : * separate TOC entry immediately following the sequence's own entry. It's
19145 : : * OK to do this rather than using full sorting logic, because the
19146 : : * dependency that tells us it's owned will have forced the table to be
19147 : : * created first. We can't just include the ALTER in the TOC entry
19148 : : * because it will fail if we haven't reassigned the sequence owner to
19149 : : * match the table's owner.
19150 : : *
19151 : : * We need not schema-qualify the table reference because both sequence
19152 : : * and table must be in the same schema.
19153 : : */
3126 peter_e@gmx.net 19154 [ + + + + ]: 375 : if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
19155 : : {
1164 drowley@postgresql.o 19156 : 137 : owning_tab = findTableByOid(tbinfo->owning_tab);
19157 : :
3216 sfrost@snowman.net 19158 [ - + ]: 137 : if (owning_tab == NULL)
1298 tgl@sss.pgh.pa.us 19159 :UBC 0 : pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
19160 : : tbinfo->owning_tab, tbinfo->dobj.catId.oid);
19161 : :
3216 sfrost@snowman.net 19162 [ + + ]:CBC 137 : if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
19163 : : {
4749 tgl@sss.pgh.pa.us 19164 : 135 : resetPQExpBuffer(query);
19165 : 135 : appendPQExpBuffer(query, "ALTER SEQUENCE %s",
2800 19166 : 135 : fmtQualifiedDumpable(tbinfo));
4749 19167 : 135 : appendPQExpBuffer(query, " OWNED BY %s",
2800 19168 : 135 : fmtQualifiedDumpable(owning_tab));
4749 19169 : 135 : appendPQExpBuffer(query, ".%s;\n",
3050 19170 : 135 : fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
19171 : :
3491 sfrost@snowman.net 19172 [ + - ]: 135 : if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19173 : 135 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 19174 : 135 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19175 : : .namespace = tbinfo->dobj.namespace->dobj.name,
19176 : : .owner = tbinfo->rolname,
19177 : : .description = "SEQUENCE OWNED BY",
19178 : : .section = SECTION_PRE_DATA,
19179 : : .createStmt = query->data,
19180 : : .deps = &(tbinfo->dobj.dumpId),
19181 : : .nDeps = 1));
19182 : : }
19183 : : }
19184 : :
19185 : : /* Dump Sequence Comments and Security Labels */
3491 sfrost@snowman.net 19186 [ - + ]: 375 : if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 19187 :UBC 0 : dumpComment(fout, "SEQUENCE", qseqname,
3491 sfrost@snowman.net 19188 : 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19189 : 0 : tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
19190 : :
3491 sfrost@snowman.net 19191 [ - + ]:CBC 375 : if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2800 tgl@sss.pgh.pa.us 19192 :UBC 0 : dumpSecLabel(fout, "SEQUENCE", qseqname,
3491 sfrost@snowman.net 19193 : 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19194 : 0 : tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
19195 : :
453 nathan@postgresql.or 19196 [ - + ]:CBC 375 : if (fout->remoteVersion < 100000)
453 nathan@postgresql.or 19197 :UBC 0 : pg_free(seq);
8851 tgl@sss.pgh.pa.us 19198 :CBC 375 : destroyPQExpBuffer(query);
19199 : 375 : destroyPQExpBuffer(delqry);
2800 19200 : 375 : free(qseqname);
10435 vadim4o@yahoo.com 19201 : 375 : }
19202 : :
19203 : : /*
19204 : : * dumpSequenceData
19205 : : * write the data of one user-defined sequence
19206 : : */
19207 : : static void
1720 peter@eisentraut.org 19208 : 393 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
19209 : : {
4749 tgl@sss.pgh.pa.us 19210 : 393 : TableInfo *tbinfo = tdinfo->tdtable;
19211 : : int64 last;
19212 : : bool called;
19213 : 393 : PQExpBuffer query = createPQExpBuffer();
19214 : :
19215 : : /*
19216 : : * For versions >= 18, the sequence information is gathered in the sorted
19217 : : * array before any calls to dumpSequenceData(). See collectSequences()
19218 : : * for more information.
19219 : : *
19220 : : * For older versions, we have to query the sequence relations
19221 : : * individually.
19222 : : */
453 nathan@postgresql.or 19223 [ - + ]: 393 : if (fout->remoteVersion < 180000)
19224 : : {
19225 : : PGresult *res;
19226 : :
453 nathan@postgresql.or 19227 :UBC 0 : appendPQExpBuffer(query,
19228 : : "SELECT last_value, is_called FROM %s",
19229 : 0 : fmtQualifiedDumpable(tbinfo));
19230 : :
19231 : 0 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19232 : :
19233 [ # # ]: 0 : if (PQntuples(res) != 1)
19234 : 0 : pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
19235 : : "query to get data of sequence \"%s\" returned %d rows (expected 1)",
19236 : : PQntuples(res)),
19237 : : tbinfo->dobj.name, PQntuples(res));
19238 : :
19239 : 0 : last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
19240 : 0 : called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
19241 : :
19242 : 0 : PQclear(res);
19243 : : }
19244 : : else
19245 : : {
453 nathan@postgresql.or 19246 :CBC 393 : SequenceItem key = {0};
19247 : : SequenceItem *entry;
19248 : :
19249 [ - + ]: 393 : Assert(sequences);
19250 [ - + ]: 393 : Assert(tbinfo->dobj.catId.oid);
19251 : :
19252 : 393 : key.oid = tbinfo->dobj.catId.oid;
19253 : 393 : entry = bsearch(&key, sequences, nsequences,
19254 : : sizeof(SequenceItem), SequenceItemCmp);
19255 : :
19256 : 393 : last = entry->last_value;
19257 : 393 : called = entry->is_called;
19258 : : }
19259 : :
4749 tgl@sss.pgh.pa.us 19260 : 393 : resetPQExpBuffer(query);
4361 heikki.linnakangas@i 19261 : 393 : appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
2800 tgl@sss.pgh.pa.us 19262 : 393 : appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
453 nathan@postgresql.or 19263 [ + + ]: 393 : appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
19264 : : last, (called ? "true" : "false"));
19265 : :
3203 sfrost@snowman.net 19266 [ + - ]: 393 : if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
3491 19267 : 393 : ArchiveEntry(fout, nilCatalogId, createDumpId(),
2460 alvherre@alvh.no-ip. 19268 : 393 : ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
19269 : : .namespace = tbinfo->dobj.namespace->dobj.name,
19270 : : .owner = tbinfo->rolname,
19271 : : .description = "SEQUENCE SET",
19272 : : .section = SECTION_DATA,
19273 : : .createStmt = query->data,
19274 : : .deps = &(tbinfo->dobj.dumpId),
19275 : : .nDeps = 1));
19276 : :
4749 tgl@sss.pgh.pa.us 19277 : 393 : destroyPQExpBuffer(query);
19278 : 393 : }
19279 : :
19280 : : /*
19281 : : * dumpTrigger
19282 : : * write the declaration of one user-defined table trigger
19283 : : */
19284 : : static void
1720 peter@eisentraut.org 19285 : 523 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
19286 : : {
3575 tgl@sss.pgh.pa.us 19287 : 523 : DumpOptions *dopt = fout->dopt;
7996 19288 : 523 : TableInfo *tbinfo = tginfo->tgtable;
19289 : : PQExpBuffer query;
19290 : : PQExpBuffer delqry;
19291 : : PQExpBuffer trigprefix;
19292 : : PQExpBuffer trigidentity;
19293 : : char *qtabname;
19294 : : char *tag;
19295 : :
19296 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 19297 [ + + ]: 523 : if (!dopt->dumpSchema)
8473 tgl@sss.pgh.pa.us 19298 : 31 : return;
19299 : :
7996 19300 : 492 : query = createPQExpBuffer();
19301 : 492 : delqry = createPQExpBuffer();
2800 19302 : 492 : trigprefix = createPQExpBuffer();
2056 alvherre@alvh.no-ip. 19303 : 492 : trigidentity = createPQExpBuffer();
19304 : :
2800 tgl@sss.pgh.pa.us 19305 : 492 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19306 : :
2056 alvherre@alvh.no-ip. 19307 : 492 : appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
19308 : 492 : appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
19309 : :
652 peter@eisentraut.org 19310 : 492 : appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
2056 alvherre@alvh.no-ip. 19311 : 492 : appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
19312 : :
19313 : : /* Triggers can depend on extensions */
19314 : 492 : append_depends_on_extension(fout, query, &tginfo->dobj,
19315 : : "pg_catalog.pg_trigger", "TRIGGER",
19316 : 492 : trigidentity->data);
19317 : :
1391 19318 [ + + ]: 492 : if (tginfo->tgispartition)
19319 : : {
19320 [ - + ]: 109 : Assert(tbinfo->ispartition);
19321 : :
19322 : : /*
19323 : : * Partition triggers only appear here because their 'tgenabled' flag
19324 : : * differs from its parent's. The trigger is created already, so
19325 : : * remove the CREATE and replace it with an ALTER. (Clear out the
19326 : : * DROP query too, so that pg_dump --create does not cause errors.)
19327 : : */
1564 19328 : 109 : resetPQExpBuffer(query);
19329 : 109 : resetPQExpBuffer(delqry);
19330 : 109 : appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
19331 [ - + ]: 109 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
19332 : 109 : fmtQualifiedDumpable(tbinfo));
19333 [ + - + + : 109 : switch (tginfo->tgenabled)
- ]
19334 : : {
19335 : 38 : case 'f':
19336 : : case 'D':
19337 : 38 : appendPQExpBufferStr(query, "DISABLE");
19338 : 38 : break;
1564 alvherre@alvh.no-ip. 19339 :UBC 0 : case 't':
19340 : : case 'O':
19341 : 0 : appendPQExpBufferStr(query, "ENABLE");
19342 : 0 : break;
1564 alvherre@alvh.no-ip. 19343 :CBC 33 : case 'R':
19344 : 33 : appendPQExpBufferStr(query, "ENABLE REPLICA");
19345 : 33 : break;
19346 : 38 : case 'A':
19347 : 38 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
19348 : 38 : break;
19349 : : }
19350 : 109 : appendPQExpBuffer(query, " TRIGGER %s;\n",
19351 : 109 : fmtId(tginfo->dobj.name));
19352 : : }
19353 [ + - - + ]: 383 : else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
19354 : : {
2047 alvherre@alvh.no-ip. 19355 :UBC 0 : appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
19356 [ # # ]: 0 : tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
2800 tgl@sss.pgh.pa.us 19357 : 0 : fmtQualifiedDumpable(tbinfo));
6797 JanWieck@Yahoo.com 19358 [ # # # # ]: 0 : switch (tginfo->tgenabled)
19359 : : {
19360 : 0 : case 'D':
19361 : : case 'f':
4361 heikki.linnakangas@i 19362 : 0 : appendPQExpBufferStr(query, "DISABLE");
6797 JanWieck@Yahoo.com 19363 : 0 : break;
19364 : 0 : case 'A':
4361 heikki.linnakangas@i 19365 : 0 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
6797 JanWieck@Yahoo.com 19366 : 0 : break;
19367 : 0 : case 'R':
4361 heikki.linnakangas@i 19368 : 0 : appendPQExpBufferStr(query, "ENABLE REPLICA");
6797 JanWieck@Yahoo.com 19369 : 0 : break;
19370 : 0 : default:
4361 heikki.linnakangas@i 19371 : 0 : appendPQExpBufferStr(query, "ENABLE");
6797 JanWieck@Yahoo.com 19372 : 0 : break;
19373 : : }
19374 : 0 : appendPQExpBuffer(query, " TRIGGER %s;\n",
7370 tgl@sss.pgh.pa.us 19375 : 0 : fmtId(tginfo->dobj.name));
19376 : : }
19377 : :
2800 tgl@sss.pgh.pa.us 19378 :CBC 492 : appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
5374 19379 : 492 : fmtId(tginfo->dobj.name));
19380 : :
3532 peter_e@gmx.net 19381 : 492 : tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
19382 : :
3491 sfrost@snowman.net 19383 [ + - ]: 492 : if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19384 : 492 : ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 19385 : 492 : ARCHIVE_OPTS(.tag = tag,
19386 : : .namespace = tbinfo->dobj.namespace->dobj.name,
19387 : : .owner = tbinfo->rolname,
19388 : : .description = "TRIGGER",
19389 : : .section = SECTION_POST_DATA,
19390 : : .createStmt = query->data,
19391 : : .dropStmt = delqry->data));
19392 : :
3491 sfrost@snowman.net 19393 [ - + ]: 492 : if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 19394 :UBC 0 : dumpComment(fout, trigprefix->data, qtabname,
3491 sfrost@snowman.net 19395 : 0 : tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
19396 : 0 : tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
19397 : :
3532 peter_e@gmx.net 19398 :CBC 492 : free(tag);
7996 tgl@sss.pgh.pa.us 19399 : 492 : destroyPQExpBuffer(query);
19400 : 492 : destroyPQExpBuffer(delqry);
2800 19401 : 492 : destroyPQExpBuffer(trigprefix);
2056 alvherre@alvh.no-ip. 19402 : 492 : destroyPQExpBuffer(trigidentity);
2800 tgl@sss.pgh.pa.us 19403 : 492 : free(qtabname);
19404 : : }
19405 : :
19406 : : /*
19407 : : * dumpEventTrigger
19408 : : * write the declaration of one user-defined event trigger
19409 : : */
19410 : : static void
1720 peter@eisentraut.org 19411 : 42 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
19412 : : {
3575 tgl@sss.pgh.pa.us 19413 : 42 : DumpOptions *dopt = fout->dopt;
19414 : : PQExpBuffer query;
19415 : : PQExpBuffer delqry;
19416 : : char *qevtname;
19417 : :
19418 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 19419 [ + + ]: 42 : if (!dopt->dumpSchema)
4319 tgl@sss.pgh.pa.us 19420 : 6 : return;
19421 : :
4849 rhaas@postgresql.org 19422 : 36 : query = createPQExpBuffer();
3019 tgl@sss.pgh.pa.us 19423 : 36 : delqry = createPQExpBuffer();
19424 : :
2800 19425 : 36 : qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
19426 : :
4361 heikki.linnakangas@i 19427 : 36 : appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
2800 tgl@sss.pgh.pa.us 19428 : 36 : appendPQExpBufferStr(query, qevtname);
4361 heikki.linnakangas@i 19429 : 36 : appendPQExpBufferStr(query, " ON ");
4849 rhaas@postgresql.org 19430 : 36 : appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
19431 : :
19432 [ + + ]: 36 : if (strcmp("", evtinfo->evttags) != 0)
19433 : : {
19434 : 5 : appendPQExpBufferStr(query, "\n WHEN TAG IN (");
19435 : 5 : appendPQExpBufferStr(query, evtinfo->evttags);
3770 heikki.linnakangas@i 19436 : 5 : appendPQExpBufferChar(query, ')');
19437 : : }
19438 : :
2454 peter@eisentraut.org 19439 : 36 : appendPQExpBufferStr(query, "\n EXECUTE FUNCTION ");
4849 rhaas@postgresql.org 19440 : 36 : appendPQExpBufferStr(query, evtinfo->evtfname);
4361 heikki.linnakangas@i 19441 : 36 : appendPQExpBufferStr(query, "();\n");
19442 : :
4849 rhaas@postgresql.org 19443 [ - + ]: 36 : if (evtinfo->evtenabled != 'O')
19444 : : {
4849 rhaas@postgresql.org 19445 :UBC 0 : appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
19446 : : qevtname);
19447 [ # # # # ]: 0 : switch (evtinfo->evtenabled)
19448 : : {
19449 : 0 : case 'D':
4361 heikki.linnakangas@i 19450 : 0 : appendPQExpBufferStr(query, "DISABLE");
4849 rhaas@postgresql.org 19451 : 0 : break;
19452 : 0 : case 'A':
4361 heikki.linnakangas@i 19453 : 0 : appendPQExpBufferStr(query, "ENABLE ALWAYS");
4849 rhaas@postgresql.org 19454 : 0 : break;
19455 : 0 : case 'R':
4361 heikki.linnakangas@i 19456 : 0 : appendPQExpBufferStr(query, "ENABLE REPLICA");
4849 rhaas@postgresql.org 19457 : 0 : break;
19458 : 0 : default:
4361 heikki.linnakangas@i 19459 : 0 : appendPQExpBufferStr(query, "ENABLE");
4849 rhaas@postgresql.org 19460 : 0 : break;
19461 : : }
4361 heikki.linnakangas@i 19462 : 0 : appendPQExpBufferStr(query, ";\n");
19463 : : }
19464 : :
3019 tgl@sss.pgh.pa.us 19465 :CBC 36 : appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
19466 : : qevtname);
19467 : :
2638 19468 [ + + ]: 36 : if (dopt->binary_upgrade)
19469 : 2 : binary_upgrade_extension_member(query, &evtinfo->dobj,
19470 : : "EVENT TRIGGER", qevtname, NULL);
19471 : :
3491 sfrost@snowman.net 19472 [ + - ]: 36 : if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19473 : 36 : ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 19474 : 36 : ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
19475 : : .owner = evtinfo->evtowner,
19476 : : .description = "EVENT TRIGGER",
19477 : : .section = SECTION_POST_DATA,
19478 : : .createStmt = query->data,
19479 : : .dropStmt = delqry->data));
19480 : :
3491 sfrost@snowman.net 19481 [ - + ]: 36 : if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 19482 :UBC 0 : dumpComment(fout, "EVENT TRIGGER", qevtname,
3491 sfrost@snowman.net 19483 : 0 : NULL, evtinfo->evtowner,
19484 : 0 : evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
19485 : :
41 fujii@postgresql.org 19486 [ - + ]:CBC 36 : if (evtinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
41 fujii@postgresql.org 19487 :UBC 0 : dumpSecLabel(fout, "EVENT TRIGGER", qevtname,
19488 : 0 : NULL, evtinfo->evtowner,
19489 : 0 : evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
19490 : :
4849 rhaas@postgresql.org 19491 :CBC 36 : destroyPQExpBuffer(query);
3019 tgl@sss.pgh.pa.us 19492 : 36 : destroyPQExpBuffer(delqry);
2800 19493 : 36 : free(qevtname);
19494 : : }
19495 : :
19496 : : /*
19497 : : * dumpRule
19498 : : * Dump a rule
19499 : : */
19500 : : static void
1720 peter@eisentraut.org 19501 : 1132 : dumpRule(Archive *fout, const RuleInfo *rinfo)
19502 : : {
3575 tgl@sss.pgh.pa.us 19503 : 1132 : DumpOptions *dopt = fout->dopt;
7996 19504 : 1132 : TableInfo *tbinfo = rinfo->ruletable;
19505 : : bool is_view;
19506 : : PQExpBuffer query;
19507 : : PQExpBuffer cmd;
19508 : : PQExpBuffer delcmd;
19509 : : PQExpBuffer ruleprefix;
19510 : : char *qtabname;
19511 : : PGresult *res;
19512 : : char *tag;
19513 : :
19514 : : /* Do nothing if not dumping schema */
336 nathan@postgresql.or 19515 [ + + ]: 1132 : if (!dopt->dumpSchema)
7996 tgl@sss.pgh.pa.us 19516 : 60 : return;
19517 : :
19518 : : /*
19519 : : * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
19520 : : * we do not want to dump it as a separate object.
19521 : : */
7622 19522 [ + + ]: 1072 : if (!rinfo->separate)
7996 19523 : 861 : return;
19524 : :
19525 : : /*
19526 : : * If it's an ON SELECT rule, we want to print it as a view definition,
19527 : : * instead of a rule.
19528 : : */
3266 19529 [ + + + - ]: 211 : is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
19530 : :
7996 19531 : 211 : query = createPQExpBuffer();
19532 : 211 : cmd = createPQExpBuffer();
19533 : 211 : delcmd = createPQExpBuffer();
2800 19534 : 211 : ruleprefix = createPQExpBuffer();
19535 : :
19536 : 211 : qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
19537 : :
3266 19538 [ + + ]: 211 : if (is_view)
19539 : : {
19540 : : PQExpBuffer result;
19541 : :
19542 : : /*
19543 : : * We need OR REPLACE here because we'll be replacing a dummy view.
19544 : : * Otherwise this should look largely like the regular view dump code.
19545 : : */
19546 : 10 : appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
2800 19547 : 10 : fmtQualifiedDumpable(tbinfo));
3266 19548 [ - + ]: 10 : if (nonemptyReloptions(tbinfo->reloptions))
19549 : : {
3266 tgl@sss.pgh.pa.us 19550 :UBC 0 : appendPQExpBufferStr(cmd, " WITH (");
19551 : 0 : appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
19552 : 0 : appendPQExpBufferChar(cmd, ')');
19553 : : }
3266 tgl@sss.pgh.pa.us 19554 :CBC 10 : result = createViewAsClause(fout, tbinfo);
19555 : 10 : appendPQExpBuffer(cmd, " AS\n%s", result->data);
19556 : 10 : destroyPQExpBuffer(result);
19557 [ - + ]: 10 : if (tbinfo->checkoption != NULL)
3266 tgl@sss.pgh.pa.us 19558 :UBC 0 : appendPQExpBuffer(cmd, "\n WITH %s CHECK OPTION",
19559 : : tbinfo->checkoption);
3266 tgl@sss.pgh.pa.us 19560 :CBC 10 : appendPQExpBufferStr(cmd, ";\n");
19561 : : }
19562 : : else
19563 : : {
19564 : : /* In the rule case, just print pg_get_ruledef's result verbatim */
19565 : 201 : appendPQExpBuffer(query,
19566 : : "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
19567 : 201 : rinfo->dobj.catId.oid);
19568 : :
19569 : 201 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19570 : :
19571 [ - + ]: 201 : if (PQntuples(res) != 1)
1298 tgl@sss.pgh.pa.us 19572 :UBC 0 : pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
19573 : : rinfo->dobj.name, tbinfo->dobj.name);
19574 : :
3266 tgl@sss.pgh.pa.us 19575 :CBC 201 : printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
19576 : :
19577 : 201 : PQclear(res);
19578 : : }
19579 : :
19580 : : /*
19581 : : * Add the command to alter the rules replication firing semantics if it
19582 : : * differs from the default.
19583 : : */
6797 JanWieck@Yahoo.com 19584 [ + + ]: 211 : if (rinfo->ev_enabled != 'O')
19585 : : {
2800 tgl@sss.pgh.pa.us 19586 : 15 : appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
6797 JanWieck@Yahoo.com 19587 [ - - + - ]: 15 : switch (rinfo->ev_enabled)
19588 : : {
6797 JanWieck@Yahoo.com 19589 :UBC 0 : case 'A':
19590 : 0 : appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
6556 bruce@momjian.us 19591 : 0 : fmtId(rinfo->dobj.name));
6797 JanWieck@Yahoo.com 19592 : 0 : break;
19593 : 0 : case 'R':
19594 : 0 : appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
6556 bruce@momjian.us 19595 : 0 : fmtId(rinfo->dobj.name));
6797 JanWieck@Yahoo.com 19596 : 0 : break;
6797 JanWieck@Yahoo.com 19597 :CBC 15 : case 'D':
19598 : 15 : appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
6556 bruce@momjian.us 19599 : 15 : fmtId(rinfo->dobj.name));
6797 JanWieck@Yahoo.com 19600 : 15 : break;
19601 : : }
19602 : : }
19603 : :
3266 tgl@sss.pgh.pa.us 19604 [ + + ]: 211 : if (is_view)
19605 : : {
19606 : : /*
19607 : : * We can't DROP a view's ON SELECT rule. Instead, use CREATE OR
19608 : : * REPLACE VIEW to replace the rule with something with minimal
19609 : : * dependencies.
19610 : : */
19611 : : PQExpBuffer result;
19612 : :
2800 19613 : 10 : appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
19614 : 10 : fmtQualifiedDumpable(tbinfo));
3266 19615 : 10 : result = createDummyViewAsClause(fout, tbinfo);
19616 : 10 : appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
19617 : 10 : destroyPQExpBuffer(result);
19618 : : }
19619 : : else
19620 : : {
19621 : 201 : appendPQExpBuffer(delcmd, "DROP RULE %s ",
19622 : 201 : fmtId(rinfo->dobj.name));
2800 19623 : 201 : appendPQExpBuffer(delcmd, "ON %s;\n",
19624 : 201 : fmtQualifiedDumpable(tbinfo));
19625 : : }
19626 : :
19627 : 211 : appendPQExpBuffer(ruleprefix, "RULE %s ON",
5374 19628 : 211 : fmtId(rinfo->dobj.name));
19629 : :
3532 peter_e@gmx.net 19630 : 211 : tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
19631 : :
3491 sfrost@snowman.net 19632 [ + - ]: 211 : if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
19633 : 211 : ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
2460 alvherre@alvh.no-ip. 19634 : 211 : ARCHIVE_OPTS(.tag = tag,
19635 : : .namespace = tbinfo->dobj.namespace->dobj.name,
19636 : : .owner = tbinfo->rolname,
19637 : : .description = "RULE",
19638 : : .section = SECTION_POST_DATA,
19639 : : .createStmt = cmd->data,
19640 : : .dropStmt = delcmd->data));
19641 : :
19642 : : /* Dump rule comments */
3491 sfrost@snowman.net 19643 [ - + ]: 211 : if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2800 tgl@sss.pgh.pa.us 19644 :UBC 0 : dumpComment(fout, ruleprefix->data, qtabname,
3491 sfrost@snowman.net 19645 : 0 : tbinfo->dobj.namespace->dobj.name,
19646 : : tbinfo->rolname,
19647 : 0 : rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
19648 : :
3532 peter_e@gmx.net 19649 :CBC 211 : free(tag);
8571 tgl@sss.pgh.pa.us 19650 : 211 : destroyPQExpBuffer(query);
7996 19651 : 211 : destroyPQExpBuffer(cmd);
19652 : 211 : destroyPQExpBuffer(delcmd);
2800 19653 : 211 : destroyPQExpBuffer(ruleprefix);
19654 : 211 : free(qtabname);
19655 : : }
19656 : :
19657 : : /*
19658 : : * getExtensionMembership --- obtain extension membership data
19659 : : *
19660 : : * We need to identify objects that are extension members as soon as they're
19661 : : * loaded, so that we can correctly determine whether they need to be dumped.
19662 : : * Generally speaking, extension member objects will get marked as *not* to
19663 : : * be dumped, as they will be recreated by the single CREATE EXTENSION
19664 : : * command. However, in binary upgrade mode we still need to dump the members
19665 : : * individually.
19666 : : */
19667 : : void
3575 19668 : 190 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
19669 : : int numExtensions)
19670 : : {
19671 : : PQExpBuffer query;
19672 : : PGresult *res;
19673 : : int ntups,
19674 : : i;
19675 : : int i_classid,
19676 : : i_objid,
19677 : : i_refobjid;
19678 : : ExtensionInfo *ext;
19679 : :
19680 : : /* Nothing to do if no extensions */
5374 19681 [ - + ]: 190 : if (numExtensions == 0)
5374 tgl@sss.pgh.pa.us 19682 :UBC 0 : return;
19683 : :
5374 tgl@sss.pgh.pa.us 19684 :CBC 190 : query = createPQExpBuffer();
19685 : :
19686 : : /* refclassid constraint is redundant but may speed the search */
4361 heikki.linnakangas@i 19687 : 190 : appendPQExpBufferStr(query, "SELECT "
19688 : : "classid, objid, refobjid "
19689 : : "FROM pg_depend "
19690 : : "WHERE refclassid = 'pg_extension'::regclass "
19691 : : "AND deptype = 'e' "
19692 : : "ORDER BY 3");
19693 : :
5011 rhaas@postgresql.org 19694 : 190 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19695 : :
5374 tgl@sss.pgh.pa.us 19696 : 190 : ntups = PQntuples(res);
19697 : :
19698 : 190 : i_classid = PQfnumber(res, "classid");
19699 : 190 : i_objid = PQfnumber(res, "objid");
19700 : 190 : i_refobjid = PQfnumber(res, "refobjid");
19701 : :
19702 : : /*
19703 : : * Since we ordered the SELECT by referenced ID, we can expect that
19704 : : * multiple entries for the same extension will appear together; this
19705 : : * saves on searches.
19706 : : */
3575 19707 : 190 : ext = NULL;
19708 : :
5374 19709 [ + + ]: 1555 : for (i = 0; i < ntups; i++)
19710 : : {
19711 : : CatalogId objId;
19712 : : Oid extId;
19713 : :
19714 : 1365 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
19715 : 1365 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
3575 19716 : 1365 : extId = atooid(PQgetvalue(res, i, i_refobjid));
19717 : :
19718 [ + + ]: 1365 : if (ext == NULL ||
19719 [ + + ]: 1175 : ext->dobj.catId.oid != extId)
19720 : 220 : ext = findExtensionByOid(extId);
19721 : :
19722 [ - + ]: 1365 : if (ext == NULL)
19723 : : {
19724 : : /* shouldn't happen */
2401 peter@eisentraut.org 19725 :UBC 0 : pg_log_warning("could not find referenced extension %u", extId);
5374 tgl@sss.pgh.pa.us 19726 : 0 : continue;
19727 : : }
19728 : :
1466 tgl@sss.pgh.pa.us 19729 :CBC 1365 : recordExtensionMembership(objId, ext);
19730 : : }
19731 : :
3575 19732 : 190 : PQclear(res);
19733 : :
19734 : 190 : destroyPQExpBuffer(query);
19735 : : }
19736 : :
19737 : : /*
19738 : : * processExtensionTables --- deal with extension configuration tables
19739 : : *
19740 : : * There are two parts to this process:
19741 : : *
19742 : : * 1. Identify and create dump records for extension configuration tables.
19743 : : *
19744 : : * Extensions can mark tables as "configuration", which means that the user
19745 : : * is able and expected to modify those tables after the extension has been
19746 : : * loaded. For these tables, we dump out only the data- the structure is
19747 : : * expected to be handled at CREATE EXTENSION time, including any indexes or
19748 : : * foreign keys, which brings us to-
19749 : : *
19750 : : * 2. Record FK dependencies between configuration tables.
19751 : : *
19752 : : * Due to the FKs being created at CREATE EXTENSION time and therefore before
19753 : : * the data is loaded, we have to work out what the best order for reloading
19754 : : * the data is, to avoid FK violations when the tables are restored. This is
19755 : : * not perfect- we can't handle circular dependencies and if any exist they
19756 : : * will cause an invalid dump to be produced (though at least all of the data
19757 : : * is included for a user to manually restore). This is currently documented
19758 : : * but perhaps we can provide a better solution in the future.
19759 : : */
19760 : : void
19761 : 189 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
19762 : : int numExtensions)
19763 : : {
19764 : 189 : DumpOptions *dopt = fout->dopt;
19765 : : PQExpBuffer query;
19766 : : PGresult *res;
19767 : : int ntups,
19768 : : i;
19769 : : int i_conrelid,
19770 : : i_confrelid;
19771 : :
19772 : : /* Nothing to do if no extensions */
19773 [ - + ]: 189 : if (numExtensions == 0)
3575 tgl@sss.pgh.pa.us 19774 :UBC 0 : return;
19775 : :
19776 : : /*
19777 : : * Identify extension configuration tables and create TableDataInfo
19778 : : * objects for them, ensuring their data will be dumped even though the
19779 : : * tables themselves won't be.
19780 : : *
19781 : : * Note that we create TableDataInfo objects even in schema-only mode, ie,
19782 : : * user data in a configuration table is treated like schema data. This
19783 : : * seems appropriate since system data in a config table would get
19784 : : * reloaded by CREATE EXTENSION. If the extension is not listed in the
19785 : : * list of extensions to be included, none of its data is dumped.
19786 : : */
5374 tgl@sss.pgh.pa.us 19787 [ + + ]:CBC 408 : for (i = 0; i < numExtensions; i++)
19788 : : {
5008 19789 : 219 : ExtensionInfo *curext = &(extinfo[i]);
19790 : 219 : char *extconfig = curext->extconfig;
19791 : 219 : char *extcondition = curext->extcondition;
5314 bruce@momjian.us 19792 : 219 : char **extconfigarray = NULL;
19793 : 219 : char **extconditionarray = NULL;
1803 michael@paquier.xyz 19794 : 219 : int nconfigitems = 0;
19795 : 219 : int nconditionitems = 0;
19796 : :
19797 : : /*
19798 : : * Check if this extension is listed as to include in the dump. If
19799 : : * not, any table data associated with it is discarded.
19800 : : */
1656 19801 [ + + ]: 219 : if (extension_include_oids.head != NULL &&
19802 [ + + ]: 8 : !simple_oid_list_member(&extension_include_oids,
19803 : : curext->dobj.catId.oid))
19804 : 6 : continue;
19805 : :
19806 : : /*
19807 : : * Check if this extension is listed as to exclude in the dump. If
19808 : : * yes, any table data associated with it is discarded.
19809 : : */
586 dean.a.rasheed@gmail 19810 [ + + + + ]: 219 : if (extension_exclude_oids.head != NULL &&
19811 : 4 : simple_oid_list_member(&extension_exclude_oids,
19812 : : curext->dobj.catId.oid))
19813 : 2 : continue;
19814 : :
1803 michael@paquier.xyz 19815 [ + + - + ]: 213 : if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
19816 : : {
19817 : : int j;
19818 : :
19819 [ - + ]: 20 : if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
1298 tgl@sss.pgh.pa.us 19820 :UBC 0 : pg_fatal("could not parse %s array", "extconfig");
1803 michael@paquier.xyz 19821 [ - + ]:CBC 20 : if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
1298 tgl@sss.pgh.pa.us 19822 :UBC 0 : pg_fatal("could not parse %s array", "extcondition");
1803 michael@paquier.xyz 19823 [ - + ]:CBC 20 : if (nconfigitems != nconditionitems)
1298 tgl@sss.pgh.pa.us 19824 :UBC 0 : pg_fatal("mismatched number of configurations and conditions for extension");
19825 : :
5374 tgl@sss.pgh.pa.us 19826 [ + + ]:CBC 60 : for (j = 0; j < nconfigitems; j++)
19827 : : {
19828 : : TableInfo *configtbl;
4567 mail@joeconway.com 19829 : 40 : Oid configtbloid = atooid(extconfigarray[j]);
3491 sfrost@snowman.net 19830 : 40 : bool dumpobj =
892 tgl@sss.pgh.pa.us 19831 : 40 : curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
19832 : :
4567 mail@joeconway.com 19833 : 40 : configtbl = findTableByOid(configtbloid);
5010 tgl@sss.pgh.pa.us 19834 [ - + ]: 40 : if (configtbl == NULL)
5010 tgl@sss.pgh.pa.us 19835 :UBC 0 : continue;
19836 : :
19837 : : /*
19838 : : * Tables of not-to-be-dumped extensions shouldn't be dumped
19839 : : * unless the table or its schema is explicitly included
19840 : : */
3491 sfrost@snowman.net 19841 [ + + ]:CBC 40 : if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
19842 : : {
19843 : : /* check table explicitly requested */
4567 mail@joeconway.com 19844 [ - + - - ]: 2 : if (table_include_oids.head != NULL &&
4567 mail@joeconway.com 19845 :UBC 0 : simple_oid_list_member(&table_include_oids,
19846 : : configtbloid))
19847 : 0 : dumpobj = true;
19848 : :
19849 : : /* check table's schema explicitly requested */
3491 sfrost@snowman.net 19850 [ + - ]:CBC 2 : if (configtbl->dobj.namespace->dobj.dump &
19851 : : DUMP_COMPONENT_DATA)
4567 mail@joeconway.com 19852 : 2 : dumpobj = true;
19853 : : }
19854 : :
19855 : : /* check table excluded by an exclusion switch */
19856 [ + + + + ]: 44 : if (table_exclude_oids.head != NULL &&
19857 : 4 : simple_oid_list_member(&table_exclude_oids,
19858 : : configtbloid))
19859 : 1 : dumpobj = false;
19860 : :
19861 : : /* check schema excluded by an exclusion switch */
19862 [ - + ]: 40 : if (simple_oid_list_member(&schema_exclude_oids,
3050 tgl@sss.pgh.pa.us 19863 : 40 : configtbl->dobj.namespace->dobj.catId.oid))
4567 mail@joeconway.com 19864 :UBC 0 : dumpobj = false;
19865 : :
4567 mail@joeconway.com 19866 [ + + ]:CBC 40 : if (dumpobj)
19867 : : {
2533 andres@anarazel.de 19868 : 39 : makeTableDataInfo(dopt, configtbl);
4567 mail@joeconway.com 19869 [ + - ]: 39 : if (configtbl->dataObj != NULL)
19870 : : {
19871 [ - + ]: 39 : if (strlen(extconditionarray[j]) > 0)
4567 mail@joeconway.com 19872 :UBC 0 : configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
19873 : : }
19874 : : }
19875 : : }
19876 : : }
5374 tgl@sss.pgh.pa.us 19877 [ + + ]:CBC 213 : if (extconfigarray)
19878 : 20 : free(extconfigarray);
19879 [ + + ]: 213 : if (extconditionarray)
19880 : 20 : free(extconditionarray);
19881 : : }
19882 : :
19883 : : /*
19884 : : * Now that all the TableDataInfo objects have been created for all the
19885 : : * extensions, check their FK dependencies and register them to try and
19886 : : * dump the data out in an order that they can be restored in.
19887 : : *
19888 : : * Note that this is not a problem for user tables as their FKs are
19889 : : * recreated after the data has been loaded.
19890 : : */
19891 : :
3575 19892 : 189 : query = createPQExpBuffer();
19893 : :
3892 sfrost@snowman.net 19894 : 189 : printfPQExpBuffer(query,
19895 : : "SELECT conrelid, confrelid "
19896 : : "FROM pg_constraint "
19897 : : "JOIN pg_depend ON (objid = confrelid) "
19898 : : "WHERE contype = 'f' "
19899 : : "AND refclassid = 'pg_extension'::regclass "
19900 : : "AND classid = 'pg_class'::regclass;");
19901 : :
19902 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
19903 : 189 : ntups = PQntuples(res);
19904 : :
19905 : 189 : i_conrelid = PQfnumber(res, "conrelid");
19906 : 189 : i_confrelid = PQfnumber(res, "confrelid");
19907 : :
19908 : : /* Now get the dependencies and register them */
19909 [ - + ]: 189 : for (i = 0; i < ntups; i++)
19910 : : {
19911 : : Oid conrelid,
19912 : : confrelid;
19913 : : TableInfo *reftable,
19914 : : *contable;
19915 : :
3892 sfrost@snowman.net 19916 :UBC 0 : conrelid = atooid(PQgetvalue(res, i, i_conrelid));
19917 : 0 : confrelid = atooid(PQgetvalue(res, i, i_confrelid));
19918 : 0 : contable = findTableByOid(conrelid);
19919 : 0 : reftable = findTableByOid(confrelid);
19920 : :
19921 [ # # ]: 0 : if (reftable == NULL ||
19922 [ # # # # ]: 0 : reftable->dataObj == NULL ||
19923 : 0 : contable == NULL ||
19924 [ # # ]: 0 : contable->dataObj == NULL)
19925 : 0 : continue;
19926 : :
19927 : : /*
19928 : : * Make referencing TABLE_DATA object depend on the referenced table's
19929 : : * TABLE_DATA object.
19930 : : */
19931 : 0 : addObjectDependency(&contable->dataObj->dobj,
19932 : 0 : reftable->dataObj->dobj.dumpId);
19933 : : }
3760 tgl@sss.pgh.pa.us 19934 :CBC 189 : PQclear(res);
5374 19935 : 189 : destroyPQExpBuffer(query);
19936 : : }
19937 : :
19938 : : /*
19939 : : * getDependencies --- obtain available dependency data
19940 : : */
19941 : : static void
5012 rhaas@postgresql.org 19942 : 189 : getDependencies(Archive *fout)
19943 : : {
19944 : : PQExpBuffer query;
19945 : : PGresult *res;
19946 : : int ntups,
19947 : : i;
19948 : : int i_classid,
19949 : : i_objid,
19950 : : i_refclassid,
19951 : : i_refobjid,
19952 : : i_deptype;
19953 : : DumpableObject *dobj,
19954 : : *refdobj;
19955 : :
2401 peter@eisentraut.org 19956 : 189 : pg_log_info("reading dependency data");
19957 : :
7996 tgl@sss.pgh.pa.us 19958 : 189 : query = createPQExpBuffer();
19959 : :
19960 : : /*
19961 : : * Messy query to collect the dependency data we need. Note that we
19962 : : * ignore the sub-object column, so that dependencies of or on a column
19963 : : * look the same as dependencies of or on a whole table.
19964 : : *
19965 : : * PIN dependencies aren't interesting, and EXTENSION dependencies were
19966 : : * already processed by getExtensionMembership.
19967 : : */
4361 heikki.linnakangas@i 19968 : 189 : appendPQExpBufferStr(query, "SELECT "
19969 : : "classid, objid, refclassid, refobjid, deptype "
19970 : : "FROM pg_depend "
19971 : : "WHERE deptype != 'p' AND deptype != 'e'\n");
19972 : :
19973 : : /*
19974 : : * Since we don't treat pg_amop entries as separate DumpableObjects, we
19975 : : * have to translate their dependencies into dependencies of their parent
19976 : : * opfamily. Ignore internal dependencies though, as those will point to
19977 : : * their parent opclass, which we needn't consider here (and if we did,
19978 : : * it'd just result in circular dependencies). Also, "loose" opfamily
19979 : : * entries will have dependencies on their parent opfamily, which we
19980 : : * should drop since they'd likewise become useless self-dependencies.
19981 : : * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
19982 : : */
1413 tgl@sss.pgh.pa.us 19983 : 189 : appendPQExpBufferStr(query, "UNION ALL\n"
19984 : : "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
19985 : : "FROM pg_depend d, pg_amop o "
19986 : : "WHERE deptype NOT IN ('p', 'e', 'i') AND "
19987 : : "classid = 'pg_amop'::regclass AND objid = o.oid "
19988 : : "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
19989 : :
19990 : : /* Likewise for pg_amproc entries */
19991 : 189 : appendPQExpBufferStr(query, "UNION ALL\n"
19992 : : "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
19993 : : "FROM pg_depend d, pg_amproc p "
19994 : : "WHERE deptype NOT IN ('p', 'e', 'i') AND "
19995 : : "classid = 'pg_amproc'::regclass AND objid = p.oid "
19996 : : "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
19997 : :
19998 : : /* Sort the output for efficiency below */
2280 19999 : 189 : appendPQExpBufferStr(query, "ORDER BY 1,2");
20000 : :
5011 rhaas@postgresql.org 20001 : 189 : res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
20002 : :
7996 tgl@sss.pgh.pa.us 20003 : 189 : ntups = PQntuples(res);
20004 : :
20005 : 189 : i_classid = PQfnumber(res, "classid");
20006 : 189 : i_objid = PQfnumber(res, "objid");
20007 : 189 : i_refclassid = PQfnumber(res, "refclassid");
20008 : 189 : i_refobjid = PQfnumber(res, "refobjid");
20009 : 189 : i_deptype = PQfnumber(res, "deptype");
20010 : :
20011 : : /*
20012 : : * Since we ordered the SELECT by referencing ID, we can expect that
20013 : : * multiple entries for the same object will appear together; this saves
20014 : : * on searches.
20015 : : */
20016 : 189 : dobj = NULL;
20017 : :
20018 [ + + ]: 407162 : for (i = 0; i < ntups; i++)
20019 : : {
20020 : : CatalogId objId;
20021 : : CatalogId refobjId;
20022 : : char deptype;
20023 : :
20024 : 406973 : objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
20025 : 406973 : objId.oid = atooid(PQgetvalue(res, i, i_objid));
20026 : 406973 : refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
20027 : 406973 : refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
20028 : 406973 : deptype = *(PQgetvalue(res, i, i_deptype));
20029 : :
20030 [ + + ]: 406973 : if (dobj == NULL ||
20031 [ + + ]: 382348 : dobj->catId.tableoid != objId.tableoid ||
20032 [ + + ]: 380226 : dobj->catId.oid != objId.oid)
20033 : 177310 : dobj = findObjectByCatalogId(objId);
20034 : :
20035 : : /*
20036 : : * Failure to find objects mentioned in pg_depend is not unexpected,
20037 : : * since for example we don't collect info about TOAST tables.
20038 : : */
20039 [ + + ]: 406973 : if (dobj == NULL)
20040 : : {
20041 : : #ifdef NOT_USED
20042 : : pg_log_warning("no referencing object %u %u",
20043 : : objId.tableoid, objId.oid);
20044 : : #endif
20045 : 25305 : continue;
20046 : : }
20047 : :
20048 : 382537 : refdobj = findObjectByCatalogId(refobjId);
20049 : :
20050 [ + + ]: 382537 : if (refdobj == NULL)
20051 : : {
20052 : : #ifdef NOT_USED
20053 : : pg_log_warning("no referenced object %u %u",
20054 : : refobjId.tableoid, refobjId.oid);
20055 : : #endif
20056 : 869 : continue;
20057 : : }
20058 : :
20059 : : /*
20060 : : * For 'x' dependencies, mark the object for later; we still add the
20061 : : * normal dependency, for possible ordering purposes. Currently
20062 : : * pg_dump_sort.c knows to put extensions ahead of all object types
20063 : : * that could possibly depend on them, but this is safer.
20064 : : */
2056 alvherre@alvh.no-ip. 20065 [ + + ]: 381668 : if (deptype == 'x')
20066 : 44 : dobj->depends_on_ext = true;
20067 : :
20068 : : /*
20069 : : * Ordinarily, table rowtypes have implicit dependencies on their
20070 : : * tables. However, for a composite type the implicit dependency goes
20071 : : * the other way in pg_depend; which is the right thing for DROP but
20072 : : * it doesn't produce the dependency ordering we need. So in that one
20073 : : * case, we reverse the direction of the dependency.
20074 : : */
7594 tgl@sss.pgh.pa.us 20075 [ + + ]: 381668 : if (deptype == 'i' &&
20076 [ + + ]: 107129 : dobj->objType == DO_TABLE &&
20077 [ + + ]: 1244 : refdobj->objType == DO_TYPE)
20078 : 182 : addObjectDependency(refdobj, dobj->dumpId);
20079 : : else
20080 : : /* normal case */
20081 : 381486 : addObjectDependency(dobj, refdobj->dumpId);
20082 : : }
20083 : :
7996 20084 : 189 : PQclear(res);
20085 : :
8851 20086 : 189 : destroyPQExpBuffer(query);
9883 bruce@momjian.us 20087 : 189 : }
20088 : :
20089 : :
20090 : : /*
20091 : : * createBoundaryObjects - create dummy DumpableObjects to represent
20092 : : * dump section boundaries.
20093 : : */
20094 : : static DumpableObject *
4872 tgl@sss.pgh.pa.us 20095 : 189 : createBoundaryObjects(void)
20096 : : {
20097 : : DumpableObject *dobjs;
20098 : :
20099 : 189 : dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
20100 : :
20101 : 189 : dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
20102 : 189 : dobjs[0].catId = nilCatalogId;
20103 : 189 : AssignDumpId(dobjs + 0);
20104 : 189 : dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
20105 : :
20106 : 189 : dobjs[1].objType = DO_POST_DATA_BOUNDARY;
20107 : 189 : dobjs[1].catId = nilCatalogId;
20108 : 189 : AssignDumpId(dobjs + 1);
20109 : 189 : dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
20110 : :
20111 : 189 : return dobjs;
20112 : : }
20113 : :
20114 : : /*
20115 : : * addBoundaryDependencies - add dependencies as needed to enforce the dump
20116 : : * section boundaries.
20117 : : */
20118 : : static void
20119 : 189 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
20120 : : DumpableObject *boundaryObjs)
20121 : : {
20122 : 189 : DumpableObject *preDataBound = boundaryObjs + 0;
20123 : 189 : DumpableObject *postDataBound = boundaryObjs + 1;
20124 : : int i;
20125 : :
20126 [ + + ]: 832807 : for (i = 0; i < numObjs; i++)
20127 : : {
20128 : 832618 : DumpableObject *dobj = dobjs[i];
20129 : :
20130 : : /*
20131 : : * The classification of object types here must match the SECTION_xxx
20132 : : * values assigned during subsequent ArchiveEntry calls!
20133 : : */
20134 [ + + + + : 832618 : switch (dobj->objType)
+ + + +
- ]
20135 : : {
20136 : 786609 : case DO_NAMESPACE:
20137 : : case DO_EXTENSION:
20138 : : case DO_TYPE:
20139 : : case DO_SHELL_TYPE:
20140 : : case DO_FUNC:
20141 : : case DO_AGG:
20142 : : case DO_OPERATOR:
20143 : : case DO_ACCESS_METHOD:
20144 : : case DO_OPCLASS:
20145 : : case DO_OPFAMILY:
20146 : : case DO_COLLATION:
20147 : : case DO_CONVERSION:
20148 : : case DO_TABLE:
20149 : : case DO_TABLE_ATTACH:
20150 : : case DO_ATTRDEF:
20151 : : case DO_PROCLANG:
20152 : : case DO_CAST:
20153 : : case DO_DUMMY_TYPE:
20154 : : case DO_TSPARSER:
20155 : : case DO_TSDICT:
20156 : : case DO_TSTEMPLATE:
20157 : : case DO_TSCONFIG:
20158 : : case DO_FDW:
20159 : : case DO_FOREIGN_SERVER:
20160 : : case DO_TRANSFORM:
20161 : : /* Pre-data objects: must come before the pre-data boundary */
20162 : 786609 : addObjectDependency(preDataBound, dobj->dumpId);
20163 : 786609 : break;
20164 : 4803 : case DO_TABLE_DATA:
20165 : : case DO_SEQUENCE_SET:
20166 : : case DO_LARGE_OBJECT:
20167 : : case DO_LARGE_OBJECT_DATA:
20168 : : /* Data objects: must come between the boundaries */
20169 : 4803 : addObjectDependency(dobj, preDataBound->dumpId);
20170 : 4803 : addObjectDependency(postDataBound, dobj->dumpId);
20171 : 4803 : break;
20172 : 5709 : case DO_INDEX:
20173 : : case DO_INDEX_ATTACH:
20174 : : case DO_STATSEXT:
20175 : : case DO_REFRESH_MATVIEW:
20176 : : case DO_TRIGGER:
20177 : : case DO_EVENT_TRIGGER:
20178 : : case DO_DEFAULT_ACL:
20179 : : case DO_POLICY:
20180 : : case DO_PUBLICATION:
20181 : : case DO_PUBLICATION_REL:
20182 : : case DO_PUBLICATION_TABLE_IN_SCHEMA:
20183 : : case DO_SUBSCRIPTION:
20184 : : case DO_SUBSCRIPTION_REL:
20185 : : /* Post-data objects: must come after the post-data boundary */
20186 : 5709 : addObjectDependency(dobj, postDataBound->dumpId);
20187 : 5709 : break;
20188 : 29307 : case DO_RULE:
20189 : : /* Rules are post-data, but only if dumped separately */
20190 [ + + ]: 29307 : if (((RuleInfo *) dobj)->separate)
20191 : 651 : addObjectDependency(dobj, postDataBound->dumpId);
20192 : 29307 : break;
20193 : 2517 : case DO_CONSTRAINT:
20194 : : case DO_FK_CONSTRAINT:
20195 : : /* Constraints are post-data, but only if dumped separately */
20196 [ + + ]: 2517 : if (((ConstraintInfo *) dobj)->separate)
20197 : 1809 : addObjectDependency(dobj, postDataBound->dumpId);
20198 : 2517 : break;
20199 : 189 : case DO_PRE_DATA_BOUNDARY:
20200 : : /* nothing to do */
20201 : 189 : break;
20202 : 189 : case DO_POST_DATA_BOUNDARY:
20203 : : /* must come after the pre-data boundary */
20204 : 189 : addObjectDependency(dobj, preDataBound->dumpId);
20205 : 189 : break;
249 jdavis@postgresql.or 20206 : 3295 : case DO_REL_STATS:
20207 : : /* stats section varies by parent object type, DATA or POST */
213 20208 [ + + ]: 3295 : if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
20209 : : {
249 20210 : 2118 : addObjectDependency(dobj, preDataBound->dumpId);
20211 : 2118 : addObjectDependency(postDataBound, dobj->dumpId);
20212 : : }
20213 : : else
20214 : 1177 : addObjectDependency(dobj, postDataBound->dumpId);
20215 : 3295 : break;
20216 : : }
20217 : : }
4872 tgl@sss.pgh.pa.us 20218 : 189 : }
20219 : :
20220 : :
20221 : : /*
20222 : : * BuildArchiveDependencies - create dependency data for archive TOC entries
20223 : : *
20224 : : * The raw dependency data obtained by getDependencies() is not terribly
20225 : : * useful in an archive dump, because in many cases there are dependency
20226 : : * chains linking through objects that don't appear explicitly in the dump.
20227 : : * For example, a view will depend on its _RETURN rule while the _RETURN rule
20228 : : * will depend on other objects --- but the rule will not appear as a separate
20229 : : * object in the dump. We need to adjust the view's dependencies to include
20230 : : * whatever the rule depends on that is included in the dump.
20231 : : *
20232 : : * Just to make things more complicated, there are also "special" dependencies
20233 : : * such as the dependency of a TABLE DATA item on its TABLE, which we must
20234 : : * not rearrange because pg_restore knows that TABLE DATA only depends on
20235 : : * its table. In these cases we must leave the dependencies strictly as-is
20236 : : * even if they refer to not-to-be-dumped objects.
20237 : : *
20238 : : * To handle this, the convention is that "special" dependencies are created
20239 : : * during ArchiveEntry calls, and an archive TOC item that has any such
20240 : : * entries will not be touched here. Otherwise, we recursively search the
20241 : : * DumpableObject data structures to build the correct dependencies for each
20242 : : * archive TOC item.
20243 : : */
20244 : : static void
20245 : 58 : BuildArchiveDependencies(Archive *fout)
20246 : : {
20247 : 58 : ArchiveHandle *AH = (ArchiveHandle *) fout;
20248 : : TocEntry *te;
20249 : :
20250 : : /* Scan all TOC entries in the archive */
20251 [ + + ]: 6642 : for (te = AH->toc->next; te != AH->toc; te = te->next)
20252 : : {
20253 : : DumpableObject *dobj;
20254 : : DumpId *dependencies;
20255 : : int nDeps;
20256 : : int allocDeps;
20257 : :
20258 : : /* No need to process entries that will not be dumped */
20259 [ + + ]: 6584 : if (te->reqs == 0)
20260 : 3224 : continue;
20261 : : /* Ignore entries that already have "special" dependencies */
20262 [ + + ]: 6571 : if (te->nDeps > 0)
20263 : 2775 : continue;
20264 : : /* Otherwise, look up the item's original DumpableObject, if any */
20265 : 3796 : dobj = findObjectByDumpId(te->dumpId);
20266 [ + + ]: 3796 : if (dobj == NULL)
20267 : 344 : continue;
20268 : : /* No work if it has no dependencies */
20269 [ + + ]: 3452 : if (dobj->nDeps <= 0)
20270 : 92 : continue;
20271 : : /* Set up work array */
20272 : 3360 : allocDeps = 64;
20273 : 3360 : dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
20274 : 3360 : nDeps = 0;
20275 : : /* Recursively find all dumpable dependencies */
20276 : 3360 : findDumpableDependencies(AH, dobj,
20277 : : &dependencies, &nDeps, &allocDeps);
20278 : : /* And save 'em ... */
20279 [ + + ]: 3360 : if (nDeps > 0)
20280 : : {
20281 : 2491 : dependencies = (DumpId *) pg_realloc(dependencies,
20282 : : nDeps * sizeof(DumpId));
20283 : 2491 : te->dependencies = dependencies;
20284 : 2491 : te->nDeps = nDeps;
20285 : : }
20286 : : else
20287 : 869 : free(dependencies);
20288 : : }
20289 : 58 : }
20290 : :
20291 : : /* Recursive search subroutine for BuildArchiveDependencies */
20292 : : static void
1720 peter@eisentraut.org 20293 : 8252 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
20294 : : DumpId **dependencies, int *nDeps, int *allocDeps)
20295 : : {
20296 : : int i;
20297 : :
20298 : : /*
20299 : : * Ignore section boundary objects: if we search through them, we'll
20300 : : * report lots of bogus dependencies.
20301 : : */
4872 tgl@sss.pgh.pa.us 20302 [ + + ]: 8252 : if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
20303 [ + + ]: 8233 : dobj->objType == DO_POST_DATA_BOUNDARY)
20304 : 1387 : return;
20305 : :
20306 [ + + ]: 17017 : for (i = 0; i < dobj->nDeps; i++)
20307 : : {
20308 : 10152 : DumpId depid = dobj->dependencies[i];
20309 : :
20310 [ + + ]: 10152 : if (TocIDRequired(AH, depid) != 0)
20311 : : {
20312 : : /* Object will be dumped, so just reference it as a dependency */
20313 [ - + ]: 5260 : if (*nDeps >= *allocDeps)
20314 : : {
4872 tgl@sss.pgh.pa.us 20315 :UBC 0 : *allocDeps *= 2;
20316 : 0 : *dependencies = (DumpId *) pg_realloc(*dependencies,
3050 20317 : 0 : *allocDeps * sizeof(DumpId));
20318 : : }
4872 tgl@sss.pgh.pa.us 20319 :CBC 5260 : (*dependencies)[*nDeps] = depid;
20320 : 5260 : (*nDeps)++;
20321 : : }
20322 : : else
20323 : : {
20324 : : /*
20325 : : * Object will not be dumped, so recursively consider its deps. We
20326 : : * rely on the assumption that sortDumpableObjects already broke
20327 : : * any dependency loops, else we might recurse infinitely.
20328 : : */
20329 : 4892 : DumpableObject *otherdobj = findObjectByDumpId(depid);
20330 : :
20331 [ + - ]: 4892 : if (otherdobj)
20332 : 4892 : findDumpableDependencies(AH, otherdobj,
20333 : : dependencies, nDeps, allocDeps);
20334 : : }
20335 : : }
20336 : : }
20337 : :
20338 : :
20339 : : /*
20340 : : * getFormattedTypeName - retrieve a nicely-formatted type name for the
20341 : : * given type OID.
20342 : : *
20343 : : * This does not guarantee to schema-qualify the output, so it should not
20344 : : * be used to create the target object name for CREATE or ALTER commands.
20345 : : *
20346 : : * Note that the result is cached and must not be freed by the caller.
20347 : : */
20348 : : static const char *
5012 rhaas@postgresql.org 20349 : 2300 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
20350 : : {
20351 : : TypeInfo *typeInfo;
20352 : : char *result;
20353 : : PQExpBuffer query;
20354 : : PGresult *res;
20355 : :
7996 tgl@sss.pgh.pa.us 20356 [ - + ]: 2300 : if (oid == 0)
20357 : : {
2062 tgl@sss.pgh.pa.us 20358 [ # # ]:UBC 0 : if ((opts & zeroAsStar) != 0)
1510 20359 : 0 : return "*";
8571 20360 [ # # ]: 0 : else if ((opts & zeroAsNone) != 0)
1510 20361 : 0 : return "NONE";
20362 : : }
20363 : :
20364 : : /* see if we have the result cached in the type's TypeInfo record */
1518 tgl@sss.pgh.pa.us 20365 :CBC 2300 : typeInfo = findTypeByOid(oid);
20366 [ + - + + ]: 2300 : if (typeInfo && typeInfo->ftypname)
1510 20367 : 1833 : return typeInfo->ftypname;
20368 : :
8571 20369 : 467 : query = createPQExpBuffer();
3302 20370 : 467 : appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
20371 : : oid);
20372 : :
5002 rhaas@postgresql.org 20373 : 467 : res = ExecuteSqlQueryForSingleRow(fout, query->data);
20374 : :
20375 : : /* result of format_type is already quoted */
3302 tgl@sss.pgh.pa.us 20376 : 467 : result = pg_strdup(PQgetvalue(res, 0, 0));
20377 : :
8571 20378 : 467 : PQclear(res);
20379 : 467 : destroyPQExpBuffer(query);
20380 : :
20381 : : /*
20382 : : * Cache the result for re-use in later requests, if possible. If we
20383 : : * don't have a TypeInfo for the type, the string will be leaked once the
20384 : : * caller is done with it ... but that case really should not happen, so
20385 : : * leaking if it does seems acceptable.
20386 : : */
1518 20387 [ + - ]: 467 : if (typeInfo)
1510 20388 : 467 : typeInfo->ftypname = result;
20389 : :
8571 20390 : 467 : return result;
20391 : : }
20392 : :
20393 : : /*
20394 : : * Return a column list clause for the given relation.
20395 : : *
20396 : : * Special case: if there are no undropped columns in the relation, return
20397 : : * "", not an invalid "()" column list.
20398 : : */
20399 : : static const char *
4600 andrew@dunslane.net 20400 : 8206 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
20401 : : {
8502 bruce@momjian.us 20402 : 8206 : int numatts = ti->numatts;
8454 20403 : 8206 : char **attnames = ti->attnames;
20404 : 8206 : bool *attisdropped = ti->attisdropped;
2403 peter@eisentraut.org 20405 : 8206 : char *attgenerated = ti->attgenerated;
20406 : : bool needComma;
20407 : : int i;
20408 : :
4361 heikki.linnakangas@i 20409 : 8206 : appendPQExpBufferChar(buffer, '(');
8487 tgl@sss.pgh.pa.us 20410 : 8206 : needComma = false;
8502 bruce@momjian.us 20411 [ + + ]: 40018 : for (i = 0; i < numatts; i++)
20412 : : {
8487 tgl@sss.pgh.pa.us 20413 [ + + ]: 31812 : if (attisdropped[i])
20414 : 598 : continue;
2403 peter@eisentraut.org 20415 [ + + ]: 31214 : if (attgenerated[i])
20416 : 1104 : continue;
8487 tgl@sss.pgh.pa.us 20417 [ + + ]: 30110 : if (needComma)
4361 heikki.linnakangas@i 20418 : 22128 : appendPQExpBufferStr(buffer, ", ");
20419 : 30110 : appendPQExpBufferStr(buffer, fmtId(attnames[i]));
8487 tgl@sss.pgh.pa.us 20420 : 30110 : needComma = true;
20421 : : }
20422 : :
8355 20423 [ + + ]: 8206 : if (!needComma)
8221 20424 : 224 : return ""; /* no undropped columns */
20425 : :
4361 heikki.linnakangas@i 20426 : 7982 : appendPQExpBufferChar(buffer, ')');
4600 andrew@dunslane.net 20427 : 7982 : return buffer->data;
20428 : : }
20429 : :
20430 : : /*
20431 : : * Check if a reloptions array is nonempty.
20432 : : */
20433 : : static bool
3586 tgl@sss.pgh.pa.us 20434 : 13449 : nonemptyReloptions(const char *reloptions)
20435 : : {
20436 : : /* Don't want to print it if it's just "{}" */
20437 [ + - + + ]: 13449 : return (reloptions != NULL && strlen(reloptions) > 2);
20438 : : }
20439 : :
20440 : : /*
20441 : : * Format a reloptions array and append it to the given buffer.
20442 : : *
20443 : : * "prefix" is prepended to the option names; typically it's "" or "toast.".
20444 : : */
20445 : : static void
3461 dean.a.rasheed@gmail 20446 : 208 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
20447 : : const char *prefix, Archive *fout)
20448 : : {
20449 : : bool res;
20450 : :
20451 : 208 : res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
20452 : 208 : fout->std_strings);
20453 [ - + ]: 208 : if (!res)
1458 peter@eisentraut.org 20454 :UBC 0 : pg_log_warning("could not parse %s array", "reloptions");
3586 tgl@sss.pgh.pa.us 20455 :CBC 208 : }
20456 : :
20457 : : /*
20458 : : * read_dump_filters - retrieve object identifier patterns from file
20459 : : *
20460 : : * Parse the specified filter file for include and exclude patterns, and add
20461 : : * them to the relevant lists. If the filename is "-" then filters will be
20462 : : * read from STDIN rather than a file.
20463 : : */
20464 : : static void
698 dgustafsson@postgres 20465 : 26 : read_dump_filters(const char *filename, DumpOptions *dopt)
20466 : : {
20467 : : FilterStateData fstate;
20468 : : char *objname;
20469 : : FilterCommandType comtype;
20470 : : FilterObjectType objtype;
20471 : :
20472 : 26 : filter_init(&fstate, filename, exit_nicely);
20473 : :
20474 [ + + ]: 84 : while (filter_read_item(&fstate, &objname, &comtype, &objtype))
20475 : : {
20476 [ + + ]: 33 : if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
20477 : : {
20478 [ - - + + : 17 : switch (objtype)
+ + + - ]
20479 : : {
698 dgustafsson@postgres 20480 :UBC 0 : case FILTER_OBJECT_TYPE_NONE:
20481 : 0 : break;
20482 : 0 : case FILTER_OBJECT_TYPE_DATABASE:
20483 : : case FILTER_OBJECT_TYPE_FUNCTION:
20484 : : case FILTER_OBJECT_TYPE_INDEX:
20485 : : case FILTER_OBJECT_TYPE_TABLE_DATA:
20486 : : case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
20487 : : case FILTER_OBJECT_TYPE_TRIGGER:
697 20488 : 0 : pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
20489 : : "include",
20490 : : filter_object_type_name(objtype));
698 20491 : 0 : exit_nicely(1);
20492 : : break; /* unreachable */
20493 : :
698 dgustafsson@postgres 20494 :CBC 1 : case FILTER_OBJECT_TYPE_EXTENSION:
20495 : 1 : simple_string_list_append(&extension_include_patterns, objname);
20496 : 1 : break;
20497 : 1 : case FILTER_OBJECT_TYPE_FOREIGN_DATA:
20498 : 1 : simple_string_list_append(&foreign_servers_include_patterns, objname);
20499 : 1 : break;
20500 : 1 : case FILTER_OBJECT_TYPE_SCHEMA:
20501 : 1 : simple_string_list_append(&schema_include_patterns, objname);
20502 : 1 : dopt->include_everything = false;
20503 : 1 : break;
20504 : 13 : case FILTER_OBJECT_TYPE_TABLE:
20505 : 13 : simple_string_list_append(&table_include_patterns, objname);
20506 : 13 : dopt->include_everything = false;
20507 : 13 : break;
20508 : 1 : case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
20509 : 1 : simple_string_list_append(&table_include_patterns_and_children,
20510 : : objname);
20511 : 1 : dopt->include_everything = false;
20512 : 1 : break;
20513 : : }
20514 : : }
20515 [ + + ]: 16 : else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
20516 : : {
20517 [ - + + + : 9 : switch (objtype)
+ + + +
- ]
20518 : : {
698 dgustafsson@postgres 20519 :UBC 0 : case FILTER_OBJECT_TYPE_NONE:
20520 : 0 : break;
698 dgustafsson@postgres 20521 :CBC 1 : case FILTER_OBJECT_TYPE_DATABASE:
20522 : : case FILTER_OBJECT_TYPE_FUNCTION:
20523 : : case FILTER_OBJECT_TYPE_INDEX:
20524 : : case FILTER_OBJECT_TYPE_TRIGGER:
20525 : : case FILTER_OBJECT_TYPE_FOREIGN_DATA:
697 20526 : 1 : pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
20527 : : "exclude",
20528 : : filter_object_type_name(objtype));
698 20529 : 1 : exit_nicely(1);
20530 : : break;
20531 : :
586 dean.a.rasheed@gmail 20532 : 1 : case FILTER_OBJECT_TYPE_EXTENSION:
20533 : 1 : simple_string_list_append(&extension_exclude_patterns, objname);
20534 : 1 : break;
698 dgustafsson@postgres 20535 : 1 : case FILTER_OBJECT_TYPE_TABLE_DATA:
20536 : 1 : simple_string_list_append(&tabledata_exclude_patterns,
20537 : : objname);
20538 : 1 : break;
20539 : 1 : case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
20540 : 1 : simple_string_list_append(&tabledata_exclude_patterns_and_children,
20541 : : objname);
20542 : 1 : break;
20543 : 2 : case FILTER_OBJECT_TYPE_SCHEMA:
20544 : 2 : simple_string_list_append(&schema_exclude_patterns, objname);
20545 : 2 : break;
20546 : 2 : case FILTER_OBJECT_TYPE_TABLE:
20547 : 2 : simple_string_list_append(&table_exclude_patterns, objname);
20548 : 2 : break;
20549 : 1 : case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
20550 : 1 : simple_string_list_append(&table_exclude_patterns_and_children,
20551 : : objname);
20552 : 1 : break;
20553 : : }
20554 : : }
20555 : : else
20556 : : {
20557 [ - + ]: 7 : Assert(comtype == FILTER_COMMAND_TYPE_NONE);
20558 [ - + ]: 7 : Assert(objtype == FILTER_OBJECT_TYPE_NONE);
20559 : : }
20560 : :
20561 [ + + ]: 32 : if (objname)
20562 : 25 : free(objname);
20563 : : }
20564 : :
20565 : 22 : filter_free(&fstate);
20566 : 22 : }
|