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