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-2022, 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 *tbinfo, 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 void findParentsByOid(TableInfo *self,
87  InhInfo *inhinfo, int numInherits);
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->dopt, tblinfo, numTables);
232 
233  pg_log_info("reading indexes");
234  getIndexes(fout, tblinfo, numTables);
235 
236  pg_log_info("flagging indexes in partitioned tables");
237  flagInhIndexes(fout, tblinfo, numTables);
238 
239  pg_log_info("reading extended statistics");
240  getExtendedStatistics(fout);
241 
242  pg_log_info("reading constraints");
243  getConstraints(fout, tblinfo, numTables);
244 
245  pg_log_info("reading triggers");
246  getTriggers(fout, tblinfo, numTables);
247 
248  pg_log_info("reading rewrite rules");
249  getRules(fout, &numRules);
250 
251  pg_log_info("reading policies");
252  getPolicies(fout, tblinfo, numTables);
253 
254  pg_log_info("reading publications");
255  (void) getPublications(fout, &numPublications);
256 
257  pg_log_info("reading publication membership of tables");
258  getPublicationTables(fout, tblinfo, numTables);
259 
260  pg_log_info("reading publication membership of schemas");
262 
263  pg_log_info("reading subscriptions");
264  getSubscriptions(fout);
265 
266  free(inhinfo); /* not needed any longer */
267 
268  *numTablesPtr = numTables;
269  return tblinfo;
270 }
271 
272 /* flagInhTables -
273  * Fill in parent link fields of tables for which we need that information,
274  * mark parents of target tables as interesting, and create
275  * TableAttachInfo objects for partitioned tables with appropriate
276  * dependency links.
277  *
278  * Note that only direct ancestors of targets are marked interesting.
279  * This is sufficient; we don't much care whether they inherited their
280  * attributes or not.
281  *
282  * modifies tblinfo
283  */
284 static void
285 flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
286  InhInfo *inhinfo, int numInherits)
287 {
288  DumpOptions *dopt = fout->dopt;
289  int i,
290  j;
291 
292  for (i = 0; i < numTables; i++)
293  {
294  bool find_parents = true;
295  bool mark_parents = true;
296 
297  /* Some kinds never have parents */
298  if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
299  tblinfo[i].relkind == RELKIND_VIEW ||
300  tblinfo[i].relkind == RELKIND_MATVIEW)
301  continue;
302 
303  /*
304  * Normally, we don't bother computing anything for non-target tables,
305  * but if load-via-partition-root is specified, we gather information
306  * on every partition in the system so that getRootTableInfo can trace
307  * from any given to leaf partition all the way up to the root. (We
308  * don't need to mark them as interesting for getTableAttrs, though.)
309  */
310  if (!tblinfo[i].dobj.dump)
311  {
312  mark_parents = false;
313 
314  if (!dopt->load_via_partition_root ||
315  !tblinfo[i].ispartition)
316  find_parents = false;
317  }
318 
319  /* If needed, find all the immediate parent tables. */
320  if (find_parents)
321  findParentsByOid(&tblinfo[i], inhinfo, numInherits);
322 
323  /*
324  * If needed, mark the parents as interesting for getTableAttrs and
325  * getIndexes.
326  */
327  if (mark_parents)
328  {
329  int numParents = tblinfo[i].numParents;
330  TableInfo **parents = tblinfo[i].parents;
331 
332  for (j = 0; j < numParents; j++)
333  parents[j]->interesting = true;
334  }
335 
336  /* Create TableAttachInfo object if needed */
337  if (tblinfo[i].dobj.dump && tblinfo[i].ispartition)
338  {
339  TableAttachInfo *attachinfo;
340 
341  /* With partitions there can only be one parent */
342  if (tblinfo[i].numParents != 1)
343  pg_fatal("invalid number of parents %d for table \"%s\"",
344  tblinfo[i].numParents,
345  tblinfo[i].dobj.name);
346 
347  attachinfo = (TableAttachInfo *) palloc(sizeof(TableAttachInfo));
348  attachinfo->dobj.objType = DO_TABLE_ATTACH;
349  attachinfo->dobj.catId.tableoid = 0;
350  attachinfo->dobj.catId.oid = 0;
351  AssignDumpId(&attachinfo->dobj);
352  attachinfo->dobj.name = pg_strdup(tblinfo[i].dobj.name);
353  attachinfo->dobj.namespace = tblinfo[i].dobj.namespace;
354  attachinfo->parentTbl = tblinfo[i].parents[0];
355  attachinfo->partitionTbl = &tblinfo[i];
356 
357  /*
358  * We must state the DO_TABLE_ATTACH object's dependencies
359  * explicitly, since it will not match anything in pg_depend.
360  *
361  * Give it dependencies on both the partition table and the parent
362  * table, so that it will not be executed till both of those
363  * exist. (There's no need to care what order those are created
364  * in.)
365  */
366  addObjectDependency(&attachinfo->dobj, tblinfo[i].dobj.dumpId);
367  addObjectDependency(&attachinfo->dobj, tblinfo[i].parents[0]->dobj.dumpId);
368  }
369  }
370 }
371 
372 /*
373  * flagInhIndexes -
374  * Create IndexAttachInfo objects for partitioned indexes, and add
375  * appropriate dependency links.
376  */
377 static void
378 flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
379 {
380  int i,
381  j;
382 
383  for (i = 0; i < numTables; i++)
384  {
385  if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
386  continue;
387 
388  Assert(tblinfo[i].numParents == 1);
389 
390  for (j = 0; j < tblinfo[i].numIndexes; j++)
391  {
392  IndxInfo *index = &(tblinfo[i].indexes[j]);
393  IndxInfo *parentidx;
394  IndexAttachInfo *attachinfo;
395 
396  if (index->parentidx == 0)
397  continue;
398 
399  parentidx = findIndexByOid(index->parentidx);
400  if (parentidx == NULL)
401  continue;
402 
403  attachinfo = (IndexAttachInfo *) pg_malloc(sizeof(IndexAttachInfo));
404 
405  attachinfo->dobj.objType = DO_INDEX_ATTACH;
406  attachinfo->dobj.catId.tableoid = 0;
407  attachinfo->dobj.catId.oid = 0;
408  AssignDumpId(&attachinfo->dobj);
409  attachinfo->dobj.name = pg_strdup(index->dobj.name);
410  attachinfo->dobj.namespace = index->indextable->dobj.namespace;
411  attachinfo->parentIdx = parentidx;
412  attachinfo->partitionIdx = index;
413 
414  /*
415  * We must state the DO_INDEX_ATTACH object's dependencies
416  * explicitly, since it will not match anything in pg_depend.
417  *
418  * Give it dependencies on both the partition index and the parent
419  * index, so that it will not be executed till both of those
420  * exist. (There's no need to care what order those are created
421  * in.)
422  *
423  * In addition, give it dependencies on the indexes' underlying
424  * tables. This does nothing of great value so far as serial
425  * restore ordering goes, but it ensures that a parallel restore
426  * will not try to run the ATTACH concurrently with other
427  * operations on those tables.
428  */
429  addObjectDependency(&attachinfo->dobj, index->dobj.dumpId);
430  addObjectDependency(&attachinfo->dobj, parentidx->dobj.dumpId);
431  addObjectDependency(&attachinfo->dobj,
432  index->indextable->dobj.dumpId);
433  addObjectDependency(&attachinfo->dobj,
434  parentidx->indextable->dobj.dumpId);
435 
436  /* keep track of the list of partitions in the parent index */
437  simple_ptr_list_append(&parentidx->partattaches, &attachinfo->dobj);
438  }
439  }
440 }
441 
442 /* flagInhAttrs -
443  * for each dumpable table in tblinfo, flag its inherited attributes
444  *
445  * What we need to do here is:
446  *
447  * - Detect child columns that inherit NOT NULL bits from their parents, so
448  * that we needn't specify that again for the child.
449  *
450  * - Detect child columns that have DEFAULT NULL when their parents had some
451  * non-null default. In this case, we make up a dummy AttrDefInfo object so
452  * that we'll correctly emit the necessary DEFAULT NULL clause; otherwise
453  * the backend will apply an inherited default to the column.
454  *
455  * - Detect child columns that have a generation expression when their parents
456  * also have one. Generation expressions are always inherited, so there is
457  * no need to set them again in child tables, and there is no syntax for it
458  * either. Exceptions: If it's a partition or we are in binary upgrade
459  * mode, we dump them because in those cases inherited tables are recreated
460  * standalone first and then reattached to the parent. (See also the logic
461  * in dumpTableSchema().) In that situation, the generation expressions
462  * must match the parent, enforced by ALTER TABLE.
463  *
464  * modifies tblinfo
465  */
466 static void
467 flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
468 {
469  int i,
470  j,
471  k;
472 
473  for (i = 0; i < numTables; i++)
474  {
475  TableInfo *tbinfo = &(tblinfo[i]);
476  int numParents;
477  TableInfo **parents;
478 
479  /* Some kinds never have parents */
480  if (tbinfo->relkind == RELKIND_SEQUENCE ||
481  tbinfo->relkind == RELKIND_VIEW ||
482  tbinfo->relkind == RELKIND_MATVIEW)
483  continue;
484 
485  /* Don't bother computing anything for non-target tables, either */
486  if (!tbinfo->dobj.dump)
487  continue;
488 
489  numParents = tbinfo->numParents;
490  parents = tbinfo->parents;
491 
492  if (numParents == 0)
493  continue; /* nothing to see here, move along */
494 
495  /* For each column, search for matching column names in parent(s) */
496  for (j = 0; j < tbinfo->numatts; j++)
497  {
498  bool foundNotNull; /* Attr was NOT NULL in a parent */
499  bool foundDefault; /* Found a default in a parent */
500  bool foundGenerated; /* Found a generated in a parent */
501 
502  /* no point in examining dropped columns */
503  if (tbinfo->attisdropped[j])
504  continue;
505 
506  foundNotNull = false;
507  foundDefault = false;
508  foundGenerated = false;
509  for (k = 0; k < numParents; k++)
510  {
511  TableInfo *parent = parents[k];
512  int inhAttrInd;
513 
514  inhAttrInd = strInArray(tbinfo->attnames[j],
515  parent->attnames,
516  parent->numatts);
517  if (inhAttrInd >= 0)
518  {
519  foundNotNull |= parent->notnull[inhAttrInd];
520  foundDefault |= (parent->attrdefs[inhAttrInd] != NULL && !parent->attgenerated[inhAttrInd]);
521  foundGenerated |= parent->attgenerated[inhAttrInd];
522  }
523  }
524 
525  /* Remember if we found inherited NOT NULL */
526  tbinfo->inhNotNull[j] = foundNotNull;
527 
528  /* Manufacture a DEFAULT NULL clause if necessary */
529  if (foundDefault && tbinfo->attrdefs[j] == NULL)
530  {
531  AttrDefInfo *attrDef;
532 
533  attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo));
534  attrDef->dobj.objType = DO_ATTRDEF;
535  attrDef->dobj.catId.tableoid = 0;
536  attrDef->dobj.catId.oid = 0;
537  AssignDumpId(&attrDef->dobj);
538  attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
539  attrDef->dobj.namespace = tbinfo->dobj.namespace;
540  attrDef->dobj.dump = tbinfo->dobj.dump;
541 
542  attrDef->adtable = tbinfo;
543  attrDef->adnum = j + 1;
544  attrDef->adef_expr = pg_strdup("NULL");
545 
546  /* Will column be dumped explicitly? */
547  if (shouldPrintColumn(dopt, tbinfo, j))
548  {
549  attrDef->separate = false;
550  /* No dependency needed: NULL cannot have dependencies */
551  }
552  else
553  {
554  /* column will be suppressed, print default separately */
555  attrDef->separate = true;
556  /* ensure it comes out after the table */
557  addObjectDependency(&attrDef->dobj,
558  tbinfo->dobj.dumpId);
559  }
560 
561  tbinfo->attrdefs[j] = attrDef;
562  }
563 
564  /* Remove generation expression from child */
565  if (foundGenerated && !tbinfo->ispartition && !dopt->binary_upgrade)
566  tbinfo->attrdefs[j] = NULL;
567  }
568  }
569 }
570 
571 /*
572  * AssignDumpId
573  * Given a newly-created dumpable object, assign a dump ID,
574  * and enter the object into the lookup tables.
575  *
576  * The caller is expected to have filled in objType and catId,
577  * but not any of the other standard fields of a DumpableObject.
578  */
579 void
581 {
582  dobj->dumpId = ++lastDumpId;
583  dobj->name = NULL; /* must be set later */
584  dobj->namespace = NULL; /* may be set later */
585  dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
586  dobj->dump_contains = DUMP_COMPONENT_ALL; /* default assumption */
587  /* All objects have definitions; we may set more components bits later */
589  dobj->ext_member = false; /* default assumption */
590  dobj->depends_on_ext = false; /* default assumption */
591  dobj->dependencies = NULL;
592  dobj->nDeps = 0;
593  dobj->allocDeps = 0;
594 
595  /* Add object to dumpIdMap[], enlarging that array if need be */
596  while (dobj->dumpId >= allocedDumpIds)
597  {
598  int newAlloc;
599 
600  if (allocedDumpIds <= 0)
601  {
602  newAlloc = 256;
604  pg_malloc(newAlloc * sizeof(DumpableObject *));
605  }
606  else
607  {
608  newAlloc = allocedDumpIds * 2;
610  pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
611  }
612  memset(dumpIdMap + allocedDumpIds, 0,
613  (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
614  allocedDumpIds = newAlloc;
615  }
616  dumpIdMap[dobj->dumpId] = dobj;
617 
618  /* If it has a valid CatalogId, enter it into the hash table */
619  if (OidIsValid(dobj->catId.tableoid))
620  {
621  CatalogIdMapEntry *entry;
622  bool found;
623 
624  /* Initialize CatalogId hash table if not done yet */
625  if (catalogIdHash == NULL)
626  catalogIdHash = catalogid_create(CATALOGIDHASH_INITIAL_SIZE, NULL);
627 
628  entry = catalogid_insert(catalogIdHash, dobj->catId, &found);
629  if (!found)
630  {
631  entry->dobj = NULL;
632  entry->ext = NULL;
633  }
634  Assert(entry->dobj == NULL);
635  entry->dobj = dobj;
636  }
637 }
638 
639 /*
640  * Assign a DumpId that's not tied to a DumpableObject.
641  *
642  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
643  * participate in the sorting logic.
644  */
645 DumpId
647 {
648  return ++lastDumpId;
649 }
650 
651 /*
652  * Return the largest DumpId so far assigned
653  */
654 DumpId
656 {
657  return lastDumpId;
658 }
659 
660 /*
661  * Find a DumpableObject by dump ID
662  *
663  * Returns NULL for invalid ID
664  */
667 {
668  if (dumpId <= 0 || dumpId >= allocedDumpIds)
669  return NULL; /* out of range? */
670  return dumpIdMap[dumpId];
671 }
672 
673 /*
674  * Find a DumpableObject by catalog ID
675  *
676  * Returns NULL for unknown ID
677  */
680 {
681  CatalogIdMapEntry *entry;
682 
683  if (catalogIdHash == NULL)
684  return NULL; /* no objects exist yet */
685 
686  entry = catalogid_lookup(catalogIdHash, catalogId);
687  if (entry == NULL)
688  return NULL;
689  return entry->dobj;
690 }
691 
692 /*
693  * Build an array of pointers to all known dumpable objects
694  *
695  * This simply creates a modifiable copy of the internal map.
696  */
697 void
698 getDumpableObjects(DumpableObject ***objs, int *numObjs)
699 {
700  int i,
701  j;
702 
703  *objs = (DumpableObject **)
705  j = 0;
706  for (i = 1; i < allocedDumpIds; i++)
707  {
708  if (dumpIdMap[i])
709  (*objs)[j++] = dumpIdMap[i];
710  }
711  *numObjs = j;
712 }
713 
714 /*
715  * Add a dependency link to a DumpableObject
716  *
717  * Note: duplicate dependencies are currently not eliminated
718  */
719 void
721 {
722  if (dobj->nDeps >= dobj->allocDeps)
723  {
724  if (dobj->allocDeps <= 0)
725  {
726  dobj->allocDeps = 16;
727  dobj->dependencies = (DumpId *)
728  pg_malloc(dobj->allocDeps * sizeof(DumpId));
729  }
730  else
731  {
732  dobj->allocDeps *= 2;
733  dobj->dependencies = (DumpId *)
734  pg_realloc(dobj->dependencies,
735  dobj->allocDeps * sizeof(DumpId));
736  }
737  }
738  dobj->dependencies[dobj->nDeps++] = refId;
739 }
740 
741 /*
742  * Remove a dependency link from a DumpableObject
743  *
744  * If there are multiple links, all are removed
745  */
746 void
748 {
749  int i;
750  int j = 0;
751 
752  for (i = 0; i < dobj->nDeps; i++)
753  {
754  if (dobj->dependencies[i] != refId)
755  dobj->dependencies[j++] = dobj->dependencies[i];
756  }
757  dobj->nDeps = j;
758 }
759 
760 
761 /*
762  * findTableByOid
763  * finds the DumpableObject for the table with the given oid
764  * returns NULL if not found
765  */
766 TableInfo *
768 {
769  CatalogId catId;
770  DumpableObject *dobj;
771 
772  catId.tableoid = RelationRelationId;
773  catId.oid = oid;
774  dobj = findObjectByCatalogId(catId);
775  Assert(dobj == NULL || dobj->objType == DO_TABLE);
776  return (TableInfo *) dobj;
777 }
778 
779 /*
780  * findIndexByOid
781  * finds the DumpableObject for the index with the given oid
782  * returns NULL if not found
783  */
784 static IndxInfo *
786 {
787  CatalogId catId;
788  DumpableObject *dobj;
789 
790  catId.tableoid = RelationRelationId;
791  catId.oid = oid;
792  dobj = findObjectByCatalogId(catId);
793  Assert(dobj == NULL || dobj->objType == DO_INDEX);
794  return (IndxInfo *) dobj;
795 }
796 
797 /*
798  * findTypeByOid
799  * finds the DumpableObject for the type with the given oid
800  * returns NULL if not found
801  */
802 TypeInfo *
804 {
805  CatalogId catId;
806  DumpableObject *dobj;
807 
808  catId.tableoid = TypeRelationId;
809  catId.oid = oid;
810  dobj = findObjectByCatalogId(catId);
811  Assert(dobj == NULL ||
812  dobj->objType == DO_TYPE || dobj->objType == DO_DUMMY_TYPE);
813  return (TypeInfo *) dobj;
814 }
815 
816 /*
817  * findFuncByOid
818  * finds the DumpableObject for the function with the given oid
819  * returns NULL if not found
820  */
821 FuncInfo *
823 {
824  CatalogId catId;
825  DumpableObject *dobj;
826 
827  catId.tableoid = ProcedureRelationId;
828  catId.oid = oid;
829  dobj = findObjectByCatalogId(catId);
830  Assert(dobj == NULL || dobj->objType == DO_FUNC);
831  return (FuncInfo *) dobj;
832 }
833 
834 /*
835  * findOprByOid
836  * finds the DumpableObject for the operator with the given oid
837  * returns NULL if not found
838  */
839 OprInfo *
841 {
842  CatalogId catId;
843  DumpableObject *dobj;
844 
845  catId.tableoid = OperatorRelationId;
846  catId.oid = oid;
847  dobj = findObjectByCatalogId(catId);
848  Assert(dobj == NULL || dobj->objType == DO_OPERATOR);
849  return (OprInfo *) dobj;
850 }
851 
852 /*
853  * findCollationByOid
854  * finds the DumpableObject for the collation with the given oid
855  * returns NULL if not found
856  */
857 CollInfo *
859 {
860  CatalogId catId;
861  DumpableObject *dobj;
862 
863  catId.tableoid = CollationRelationId;
864  catId.oid = oid;
865  dobj = findObjectByCatalogId(catId);
866  Assert(dobj == NULL || dobj->objType == DO_COLLATION);
867  return (CollInfo *) dobj;
868 }
869 
870 /*
871  * findNamespaceByOid
872  * finds the DumpableObject for the namespace with the given oid
873  * returns NULL if not found
874  */
877 {
878  CatalogId catId;
879  DumpableObject *dobj;
880 
881  catId.tableoid = NamespaceRelationId;
882  catId.oid = oid;
883  dobj = findObjectByCatalogId(catId);
884  Assert(dobj == NULL || dobj->objType == DO_NAMESPACE);
885  return (NamespaceInfo *) dobj;
886 }
887 
888 /*
889  * findExtensionByOid
890  * finds the DumpableObject for the extension with the given oid
891  * returns NULL if not found
892  */
895 {
896  CatalogId catId;
897  DumpableObject *dobj;
898 
899  catId.tableoid = ExtensionRelationId;
900  catId.oid = oid;
901  dobj = findObjectByCatalogId(catId);
902  Assert(dobj == NULL || dobj->objType == DO_EXTENSION);
903  return (ExtensionInfo *) dobj;
904 }
905 
906 /*
907  * findPublicationByOid
908  * finds the DumpableObject for the publication with the given oid
909  * returns NULL if not found
910  */
913 {
914  CatalogId catId;
915  DumpableObject *dobj;
916 
917  catId.tableoid = PublicationRelationId;
918  catId.oid = oid;
919  dobj = findObjectByCatalogId(catId);
920  Assert(dobj == NULL || dobj->objType == DO_PUBLICATION);
921  return (PublicationInfo *) dobj;
922 }
923 
924 
925 /*
926  * recordExtensionMembership
927  * Record that the object identified by the given catalog ID
928  * belongs to the given extension
929  */
930 void
932 {
933  CatalogIdMapEntry *entry;
934  bool found;
935 
936  /* CatalogId hash table must exist, if we have an ExtensionInfo */
937  Assert(catalogIdHash != NULL);
938 
939  /* Add reference to CatalogId hash */
940  entry = catalogid_insert(catalogIdHash, catId, &found);
941  if (!found)
942  {
943  entry->dobj = NULL;
944  entry->ext = NULL;
945  }
946  Assert(entry->ext == NULL);
947  entry->ext = ext;
948 }
949 
950 /*
951  * findOwningExtension
952  * return owning extension for specified catalog ID, or NULL if none
953  */
956 {
957  CatalogIdMapEntry *entry;
958 
959  if (catalogIdHash == NULL)
960  return NULL; /* no objects exist yet */
961 
962  entry = catalogid_lookup(catalogIdHash, catalogId);
963  if (entry == NULL)
964  return NULL;
965  return entry->ext;
966 }
967 
968 
969 /*
970  * findParentsByOid
971  * find a table's parents in tblinfo[]
972  */
973 static void
975  InhInfo *inhinfo, int numInherits)
976 {
977  Oid oid = self->dobj.catId.oid;
978  int i,
979  j;
980  int numParents;
981 
982  numParents = 0;
983  for (i = 0; i < numInherits; i++)
984  {
985  if (inhinfo[i].inhrelid == oid)
986  numParents++;
987  }
988 
989  self->numParents = numParents;
990 
991  if (numParents > 0)
992  {
993  self->parents = (TableInfo **)
994  pg_malloc(sizeof(TableInfo *) * numParents);
995  j = 0;
996  for (i = 0; i < numInherits; i++)
997  {
998  if (inhinfo[i].inhrelid == oid)
999  {
1000  TableInfo *parent;
1001 
1002  parent = findTableByOid(inhinfo[i].inhparent);
1003  if (parent == NULL)
1004  pg_fatal("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
1005  inhinfo[i].inhparent,
1006  self->dobj.name,
1007  oid);
1008  self->parents[j++] = parent;
1009  }
1010  }
1011  }
1012  else
1013  self->parents = NULL;
1014 }
1015 
1016 /*
1017  * parseOidArray
1018  * parse a string of numbers delimited by spaces into a character array
1019  *
1020  * Note: actually this is used for both Oids and potentially-signed
1021  * attribute numbers. This should cause no trouble, but we could split
1022  * the function into two functions with different argument types if it does.
1023  */
1024 
1025 void
1026 parseOidArray(const char *str, Oid *array, int arraysize)
1027 {
1028  int j,
1029  argNum;
1030  char temp[100];
1031  char s;
1032 
1033  argNum = 0;
1034  j = 0;
1035  for (;;)
1036  {
1037  s = *str++;
1038  if (s == ' ' || s == '\0')
1039  {
1040  if (j > 0)
1041  {
1042  if (argNum >= arraysize)
1043  pg_fatal("could not parse numeric array \"%s\": too many numbers", str);
1044  temp[j] = '\0';
1045  array[argNum++] = atooid(temp);
1046  j = 0;
1047  }
1048  if (s == '\0')
1049  break;
1050  }
1051  else
1052  {
1053  if (!(isdigit((unsigned char) s) || s == '-') ||
1054  j >= sizeof(temp) - 1)
1055  pg_fatal("could not parse numeric array \"%s\": invalid character in number", str);
1056  temp[j++] = s;
1057  }
1058  }
1059 
1060  while (argNum < arraysize)
1061  array[argNum++] = InvalidOid;
1062 }
1063 
1064 
1065 /*
1066  * strInArray:
1067  * takes in a string and a string array and the number of elements in the
1068  * string array.
1069  * returns the index if the string is somewhere in the array, -1 otherwise
1070  */
1071 
1072 static int
1073 strInArray(const char *pattern, char **arr, int arr_size)
1074 {
1075  int i;
1076 
1077  for (i = 0; i < arr_size; i++)
1078  {
1079  if (strcmp(pattern, arr[i]) == 0)
1080  return i;
1081  }
1082  return -1;
1083 }
void recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
Definition: common.c:931
static void flagInhTables(Archive *fout, TableInfo *tbinfo, int numTables, InhInfo *inhinfo, int numInherits)
Definition: common.c:285
FuncInfo * findFuncByOid(Oid oid)
Definition: common.c:822
static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables)
NamespaceInfo * findNamespaceByOid(Oid oid)
Definition: common.c:876
ExtensionInfo * findOwningExtension(CatalogId catalogId)
Definition: common.c:955
TableInfo * getSchemaData(Archive *fout, int *numTablesPtr)
Definition: common.c:97
DumpableObject * findObjectByCatalogId(CatalogId catalogId)
Definition: common.c:679
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:720
static int allocedDumpIds
Definition: common.c:38
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition: common.c:666
void parseOidArray(const char *str, Oid *array, int arraysize)
Definition: common.c:1026
TableInfo * findTableByOid(Oid oid)
Definition: common.c:767
static IndxInfo * findIndexByOid(Oid oid)
Definition: common.c:785
static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
Definition: common.c:467
DumpId createDumpId(void)
Definition: common.c:646
ExtensionInfo * findExtensionByOid(Oid oid)
Definition: common.c:894
void AssignDumpId(DumpableObject *dobj)
Definition: common.c:580
DumpId getMaxDumpId(void)
Definition: common.c:655
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:1073
void getDumpableObjects(DumpableObject ***objs, int *numObjs)
Definition: common.c:698
CollInfo * findCollationByOid(Oid oid)
Definition: common.c:858
static catalogid_hash * catalogIdHash
Definition: common.c:80
TypeInfo * findTypeByOid(Oid oid)
Definition: common.c:803
OprInfo * findOprByOid(Oid oid)
Definition: common.c:840
struct _catalogIdMapEntry CatalogIdMapEntry
void removeObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:747
static void findParentsByOid(TableInfo *self, InhInfo *inhinfo, int numInherits)
Definition: common.c:974
static DumpId lastDumpId
Definition: common.c:39
PublicationInfo * findPublicationByOid(Oid oid)
Definition: common.c:912
unsigned int uint32
Definition: c.h:441
#define OidIsValid(objectId)
Definition: c.h:710
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#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:1068
int DumpId
Definition: pg_backup.h:265
#define pg_fatal(...)
NamespaceInfo * getNamespaces(Archive *fout, int *numNamespaces)
Definition: pg_dump.c:4966
void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7017
void getPublicationNamespaces(Archive *fout)
Definition: pg_dump.c:4055
DefaultACLInfo * getDefaultACLs(Archive *fout, int *numDefaultACLs)
Definition: pg_dump.c:9101
void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:3570
void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17368
ForeignServerInfo * getForeignServers(Archive *fout, int *numForeignServers)
Definition: pg_dump.c:9007
AccessMethodInfo * getAccessMethods(Archive *fout, int *numAccessMethods)
Definition: pg_dump.c:5557
FdwInfo * getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
Definition: pg_dump.c:8917
FuncInfo * getFuncs(Archive *fout, int *numFuncs)
Definition: pg_dump.c:5908
TSConfigInfo * getTSConfigurations(Archive *fout, int *numTSConfigs)
Definition: pg_dump.c:8852
ConvInfo * getConversions(Archive *fout, int *numConversions)
Definition: pg_dump.c:5489
void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:6526
void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:4142
AggInfo * getAggregates(Archive *fout, int *numAggs)
Definition: pg_dump.c:5762
void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:6635
TSDictInfo * getTSDictionaries(Archive *fout, int *numTSDicts)
Definition: pg_dump.c:8715
InhInfo * getInherits(Archive *fout, int *numInherits)
Definition: pg_dump.c:6589
OpfamilyInfo * getOpfamilies(Archive *fout, int *numOpfamilies)
Definition: pg_dump.c:5694
void getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition: pg_dump.c:8052
PublicationInfo * getPublications(Archive *fout, int *numPublications)
Definition: pg_dump.c:3855
TSTemplateInfo * getTSTemplates(Archive *fout, int *numTSTemplates)
Definition: pg_dump.c:8787
ProcLangInfo * getProcLangs(Archive *fout, int *numProcLangs)
Definition: pg_dump.c:7755
TypeInfo * getTypes(Archive *fout, int *numTypes)
Definition: pg_dump.c:5177
void getExtendedStatistics(Archive *fout)
Definition: pg_dump.c:6945
void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17461
OpclassInfo * getOpclasses(Archive *fout, int *numOpclasses)
Definition: pg_dump.c:5628
CollInfo * getCollations(Archive *fout, int *numCollations)
Definition: pg_dump.c:5421
void getSubscriptions(Archive *fout)
Definition: pg_dump.c:4396
ExtensionInfo * getExtensions(Archive *fout, int *numExtensions)
Definition: pg_dump.c:5102
TSParserInfo * getTSParsers(Archive *fout, int *numTSParsers)
Definition: pg_dump.c:8635
TransformInfo * getTransforms(Archive *fout, int *numTransforms)
Definition: pg_dump.c:7961
void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7398
OprInfo * getOperators(Archive *fout, int *numOprs)
Definition: pg_dump.c:5347
RuleInfo * getRules(Archive *fout, int *numRules)
Definition: pg_dump.c:7297
EventTriggerInfo * getEventTriggers(Archive *fout, int *numEventTriggers)
Definition: pg_dump.c:7668
TableInfo * getTables(Archive *fout, int *numTables)
Definition: pg_dump.c:6106
bool shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
Definition: pg_dump.c:8617
CastInfo * getCasts(Archive *fout, int *numCasts)
Definition: pg_dump.c:7845
#define DUMP_COMPONENT_ALL
Definition: pg_dump.h:103
#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:209
Oid tableoid
Definition: pg_backup.h:261
DumpableObject dobj
Definition: pg_dump.h:372
char * adef_expr
Definition: pg_dump.h:375
TableInfo * adtable
Definition: pg_dump.h:373
bool separate
Definition: pg_dump.h:376
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 load_via_partition_root
Definition: pg_backup.h:187
int binary_upgrade
Definition: pg_backup.h:161
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:413
DumpableObject dobj
Definition: pg_dump.h:411
IndxInfo * parentIdx
Definition: pg_dump.h:412
TableInfo * indextable
Definition: pg_dump.h:389
SimplePtrList partattaches
Definition: pg_dump.h:403
DumpableObject dobj
Definition: pg_dump.h:388
TableInfo * partitionTbl
Definition: pg_dump.h:367
DumpableObject dobj
Definition: pg_dump.h:365
TableInfo * parentTbl
Definition: pg_dump.h:366
bool ispartition
Definition: pg_dump.h:320
struct _indxInfo * indexes
Definition: pg_dump.h:357
DumpableObject dobj
Definition: pg_dump.h:283
int numParents
Definition: pg_dump.h:354
struct _tableInfo ** parents
Definition: pg_dump.h:355
char * attgenerated
Definition: pg_dump.h:335
bool * attisdropped
Definition: pg_dump.h:333
int numatts
Definition: pg_dump.h:326
struct _attrDefInfo ** attrdefs
Definition: pg_dump.h:346
bool * notnull
Definition: pg_dump.h:344
char ** attnames
Definition: pg_dump.h:327
char relkind
Definition: pg_dump.h:286
int numIndexes
Definition: pg_dump.h:356
bool * inhNotNull
Definition: pg_dump.h:345
Definition: type.h:90