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