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