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