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