TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * common.c
4 : * Catalog routines used by pg_dump; long ago these were shared
5 : * by another dump tool, but not anymore.
6 : *
7 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
8 : * Portions Copyright (c) 1994, Regents of the University of California
9 : *
10 : *
11 : * IDENTIFICATION
12 : * src/bin/pg_dump/common.c
13 : *
14 : *-------------------------------------------------------------------------
15 : */
16 : #include "postgres_fe.h"
17 :
18 : #include <ctype.h>
19 :
20 : #include "catalog/pg_class_d.h"
21 : #include "catalog/pg_collation_d.h"
22 : #include "catalog/pg_extension_d.h"
23 : #include "catalog/pg_namespace_d.h"
24 : #include "catalog/pg_operator_d.h"
25 : #include "catalog/pg_proc_d.h"
26 : #include "catalog/pg_publication_d.h"
27 : #include "catalog/pg_type_d.h"
28 : #include "common/hashfn.h"
29 : #include "fe_utils/string_utils.h"
30 : #include "pg_backup_archiver.h"
31 : #include "pg_backup_utils.h"
32 : #include "pg_dump.h"
33 :
34 : /*
35 : * Variables for mapping DumpId to DumpableObject
36 : */
37 : static DumpableObject **dumpIdMap = NULL;
38 : static int allocedDumpIds = 0;
39 : static DumpId lastDumpId = 0; /* Note: 0 is InvalidDumpId */
40 :
41 : /*
42 : * Infrastructure for mapping CatalogId to DumpableObject
43 : *
44 : * We use a hash table generated by simplehash.h. That infrastructure
45 : * requires all the hash table entries to be the same size, and it also
46 : * expects that it can move them around when resizing the table. So we
47 : * cannot make the DumpableObjects be elements of the hash table directly;
48 : * instead, the hash table elements contain pointers to DumpableObjects.
49 : *
50 : * It turns out to be convenient to also use this data structure to map
51 : * CatalogIds to owning extensions, if any. Since extension membership
52 : * data is read before creating most DumpableObjects, either one of dobj
53 : * and ext could be NULL.
54 : */
55 : typedef struct _catalogIdMapEntry
56 : {
57 : CatalogId catId; /* the indexed CatalogId */
58 : uint32 status; /* hash status */
59 : uint32 hashval; /* hash code for the CatalogId */
60 : DumpableObject *dobj; /* the associated DumpableObject, if any */
61 : ExtensionInfo *ext; /* owning extension, if any */
62 : } CatalogIdMapEntry;
63 :
64 : #define SH_PREFIX catalogid
65 : #define SH_ELEMENT_TYPE CatalogIdMapEntry
66 : #define SH_KEY_TYPE CatalogId
67 : #define SH_KEY catId
68 : #define SH_HASH_KEY(tb, key) hash_bytes((const unsigned char *) &(key), sizeof(CatalogId))
69 : #define SH_EQUAL(tb, a, b) ((a).oid == (b).oid && (a).tableoid == (b).tableoid)
70 : #define SH_STORE_HASH
71 : #define SH_GET_HASH(tb, a) (a)->hashval
72 : #define SH_SCOPE static inline
73 : #define SH_RAW_ALLOCATOR pg_malloc0
74 : #define SH_DECLARE
75 : #define SH_DEFINE
76 : #include "lib/simplehash.h"
77 :
78 : #define CATALOGIDHASH_INITIAL_SIZE 10000
79 :
80 : static catalogid_hash *catalogIdHash = NULL;
81 :
82 : static void flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
83 : InhInfo *inhinfo, int numInherits);
84 : static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables);
85 : static void flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo,
86 : int numTables);
87 : static int strInArray(const char *pattern, char **arr, int arr_size);
88 : static IndxInfo *findIndexByOid(Oid oid);
89 :
90 :
91 : /*
92 : * getSchemaData
93 : * Collect information about all potentially dumpable objects
94 : */
95 ECB : TableInfo *
96 GIC 119 : getSchemaData(Archive *fout, int *numTablesPtr)
97 : {
98 : TableInfo *tblinfo;
99 : ExtensionInfo *extinfo;
100 : InhInfo *inhinfo;
101 : int numTables;
102 : int numTypes;
103 : int numFuncs;
104 : int numOperators;
105 : int numCollations;
106 : int numNamespaces;
107 : int numExtensions;
108 : int numPublications;
109 : int numAggregates;
110 : int numInherits;
111 : int numRules;
112 : int numProcLangs;
113 : int numCasts;
114 : int numTransforms;
115 : int numAccessMethods;
116 : int numOpclasses;
117 : int numOpfamilies;
118 : int numConversions;
119 : int numTSParsers;
120 : int numTSTemplates;
121 : int numTSDicts;
122 : int numTSConfigs;
123 : int numForeignDataWrappers;
124 : int numForeignServers;
125 : int numDefaultACLs;
126 : int numEventTriggers;
127 :
128 : /*
129 : * We must read extensions and extension membership info first, because
130 : * extension membership needs to be consultable during decisions about
131 : * whether other objects are to be dumped.
132 ECB : */
133 CBC 119 : pg_log_info("reading extensions");
134 GIC 119 : extinfo = getExtensions(fout, &numExtensions);
135 ECB :
136 CBC 119 : pg_log_info("identifying extension members");
137 GIC 119 : getExtensionMembership(fout, extinfo, numExtensions);
138 ECB :
139 CBC 119 : pg_log_info("reading schemas");
140 GIC 119 : (void) getNamespaces(fout, &numNamespaces);
141 :
142 : /*
143 : * getTables should be done as soon as possible, so as to minimize the
144 : * window between starting our transaction and acquiring per-table locks.
145 : * However, we have to do getNamespaces first because the tables get
146 : * linked to their containing namespaces during getTables.
147 ECB : */
148 CBC 119 : pg_log_info("reading user-defined tables");
149 GIC 119 : tblinfo = getTables(fout, &numTables);
150 ECB :
151 GIC 118 : getOwnedSeqs(fout, tblinfo, numTables);
152 ECB :
153 CBC 118 : pg_log_info("reading user-defined functions");
154 GIC 118 : (void) getFuncs(fout, &numFuncs);
155 :
156 ECB : /* this must be after getTables and getFuncs */
157 CBC 118 : pg_log_info("reading user-defined types");
158 GIC 118 : (void) getTypes(fout, &numTypes);
159 :
160 ECB : /* this must be after getFuncs, too */
161 CBC 118 : pg_log_info("reading procedural languages");
162 GIC 118 : getProcLangs(fout, &numProcLangs);
163 ECB :
164 CBC 118 : pg_log_info("reading user-defined aggregate functions");
165 GIC 118 : getAggregates(fout, &numAggregates);
166 ECB :
167 CBC 118 : pg_log_info("reading user-defined operators");
168 GIC 118 : (void) getOperators(fout, &numOperators);
169 ECB :
170 CBC 118 : pg_log_info("reading user-defined access methods");
171 GIC 118 : getAccessMethods(fout, &numAccessMethods);
172 ECB :
173 CBC 118 : pg_log_info("reading user-defined operator classes");
174 GIC 118 : getOpclasses(fout, &numOpclasses);
175 ECB :
176 CBC 118 : pg_log_info("reading user-defined operator families");
177 GIC 118 : getOpfamilies(fout, &numOpfamilies);
178 ECB :
179 CBC 118 : pg_log_info("reading user-defined text search parsers");
180 GIC 118 : getTSParsers(fout, &numTSParsers);
181 ECB :
182 CBC 118 : pg_log_info("reading user-defined text search templates");
183 GIC 118 : getTSTemplates(fout, &numTSTemplates);
184 ECB :
185 CBC 118 : pg_log_info("reading user-defined text search dictionaries");
186 GIC 118 : getTSDictionaries(fout, &numTSDicts);
187 ECB :
188 CBC 118 : pg_log_info("reading user-defined text search configurations");
189 GIC 118 : getTSConfigurations(fout, &numTSConfigs);
190 ECB :
191 CBC 118 : pg_log_info("reading user-defined foreign-data wrappers");
192 GIC 118 : getForeignDataWrappers(fout, &numForeignDataWrappers);
193 ECB :
194 CBC 118 : pg_log_info("reading user-defined foreign servers");
195 GIC 118 : getForeignServers(fout, &numForeignServers);
196 ECB :
197 CBC 118 : pg_log_info("reading default privileges");
198 GIC 118 : getDefaultACLs(fout, &numDefaultACLs);
199 ECB :
200 CBC 118 : pg_log_info("reading user-defined collations");
201 GIC 118 : (void) getCollations(fout, &numCollations);
202 ECB :
203 CBC 118 : pg_log_info("reading user-defined conversions");
204 GIC 118 : getConversions(fout, &numConversions);
205 ECB :
206 CBC 118 : pg_log_info("reading type casts");
207 GIC 118 : getCasts(fout, &numCasts);
208 ECB :
209 CBC 118 : pg_log_info("reading transforms");
210 GIC 118 : getTransforms(fout, &numTransforms);
211 ECB :
212 CBC 118 : pg_log_info("reading table inheritance information");
213 GIC 118 : inhinfo = getInherits(fout, &numInherits);
214 ECB :
215 CBC 118 : pg_log_info("reading event triggers");
216 GIC 118 : getEventTriggers(fout, &numEventTriggers);
217 :
218 ECB : /* Identify extension configuration tables that should be dumped */
219 CBC 118 : pg_log_info("finding extension tables");
220 GIC 118 : processExtensionTables(fout, extinfo, numExtensions);
221 :
222 ECB : /* Link tables to parents, mark parents of target tables interesting */
223 CBC 118 : pg_log_info("finding inheritance relationships");
224 GIC 118 : flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
225 ECB :
226 CBC 118 : pg_log_info("reading column info for interesting tables");
227 GIC 118 : getTableAttrs(fout, tblinfo, numTables);
228 ECB :
229 CBC 118 : pg_log_info("flagging inherited columns in subtables");
230 GNC 118 : flagInhAttrs(fout, fout->dopt, tblinfo, numTables);
231 ECB :
232 CBC 118 : pg_log_info("reading partitioning data");
233 GIC 118 : getPartitioningInfo(fout);
234 ECB :
235 CBC 118 : pg_log_info("reading indexes");
236 GIC 118 : getIndexes(fout, tblinfo, numTables);
237 ECB :
238 CBC 118 : pg_log_info("flagging indexes in partitioned tables");
239 GIC 118 : flagInhIndexes(fout, tblinfo, numTables);
240 ECB :
241 CBC 118 : pg_log_info("reading extended statistics");
242 GIC 118 : getExtendedStatistics(fout);
243 ECB :
244 CBC 118 : pg_log_info("reading constraints");
245 GIC 118 : getConstraints(fout, tblinfo, numTables);
246 ECB :
247 CBC 118 : pg_log_info("reading triggers");
248 GIC 118 : getTriggers(fout, tblinfo, numTables);
249 ECB :
250 CBC 118 : pg_log_info("reading rewrite rules");
251 GIC 118 : getRules(fout, &numRules);
252 ECB :
253 CBC 118 : pg_log_info("reading policies");
254 GIC 118 : getPolicies(fout, tblinfo, numTables);
255 ECB :
256 CBC 118 : pg_log_info("reading publications");
257 GIC 118 : (void) getPublications(fout, &numPublications);
258 ECB :
259 CBC 118 : pg_log_info("reading publication membership of tables");
260 GIC 118 : getPublicationTables(fout, tblinfo, numTables);
261 ECB :
262 CBC 118 : pg_log_info("reading publication membership of schemas");
263 GIC 118 : getPublicationNamespaces(fout);
264 ECB :
265 CBC 118 : pg_log_info("reading subscriptions");
266 GIC 118 : getSubscriptions(fout);
267 ECB :
268 GIC 118 : free(inhinfo); /* not needed any longer */
269 ECB :
270 CBC 118 : *numTablesPtr = numTables;
271 GIC 118 : return tblinfo;
272 : }
273 :
274 : /* flagInhTables -
275 : * Fill in parent link fields of tables for which we need that information,
276 : * mark parents of target tables as interesting, and create
277 : * TableAttachInfo objects for partitioned tables with appropriate
278 : * dependency links.
279 : *
280 : * Note that only direct ancestors of targets are marked interesting.
281 : * This is sufficient; we don't much care whether they inherited their
282 : * attributes or not.
283 : *
284 : * modifies tblinfo
285 : */
286 ECB : static void
287 GIC 118 : flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
288 : InhInfo *inhinfo, int numInherits)
289 ECB : {
290 GNC 118 : TableInfo *child = NULL;
291 118 : TableInfo *parent = NULL;
292 ECB : int i,
293 : j;
294 :
295 : /*
296 : * Set up links from child tables to their parents.
297 : *
298 : * We used to attempt to skip this work for tables that are not to be
299 : * dumped; but the optimizable cases are rare in practice, and setting up
300 : * these links in bulk is cheaper than the old way. (Note in particular
301 : * that it's very rare for a child to have more than one parent.)
302 : */
303 GNC 2272 : for (i = 0; i < numInherits; i++)
304 : {
305 : /*
306 : * Skip a hashtable lookup if it's same table as last time. This is
307 : * unlikely for the child, but less so for the parent. (Maybe we
308 : * should ask the backend for a sorted array to make it more likely?
309 : * Not clear the sorting effort would be repaid, though.)
310 : */
311 2154 : if (child == NULL ||
312 1543 : child->dobj.catId.oid != inhinfo[i].inhrelid)
313 : {
314 2129 : child = findTableByOid(inhinfo[i].inhrelid);
315 :
316 : /*
317 : * If we find no TableInfo, assume the pg_inherits entry is for a
318 : * partitioned index, which we don't need to track.
319 : */
320 2129 : if (child == NULL)
321 607 : continue;
322 : }
323 1547 : if (parent == NULL ||
324 1495 : parent->dobj.catId.oid != inhinfo[i].inhparent)
325 : {
326 960 : parent = findTableByOid(inhinfo[i].inhparent);
327 960 : if (parent == NULL)
328 UNC 0 : pg_fatal("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
329 : inhinfo[i].inhparent,
330 : child->dobj.name,
331 : child->dobj.catId.oid);
332 : }
333 : /* Add this parent to the child's list of parents. */
334 GNC 1547 : if (child->numParents > 0)
335 25 : child->parents = pg_realloc_array(child->parents,
336 : TableInfo *,
337 : child->numParents + 1);
338 : else
339 1522 : child->parents = pg_malloc_array(TableInfo *, 1);
340 1547 : child->parents[child->numParents++] = parent;
341 : }
342 :
343 : /*
344 : * Now consider all child tables and mark parents interesting as needed.
345 : */
346 GIC 30474 : for (i = 0; i < numTables; i++)
347 : {
348 : /*
349 ECB : * If needed, mark the parents as interesting for getTableAttrs and
350 : * getIndexes. We only need this for direct parents of dumpable
351 : * tables.
352 EUB : */
353 GNC 30356 : if (tblinfo[i].dobj.dump)
354 : {
355 GIC 20412 : int numParents = tblinfo[i].numParents;
356 20412 : TableInfo **parents = tblinfo[i].parents;
357 :
358 CBC 21915 : for (j = 0; j < numParents; j++)
359 1503 : parents[j]->interesting = true;
360 : }
361 :
362 : /* Create TableAttachInfo object if needed */
363 GNC 30356 : if ((tblinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
364 5139 : tblinfo[i].ispartition)
365 ECB : {
366 : TableAttachInfo *attachinfo;
367 :
368 : /* With partitions there can only be one parent */
369 GIC 1166 : if (tblinfo[i].numParents != 1)
370 UIC 0 : pg_fatal("invalid number of parents %d for table \"%s\"",
371 ECB : tblinfo[i].numParents,
372 : tblinfo[i].dobj.name);
373 :
374 GIC 1166 : attachinfo = (TableAttachInfo *) palloc(sizeof(TableAttachInfo));
375 1166 : attachinfo->dobj.objType = DO_TABLE_ATTACH;
376 1166 : attachinfo->dobj.catId.tableoid = 0;
377 1166 : attachinfo->dobj.catId.oid = 0;
378 CBC 1166 : AssignDumpId(&attachinfo->dobj);
379 GIC 1166 : attachinfo->dobj.name = pg_strdup(tblinfo[i].dobj.name);
380 CBC 1166 : attachinfo->dobj.namespace = tblinfo[i].dobj.namespace;
381 1166 : attachinfo->parentTbl = tblinfo[i].parents[0];
382 GIC 1166 : attachinfo->partitionTbl = &tblinfo[i];
383 ECB :
384 : /*
385 : * We must state the DO_TABLE_ATTACH object's dependencies
386 : * explicitly, since it will not match anything in pg_depend.
387 : *
388 : * Give it dependencies on both the partition table and the parent
389 : * table, so that it will not be executed till both of those
390 : * exist. (There's no need to care what order those are created
391 : * in.)
392 : */
393 GIC 1166 : addObjectDependency(&attachinfo->dobj, tblinfo[i].dobj.dumpId);
394 CBC 1166 : addObjectDependency(&attachinfo->dobj, tblinfo[i].parents[0]->dobj.dumpId);
395 EUB : }
396 : }
397 GIC 118 : }
398 :
399 ECB : /*
400 : * flagInhIndexes -
401 : * Create IndexAttachInfo objects for partitioned indexes, and add
402 : * appropriate dependency links.
403 : */
404 : static void
405 CBC 118 : flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
406 ECB : {
407 : int i,
408 : j;
409 :
410 GIC 30474 : for (i = 0; i < numTables; i++)
411 : {
412 30356 : if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
413 29164 : continue;
414 :
415 1192 : Assert(tblinfo[i].numParents == 1);
416 :
417 1809 : for (j = 0; j < tblinfo[i].numIndexes; j++)
418 ECB : {
419 CBC 617 : IndxInfo *index = &(tblinfo[i].indexes[j]);
420 : IndxInfo *parentidx;
421 : IndexAttachInfo *attachinfo;
422 ECB :
423 GIC 617 : if (index->parentidx == 0)
424 50 : continue;
425 :
426 567 : parentidx = findIndexByOid(index->parentidx);
427 567 : if (parentidx == NULL)
428 UIC 0 : continue;
429 :
430 GNC 567 : attachinfo = pg_malloc_object(IndexAttachInfo);
431 :
432 GIC 567 : attachinfo->dobj.objType = DO_INDEX_ATTACH;
433 567 : attachinfo->dobj.catId.tableoid = 0;
434 567 : attachinfo->dobj.catId.oid = 0;
435 CBC 567 : AssignDumpId(&attachinfo->dobj);
436 GIC 567 : attachinfo->dobj.name = pg_strdup(index->dobj.name);
437 CBC 567 : attachinfo->dobj.namespace = index->indextable->dobj.namespace;
438 567 : attachinfo->parentIdx = parentidx;
439 GIC 567 : attachinfo->partitionIdx = index;
440 ECB :
441 : /*
442 : * We must state the DO_INDEX_ATTACH object's dependencies
443 : * explicitly, since it will not match anything in pg_depend.
444 : *
445 : * Give it dependencies on both the partition index and the parent
446 : * index, so that it will not be executed till both of those
447 : * exist. (There's no need to care what order those are created
448 : * in.)
449 : *
450 : * In addition, give it dependencies on the indexes' underlying
451 : * tables. This does nothing of great value so far as serial
452 : * restore ordering goes, but it ensures that a parallel restore
453 EUB : * will not try to run the ATTACH concurrently with other
454 : * operations on those tables.
455 ECB : */
456 GIC 567 : addObjectDependency(&attachinfo->dobj, index->dobj.dumpId);
457 CBC 567 : addObjectDependency(&attachinfo->dobj, parentidx->dobj.dumpId);
458 567 : addObjectDependency(&attachinfo->dobj,
459 567 : index->indextable->dobj.dumpId);
460 567 : addObjectDependency(&attachinfo->dobj,
461 567 : parentidx->indextable->dobj.dumpId);
462 ECB :
463 : /* keep track of the list of partitions in the parent index */
464 CBC 567 : simple_ptr_list_append(&parentidx->partattaches, &attachinfo->dobj);
465 : }
466 : }
467 GIC 118 : }
468 :
469 : /* flagInhAttrs -
470 : * for each dumpable table in tblinfo, flag its inherited attributes
471 : *
472 : * What we need to do here is:
473 : *
474 : * - Detect child columns that inherit NOT NULL bits from their parents, so
475 : * that we needn't specify that again for the child. (Versions >= 16 no
476 : * longer need this.)
477 : *
478 : * - Detect child columns that have DEFAULT NULL when their parents had some
479 : * non-null default. In this case, we make up a dummy AttrDefInfo object so
480 : * that we'll correctly emit the necessary DEFAULT NULL clause; otherwise
481 : * the backend will apply an inherited default to the column.
482 ECB : *
483 : * - Detect child columns that have a generation expression and all their
484 : * parents also have the same generation expression, and if so suppress the
485 : * child's expression. The child will inherit the generation expression
486 : * automatically, so there's no need to dump it. This improves the dump's
487 : * compatibility with pre-v16 servers, which didn't allow the child's
488 : * expression to be given explicitly. Exceptions: If it's a partition or
489 : * we are in binary upgrade mode, we dump such expressions anyway because
490 : * in those cases inherited tables are recreated standalone first and then
491 : * reattached to the parent. (See also the logic in dumpTableSchema().)
492 : *
493 : * modifies tblinfo
494 : */
495 : static void
496 GNC 118 : flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables)
497 : {
498 : int i,
499 : j,
500 : k;
501 :
502 : /*
503 : * We scan the tables in OID order, since that's how tblinfo[] is sorted.
504 : * Hence we will typically visit parents before their children --- but
505 : * that is *not* guaranteed. Thus this loop must be careful that it does
506 : * not alter table properties in a way that could change decisions made at
507 : * child tables during other iterations.
508 : */
509 GIC 30474 : for (i = 0; i < numTables; i++)
510 : {
511 30356 : TableInfo *tbinfo = &(tblinfo[i]);
512 : int numParents;
513 : TableInfo **parents;
514 :
515 : /* Some kinds never have parents */
516 30356 : if (tbinfo->relkind == RELKIND_SEQUENCE ||
517 29911 : tbinfo->relkind == RELKIND_VIEW ||
518 12993 : tbinfo->relkind == RELKIND_MATVIEW)
519 17763 : continue;
520 :
521 : /* Don't bother computing anything for non-target tables, either */
522 12593 : if (!tbinfo->dobj.dump)
523 1425 : continue;
524 :
525 11168 : numParents = tbinfo->numParents;
526 11168 : parents = tbinfo->parents;
527 :
528 11168 : if (numParents == 0)
529 9690 : continue; /* nothing to see here, move along */
530 ECB :
531 : /* For each column, search for matching column names in parent(s) */
532 GIC 5485 : for (j = 0; j < tbinfo->numatts; j++)
533 : {
534 : bool foundNotNull; /* Attr was NOT NULL in a parent */
535 : bool foundDefault; /* Found a default in a parent */
536 : bool foundSameGenerated; /* Found matching GENERATED */
537 : bool foundDiffGenerated; /* Found non-matching GENERATED */
538 :
539 : /* no point in examining dropped columns */
540 4007 : if (tbinfo->attisdropped[j])
541 305 : continue;
542 :
543 3702 : foundNotNull = false;
544 CBC 3702 : foundDefault = false;
545 GNC 3702 : foundSameGenerated = false;
546 3702 : foundDiffGenerated = false;
547 CBC 7524 : for (k = 0; k < numParents; k++)
548 : {
549 GIC 3822 : TableInfo *parent = parents[k];
550 : int inhAttrInd;
551 :
552 CBC 3822 : inhAttrInd = strInArray(tbinfo->attnames[j],
553 ECB : parent->attnames,
554 : parent->numatts);
555 CBC 3822 : if (inhAttrInd >= 0)
556 : {
557 GNC 3637 : AttrDefInfo *parentDef = parent->attrdefs[inhAttrInd];
558 :
559 GIC 3637 : foundNotNull |= parent->notnull[inhAttrInd];
560 GNC 7654 : foundDefault |= (parentDef != NULL &&
561 3967 : strcmp(parentDef->adef_expr, "NULL") != 0 &&
562 330 : !parent->attgenerated[inhAttrInd]);
563 3637 : if (parent->attgenerated[inhAttrInd])
564 : {
565 : /* these pointer nullness checks are just paranoia */
566 128 : if (parentDef != NULL &&
567 122 : tbinfo->attrdefs[j] != NULL &&
568 122 : strcmp(parentDef->adef_expr,
569 122 : tbinfo->attrdefs[j]->adef_expr) == 0)
570 97 : foundSameGenerated = true;
571 : else
572 31 : foundDiffGenerated = true;
573 : }
574 : }
575 ECB : }
576 :
577 : /* In versions < 16, remember if we found inherited NOT NULL */
578 GNC 3702 : if (fout->remoteVersion < 160000)
579 UNC 0 : tbinfo->localNotNull[j] = !foundNotNull;
580 ECB :
581 : /*
582 : * Manufacture a DEFAULT NULL clause if necessary. This breaks
583 : * the advice given above to avoid changing state that might get
584 : * inspected in other loop iterations. We prevent trouble by
585 : * having the foundDefault test above check whether adef_expr is
586 : * "NULL", so that it will reach the same conclusion before or
587 : * after this is done.
588 : */
589 GIC 3702 : if (foundDefault && tbinfo->attrdefs[j] == NULL)
590 ECB : {
591 : AttrDefInfo *attrDef;
592 :
593 GNC 40 : attrDef = pg_malloc_object(AttrDefInfo);
594 GIC 40 : attrDef->dobj.objType = DO_ATTRDEF;
595 40 : attrDef->dobj.catId.tableoid = 0;
596 40 : attrDef->dobj.catId.oid = 0;
597 40 : AssignDumpId(&attrDef->dobj);
598 CBC 40 : attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
599 40 : attrDef->dobj.namespace = tbinfo->dobj.namespace;
600 GIC 40 : attrDef->dobj.dump = tbinfo->dobj.dump;
601 ECB :
602 CBC 40 : attrDef->adtable = tbinfo;
603 40 : attrDef->adnum = j + 1;
604 40 : attrDef->adef_expr = pg_strdup("NULL");
605 ECB :
606 : /* Will column be dumped explicitly? */
607 CBC 40 : if (shouldPrintColumn(dopt, tbinfo, j))
608 : {
609 GIC 40 : attrDef->separate = false;
610 ECB : /* No dependency needed: NULL cannot have dependencies */
611 : }
612 : else
613 : {
614 : /* column will be suppressed, print default separately */
615 LBC 0 : attrDef->separate = true;
616 : /* ensure it comes out after the table */
617 0 : addObjectDependency(&attrDef->dobj,
618 ECB : tbinfo->dobj.dumpId);
619 : }
620 :
621 CBC 40 : tbinfo->attrdefs[j] = attrDef;
622 : }
623 :
624 : /* No need to dump generation expression if it's inheritable */
625 GNC 3702 : if (foundSameGenerated && !foundDiffGenerated &&
626 97 : !tbinfo->ispartition && !dopt->binary_upgrade)
627 86 : tbinfo->attrdefs[j]->dobj.dump = DUMP_COMPONENT_NONE;
628 ECB : }
629 : }
630 GIC 118 : }
631 ECB :
632 : /*
633 : * AssignDumpId
634 : * Given a newly-created dumpable object, assign a dump ID,
635 : * and enter the object into the lookup tables.
636 : *
637 : * The caller is expected to have filled in objType and catId,
638 EUB : * but not any of the other standard fields of a DumpableObject.
639 : */
640 : void
641 GIC 510276 : AssignDumpId(DumpableObject *dobj)
642 : {
643 510276 : dobj->dumpId = ++lastDumpId;
644 510276 : dobj->name = NULL; /* must be set later */
645 510276 : dobj->namespace = NULL; /* may be set later */
646 510276 : dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
647 510276 : dobj->dump_contains = DUMP_COMPONENT_ALL; /* default assumption */
648 ECB : /* All objects have definitions; we may set more components bits later */
649 GIC 510276 : dobj->components = DUMP_COMPONENT_DEFINITION;
650 510276 : dobj->ext_member = false; /* default assumption */
651 510276 : dobj->depends_on_ext = false; /* default assumption */
652 CBC 510276 : dobj->dependencies = NULL;
653 510276 : dobj->nDeps = 0;
654 510276 : dobj->allocDeps = 0;
655 ECB :
656 : /* Add object to dumpIdMap[], enlarging that array if need be */
657 CBC 510923 : while (dobj->dumpId >= allocedDumpIds)
658 ECB : {
659 : int newAlloc;
660 :
661 CBC 647 : if (allocedDumpIds <= 0)
662 ECB : {
663 CBC 119 : newAlloc = 256;
664 GNC 119 : dumpIdMap = pg_malloc_array(DumpableObject *, newAlloc);
665 ECB : }
666 : else
667 : {
668 GIC 528 : newAlloc = allocedDumpIds * 2;
669 GNC 528 : dumpIdMap = pg_realloc_array(dumpIdMap, DumpableObject *, newAlloc);
670 : }
671 GIC 647 : memset(dumpIdMap + allocedDumpIds, 0,
672 GBC 647 : (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
673 GIC 647 : allocedDumpIds = newAlloc;
674 EUB : }
675 GIC 510276 : dumpIdMap[dobj->dumpId] = dobj;
676 :
677 : /* If it has a valid CatalogId, enter it into the hash table */
678 CBC 510276 : if (OidIsValid(dobj->catId.tableoid))
679 : {
680 : CatalogIdMapEntry *entry;
681 : bool found;
682 ECB :
683 : /* Initialize CatalogId hash table if not done yet */
684 CBC 498767 : if (catalogIdHash == NULL)
685 GIC 119 : catalogIdHash = catalogid_create(CATALOGIDHASH_INITIAL_SIZE, NULL);
686 :
687 CBC 498767 : entry = catalogid_insert(catalogIdHash, dobj->catId, &found);
688 GIC 498767 : if (!found)
689 : {
690 498295 : entry->dobj = NULL;
691 498295 : entry->ext = NULL;
692 : }
693 498767 : Assert(entry->dobj == NULL);
694 498767 : entry->dobj = dobj;
695 : }
696 510276 : }
697 :
698 ECB : /*
699 : * Assign a DumpId that's not tied to a DumpableObject.
700 : *
701 : * This is used when creating a "fixed" ArchiveEntry that doesn't need to
702 : * participate in the sorting logic.
703 : */
704 : DumpId
705 GIC 3626 : createDumpId(void)
706 ECB : {
707 CBC 3626 : return ++lastDumpId;
708 ECB : }
709 :
710 : /*
711 : * Return the largest DumpId so far assigned
712 : */
713 : DumpId
714 CBC 898 : getMaxDumpId(void)
715 : {
716 GIC 898 : return lastDumpId;
717 : }
718 ECB :
719 : /*
720 : * Find a DumpableObject by dump ID
721 : *
722 : * Returns NULL for invalid ID
723 : */
724 : DumpableObject *
725 CBC 17510433 : findObjectByDumpId(DumpId dumpId)
726 ECB : {
727 GIC 17510433 : if (dumpId <= 0 || dumpId >= allocedDumpIds)
728 LBC 0 : return NULL; /* out of range? */
729 CBC 17510433 : return dumpIdMap[dumpId];
730 ECB : }
731 :
732 : /*
733 : * Find a DumpableObject by catalog ID
734 : *
735 : * Returns NULL for unknown ID
736 : */
737 : DumpableObject *
738 GIC 1545284 : findObjectByCatalogId(CatalogId catalogId)
739 : {
740 : CatalogIdMapEntry *entry;
741 ECB :
742 CBC 1545284 : if (catalogIdHash == NULL)
743 UIC 0 : return NULL; /* no objects exist yet */
744 ECB :
745 CBC 1545284 : entry = catalogid_lookup(catalogIdHash, catalogId);
746 GIC 1545284 : if (entry == NULL)
747 CBC 410718 : return NULL;
748 1134566 : return entry->dobj;
749 : }
750 ECB :
751 : /*
752 : * Build an array of pointers to all known dumpable objects
753 : *
754 : * This simply creates a modifiable copy of the internal map.
755 : */
756 : void
757 GIC 124 : getDumpableObjects(DumpableObject ***objs, int *numObjs)
758 : {
759 : int i,
760 : j;
761 :
762 GNC 124 : *objs = pg_malloc_array(DumpableObject *, allocedDumpIds);
763 CBC 124 : j = 0;
764 GIC 770048 : for (i = 1; i < allocedDumpIds; i++)
765 : {
766 769924 : if (dumpIdMap[i])
767 535191 : (*objs)[j++] = dumpIdMap[i];
768 : }
769 124 : *numObjs = j;
770 CBC 124 : }
771 :
772 ECB : /*
773 : * Add a dependency link to a DumpableObject
774 : *
775 : * Note: duplicate dependencies are currently not eliminated
776 : */
777 : void
778 GIC 762922 : addObjectDependency(DumpableObject *dobj, DumpId refId)
779 : {
780 762922 : if (dobj->nDeps >= dobj->allocDeps)
781 ECB : {
782 GIC 113381 : if (dobj->allocDeps <= 0)
783 ECB : {
784 GBC 110466 : dobj->allocDeps = 16;
785 GNC 110466 : dobj->dependencies = pg_malloc_array(DumpId, dobj->allocDeps);
786 : }
787 : else
788 : {
789 GIC 2915 : dobj->allocDeps *= 2;
790 GNC 2915 : dobj->dependencies = pg_realloc_array(dobj->dependencies,
791 : DumpId, dobj->allocDeps);
792 ECB : }
793 : }
794 GIC 762922 : dobj->dependencies[dobj->nDeps++] = refId;
795 762922 : }
796 ECB :
797 EUB : /*
798 : * Remove a dependency link from a DumpableObject
799 ECB : *
800 : * If there are multiple links, all are removed
801 : */
802 : void
803 GIC 19405 : removeObjectDependency(DumpableObject *dobj, DumpId refId)
804 : {
805 : int i;
806 19405 : int j = 0;
807 :
808 90523 : for (i = 0; i < dobj->nDeps; i++)
809 : {
810 71118 : if (dobj->dependencies[i] != refId)
811 CBC 50666 : dobj->dependencies[j++] = dobj->dependencies[i];
812 : }
813 GIC 19405 : dobj->nDeps = j;
814 19405 : }
815 :
816 ECB :
817 : /*
818 : * findTableByOid
819 : * finds the DumpableObject for the table with the given oid
820 : * returns NULL if not found
821 : */
822 : TableInfo *
823 CBC 52146 : findTableByOid(Oid oid)
824 ECB : {
825 : CatalogId catId;
826 : DumpableObject *dobj;
827 :
828 GIC 52146 : catId.tableoid = RelationRelationId;
829 52146 : catId.oid = oid;
830 52146 : dobj = findObjectByCatalogId(catId);
831 52146 : Assert(dobj == NULL || dobj->objType == DO_TABLE);
832 CBC 52146 : return (TableInfo *) dobj;
833 : }
834 ECB :
835 : /*
836 : * findIndexByOid
837 : * finds the DumpableObject for the index with the given oid
838 : * returns NULL if not found
839 : */
840 : static IndxInfo *
841 GIC 567 : findIndexByOid(Oid oid)
842 : {
843 ECB : CatalogId catId;
844 : DumpableObject *dobj;
845 :
846 GIC 567 : catId.tableoid = RelationRelationId;
847 567 : catId.oid = oid;
848 CBC 567 : dobj = findObjectByCatalogId(catId);
849 567 : Assert(dobj == NULL || dobj->objType == DO_INDEX);
850 GIC 567 : return (IndxInfo *) dobj;
851 : }
852 :
853 : /*
854 : * findTypeByOid
855 : * finds the DumpableObject for the type with the given oid
856 : * returns NULL if not found
857 ECB : */
858 : TypeInfo *
859 GIC 55269 : findTypeByOid(Oid oid)
860 ECB : {
861 : CatalogId catId;
862 : DumpableObject *dobj;
863 :
864 CBC 55269 : catId.tableoid = TypeRelationId;
865 55269 : catId.oid = oid;
866 GIC 55269 : dobj = findObjectByCatalogId(catId);
867 CBC 55269 : Assert(dobj == NULL ||
868 ECB : dobj->objType == DO_TYPE || dobj->objType == DO_DUMMY_TYPE);
869 GIC 55269 : return (TypeInfo *) dobj;
870 : }
871 :
872 : /*
873 : * findFuncByOid
874 : * finds the DumpableObject for the function with the given oid
875 : * returns NULL if not found
876 : */
877 ECB : FuncInfo *
878 GIC 278 : findFuncByOid(Oid oid)
879 : {
880 : CatalogId catId;
881 : DumpableObject *dobj;
882 ECB :
883 CBC 278 : catId.tableoid = ProcedureRelationId;
884 278 : catId.oid = oid;
885 278 : dobj = findObjectByCatalogId(catId);
886 278 : Assert(dobj == NULL || dobj->objType == DO_FUNC);
887 GIC 278 : return (FuncInfo *) dobj;
888 : }
889 :
890 : /*
891 : * findOprByOid
892 : * finds the DumpableObject for the operator with the given oid
893 : * returns NULL if not found
894 : */
895 ECB : OprInfo *
896 GIC 25 : findOprByOid(Oid oid)
897 : {
898 : CatalogId catId;
899 : DumpableObject *dobj;
900 ECB :
901 CBC 25 : catId.tableoid = OperatorRelationId;
902 25 : catId.oid = oid;
903 25 : dobj = findObjectByCatalogId(catId);
904 25 : Assert(dobj == NULL || dobj->objType == DO_OPERATOR);
905 GIC 25 : return (OprInfo *) dobj;
906 : }
907 :
908 : /*
909 : * findCollationByOid
910 : * finds the DumpableObject for the collation with the given oid
911 : * returns NULL if not found
912 : */
913 ECB : CollInfo *
914 GIC 82 : findCollationByOid(Oid oid)
915 : {
916 : CatalogId catId;
917 : DumpableObject *dobj;
918 ECB :
919 CBC 82 : catId.tableoid = CollationRelationId;
920 82 : catId.oid = oid;
921 82 : dobj = findObjectByCatalogId(catId);
922 GIC 82 : Assert(dobj == NULL || dobj->objType == DO_COLLATION);
923 CBC 82 : return (CollInfo *) dobj;
924 : }
925 :
926 : /*
927 : * findNamespaceByOid
928 : * finds the DumpableObject for the namespace with the given oid
929 : * returns NULL if not found
930 : */
931 : NamespaceInfo *
932 446460 : findNamespaceByOid(Oid oid)
933 : {
934 : CatalogId catId;
935 : DumpableObject *dobj;
936 :
937 446460 : catId.tableoid = NamespaceRelationId;
938 446460 : catId.oid = oid;
939 446460 : dobj = findObjectByCatalogId(catId);
940 446460 : Assert(dobj == NULL || dobj->objType == DO_NAMESPACE);
941 446460 : return (NamespaceInfo *) dobj;
942 : }
943 :
944 : /*
945 : * findExtensionByOid
946 : * finds the DumpableObject for the extension with the given oid
947 : * returns NULL if not found
948 : */
949 : ExtensionInfo *
950 141 : findExtensionByOid(Oid oid)
951 : {
952 : CatalogId catId;
953 : DumpableObject *dobj;
954 :
955 141 : catId.tableoid = ExtensionRelationId;
956 141 : catId.oid = oid;
957 141 : dobj = findObjectByCatalogId(catId);
958 141 : Assert(dobj == NULL || dobj->objType == DO_EXTENSION);
959 141 : return (ExtensionInfo *) dobj;
960 : }
961 :
962 : /*
963 : * findPublicationByOid
964 : * finds the DumpableObject for the publication with the given oid
965 : * returns NULL if not found
966 : */
967 : PublicationInfo *
968 405 : findPublicationByOid(Oid oid)
969 : {
970 : CatalogId catId;
971 : DumpableObject *dobj;
972 :
973 405 : catId.tableoid = PublicationRelationId;
974 405 : catId.oid = oid;
975 405 : dobj = findObjectByCatalogId(catId);
976 405 : Assert(dobj == NULL || dobj->objType == DO_PUBLICATION);
977 405 : return (PublicationInfo *) dobj;
978 : }
979 :
980 :
981 : /*
982 : * recordExtensionMembership
983 : * Record that the object identified by the given catalog ID
984 : * belongs to the given extension
985 : */
986 ECB : void
987 GIC 806 : recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
988 : {
989 : CatalogIdMapEntry *entry;
990 : bool found;
991 ECB :
992 : /* CatalogId hash table must exist, if we have an ExtensionInfo */
993 CBC 806 : Assert(catalogIdHash != NULL);
994 ECB :
995 : /* Add reference to CatalogId hash */
996 GIC 806 : entry = catalogid_insert(catalogIdHash, catId, &found);
997 806 : if (!found)
998 : {
999 806 : entry->dobj = NULL;
1000 806 : entry->ext = NULL;
1001 : }
1002 806 : Assert(entry->ext == NULL);
1003 806 : entry->ext = ext;
1004 CBC 806 : }
1005 :
1006 : /*
1007 : * findOwningExtension
1008 : * return owning extension for specified catalog ID, or NULL if none
1009 ECB : */
1010 : ExtensionInfo *
1011 CBC 445511 : findOwningExtension(CatalogId catalogId)
1012 ECB : {
1013 : CatalogIdMapEntry *entry;
1014 :
1015 GIC 445511 : if (catalogIdHash == NULL)
1016 UIC 0 : return NULL; /* no objects exist yet */
1017 :
1018 GIC 445511 : entry = catalogid_lookup(catalogIdHash, catalogId);
1019 445511 : if (entry == NULL)
1020 UIC 0 : return NULL;
1021 GIC 445511 : return entry->ext;
1022 ECB : }
1023 :
1024 :
1025 : /*
1026 : * parseOidArray
1027 EUB : * parse a string of numbers delimited by spaces into a character array
1028 ECB : *
1029 : * Note: actually this is used for both Oids and potentially-signed
1030 : * attribute numbers. This should cause no trouble, but we could split
1031 : * the function into two functions with different argument types if it does.
1032 : */
1033 :
1034 : void
1035 GIC 4619 : parseOidArray(const char *str, Oid *array, int arraysize)
1036 : {
1037 : int j,
1038 : argNum;
1039 : char temp[100];
1040 : char s;
1041 :
1042 CBC 4619 : argNum = 0;
1043 GIC 4619 : j = 0;
1044 : for (;;)
1045 : {
1046 21735 : s = *str++;
1047 21735 : if (s == ' ' || s == '\0')
1048 : {
1049 CBC 7366 : if (j > 0)
1050 ECB : {
1051 GIC 7366 : if (argNum >= arraysize)
1052 UIC 0 : pg_fatal("could not parse numeric array \"%s\": too many numbers", str);
1053 CBC 7366 : temp[j] = '\0';
1054 7366 : array[argNum++] = atooid(temp);
1055 GIC 7366 : j = 0;
1056 ECB : }
1057 GIC 7366 : if (s == '\0')
1058 CBC 4619 : break;
1059 EUB : }
1060 ECB : else
1061 : {
1062 CBC 14369 : if (!(isdigit((unsigned char) s) || s == '-') ||
1063 GIC 14369 : j >= sizeof(temp) - 1)
1064 LBC 0 : pg_fatal("could not parse numeric array \"%s\": invalid character in number", str);
1065 CBC 14369 : temp[j++] = s;
1066 : }
1067 : }
1068 :
1069 4619 : while (argNum < arraysize)
1070 LBC 0 : array[argNum++] = InvalidOid;
1071 GBC 4619 : }
1072 ECB :
1073 :
1074 : /*
1075 : * strInArray:
1076 : * takes in a string and a string array and the number of elements in the
1077 EUB : * string array.
1078 ECB : * returns the index if the string is somewhere in the array, -1 otherwise
1079 : */
1080 :
1081 : static int
1082 GIC 3822 : strInArray(const char *pattern, char **arr, int arr_size)
1083 : {
1084 : int i;
1085 :
1086 7771 : for (i = 0; i < arr_size; i++)
1087 : {
1088 7586 : if (strcmp(pattern, arr[i]) == 0)
1089 CBC 3637 : return i;
1090 : }
1091 GIC 185 : return -1;
1092 : }
|