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