1 /*-------------------------------------------------------------------------
4 * Catalog routines used by pg_dump; long ago these were shared
5 * by another dump tool, but not anymore.
7 * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/bin/pg_dump/common.c
14 *-------------------------------------------------------------------------
16 #include "pg_backup_archiver.h"
17 #include "pg_backup_utils.h"
21 #include "catalog/pg_class.h"
25 * Variables for mapping DumpId to DumpableObject
27 static DumpableObject **dumpIdMap = NULL;
28 static int allocedDumpIds = 0;
29 static DumpId lastDumpId = 0;
32 * Variables for mapping CatalogId to DumpableObject
34 static bool catalogIdMapValid = false;
35 static DumpableObject **catalogIdMap = NULL;
36 static int numCatalogIds = 0;
39 * These variables are static to avoid the notational cruft of having to pass
40 * them into findTableByOid() and friends. For each of these arrays, we
41 * build a sorted-by-OID index array immediately after it's built, and then
42 * we use binary search in findTableByOid() and friends. (qsort'ing the base
43 * arrays themselves would be simpler, but it doesn't work because pg_dump.c
44 * may have already established pointers between items.)
46 static TableInfo *tblinfo;
47 static TypeInfo *typinfo;
48 static FuncInfo *funinfo;
49 static OprInfo *oprinfo;
50 static NamespaceInfo *nspinfo;
54 static int numOperators;
55 static int numCollations;
56 static int numNamespaces;
57 static DumpableObject **tblinfoindex;
58 static DumpableObject **typinfoindex;
59 static DumpableObject **funinfoindex;
60 static DumpableObject **oprinfoindex;
61 static DumpableObject **collinfoindex;
62 static DumpableObject **nspinfoindex;
65 static void flagInhTables(TableInfo *tbinfo, int numTables,
66 InhInfo *inhinfo, int numInherits);
67 static void flagInhAttrs(TableInfo *tblinfo, int numTables);
68 static DumpableObject **buildIndexArray(void *objArray, int numObjs,
70 static int DOCatalogIdCompare(const void *p1, const void *p2);
71 static void findParentsByOid(TableInfo *self,
72 InhInfo *inhinfo, int numInherits);
73 static int strInArray(const char *pattern, char **arr, int arr_size);
78 * Collect information about all potentially dumpable objects
81 getSchemaData(Archive *fout, int *numTablesPtr)
83 ExtensionInfo *extinfo;
99 int numForeignDataWrappers;
100 int numForeignServers;
102 int numEventTriggers;
105 write_msg(NULL, "reading schemas\n");
106 nspinfo = getNamespaces(fout, &numNamespaces);
107 nspinfoindex = buildIndexArray(nspinfo, numNamespaces, sizeof(NamespaceInfo));
110 * getTables should be done as soon as possible, so as to minimize the
111 * window between starting our transaction and acquiring per-table locks.
112 * However, we have to do getNamespaces first because the tables get
113 * linked to their containing namespaces during getTables.
116 write_msg(NULL, "reading user-defined tables\n");
117 tblinfo = getTables(fout, &numTables);
118 tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
120 /* Do this after we've built tblinfoindex */
121 getOwnedSeqs(fout, tblinfo, numTables);
124 write_msg(NULL, "reading extensions\n");
125 extinfo = getExtensions(fout, &numExtensions);
128 write_msg(NULL, "reading user-defined functions\n");
129 funinfo = getFuncs(fout, &numFuncs);
130 funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
132 /* this must be after getTables and getFuncs */
134 write_msg(NULL, "reading user-defined types\n");
135 typinfo = getTypes(fout, &numTypes);
136 typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
138 /* this must be after getFuncs, too */
140 write_msg(NULL, "reading procedural languages\n");
141 getProcLangs(fout, &numProcLangs);
144 write_msg(NULL, "reading user-defined aggregate functions\n");
145 getAggregates(fout, &numAggregates);
148 write_msg(NULL, "reading user-defined operators\n");
149 oprinfo = getOperators(fout, &numOperators);
150 oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
153 write_msg(NULL, "reading user-defined operator classes\n");
154 getOpclasses(fout, &numOpclasses);
157 write_msg(NULL, "reading user-defined operator families\n");
158 getOpfamilies(fout, &numOpfamilies);
161 write_msg(NULL, "reading user-defined text search parsers\n");
162 getTSParsers(fout, &numTSParsers);
165 write_msg(NULL, "reading user-defined text search templates\n");
166 getTSTemplates(fout, &numTSTemplates);
169 write_msg(NULL, "reading user-defined text search dictionaries\n");
170 getTSDictionaries(fout, &numTSDicts);
173 write_msg(NULL, "reading user-defined text search configurations\n");
174 getTSConfigurations(fout, &numTSConfigs);
177 write_msg(NULL, "reading user-defined foreign-data wrappers\n");
178 getForeignDataWrappers(fout, &numForeignDataWrappers);
181 write_msg(NULL, "reading user-defined foreign servers\n");
182 getForeignServers(fout, &numForeignServers);
185 write_msg(NULL, "reading default privileges\n");
186 getDefaultACLs(fout, &numDefaultACLs);
189 write_msg(NULL, "reading user-defined collations\n");
190 collinfo = getCollations(fout, &numCollations);
191 collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
194 write_msg(NULL, "reading user-defined conversions\n");
195 getConversions(fout, &numConversions);
198 write_msg(NULL, "reading type casts\n");
199 getCasts(fout, &numCasts);
202 write_msg(NULL, "reading table inheritance information\n");
203 inhinfo = getInherits(fout, &numInherits);
206 write_msg(NULL, "reading event triggers\n");
207 getEventTriggers(fout, &numEventTriggers);
210 * Identify extension member objects and mark them as not to be dumped.
211 * This must happen after reading all objects that can be direct members
212 * of extensions, but before we begin to process table subsidiary objects.
215 write_msg(NULL, "finding extension members\n");
216 getExtensionMembership(fout, extinfo, numExtensions);
218 /* Link tables to parents, mark parents of target tables interesting */
220 write_msg(NULL, "finding inheritance relationships\n");
221 flagInhTables(tblinfo, numTables, inhinfo, numInherits);
224 write_msg(NULL, "reading column info for interesting tables\n");
225 getTableAttrs(fout, tblinfo, numTables);
228 write_msg(NULL, "flagging inherited columns in subtables\n");
229 flagInhAttrs(tblinfo, numTables);
232 write_msg(NULL, "reading indexes\n");
233 getIndexes(fout, tblinfo, numTables);
236 write_msg(NULL, "reading constraints\n");
237 getConstraints(fout, tblinfo, numTables);
240 write_msg(NULL, "reading triggers\n");
241 getTriggers(fout, tblinfo, numTables);
244 write_msg(NULL, "reading rewrite rules\n");
245 getRules(fout, &numRules);
247 *numTablesPtr = numTables;
252 * Fill in parent link fields of every target table, and mark
253 * parents of target tables as interesting
255 * Note that only direct ancestors of targets are marked interesting.
256 * This is sufficient; we don't much care whether they inherited their
262 flagInhTables(TableInfo *tblinfo, int numTables,
263 InhInfo *inhinfo, int numInherits)
270 for (i = 0; i < numTables; i++)
272 /* Some kinds never have parents */
273 if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
274 tblinfo[i].relkind == RELKIND_VIEW ||
275 tblinfo[i].relkind == RELKIND_MATVIEW)
278 /* Don't bother computing anything for non-target tables, either */
279 if (!tblinfo[i].dobj.dump)
282 /* Find all the immediate parent tables */
283 findParentsByOid(&tblinfo[i], inhinfo, numInherits);
285 /* Mark the parents as interesting for getTableAttrs */
286 numParents = tblinfo[i].numParents;
287 parents = tblinfo[i].parents;
288 for (j = 0; j < numParents; j++)
289 parents[j]->interesting = true;
294 * for each dumpable table in tblinfo, flag its inherited attributes
296 * What we need to do here is detect child columns that inherit NOT NULL
297 * bits from their parents (so that we needn't specify that again for the
298 * child) and child columns that have DEFAULT NULL when their parents had
299 * some non-null default. In the latter case, we make up a dummy AttrDefInfo
300 * object so that we'll correctly emit the necessary DEFAULT NULL clause;
301 * otherwise the backend will apply an inherited default to the column.
306 flagInhAttrs(TableInfo *tblinfo, int numTables)
312 for (i = 0; i < numTables; i++)
314 TableInfo *tbinfo = &(tblinfo[i]);
318 /* Some kinds never have parents */
319 if (tbinfo->relkind == RELKIND_SEQUENCE ||
320 tbinfo->relkind == RELKIND_VIEW ||
321 tbinfo->relkind == RELKIND_MATVIEW)
324 /* Don't bother computing anything for non-target tables, either */
325 if (!tbinfo->dobj.dump)
328 numParents = tbinfo->numParents;
329 parents = tbinfo->parents;
332 continue; /* nothing to see here, move along */
334 /* For each column, search for matching column names in parent(s) */
335 for (j = 0; j < tbinfo->numatts; j++)
337 bool foundNotNull; /* Attr was NOT NULL in a parent */
338 bool foundDefault; /* Found a default in a parent */
340 /* no point in examining dropped columns */
341 if (tbinfo->attisdropped[j])
344 foundNotNull = false;
345 foundDefault = false;
346 for (k = 0; k < numParents; k++)
348 TableInfo *parent = parents[k];
351 inhAttrInd = strInArray(tbinfo->attnames[j],
356 foundNotNull |= parent->notnull[inhAttrInd];
357 foundDefault |= (parent->attrdefs[inhAttrInd] != NULL);
361 /* Remember if we found inherited NOT NULL */
362 tbinfo->inhNotNull[j] = foundNotNull;
364 /* Manufacture a DEFAULT NULL clause if necessary */
365 if (foundDefault && tbinfo->attrdefs[j] == NULL)
367 AttrDefInfo *attrDef;
369 attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo));
370 attrDef->dobj.objType = DO_ATTRDEF;
371 attrDef->dobj.catId.tableoid = 0;
372 attrDef->dobj.catId.oid = 0;
373 AssignDumpId(&attrDef->dobj);
374 attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
375 attrDef->dobj.namespace = tbinfo->dobj.namespace;
376 attrDef->dobj.dump = tbinfo->dobj.dump;
378 attrDef->adtable = tbinfo;
379 attrDef->adnum = j + 1;
380 attrDef->adef_expr = pg_strdup("NULL");
382 /* Will column be dumped explicitly? */
383 if (shouldPrintColumn(tbinfo, j))
385 attrDef->separate = false;
386 /* No dependency needed: NULL cannot have dependencies */
390 /* column will be suppressed, print default separately */
391 attrDef->separate = true;
392 /* ensure it comes out after the table */
393 addObjectDependency(&attrDef->dobj,
394 tbinfo->dobj.dumpId);
397 tbinfo->attrdefs[j] = attrDef;
405 * Given a newly-created dumpable object, assign a dump ID,
406 * and enter the object into the lookup table.
408 * The caller is expected to have filled in objType and catId,
409 * but not any of the other standard fields of a DumpableObject.
412 AssignDumpId(DumpableObject *dobj)
414 dobj->dumpId = ++lastDumpId;
415 dobj->name = NULL; /* must be set later */
416 dobj->namespace = NULL; /* may be set later */
417 dobj->dump = true; /* default assumption */
418 dobj->ext_member = false; /* default assumption */
419 dobj->dependencies = NULL;
423 while (dobj->dumpId >= allocedDumpIds)
427 if (allocedDumpIds <= 0)
430 dumpIdMap = (DumpableObject **)
431 pg_malloc(newAlloc * sizeof(DumpableObject *));
435 newAlloc = allocedDumpIds * 2;
436 dumpIdMap = (DumpableObject **)
437 pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
439 memset(dumpIdMap + allocedDumpIds, 0,
440 (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
441 allocedDumpIds = newAlloc;
443 dumpIdMap[dobj->dumpId] = dobj;
445 /* mark catalogIdMap invalid, but don't rebuild it yet */
446 catalogIdMapValid = false;
450 * Assign a DumpId that's not tied to a DumpableObject.
452 * This is used when creating a "fixed" ArchiveEntry that doesn't need to
453 * participate in the sorting logic.
462 * Return the largest DumpId so far assigned
471 * Find a DumpableObject by dump ID
473 * Returns NULL for invalid ID
476 findObjectByDumpId(DumpId dumpId)
478 if (dumpId <= 0 || dumpId >= allocedDumpIds)
479 return NULL; /* out of range? */
480 return dumpIdMap[dumpId];
484 * Find a DumpableObject by catalog ID
486 * Returns NULL for unknown ID
488 * We use binary search in a sorted list that is built on first call.
489 * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed,
490 * the code would work, but possibly be very slow. In the current usage
491 * pattern that does not happen, indeed we build the list at most twice.
494 findObjectByCatalogId(CatalogId catalogId)
496 DumpableObject **low;
497 DumpableObject **high;
499 if (!catalogIdMapValid)
503 getDumpableObjects(&catalogIdMap, &numCatalogIds);
504 if (numCatalogIds > 1)
505 qsort((void *) catalogIdMap, numCatalogIds,
506 sizeof(DumpableObject *), DOCatalogIdCompare);
507 catalogIdMapValid = true;
511 * We could use bsearch() here, but the notational cruft of calling
512 * bsearch is nearly as bad as doing it ourselves; and the generalized
513 * bsearch function is noticeably slower as well.
515 if (numCatalogIds <= 0)
518 high = catalogIdMap + (numCatalogIds - 1);
521 DumpableObject **middle;
524 middle = low + (high - low) / 2;
525 /* comparison must match DOCatalogIdCompare, below */
526 difference = oidcmp((*middle)->catId.oid, catalogId.oid);
528 difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
531 else if (difference < 0)
540 * Find a DumpableObject by OID, in a pre-sorted array of one type of object
542 * Returns NULL for unknown OID
544 static DumpableObject *
545 findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
547 DumpableObject **low;
548 DumpableObject **high;
551 * This is the same as findObjectByCatalogId except we assume we need not
552 * look at table OID because the objects are all the same type.
554 * We could use bsearch() here, but the notational cruft of calling
555 * bsearch is nearly as bad as doing it ourselves; and the generalized
556 * bsearch function is noticeably slower as well.
561 high = indexArray + (numObjs - 1);
564 DumpableObject **middle;
567 middle = low + (high - low) / 2;
568 difference = oidcmp((*middle)->catId.oid, oid);
571 else if (difference < 0)
580 * Build an index array of DumpableObject pointers, sorted by OID
582 static DumpableObject **
583 buildIndexArray(void *objArray, int numObjs, Size objSize)
585 DumpableObject **ptrs;
588 ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
589 for (i = 0; i < numObjs; i++)
590 ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
592 /* We can use DOCatalogIdCompare to sort since its first key is OID */
594 qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
601 * qsort comparator for pointers to DumpableObjects
604 DOCatalogIdCompare(const void *p1, const void *p2)
606 const DumpableObject *obj1 = *(DumpableObject *const *) p1;
607 const DumpableObject *obj2 = *(DumpableObject *const *) p2;
611 * Compare OID first since it's usually unique, whereas there will only be
612 * a few distinct values of tableoid.
614 cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
616 cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
621 * Build an array of pointers to all known dumpable objects
623 * This simply creates a modifiable copy of the internal map.
626 getDumpableObjects(DumpableObject ***objs, int *numObjs)
631 *objs = (DumpableObject **)
632 pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
634 for (i = 1; i < allocedDumpIds; i++)
637 (*objs)[j++] = dumpIdMap[i];
643 * Add a dependency link to a DumpableObject
645 * Note: duplicate dependencies are currently not eliminated
648 addObjectDependency(DumpableObject *dobj, DumpId refId)
650 if (dobj->nDeps >= dobj->allocDeps)
652 if (dobj->allocDeps <= 0)
654 dobj->allocDeps = 16;
655 dobj->dependencies = (DumpId *)
656 pg_malloc(dobj->allocDeps * sizeof(DumpId));
660 dobj->allocDeps *= 2;
661 dobj->dependencies = (DumpId *)
662 pg_realloc(dobj->dependencies,
663 dobj->allocDeps * sizeof(DumpId));
666 dobj->dependencies[dobj->nDeps++] = refId;
670 * Remove a dependency link from a DumpableObject
672 * If there are multiple links, all are removed
675 removeObjectDependency(DumpableObject *dobj, DumpId refId)
680 for (i = 0; i < dobj->nDeps; i++)
682 if (dobj->dependencies[i] != refId)
683 dobj->dependencies[j++] = dobj->dependencies[i];
691 * finds the entry (in tblinfo) of the table with the given oid
692 * returns NULL if not found
695 findTableByOid(Oid oid)
697 return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
702 * finds the entry (in typinfo) of the type with the given oid
703 * returns NULL if not found
706 findTypeByOid(Oid oid)
708 return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
713 * finds the entry (in funinfo) of the function with the given oid
714 * returns NULL if not found
717 findFuncByOid(Oid oid)
719 return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
724 * finds the entry (in oprinfo) of the operator with the given oid
725 * returns NULL if not found
728 findOprByOid(Oid oid)
730 return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
735 * finds the entry (in collinfo) of the collation with the given oid
736 * returns NULL if not found
739 findCollationByOid(Oid oid)
741 return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
746 * finds the entry (in nspinfo) of the namespace with the given oid
747 * returns NULL if not found
750 findNamespaceByOid(Oid oid)
752 return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
758 * find a table's parents in tblinfo[]
761 findParentsByOid(TableInfo *self,
762 InhInfo *inhinfo, int numInherits)
764 Oid oid = self->dobj.catId.oid;
770 for (i = 0; i < numInherits; i++)
772 if (inhinfo[i].inhrelid == oid)
776 self->numParents = numParents;
780 self->parents = (TableInfo **)
781 pg_malloc(sizeof(TableInfo *) * numParents);
783 for (i = 0; i < numInherits; i++)
785 if (inhinfo[i].inhrelid == oid)
789 parent = findTableByOid(inhinfo[i].inhparent);
792 write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n",
793 inhinfo[i].inhparent,
798 self->parents[j++] = parent;
803 self->parents = NULL;
808 * parse a string of numbers delimited by spaces into a character array
810 * Note: actually this is used for both Oids and potentially-signed
811 * attribute numbers. This should cause no trouble, but we could split
812 * the function into two functions with different argument types if it does.
816 parseOidArray(const char *str, Oid *array, int arraysize)
828 if (s == ' ' || s == '\0')
832 if (argNum >= arraysize)
834 write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str);
838 array[argNum++] = atooid(temp);
846 if (!(isdigit((unsigned char) s) || s == '-') ||
847 j >= sizeof(temp) - 1)
849 write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str);
856 while (argNum < arraysize)
857 array[argNum++] = InvalidOid;
863 * takes in a string and a string array and the number of elements in the
865 * returns the index if the string is somewhere in the array, -1 otherwise
869 strInArray(const char *pattern, char **arr, int arr_size)
873 for (i = 0; i < arr_size; i++)
875 if (strcmp(pattern, arr[i]) == 0)
883 * Support for simple list operations
887 simple_oid_list_append(SimpleOidList *list, Oid val)
889 SimpleOidListCell *cell;
891 cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell));
896 list->tail->next = cell;
903 simple_oid_list_member(SimpleOidList *list, Oid val)
905 SimpleOidListCell *cell;
907 for (cell = list->head; cell; cell = cell->next)
909 if (cell->val == val)