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-2002, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
14 * $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.71 2002/10/09 16:20:25 momjian Exp $
16 *-------------------------------------------------------------------------
19 #include "postgres_fe.h"
21 #include "pg_backup_archiver.h"
23 #include "catalog/pg_class.h"
32 static void findParentsByOid(TableInfo *tblinfo, int numTables,
33 InhInfo *inhinfo, int numInherits,
35 int *numParentsPtr, int **parentIndexes);
36 static void flagInhTables(TableInfo *tbinfo, int numTables,
37 InhInfo *inhinfo, int numInherits);
38 static void flagInhAttrs(TableInfo *tbinfo, int numTables,
39 InhInfo *inhinfo, int numInherits);
40 static int strInArray(const char *pattern, char **arr, int arr_size);
45 * we have a valid connection, we are now going to dump the schema
50 dumpSchema(Archive *fout,
53 const bool schemaOnly,
64 NamespaceInfo *nsinfo;
74 write_msg(NULL, "reading namespaces\n");
75 nsinfo = getNamespaces(&numNamespaces);
78 write_msg(NULL, "reading user-defined types\n");
79 tinfo = getTypes(&numTypes);
82 write_msg(NULL, "reading user-defined functions\n");
83 finfo = getFuncs(&numFuncs);
86 write_msg(NULL, "reading user-defined aggregate functions\n");
87 agginfo = getAggregates(&numAggregates);
90 write_msg(NULL, "reading user-defined operators\n");
91 oprinfo = getOperators(&numOperators);
94 write_msg(NULL, "reading user-defined operator classes\n");
95 opcinfo = getOpclasses(&numOpclasses);
98 write_msg(NULL, "reading user-defined tables\n");
99 tblinfo = getTables(&numTables);
102 write_msg(NULL, "reading table inheritance information\n");
103 inhinfo = getInherits(&numInherits);
105 /* Link tables to parents, mark parents of target tables interesting */
107 write_msg(NULL, "finding inheritance relationships\n");
108 flagInhTables(tblinfo, numTables, inhinfo, numInherits);
111 write_msg(NULL, "reading column info for interesting tables\n");
112 getTableAttrs(tblinfo, numTables);
115 write_msg(NULL, "flagging inherited columns in subtables\n");
116 flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
121 write_msg(NULL, "dumping out database comment\n");
128 write_msg(NULL, "dumping out user-defined namespaces\n");
129 dumpNamespaces(fout, nsinfo, numNamespaces);
135 write_msg(NULL, "dumping out user-defined types\n");
136 dumpTypes(fout, finfo, numFuncs, tinfo, numTypes);
140 write_msg(NULL, "dumping out tables\n");
141 dumpTables(fout, tblinfo, numTables,
142 aclsSkip, schemaOnly, dataOnly);
147 write_msg(NULL, "dumping out indexes\n");
148 dumpIndexes(fout, tblinfo, numTables);
154 write_msg(NULL, "dumping out user-defined procedural languages\n");
155 dumpProcLangs(fout, finfo, numFuncs);
161 write_msg(NULL, "dumping out user-defined functions\n");
162 dumpFuncs(fout, finfo, numFuncs);
168 write_msg(NULL, "dumping out user-defined aggregate functions\n");
169 dumpAggs(fout, agginfo, numAggregates);
175 write_msg(NULL, "dumping out user-defined operators\n");
176 dumpOprs(fout, oprinfo, numOperators);
182 write_msg(NULL, "dumping out user-defined operator classes\n");
183 dumpOpclasses(fout, opcinfo, numOpclasses);
189 write_msg(NULL, "dumping out user-defined casts\n");
190 dumpCasts(fout, finfo, numFuncs, tinfo, numTypes);
193 *numTablesPtr = numTables;
198 * Fill in parentIndexes fields of every target table, and mark
199 * parents of target tables as interesting
201 * Note that only direct ancestors of targets are marked interesting.
202 * This is sufficient; we don't much care whether they inherited their
208 flagInhTables(TableInfo *tblinfo, int numTables,
209 InhInfo *inhinfo, int numInherits)
216 for (i = 0; i < numTables; i++)
218 /* Sequences and views never have parents */
219 if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
220 tblinfo[i].relkind == RELKIND_VIEW)
223 /* Don't bother computing anything for non-target tables, either */
224 if (!tblinfo[i].dump)
227 /* Find all the immediate parent tables */
228 findParentsByOid(tblinfo, numTables,
229 inhinfo, numInherits,
231 &tblinfo[i].numParents,
232 &tblinfo[i].parentIndexes);
233 numParents = tblinfo[i].numParents;
234 parentIndexes = tblinfo[i].parentIndexes;
236 /* Mark the parents as interesting for getTableAttrs */
237 for (j = 0; j < numParents; j++)
239 int parentInd = parentIndexes[j];
241 tblinfo[parentInd].interesting = true;
247 * for each dumpable table in tblinfo, flag its inherited attributes
248 * so when we dump the table out, we don't dump out the inherited attributes
253 flagInhAttrs(TableInfo *tblinfo, int numTables,
254 InhInfo *inhinfo, int numInherits)
263 bool foundAttr; /* Attr was found in a parent */
264 bool foundNotNull; /* Attr was NOT NULL in a parent */
265 bool defaultsMatch; /* All non-empty defaults match */
266 bool defaultsFound; /* Found a default in a parent */
270 for (i = 0; i < numTables; i++)
272 /* Sequences and views never have parents */
273 if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
274 tblinfo[i].relkind == RELKIND_VIEW)
277 /* Don't bother computing anything for non-target tables, either */
278 if (!tblinfo[i].dump)
281 numParents = tblinfo[i].numParents;
282 parentIndexes = tblinfo[i].parentIndexes;
285 continue; /* nothing to see here, move along */
287 /*----------------------------------------------------------------
288 * For each attr, check the parent info: if no parent has an attr
289 * with the same name, then it's not inherited. If there *is* an
290 * attr with the same name, then only dump it if:
292 * - it is NOT NULL and zero parents are NOT NULL
294 * - it has a default value AND the default value does not match
295 * all parent default values, or no parents specify a default.
297 * See discussion on -hackers around 2-Apr-2001.
298 *----------------------------------------------------------------
300 for (j = 0; j < tblinfo[i].numatts; j++)
303 foundNotNull = false;
304 defaultsMatch = true;
305 defaultsFound = false;
307 attrDef = tblinfo[i].adef_expr[j];
309 for (k = 0; k < numParents; k++)
311 parentInd = parentIndexes[k];
312 inhAttrInd = strInArray(tblinfo[i].attnames[j],
313 tblinfo[parentInd].attnames,
314 tblinfo[parentInd].numatts);
316 if (inhAttrInd != -1)
319 foundNotNull |= tblinfo[parentInd].notnull[inhAttrInd];
320 if (attrDef != NULL) /* If we have a default,
323 inhDef = tblinfo[parentInd].adef_expr[inhAttrInd];
327 defaultsFound = true;
328 defaultsMatch &= (strcmp(attrDef, inhDef) == 0);
335 * Based on the scan of the parents, decide if we can rely on
338 if (foundAttr) /* Attr was inherited */
340 /* Set inherited flag by default */
341 tblinfo[i].inhAttrs[j] = true;
342 tblinfo[i].inhAttrDef[j] = true;
343 tblinfo[i].inhNotNull[j] = true;
346 * Clear it if attr had a default, but parents did not, or
349 if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch))
351 tblinfo[i].inhAttrs[j] = false;
352 tblinfo[i].inhAttrDef[j] = false;
356 * Clear it if NOT NULL and none of the parents were NOT
359 if (tblinfo[i].notnull[j] && !foundNotNull)
361 tblinfo[i].inhAttrs[j] = false;
362 tblinfo[i].inhNotNull[j] = false;
365 /* Clear it if attr has local definition */
366 if (g_fout->remoteVersion >= 70300 && tblinfo[i].attislocal[j])
368 tblinfo[i].inhAttrs[j] = false;
378 * finds the index (in tblinfo) of the table with the given oid
379 * returns -1 if not found
381 * NOTE: should hash this, but just do linear search for now
384 findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
388 for (i = 0; i < numTables; i++)
390 if (strcmp(tblinfo[i].oid, oid) == 0)
399 * finds the index (in finfo) of the function with the given OID
400 * returns -1 if not found
402 * NOTE: should hash this, but just do linear search for now
405 findFuncByOid(FuncInfo *finfo, int numFuncs, const char *oid)
409 for (i = 0; i < numFuncs; i++)
411 if (strcmp(finfo[i].oid, oid) == 0)
418 * Finds the index (in tinfo) of the type with the given OID. Returns
422 findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid)
426 for (i = 0; i < numTypes; i++)
428 if (strcmp(tinfo[i].oid, oid) == 0)
436 * given the oid of an operator, return the name of the operator
438 * NOTE: should hash this, but just do linear search for now
441 findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid)
445 for (i = 0; i < numOprs; i++)
447 if (strcmp(oprinfo[i].oid, oid) == 0)
448 return oprinfo[i].oprname;
451 /* should never get here */
452 write_msg(NULL, "failed sanity check, operator with oid %s not found\n", oid);
454 /* no suitable operator name was found */
461 * given the oid of a class, find its parent classes in tblinfo[]
463 * Returns the number of parents and their array indexes into the
464 * last two arguments.
468 findParentsByOid(TableInfo *tblinfo, int numTables,
469 InhInfo *inhinfo, int numInherits,
471 int *numParentsPtr, int **parentIndexes)
480 for (i = 0; i < numInherits; i++)
482 if (strcmp(inhinfo[i].inhrelid, oid) == 0)
486 *numParentsPtr = numParents;
490 *parentIndexes = (int *) malloc(sizeof(int) * numParents);
492 for (i = 0; i < numInherits; i++)
494 if (strcmp(inhinfo[i].inhrelid, oid) == 0)
496 parentInd = findTableByOid(tblinfo, numTables,
497 inhinfo[i].inhparent);
500 selfInd = findTableByOid(tblinfo, numTables, oid);
502 write_msg(NULL, "failed sanity check, parent oid %s of table %s (oid %s) not found\n",
503 inhinfo[i].inhparent,
504 tblinfo[selfInd].relname,
507 write_msg(NULL, "failed sanity check, parent oid %s of table (oid %s) not found\n",
508 inhinfo[i].inhparent,
513 (*parentIndexes)[j++] = parentInd;
518 *parentIndexes = NULL;
523 * parse a string of numbers delimited by spaces into a character array
527 parseNumericArray(const char *str, char **array, int arraysize)
539 if (s == ' ' || s == '\0')
543 if (argNum >= arraysize)
545 write_msg(NULL, "parseNumericArray: too many numbers\n");
549 array[argNum++] = strdup(temp);
557 if (!(isdigit((unsigned char) s) || s == '-') ||
558 j >= sizeof(temp) - 1)
560 write_msg(NULL, "parseNumericArray: bogus number\n");
567 while (argNum < arraysize)
568 array[argNum++] = strdup("0");
574 * takes in a string and a string array and the number of elements in the
576 * returns the index if the string is somewhere in the array, -1 otherwise
580 strInArray(const char *pattern, char **arr, int arr_size)
584 for (i = 0; i < arr_size; i++)
586 if (strcmp(pattern, arr[i]) == 0)