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