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-2020, 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 "fe_utils/string_utils.h"
22 #include "pg_backup_archiver.h"
23 #include "pg_backup_utils.h"
24 #include "pg_dump.h"
25 
26 /*
27  * Variables for mapping DumpId to DumpableObject
28  */
29 static DumpableObject **dumpIdMap = NULL;
30 static int allocedDumpIds = 0;
31 static DumpId lastDumpId = 0;
32 
33 /*
34  * Variables for mapping CatalogId to DumpableObject
35  */
36 static bool catalogIdMapValid = false;
37 static DumpableObject **catalogIdMap = NULL;
38 static int numCatalogIds = 0;
39 
40 /*
41  * These variables are static to avoid the notational cruft of having to pass
42  * them into findTableByOid() and friends. For each of these arrays, we build
43  * a sorted-by-OID index array immediately after the objects are fetched,
44  * and then we use binary search in findTableByOid() and friends. (qsort'ing
45  * the object arrays themselves would be simpler, but it doesn't work because
46  * pg_dump.c may have already established pointers between items.)
47  */
55 static int numTables;
56 static int numTypes;
57 static int numFuncs;
58 static int numOperators;
59 static int numCollations;
60 static int numNamespaces;
61 static int numExtensions;
62 
63 /* This is an array of object identities, not actual DumpableObjects */
65 static int numextmembers;
66 
67 static void flagInhTables(Archive *fout, TableInfo *tbinfo, int numTables,
68  InhInfo *inhinfo, int numInherits);
69 static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables);
70 static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables);
71 static DumpableObject **buildIndexArray(void *objArray, int numObjs,
72  Size objSize);
73 static int DOCatalogIdCompare(const void *p1, const void *p2);
74 static int ExtensionMemberIdCompare(const void *p1, const void *p2);
75 static void findParentsByOid(TableInfo *self,
76  InhInfo *inhinfo, int numInherits);
77 static int strInArray(const char *pattern, char **arr, int arr_size);
78 static IndxInfo *findIndexByOid(Oid oid, DumpableObject **idxinfoindex,
79  int numIndexes);
80 
81 
82 /*
83  * getSchemaData
84  * Collect information about all potentially dumpable objects
85  */
86 TableInfo *
87 getSchemaData(Archive *fout, int *numTablesPtr)
88 {
89  TableInfo *tblinfo;
91  FuncInfo *funinfo;
92  OprInfo *oprinfo;
93  CollInfo *collinfo;
94  NamespaceInfo *nspinfo;
95  ExtensionInfo *extinfo;
96  InhInfo *inhinfo;
97  int numAggregates;
98  int numInherits;
99  int numRules;
100  int numProcLangs;
101  int numCasts;
102  int numTransforms;
103  int numAccessMethods;
104  int numOpclasses;
105  int numOpfamilies;
106  int numConversions;
107  int numTSParsers;
108  int numTSTemplates;
109  int numTSDicts;
110  int numTSConfigs;
111  int numForeignDataWrappers;
112  int numForeignServers;
113  int numDefaultACLs;
114  int numEventTriggers;
115 
116  /*
117  * We must read extensions and extension membership info first, because
118  * extension membership needs to be consultable during decisions about
119  * whether other objects are to be dumped.
120  */
121  pg_log_info("reading extensions");
122  extinfo = getExtensions(fout, &numExtensions);
123  extinfoindex = buildIndexArray(extinfo, numExtensions, sizeof(ExtensionInfo));
124 
125  pg_log_info("identifying extension members");
126  getExtensionMembership(fout, extinfo, numExtensions);
127 
128  pg_log_info("reading schemas");
129  nspinfo = getNamespaces(fout, &numNamespaces);
130  nspinfoindex = buildIndexArray(nspinfo, numNamespaces, sizeof(NamespaceInfo));
131 
132  /*
133  * getTables should be done as soon as possible, so as to minimize the
134  * window between starting our transaction and acquiring per-table locks.
135  * However, we have to do getNamespaces first because the tables get
136  * linked to their containing namespaces during getTables.
137  */
138  pg_log_info("reading user-defined tables");
139  tblinfo = getTables(fout, &numTables);
140  tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
141 
142  /* Do this after we've built tblinfoindex */
143  getOwnedSeqs(fout, tblinfo, numTables);
144 
145  pg_log_info("reading user-defined functions");
146  funinfo = getFuncs(fout, &numFuncs);
147  funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
148 
149  /* this must be after getTables and getFuncs */
150  pg_log_info("reading user-defined types");
151  typinfo = getTypes(fout, &numTypes);
152  typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
153 
154  /* this must be after getFuncs, too */
155  pg_log_info("reading procedural languages");
156  getProcLangs(fout, &numProcLangs);
157 
158  pg_log_info("reading user-defined aggregate functions");
159  getAggregates(fout, &numAggregates);
160 
161  pg_log_info("reading user-defined operators");
162  oprinfo = getOperators(fout, &numOperators);
163  oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
164 
165  pg_log_info("reading user-defined access methods");
166  getAccessMethods(fout, &numAccessMethods);
167 
168  pg_log_info("reading user-defined operator classes");
169  getOpclasses(fout, &numOpclasses);
170 
171  pg_log_info("reading user-defined operator families");
172  getOpfamilies(fout, &numOpfamilies);
173 
174  pg_log_info("reading user-defined text search parsers");
175  getTSParsers(fout, &numTSParsers);
176 
177  pg_log_info("reading user-defined text search templates");
178  getTSTemplates(fout, &numTSTemplates);
179 
180  pg_log_info("reading user-defined text search dictionaries");
181  getTSDictionaries(fout, &numTSDicts);
182 
183  pg_log_info("reading user-defined text search configurations");
184  getTSConfigurations(fout, &numTSConfigs);
185 
186  pg_log_info("reading user-defined foreign-data wrappers");
187  getForeignDataWrappers(fout, &numForeignDataWrappers);
188 
189  pg_log_info("reading user-defined foreign servers");
190  getForeignServers(fout, &numForeignServers);
191 
192  pg_log_info("reading default privileges");
193  getDefaultACLs(fout, &numDefaultACLs);
194 
195  pg_log_info("reading user-defined collations");
196  collinfo = getCollations(fout, &numCollations);
197  collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
198 
199  pg_log_info("reading user-defined conversions");
200  getConversions(fout, &numConversions);
201 
202  pg_log_info("reading type casts");
203  getCasts(fout, &numCasts);
204 
205  pg_log_info("reading transforms");
206  getTransforms(fout, &numTransforms);
207 
208  pg_log_info("reading table inheritance information");
209  inhinfo = getInherits(fout, &numInherits);
210 
211  pg_log_info("reading event triggers");
212  getEventTriggers(fout, &numEventTriggers);
213 
214  /* Identify extension configuration tables that should be dumped */
215  pg_log_info("finding extension tables");
216  processExtensionTables(fout, extinfo, numExtensions);
217 
218  /* Link tables to parents, mark parents of target tables interesting */
219  pg_log_info("finding inheritance relationships");
220  flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
221 
222  pg_log_info("reading column info for interesting tables");
223  getTableAttrs(fout, tblinfo, numTables);
224 
225  pg_log_info("flagging inherited columns in subtables");
226  flagInhAttrs(fout->dopt, tblinfo, numTables);
227 
228  pg_log_info("reading indexes");
229  getIndexes(fout, tblinfo, numTables);
230 
231  pg_log_info("flagging indexes in partitioned tables");
232  flagInhIndexes(fout, tblinfo, numTables);
233 
234  pg_log_info("reading extended statistics");
235  getExtendedStatistics(fout);
236 
237  pg_log_info("reading constraints");
238  getConstraints(fout, tblinfo, numTables);
239 
240  pg_log_info("reading triggers");
241  getTriggers(fout, tblinfo, numTables);
242 
243  pg_log_info("reading rewrite rules");
244  getRules(fout, &numRules);
245 
246  pg_log_info("reading policies");
247  getPolicies(fout, tblinfo, numTables);
248 
249  pg_log_info("reading publications");
250  getPublications(fout);
251 
252  pg_log_info("reading publication membership");
253  getPublicationTables(fout, tblinfo, numTables);
254 
255  pg_log_info("reading subscriptions");
256  getSubscriptions(fout);
257 
258  *numTablesPtr = numTables;
259  return tblinfo;
260 }
261 
262 /* flagInhTables -
263  * Fill in parent link fields of tables for which we need that information,
264  * and mark parents of target tables as interesting
265  *
266  * Note that only direct ancestors of targets are marked interesting.
267  * This is sufficient; we don't much care whether they inherited their
268  * attributes or not.
269  *
270  * modifies tblinfo
271  */
272 static void
274  InhInfo *inhinfo, int numInherits)
275 {
276  DumpOptions *dopt = fout->dopt;
277  int i,
278  j;
279 
280  for (i = 0; i < numTables; i++)
281  {
282  bool find_parents = true;
283  bool mark_parents = true;
284 
285  /* Some kinds never have parents */
286  if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
287  tblinfo[i].relkind == RELKIND_VIEW ||
288  tblinfo[i].relkind == RELKIND_MATVIEW)
289  continue;
290 
291  /*
292  * Normally, we don't bother computing anything for non-target tables,
293  * but if load-via-partition-root is specified, we gather information
294  * on every partition in the system so that getRootTableInfo can trace
295  * from any given to leaf partition all the way up to the root. (We
296  * don't need to mark them as interesting for getTableAttrs, though.)
297  */
298  if (!tblinfo[i].dobj.dump)
299  {
300  mark_parents = false;
301 
302  if (!dopt->load_via_partition_root ||
303  !tblinfo[i].ispartition)
304  find_parents = false;
305  }
306 
307  /* If needed, find all the immediate parent tables. */
308  if (find_parents)
309  findParentsByOid(&tblinfo[i], inhinfo, numInherits);
310 
311  /*
312  * If needed, mark the parents as interesting for getTableAttrs and
313  * getIndexes.
314  */
315  if (mark_parents)
316  {
317  int numParents = tblinfo[i].numParents;
318  TableInfo **parents = tblinfo[i].parents;
319 
320  for (j = 0; j < numParents; j++)
321  parents[j]->interesting = true;
322  }
323  }
324 }
325 
326 /*
327  * flagInhIndexes -
328  * Create IndexAttachInfo objects for partitioned indexes, and add
329  * appropriate dependency links.
330  */
331 static void
333 {
334  int i,
335  j,
336  k;
337  DumpableObject ***parentIndexArray;
338 
339  parentIndexArray = (DumpableObject ***)
340  pg_malloc0(getMaxDumpId() * sizeof(DumpableObject **));
341 
342  for (i = 0; i < numTables; i++)
343  {
344  TableInfo *parenttbl;
345  IndexAttachInfo *attachinfo;
346 
347  if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
348  continue;
349 
350  Assert(tblinfo[i].numParents == 1);
351  parenttbl = tblinfo[i].parents[0];
352 
353  /*
354  * We need access to each parent table's index list, but there is no
355  * index to cover them outside of this function. To avoid having to
356  * sort every parent table's indexes each time we come across each of
357  * its partitions, create an indexed array for each parent the first
358  * time it is required.
359  */
360  if (parentIndexArray[parenttbl->dobj.dumpId] == NULL)
361  parentIndexArray[parenttbl->dobj.dumpId] =
362  buildIndexArray(parenttbl->indexes,
363  parenttbl->numIndexes,
364  sizeof(IndxInfo));
365 
366  attachinfo = (IndexAttachInfo *)
367  pg_malloc0(tblinfo[i].numIndexes * sizeof(IndexAttachInfo));
368  for (j = 0, k = 0; j < tblinfo[i].numIndexes; j++)
369  {
370  IndxInfo *index = &(tblinfo[i].indexes[j]);
371  IndxInfo *parentidx;
372 
373  if (index->parentidx == 0)
374  continue;
375 
376  parentidx = findIndexByOid(index->parentidx,
377  parentIndexArray[parenttbl->dobj.dumpId],
378  parenttbl->numIndexes);
379  if (parentidx == NULL)
380  continue;
381 
382  attachinfo[k].dobj.objType = DO_INDEX_ATTACH;
383  attachinfo[k].dobj.catId.tableoid = 0;
384  attachinfo[k].dobj.catId.oid = 0;
385  AssignDumpId(&attachinfo[k].dobj);
386  attachinfo[k].dobj.name = pg_strdup(index->dobj.name);
387  attachinfo[k].dobj.namespace = index->indextable->dobj.namespace;
388  attachinfo[k].parentIdx = parentidx;
389  attachinfo[k].partitionIdx = index;
390 
391  /*
392  * We must state the DO_INDEX_ATTACH object's dependencies
393  * explicitly, since it will not match anything in pg_depend.
394  *
395  * Give it dependencies on both the partition index and the parent
396  * index, so that it will not be executed till both of those
397  * exist. (There's no need to care what order those are created
398  * in.)
399  *
400  * In addition, give it dependencies on the indexes' underlying
401  * tables. This does nothing of great value so far as serial
402  * restore ordering goes, but it ensures that a parallel restore
403  * will not try to run the ATTACH concurrently with other
404  * operations on those tables.
405  */
406  addObjectDependency(&attachinfo[k].dobj, index->dobj.dumpId);
407  addObjectDependency(&attachinfo[k].dobj, parentidx->dobj.dumpId);
408  addObjectDependency(&attachinfo[k].dobj,
409  index->indextable->dobj.dumpId);
410  addObjectDependency(&attachinfo[k].dobj,
411  parentidx->indextable->dobj.dumpId);
412 
413  /* keep track of the list of partitions in the parent index */
414  simple_ptr_list_append(&parentidx->partattaches, &attachinfo[k].dobj);
415 
416  k++;
417  }
418  }
419 
420  for (i = 0; i < numTables; i++)
421  if (parentIndexArray[i])
422  pg_free(parentIndexArray[i]);
423  pg_free(parentIndexArray);
424 }
425 
426 /* flagInhAttrs -
427  * for each dumpable table in tblinfo, flag its inherited attributes
428  *
429  * What we need to do here is detect child columns that inherit NOT NULL
430  * bits from their parents (so that we needn't specify that again for the
431  * child) and child columns that have DEFAULT NULL when their parents had
432  * some non-null default. In the latter case, we make up a dummy AttrDefInfo
433  * object so that we'll correctly emit the necessary DEFAULT NULL clause;
434  * otherwise the backend will apply an inherited default to the column.
435  *
436  * modifies tblinfo
437  */
438 static void
440 {
441  int i,
442  j,
443  k;
444 
445  for (i = 0; i < numTables; i++)
446  {
447  TableInfo *tbinfo = &(tblinfo[i]);
448  int numParents;
449  TableInfo **parents;
450 
451  /* Some kinds never have parents */
452  if (tbinfo->relkind == RELKIND_SEQUENCE ||
453  tbinfo->relkind == RELKIND_VIEW ||
454  tbinfo->relkind == RELKIND_MATVIEW)
455  continue;
456 
457  /* Don't bother computing anything for non-target tables, either */
458  if (!tbinfo->dobj.dump)
459  continue;
460 
461  numParents = tbinfo->numParents;
462  parents = tbinfo->parents;
463 
464  if (numParents == 0)
465  continue; /* nothing to see here, move along */
466 
467  /* For each column, search for matching column names in parent(s) */
468  for (j = 0; j < tbinfo->numatts; j++)
469  {
470  bool foundNotNull; /* Attr was NOT NULL in a parent */
471  bool foundDefault; /* Found a default in a parent */
472 
473  /* no point in examining dropped columns */
474  if (tbinfo->attisdropped[j])
475  continue;
476 
477  foundNotNull = false;
478  foundDefault = false;
479  for (k = 0; k < numParents; k++)
480  {
481  TableInfo *parent = parents[k];
482  int inhAttrInd;
483 
484  inhAttrInd = strInArray(tbinfo->attnames[j],
485  parent->attnames,
486  parent->numatts);
487  if (inhAttrInd >= 0)
488  {
489  foundNotNull |= parent->notnull[inhAttrInd];
490  foundDefault |= (parent->attrdefs[inhAttrInd] != NULL);
491  }
492  }
493 
494  /* Remember if we found inherited NOT NULL */
495  tbinfo->inhNotNull[j] = foundNotNull;
496 
497  /* Manufacture a DEFAULT NULL clause if necessary */
498  if (foundDefault && tbinfo->attrdefs[j] == NULL)
499  {
500  AttrDefInfo *attrDef;
501 
502  attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo));
503  attrDef->dobj.objType = DO_ATTRDEF;
504  attrDef->dobj.catId.tableoid = 0;
505  attrDef->dobj.catId.oid = 0;
506  AssignDumpId(&attrDef->dobj);
507  attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
508  attrDef->dobj.namespace = tbinfo->dobj.namespace;
509  attrDef->dobj.dump = tbinfo->dobj.dump;
510 
511  attrDef->adtable = tbinfo;
512  attrDef->adnum = j + 1;
513  attrDef->adef_expr = pg_strdup("NULL");
514 
515  /* Will column be dumped explicitly? */
516  if (shouldPrintColumn(dopt, tbinfo, j))
517  {
518  attrDef->separate = false;
519  /* No dependency needed: NULL cannot have dependencies */
520  }
521  else
522  {
523  /* column will be suppressed, print default separately */
524  attrDef->separate = true;
525  /* ensure it comes out after the table */
526  addObjectDependency(&attrDef->dobj,
527  tbinfo->dobj.dumpId);
528  }
529 
530  tbinfo->attrdefs[j] = attrDef;
531  }
532  }
533  }
534 }
535 
536 /*
537  * AssignDumpId
538  * Given a newly-created dumpable object, assign a dump ID,
539  * and enter the object into the lookup table.
540  *
541  * The caller is expected to have filled in objType and catId,
542  * but not any of the other standard fields of a DumpableObject.
543  */
544 void
546 {
547  dobj->dumpId = ++lastDumpId;
548  dobj->name = NULL; /* must be set later */
549  dobj->namespace = NULL; /* may be set later */
550  dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
551  dobj->ext_member = false; /* default assumption */
552  dobj->depends_on_ext = false; /* default assumption */
553  dobj->dependencies = NULL;
554  dobj->nDeps = 0;
555  dobj->allocDeps = 0;
556 
557  while (dobj->dumpId >= allocedDumpIds)
558  {
559  int newAlloc;
560 
561  if (allocedDumpIds <= 0)
562  {
563  newAlloc = 256;
564  dumpIdMap = (DumpableObject **)
565  pg_malloc(newAlloc * sizeof(DumpableObject *));
566  }
567  else
568  {
569  newAlloc = allocedDumpIds * 2;
570  dumpIdMap = (DumpableObject **)
571  pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
572  }
573  memset(dumpIdMap + allocedDumpIds, 0,
574  (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
575  allocedDumpIds = newAlloc;
576  }
577  dumpIdMap[dobj->dumpId] = dobj;
578 
579  /* mark catalogIdMap invalid, but don't rebuild it yet */
580  catalogIdMapValid = false;
581 }
582 
583 /*
584  * Assign a DumpId that's not tied to a DumpableObject.
585  *
586  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
587  * participate in the sorting logic.
588  */
589 DumpId
591 {
592  return ++lastDumpId;
593 }
594 
595 /*
596  * Return the largest DumpId so far assigned
597  */
598 DumpId
600 {
601  return lastDumpId;
602 }
603 
604 /*
605  * Find a DumpableObject by dump ID
606  *
607  * Returns NULL for invalid ID
608  */
611 {
612  if (dumpId <= 0 || dumpId >= allocedDumpIds)
613  return NULL; /* out of range? */
614  return dumpIdMap[dumpId];
615 }
616 
617 /*
618  * Find a DumpableObject by catalog ID
619  *
620  * Returns NULL for unknown ID
621  *
622  * We use binary search in a sorted list that is built on first call.
623  * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed,
624  * the code would work, but possibly be very slow. In the current usage
625  * pattern that does not happen, indeed we build the list at most twice.
626  */
629 {
630  DumpableObject **low;
631  DumpableObject **high;
632 
633  if (!catalogIdMapValid)
634  {
635  if (catalogIdMap)
636  free(catalogIdMap);
637  getDumpableObjects(&catalogIdMap, &numCatalogIds);
638  if (numCatalogIds > 1)
639  qsort((void *) catalogIdMap, numCatalogIds,
641  catalogIdMapValid = true;
642  }
643 
644  /*
645  * We could use bsearch() here, but the notational cruft of calling
646  * bsearch is nearly as bad as doing it ourselves; and the generalized
647  * bsearch function is noticeably slower as well.
648  */
649  if (numCatalogIds <= 0)
650  return NULL;
651  low = catalogIdMap;
652  high = catalogIdMap + (numCatalogIds - 1);
653  while (low <= high)
654  {
655  DumpableObject **middle;
656  int difference;
657 
658  middle = low + (high - low) / 2;
659  /* comparison must match DOCatalogIdCompare, below */
660  difference = oidcmp((*middle)->catId.oid, catalogId.oid);
661  if (difference == 0)
662  difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
663  if (difference == 0)
664  return *middle;
665  else if (difference < 0)
666  low = middle + 1;
667  else
668  high = middle - 1;
669  }
670  return NULL;
671 }
672 
673 /*
674  * Find a DumpableObject by OID, in a pre-sorted array of one type of object
675  *
676  * Returns NULL for unknown OID
677  */
678 static DumpableObject *
679 findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
680 {
681  DumpableObject **low;
682  DumpableObject **high;
683 
684  /*
685  * This is the same as findObjectByCatalogId except we assume we need not
686  * look at table OID because the objects are all the same type.
687  *
688  * We could use bsearch() here, but the notational cruft of calling
689  * bsearch is nearly as bad as doing it ourselves; and the generalized
690  * bsearch function is noticeably slower as well.
691  */
692  if (numObjs <= 0)
693  return NULL;
694  low = indexArray;
695  high = indexArray + (numObjs - 1);
696  while (low <= high)
697  {
698  DumpableObject **middle;
699  int difference;
700 
701  middle = low + (high - low) / 2;
702  difference = oidcmp((*middle)->catId.oid, oid);
703  if (difference == 0)
704  return *middle;
705  else if (difference < 0)
706  low = middle + 1;
707  else
708  high = middle - 1;
709  }
710  return NULL;
711 }
712 
713 /*
714  * Build an index array of DumpableObject pointers, sorted by OID
715  */
716 static DumpableObject **
717 buildIndexArray(void *objArray, int numObjs, Size objSize)
718 {
719  DumpableObject **ptrs;
720  int i;
721 
722  ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
723  for (i = 0; i < numObjs; i++)
724  ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
725 
726  /* We can use DOCatalogIdCompare to sort since its first key is OID */
727  if (numObjs > 1)
728  qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
730 
731  return ptrs;
732 }
733 
734 /*
735  * qsort comparator for pointers to DumpableObjects
736  */
737 static int
738 DOCatalogIdCompare(const void *p1, const void *p2)
739 {
740  const DumpableObject *obj1 = *(DumpableObject *const *) p1;
741  const DumpableObject *obj2 = *(DumpableObject *const *) p2;
742  int cmpval;
743 
744  /*
745  * Compare OID first since it's usually unique, whereas there will only be
746  * a few distinct values of tableoid.
747  */
748  cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
749  if (cmpval == 0)
750  cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
751  return cmpval;
752 }
753 
754 /*
755  * Build an array of pointers to all known dumpable objects
756  *
757  * This simply creates a modifiable copy of the internal map.
758  */
759 void
760 getDumpableObjects(DumpableObject ***objs, int *numObjs)
761 {
762  int i,
763  j;
764 
765  *objs = (DumpableObject **)
767  j = 0;
768  for (i = 1; i < allocedDumpIds; i++)
769  {
770  if (dumpIdMap[i])
771  (*objs)[j++] = dumpIdMap[i];
772  }
773  *numObjs = j;
774 }
775 
776 /*
777  * Add a dependency link to a DumpableObject
778  *
779  * Note: duplicate dependencies are currently not eliminated
780  */
781 void
783 {
784  if (dobj->nDeps >= dobj->allocDeps)
785  {
786  if (dobj->allocDeps <= 0)
787  {
788  dobj->allocDeps = 16;
789  dobj->dependencies = (DumpId *)
790  pg_malloc(dobj->allocDeps * sizeof(DumpId));
791  }
792  else
793  {
794  dobj->allocDeps *= 2;
795  dobj->dependencies = (DumpId *)
796  pg_realloc(dobj->dependencies,
797  dobj->allocDeps * sizeof(DumpId));
798  }
799  }
800  dobj->dependencies[dobj->nDeps++] = refId;
801 }
802 
803 /*
804  * Remove a dependency link from a DumpableObject
805  *
806  * If there are multiple links, all are removed
807  */
808 void
810 {
811  int i;
812  int j = 0;
813 
814  for (i = 0; i < dobj->nDeps; i++)
815  {
816  if (dobj->dependencies[i] != refId)
817  dobj->dependencies[j++] = dobj->dependencies[i];
818  }
819  dobj->nDeps = j;
820 }
821 
822 
823 /*
824  * findTableByOid
825  * finds the entry (in tblinfo) of the table with the given oid
826  * returns NULL if not found
827  */
828 TableInfo *
830 {
831  return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
832 }
833 
834 /*
835  * findTypeByOid
836  * finds the entry (in typinfo) of the type with the given oid
837  * returns NULL if not found
838  */
839 TypeInfo *
841 {
842  return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
843 }
844 
845 /*
846  * findFuncByOid
847  * finds the entry (in funinfo) of the function with the given oid
848  * returns NULL if not found
849  */
850 FuncInfo *
852 {
853  return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
854 }
855 
856 /*
857  * findOprByOid
858  * finds the entry (in oprinfo) of the operator with the given oid
859  * returns NULL if not found
860  */
861 OprInfo *
863 {
864  return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
865 }
866 
867 /*
868  * findCollationByOid
869  * finds the entry (in collinfo) of the collation with the given oid
870  * returns NULL if not found
871  */
872 CollInfo *
874 {
875  return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
876 }
877 
878 /*
879  * findNamespaceByOid
880  * finds the entry (in nspinfo) of the namespace with the given oid
881  * returns NULL if not found
882  */
885 {
886  return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
887 }
888 
889 /*
890  * findExtensionByOid
891  * finds the entry (in extinfo) of the extension with the given oid
892  * returns NULL if not found
893  */
896 {
897  return (ExtensionInfo *) findObjectByOid(oid, extinfoindex, numExtensions);
898 }
899 
900 /*
901  * findIndexByOid
902  * find the entry of the index with the given oid
903  *
904  * This one's signature is different from the previous ones because we lack a
905  * global array of all indexes, so caller must pass their array as argument.
906  */
907 static IndxInfo *
908 findIndexByOid(Oid oid, DumpableObject **idxinfoindex, int numIndexes)
909 {
910  return (IndxInfo *) findObjectByOid(oid, idxinfoindex, numIndexes);
911 }
912 
913 /*
914  * setExtensionMembership
915  * accept and save data about which objects belong to extensions
916  */
917 void
919 {
920  /* Sort array in preparation for binary searches */
921  if (nextmems > 1)
922  qsort((void *) extmems, nextmems, sizeof(ExtensionMemberId),
924  /* And save */
925  extmembers = extmems;
926  numextmembers = nextmems;
927 }
928 
929 /*
930  * findOwningExtension
931  * return owning extension for specified catalog ID, or NULL if none
932  */
935 {
936  ExtensionMemberId *low;
937  ExtensionMemberId *high;
938 
939  /*
940  * We could use bsearch() here, but the notational cruft of calling
941  * bsearch is nearly as bad as doing it ourselves; and the generalized
942  * bsearch function is noticeably slower as well.
943  */
944  if (numextmembers <= 0)
945  return NULL;
946  low = extmembers;
947  high = extmembers + (numextmembers - 1);
948  while (low <= high)
949  {
950  ExtensionMemberId *middle;
951  int difference;
952 
953  middle = low + (high - low) / 2;
954  /* comparison must match ExtensionMemberIdCompare, below */
955  difference = oidcmp(middle->catId.oid, catalogId.oid);
956  if (difference == 0)
957  difference = oidcmp(middle->catId.tableoid, catalogId.tableoid);
958  if (difference == 0)
959  return middle->ext;
960  else if (difference < 0)
961  low = middle + 1;
962  else
963  high = middle - 1;
964  }
965  return NULL;
966 }
967 
968 /*
969  * qsort comparator for ExtensionMemberIds
970  */
971 static int
972 ExtensionMemberIdCompare(const void *p1, const void *p2)
973 {
974  const ExtensionMemberId *obj1 = (const ExtensionMemberId *) p1;
975  const ExtensionMemberId *obj2 = (const ExtensionMemberId *) p2;
976  int cmpval;
977 
978  /*
979  * Compare OID first since it's usually unique, whereas there will only be
980  * a few distinct values of tableoid.
981  */
982  cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
983  if (cmpval == 0)
984  cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
985  return cmpval;
986 }
987 
988 
989 /*
990  * findParentsByOid
991  * find a table's parents in tblinfo[]
992  */
993 static void
995  InhInfo *inhinfo, int numInherits)
996 {
997  Oid oid = self->dobj.catId.oid;
998  int i,
999  j;
1000  int numParents;
1001 
1002  numParents = 0;
1003  for (i = 0; i < numInherits; i++)
1004  {
1005  if (inhinfo[i].inhrelid == oid)
1006  numParents++;
1007  }
1008 
1009  self->numParents = numParents;
1010 
1011  if (numParents > 0)
1012  {
1013  self->parents = (TableInfo **)
1014  pg_malloc(sizeof(TableInfo *) * numParents);
1015  j = 0;
1016  for (i = 0; i < numInherits; i++)
1017  {
1018  if (inhinfo[i].inhrelid == oid)
1019  {
1020  TableInfo *parent;
1021 
1022  parent = findTableByOid(inhinfo[i].inhparent);
1023  if (parent == NULL)
1024  {
1025  pg_log_error("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
1026  inhinfo[i].inhparent,
1027  self->dobj.name,
1028  oid);
1029  exit_nicely(1);
1030  }
1031  self->parents[j++] = parent;
1032  }
1033  }
1034  }
1035  else
1036  self->parents = NULL;
1037 }
1038 
1039 /*
1040  * parseOidArray
1041  * parse a string of numbers delimited by spaces into a character array
1042  *
1043  * Note: actually this is used for both Oids and potentially-signed
1044  * attribute numbers. This should cause no trouble, but we could split
1045  * the function into two functions with different argument types if it does.
1046  */
1047 
1048 void
1049 parseOidArray(const char *str, Oid *array, int arraysize)
1050 {
1051  int j,
1052  argNum;
1053  char temp[100];
1054  char s;
1055 
1056  argNum = 0;
1057  j = 0;
1058  for (;;)
1059  {
1060  s = *str++;
1061  if (s == ' ' || s == '\0')
1062  {
1063  if (j > 0)
1064  {
1065  if (argNum >= arraysize)
1066  {
1067  pg_log_error("could not parse numeric array \"%s\": too many numbers", str);
1068  exit_nicely(1);
1069  }
1070  temp[j] = '\0';
1071  array[argNum++] = atooid(temp);
1072  j = 0;
1073  }
1074  if (s == '\0')
1075  break;
1076  }
1077  else
1078  {
1079  if (!(isdigit((unsigned char) s) || s == '-') ||
1080  j >= sizeof(temp) - 1)
1081  {
1082  pg_log_error("could not parse numeric array \"%s\": invalid character in number", str);
1083  exit_nicely(1);
1084  }
1085  temp[j++] = s;
1086  }
1087  }
1088 
1089  while (argNum < arraysize)
1090  array[argNum++] = InvalidOid;
1091 }
1092 
1093 
1094 /*
1095  * strInArray:
1096  * takes in a string and a string array and the number of elements in the
1097  * string array.
1098  * returns the index if the string is somewhere in the array, -1 otherwise
1099  */
1100 
1101 static int
1102 strInArray(const char *pattern, char **arr, int arr_size)
1103 {
1104  int i;
1105 
1106  for (i = 0; i < arr_size; i++)
1107  {
1108  if (strcmp(pattern, arr[i]) == 0)
1109  return i;
1110  }
1111  return -1;
1112 }
FuncInfo * getFuncs(Archive *fout, int *numFuncs)
Definition: pg_dump.c:5809
static DumpableObject ** collinfoindex
Definition: common.c:52
static int numTypes
Definition: common.c:56
char * name
Definition: pg_dump.h:130
TableInfo * findTableByOid(Oid oid)
Definition: common.c:829
ExtensionInfo * ext
Definition: pg_dump.h:639
int DumpId
Definition: pg_backup.h:234
AggInfo * getAggregates(Archive *fout, int *numAggs)
Definition: pg_dump.c:5615
struct _tableInfo ** parents
Definition: pg_dump.h:332
static int allocedDumpIds
Definition: common.c:30
void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:4046
CollInfo * getCollations(Archive *fout, int *numCollations)
Definition: pg_dump.c:5229
char relkind
Definition: pg_dump.h:265
DumpComponents dump
Definition: pg_dump.h:131
static DumpId lastDumpId
Definition: common.c:31
Oid tableoid
Definition: pg_backup.h:230
static DumpableObject ** dumpIdMap
Definition: common.c:29
#define oidcmp(x, y)
Definition: pg_dump.h:20
void AssignDumpId(DumpableObject *dobj)
Definition: common.c:545
OprInfo * getOperators(Archive *fout, int *numOprs)
Definition: pg_dump.c:5146
static DumpableObject ** oprinfoindex
Definition: common.c:51
DumpId * dependencies
Definition: pg_dump.h:136
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
TransformInfo * getTransforms(Archive *fout, int *numTransforms)
Definition: pg_dump.c:8334
DefaultACLInfo * getDefaultACLs(Archive *fout, int *numDefaultACLs)
Definition: pg_dump.c:9533
#define pg_log_error(...)
Definition: logging.h:79
static void flagInhTables(Archive *fout, TableInfo *tbinfo, int numTables, InhInfo *inhinfo, int numInherits)
Definition: common.c:273
static int numFuncs
Definition: common.c:57
AccessMethodInfo * getAccessMethods(Archive *fout, int *numAccessMethods)
Definition: pg_dump.c:5382
static int DOCatalogIdCompare(const void *p1, const void *p2)
Definition: common.c:738
bool shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
Definition: pg_dump.c:8871
static int numCatalogIds
Definition: common.c:38
OpclassInfo * getOpclasses(Archive *fout, int *numOpclasses)
Definition: pg_dump.c:5456
bool * inhNotNull
Definition: pg_dump.h:320
TSConfigInfo * getTSConfigurations(Archive *fout, int *numTSConfigs)
Definition: pg_dump.c:9140
static void findParentsByOid(TableInfo *self, InhInfo *inhinfo, int numInherits)
Definition: common.c:994
DumpId dumpId
Definition: pg_dump.h:129
static int numTables
Definition: common.c:55
unsigned int Oid
Definition: postgres_ext.h:31
char ** attnames
Definition: pg_dump.h:303
DumpableObject dobj
Definition: pg_dump.h:259
bool ext_member
Definition: pg_dump.h:134
Oid parentidx
Definition: pg_dump.h:371
static DumpableObject ** buildIndexArray(void *objArray, int numObjs, Size objSize)
Definition: common.c:717
TSParserInfo * getTSParsers(Archive *fout, int *numTSParsers)
Definition: pg_dump.c:8889
static DumpableObject * findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
Definition: common.c:679
Definition: type.h:89
static int strInArray(const char *pattern, char **arr, int arr_size)
Definition: common.c:1102
DumpableObject dobj
Definition: pg_dump.h:380
static DumpableObject ** typinfoindex
Definition: common.c:49
OprInfo * findOprByOid(Oid oid)
Definition: common.c:862
bool separate
Definition: pg_dump.h:346
void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7422
static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables)
InhInfo * getInherits(Archive *fout, int *numInherits)
Definition: pg_dump.c:6940
ExtensionInfo * findOwningExtension(CatalogId catalogId)
Definition: common.c:934
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
static int numOperators
Definition: common.c:58
DumpOptions * dopt
Definition: pg_backup.h:182
void setExtensionMembership(ExtensionMemberId *extmems, int nextmems)
Definition: common.c:918
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition: common.c:610
TableInfo * getTables(Archive *fout, int *numTables)
Definition: pg_dump.c:6044
TableInfo * indextable
Definition: pg_dump.h:359
void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:3573
DumpableObject * findObjectByCatalogId(CatalogId catalogId)
Definition: common.c:628
EventTriggerInfo * getEventTriggers(Archive *fout, int *numEventTriggers)
Definition: pg_dump.c:7952
static DumpableObject ** tblinfoindex
Definition: common.c:48
NamespaceInfo * findNamespaceByOid(Oid oid)
Definition: common.c:884
NamespaceInfo * getNamespaces(Archive *fout, int *numNamespaces)
Definition: pg_dump.c:4666
IndxInfo * partitionIdx
Definition: pg_dump.h:382
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
bool * attisdropped
Definition: pg_dump.h:309
TableInfo * getSchemaData(Archive *fout, int *numTablesPtr)
Definition: common.c:87
static int numExtensions
Definition: common.c:61
TableInfo * adtable
Definition: pg_dump.h:343
static int numNamespaces
Definition: common.c:60
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
#define atooid(x)
Definition: postgres_ext.h:42
RuleInfo * getRules(Archive *fout, int *numRules)
Definition: pg_dump.c:7645
FuncInfo * findFuncByOid(Oid oid)
Definition: common.c:851
FdwInfo * getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
Definition: pg_dump.c:9217
void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:18000
static IndxInfo * findIndexByOid(Oid oid, DumpableObject **idxinfoindex, int numIndexes)
Definition: common.c:908
int numatts
Definition: pg_dump.h:302
void getSubscriptions(Archive *fout)
Definition: pg_dump.c:4194
void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:6989
static int ExtensionMemberIdCompare(const void *p1, const void *p2)
Definition: common.c:972
SimplePtrList partattaches
Definition: pg_dump.h:372
TSDictInfo * getTSDictionaries(Archive *fout, int *numTSDicts)
Definition: pg_dump.c:8980
#define exit_nicely(code)
Definition: pg_dumpall.c:95
void parseOidArray(const char *str, Oid *array, int arraysize)
Definition: common.c:1049
void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7758
Datum difference(PG_FUNCTION_ARGS)
int numIndexes
Definition: pg_dump.h:333
static ExtensionMemberId * extmembers
Definition: common.c:64
ExtensionInfo * findExtensionByOid(Oid oid)
Definition: common.c:895
void removeObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:809
void getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition: pg_dump.c:8431
bool depends_on_ext
Definition: pg_dump.h:135
bool * notnull
Definition: pg_dump.h:319
DumpableObject dobj
Definition: pg_dump.h:342
#define InvalidOid
Definition: postgres_ext.h:36
DumpId getMaxDumpId(void)
Definition: common.c:599
#define free(a)
Definition: header.h:65
void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:6877
bool ispartition
Definition: pg_dump.h:296
ConvInfo * getConversions(Archive *fout, int *numConversions)
Definition: pg_dump.c:5309
static DumpableObject ** catalogIdMap
Definition: common.c:37
#define Assert(condition)
Definition: c.h:738
IndxInfo * parentIdx
Definition: pg_dump.h:381
static bool catalogIdMapValid
Definition: common.c:36
CollInfo * findCollationByOid(Oid oid)
Definition: common.c:873
size_t Size
Definition: c.h:466
struct _attrDefInfo ** attrdefs
Definition: pg_dump.h:321
OpfamilyInfo * getOpfamilies(Archive *fout, int *numOpfamilies)
Definition: pg_dump.c:5531
TSTemplateInfo * getTSTemplates(Archive *fout, int *numTSTemplates)
Definition: pg_dump.c:9064
static int numCollations
Definition: common.c:59
void pg_free(void *ptr)
Definition: fe_memutils.c:105
void getExtendedStatistics(Archive *fout)
Definition: pg_dump.c:7344
ExtensionInfo * getExtensions(Archive *fout, int *numExtensions)
Definition: pg_dump.c:4812
static int numextmembers
Definition: common.c:65
TypeInfo * getTypes(Archive *fout, int *numTypes)
Definition: pg_dump.c:4896
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:782
static DumpableObject ** extinfoindex
Definition: common.c:54
void getPublications(Archive *fout)
Definition: pg_dump.c:3848
ForeignServerInfo * getForeignServers(Archive *fout, int *numForeignServers)
Definition: pg_dump.c:9383
static DumpableObject ** funinfoindex
Definition: common.c:50
CatalogId catId
Definition: pg_dump.h:128
struct _indxInfo * indexes
Definition: pg_dump.h:334
#define DUMP_COMPONENT_ALL
Definition: pg_dump.h:96
DumpableObject dobj
Definition: pg_dump.h:358
CatalogId catId
Definition: pg_dump.h:638
void simple_ptr_list_append(SimplePtrList *list, void *ptr)
Definition: simple_list.c:162
int i
static DumpableObject ** nspinfoindex
Definition: common.c:53
ProcLangInfo * getProcLangs(Archive *fout, int *numProcLangs)
Definition: pg_dump.c:8043
TypeInfo * findTypeByOid(Oid oid)
Definition: common.c:840
void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17895
int numParents
Definition: pg_dump.h:331
#define qsort(a, b, c, d)
Definition: port.h:479
DumpableObjectType objType
Definition: pg_dump.h:127
static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
Definition: common.c:439
#define pg_log_info(...)
Definition: logging.h:87
int load_via_partition_root
Definition: pg_backup.h:160
DumpId createDumpId(void)
Definition: common.c:590
CastInfo * getCasts(Archive *fout, int *numCasts)
Definition: pg_dump.c:8221
char * adef_expr
Definition: pg_dump.h:345
void getDumpableObjects(DumpableObject ***objs, int *numObjs)
Definition: common.c:760