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 *tblinfo, int numTables,
83  InhInfo *inhinfo, int numInherits);
84 static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables);
85 static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables);
86 static 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 = pg_malloc_object(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 = pg_malloc_object(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  }
605  else
606  {
607  newAlloc = allocedDumpIds * 2;
609  }
610  memset(dumpIdMap + allocedDumpIds, 0,
611  (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
612  allocedDumpIds = newAlloc;
613  }
614  dumpIdMap[dobj->dumpId] = dobj;
615 
616  /* If it has a valid CatalogId, enter it into the hash table */
617  if (OidIsValid(dobj->catId.tableoid))
618  {
619  CatalogIdMapEntry *entry;
620  bool found;
621 
622  /* Initialize CatalogId hash table if not done yet */
623  if (catalogIdHash == NULL)
624  catalogIdHash = catalogid_create(CATALOGIDHASH_INITIAL_SIZE, NULL);
625 
626  entry = catalogid_insert(catalogIdHash, dobj->catId, &found);
627  if (!found)
628  {
629  entry->dobj = NULL;
630  entry->ext = NULL;
631  }
632  Assert(entry->dobj == NULL);
633  entry->dobj = dobj;
634  }
635 }
636 
637 /*
638  * Assign a DumpId that's not tied to a DumpableObject.
639  *
640  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
641  * participate in the sorting logic.
642  */
643 DumpId
645 {
646  return ++lastDumpId;
647 }
648 
649 /*
650  * Return the largest DumpId so far assigned
651  */
652 DumpId
654 {
655  return lastDumpId;
656 }
657 
658 /*
659  * Find a DumpableObject by dump ID
660  *
661  * Returns NULL for invalid ID
662  */
665 {
666  if (dumpId <= 0 || dumpId >= allocedDumpIds)
667  return NULL; /* out of range? */
668  return dumpIdMap[dumpId];
669 }
670 
671 /*
672  * Find a DumpableObject by catalog ID
673  *
674  * Returns NULL for unknown ID
675  */
678 {
679  CatalogIdMapEntry *entry;
680 
681  if (catalogIdHash == NULL)
682  return NULL; /* no objects exist yet */
683 
684  entry = catalogid_lookup(catalogIdHash, catalogId);
685  if (entry == NULL)
686  return NULL;
687  return entry->dobj;
688 }
689 
690 /*
691  * Build an array of pointers to all known dumpable objects
692  *
693  * This simply creates a modifiable copy of the internal map.
694  */
695 void
696 getDumpableObjects(DumpableObject ***objs, int *numObjs)
697 {
698  int i,
699  j;
700 
702  j = 0;
703  for (i = 1; i < allocedDumpIds; i++)
704  {
705  if (dumpIdMap[i])
706  (*objs)[j++] = dumpIdMap[i];
707  }
708  *numObjs = j;
709 }
710 
711 /*
712  * Add a dependency link to a DumpableObject
713  *
714  * Note: duplicate dependencies are currently not eliminated
715  */
716 void
718 {
719  if (dobj->nDeps >= dobj->allocDeps)
720  {
721  if (dobj->allocDeps <= 0)
722  {
723  dobj->allocDeps = 16;
725  }
726  else
727  {
728  dobj->allocDeps *= 2;
730  DumpId, dobj->allocDeps);
731  }
732  }
733  dobj->dependencies[dobj->nDeps++] = refId;
734 }
735 
736 /*
737  * Remove a dependency link from a DumpableObject
738  *
739  * If there are multiple links, all are removed
740  */
741 void
743 {
744  int i;
745  int j = 0;
746 
747  for (i = 0; i < dobj->nDeps; i++)
748  {
749  if (dobj->dependencies[i] != refId)
750  dobj->dependencies[j++] = dobj->dependencies[i];
751  }
752  dobj->nDeps = j;
753 }
754 
755 
756 /*
757  * findTableByOid
758  * finds the DumpableObject for the table with the given oid
759  * returns NULL if not found
760  */
761 TableInfo *
763 {
764  CatalogId catId;
765  DumpableObject *dobj;
766 
767  catId.tableoid = RelationRelationId;
768  catId.oid = oid;
769  dobj = findObjectByCatalogId(catId);
770  Assert(dobj == NULL || dobj->objType == DO_TABLE);
771  return (TableInfo *) dobj;
772 }
773 
774 /*
775  * findIndexByOid
776  * finds the DumpableObject for the index with the given oid
777  * returns NULL if not found
778  */
779 static IndxInfo *
781 {
782  CatalogId catId;
783  DumpableObject *dobj;
784 
785  catId.tableoid = RelationRelationId;
786  catId.oid = oid;
787  dobj = findObjectByCatalogId(catId);
788  Assert(dobj == NULL || dobj->objType == DO_INDEX);
789  return (IndxInfo *) dobj;
790 }
791 
792 /*
793  * findTypeByOid
794  * finds the DumpableObject for the type with the given oid
795  * returns NULL if not found
796  */
797 TypeInfo *
799 {
800  CatalogId catId;
801  DumpableObject *dobj;
802 
803  catId.tableoid = TypeRelationId;
804  catId.oid = oid;
805  dobj = findObjectByCatalogId(catId);
806  Assert(dobj == NULL ||
807  dobj->objType == DO_TYPE || dobj->objType == DO_DUMMY_TYPE);
808  return (TypeInfo *) dobj;
809 }
810 
811 /*
812  * findFuncByOid
813  * finds the DumpableObject for the function with the given oid
814  * returns NULL if not found
815  */
816 FuncInfo *
818 {
819  CatalogId catId;
820  DumpableObject *dobj;
821 
822  catId.tableoid = ProcedureRelationId;
823  catId.oid = oid;
824  dobj = findObjectByCatalogId(catId);
825  Assert(dobj == NULL || dobj->objType == DO_FUNC);
826  return (FuncInfo *) dobj;
827 }
828 
829 /*
830  * findOprByOid
831  * finds the DumpableObject for the operator with the given oid
832  * returns NULL if not found
833  */
834 OprInfo *
836 {
837  CatalogId catId;
838  DumpableObject *dobj;
839 
840  catId.tableoid = OperatorRelationId;
841  catId.oid = oid;
842  dobj = findObjectByCatalogId(catId);
843  Assert(dobj == NULL || dobj->objType == DO_OPERATOR);
844  return (OprInfo *) dobj;
845 }
846 
847 /*
848  * findCollationByOid
849  * finds the DumpableObject for the collation with the given oid
850  * returns NULL if not found
851  */
852 CollInfo *
854 {
855  CatalogId catId;
856  DumpableObject *dobj;
857 
858  catId.tableoid = CollationRelationId;
859  catId.oid = oid;
860  dobj = findObjectByCatalogId(catId);
861  Assert(dobj == NULL || dobj->objType == DO_COLLATION);
862  return (CollInfo *) dobj;
863 }
864 
865 /*
866  * findNamespaceByOid
867  * finds the DumpableObject for the namespace with the given oid
868  * returns NULL if not found
869  */
872 {
873  CatalogId catId;
874  DumpableObject *dobj;
875 
876  catId.tableoid = NamespaceRelationId;
877  catId.oid = oid;
878  dobj = findObjectByCatalogId(catId);
879  Assert(dobj == NULL || dobj->objType == DO_NAMESPACE);
880  return (NamespaceInfo *) dobj;
881 }
882 
883 /*
884  * findExtensionByOid
885  * finds the DumpableObject for the extension with the given oid
886  * returns NULL if not found
887  */
890 {
891  CatalogId catId;
892  DumpableObject *dobj;
893 
894  catId.tableoid = ExtensionRelationId;
895  catId.oid = oid;
896  dobj = findObjectByCatalogId(catId);
897  Assert(dobj == NULL || dobj->objType == DO_EXTENSION);
898  return (ExtensionInfo *) dobj;
899 }
900 
901 /*
902  * findPublicationByOid
903  * finds the DumpableObject for the publication with the given oid
904  * returns NULL if not found
905  */
908 {
909  CatalogId catId;
910  DumpableObject *dobj;
911 
912  catId.tableoid = PublicationRelationId;
913  catId.oid = oid;
914  dobj = findObjectByCatalogId(catId);
915  Assert(dobj == NULL || dobj->objType == DO_PUBLICATION);
916  return (PublicationInfo *) dobj;
917 }
918 
919 
920 /*
921  * recordExtensionMembership
922  * Record that the object identified by the given catalog ID
923  * belongs to the given extension
924  */
925 void
927 {
928  CatalogIdMapEntry *entry;
929  bool found;
930 
931  /* CatalogId hash table must exist, if we have an ExtensionInfo */
932  Assert(catalogIdHash != NULL);
933 
934  /* Add reference to CatalogId hash */
935  entry = catalogid_insert(catalogIdHash, catId, &found);
936  if (!found)
937  {
938  entry->dobj = NULL;
939  entry->ext = NULL;
940  }
941  Assert(entry->ext == NULL);
942  entry->ext = ext;
943 }
944 
945 /*
946  * findOwningExtension
947  * return owning extension for specified catalog ID, or NULL if none
948  */
951 {
952  CatalogIdMapEntry *entry;
953 
954  if (catalogIdHash == NULL)
955  return NULL; /* no objects exist yet */
956 
957  entry = catalogid_lookup(catalogIdHash, catalogId);
958  if (entry == NULL)
959  return NULL;
960  return entry->ext;
961 }
962 
963 
964 /*
965  * findParentsByOid
966  * find a table's parents in tblinfo[]
967  */
968 static void
970  InhInfo *inhinfo, int numInherits)
971 {
972  Oid oid = self->dobj.catId.oid;
973  int i,
974  j;
975  int numParents;
976 
977  numParents = 0;
978  for (i = 0; i < numInherits; i++)
979  {
980  if (inhinfo[i].inhrelid == oid)
981  numParents++;
982  }
983 
984  self->numParents = numParents;
985 
986  if (numParents > 0)
987  {
988  self->parents = pg_malloc_array(TableInfo *, numParents);
989  j = 0;
990  for (i = 0; i < numInherits; i++)
991  {
992  if (inhinfo[i].inhrelid == oid)
993  {
994  TableInfo *parent;
995 
996  parent = findTableByOid(inhinfo[i].inhparent);
997  if (parent == NULL)
998  pg_fatal("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
999  inhinfo[i].inhparent,
1000  self->dobj.name,
1001  oid);
1002  self->parents[j++] = parent;
1003  }
1004  }
1005  }
1006  else
1007  self->parents = NULL;
1008 }
1009 
1010 /*
1011  * parseOidArray
1012  * parse a string of numbers delimited by spaces into a character array
1013  *
1014  * Note: actually this is used for both Oids and potentially-signed
1015  * attribute numbers. This should cause no trouble, but we could split
1016  * the function into two functions with different argument types if it does.
1017  */
1018 
1019 void
1020 parseOidArray(const char *str, Oid *array, int arraysize)
1021 {
1022  int j,
1023  argNum;
1024  char temp[100];
1025  char s;
1026 
1027  argNum = 0;
1028  j = 0;
1029  for (;;)
1030  {
1031  s = *str++;
1032  if (s == ' ' || s == '\0')
1033  {
1034  if (j > 0)
1035  {
1036  if (argNum >= arraysize)
1037  pg_fatal("could not parse numeric array \"%s\": too many numbers", str);
1038  temp[j] = '\0';
1039  array[argNum++] = atooid(temp);
1040  j = 0;
1041  }
1042  if (s == '\0')
1043  break;
1044  }
1045  else
1046  {
1047  if (!(isdigit((unsigned char) s) || s == '-') ||
1048  j >= sizeof(temp) - 1)
1049  pg_fatal("could not parse numeric array \"%s\": invalid character in number", str);
1050  temp[j++] = s;
1051  }
1052  }
1053 
1054  while (argNum < arraysize)
1055  array[argNum++] = InvalidOid;
1056 }
1057 
1058 
1059 /*
1060  * strInArray:
1061  * takes in a string and a string array and the number of elements in the
1062  * string array.
1063  * returns the index if the string is somewhere in the array, -1 otherwise
1064  */
1065 
1066 static int
1067 strInArray(const char *pattern, char **arr, int arr_size)
1068 {
1069  int i;
1070 
1071  for (i = 0; i < arr_size; i++)
1072  {
1073  if (strcmp(pattern, arr[i]) == 0)
1074  return i;
1075  }
1076  return -1;
1077 }
void recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
Definition: common.c:926
FuncInfo * findFuncByOid(Oid oid)
Definition: common.c:817
static void flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables, InhInfo *inhinfo, int numInherits)
Definition: common.c:285
static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables)
NamespaceInfo * findNamespaceByOid(Oid oid)
Definition: common.c:871
ExtensionInfo * findOwningExtension(CatalogId catalogId)
Definition: common.c:950
TableInfo * getSchemaData(Archive *fout, int *numTablesPtr)
Definition: common.c:97
DumpableObject * findObjectByCatalogId(CatalogId catalogId)
Definition: common.c:677
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:717
static int allocedDumpIds
Definition: common.c:38
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition: common.c:664
void parseOidArray(const char *str, Oid *array, int arraysize)
Definition: common.c:1020
TableInfo * findTableByOid(Oid oid)
Definition: common.c:762
static IndxInfo * findIndexByOid(Oid oid)
Definition: common.c:780
static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
Definition: common.c:467
DumpId createDumpId(void)
Definition: common.c:644
ExtensionInfo * findExtensionByOid(Oid oid)
Definition: common.c:889
void AssignDumpId(DumpableObject *dobj)
Definition: common.c:580
DumpId getMaxDumpId(void)
Definition: common.c:653
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:1067
void getDumpableObjects(DumpableObject ***objs, int *numObjs)
Definition: common.c:696
CollInfo * findCollationByOid(Oid oid)
Definition: common.c:853
static catalogid_hash * catalogIdHash
Definition: common.c:80
TypeInfo * findTypeByOid(Oid oid)
Definition: common.c:798
OprInfo * findOprByOid(Oid oid)
Definition: common.c:835
struct _catalogIdMapEntry CatalogIdMapEntry
void removeObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:742
static void findParentsByOid(TableInfo *self, InhInfo *inhinfo, int numInherits)
Definition: common.c:969
static DumpId lastDumpId
Definition: common.c:39
PublicationInfo * findPublicationByOid(Oid oid)
Definition: common.c:907
unsigned int uint32
Definition: c.h:442
#define OidIsValid(objectId)
Definition: c.h:711
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:1199
int DumpId
Definition: pg_backup.h:267
#define pg_fatal(...)
NamespaceInfo * getNamespaces(Archive *fout, int *numNamespaces)
Definition: pg_dump.c:5037
void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7088
void getPublicationNamespaces(Archive *fout)
Definition: pg_dump.c:4116
DefaultACLInfo * getDefaultACLs(Archive *fout, int *numDefaultACLs)
Definition: pg_dump.c:9172
void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:3631
void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17464
ForeignServerInfo * getForeignServers(Archive *fout, int *numForeignServers)
Definition: pg_dump.c:9078
AccessMethodInfo * getAccessMethods(Archive *fout, int *numAccessMethods)
Definition: pg_dump.c:5628
FdwInfo * getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
Definition: pg_dump.c:8988
FuncInfo * getFuncs(Archive *fout, int *numFuncs)
Definition: pg_dump.c:5979
TSConfigInfo * getTSConfigurations(Archive *fout, int *numTSConfigs)
Definition: pg_dump.c:8923
ConvInfo * getConversions(Archive *fout, int *numConversions)
Definition: pg_dump.c:5560
void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:6597
void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:4203
AggInfo * getAggregates(Archive *fout, int *numAggs)
Definition: pg_dump.c:5833
void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:6706
TSDictInfo * getTSDictionaries(Archive *fout, int *numTSDicts)
Definition: pg_dump.c:8786
InhInfo * getInherits(Archive *fout, int *numInherits)
Definition: pg_dump.c:6660
OpfamilyInfo * getOpfamilies(Archive *fout, int *numOpfamilies)
Definition: pg_dump.c:5765
void getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition: pg_dump.c:8123
PublicationInfo * getPublications(Archive *fout, int *numPublications)
Definition: pg_dump.c:3916
TSTemplateInfo * getTSTemplates(Archive *fout, int *numTSTemplates)
Definition: pg_dump.c:8858
ProcLangInfo * getProcLangs(Archive *fout, int *numProcLangs)
Definition: pg_dump.c:7826
TypeInfo * getTypes(Archive *fout, int *numTypes)
Definition: pg_dump.c:5248
void getExtendedStatistics(Archive *fout)
Definition: pg_dump.c:7016
void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17557
OpclassInfo * getOpclasses(Archive *fout, int *numOpclasses)
Definition: pg_dump.c:5699
CollInfo * getCollations(Archive *fout, int *numCollations)
Definition: pg_dump.c:5492
void getSubscriptions(Archive *fout)
Definition: pg_dump.c:4457
ExtensionInfo * getExtensions(Archive *fout, int *numExtensions)
Definition: pg_dump.c:5173
TSParserInfo * getTSParsers(Archive *fout, int *numTSParsers)
Definition: pg_dump.c:8706
TransformInfo * getTransforms(Archive *fout, int *numTransforms)
Definition: pg_dump.c:8032
void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7469
OprInfo * getOperators(Archive *fout, int *numOprs)
Definition: pg_dump.c:5418
RuleInfo * getRules(Archive *fout, int *numRules)
Definition: pg_dump.c:7368
EventTriggerInfo * getEventTriggers(Archive *fout, int *numEventTriggers)
Definition: pg_dump.c:7739
TableInfo * getTables(Archive *fout, int *numTables)
Definition: pg_dump.c:6177
bool shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
Definition: pg_dump.c:8688
CastInfo * getCasts(Archive *fout, int *numCasts)
Definition: pg_dump.c:7916
#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:211
Oid tableoid
Definition: pg_backup.h:263
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:189
int binary_upgrade
Definition: pg_backup.h:163
DumpComponents dump
Definition: pg_dump.h:138
char * name
Definition: pg_dump.h:137
DumpId * dependencies
Definition: pg_dump.h:144
DumpId dumpId
Definition: pg_dump.h:136
bool ext_member
Definition: pg_dump.h:142
DumpComponents components
Definition: pg_dump.h:141
DumpableObjectType objType
Definition: pg_dump.h:134
CatalogId catId
Definition: pg_dump.h:135
DumpComponents dump_contains
Definition: pg_dump.h:140
bool depends_on_ext
Definition: pg_dump.h:143
IndxInfo * partitionIdx
Definition: pg_dump.h: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:95