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-2019, 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->dependencies = NULL;
553  dobj->nDeps = 0;
554  dobj->allocDeps = 0;
555 
556  while (dobj->dumpId >= allocedDumpIds)
557  {
558  int newAlloc;
559 
560  if (allocedDumpIds <= 0)
561  {
562  newAlloc = 256;
563  dumpIdMap = (DumpableObject **)
564  pg_malloc(newAlloc * sizeof(DumpableObject *));
565  }
566  else
567  {
568  newAlloc = allocedDumpIds * 2;
569  dumpIdMap = (DumpableObject **)
570  pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
571  }
572  memset(dumpIdMap + allocedDumpIds, 0,
573  (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
574  allocedDumpIds = newAlloc;
575  }
576  dumpIdMap[dobj->dumpId] = dobj;
577 
578  /* mark catalogIdMap invalid, but don't rebuild it yet */
579  catalogIdMapValid = false;
580 }
581 
582 /*
583  * Assign a DumpId that's not tied to a DumpableObject.
584  *
585  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
586  * participate in the sorting logic.
587  */
588 DumpId
590 {
591  return ++lastDumpId;
592 }
593 
594 /*
595  * Return the largest DumpId so far assigned
596  */
597 DumpId
599 {
600  return lastDumpId;
601 }
602 
603 /*
604  * Find a DumpableObject by dump ID
605  *
606  * Returns NULL for invalid ID
607  */
610 {
611  if (dumpId <= 0 || dumpId >= allocedDumpIds)
612  return NULL; /* out of range? */
613  return dumpIdMap[dumpId];
614 }
615 
616 /*
617  * Find a DumpableObject by catalog ID
618  *
619  * Returns NULL for unknown ID
620  *
621  * We use binary search in a sorted list that is built on first call.
622  * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed,
623  * the code would work, but possibly be very slow. In the current usage
624  * pattern that does not happen, indeed we build the list at most twice.
625  */
628 {
629  DumpableObject **low;
630  DumpableObject **high;
631 
632  if (!catalogIdMapValid)
633  {
634  if (catalogIdMap)
635  free(catalogIdMap);
636  getDumpableObjects(&catalogIdMap, &numCatalogIds);
637  if (numCatalogIds > 1)
638  qsort((void *) catalogIdMap, numCatalogIds,
640  catalogIdMapValid = true;
641  }
642 
643  /*
644  * We could use bsearch() here, but the notational cruft of calling
645  * bsearch is nearly as bad as doing it ourselves; and the generalized
646  * bsearch function is noticeably slower as well.
647  */
648  if (numCatalogIds <= 0)
649  return NULL;
650  low = catalogIdMap;
651  high = catalogIdMap + (numCatalogIds - 1);
652  while (low <= high)
653  {
654  DumpableObject **middle;
655  int difference;
656 
657  middle = low + (high - low) / 2;
658  /* comparison must match DOCatalogIdCompare, below */
659  difference = oidcmp((*middle)->catId.oid, catalogId.oid);
660  if (difference == 0)
661  difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
662  if (difference == 0)
663  return *middle;
664  else if (difference < 0)
665  low = middle + 1;
666  else
667  high = middle - 1;
668  }
669  return NULL;
670 }
671 
672 /*
673  * Find a DumpableObject by OID, in a pre-sorted array of one type of object
674  *
675  * Returns NULL for unknown OID
676  */
677 static DumpableObject *
678 findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
679 {
680  DumpableObject **low;
681  DumpableObject **high;
682 
683  /*
684  * This is the same as findObjectByCatalogId except we assume we need not
685  * look at table OID because the objects are all the same type.
686  *
687  * We could use bsearch() here, but the notational cruft of calling
688  * bsearch is nearly as bad as doing it ourselves; and the generalized
689  * bsearch function is noticeably slower as well.
690  */
691  if (numObjs <= 0)
692  return NULL;
693  low = indexArray;
694  high = indexArray + (numObjs - 1);
695  while (low <= high)
696  {
697  DumpableObject **middle;
698  int difference;
699 
700  middle = low + (high - low) / 2;
701  difference = oidcmp((*middle)->catId.oid, oid);
702  if (difference == 0)
703  return *middle;
704  else if (difference < 0)
705  low = middle + 1;
706  else
707  high = middle - 1;
708  }
709  return NULL;
710 }
711 
712 /*
713  * Build an index array of DumpableObject pointers, sorted by OID
714  */
715 static DumpableObject **
716 buildIndexArray(void *objArray, int numObjs, Size objSize)
717 {
718  DumpableObject **ptrs;
719  int i;
720 
721  ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
722  for (i = 0; i < numObjs; i++)
723  ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
724 
725  /* We can use DOCatalogIdCompare to sort since its first key is OID */
726  if (numObjs > 1)
727  qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
729 
730  return ptrs;
731 }
732 
733 /*
734  * qsort comparator for pointers to DumpableObjects
735  */
736 static int
737 DOCatalogIdCompare(const void *p1, const void *p2)
738 {
739  const DumpableObject *obj1 = *(DumpableObject *const *) p1;
740  const DumpableObject *obj2 = *(DumpableObject *const *) p2;
741  int cmpval;
742 
743  /*
744  * Compare OID first since it's usually unique, whereas there will only be
745  * a few distinct values of tableoid.
746  */
747  cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
748  if (cmpval == 0)
749  cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
750  return cmpval;
751 }
752 
753 /*
754  * Build an array of pointers to all known dumpable objects
755  *
756  * This simply creates a modifiable copy of the internal map.
757  */
758 void
759 getDumpableObjects(DumpableObject ***objs, int *numObjs)
760 {
761  int i,
762  j;
763 
764  *objs = (DumpableObject **)
766  j = 0;
767  for (i = 1; i < allocedDumpIds; i++)
768  {
769  if (dumpIdMap[i])
770  (*objs)[j++] = dumpIdMap[i];
771  }
772  *numObjs = j;
773 }
774 
775 /*
776  * Add a dependency link to a DumpableObject
777  *
778  * Note: duplicate dependencies are currently not eliminated
779  */
780 void
782 {
783  if (dobj->nDeps >= dobj->allocDeps)
784  {
785  if (dobj->allocDeps <= 0)
786  {
787  dobj->allocDeps = 16;
788  dobj->dependencies = (DumpId *)
789  pg_malloc(dobj->allocDeps * sizeof(DumpId));
790  }
791  else
792  {
793  dobj->allocDeps *= 2;
794  dobj->dependencies = (DumpId *)
795  pg_realloc(dobj->dependencies,
796  dobj->allocDeps * sizeof(DumpId));
797  }
798  }
799  dobj->dependencies[dobj->nDeps++] = refId;
800 }
801 
802 /*
803  * Remove a dependency link from a DumpableObject
804  *
805  * If there are multiple links, all are removed
806  */
807 void
809 {
810  int i;
811  int j = 0;
812 
813  for (i = 0; i < dobj->nDeps; i++)
814  {
815  if (dobj->dependencies[i] != refId)
816  dobj->dependencies[j++] = dobj->dependencies[i];
817  }
818  dobj->nDeps = j;
819 }
820 
821 
822 /*
823  * findTableByOid
824  * finds the entry (in tblinfo) of the table with the given oid
825  * returns NULL if not found
826  */
827 TableInfo *
829 {
830  return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
831 }
832 
833 /*
834  * findTypeByOid
835  * finds the entry (in typinfo) of the type with the given oid
836  * returns NULL if not found
837  */
838 TypeInfo *
840 {
841  return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
842 }
843 
844 /*
845  * findFuncByOid
846  * finds the entry (in funinfo) of the function with the given oid
847  * returns NULL if not found
848  */
849 FuncInfo *
851 {
852  return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
853 }
854 
855 /*
856  * findOprByOid
857  * finds the entry (in oprinfo) of the operator with the given oid
858  * returns NULL if not found
859  */
860 OprInfo *
862 {
863  return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
864 }
865 
866 /*
867  * findCollationByOid
868  * finds the entry (in collinfo) of the collation with the given oid
869  * returns NULL if not found
870  */
871 CollInfo *
873 {
874  return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
875 }
876 
877 /*
878  * findNamespaceByOid
879  * finds the entry (in nspinfo) of the namespace with the given oid
880  * returns NULL if not found
881  */
884 {
885  return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
886 }
887 
888 /*
889  * findExtensionByOid
890  * finds the entry (in extinfo) of the extension with the given oid
891  * returns NULL if not found
892  */
895 {
896  return (ExtensionInfo *) findObjectByOid(oid, extinfoindex, numExtensions);
897 }
898 
899 /*
900  * findIndexByOid
901  * find the entry of the index with the given oid
902  *
903  * This one's signature is different from the previous ones because we lack a
904  * global array of all indexes, so caller must pass their array as argument.
905  */
906 static IndxInfo *
907 findIndexByOid(Oid oid, DumpableObject **idxinfoindex, int numIndexes)
908 {
909  return (IndxInfo *) findObjectByOid(oid, idxinfoindex, numIndexes);
910 }
911 
912 /*
913  * setExtensionMembership
914  * accept and save data about which objects belong to extensions
915  */
916 void
918 {
919  /* Sort array in preparation for binary searches */
920  if (nextmems > 1)
921  qsort((void *) extmems, nextmems, sizeof(ExtensionMemberId),
923  /* And save */
924  extmembers = extmems;
925  numextmembers = nextmems;
926 }
927 
928 /*
929  * findOwningExtension
930  * return owning extension for specified catalog ID, or NULL if none
931  */
934 {
935  ExtensionMemberId *low;
936  ExtensionMemberId *high;
937 
938  /*
939  * We could use bsearch() here, but the notational cruft of calling
940  * bsearch is nearly as bad as doing it ourselves; and the generalized
941  * bsearch function is noticeably slower as well.
942  */
943  if (numextmembers <= 0)
944  return NULL;
945  low = extmembers;
946  high = extmembers + (numextmembers - 1);
947  while (low <= high)
948  {
949  ExtensionMemberId *middle;
950  int difference;
951 
952  middle = low + (high - low) / 2;
953  /* comparison must match ExtensionMemberIdCompare, below */
954  difference = oidcmp(middle->catId.oid, catalogId.oid);
955  if (difference == 0)
956  difference = oidcmp(middle->catId.tableoid, catalogId.tableoid);
957  if (difference == 0)
958  return middle->ext;
959  else if (difference < 0)
960  low = middle + 1;
961  else
962  high = middle - 1;
963  }
964  return NULL;
965 }
966 
967 /*
968  * qsort comparator for ExtensionMemberIds
969  */
970 static int
971 ExtensionMemberIdCompare(const void *p1, const void *p2)
972 {
973  const ExtensionMemberId *obj1 = (const ExtensionMemberId *) p1;
974  const ExtensionMemberId *obj2 = (const ExtensionMemberId *) p2;
975  int cmpval;
976 
977  /*
978  * Compare OID first since it's usually unique, whereas there will only be
979  * a few distinct values of tableoid.
980  */
981  cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
982  if (cmpval == 0)
983  cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
984  return cmpval;
985 }
986 
987 
988 /*
989  * findParentsByOid
990  * find a table's parents in tblinfo[]
991  */
992 static void
994  InhInfo *inhinfo, int numInherits)
995 {
996  Oid oid = self->dobj.catId.oid;
997  int i,
998  j;
999  int numParents;
1000 
1001  numParents = 0;
1002  for (i = 0; i < numInherits; i++)
1003  {
1004  if (inhinfo[i].inhrelid == oid)
1005  numParents++;
1006  }
1007 
1008  self->numParents = numParents;
1009 
1010  if (numParents > 0)
1011  {
1012  self->parents = (TableInfo **)
1013  pg_malloc(sizeof(TableInfo *) * numParents);
1014  j = 0;
1015  for (i = 0; i < numInherits; i++)
1016  {
1017  if (inhinfo[i].inhrelid == oid)
1018  {
1019  TableInfo *parent;
1020 
1021  parent = findTableByOid(inhinfo[i].inhparent);
1022  if (parent == NULL)
1023  {
1024  pg_log_error("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
1025  inhinfo[i].inhparent,
1026  self->dobj.name,
1027  oid);
1028  exit_nicely(1);
1029  }
1030  self->parents[j++] = parent;
1031  }
1032  }
1033  }
1034  else
1035  self->parents = NULL;
1036 }
1037 
1038 /*
1039  * parseOidArray
1040  * parse a string of numbers delimited by spaces into a character array
1041  *
1042  * Note: actually this is used for both Oids and potentially-signed
1043  * attribute numbers. This should cause no trouble, but we could split
1044  * the function into two functions with different argument types if it does.
1045  */
1046 
1047 void
1048 parseOidArray(const char *str, Oid *array, int arraysize)
1049 {
1050  int j,
1051  argNum;
1052  char temp[100];
1053  char s;
1054 
1055  argNum = 0;
1056  j = 0;
1057  for (;;)
1058  {
1059  s = *str++;
1060  if (s == ' ' || s == '\0')
1061  {
1062  if (j > 0)
1063  {
1064  if (argNum >= arraysize)
1065  {
1066  pg_log_error("could not parse numeric array \"%s\": too many numbers", str);
1067  exit_nicely(1);
1068  }
1069  temp[j] = '\0';
1070  array[argNum++] = atooid(temp);
1071  j = 0;
1072  }
1073  if (s == '\0')
1074  break;
1075  }
1076  else
1077  {
1078  if (!(isdigit((unsigned char) s) || s == '-') ||
1079  j >= sizeof(temp) - 1)
1080  {
1081  pg_log_error("could not parse numeric array \"%s\": invalid character in number", str);
1082  exit_nicely(1);
1083  }
1084  temp[j++] = s;
1085  }
1086  }
1087 
1088  while (argNum < arraysize)
1089  array[argNum++] = InvalidOid;
1090 }
1091 
1092 
1093 /*
1094  * strInArray:
1095  * takes in a string and a string array and the number of elements in the
1096  * string array.
1097  * returns the index if the string is somewhere in the array, -1 otherwise
1098  */
1099 
1100 static int
1101 strInArray(const char *pattern, char **arr, int arr_size)
1102 {
1103  int i;
1104 
1105  for (i = 0; i < arr_size; i++)
1106  {
1107  if (strcmp(pattern, arr[i]) == 0)
1108  return i;
1109  }
1110  return -1;
1111 }
FuncInfo * getFuncs(Archive *fout, int *numFuncs)
Definition: pg_dump.c:5660
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:828
ExtensionInfo * ext
Definition: pg_dump.h:636
int DumpId
Definition: pg_backup.h:234
AggInfo * getAggregates(Archive *fout, int *numAggs)
Definition: pg_dump.c:5466
struct _tableInfo ** parents
Definition: pg_dump.h:330
static int allocedDumpIds
Definition: common.c:30
void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:3950
CollInfo * getCollations(Archive *fout, int *numCollations)
Definition: pg_dump.c:5080
char relkind
Definition: pg_dump.h:264
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:4997
static DumpableObject ** oprinfoindex
Definition: common.c:51
DumpId * dependencies
Definition: pg_dump.h:135
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
TransformInfo * getTransforms(Archive *fout, int *numTransforms)
Definition: pg_dump.c:8158
DefaultACLInfo * getDefaultACLs(Archive *fout, int *numDefaultACLs)
Definition: pg_dump.c:9357
#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:5233
static int DOCatalogIdCompare(const void *p1, const void *p2)
Definition: common.c:737
bool shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
Definition: pg_dump.c:8695
static int numCatalogIds
Definition: common.c:38
OpclassInfo * getOpclasses(Archive *fout, int *numOpclasses)
Definition: pg_dump.c:5307
bool * inhNotNull
Definition: pg_dump.h:318
TSConfigInfo * getTSConfigurations(Archive *fout, int *numTSConfigs)
Definition: pg_dump.c:8964
static void findParentsByOid(TableInfo *self, InhInfo *inhinfo, int numInherits)
Definition: common.c:993
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:301
DumpableObject dobj
Definition: pg_dump.h:258
bool ext_member
Definition: pg_dump.h:134
Oid parentidx
Definition: pg_dump.h:369
char relkind
Definition: pg_class.h:81
static DumpableObject ** buildIndexArray(void *objArray, int numObjs, Size objSize)
Definition: common.c:716
TSParserInfo * getTSParsers(Archive *fout, int *numTSParsers)
Definition: pg_dump.c:8713
static DumpableObject * findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
Definition: common.c:678
Definition: type.h:89
static int strInArray(const char *pattern, char **arr, int arr_size)
Definition: common.c:1101
DumpableObject dobj
Definition: pg_dump.h:378
static DumpableObject ** typinfoindex
Definition: common.c:49
OprInfo * findOprByOid(Oid oid)
Definition: common.c:861
bool separate
Definition: pg_dump.h:344
void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7246
static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables)
InhInfo * getInherits(Archive *fout, int *numInherits)
Definition: pg_dump.c:6767
ExtensionInfo * findOwningExtension(CatalogId catalogId)
Definition: common.c:933
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:917
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition: common.c:609
TableInfo * getTables(Archive *fout, int *numTables)
Definition: pg_dump.c:5895
TableInfo * indextable
Definition: pg_dump.h:357
void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:3508
DumpableObject * findObjectByCatalogId(CatalogId catalogId)
Definition: common.c:627
EventTriggerInfo * getEventTriggers(Archive *fout, int *numEventTriggers)
Definition: pg_dump.c:7776
static DumpableObject ** tblinfoindex
Definition: common.c:48
NamespaceInfo * findNamespaceByOid(Oid oid)
Definition: common.c:883
NamespaceInfo * getNamespaces(Archive *fout, int *numNamespaces)
Definition: pg_dump.c:4517
IndxInfo * partitionIdx
Definition: pg_dump.h:380
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
bool * attisdropped
Definition: pg_dump.h:307
TableInfo * getSchemaData(Archive *fout, int *numTablesPtr)
Definition: common.c:87
static int numExtensions
Definition: common.c:61
TableInfo * adtable
Definition: pg_dump.h:341
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:7469
FuncInfo * findFuncByOid(Oid oid)
Definition: common.c:850
FdwInfo * getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
Definition: pg_dump.c:9041
void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17793
static IndxInfo * findIndexByOid(Oid oid, DumpableObject **idxinfoindex, int numIndexes)
Definition: common.c:907
int numatts
Definition: pg_dump.h:300
void getSubscriptions(Archive *fout)
Definition: pg_dump.c:4095
void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:6816
static int ExtensionMemberIdCompare(const void *p1, const void *p2)
Definition: common.c:971
SimplePtrList partattaches
Definition: pg_dump.h:370
TSDictInfo * getTSDictionaries(Archive *fout, int *numTSDicts)
Definition: pg_dump.c:8804
#define exit_nicely(code)
Definition: pg_dumpall.c:95
void parseOidArray(const char *str, Oid *array, int arraysize)
Definition: common.c:1048
void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7582
Datum difference(PG_FUNCTION_ARGS)
int numIndexes
Definition: pg_dump.h:331
static ExtensionMemberId * extmembers
Definition: common.c:64
ExtensionInfo * findExtensionByOid(Oid oid)
Definition: common.c:894
void removeObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:808
void getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition: pg_dump.c:8255
bool * notnull
Definition: pg_dump.h:317
DumpableObject dobj
Definition: pg_dump.h:340
#define InvalidOid
Definition: postgres_ext.h:36
DumpId getMaxDumpId(void)
Definition: common.c:598
#define free(a)
Definition: header.h:65
void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:6704
bool ispartition
Definition: pg_dump.h:294
ConvInfo * getConversions(Archive *fout, int *numConversions)
Definition: pg_dump.c:5160
static DumpableObject ** catalogIdMap
Definition: common.c:37
#define Assert(condition)
Definition: c.h:739
IndxInfo * parentIdx
Definition: pg_dump.h:379
static bool catalogIdMapValid
Definition: common.c:36
CollInfo * findCollationByOid(Oid oid)
Definition: common.c:872
size_t Size
Definition: c.h:467
struct _attrDefInfo ** attrdefs
Definition: pg_dump.h:319
OpfamilyInfo * getOpfamilies(Archive *fout, int *numOpfamilies)
Definition: pg_dump.c:5382
TSTemplateInfo * getTSTemplates(Archive *fout, int *numTSTemplates)
Definition: pg_dump.c:8888
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:7168
ExtensionInfo * getExtensions(Archive *fout, int *numExtensions)
Definition: pg_dump.c:4663
static int numextmembers
Definition: common.c:65
TypeInfo * getTypes(Archive *fout, int *numTypes)
Definition: pg_dump.c:4747
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:781
static DumpableObject ** extinfoindex
Definition: common.c:54
void getPublications(Archive *fout)
Definition: pg_dump.c:3768
ForeignServerInfo * getForeignServers(Archive *fout, int *numForeignServers)
Definition: pg_dump.c:9207
static DumpableObject ** funinfoindex
Definition: common.c:50
CatalogId catId
Definition: pg_dump.h:128
struct _indxInfo * indexes
Definition: pg_dump.h:332
#define DUMP_COMPONENT_ALL
Definition: pg_dump.h:96
DumpableObject dobj
Definition: pg_dump.h:356
CatalogId catId
Definition: pg_dump.h:635
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:7867
TypeInfo * findTypeByOid(Oid oid)
Definition: common.c:839
void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17688
int numParents
Definition: pg_dump.h:329
#define qsort(a, b, c, d)
Definition: port.h:488
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:589
CastInfo * getCasts(Archive *fout, int *numCasts)
Definition: pg_dump.c:8045
char * adef_expr
Definition: pg_dump.h:343
void getDumpableObjects(DumpableObject ***objs, int *numObjs)
Definition: common.c:759