1 /*-------------------------------------------------------------------------
4 * common routines between pg_dump and pg4_dump
6 * Since pg4_dump is long-dead code, there is no longer any useful distinction
7 * between this file and pg_dump.c.
9 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
16 *-------------------------------------------------------------------------
18 #include "postgres_fe.h"
22 #include "catalog/pg_class.h"
24 #include "pg_backup_archiver.h"
28 * Variables for mapping DumpId to DumpableObject
30 static DumpableObject
**dumpIdMap
= NULL
;
31 static int allocedDumpIds
= 0;
32 static DumpId lastDumpId
= 0;
35 * Variables for mapping CatalogId to DumpableObject
37 static bool catalogIdMapValid
= false;
38 static DumpableObject
**catalogIdMap
= NULL
;
39 static int numCatalogIds
= 0;
42 * These variables are static to avoid the notational cruft of having to pass
43 * them into findTableByOid() and friends. For each of these arrays, we
44 * build a sorted-by-OID index array immediately after it's built, and then
45 * we use binary search in findTableByOid() and friends. (qsort'ing the base
46 * arrays themselves would be simpler, but it doesn't work because pg_dump.c
47 * may have already established pointers between items.)
49 static TableInfo
*tblinfo
;
50 static TypeInfo
*typinfo
;
51 static FuncInfo
*funinfo
;
52 static OprInfo
*oprinfo
;
56 static int numOperators
;
57 static DumpableObject
**tblinfoindex
;
58 static DumpableObject
**typinfoindex
;
59 static DumpableObject
**funinfoindex
;
60 static DumpableObject
**oprinfoindex
;
63 static void flagInhTables(TableInfo
*tbinfo
, int numTables
,
64 InhInfo
*inhinfo
, int numInherits
);
65 static void flagInhAttrs(TableInfo
*tblinfo
, int numTables
);
66 static DumpableObject
**buildIndexArray(void *objArray
, int numObjs
,
68 static int DOCatalogIdCompare(const void *p1
, const void *p2
);
69 static void findParentsByOid(TableInfo
*self
,
70 InhInfo
*inhinfo
, int numInherits
);
71 static int strInArray(const char *pattern
, char **arr
, int arr_size
);
76 * Collect information about all potentially dumpable objects
79 getSchemaData(int *numTablesPtr
)
81 NamespaceInfo
*nsinfo
;
85 ProcLangInfo
*proclanginfo
;
88 OpfamilyInfo
*opfinfo
;
90 TSParserInfo
*prsinfo
;
91 TSTemplateInfo
*tmplinfo
;
93 TSConfigInfo
*cfginfo
;
95 ForeignServerInfo
*srvinfo
;
109 int numForeignDataWrappers
;
110 int numForeignServers
;
113 write_msg(NULL
, "reading schemas\n");
114 nsinfo
= getNamespaces(&numNamespaces
);
117 write_msg(NULL
, "reading user-defined functions\n");
118 funinfo
= getFuncs(&numFuncs
);
119 funinfoindex
= buildIndexArray(funinfo
, numFuncs
, sizeof(FuncInfo
));
121 /* this must be after getFuncs */
123 write_msg(NULL
, "reading user-defined types\n");
124 typinfo
= getTypes(&numTypes
);
125 typinfoindex
= buildIndexArray(typinfo
, numTypes
, sizeof(TypeInfo
));
127 /* this must be after getFuncs, too */
129 write_msg(NULL
, "reading procedural languages\n");
130 proclanginfo
= getProcLangs(&numProcLangs
);
133 write_msg(NULL
, "reading user-defined aggregate functions\n");
134 agginfo
= getAggregates(&numAggregates
);
137 write_msg(NULL
, "reading user-defined operators\n");
138 oprinfo
= getOperators(&numOperators
);
139 oprinfoindex
= buildIndexArray(oprinfo
, numOperators
, sizeof(OprInfo
));
142 write_msg(NULL
, "reading user-defined operator classes\n");
143 opcinfo
= getOpclasses(&numOpclasses
);
146 write_msg(NULL
, "reading user-defined text search parsers\n");
147 prsinfo
= getTSParsers(&numTSParsers
);
150 write_msg(NULL
, "reading user-defined text search templates\n");
151 tmplinfo
= getTSTemplates(&numTSTemplates
);
154 write_msg(NULL
, "reading user-defined text search dictionaries\n");
155 dictinfo
= getTSDictionaries(&numTSDicts
);
158 write_msg(NULL
, "reading user-defined text search configurations\n");
159 cfginfo
= getTSConfigurations(&numTSConfigs
);
162 write_msg(NULL
, "reading user-defined foreign-data wrappers\n");
163 fdwinfo
= getForeignDataWrappers(&numForeignDataWrappers
);
166 write_msg(NULL
, "reading user-defined foreign servers\n");
167 srvinfo
= getForeignServers(&numForeignServers
);
170 write_msg(NULL
, "reading user-defined operator families\n");
171 opfinfo
= getOpfamilies(&numOpfamilies
);
174 write_msg(NULL
, "reading user-defined conversions\n");
175 convinfo
= getConversions(&numConversions
);
178 write_msg(NULL
, "reading user-defined tables\n");
179 tblinfo
= getTables(&numTables
);
180 tblinfoindex
= buildIndexArray(tblinfo
, numTables
, sizeof(TableInfo
));
183 write_msg(NULL
, "reading table inheritance information\n");
184 inhinfo
= getInherits(&numInherits
);
187 write_msg(NULL
, "reading rewrite rules\n");
188 ruleinfo
= getRules(&numRules
);
191 write_msg(NULL
, "reading type casts\n");
192 castinfo
= getCasts(&numCasts
);
194 /* Link tables to parents, mark parents of target tables interesting */
196 write_msg(NULL
, "finding inheritance relationships\n");
197 flagInhTables(tblinfo
, numTables
, inhinfo
, numInherits
);
200 write_msg(NULL
, "reading column info for interesting tables\n");
201 getTableAttrs(tblinfo
, numTables
);
204 write_msg(NULL
, "flagging inherited columns in subtables\n");
205 flagInhAttrs(tblinfo
, numTables
);
208 write_msg(NULL
, "reading indexes\n");
209 getIndexes(tblinfo
, numTables
);
212 write_msg(NULL
, "reading constraints\n");
213 getConstraints(tblinfo
, numTables
);
216 write_msg(NULL
, "reading triggers\n");
217 getTriggers(tblinfo
, numTables
);
219 *numTablesPtr
= numTables
;
224 * Fill in parent link fields of every target table, and mark
225 * parents of target tables as interesting
227 * Note that only direct ancestors of targets are marked interesting.
228 * This is sufficient; we don't much care whether they inherited their
234 flagInhTables(TableInfo
*tblinfo
, int numTables
,
235 InhInfo
*inhinfo
, int numInherits
)
242 for (i
= 0; i
< numTables
; i
++)
244 /* Sequences and views never have parents */
245 if (tblinfo
[i
].relkind
== RELKIND_SEQUENCE
||
246 tblinfo
[i
].relkind
== RELKIND_VIEW
)
249 /* Don't bother computing anything for non-target tables, either */
250 if (!tblinfo
[i
].dobj
.dump
)
253 /* Find all the immediate parent tables */
254 findParentsByOid(&tblinfo
[i
], inhinfo
, numInherits
);
256 /* Mark the parents as interesting for getTableAttrs */
257 numParents
= tblinfo
[i
].numParents
;
258 parents
= tblinfo
[i
].parents
;
259 for (j
= 0; j
< numParents
; j
++)
260 parents
[j
]->interesting
= true;
265 * for each dumpable table in tblinfo, flag its inherited attributes
266 * so when we dump the table out, we don't dump out the inherited attributes
271 flagInhAttrs(TableInfo
*tblinfo
, int numTables
)
277 for (i
= 0; i
< numTables
; i
++)
279 TableInfo
*tbinfo
= &(tblinfo
[i
]);
284 /* Sequences and views never have parents */
285 if (tbinfo
->relkind
== RELKIND_SEQUENCE
||
286 tbinfo
->relkind
== RELKIND_VIEW
)
289 /* Don't bother computing anything for non-target tables, either */
290 if (!tbinfo
->dobj
.dump
)
293 numParents
= tbinfo
->numParents
;
294 parents
= tbinfo
->parents
;
297 continue; /* nothing to see here, move along */
299 /*----------------------------------------------------------------
300 * For each attr, check the parent info: if no parent has an attr
301 * with the same name, then it's not inherited. If there *is* an
302 * attr with the same name, then only dump it if:
304 * - it is NOT NULL and zero parents are NOT NULL
306 * - it has a default value AND the default value does not match
307 * all parent default values, or no parents specify a default.
309 * See discussion on -hackers around 2-Apr-2001.
310 *----------------------------------------------------------------
312 for (j
= 0; j
< tbinfo
->numatts
; j
++)
314 bool foundAttr
; /* Attr was found in a parent */
315 bool foundNotNull
; /* Attr was NOT NULL in a parent */
316 bool defaultsMatch
; /* All non-empty defaults match */
317 bool defaultsFound
; /* Found a default in a parent */
318 AttrDefInfo
*attrDef
;
321 foundNotNull
= false;
322 defaultsMatch
= true;
323 defaultsFound
= false;
325 attrDef
= tbinfo
->attrdefs
[j
];
327 for (k
= 0; k
< numParents
; k
++)
332 inhAttrInd
= strInArray(tbinfo
->attnames
[j
],
336 if (inhAttrInd
!= -1)
338 AttrDefInfo
*inhDef
= parent
->attrdefs
[inhAttrInd
];
341 foundNotNull
|= parent
->notnull
[inhAttrInd
];
344 defaultsFound
= true;
347 * If any parent has a default and the child doesn't,
348 * we have to emit an explicit DEFAULT NULL clause for
349 * the child, else the parent's default will win.
353 attrDef
= (AttrDefInfo
*) malloc(sizeof(AttrDefInfo
));
354 attrDef
->dobj
.objType
= DO_ATTRDEF
;
355 attrDef
->dobj
.catId
.tableoid
= 0;
356 attrDef
->dobj
.catId
.oid
= 0;
357 AssignDumpId(&attrDef
->dobj
);
358 attrDef
->adtable
= tbinfo
;
359 attrDef
->adnum
= j
+ 1;
360 attrDef
->adef_expr
= strdup("NULL");
362 attrDef
->dobj
.name
= strdup(tbinfo
->dobj
.name
);
363 attrDef
->dobj
.namespace = tbinfo
->dobj
.namespace;
365 attrDef
->dobj
.dump
= tbinfo
->dobj
.dump
;
367 attrDef
->separate
= false;
368 addObjectDependency(&tbinfo
->dobj
,
369 attrDef
->dobj
.dumpId
);
371 tbinfo
->attrdefs
[j
] = attrDef
;
373 if (strcmp(attrDef
->adef_expr
, inhDef
->adef_expr
) != 0)
375 defaultsMatch
= false;
378 * Whenever there is a non-matching parent
379 * default, add a dependency to force the parent
380 * default to be dumped first, in case the
381 * defaults end up being dumped as separate
382 * commands. Otherwise the parent default will
383 * override the child's when it is applied.
385 addObjectDependency(&attrDef
->dobj
,
386 inhDef
->dobj
.dumpId
);
393 * Based on the scan of the parents, decide if we can rely on the
396 if (foundAttr
) /* Attr was inherited */
398 /* Set inherited flag by default */
399 tbinfo
->inhAttrs
[j
] = true;
400 tbinfo
->inhAttrDef
[j
] = true;
401 tbinfo
->inhNotNull
[j
] = true;
404 * Clear it if attr had a default, but parents did not, or
407 if ((attrDef
!= NULL
) && (!defaultsFound
|| !defaultsMatch
))
409 tbinfo
->inhAttrs
[j
] = false;
410 tbinfo
->inhAttrDef
[j
] = false;
414 * Clear it if NOT NULL and none of the parents were NOT NULL
416 if (tbinfo
->notnull
[j
] && !foundNotNull
)
418 tbinfo
->inhAttrs
[j
] = false;
419 tbinfo
->inhNotNull
[j
] = false;
422 /* Clear it if attr has local definition */
423 if (tbinfo
->attislocal
[j
])
424 tbinfo
->inhAttrs
[j
] = false;
432 * Given a newly-created dumpable object, assign a dump ID,
433 * and enter the object into the lookup table.
435 * The caller is expected to have filled in objType and catId,
436 * but not any of the other standard fields of a DumpableObject.
439 AssignDumpId(DumpableObject
*dobj
)
441 dobj
->dumpId
= ++lastDumpId
;
442 dobj
->name
= NULL
; /* must be set later */
443 dobj
->namespace = NULL
; /* may be set later */
444 dobj
->dump
= true; /* default assumption */
445 dobj
->dependencies
= NULL
;
449 while (dobj
->dumpId
>= allocedDumpIds
)
453 if (allocedDumpIds
<= 0)
456 dumpIdMap
= (DumpableObject
**)
457 pg_malloc(newAlloc
* sizeof(DumpableObject
*));
461 newAlloc
= allocedDumpIds
* 2;
462 dumpIdMap
= (DumpableObject
**)
463 pg_realloc(dumpIdMap
, newAlloc
* sizeof(DumpableObject
*));
465 memset(dumpIdMap
+ allocedDumpIds
, 0,
466 (newAlloc
- allocedDumpIds
) * sizeof(DumpableObject
*));
467 allocedDumpIds
= newAlloc
;
469 dumpIdMap
[dobj
->dumpId
] = dobj
;
471 /* mark catalogIdMap invalid, but don't rebuild it yet */
472 catalogIdMapValid
= false;
476 * Assign a DumpId that's not tied to a DumpableObject.
478 * This is used when creating a "fixed" ArchiveEntry that doesn't need to
479 * participate in the sorting logic.
488 * Return the largest DumpId so far assigned
497 * Find a DumpableObject by dump ID
499 * Returns NULL for invalid ID
502 findObjectByDumpId(DumpId dumpId
)
504 if (dumpId
<= 0 || dumpId
>= allocedDumpIds
)
505 return NULL
; /* out of range? */
506 return dumpIdMap
[dumpId
];
510 * Find a DumpableObject by catalog ID
512 * Returns NULL for unknown ID
514 * We use binary search in a sorted list that is built on first call.
515 * If AssignDumpId() and findObjectByCatalogId() calls were intermixed,
516 * the code would work, but possibly be very slow. In the current usage
517 * pattern that does not happen, indeed we only need to build the list once.
520 findObjectByCatalogId(CatalogId catalogId
)
522 DumpableObject
**low
;
523 DumpableObject
**high
;
525 if (!catalogIdMapValid
)
529 getDumpableObjects(&catalogIdMap
, &numCatalogIds
);
530 if (numCatalogIds
> 1)
531 qsort((void *) catalogIdMap
, numCatalogIds
,
532 sizeof(DumpableObject
*), DOCatalogIdCompare
);
533 catalogIdMapValid
= true;
537 * We could use bsearch() here, but the notational cruft of calling
538 * bsearch is nearly as bad as doing it ourselves; and the generalized
539 * bsearch function is noticeably slower as well.
541 if (numCatalogIds
<= 0)
544 high
= catalogIdMap
+ (numCatalogIds
- 1);
547 DumpableObject
**middle
;
550 middle
= low
+ (high
- low
) / 2;
551 /* comparison must match DOCatalogIdCompare, below */
552 difference
= oidcmp((*middle
)->catId
.oid
, catalogId
.oid
);
554 difference
= oidcmp((*middle
)->catId
.tableoid
, catalogId
.tableoid
);
557 else if (difference
< 0)
566 * Find a DumpableObject by OID, in a pre-sorted array of one type of object
568 * Returns NULL for unknown OID
570 static DumpableObject
*
571 findObjectByOid(Oid oid
, DumpableObject
**indexArray
, int numObjs
)
573 DumpableObject
**low
;
574 DumpableObject
**high
;
577 * This is the same as findObjectByCatalogId except we assume we need not
578 * look at table OID because the objects are all the same type.
580 * We could use bsearch() here, but the notational cruft of calling
581 * bsearch is nearly as bad as doing it ourselves; and the generalized
582 * bsearch function is noticeably slower as well.
587 high
= indexArray
+ (numObjs
- 1);
590 DumpableObject
**middle
;
593 middle
= low
+ (high
- low
) / 2;
594 difference
= oidcmp((*middle
)->catId
.oid
, oid
);
597 else if (difference
< 0)
606 * Build an index array of DumpableObject pointers, sorted by OID
608 static DumpableObject
**
609 buildIndexArray(void *objArray
, int numObjs
, Size objSize
)
611 DumpableObject
**ptrs
;
614 ptrs
= (DumpableObject
**) malloc(numObjs
* sizeof(DumpableObject
*));
615 for (i
= 0; i
< numObjs
; i
++)
616 ptrs
[i
] = (DumpableObject
*) ((char *) objArray
+ i
* objSize
);
618 /* We can use DOCatalogIdCompare to sort since its first key is OID */
620 qsort((void *) ptrs
, numObjs
, sizeof(DumpableObject
*),
627 * qsort comparator for pointers to DumpableObjects
630 DOCatalogIdCompare(const void *p1
, const void *p2
)
632 DumpableObject
*obj1
= *(DumpableObject
**) p1
;
633 DumpableObject
*obj2
= *(DumpableObject
**) p2
;
637 * Compare OID first since it's usually unique, whereas there will only be
638 * a few distinct values of tableoid.
640 cmpval
= oidcmp(obj1
->catId
.oid
, obj2
->catId
.oid
);
642 cmpval
= oidcmp(obj1
->catId
.tableoid
, obj2
->catId
.tableoid
);
647 * Build an array of pointers to all known dumpable objects
649 * This simply creates a modifiable copy of the internal map.
652 getDumpableObjects(DumpableObject
***objs
, int *numObjs
)
657 *objs
= (DumpableObject
**)
658 pg_malloc(allocedDumpIds
* sizeof(DumpableObject
*));
660 for (i
= 1; i
< allocedDumpIds
; i
++)
663 (*objs
)[j
++] = dumpIdMap
[i
];
669 * Add a dependency link to a DumpableObject
671 * Note: duplicate dependencies are currently not eliminated
674 addObjectDependency(DumpableObject
*dobj
, DumpId refId
)
676 if (dobj
->nDeps
>= dobj
->allocDeps
)
678 if (dobj
->allocDeps
<= 0)
680 dobj
->allocDeps
= 16;
681 dobj
->dependencies
= (DumpId
*)
682 pg_malloc(dobj
->allocDeps
* sizeof(DumpId
));
686 dobj
->allocDeps
*= 2;
687 dobj
->dependencies
= (DumpId
*)
688 pg_realloc(dobj
->dependencies
,
689 dobj
->allocDeps
* sizeof(DumpId
));
692 dobj
->dependencies
[dobj
->nDeps
++] = refId
;
696 * Remove a dependency link from a DumpableObject
698 * If there are multiple links, all are removed
701 removeObjectDependency(DumpableObject
*dobj
, DumpId refId
)
706 for (i
= 0; i
< dobj
->nDeps
; i
++)
708 if (dobj
->dependencies
[i
] != refId
)
709 dobj
->dependencies
[j
++] = dobj
->dependencies
[i
];
717 * finds the entry (in tblinfo) of the table with the given oid
718 * returns NULL if not found
721 findTableByOid(Oid oid
)
723 return (TableInfo
*) findObjectByOid(oid
, tblinfoindex
, numTables
);
728 * finds the entry (in typinfo) of the type with the given oid
729 * returns NULL if not found
732 findTypeByOid(Oid oid
)
734 return (TypeInfo
*) findObjectByOid(oid
, typinfoindex
, numTypes
);
739 * finds the entry (in funinfo) of the function with the given oid
740 * returns NULL if not found
743 findFuncByOid(Oid oid
)
745 return (FuncInfo
*) findObjectByOid(oid
, funinfoindex
, numFuncs
);
750 * finds the entry (in oprinfo) of the operator with the given oid
751 * returns NULL if not found
754 findOprByOid(Oid oid
)
756 return (OprInfo
*) findObjectByOid(oid
, oprinfoindex
, numOperators
);
762 * find a table's parents in tblinfo[]
765 findParentsByOid(TableInfo
*self
,
766 InhInfo
*inhinfo
, int numInherits
)
768 Oid oid
= self
->dobj
.catId
.oid
;
774 for (i
= 0; i
< numInherits
; i
++)
776 if (inhinfo
[i
].inhrelid
== oid
)
780 self
->numParents
= numParents
;
784 self
->parents
= (TableInfo
**)
785 pg_malloc(sizeof(TableInfo
*) * numParents
);
787 for (i
= 0; i
< numInherits
; i
++)
789 if (inhinfo
[i
].inhrelid
== oid
)
793 parent
= findTableByOid(inhinfo
[i
].inhparent
);
796 write_msg(NULL
, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n",
797 inhinfo
[i
].inhparent
,
802 self
->parents
[j
++] = parent
;
807 self
->parents
= NULL
;
812 * parse a string of numbers delimited by spaces into a character array
814 * Note: actually this is used for both Oids and potentially-signed
815 * attribute numbers. This should cause no trouble, but we could split
816 * the function into two functions with different argument types if it does.
820 parseOidArray(const char *str
, Oid
*array
, int arraysize
)
832 if (s
== ' ' || s
== '\0')
836 if (argNum
>= arraysize
)
838 write_msg(NULL
, "could not parse numeric array \"%s\": too many numbers\n", str
);
842 array
[argNum
++] = atooid(temp
);
850 if (!(isdigit((unsigned char) s
) || s
== '-') ||
851 j
>= sizeof(temp
) - 1)
853 write_msg(NULL
, "could not parse numeric array \"%s\": invalid character in number\n", str
);
860 while (argNum
< arraysize
)
861 array
[argNum
++] = InvalidOid
;
867 * takes in a string and a string array and the number of elements in the
869 * returns the index if the string is somewhere in the array, -1 otherwise
873 strInArray(const char *pattern
, char **arr
, int arr_size
)
877 for (i
= 0; i
< arr_size
; i
++)
879 if (strcmp(pattern
, arr
[i
]) == 0)
887 * Support for simple list operations
891 simple_oid_list_append(SimpleOidList
*list
, Oid val
)
893 SimpleOidListCell
*cell
;
895 cell
= (SimpleOidListCell
*) pg_malloc(sizeof(SimpleOidListCell
));
900 list
->tail
->next
= cell
;
907 simple_string_list_append(SimpleStringList
*list
, const char *val
)
909 SimpleStringListCell
*cell
;
911 /* this calculation correctly accounts for the null trailing byte */
912 cell
= (SimpleStringListCell
*)
913 pg_malloc(sizeof(SimpleStringListCell
) + strlen(val
));
915 strcpy(cell
->val
, val
);
918 list
->tail
->next
= cell
;
925 simple_oid_list_member(SimpleOidList
*list
, Oid val
)
927 SimpleOidListCell
*cell
;
929 for (cell
= list
->head
; cell
; cell
= cell
->next
)
931 if (cell
->val
== val
)
938 simple_string_list_member(SimpleStringList
*list
, const char *val
)
940 SimpleStringListCell
*cell
;
942 for (cell
= list
->head
; cell
; cell
= cell
->next
)
944 if (strcmp(cell
->val
, val
) == 0)
952 * Safer versions of some standard C library functions. If an
953 * out-of-memory condition occurs, these functions will bail out
954 * safely; therefore, their return value is guaranteed to be non-NULL.
956 * XXX need to refactor things so that these can be in a file that can be
957 * shared by pg_dumpall and pg_restore as well as pg_dump.
961 pg_strdup(const char *string
)
966 exit_horribly(NULL
, NULL
, "cannot duplicate null pointer\n");
967 tmp
= strdup(string
);
969 exit_horribly(NULL
, NULL
, "out of memory\n");
974 pg_malloc(size_t size
)
980 exit_horribly(NULL
, NULL
, "out of memory\n");
985 pg_calloc(size_t nmemb
, size_t size
)
989 tmp
= calloc(nmemb
, size
);
991 exit_horribly(NULL
, NULL
, "out of memory\n");
996 pg_realloc(void *ptr
, size_t size
)
1000 tmp
= realloc(ptr
, size
);
1002 exit_horribly(NULL
, NULL
, "out of memory\n");