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