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; /* Note: 0 is InvalidDumpId */
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  if (numObjs <= 0)
723  return NULL;
724 
725  ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
726  for (i = 0; i < numObjs; i++)
727  ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
728 
729  /* We can use DOCatalogIdCompare to sort since its first key is OID */
730  if (numObjs > 1)
731  qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
733 
734  return ptrs;
735 }
736 
737 /*
738  * qsort comparator for pointers to DumpableObjects
739  */
740 static int
741 DOCatalogIdCompare(const void *p1, const void *p2)
742 {
743  const DumpableObject *obj1 = *(DumpableObject *const *) p1;
744  const DumpableObject *obj2 = *(DumpableObject *const *) p2;
745  int cmpval;
746 
747  /*
748  * Compare OID first since it's usually unique, whereas there will only be
749  * a few distinct values of tableoid.
750  */
751  cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
752  if (cmpval == 0)
753  cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
754  return cmpval;
755 }
756 
757 /*
758  * Build an array of pointers to all known dumpable objects
759  *
760  * This simply creates a modifiable copy of the internal map.
761  */
762 void
763 getDumpableObjects(DumpableObject ***objs, int *numObjs)
764 {
765  int i,
766  j;
767 
768  *objs = (DumpableObject **)
770  j = 0;
771  for (i = 1; i < allocedDumpIds; i++)
772  {
773  if (dumpIdMap[i])
774  (*objs)[j++] = dumpIdMap[i];
775  }
776  *numObjs = j;
777 }
778 
779 /*
780  * Add a dependency link to a DumpableObject
781  *
782  * Note: duplicate dependencies are currently not eliminated
783  */
784 void
786 {
787  if (dobj->nDeps >= dobj->allocDeps)
788  {
789  if (dobj->allocDeps <= 0)
790  {
791  dobj->allocDeps = 16;
792  dobj->dependencies = (DumpId *)
793  pg_malloc(dobj->allocDeps * sizeof(DumpId));
794  }
795  else
796  {
797  dobj->allocDeps *= 2;
798  dobj->dependencies = (DumpId *)
799  pg_realloc(dobj->dependencies,
800  dobj->allocDeps * sizeof(DumpId));
801  }
802  }
803  dobj->dependencies[dobj->nDeps++] = refId;
804 }
805 
806 /*
807  * Remove a dependency link from a DumpableObject
808  *
809  * If there are multiple links, all are removed
810  */
811 void
813 {
814  int i;
815  int j = 0;
816 
817  for (i = 0; i < dobj->nDeps; i++)
818  {
819  if (dobj->dependencies[i] != refId)
820  dobj->dependencies[j++] = dobj->dependencies[i];
821  }
822  dobj->nDeps = j;
823 }
824 
825 
826 /*
827  * findTableByOid
828  * finds the entry (in tblinfo) of the table with the given oid
829  * returns NULL if not found
830  */
831 TableInfo *
833 {
834  return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
835 }
836 
837 /*
838  * findTypeByOid
839  * finds the entry (in typinfo) of the type with the given oid
840  * returns NULL if not found
841  */
842 TypeInfo *
844 {
845  return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
846 }
847 
848 /*
849  * findFuncByOid
850  * finds the entry (in funinfo) of the function with the given oid
851  * returns NULL if not found
852  */
853 FuncInfo *
855 {
856  return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
857 }
858 
859 /*
860  * findOprByOid
861  * finds the entry (in oprinfo) of the operator with the given oid
862  * returns NULL if not found
863  */
864 OprInfo *
866 {
867  return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
868 }
869 
870 /*
871  * findCollationByOid
872  * finds the entry (in collinfo) of the collation with the given oid
873  * returns NULL if not found
874  */
875 CollInfo *
877 {
878  return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
879 }
880 
881 /*
882  * findNamespaceByOid
883  * finds the entry (in nspinfo) of the namespace with the given oid
884  * returns NULL if not found
885  */
888 {
889  return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
890 }
891 
892 /*
893  * findExtensionByOid
894  * finds the entry (in extinfo) of the extension with the given oid
895  * returns NULL if not found
896  */
899 {
900  return (ExtensionInfo *) findObjectByOid(oid, extinfoindex, numExtensions);
901 }
902 
903 /*
904  * findIndexByOid
905  * find the entry of the index with the given oid
906  *
907  * This one's signature is different from the previous ones because we lack a
908  * global array of all indexes, so caller must pass their array as argument.
909  */
910 static IndxInfo *
911 findIndexByOid(Oid oid, DumpableObject **idxinfoindex, int numIndexes)
912 {
913  return (IndxInfo *) findObjectByOid(oid, idxinfoindex, numIndexes);
914 }
915 
916 /*
917  * setExtensionMembership
918  * accept and save data about which objects belong to extensions
919  */
920 void
922 {
923  /* Sort array in preparation for binary searches */
924  if (nextmems > 1)
925  qsort((void *) extmems, nextmems, sizeof(ExtensionMemberId),
927  /* And save */
928  extmembers = extmems;
929  numextmembers = nextmems;
930 }
931 
932 /*
933  * findOwningExtension
934  * return owning extension for specified catalog ID, or NULL if none
935  */
938 {
939  ExtensionMemberId *low;
940  ExtensionMemberId *high;
941 
942  /*
943  * We could use bsearch() here, but the notational cruft of calling
944  * bsearch is nearly as bad as doing it ourselves; and the generalized
945  * bsearch function is noticeably slower as well.
946  */
947  if (numextmembers <= 0)
948  return NULL;
949  low = extmembers;
950  high = extmembers + (numextmembers - 1);
951  while (low <= high)
952  {
953  ExtensionMemberId *middle;
954  int difference;
955 
956  middle = low + (high - low) / 2;
957  /* comparison must match ExtensionMemberIdCompare, below */
958  difference = oidcmp(middle->catId.oid, catalogId.oid);
959  if (difference == 0)
960  difference = oidcmp(middle->catId.tableoid, catalogId.tableoid);
961  if (difference == 0)
962  return middle->ext;
963  else if (difference < 0)
964  low = middle + 1;
965  else
966  high = middle - 1;
967  }
968  return NULL;
969 }
970 
971 /*
972  * qsort comparator for ExtensionMemberIds
973  */
974 static int
975 ExtensionMemberIdCompare(const void *p1, const void *p2)
976 {
977  const ExtensionMemberId *obj1 = (const ExtensionMemberId *) p1;
978  const ExtensionMemberId *obj2 = (const ExtensionMemberId *) p2;
979  int cmpval;
980 
981  /*
982  * Compare OID first since it's usually unique, whereas there will only be
983  * a few distinct values of tableoid.
984  */
985  cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
986  if (cmpval == 0)
987  cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
988  return cmpval;
989 }
990 
991 
992 /*
993  * findParentsByOid
994  * find a table's parents in tblinfo[]
995  */
996 static void
998  InhInfo *inhinfo, int numInherits)
999 {
1000  Oid oid = self->dobj.catId.oid;
1001  int i,
1002  j;
1003  int numParents;
1004 
1005  numParents = 0;
1006  for (i = 0; i < numInherits; i++)
1007  {
1008  if (inhinfo[i].inhrelid == oid)
1009  numParents++;
1010  }
1011 
1012  self->numParents = numParents;
1013 
1014  if (numParents > 0)
1015  {
1016  self->parents = (TableInfo **)
1017  pg_malloc(sizeof(TableInfo *) * numParents);
1018  j = 0;
1019  for (i = 0; i < numInherits; i++)
1020  {
1021  if (inhinfo[i].inhrelid == oid)
1022  {
1023  TableInfo *parent;
1024 
1025  parent = findTableByOid(inhinfo[i].inhparent);
1026  if (parent == NULL)
1027  {
1028  pg_log_error("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
1029  inhinfo[i].inhparent,
1030  self->dobj.name,
1031  oid);
1032  exit_nicely(1);
1033  }
1034  self->parents[j++] = parent;
1035  }
1036  }
1037  }
1038  else
1039  self->parents = NULL;
1040 }
1041 
1042 /*
1043  * parseOidArray
1044  * parse a string of numbers delimited by spaces into a character array
1045  *
1046  * Note: actually this is used for both Oids and potentially-signed
1047  * attribute numbers. This should cause no trouble, but we could split
1048  * the function into two functions with different argument types if it does.
1049  */
1050 
1051 void
1052 parseOidArray(const char *str, Oid *array, int arraysize)
1053 {
1054  int j,
1055  argNum;
1056  char temp[100];
1057  char s;
1058 
1059  argNum = 0;
1060  j = 0;
1061  for (;;)
1062  {
1063  s = *str++;
1064  if (s == ' ' || s == '\0')
1065  {
1066  if (j > 0)
1067  {
1068  if (argNum >= arraysize)
1069  {
1070  pg_log_error("could not parse numeric array \"%s\": too many numbers", str);
1071  exit_nicely(1);
1072  }
1073  temp[j] = '\0';
1074  array[argNum++] = atooid(temp);
1075  j = 0;
1076  }
1077  if (s == '\0')
1078  break;
1079  }
1080  else
1081  {
1082  if (!(isdigit((unsigned char) s) || s == '-') ||
1083  j >= sizeof(temp) - 1)
1084  {
1085  pg_log_error("could not parse numeric array \"%s\": invalid character in number", str);
1086  exit_nicely(1);
1087  }
1088  temp[j++] = s;
1089  }
1090  }
1091 
1092  while (argNum < arraysize)
1093  array[argNum++] = InvalidOid;
1094 }
1095 
1096 
1097 /*
1098  * strInArray:
1099  * takes in a string and a string array and the number of elements in the
1100  * string array.
1101  * returns the index if the string is somewhere in the array, -1 otherwise
1102  */
1103 
1104 static int
1105 strInArray(const char *pattern, char **arr, int arr_size)
1106 {
1107  int i;
1108 
1109  for (i = 0; i < arr_size; i++)
1110  {
1111  if (strcmp(pattern, arr[i]) == 0)
1112  return i;
1113  }
1114  return -1;
1115 }
FuncInfo * getFuncs(Archive *fout, int *numFuncs)
Definition: pg_dump.c:5828
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:832
ExtensionInfo * ext
Definition: pg_dump.h:643
int DumpId
Definition: pg_backup.h:243
AggInfo * getAggregates(Archive *fout, int *numAggs)
Definition: pg_dump.c:5635
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:4065
CollInfo * getCollations(Archive *fout, int *numCollations)
Definition: pg_dump.c:5253
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:239
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:5171
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:8447
DefaultACLInfo * getDefaultACLs(Archive *fout, int *numDefaultACLs)
Definition: pg_dump.c:9603
#define pg_log_error(...)
Definition: logging.h:80
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:5404
static int DOCatalogIdCompare(const void *p1, const void *p2)
Definition: common.c:741
bool shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
Definition: pg_dump.c:8945
static int numCatalogIds
Definition: common.c:38
OpclassInfo * getOpclasses(Archive *fout, int *numOpclasses)
Definition: pg_dump.c:5478
bool * inhNotNull
Definition: pg_dump.h:320
TSConfigInfo * getTSConfigurations(Archive *fout, int *numTSConfigs)
Definition: pg_dump.c:9211
static void findParentsByOid(TableInfo *self, InhInfo *inhinfo, int numInherits)
Definition: common.c:997
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:373
static DumpableObject ** buildIndexArray(void *objArray, int numObjs, Size objSize)
Definition: common.c:717
TSParserInfo * getTSParsers(Archive *fout, int *numTSParsers)
Definition: pg_dump.c:8963
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:1105
DumpableObject dobj
Definition: pg_dump.h:382
static DumpableObject ** typinfoindex
Definition: common.c:49
OprInfo * findOprByOid(Oid oid)
Definition: common.c:865
bool separate
Definition: pg_dump.h:346
void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7511
static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables)
InhInfo * getInherits(Archive *fout, int *numInherits)
Definition: pg_dump.c:6957
ExtensionInfo * findOwningExtension(CatalogId catalogId)
Definition: common.c:937
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
static int numOperators
Definition: common.c:58
DumpOptions * dopt
Definition: pg_backup.h:191
void setExtensionMembership(ExtensionMemberId *extmems, int nextmems)
Definition: common.c:921
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition: common.c:610
TableInfo * getTables(Archive *fout, int *numTables)
Definition: pg_dump.c:6062
TableInfo * indextable
Definition: pg_dump.h:359
void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:3592
DumpableObject * findObjectByCatalogId(CatalogId catalogId)
Definition: common.c:628
EventTriggerInfo * getEventTriggers(Archive *fout, int *numEventTriggers)
Definition: pg_dump.c:8065
static DumpableObject ** tblinfoindex
Definition: common.c:48
NamespaceInfo * findNamespaceByOid(Oid oid)
Definition: common.c:887
NamespaceInfo * getNamespaces(Archive *fout, int *numNamespaces)
Definition: pg_dump.c:4692
IndxInfo * partitionIdx
Definition: pg_dump.h:384
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:7758
FuncInfo * findFuncByOid(Oid oid)
Definition: common.c:854
FdwInfo * getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
Definition: pg_dump.c:9287
void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17907
static IndxInfo * findIndexByOid(Oid oid, DumpableObject **idxinfoindex, int numIndexes)
Definition: common.c:911
int numatts
Definition: pg_dump.h:302
void getSubscriptions(Archive *fout)
Definition: pg_dump.c:4213
void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7006
static int ExtensionMemberIdCompare(const void *p1, const void *p2)
Definition: common.c:975
SimplePtrList partattaches
Definition: pg_dump.h:374
TSDictInfo * getTSDictionaries(Archive *fout, int *numTSDicts)
Definition: pg_dump.c:9053
#define exit_nicely(code)
Definition: pg_dumpall.c:96
void parseOidArray(const char *str, Oid *array, int arraysize)
Definition: common.c:1052
void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7871
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:898
void removeObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:812
void getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition: pg_dump.c:8544
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:6894
bool ispartition
Definition: pg_dump.h:296
ConvInfo * getConversions(Archive *fout, int *numConversions)
Definition: pg_dump.c:5332
static DumpableObject ** catalogIdMap
Definition: common.c:37
#define Assert(condition)
Definition: c.h:800
IndxInfo * parentIdx
Definition: pg_dump.h:383
static bool catalogIdMapValid
Definition: common.c:36
CollInfo * findCollationByOid(Oid oid)
Definition: common.c:876
size_t Size
Definition: c.h:528
struct _attrDefInfo ** attrdefs
Definition: pg_dump.h:321
OpfamilyInfo * getOpfamilies(Archive *fout, int *numOpfamilies)
Definition: pg_dump.c:5552
TSTemplateInfo * getTSTemplates(Archive *fout, int *numTSTemplates)
Definition: pg_dump.c:9136
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:7434
ExtensionInfo * getExtensions(Archive *fout, int *numExtensions)
Definition: pg_dump.c:4838
static int numextmembers
Definition: common.c:65
TypeInfo * getTypes(Archive *fout, int *numTypes)
Definition: pg_dump.c:4922
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:785
static DumpableObject ** extinfoindex
Definition: common.c:54
void getPublications(Archive *fout)
Definition: pg_dump.c:3867
ForeignServerInfo * getForeignServers(Archive *fout, int *numForeignServers)
Definition: pg_dump.c:9453
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:642
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:8156
TypeInfo * findTypeByOid(Oid oid)
Definition: common.c:843
void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17802
int numParents
Definition: pg_dump.h:331
#define qsort(a, b, c, d)
Definition: port.h:497
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:88
int load_via_partition_root
Definition: pg_backup.h:168
DumpId createDumpId(void)
Definition: common.c:590
CastInfo * getCasts(Archive *fout, int *numCasts)
Definition: pg_dump.c:8334
char * adef_expr
Definition: pg_dump.h:345
void getDumpableObjects(DumpableObject ***objs, int *numObjs)
Definition: common.c:763