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