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 constraints\n");
277  getConstraints(fout, tblinfo, numTables);
278 
279  if (g_verbose)
280  write_msg(NULL, "reading triggers\n");
281  getTriggers(fout, tblinfo, numTables);
282 
283  if (g_verbose)
284  write_msg(NULL, "reading rewrite rules\n");
285  getRules(fout, &numRules);
286 
287  if (g_verbose)
288  write_msg(NULL, "reading policies\n");
289  getPolicies(fout, tblinfo, numTables);
290 
291  if (g_verbose)
292  write_msg(NULL, "reading partition key information for interesting tables\n");
293  getTablePartitionKeyInfo(fout, tblinfo, numTables);
294 
295  if (g_verbose)
296  write_msg(NULL, "reading publications\n");
297  getPublications(fout);
298 
299  if (g_verbose)
300  write_msg(NULL, "reading publication membership\n");
301  getPublicationTables(fout, tblinfo, numTables);
302 
303  if (g_verbose)
304  write_msg(NULL, "reading subscriptions\n");
305  getSubscriptions(fout);
306 
307  *numTablesPtr = numTables;
308  return tblinfo;
309 }
310 
311 /* flagInhTables -
312  * Fill in parent link fields of every target table, and mark
313  * parents of target tables as interesting
314  *
315  * Note that only direct ancestors of targets are marked interesting.
316  * This is sufficient; we don't much care whether they inherited their
317  * attributes or not.
318  *
319  * modifies tblinfo
320  */
321 static void
323  InhInfo *inhinfo, int numInherits)
324 {
325  int i,
326  j;
327  int numParents;
328  TableInfo **parents;
329 
330  for (i = 0; i < numTables; i++)
331  {
332  /* Some kinds never have parents */
333  if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
334  tblinfo[i].relkind == RELKIND_VIEW ||
335  tblinfo[i].relkind == RELKIND_MATVIEW)
336  continue;
337 
338  /* Don't bother computing anything for non-target tables, either */
339  if (!tblinfo[i].dobj.dump)
340  continue;
341 
342  /* Find all the immediate parent tables */
343  findParentsByOid(&tblinfo[i], inhinfo, numInherits);
344 
345  /* Mark the parents as interesting for getTableAttrs */
346  numParents = tblinfo[i].numParents;
347  parents = tblinfo[i].parents;
348  for (j = 0; j < numParents; j++)
349  parents[j]->interesting = true;
350  }
351 }
352 
353 /* flagPartitions -
354  * Fill in parent link fields of every target table that is partition,
355  * and mark parents of partitions as interesting
356  *
357  * modifies tblinfo
358  */
359 static void
361  PartInfo *partinfo, int numPartitions)
362 {
363  int i;
364 
365  for (i = 0; i < numTables; i++)
366  {
367  /* Some kinds are never partitions */
368  if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
369  tblinfo[i].relkind == RELKIND_VIEW ||
370  tblinfo[i].relkind == RELKIND_MATVIEW)
371  continue;
372 
373  /* Don't bother computing anything for non-target tables, either */
374  if (!tblinfo[i].dobj.dump)
375  continue;
376 
377  /* Find the parent TableInfo and save */
378  findPartitionParentByOid(&tblinfo[i], partinfo, numPartitions);
379 
380  /* Mark the parent as interesting for getTableAttrs */
381  if (tblinfo[i].partitionOf)
382  {
383  tblinfo[i].partitionOf->interesting = true;
384  addObjectDependency(&tblinfo[i].dobj,
385  tblinfo[i].partitionOf->dobj.dumpId);
386  }
387  }
388 }
389 
390 /* flagInhAttrs -
391  * for each dumpable table in tblinfo, flag its inherited attributes
392  *
393  * What we need to do here is detect child columns that inherit NOT NULL
394  * bits from their parents (so that we needn't specify that again for the
395  * child) and child columns that have DEFAULT NULL when their parents had
396  * some non-null default. In the latter case, we make up a dummy AttrDefInfo
397  * object so that we'll correctly emit the necessary DEFAULT NULL clause;
398  * otherwise the backend will apply an inherited default to the column.
399  *
400  * modifies tblinfo
401  */
402 static void
404 {
405  int i,
406  j,
407  k;
408 
409  for (i = 0; i < numTables; i++)
410  {
411  TableInfo *tbinfo = &(tblinfo[i]);
412  int numParents;
413  TableInfo **parents;
414 
415  /* Some kinds never have parents */
416  if (tbinfo->relkind == RELKIND_SEQUENCE ||
417  tbinfo->relkind == RELKIND_VIEW ||
418  tbinfo->relkind == RELKIND_MATVIEW)
419  continue;
420 
421  /* Don't bother computing anything for non-target tables, either */
422  if (!tbinfo->dobj.dump)
423  continue;
424 
425  numParents = tbinfo->numParents;
426  parents = tbinfo->parents;
427 
428  if (numParents == 0)
429  continue; /* nothing to see here, move along */
430 
431  /* For each column, search for matching column names in parent(s) */
432  for (j = 0; j < tbinfo->numatts; j++)
433  {
434  bool foundNotNull; /* Attr was NOT NULL in a parent */
435  bool foundDefault; /* Found a default in a parent */
436 
437  /* no point in examining dropped columns */
438  if (tbinfo->attisdropped[j])
439  continue;
440 
441  foundNotNull = false;
442  foundDefault = false;
443  for (k = 0; k < numParents; k++)
444  {
445  TableInfo *parent = parents[k];
446  int inhAttrInd;
447 
448  inhAttrInd = strInArray(tbinfo->attnames[j],
449  parent->attnames,
450  parent->numatts);
451  if (inhAttrInd >= 0)
452  {
453  foundNotNull |= parent->notnull[inhAttrInd];
454  foundDefault |= (parent->attrdefs[inhAttrInd] != NULL);
455  }
456  }
457 
458  /* Remember if we found inherited NOT NULL */
459  tbinfo->inhNotNull[j] = foundNotNull;
460 
461  /* Manufacture a DEFAULT NULL clause if necessary */
462  if (foundDefault && tbinfo->attrdefs[j] == NULL)
463  {
464  AttrDefInfo *attrDef;
465 
466  attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo));
467  attrDef->dobj.objType = DO_ATTRDEF;
468  attrDef->dobj.catId.tableoid = 0;
469  attrDef->dobj.catId.oid = 0;
470  AssignDumpId(&attrDef->dobj);
471  attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
472  attrDef->dobj.namespace = tbinfo->dobj.namespace;
473  attrDef->dobj.dump = tbinfo->dobj.dump;
474 
475  attrDef->adtable = tbinfo;
476  attrDef->adnum = j + 1;
477  attrDef->adef_expr = pg_strdup("NULL");
478 
479  /* Will column be dumped explicitly? */
480  if (shouldPrintColumn(dopt, tbinfo, j))
481  {
482  attrDef->separate = false;
483  /* No dependency needed: NULL cannot have dependencies */
484  }
485  else
486  {
487  /* column will be suppressed, print default separately */
488  attrDef->separate = true;
489  /* ensure it comes out after the table */
490  addObjectDependency(&attrDef->dobj,
491  tbinfo->dobj.dumpId);
492  }
493 
494  tbinfo->attrdefs[j] = attrDef;
495  }
496  }
497  }
498 }
499 
500 /*
501  * AssignDumpId
502  * Given a newly-created dumpable object, assign a dump ID,
503  * and enter the object into the lookup table.
504  *
505  * The caller is expected to have filled in objType and catId,
506  * but not any of the other standard fields of a DumpableObject.
507  */
508 void
510 {
511  dobj->dumpId = ++lastDumpId;
512  dobj->name = NULL; /* must be set later */
513  dobj->namespace = NULL; /* may be set later */
514  dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
515  dobj->ext_member = false; /* default assumption */
516  dobj->dependencies = NULL;
517  dobj->nDeps = 0;
518  dobj->allocDeps = 0;
519 
520  while (dobj->dumpId >= allocedDumpIds)
521  {
522  int newAlloc;
523 
524  if (allocedDumpIds <= 0)
525  {
526  newAlloc = 256;
527  dumpIdMap = (DumpableObject **)
528  pg_malloc(newAlloc * sizeof(DumpableObject *));
529  }
530  else
531  {
532  newAlloc = allocedDumpIds * 2;
533  dumpIdMap = (DumpableObject **)
534  pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
535  }
536  memset(dumpIdMap + allocedDumpIds, 0,
537  (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
538  allocedDumpIds = newAlloc;
539  }
540  dumpIdMap[dobj->dumpId] = dobj;
541 
542  /* mark catalogIdMap invalid, but don't rebuild it yet */
543  catalogIdMapValid = false;
544 }
545 
546 /*
547  * Assign a DumpId that's not tied to a DumpableObject.
548  *
549  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
550  * participate in the sorting logic.
551  */
552 DumpId
554 {
555  return ++lastDumpId;
556 }
557 
558 /*
559  * Return the largest DumpId so far assigned
560  */
561 DumpId
563 {
564  return lastDumpId;
565 }
566 
567 /*
568  * Find a DumpableObject by dump ID
569  *
570  * Returns NULL for invalid ID
571  */
574 {
575  if (dumpId <= 0 || dumpId >= allocedDumpIds)
576  return NULL; /* out of range? */
577  return dumpIdMap[dumpId];
578 }
579 
580 /*
581  * Find a DumpableObject by catalog ID
582  *
583  * Returns NULL for unknown ID
584  *
585  * We use binary search in a sorted list that is built on first call.
586  * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed,
587  * the code would work, but possibly be very slow. In the current usage
588  * pattern that does not happen, indeed we build the list at most twice.
589  */
592 {
593  DumpableObject **low;
594  DumpableObject **high;
595 
596  if (!catalogIdMapValid)
597  {
598  if (catalogIdMap)
599  free(catalogIdMap);
600  getDumpableObjects(&catalogIdMap, &numCatalogIds);
601  if (numCatalogIds > 1)
602  qsort((void *) catalogIdMap, numCatalogIds,
604  catalogIdMapValid = true;
605  }
606 
607  /*
608  * We could use bsearch() here, but the notational cruft of calling
609  * bsearch is nearly as bad as doing it ourselves; and the generalized
610  * bsearch function is noticeably slower as well.
611  */
612  if (numCatalogIds <= 0)
613  return NULL;
614  low = catalogIdMap;
615  high = catalogIdMap + (numCatalogIds - 1);
616  while (low <= high)
617  {
618  DumpableObject **middle;
619  int difference;
620 
621  middle = low + (high - low) / 2;
622  /* comparison must match DOCatalogIdCompare, below */
623  difference = oidcmp((*middle)->catId.oid, catalogId.oid);
624  if (difference == 0)
625  difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
626  if (difference == 0)
627  return *middle;
628  else if (difference < 0)
629  low = middle + 1;
630  else
631  high = middle - 1;
632  }
633  return NULL;
634 }
635 
636 /*
637  * Find a DumpableObject by OID, in a pre-sorted array of one type of object
638  *
639  * Returns NULL for unknown OID
640  */
641 static DumpableObject *
642 findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
643 {
644  DumpableObject **low;
645  DumpableObject **high;
646 
647  /*
648  * This is the same as findObjectByCatalogId except we assume we need not
649  * look at table OID because the objects are all the same type.
650  *
651  * We could use bsearch() here, but the notational cruft of calling
652  * bsearch is nearly as bad as doing it ourselves; and the generalized
653  * bsearch function is noticeably slower as well.
654  */
655  if (numObjs <= 0)
656  return NULL;
657  low = indexArray;
658  high = indexArray + (numObjs - 1);
659  while (low <= high)
660  {
661  DumpableObject **middle;
662  int difference;
663 
664  middle = low + (high - low) / 2;
665  difference = oidcmp((*middle)->catId.oid, oid);
666  if (difference == 0)
667  return *middle;
668  else if (difference < 0)
669  low = middle + 1;
670  else
671  high = middle - 1;
672  }
673  return NULL;
674 }
675 
676 /*
677  * Build an index array of DumpableObject pointers, sorted by OID
678  */
679 static DumpableObject **
680 buildIndexArray(void *objArray, int numObjs, Size objSize)
681 {
682  DumpableObject **ptrs;
683  int i;
684 
685  ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
686  for (i = 0; i < numObjs; i++)
687  ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
688 
689  /* We can use DOCatalogIdCompare to sort since its first key is OID */
690  if (numObjs > 1)
691  qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
693 
694  return ptrs;
695 }
696 
697 /*
698  * qsort comparator for pointers to DumpableObjects
699  */
700 static int
701 DOCatalogIdCompare(const void *p1, const void *p2)
702 {
703  const DumpableObject *obj1 = *(DumpableObject *const *) p1;
704  const DumpableObject *obj2 = *(DumpableObject *const *) p2;
705  int cmpval;
706 
707  /*
708  * Compare OID first since it's usually unique, whereas there will only be
709  * a few distinct values of tableoid.
710  */
711  cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
712  if (cmpval == 0)
713  cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
714  return cmpval;
715 }
716 
717 /*
718  * Build an array of pointers to all known dumpable objects
719  *
720  * This simply creates a modifiable copy of the internal map.
721  */
722 void
723 getDumpableObjects(DumpableObject ***objs, int *numObjs)
724 {
725  int i,
726  j;
727 
728  *objs = (DumpableObject **)
730  j = 0;
731  for (i = 1; i < allocedDumpIds; i++)
732  {
733  if (dumpIdMap[i])
734  (*objs)[j++] = dumpIdMap[i];
735  }
736  *numObjs = j;
737 }
738 
739 /*
740  * Add a dependency link to a DumpableObject
741  *
742  * Note: duplicate dependencies are currently not eliminated
743  */
744 void
746 {
747  if (dobj->nDeps >= dobj->allocDeps)
748  {
749  if (dobj->allocDeps <= 0)
750  {
751  dobj->allocDeps = 16;
752  dobj->dependencies = (DumpId *)
753  pg_malloc(dobj->allocDeps * sizeof(DumpId));
754  }
755  else
756  {
757  dobj->allocDeps *= 2;
758  dobj->dependencies = (DumpId *)
759  pg_realloc(dobj->dependencies,
760  dobj->allocDeps * sizeof(DumpId));
761  }
762  }
763  dobj->dependencies[dobj->nDeps++] = refId;
764 }
765 
766 /*
767  * Remove a dependency link from a DumpableObject
768  *
769  * If there are multiple links, all are removed
770  */
771 void
773 {
774  int i;
775  int j = 0;
776 
777  for (i = 0; i < dobj->nDeps; i++)
778  {
779  if (dobj->dependencies[i] != refId)
780  dobj->dependencies[j++] = dobj->dependencies[i];
781  }
782  dobj->nDeps = j;
783 }
784 
785 
786 /*
787  * findTableByOid
788  * finds the entry (in tblinfo) of the table with the given oid
789  * returns NULL if not found
790  */
791 TableInfo *
793 {
794  return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
795 }
796 
797 /*
798  * findTypeByOid
799  * finds the entry (in typinfo) of the type with the given oid
800  * returns NULL if not found
801  */
802 TypeInfo *
804 {
805  return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
806 }
807 
808 /*
809  * findFuncByOid
810  * finds the entry (in funinfo) of the function with the given oid
811  * returns NULL if not found
812  */
813 FuncInfo *
815 {
816  return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
817 }
818 
819 /*
820  * findOprByOid
821  * finds the entry (in oprinfo) of the operator with the given oid
822  * returns NULL if not found
823  */
824 OprInfo *
826 {
827  return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
828 }
829 
830 /*
831  * findCollationByOid
832  * finds the entry (in collinfo) of the collation with the given oid
833  * returns NULL if not found
834  */
835 CollInfo *
837 {
838  return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
839 }
840 
841 /*
842  * findNamespaceByOid
843  * finds the entry (in nspinfo) of the namespace with the given oid
844  * returns NULL if not found
845  */
848 {
849  return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
850 }
851 
852 /*
853  * findExtensionByOid
854  * finds the entry (in extinfo) of the extension with the given oid
855  * returns NULL if not found
856  */
859 {
860  return (ExtensionInfo *) findObjectByOid(oid, extinfoindex, numExtensions);
861 }
862 
863 
864 /*
865  * setExtensionMembership
866  * accept and save data about which objects belong to extensions
867  */
868 void
870 {
871  /* Sort array in preparation for binary searches */
872  if (nextmems > 1)
873  qsort((void *) extmems, nextmems, sizeof(ExtensionMemberId),
875  /* And save */
876  extmembers = extmems;
877  numextmembers = nextmems;
878 }
879 
880 /*
881  * findOwningExtension
882  * return owning extension for specified catalog ID, or NULL if none
883  */
886 {
887  ExtensionMemberId *low;
888  ExtensionMemberId *high;
889 
890  /*
891  * We could use bsearch() here, but the notational cruft of calling
892  * bsearch is nearly as bad as doing it ourselves; and the generalized
893  * bsearch function is noticeably slower as well.
894  */
895  if (numextmembers <= 0)
896  return NULL;
897  low = extmembers;
898  high = extmembers + (numextmembers - 1);
899  while (low <= high)
900  {
901  ExtensionMemberId *middle;
902  int difference;
903 
904  middle = low + (high - low) / 2;
905  /* comparison must match ExtensionMemberIdCompare, below */
906  difference = oidcmp(middle->catId.oid, catalogId.oid);
907  if (difference == 0)
908  difference = oidcmp(middle->catId.tableoid, catalogId.tableoid);
909  if (difference == 0)
910  return middle->ext;
911  else if (difference < 0)
912  low = middle + 1;
913  else
914  high = middle - 1;
915  }
916  return NULL;
917 }
918 
919 /*
920  * qsort comparator for ExtensionMemberIds
921  */
922 static int
923 ExtensionMemberIdCompare(const void *p1, const void *p2)
924 {
925  const ExtensionMemberId *obj1 = (const ExtensionMemberId *) p1;
926  const ExtensionMemberId *obj2 = (const ExtensionMemberId *) p2;
927  int cmpval;
928 
929  /*
930  * Compare OID first since it's usually unique, whereas there will only be
931  * a few distinct values of tableoid.
932  */
933  cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
934  if (cmpval == 0)
935  cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
936  return cmpval;
937 }
938 
939 
940 /*
941  * findParentsByOid
942  * find a table's parents in tblinfo[]
943  */
944 static void
946  InhInfo *inhinfo, int numInherits)
947 {
948  Oid oid = self->dobj.catId.oid;
949  int i,
950  j;
951  int numParents;
952 
953  numParents = 0;
954  for (i = 0; i < numInherits; i++)
955  {
956  if (inhinfo[i].inhrelid == oid)
957  numParents++;
958  }
959 
960  self->numParents = numParents;
961 
962  if (numParents > 0)
963  {
964  self->parents = (TableInfo **)
965  pg_malloc(sizeof(TableInfo *) * numParents);
966  j = 0;
967  for (i = 0; i < numInherits; i++)
968  {
969  if (inhinfo[i].inhrelid == oid)
970  {
971  TableInfo *parent;
972 
973  parent = findTableByOid(inhinfo[i].inhparent);
974  if (parent == NULL)
975  {
976  write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n",
977  inhinfo[i].inhparent,
978  self->dobj.name,
979  oid);
980  exit_nicely(1);
981  }
982  self->parents[j++] = parent;
983  }
984  }
985  }
986  else
987  self->parents = NULL;
988 }
989 
990 /*
991  * findPartitionParentByOid
992  * find a partition's parent in tblinfo[]
993  */
994 static void
996  int numPartitions)
997 {
998  Oid oid = self->dobj.catId.oid;
999  int i;
1000 
1001  for (i = 0; i < numPartitions; i++)
1002  {
1003  if (partinfo[i].partrelid == oid)
1004  {
1005  TableInfo *parent;
1006 
1007  parent = findTableByOid(partinfo[i].partparent);
1008  if (parent == NULL)
1009  {
1010  write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n",
1011  partinfo[i].partparent,
1012  self->dobj.name,
1013  oid);
1014  exit_nicely(1);
1015  }
1016  self->partitionOf = parent;
1017 
1018  /* While we're at it, also save the partdef */
1019  self->partitiondef = partinfo[i].partdef;
1020  }
1021  }
1022 }
1023 
1024 /*
1025  * parseOidArray
1026  * parse a string of numbers delimited by spaces into a character array
1027  *
1028  * Note: actually this is used for both Oids and potentially-signed
1029  * attribute numbers. This should cause no trouble, but we could split
1030  * the function into two functions with different argument types if it does.
1031  */
1032 
1033 void
1034 parseOidArray(const char *str, Oid *array, int arraysize)
1035 {
1036  int j,
1037  argNum;
1038  char temp[100];
1039  char s;
1040 
1041  argNum = 0;
1042  j = 0;
1043  for (;;)
1044  {
1045  s = *str++;
1046  if (s == ' ' || s == '\0')
1047  {
1048  if (j > 0)
1049  {
1050  if (argNum >= arraysize)
1051  {
1052  write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str);
1053  exit_nicely(1);
1054  }
1055  temp[j] = '\0';
1056  array[argNum++] = atooid(temp);
1057  j = 0;
1058  }
1059  if (s == '\0')
1060  break;
1061  }
1062  else
1063  {
1064  if (!(isdigit((unsigned char) s) || s == '-') ||
1065  j >= sizeof(temp) - 1)
1066  {
1067  write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str);
1068  exit_nicely(1);
1069  }
1070  temp[j++] = s;
1071  }
1072  }
1073 
1074  while (argNum < arraysize)
1075  array[argNum++] = InvalidOid;
1076 }
1077 
1078 
1079 /*
1080  * strInArray:
1081  * takes in a string and a string array and the number of elements in the
1082  * string array.
1083  * returns the index if the string is somewhere in the array, -1 otherwise
1084  */
1085 
1086 static int
1087 strInArray(const char *pattern, char **arr, int arr_size)
1088 {
1089  int i;
1090 
1091  for (i = 0; i < arr_size; i++)
1092  {
1093  if (strcmp(pattern, arr[i]) == 0)
1094  return i;
1095  }
1096  return -1;
1097 }
FuncInfo * getFuncs(Archive *fout, int *numFuncs)
Definition: pg_dump.c:5107
static DumpableObject ** collinfoindex
Definition: common.c:54
static int numTypes
Definition: common.c:58
char * name
Definition: pg_dump.h:132
TableInfo * findTableByOid(Oid oid)
Definition: common.c:792
ExtensionInfo * ext
Definition: pg_dump.h:619
int DumpId
Definition: pg_backup.h:228
AggInfo * getAggregates(Archive *fout, int *numAggs)
Definition: pg_dump.c:4915
struct _tableInfo ** parents
Definition: pg_dump.h:324
static int allocedDumpIds
Definition: common.c:32
void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:3464
static void flagPartitions(TableInfo *tblinfo, int numTables, PartInfo *partinfo, int numPartitions)
Definition: common.c:360
CollInfo * getCollations(Archive *fout, int *numCollations)
Definition: pg_dump.c:4514
char relkind
Definition: pg_dump.h:266
DumpComponents dump
Definition: pg_dump.h:133
static DumpId lastDumpId
Definition: common.c:33
Oid tableoid
Definition: pg_backup.h:224
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:995
void AssignDumpId(DumpableObject *dobj)
Definition: common.c:509
OprInfo * getOperators(Archive *fout, int *numOprs)
Definition: pg_dump.c:4428
static DumpableObject ** oprinfoindex
Definition: common.c:53
DumpId * dependencies
Definition: pg_dump.h:137
char * partdef
Definition: pg_dump.h:473
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
TransformInfo * getTransforms(Archive *fout, int *numTransforms)
Definition: pg_dump.c:7413
DefaultACLInfo * getDefaultACLs(Archive *fout, int *numDefaultACLs)
Definition: pg_dump.c:8674
static int numFuncs
Definition: common.c:59
AccessMethodInfo * getAccessMethods(Archive *fout, int *numAccessMethods)
Definition: pg_dump.c:4673
static int DOCatalogIdCompare(const void *p1, const void *p2)
Definition: common.c:701
bool shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
Definition: pg_dump.c:7996
#define RELKIND_MATVIEW
Definition: pg_class.h:167
static int numCatalogIds
Definition: common.c:40
OpclassInfo * getOpclasses(Archive *fout, int *numOpclasses)
Definition: pg_dump.c:4750
bool * inhNotNull
Definition: pg_dump.h:315
TSConfigInfo * getTSConfigurations(Archive *fout, int *numTSConfigs)
Definition: pg_dump.c:8272
PartInfo * getPartitions(Archive *fout, int *numPartitions)
Definition: pg_dump.c:6171
static void flagInhTables(TableInfo *tbinfo, int numTables, InhInfo *inhinfo, int numInherits)
Definition: common.c:322
static void findParentsByOid(TableInfo *self, InhInfo *inhinfo, int numInherits)
Definition: common.c:945
DumpId dumpId
Definition: pg_dump.h:131
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:7507
char ** attnames
Definition: pg_dump.h:301
DumpableObject dobj
Definition: pg_dump.h:260
bool ext_member
Definition: pg_dump.h:136
static DumpableObject ** buildIndexArray(void *objArray, int numObjs, Size objSize)
Definition: common.c:680
TSParserInfo * getTSParsers(Archive *fout, int *numTSParsers)
Definition: pg_dump.c:8012
static DumpableObject * findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
Definition: common.c:642
static int strInArray(const char *pattern, char **arr, int arr_size)
Definition: common.c:1087
static DumpableObject ** typinfoindex
Definition: common.c:51
OprInfo * findOprByOid(Oid oid)
Definition: common.c:825
bool separate
Definition: pg_dump.h:338
void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:6522
InhInfo * getInherits(Archive *fout, int *numInherits)
Definition: pg_dump.c:6114
ExtensionInfo * findOwningExtension(CatalogId catalogId)
Definition: common.c:885
static int numOperators
Definition: common.c:60
DumpOptions * dopt
Definition: pg_backup.h:178
void setExtensionMembership(ExtensionMemberId *extmems, int nextmems)
Definition: common.c:869
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition: common.c:573
TableInfo * getTables(Archive *fout, int *numTables)
Definition: pg_dump.c:5341
void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:3065
DumpableObject * findObjectByCatalogId(CatalogId catalogId)
Definition: common.c:591
EventTriggerInfo * getEventTriggers(Archive *fout, int *numEventTriggers)
Definition: pg_dump.c:7022
static DumpableObject ** tblinfoindex
Definition: common.c:50
NamespaceInfo * findNamespaceByOid(Oid oid)
Definition: common.c:847
NamespaceInfo * getNamespaces(Archive *fout, int *numNamespaces)
Definition: pg_dump.c:3941
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
bool * attisdropped
Definition: pg_dump.h:307
TableInfo * getSchemaData(Archive *fout, int *numTablesPtr)
Definition: common.c:90
static int numExtensions
Definition: common.c:63
TableInfo * adtable
Definition: pg_dump.h:335
static int numNamespaces
Definition: common.c:62
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
RuleInfo * getRules(Archive *fout, int *numRules)
Definition: pg_dump.c:6706
FuncInfo * findFuncByOid(Oid oid)
Definition: common.c:814
FdwInfo * getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
Definition: pg_dump.c:8352
void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:16780
int numatts
Definition: pg_dump.h:300
void getSubscriptions(Archive *fout)
Definition: pg_dump.c:3594
void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:6237
static int ExtensionMemberIdCompare(const void *p1, const void *p2)
Definition: common.c:923
TSDictInfo * getTSDictionaries(Archive *fout, int *numTSDicts)
Definition: pg_dump.c:8106
#define exit_nicely(code)
Definition: pg_dumpall.c:86
void parseOidArray(const char *str, Oid *array, int arraysize)
Definition: common.c:1034
void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:6822
Datum difference(PG_FUNCTION_ARGS)
static ExtensionMemberId * extmembers
Definition: common.c:66
ExtensionInfo * findExtensionByOid(Oid oid)
Definition: common.c:858
void removeObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:772
void getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition: pg_dump.c:7556
bool * notnull
Definition: pg_dump.h:314
DumpableObject dobj
Definition: pg_dump.h:334
#define InvalidOid
Definition: postgres_ext.h:36
DumpId getMaxDumpId(void)
Definition: common.c:562
#define free(a)
Definition: header.h:60
void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:6063
char * partitiondef
Definition: pg_dump.h:329
void write_msg(const char *modulename, const char *fmt,...)
ConvInfo * getConversions(Archive *fout, int *numConversions)
Definition: pg_dump.c:4597
#define NULL
Definition: c.h:226
static DumpableObject ** catalogIdMap
Definition: common.c:39
struct _tableInfo * partitionOf
Definition: pg_dump.h:328
static bool catalogIdMapValid
Definition: common.c:38
CollInfo * findCollationByOid(Oid oid)
Definition: common.c:836
size_t Size
Definition: c.h:353
struct _attrDefInfo ** attrdefs
Definition: pg_dump.h:316
OpfamilyInfo * getOpfamilies(Archive *fout, int *numOpfamilies)
Definition: pg_dump.c:4828
TSTemplateInfo * getTSTemplates(Archive *fout, int *numTSTemplates)
Definition: pg_dump.c:8193
static int numCollations
Definition: common.c:61
ExtensionInfo * getExtensions(Archive *fout, int *numExtensions)
Definition: pg_dump.c:4088
static int numextmembers
Definition: common.c:67
TypeInfo * getTypes(Archive *fout, int *numTypes)
Definition: pg_dump.c:4175
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:745
static DumpableObject ** extinfoindex
Definition: common.c:56
void getPublications(Archive *fout)
Definition: pg_dump.c:3328
ForeignServerInfo * getForeignServers(Archive *fout, int *numForeignServers)
Definition: pg_dump.c:8521
static DumpableObject ** funinfoindex
Definition: common.c:52
CatalogId catId
Definition: pg_dump.h:130
#define atooid(x)
Definition: lo.c:17
#define DUMP_COMPONENT_ALL
Definition: pg_dump.h:98
bool interesting
Definition: pg_dump.h:292
CatalogId catId
Definition: pg_dump.h:618
#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:7116
TypeInfo * findTypeByOid(Oid oid)
Definition: common.c:803
void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:16672
int numParents
Definition: pg_dump.h:323
#define qsort(a, b, c, d)
Definition: port.h:440
#define RELKIND_SEQUENCE
Definition: pg_class.h:162
DumpableObjectType objType
Definition: pg_dump.h:129
static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
Definition: common.c:403
bool g_verbose
Definition: pg_dump.c:93
DumpId createDumpId(void)
Definition: common.c:553
CastInfo * getCasts(Archive *fout, int *numCasts)
Definition: pg_dump.c:7297
char * adef_expr
Definition: pg_dump.h:337
void getDumpableObjects(DumpableObject ***objs, int *numObjs)
Definition: common.c:723