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