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