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-2024, 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 "fe_utils/string_utils.h"
31 #include "pg_backup_archiver.h"
32 #include "pg_backup_utils.h"
33 #include "pg_dump.h"
34 
35 /*
36  * Variables for mapping DumpId to DumpableObject
37  */
38 static DumpableObject **dumpIdMap = NULL;
39 static int allocedDumpIds = 0;
40 static DumpId lastDumpId = 0; /* Note: 0 is InvalidDumpId */
41 
42 /*
43  * Infrastructure for mapping CatalogId to DumpableObject
44  *
45  * We use a hash table generated by simplehash.h. That infrastructure
46  * requires all the hash table entries to be the same size, and it also
47  * expects that it can move them around when resizing the table. So we
48  * cannot make the DumpableObjects be elements of the hash table directly;
49  * instead, the hash table elements contain pointers to DumpableObjects.
50  * This does have the advantage of letting us map multiple CatalogIds
51  * to one DumpableObject, which is useful for blobs.
52  *
53  * It turns out to be convenient to also use this data structure to map
54  * CatalogIds to owning extensions, if any. Since extension membership
55  * data is read before creating most DumpableObjects, either one of dobj
56  * and ext could be NULL.
57  */
58 typedef struct _catalogIdMapEntry
59 {
60  CatalogId catId; /* the indexed CatalogId */
61  uint32 status; /* hash status */
62  uint32 hashval; /* hash code for the CatalogId */
63  DumpableObject *dobj; /* the associated DumpableObject, if any */
64  ExtensionInfo *ext; /* owning extension, if any */
66 
67 #define SH_PREFIX catalogid
68 #define SH_ELEMENT_TYPE CatalogIdMapEntry
69 #define SH_KEY_TYPE CatalogId
70 #define SH_KEY catId
71 #define SH_HASH_KEY(tb, key) hash_bytes((const unsigned char *) &(key), sizeof(CatalogId))
72 #define SH_EQUAL(tb, a, b) ((a).oid == (b).oid && (a).tableoid == (b).tableoid)
73 #define SH_STORE_HASH
74 #define SH_GET_HASH(tb, a) (a)->hashval
75 #define SH_SCOPE static inline
76 #define SH_RAW_ALLOCATOR pg_malloc0
77 #define SH_DECLARE
78 #define SH_DEFINE
79 #include "lib/simplehash.h"
80 
81 #define CATALOGIDHASH_INITIAL_SIZE 10000
82 
83 static catalogid_hash *catalogIdHash = NULL;
84 
85 static void flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
86  InhInfo *inhinfo, int numInherits);
87 static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables);
88 static void flagInhAttrs(Archive *fout, TableInfo *tblinfo, int numTables);
89 static int strInArray(const char *pattern, char **arr, int arr_size);
90 static IndxInfo *findIndexByOid(Oid oid);
91 
92 
93 /*
94  * getSchemaData
95  * Collect information about all potentially dumpable objects
96  */
97 TableInfo *
98 getSchemaData(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");
168  getTSConfigurations(fout);
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, tblinfo, numTables);
210 
211  pg_log_info("reading partitioning data");
212  getPartitioningInfo(fout);
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");
221  getExtendedStatistics(fout);
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 tables");
248  getSubscriptionTables(fout);
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  */
268 static void
269 flagInhTables(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  */
386 static void
387 flagInhIndexes(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.
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  */
476 static void
477 flagInhAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
478 {
479  DumpOptions *dopt = fout->dopt;
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 
521  /* no point in examining dropped columns */
522  if (tbinfo->attisdropped[j])
523  continue;
524 
525  foundNotNull = false;
526  foundDefault = false;
527  foundSameGenerated = false;
528  foundDiffGenerated = false;
529  for (k = 0; k < numParents; k++)
530  {
531  TableInfo *parent = parents[k];
532  int inhAttrInd;
533 
534  inhAttrInd = strInArray(tbinfo->attnames[j],
535  parent->attnames,
536  parent->numatts);
537  if (inhAttrInd >= 0)
538  {
539  AttrDefInfo *parentDef = parent->attrdefs[inhAttrInd];
540 
541  foundNotNull |= parent->notnull[inhAttrInd];
542  foundDefault |= (parentDef != NULL &&
543  strcmp(parentDef->adef_expr, "NULL") != 0 &&
544  !parent->attgenerated[inhAttrInd]);
545  if (parent->attgenerated[inhAttrInd])
546  {
547  /* these pointer nullness checks are just paranoia */
548  if (parentDef != NULL &&
549  tbinfo->attrdefs[j] != NULL &&
550  strcmp(parentDef->adef_expr,
551  tbinfo->attrdefs[j]->adef_expr) == 0)
552  foundSameGenerated = true;
553  else
554  foundDiffGenerated = true;
555  }
556  }
557  }
558 
559  /* Remember if we found inherited NOT NULL */
560  tbinfo->inhNotNull[j] = foundNotNull;
561 
562  /*
563  * Manufacture a DEFAULT NULL clause if necessary. This breaks
564  * the advice given above to avoid changing state that might get
565  * inspected in other loop iterations. We prevent trouble by
566  * having the foundDefault test above check whether adef_expr is
567  * "NULL", so that it will reach the same conclusion before or
568  * after this is done.
569  */
570  if (foundDefault && tbinfo->attrdefs[j] == NULL)
571  {
572  AttrDefInfo *attrDef;
573 
574  attrDef = pg_malloc_object(AttrDefInfo);
575  attrDef->dobj.objType = DO_ATTRDEF;
576  attrDef->dobj.catId.tableoid = 0;
577  attrDef->dobj.catId.oid = 0;
578  AssignDumpId(&attrDef->dobj);
579  attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
580  attrDef->dobj.namespace = tbinfo->dobj.namespace;
581  attrDef->dobj.dump = tbinfo->dobj.dump;
582 
583  attrDef->adtable = tbinfo;
584  attrDef->adnum = j + 1;
585  attrDef->adef_expr = pg_strdup("NULL");
586 
587  /* Will column be dumped explicitly? */
588  if (shouldPrintColumn(dopt, tbinfo, j))
589  {
590  attrDef->separate = false;
591  /* No dependency needed: NULL cannot have dependencies */
592  }
593  else
594  {
595  /* column will be suppressed, print default separately */
596  attrDef->separate = true;
597  /* ensure it comes out after the table */
598  addObjectDependency(&attrDef->dobj,
599  tbinfo->dobj.dumpId);
600  }
601 
602  tbinfo->attrdefs[j] = attrDef;
603  }
604 
605  /* No need to dump generation expression if it's inheritable */
606  if (foundSameGenerated && !foundDiffGenerated &&
607  !tbinfo->ispartition && !dopt->binary_upgrade)
608  tbinfo->attrdefs[j]->dobj.dump = DUMP_COMPONENT_NONE;
609  }
610  }
611 }
612 
613 /*
614  * AssignDumpId
615  * Given a newly-created dumpable object, assign a dump ID,
616  * and enter the object into the lookup tables.
617  *
618  * The caller is expected to have filled in objType and catId,
619  * but not any of the other standard fields of a DumpableObject.
620  */
621 void
623 {
624  dobj->dumpId = ++lastDumpId;
625  dobj->name = NULL; /* must be set later */
626  dobj->namespace = NULL; /* may be set later */
627  dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
628  dobj->dump_contains = DUMP_COMPONENT_ALL; /* default assumption */
629  /* All objects have definitions; we may set more components bits later */
631  dobj->ext_member = false; /* default assumption */
632  dobj->depends_on_ext = false; /* default assumption */
633  dobj->dependencies = NULL;
634  dobj->nDeps = 0;
635  dobj->allocDeps = 0;
636 
637  /* Add object to dumpIdMap[], enlarging that array if need be */
638  while (dobj->dumpId >= allocedDumpIds)
639  {
640  int newAlloc;
641 
642  if (allocedDumpIds <= 0)
643  {
644  newAlloc = 256;
646  }
647  else
648  {
649  newAlloc = allocedDumpIds * 2;
651  }
652  memset(dumpIdMap + allocedDumpIds, 0,
653  (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
654  allocedDumpIds = newAlloc;
655  }
656  dumpIdMap[dobj->dumpId] = dobj;
657 
658  /* If it has a valid CatalogId, enter it into the hash table */
659  if (OidIsValid(dobj->catId.tableoid))
660  {
661  CatalogIdMapEntry *entry;
662  bool found;
663 
664  /* Initialize CatalogId hash table if not done yet */
665  if (catalogIdHash == NULL)
666  catalogIdHash = catalogid_create(CATALOGIDHASH_INITIAL_SIZE, NULL);
667 
668  entry = catalogid_insert(catalogIdHash, dobj->catId, &found);
669  if (!found)
670  {
671  entry->dobj = NULL;
672  entry->ext = NULL;
673  }
674  Assert(entry->dobj == NULL);
675  entry->dobj = dobj;
676  }
677 }
678 
679 /*
680  * recordAdditionalCatalogID
681  * Record an additional catalog ID for the given DumpableObject
682  */
683 void
685 {
686  CatalogIdMapEntry *entry;
687  bool found;
688 
689  /* CatalogId hash table must exist, if we have a DumpableObject */
690  Assert(catalogIdHash != NULL);
691 
692  /* Add reference to CatalogId hash */
693  entry = catalogid_insert(catalogIdHash, catId, &found);
694  if (!found)
695  {
696  entry->dobj = NULL;
697  entry->ext = NULL;
698  }
699  Assert(entry->dobj == NULL);
700  entry->dobj = dobj;
701 }
702 
703 /*
704  * Assign a DumpId that's not tied to a DumpableObject.
705  *
706  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
707  * participate in the sorting logic.
708  */
709 DumpId
711 {
712  return ++lastDumpId;
713 }
714 
715 /*
716  * Return the largest DumpId so far assigned
717  */
718 DumpId
720 {
721  return lastDumpId;
722 }
723 
724 /*
725  * Find a DumpableObject by dump ID
726  *
727  * Returns NULL for invalid ID
728  */
731 {
732  if (dumpId <= 0 || dumpId >= allocedDumpIds)
733  return NULL; /* out of range? */
734  return dumpIdMap[dumpId];
735 }
736 
737 /*
738  * Find a DumpableObject by catalog ID
739  *
740  * Returns NULL for unknown ID
741  */
744 {
745  CatalogIdMapEntry *entry;
746 
747  if (catalogIdHash == NULL)
748  return NULL; /* no objects exist yet */
749 
750  entry = catalogid_lookup(catalogIdHash, catalogId);
751  if (entry == NULL)
752  return NULL;
753  return entry->dobj;
754 }
755 
756 /*
757  * Build an array of pointers to all known dumpable objects
758  *
759  * This simply creates a modifiable copy of the internal map.
760  */
761 void
762 getDumpableObjects(DumpableObject ***objs, int *numObjs)
763 {
764  int i,
765  j;
766 
768  j = 0;
769  for (i = 1; i < allocedDumpIds; i++)
770  {
771  if (dumpIdMap[i])
772  (*objs)[j++] = dumpIdMap[i];
773  }
774  *numObjs = j;
775 }
776 
777 /*
778  * Add a dependency link to a DumpableObject
779  *
780  * Note: duplicate dependencies are currently not eliminated
781  */
782 void
784 {
785  if (dobj->nDeps >= dobj->allocDeps)
786  {
787  if (dobj->allocDeps <= 0)
788  {
789  dobj->allocDeps = 16;
791  }
792  else
793  {
794  dobj->allocDeps *= 2;
796  DumpId, dobj->allocDeps);
797  }
798  }
799  dobj->dependencies[dobj->nDeps++] = refId;
800 }
801 
802 /*
803  * Remove a dependency link from a DumpableObject
804  *
805  * If there are multiple links, all are removed
806  */
807 void
809 {
810  int i;
811  int j = 0;
812 
813  for (i = 0; i < dobj->nDeps; i++)
814  {
815  if (dobj->dependencies[i] != refId)
816  dobj->dependencies[j++] = dobj->dependencies[i];
817  }
818  dobj->nDeps = j;
819 }
820 
821 
822 /*
823  * findTableByOid
824  * finds the DumpableObject for the table with the given oid
825  * returns NULL if not found
826  */
827 TableInfo *
829 {
830  CatalogId catId;
831  DumpableObject *dobj;
832 
833  catId.tableoid = RelationRelationId;
834  catId.oid = oid;
835  dobj = findObjectByCatalogId(catId);
836  Assert(dobj == NULL || dobj->objType == DO_TABLE);
837  return (TableInfo *) dobj;
838 }
839 
840 /*
841  * findIndexByOid
842  * finds the DumpableObject for the index with the given oid
843  * returns NULL if not found
844  */
845 static IndxInfo *
847 {
848  CatalogId catId;
849  DumpableObject *dobj;
850 
851  catId.tableoid = RelationRelationId;
852  catId.oid = oid;
853  dobj = findObjectByCatalogId(catId);
854  Assert(dobj == NULL || dobj->objType == DO_INDEX);
855  return (IndxInfo *) dobj;
856 }
857 
858 /*
859  * findTypeByOid
860  * finds the DumpableObject for the type with the given oid
861  * returns NULL if not found
862  */
863 TypeInfo *
865 {
866  CatalogId catId;
867  DumpableObject *dobj;
868 
869  catId.tableoid = TypeRelationId;
870  catId.oid = oid;
871  dobj = findObjectByCatalogId(catId);
872  Assert(dobj == NULL ||
873  dobj->objType == DO_TYPE || dobj->objType == DO_DUMMY_TYPE);
874  return (TypeInfo *) dobj;
875 }
876 
877 /*
878  * findFuncByOid
879  * finds the DumpableObject for the function with the given oid
880  * returns NULL if not found
881  */
882 FuncInfo *
884 {
885  CatalogId catId;
886  DumpableObject *dobj;
887 
888  catId.tableoid = ProcedureRelationId;
889  catId.oid = oid;
890  dobj = findObjectByCatalogId(catId);
891  Assert(dobj == NULL || dobj->objType == DO_FUNC);
892  return (FuncInfo *) dobj;
893 }
894 
895 /*
896  * findOprByOid
897  * finds the DumpableObject for the operator with the given oid
898  * returns NULL if not found
899  */
900 OprInfo *
902 {
903  CatalogId catId;
904  DumpableObject *dobj;
905 
906  catId.tableoid = OperatorRelationId;
907  catId.oid = oid;
908  dobj = findObjectByCatalogId(catId);
909  Assert(dobj == NULL || dobj->objType == DO_OPERATOR);
910  return (OprInfo *) dobj;
911 }
912 
913 /*
914  * findCollationByOid
915  * finds the DumpableObject for the collation with the given oid
916  * returns NULL if not found
917  */
918 CollInfo *
920 {
921  CatalogId catId;
922  DumpableObject *dobj;
923 
924  catId.tableoid = CollationRelationId;
925  catId.oid = oid;
926  dobj = findObjectByCatalogId(catId);
927  Assert(dobj == NULL || dobj->objType == DO_COLLATION);
928  return (CollInfo *) dobj;
929 }
930 
931 /*
932  * findNamespaceByOid
933  * finds the DumpableObject for the namespace with the given oid
934  * returns NULL if not found
935  */
938 {
939  CatalogId catId;
940  DumpableObject *dobj;
941 
942  catId.tableoid = NamespaceRelationId;
943  catId.oid = oid;
944  dobj = findObjectByCatalogId(catId);
945  Assert(dobj == NULL || dobj->objType == DO_NAMESPACE);
946  return (NamespaceInfo *) dobj;
947 }
948 
949 /*
950  * findExtensionByOid
951  * finds the DumpableObject for the extension with the given oid
952  * returns NULL if not found
953  */
956 {
957  CatalogId catId;
958  DumpableObject *dobj;
959 
960  catId.tableoid = ExtensionRelationId;
961  catId.oid = oid;
962  dobj = findObjectByCatalogId(catId);
963  Assert(dobj == NULL || dobj->objType == DO_EXTENSION);
964  return (ExtensionInfo *) dobj;
965 }
966 
967 /*
968  * findPublicationByOid
969  * finds the DumpableObject for the publication with the given oid
970  * returns NULL if not found
971  */
974 {
975  CatalogId catId;
976  DumpableObject *dobj;
977 
978  catId.tableoid = PublicationRelationId;
979  catId.oid = oid;
980  dobj = findObjectByCatalogId(catId);
981  Assert(dobj == NULL || dobj->objType == DO_PUBLICATION);
982  return (PublicationInfo *) dobj;
983 }
984 
985 /*
986  * findSubscriptionByOid
987  * finds the DumpableObject for the subscription with the given oid
988  * returns NULL if not found
989  */
992 {
993  CatalogId catId;
994  DumpableObject *dobj;
995 
996  catId.tableoid = SubscriptionRelationId;
997  catId.oid = oid;
998  dobj = findObjectByCatalogId(catId);
999  Assert(dobj == NULL || dobj->objType == DO_SUBSCRIPTION);
1000  return (SubscriptionInfo *) dobj;
1001 }
1002 
1003 
1004 /*
1005  * recordExtensionMembership
1006  * Record that the object identified by the given catalog ID
1007  * belongs to the given extension
1008  */
1009 void
1011 {
1012  CatalogIdMapEntry *entry;
1013  bool found;
1014 
1015  /* CatalogId hash table must exist, if we have an ExtensionInfo */
1016  Assert(catalogIdHash != NULL);
1017 
1018  /* Add reference to CatalogId hash */
1019  entry = catalogid_insert(catalogIdHash, catId, &found);
1020  if (!found)
1021  {
1022  entry->dobj = NULL;
1023  entry->ext = NULL;
1024  }
1025  Assert(entry->ext == NULL);
1026  entry->ext = ext;
1027 }
1028 
1029 /*
1030  * findOwningExtension
1031  * return owning extension for specified catalog ID, or NULL if none
1032  */
1033 ExtensionInfo *
1035 {
1036  CatalogIdMapEntry *entry;
1037 
1038  if (catalogIdHash == NULL)
1039  return NULL; /* no objects exist yet */
1040 
1041  entry = catalogid_lookup(catalogIdHash, catalogId);
1042  if (entry == NULL)
1043  return NULL;
1044  return entry->ext;
1045 }
1046 
1047 
1048 /*
1049  * parseOidArray
1050  * parse a string of numbers delimited by spaces into a character array
1051  *
1052  * Note: actually this is used for both Oids and potentially-signed
1053  * attribute numbers. This should cause no trouble, but we could split
1054  * the function into two functions with different argument types if it does.
1055  */
1056 
1057 void
1058 parseOidArray(const char *str, Oid *array, int arraysize)
1059 {
1060  int j,
1061  argNum;
1062  char temp[100];
1063  char s;
1064 
1065  argNum = 0;
1066  j = 0;
1067  for (;;)
1068  {
1069  s = *str++;
1070  if (s == ' ' || s == '\0')
1071  {
1072  if (j > 0)
1073  {
1074  if (argNum >= arraysize)
1075  pg_fatal("could not parse numeric array \"%s\": too many numbers", str);
1076  temp[j] = '\0';
1077  array[argNum++] = atooid(temp);
1078  j = 0;
1079  }
1080  if (s == '\0')
1081  break;
1082  }
1083  else
1084  {
1085  if (!(isdigit((unsigned char) s) || s == '-') ||
1086  j >= sizeof(temp) - 1)
1087  pg_fatal("could not parse numeric array \"%s\": invalid character in number", str);
1088  temp[j++] = s;
1089  }
1090  }
1091 
1092  while (argNum < arraysize)
1093  array[argNum++] = InvalidOid;
1094 }
1095 
1096 
1097 /*
1098  * strInArray:
1099  * takes in a string and a string array and the number of elements in the
1100  * string array.
1101  * returns the index if the string is somewhere in the array, -1 otherwise
1102  */
1103 
1104 static int
1105 strInArray(const char *pattern, char **arr, int arr_size)
1106 {
1107  int i;
1108 
1109  for (i = 0; i < arr_size; i++)
1110  {
1111  if (strcmp(pattern, arr[i]) == 0)
1112  return i;
1113  }
1114  return -1;
1115 }
void recordAdditionalCatalogID(CatalogId catId, DumpableObject *dobj)
Definition: common.c:684
void recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
Definition: common.c:1010
FuncInfo * findFuncByOid(Oid oid)
Definition: common.c:883
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)
NamespaceInfo * findNamespaceByOid(Oid oid)
Definition: common.c:937
SubscriptionInfo * findSubscriptionByOid(Oid oid)
Definition: common.c:991
ExtensionInfo * findOwningExtension(CatalogId catalogId)
Definition: common.c:1034
TableInfo * getSchemaData(Archive *fout, int *numTablesPtr)
Definition: common.c:98
DumpableObject * findObjectByCatalogId(CatalogId catalogId)
Definition: common.c:743
static void flagInhAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition: common.c:477
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:783
static int allocedDumpIds
Definition: common.c:39
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition: common.c:730
void parseOidArray(const char *str, Oid *array, int arraysize)
Definition: common.c:1058
TableInfo * findTableByOid(Oid oid)
Definition: common.c:828
static IndxInfo * findIndexByOid(Oid oid)
Definition: common.c:846
DumpId createDumpId(void)
Definition: common.c:710
ExtensionInfo * findExtensionByOid(Oid oid)
Definition: common.c:955
void AssignDumpId(DumpableObject *dobj)
Definition: common.c:622
DumpId getMaxDumpId(void)
Definition: common.c:719
static DumpableObject ** dumpIdMap
Definition: common.c:38
#define CATALOGIDHASH_INITIAL_SIZE
Definition: common.c:81
static int strInArray(const char *pattern, char **arr, int arr_size)
Definition: common.c:1105
void getDumpableObjects(DumpableObject ***objs, int *numObjs)
Definition: common.c:762
CollInfo * findCollationByOid(Oid oid)
Definition: common.c:919
static catalogid_hash * catalogIdHash
Definition: common.c:83
TypeInfo * findTypeByOid(Oid oid)
Definition: common.c:864
OprInfo * findOprByOid(Oid oid)
Definition: common.c:901
struct _catalogIdMapEntry CatalogIdMapEntry
void removeObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:808
static DumpId lastDumpId
Definition: common.c:40
PublicationInfo * findPublicationByOid(Oid oid)
Definition: common.c:973
unsigned int uint32
Definition: c.h:506
#define Assert(condition)
Definition: c.h:858
#define OidIsValid(objectId)
Definition: c.h:775
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
#define pg_realloc_array(pointer, type, count)
Definition: fe_memutils.h:51
#define pg_malloc_array(type, count)
Definition: fe_memutils.h:44
#define pg_malloc_object(type)
Definition: fe_memutils.h:38
const char * str
#define free(a)
Definition: header.h:65
int j
Definition: isn.c:74
int i
Definition: isn.c:73
#define pg_log_info(...)
Definition: logging.h:124
void * palloc(Size size)
Definition: mcxt.c:1317
int DumpId
Definition: pg_backup.h:270
#define pg_fatal(...)
void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7694
void getPublicationNamespaces(Archive *fout)
Definition: pg_dump.c:4398
void getPartitioningInfo(Archive *fout)
Definition: pg_dump.c:7245
void getForeignDataWrappers(Archive *fout)
Definition: pg_dump.c:9451
void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:3919
void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17891
void getTypes(Archive *fout)
Definition: pg_dump.c:5805
void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7126
void getOpclasses(Archive *fout)
Definition: pg_dump.c:6222
void getForeignServers(Archive *fout)
Definition: pg_dump.c:9535
void getFuncs(Archive *fout)
Definition: pg_dump.c:6485
void getTSDictionaries(Archive *fout)
Definition: pg_dump.c:9267
void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:4485
void getCasts(Archive *fout)
Definition: pg_dump.c:8427
void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7305
void getTSConfigurations(Archive *fout)
Definition: pg_dump.c:9392
void getAccessMethods(Archive *fout)
Definition: pg_dump.c:6160
void getConversions(Archive *fout)
Definition: pg_dump.c:6098
void getRules(Archive *fout)
Definition: pg_dump.c:7972
InhInfo * getInherits(Archive *fout, int *numInherits)
Definition: pg_dump.c:7189
void getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition: pg_dump.c:8621
void getSubscriptionTables(Archive *fout)
Definition: pg_dump.c:4939
void getCollations(Archive *fout)
Definition: pg_dump.c:6036
void getAggregates(Archive *fout)
Definition: pg_dump.c:6344
void getNamespaces(Archive *fout)
Definition: pg_dump.c:5601
void getPublications(Archive *fout)
Definition: pg_dump.c:4204
void getTSParsers(Archive *fout)
Definition: pg_dump.c:9193
void getExtendedStatistics(Archive *fout)
Definition: pg_dump.c:7615
void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17984
void getDefaultACLs(Archive *fout)
Definition: pg_dump.c:9623
void getSubscriptions(Archive *fout)
Definition: pg_dump.c:4739
ExtensionInfo * getExtensions(Archive *fout, int *numExtensions)
Definition: pg_dump.c:5733
void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:8069
void getTransforms(Archive *fout)
Definition: pg_dump.c:8537
void getEventTriggers(Archive *fout)
Definition: pg_dump.c:8265
TableInfo * getTables(Archive *fout, int *numTables)
Definition: pg_dump.c:6680
void getTSTemplates(Archive *fout)
Definition: pg_dump.c:9333
void getProcLangs(Archive *fout)
Definition: pg_dump.c:8343
bool shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
Definition: pg_dump.c:9178
void getOperators(Archive *fout)
Definition: pg_dump.c:5968
void getOpfamilies(Archive *fout)
Definition: pg_dump.c:6282
#define DUMP_COMPONENT_ALL
Definition: pg_dump.h:104
#define DUMP_COMPONENT_NONE
Definition: pg_dump.h:96
#define DUMP_COMPONENT_DEFINITION
Definition: pg_dump.h:97
@ DO_TYPE
Definition: pg_dump.h:42
@ DO_INDEX
Definition: pg_dump.h:55
@ DO_COLLATION
Definition: pg_dump.h:50
@ DO_OPERATOR
Definition: pg_dump.h:46
@ DO_SUBSCRIPTION
Definition: pg_dump.h:85
@ DO_ATTRDEF
Definition: pg_dump.h:54
@ DO_TABLE_ATTACH
Definition: pg_dump.h:53
@ DO_INDEX_ATTACH
Definition: pg_dump.h:56
@ DO_FUNC
Definition: pg_dump.h:44
@ DO_DUMMY_TYPE
Definition: pg_dump.h:66
@ DO_EXTENSION
Definition: pg_dump.h:41
@ DO_PUBLICATION
Definition: pg_dump.h:82
@ DO_TABLE
Definition: pg_dump.h:52
@ DO_NAMESPACE
Definition: pg_dump.h:40
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define atooid(x)
Definition: postgres_ext.h:42
void simple_ptr_list_append(SimplePtrList *list, void *ptr)
Definition: simple_list.c:162
DumpOptions * dopt
Definition: pg_backup.h:214
Oid tableoid
Definition: pg_backup.h:266
DumpableObject dobj
Definition: pg_dump.h:375
char * adef_expr
Definition: pg_dump.h:378
TableInfo * adtable
Definition: pg_dump.h:376
bool separate
Definition: pg_dump.h:379
CatalogId catId
Definition: common.c:60
ExtensionInfo * ext
Definition: common.c:64
uint32 status
Definition: common.c:61
DumpableObject * dobj
Definition: common.c:63
uint32 hashval
Definition: common.c:62
int binary_upgrade
Definition: pg_backup.h:166
DumpComponents dump
Definition: pg_dump.h:139
char * name
Definition: pg_dump.h:138
DumpId * dependencies
Definition: pg_dump.h:145
DumpId dumpId
Definition: pg_dump.h:137
bool ext_member
Definition: pg_dump.h:143
DumpComponents components
Definition: pg_dump.h:142
DumpableObjectType objType
Definition: pg_dump.h:135
CatalogId catId
Definition: pg_dump.h:136
DumpComponents dump_contains
Definition: pg_dump.h:141
bool depends_on_ext
Definition: pg_dump.h:144
IndxInfo * partitionIdx
Definition: pg_dump.h:416
DumpableObject dobj
Definition: pg_dump.h:414
IndxInfo * parentIdx
Definition: pg_dump.h:415
TableInfo * indextable
Definition: pg_dump.h:392
SimplePtrList partattaches
Definition: pg_dump.h:406
DumpableObject dobj
Definition: pg_dump.h:391
Oid inhparent
Definition: pg_dump.h:515
Oid inhrelid
Definition: pg_dump.h:514
TableInfo * partitionTbl
Definition: pg_dump.h:370
DumpableObject dobj
Definition: pg_dump.h:368
TableInfo * parentTbl
Definition: pg_dump.h:369
bool ispartition
Definition: pg_dump.h:322
struct _indxInfo * indexes
Definition: pg_dump.h:360
DumpableObject dobj
Definition: pg_dump.h:285
int numParents
Definition: pg_dump.h:325
struct _tableInfo ** parents
Definition: pg_dump.h:326
char * attgenerated
Definition: pg_dump.h:340
bool * attisdropped
Definition: pg_dump.h:338
int numatts
Definition: pg_dump.h:332
struct _attrDefInfo ** attrdefs
Definition: pg_dump.h:351
bool * notnull
Definition: pg_dump.h:349
char ** attnames
Definition: pg_dump.h:333
char relkind
Definition: pg_dump.h:288
int numIndexes
Definition: pg_dump.h:359
bool * inhNotNull
Definition: pg_dump.h:350
Definition: type.h:95