PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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 */
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
83
84static void flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
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 */
99{
100 TableInfo *tblinfo;
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");
114
115 pg_log_info("identifying extension members");
117
118 pg_log_info("reading schemas");
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");
142
143 pg_log_info("reading user-defined aggregate functions");
145
146 pg_log_info("reading user-defined operators");
148
149 pg_log_info("reading user-defined access methods");
151
152 pg_log_info("reading user-defined operator classes");
154
155 pg_log_info("reading user-defined operator families");
157
158 pg_log_info("reading user-defined text search parsers");
160
161 pg_log_info("reading user-defined text search templates");
163
164 pg_log_info("reading user-defined text search dictionaries");
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");
175
176 pg_log_info("reading default privileges");
178
179 pg_log_info("reading user-defined collations");
181
182 pg_log_info("reading user-defined conversions");
184
185 pg_log_info("reading type casts");
186 getCasts(fout);
187
188 pg_log_info("reading transforms");
190
191 pg_log_info("reading table inheritance information");
193
194 pg_log_info("reading event triggers");
196
197 /* Identify extension configuration tables that should be dumped */
198 pg_log_info("finding extension tables");
200
201 /* Link tables to parents, mark parents of target tables interesting */
202 pg_log_info("finding inheritance relationships");
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");
237
238 pg_log_info("reading publication membership of tables");
240
241 pg_log_info("reading publication membership of schemas");
243
244 pg_log_info("reading subscriptions");
246
247 pg_log_info("reading subscription membership of relations");
249
250 free(inhinfo); /* not needed any longer */
251
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
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 {
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
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
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;
404
405 if (index->parentidx == 0)
406 continue;
407
408 parentidx = findIndexByOid(index->parentidx);
409 if (parentidx == NULL)
410 continue;
411
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);
441 index->indextable->dobj.dumpId);
443 parentidx->indextable->dobj.dumpId);
444
445 /* keep track of the list of partitions in the parent index */
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
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 tbinfo->relkind == RELKIND_PROPGRAPH)
502 continue;
503
504 /* Don't bother computing anything for non-target tables, either */
505 if (!tbinfo->dobj.dump)
506 continue;
507
508 numParents = tbinfo->numParents;
509 parents = tbinfo->parents;
510
511 if (numParents == 0)
512 continue; /* nothing to see here, move along */
513
514 /* For each column, search for matching column names in parent(s) */
515 for (j = 0; j < tbinfo->numatts; j++)
516 {
517 bool foundNotNull; /* Attr was NOT NULL in a parent */
518 bool foundDefault; /* Found a default in a parent */
519 bool foundSameGenerated; /* Found matching GENERATED */
520 bool foundDiffGenerated; /* Found non-matching GENERATED */
521 bool allNotNullsInvalid = true; /* is NOT NULL NOT VALID
522 * on all parents? */
523
524 /* no point in examining dropped columns */
525 if (tbinfo->attisdropped[j])
526 continue;
527
528 foundNotNull = false;
529 foundDefault = false;
530 foundSameGenerated = false;
531 foundDiffGenerated = false;
532 for (k = 0; k < numParents; k++)
533 {
534 TableInfo *parent = parents[k];
535 int inhAttrInd;
536
537 inhAttrInd = strInArray(tbinfo->attnames[j],
538 parent->attnames,
539 parent->numatts);
540 if (inhAttrInd >= 0)
541 {
543
544 /*
545 * Account for each parent having a not-null constraint.
546 * In versions 18 and later, we don't need this (and those
547 * didn't have NO INHERIT.)
548 */
549 if (fout->remoteVersion < 180000 &&
550 parent->notnull_constrs[inhAttrInd] != NULL)
551 foundNotNull = true;
552
553 /*
554 * Keep track of whether all the parents that have a
555 * not-null constraint on this column have it as NOT
556 * VALID; if they all are, arrange to have it printed for
557 * this column. If at least one parent has it as valid,
558 * there's no need.
559 */
560 if (fout->remoteVersion >= 180000 &&
561 parent->notnull_constrs[inhAttrInd] &&
562 !parent->notnull_invalid[inhAttrInd])
563 allNotNullsInvalid = false;
564
565 foundDefault |= (parentDef != NULL &&
566 strcmp(parentDef->adef_expr, "NULL") != 0 &&
567 !parent->attgenerated[inhAttrInd]);
568 if (parent->attgenerated[inhAttrInd])
569 {
570 /* these pointer nullness checks are just paranoia */
571 if (parentDef != NULL &&
572 tbinfo->attrdefs[j] != NULL &&
573 strcmp(parentDef->adef_expr,
574 tbinfo->attrdefs[j]->adef_expr) == 0)
575 foundSameGenerated = true;
576 else
577 foundDiffGenerated = true;
578 }
579 }
580 }
581
582 /*
583 * In versions < 18, for lack of a better system, we arbitrarily
584 * decide that a not-null constraint is not locally defined if at
585 * least one of the parents has it.
586 */
587 if (fout->remoteVersion < 180000 && foundNotNull)
588 tbinfo->notnull_islocal[j] = false;
589
590 /*
591 * For versions >18, we must print the not-null constraint locally
592 * for this table even if it isn't really locally defined, but is
593 * valid for the child and no parent has it as valid.
594 */
595 if (fout->remoteVersion >= 180000 && allNotNullsInvalid)
596 tbinfo->notnull_islocal[j] = true;
597
598 /*
599 * Manufacture a DEFAULT NULL clause if necessary. This breaks
600 * the advice given above to avoid changing state that might get
601 * inspected in other loop iterations. We prevent trouble by
602 * having the foundDefault test above check whether adef_expr is
603 * "NULL", so that it will reach the same conclusion before or
604 * after this is done.
605 */
606 if (foundDefault && tbinfo->attrdefs[j] == NULL)
607 {
609
611 attrDef->dobj.objType = DO_ATTRDEF;
612 attrDef->dobj.catId.tableoid = 0;
613 attrDef->dobj.catId.oid = 0;
614 AssignDumpId(&attrDef->dobj);
615 attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
616 attrDef->dobj.namespace = tbinfo->dobj.namespace;
617 attrDef->dobj.dump = tbinfo->dobj.dump;
618
619 attrDef->adtable = tbinfo;
620 attrDef->adnum = j + 1;
621 attrDef->adef_expr = pg_strdup("NULL");
622
623 /* Will column be dumped explicitly? */
624 if (shouldPrintColumn(dopt, tbinfo, j))
625 {
626 attrDef->separate = false;
627 /* No dependency needed: NULL cannot have dependencies */
628 }
629 else
630 {
631 /* column will be suppressed, print default separately */
632 attrDef->separate = true;
633 /* ensure it comes out after the table */
635 tbinfo->dobj.dumpId);
636 }
637
638 tbinfo->attrdefs[j] = attrDef;
639 }
640
641 /* No need to dump generation expression if it's inheritable */
643 !tbinfo->ispartition && !dopt->binary_upgrade)
644 tbinfo->attrdefs[j]->dobj.dump = DUMP_COMPONENT_NONE;
645 }
646 }
647}
648
649/*
650 * AssignDumpId
651 * Given a newly-created dumpable object, assign a dump ID,
652 * and enter the object into the lookup tables.
653 *
654 * The caller is expected to have filled in objType and catId,
655 * but not any of the other standard fields of a DumpableObject.
656 */
657void
659{
660 dobj->dumpId = ++lastDumpId;
661 dobj->name = NULL; /* must be set later */
662 dobj->namespace = NULL; /* may be set later */
663 dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
664 dobj->dump_contains = DUMP_COMPONENT_ALL; /* default assumption */
665 /* All objects have definitions; we may set more components bits later */
667 dobj->ext_member = false; /* default assumption */
668 dobj->depends_on_ext = false; /* default assumption */
669 dobj->dependencies = NULL;
670 dobj->nDeps = 0;
671 dobj->allocDeps = 0;
672
673 /* Add object to dumpIdMap[], enlarging that array if need be */
674 while (dobj->dumpId >= allocedDumpIds)
675 {
676 int newAlloc;
677
678 if (allocedDumpIds <= 0)
679 {
680 newAlloc = 256;
682 }
683 else
684 {
687 }
689 (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
691 }
692 dumpIdMap[dobj->dumpId] = dobj;
693
694 /* If it has a valid CatalogId, enter it into the hash table */
695 if (OidIsValid(dobj->catId.tableoid))
696 {
697 CatalogIdMapEntry *entry;
698 bool found;
699
700 /* Initialize CatalogId hash table if not done yet */
701 if (catalogIdHash == NULL)
703
704 entry = catalogid_insert(catalogIdHash, dobj->catId, &found);
705 if (!found)
706 {
707 entry->dobj = NULL;
708 entry->ext = NULL;
709 }
710 Assert(entry->dobj == NULL);
711 entry->dobj = dobj;
712 }
713}
714
715/*
716 * recordAdditionalCatalogID
717 * Record an additional catalog ID for the given DumpableObject
718 */
719void
721{
722 CatalogIdMapEntry *entry;
723 bool found;
724
725 /* CatalogId hash table must exist, if we have a DumpableObject */
727
728 /* Add reference to CatalogId hash */
729 entry = catalogid_insert(catalogIdHash, catId, &found);
730 if (!found)
731 {
732 entry->dobj = NULL;
733 entry->ext = NULL;
734 }
735 Assert(entry->dobj == NULL);
736 entry->dobj = dobj;
737}
738
739/*
740 * Assign a DumpId that's not tied to a DumpableObject.
741 *
742 * This is used when creating a "fixed" ArchiveEntry that doesn't need to
743 * participate in the sorting logic.
744 */
745DumpId
747{
748 return ++lastDumpId;
749}
750
751/*
752 * Return the largest DumpId so far assigned
753 */
754DumpId
756{
757 return lastDumpId;
758}
759
760/*
761 * Find a DumpableObject by dump ID
762 *
763 * Returns NULL for invalid ID
764 */
767{
769 return NULL; /* out of range? */
770 return dumpIdMap[dumpId];
771}
772
773/*
774 * Find a DumpableObject by catalog ID
775 *
776 * Returns NULL for unknown ID
777 */
780{
781 CatalogIdMapEntry *entry;
782
783 if (catalogIdHash == NULL)
784 return NULL; /* no objects exist yet */
785
786 entry = catalogid_lookup(catalogIdHash, catalogId);
787 if (entry == NULL)
788 return NULL;
789 return entry->dobj;
790}
791
792/*
793 * Build an array of pointers to all known dumpable objects
794 *
795 * This simply creates a modifiable copy of the internal map.
796 */
797void
799{
800 int i,
801 j;
802
804 j = 0;
805 for (i = 1; i < allocedDumpIds; i++)
806 {
807 if (dumpIdMap[i])
808 (*objs)[j++] = dumpIdMap[i];
809 }
810 *numObjs = j;
811}
812
813/*
814 * Add a dependency link to a DumpableObject
815 *
816 * Note: duplicate dependencies are currently not eliminated
817 */
818void
820{
821 if (dobj->nDeps >= dobj->allocDeps)
822 {
823 if (dobj->allocDeps <= 0)
824 {
825 dobj->allocDeps = 16;
827 }
828 else
829 {
830 dobj->allocDeps *= 2;
832 DumpId, dobj->allocDeps);
833 }
834 }
835 dobj->dependencies[dobj->nDeps++] = refId;
836}
837
838/*
839 * Remove a dependency link from a DumpableObject
840 *
841 * If there are multiple links, all are removed
842 */
843void
845{
846 int i;
847 int j = 0;
848
849 for (i = 0; i < dobj->nDeps; i++)
850 {
851 if (dobj->dependencies[i] != refId)
852 dobj->dependencies[j++] = dobj->dependencies[i];
853 }
854 dobj->nDeps = j;
855}
856
857
858/*
859 * findTableByOid
860 * finds the DumpableObject for the table with the given oid
861 * returns NULL if not found
862 */
863TableInfo *
865{
866 CatalogId catId;
867 DumpableObject *dobj;
868
870 catId.oid = oid;
871 dobj = findObjectByCatalogId(catId);
872 Assert(dobj == NULL || dobj->objType == DO_TABLE);
873 return (TableInfo *) dobj;
874}
875
876/*
877 * findIndexByOid
878 * finds the DumpableObject for the index with the given oid
879 * returns NULL if not found
880 */
881static IndxInfo *
883{
884 CatalogId catId;
885 DumpableObject *dobj;
886
888 catId.oid = oid;
889 dobj = findObjectByCatalogId(catId);
890 Assert(dobj == NULL || dobj->objType == DO_INDEX);
891 return (IndxInfo *) dobj;
892}
893
894/*
895 * findTypeByOid
896 * finds the DumpableObject for the type with the given oid
897 * returns NULL if not found
898 */
899TypeInfo *
901{
902 CatalogId catId;
903 DumpableObject *dobj;
904
905 catId.tableoid = TypeRelationId;
906 catId.oid = oid;
907 dobj = findObjectByCatalogId(catId);
908 Assert(dobj == NULL ||
909 dobj->objType == DO_TYPE || dobj->objType == DO_DUMMY_TYPE);
910 return (TypeInfo *) dobj;
911}
912
913/*
914 * findFuncByOid
915 * finds the DumpableObject for the function with the given oid
916 * returns NULL if not found
917 */
918FuncInfo *
920{
921 CatalogId catId;
922 DumpableObject *dobj;
923
925 catId.oid = oid;
926 dobj = findObjectByCatalogId(catId);
927 Assert(dobj == NULL || dobj->objType == DO_FUNC);
928 return (FuncInfo *) dobj;
929}
930
931/*
932 * findOprByOid
933 * finds the DumpableObject for the operator with the given oid
934 * returns NULL if not found
935 */
936OprInfo *
938{
939 CatalogId catId;
940 DumpableObject *dobj;
941
943 catId.oid = oid;
944 dobj = findObjectByCatalogId(catId);
945 Assert(dobj == NULL || dobj->objType == DO_OPERATOR);
946 return (OprInfo *) dobj;
947}
948
949/*
950 * findAccessMethodByOid
951 * finds the DumpableObject for the access method with the given oid
952 * returns NULL if not found
953 */
956{
957 CatalogId catId;
958 DumpableObject *dobj;
959
961 catId.oid = oid;
962 dobj = findObjectByCatalogId(catId);
963 Assert(dobj == NULL || dobj->objType == DO_ACCESS_METHOD);
964 return (AccessMethodInfo *) dobj;
965}
966
967/*
968 * findCollationByOid
969 * finds the DumpableObject for the collation with the given oid
970 * returns NULL if not found
971 */
972CollInfo *
974{
975 CatalogId catId;
976 DumpableObject *dobj;
977
979 catId.oid = oid;
980 dobj = findObjectByCatalogId(catId);
981 Assert(dobj == NULL || dobj->objType == DO_COLLATION);
982 return (CollInfo *) dobj;
983}
984
985/*
986 * findNamespaceByOid
987 * finds the DumpableObject for the namespace with the given oid
988 * returns NULL if not found
989 */
992{
993 CatalogId catId;
994 DumpableObject *dobj;
995
997 catId.oid = oid;
998 dobj = findObjectByCatalogId(catId);
999 Assert(dobj == NULL || dobj->objType == DO_NAMESPACE);
1000 return (NamespaceInfo *) dobj;
1001}
1002
1003/*
1004 * findExtensionByOid
1005 * finds the DumpableObject for the extension with the given oid
1006 * returns NULL if not found
1007 */
1010{
1011 CatalogId catId;
1012 DumpableObject *dobj;
1013
1015 catId.oid = oid;
1016 dobj = findObjectByCatalogId(catId);
1017 Assert(dobj == NULL || dobj->objType == DO_EXTENSION);
1018 return (ExtensionInfo *) dobj;
1019}
1020
1021/*
1022 * findPublicationByOid
1023 * finds the DumpableObject for the publication with the given oid
1024 * returns NULL if not found
1025 */
1028{
1029 CatalogId catId;
1030 DumpableObject *dobj;
1031
1033 catId.oid = oid;
1034 dobj = findObjectByCatalogId(catId);
1035 Assert(dobj == NULL || dobj->objType == DO_PUBLICATION);
1036 return (PublicationInfo *) dobj;
1037}
1038
1039/*
1040 * findSubscriptionByOid
1041 * finds the DumpableObject for the subscription with the given oid
1042 * returns NULL if not found
1043 */
1046{
1047 CatalogId catId;
1048 DumpableObject *dobj;
1049
1051 catId.oid = oid;
1052 dobj = findObjectByCatalogId(catId);
1053 Assert(dobj == NULL || dobj->objType == DO_SUBSCRIPTION);
1054 return (SubscriptionInfo *) dobj;
1055}
1056
1057
1058/*
1059 * recordExtensionMembership
1060 * Record that the object identified by the given catalog ID
1061 * belongs to the given extension
1062 */
1063void
1065{
1066 CatalogIdMapEntry *entry;
1067 bool found;
1068
1069 /* CatalogId hash table must exist, if we have an ExtensionInfo */
1071
1072 /* Add reference to CatalogId hash */
1073 entry = catalogid_insert(catalogIdHash, catId, &found);
1074 if (!found)
1075 {
1076 entry->dobj = NULL;
1077 entry->ext = NULL;
1078 }
1079 Assert(entry->ext == NULL);
1080 entry->ext = ext;
1081}
1082
1083/*
1084 * findOwningExtension
1085 * return owning extension for specified catalog ID, or NULL if none
1086 */
1089{
1090 CatalogIdMapEntry *entry;
1091
1092 if (catalogIdHash == NULL)
1093 return NULL; /* no objects exist yet */
1094
1095 entry = catalogid_lookup(catalogIdHash, catalogId);
1096 if (entry == NULL)
1097 return NULL;
1098 return entry->ext;
1099}
1100
1101
1102/*
1103 * parseOidArray
1104 * parse a string of numbers delimited by spaces into a character array
1105 *
1106 * Note: actually this is used for both Oids and potentially-signed
1107 * attribute numbers. This should cause no trouble, but we could split
1108 * the function into two functions with different argument types if it does.
1109 */
1110
1111void
1112parseOidArray(const char *str, Oid *array, int arraysize)
1113{
1114 int j,
1115 argNum;
1116 char temp[100];
1117 char s;
1118
1119 argNum = 0;
1120 j = 0;
1121 for (;;)
1122 {
1123 s = *str++;
1124 if (s == ' ' || s == '\0')
1125 {
1126 if (j > 0)
1127 {
1128 if (argNum >= arraysize)
1129 pg_fatal("could not parse numeric array \"%s\": too many numbers", str);
1130 temp[j] = '\0';
1131 array[argNum++] = atooid(temp);
1132 j = 0;
1133 }
1134 if (s == '\0')
1135 break;
1136 }
1137 else
1138 {
1139 if (!(isdigit((unsigned char) s) || s == '-') ||
1140 j >= sizeof(temp) - 1)
1141 pg_fatal("could not parse numeric array \"%s\": invalid character in number", str);
1142 temp[j++] = s;
1143 }
1144 }
1145
1146 while (argNum < arraysize)
1147 array[argNum++] = InvalidOid;
1148}
1149
1150
1151/*
1152 * strInArray:
1153 * takes in a string and a string array and the number of elements in the
1154 * string array.
1155 * returns the index if the string is somewhere in the array, -1 otherwise
1156 */
1157
1158static int
1159strInArray(const char *pattern, char **arr, int arr_size)
1160{
1161 int i;
1162
1163 for (i = 0; i < arr_size; i++)
1164 {
1165 if (strcmp(pattern, arr[i]) == 0)
1166 return i;
1167 }
1168 return -1;
1169}
void recordAdditionalCatalogID(CatalogId catId, DumpableObject *dobj)
Definition common.c:720
void recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
Definition common.c:1064
static void flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables)
Definition common.c:478
FuncInfo * findFuncByOid(Oid oid)
Definition common.c:919
TableInfo * findTableByOid(Oid oid)
Definition common.c:864
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:1009
CollInfo * findCollationByOid(Oid oid)
Definition common.c:973
SubscriptionInfo * findSubscriptionByOid(Oid oid)
Definition common.c:1045
OprInfo * findOprByOid(Oid oid)
Definition common.c:937
NamespaceInfo * findNamespaceByOid(Oid oid)
Definition common.c:991
DumpId createDumpId(void)
Definition common.c:746
AccessMethodInfo * findAccessMethodByOid(Oid oid)
Definition common.c:955
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition common.c:819
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition common.c:766
static int allocedDumpIds
Definition common.c:38
void parseOidArray(const char *str, Oid *array, int arraysize)
Definition common.c:1112
ExtensionInfo * findOwningExtension(CatalogId catalogId)
Definition common.c:1088
TableInfo * getSchemaData(Archive *fout, int *numTablesPtr)
Definition common.c:98
TypeInfo * findTypeByOid(Oid oid)
Definition common.c:900
static IndxInfo * findIndexByOid(Oid oid)
Definition common.c:882
DumpableObject * findObjectByCatalogId(CatalogId catalogId)
Definition common.c:779
void AssignDumpId(DumpableObject *dobj)
Definition common.c:658
DumpId getMaxDumpId(void)
Definition common.c:755
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:1159
void getDumpableObjects(DumpableObject ***objs, int *numObjs)
Definition common.c:798
static catalogid_hash * catalogIdHash
Definition common.c:82
PublicationInfo * findPublicationByOid(Oid oid)
Definition common.c:1027
struct _catalogIdMapEntry CatalogIdMapEntry
void removeObjectDependency(DumpableObject *dobj, DumpId refId)
Definition common.c:844
static DumpId lastDumpId
Definition common.c:39
#define Assert(condition)
Definition c.h:945
uint32_t uint32
Definition c.h:618
#define OidIsValid(objectId)
Definition c.h:860
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 palloc_object(type)
Definition fe_memutils.h:74
#define pg_malloc_object(type)
Definition fe_memutils.h:50
const char * str
int j
Definition isn.c:78
int i
Definition isn.c:77
#define pg_log_info(...)
Definition logging.h:124
int DumpId
Definition pg_backup.h:285
#define pg_fatal(...)
void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:8389
ExtensionInfo * getExtensions(Archive *fout, int *numExtensions)
Definition pg_dump.c:6216
void getPublicationNamespaces(Archive *fout)
Definition pg_dump.c:4804
void getPartitioningInfo(Archive *fout)
Definition pg_dump.c:7878
InhInfo * getInherits(Archive *fout, int *numInherits)
Definition pg_dump.c:7822
void getForeignDataWrappers(Archive *fout)
Definition pg_dump.c:10520
void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:4226
void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition pg_dump.c:20196
void getTypes(Archive *fout)
Definition pg_dump.c:6291
void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:7757
void getOpclasses(Archive *fout)
Definition pg_dump.c:6737
void getForeignServers(Archive *fout)
Definition pg_dump.c:10614
void getFuncs(Archive *fout)
Definition pg_dump.c:7006
void getTSDictionaries(Archive *fout)
Definition pg_dump.c:10336
void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:4884
void getCasts(Archive *fout)
Definition pg_dump.c:9138
void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:7938
void getTSConfigurations(Archive *fout)
Definition pg_dump.c:10461
void getAccessMethods(Archive *fout)
Definition pg_dump.c:6663
void getConversions(Archive *fout)
Definition pg_dump.c:6601
void getRules(Archive *fout)
Definition pg_dump.c:8683
void getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition pg_dump.c:9332
void getCollations(Archive *fout)
Definition pg_dump.c:6535
void getAggregates(Archive *fout)
Definition pg_dump.c:6865
void getNamespaces(Archive *fout)
Definition pg_dump.c:6084
void getPublications(Archive *fout)
Definition pg_dump.c:4516
void getTSParsers(Archive *fout)
Definition pg_dump.c:10262
TableInfo * getTables(Archive *fout, int *numTables)
Definition pg_dump.c:7279
void getExtendedStatistics(Archive *fout)
Definition pg_dump.c:8307
void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition pg_dump.c:20289
void getDefaultACLs(Archive *fout)
Definition pg_dump.c:10702
void getSubscriptions(Archive *fout)
Definition pg_dump.c:5159
void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
Definition pg_dump.c:8780
void getTransforms(Archive *fout)
Definition pg_dump.c:9248
void getEventTriggers(Archive *fout)
Definition pg_dump.c:8976
void getTSTemplates(Archive *fout)
Definition pg_dump.c:10402
void getProcLangs(Archive *fout)
Definition pg_dump.c:9054
bool shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
Definition pg_dump.c:10247
void getSubscriptionRelations(Archive *fout)
Definition pg_dump.c:5409
void getOperators(Archive *fout)
Definition pg_dump.c:6459
void getOpfamilies(Archive *fout)
Definition pg_dump.c:6800
#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
static Archive * fout
Definition pg_dumpall.c:139
#define InvalidOid
unsigned int Oid
#define atooid(x)
static int fb(int x)
void simple_ptr_list_append(SimplePtrList *list, void *ptr)
#define free(a)
int remoteVersion
Definition pg_backup.h:234
DumpOptions * dopt
Definition pg_backup.h:229
Oid tableoid
Definition pg_backup.h:281
CatalogId catId
Definition common.c:59
ExtensionInfo * ext
Definition common.c:63
DumpableObject * dobj
Definition common.c:62
int binary_upgrade
Definition pg_backup.h:175
DumpComponents dump
Definition pg_dump.h:153
DumpId * dependencies
Definition pg_dump.h:159
DumpId dumpId
Definition pg_dump.h:151
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
TableInfo * indextable
Definition pg_dump.h:421
SimplePtrList partattaches
Definition pg_dump.h:435
DumpableObject dobj
Definition pg_dump.h:420
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
int numatts
Definition pg_dump.h:354
struct _attrDefInfo ** attrdefs
Definition pg_dump.h:379
char ** attnames
Definition pg_dump.h:355
int numIndexes
Definition pg_dump.h:388
Definition type.h:96