1 /*-------------------------------------------------------------------------
4 * common routines between pg_dump and pg4_dump
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.55 2001/04/03 08:52:59 pjw Exp $
13 * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
15 * - Fixed dumpTable output to output lengths for char and varchar types!
16 * - Added single. quote to twin single quote expansion for 'insert' string
19 * Modifications 14-Sep-2000 - pjw@rhyme.com.au
20 * - Added enum for findTypeByOid to specify how to handle OID and which
21 * string to return - formatted type, or base type. If the base type
22 * is returned then fmtId is called on the string.
24 * Modifications 4-Apr-2001 - pjw@rhyme.com.au
25 * - Changed flagInhAttrs to check all parent tables for overridden settings
26 * and set flags accordingly.
28 * BEWARE: Since fmtId uses a static buffer, using 'useBaseTypeName' on more
29 * than one call in a line will cause problems.
31 *-------------------------------------------------------------------------
43 static char **findParentsByOid(TableInfo *tbinfo, int numTables,
44 InhInfo *inhinfo, int numInherits,
47 int (**parentIndices)[]);
48 static int findTableByOid(TableInfo *tbinfo, int numTables, const char *oid);
49 static void flagInhAttrs(TableInfo *tbinfo, int numTables,
50 InhInfo *inhinfo, int numInherits);
51 static int strInArray(const char *pattern, char **arr, int arr_size);
55 * given an oid of a type, return its typename
57 * if oid is "0", return "opaque" -- this is a special case
59 * NOTE: should hash this, but just do linear search for now
63 findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid, OidOptions opts)
67 if (strcmp(oid, "0") == 0)
70 if ((opts & zeroAsOpaque) != 0)
76 else if ((opts & zeroAsAny) != 0)
84 for (i = 0; i < numTypes; i++)
86 if (strcmp(tinfo[i].oid, oid) == 0)
88 if ((opts & useBaseTypeName) != 0)
89 return (char *) fmtId(tinfo[i].typname, false);
91 return tinfo[i].typedefn;
95 /* no suitable type name was found */
101 * given the oid of an operator, return the name of the operator
104 * NOTE: should hash this, but just do linear search for now
108 findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid)
112 for (i = 0; i < numOprs; i++)
114 if (strcmp(oprinfo[i].oid, oid) == 0)
115 return oprinfo[i].oprname;
118 /* should never get here */
119 fprintf(stderr, "failed sanity check, opr with oid %s was not found\n",
122 /* no suitable operator name was found */
129 * given the oid of a class, return the names of its parent classes
130 * and assign the number of parents, and parent indices to the last arguments.
133 * returns NULL if none
137 findParentsByOid(TableInfo *tblinfo, int numTables,
138 InhInfo *inhinfo, int numInherits, const char *oid,
139 int *numParentsPtr, int (**parentIndices)[])
149 for (i = 0; i < numInherits; i++)
151 if (strcmp(inhinfo[i].inhrelid, oid) == 0)
155 *numParentsPtr = numParents;
159 result = (char **) malloc(sizeof(char *) * numParents);
160 (*parentIndices) = malloc(sizeof(int) * numParents);
162 for (i = 0; i < numInherits; i++)
164 if (strcmp(inhinfo[i].inhrelid, oid) == 0)
166 parentInd = findTableByOid(tblinfo, numTables,
167 inhinfo[i].inhparent);
170 selfInd = findTableByOid(tblinfo, numTables, oid);
172 "failed sanity check, parent oid %s of table %s (oid %s) was not found\n",
173 inhinfo[i].inhparent,
174 (selfInd >= 0) ? tblinfo[selfInd].relname : "",
178 (**parentIndices)[j] = parentInd;
179 result[j++] = tblinfo[parentInd].relname;
186 (*parentIndices) = NULL;
193 * parse a string of numbers delimited by spaces into a character array
197 parseNumericArray(const char *str, char **array, int arraysize)
209 if (s == ' ' || s == '\0')
213 if (argNum >= arraysize)
215 fprintf(stderr, "parseNumericArray: too many numbers\n");
219 array[argNum++] = strdup(temp);
227 if (!(isdigit((unsigned char) s) || s == '-') ||
228 j >= sizeof(temp) - 1)
230 fprintf(stderr, "parseNumericArray: bogus number\n");
236 while (argNum < arraysize)
237 array[argNum++] = strdup("0");
243 * takes in a string and a string array and the number of elements in the
245 * returns the index if the string is somewhere in the array, -1 otherwise
250 strInArray(const char *pattern, char **arr, int arr_size)
254 for (i = 0; i < arr_size; i++)
256 if (strcmp(pattern, arr[i]) == 0)
264 * we have a valid connection, we are now going to dump the schema
270 dumpSchema(Archive *fout,
272 const char *tablename,
275 const bool schemaOnly,
285 TypeInfo *tinfo = NULL;
286 FuncInfo *finfo = NULL;
287 AggInfo *agginfo = NULL;
288 TableInfo *tblinfo = NULL;
289 InhInfo *inhinfo = NULL;
290 OprInfo *oprinfo = NULL;
291 IndInfo *indinfo = NULL;
294 fprintf(stderr, "%s reading user-defined types %s\n",
295 g_comment_start, g_comment_end);
296 tinfo = getTypes(&numTypes);
299 fprintf(stderr, "%s reading user-defined functions %s\n",
300 g_comment_start, g_comment_end);
301 finfo = getFuncs(&numFuncs);
304 fprintf(stderr, "%s reading user-defined aggregates %s\n",
305 g_comment_start, g_comment_end);
306 agginfo = getAggregates(&numAggregates);
309 fprintf(stderr, "%s reading user-defined operators %s\n",
310 g_comment_start, g_comment_end);
311 oprinfo = getOperators(&numOperators);
314 fprintf(stderr, "%s reading user-defined tables %s\n",
315 g_comment_start, g_comment_end);
316 tblinfo = getTables(&numTables, finfo, numFuncs);
319 fprintf(stderr, "%s reading indices information %s\n",
320 g_comment_start, g_comment_end);
321 indinfo = getIndices(&numIndices);
324 fprintf(stderr, "%s reading table inheritance information %s\n",
325 g_comment_start, g_comment_end);
326 inhinfo = getInherits(&numInherits);
329 fprintf(stderr, "%s finding the attribute names and types for each table %s\n",
330 g_comment_start, g_comment_end);
331 getTableAttrs(tblinfo, numTables);
334 fprintf(stderr, "%s flagging inherited attributes in subtables %s\n",
335 g_comment_start, g_comment_end);
336 flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
338 if (!tablename && !dataOnly)
341 fprintf(stderr, "%s dumping out database comment %s\n",
342 g_comment_start, g_comment_end);
346 if (!tablename && fout)
349 fprintf(stderr, "%s dumping out user-defined types %s\n",
350 g_comment_start, g_comment_end);
351 dumpTypes(fout, finfo, numFuncs, tinfo, numTypes);
355 fprintf(stderr, "%s dumping out tables %s\n",
356 g_comment_start, g_comment_end);
358 dumpTables(fout, tblinfo, numTables, indinfo, numIndices, inhinfo, numInherits,
359 tinfo, numTypes, tablename, aclsSkip, oids, schemaOnly, dataOnly);
361 if (fout && !dataOnly)
364 fprintf(stderr, "%s dumping out indices %s\n",
365 g_comment_start, g_comment_end);
366 dumpIndices(fout, indinfo, numIndices, tblinfo, numTables, tablename);
369 if (!tablename && !dataOnly)
372 fprintf(stderr, "%s dumping out user-defined procedural languages %s\n",
373 g_comment_start, g_comment_end);
374 dumpProcLangs(fout, finfo, numFuncs, tinfo, numTypes);
377 if (!tablename && !dataOnly)
380 fprintf(stderr, "%s dumping out user-defined functions %s\n",
381 g_comment_start, g_comment_end);
382 dumpFuncs(fout, finfo, numFuncs, tinfo, numTypes);
385 if (!tablename && !dataOnly)
388 fprintf(stderr, "%s dumping out user-defined aggregates %s\n",
389 g_comment_start, g_comment_end);
390 dumpAggs(fout, agginfo, numAggregates, tinfo, numTypes);
393 if (!tablename && !dataOnly)
396 fprintf(stderr, "%s dumping out user-defined operators %s\n",
397 g_comment_start, g_comment_end);
398 dumpOprs(fout, oprinfo, numOperators, tinfo, numTypes);
401 *numTablesPtr = numTables;
402 clearAggInfo(agginfo, numAggregates);
403 clearOprInfo(oprinfo, numOperators);
404 clearTypeInfo(tinfo, numTypes);
405 clearFuncInfo(finfo, numFuncs);
406 clearInhInfo(inhinfo, numInherits);
407 clearIndInfo(indinfo, numIndices);
412 * for each table in tblinfo, flag its inherited attributes
413 * so when we dump the table out, we don't dump out the inherited attributes
415 * initializes the parentRels field of each table
421 flagInhAttrs(TableInfo *tblinfo, int numTables,
422 InhInfo *inhinfo, int numInherits)
429 int (*parentIndices)[];
430 bool foundAttr; /* Attr was found in a parent */
431 bool foundNotNull; /* Attr was NOT NULL in a parent */
432 bool defaultsMatch; /* All non-empty defaults match */
433 bool defaultsFound; /* Found a default in a parent */
438 * we go backwards because the tables in tblinfo are in OID order,
439 * meaning the subtables are after the parent tables we flag inherited
440 * attributes from child tables first
442 for (i = numTables - 1; i >= 0; i--)
445 /* Sequences can never have parents, and attr info is undefined */
446 if (tblinfo[i].sequence)
449 /* Get all the parents and their indexes. */
450 tblinfo[i].parentRels = findParentsByOid(tblinfo, numTables,
451 inhinfo, numInherits,
453 &tblinfo[i].numParents,
457 * For each attr, check the parent info: if no parent has
458 * an attr with the same name, then it's not inherited. If there
459 * *is* an attr with the same name, then only dump it if:
461 * - it is NOT NULL and zero parents are NOT NULL
463 * - it has a default value AND the default value
464 * does not match all parent default values, or
465 * no parents specify a default.
467 * See discussion on -hackers around 2-Apr-2001.
469 for (j = 0; j < tblinfo[i].numatts; j++)
472 foundNotNull = false;
473 defaultsMatch = true;
474 defaultsFound = false;
476 attrDef = tblinfo[i].adef_expr[j];
478 for (k = 0; k < tblinfo[i].numParents; k++)
480 parentInd = (*parentIndices)[k];
484 /* shouldn't happen unless findParentsByOid is broken */
485 fprintf(stderr, "failed sanity check, table %s not found by flagInhAttrs\n",
486 tblinfo[i].parentRels[k]);
490 inhAttrInd = strInArray(tblinfo[i].attnames[j],
491 tblinfo[parentInd].attnames,
492 tblinfo[parentInd].numatts);
494 if (inhAttrInd != -1)
497 foundNotNull |= tblinfo[parentInd].notnull[inhAttrInd];
498 if (attrDef != NULL) /* It we have a default, check parent */
500 inhDef = tblinfo[parentInd].adef_expr[inhAttrInd];
504 defaultsFound = true;
505 defaultsMatch &= (strcmp(attrDef, inhDef) == 0);
512 * Based on the scan of the parents, decide if we
513 * can rely on the inherited attr
515 if (foundAttr) /* Attr was inherited */
517 /* Set inherited flag by default */
518 tblinfo[i].inhAttrs[j] = 1;
519 tblinfo[i].inhAttrDef[j] = 1;
520 tblinfo[i].inhNotNull[j] = 1;
522 /* Clear it if attr had a default, but parents did not, or mismatch */
523 if ( (attrDef != NULL) && (!defaultsFound || !defaultsMatch) )
525 tblinfo[i].inhAttrs[j] = 0;
526 tblinfo[i].inhAttrDef[j] = 0;
529 /* Clear it if NOT NULL and none of the parents were NOT NULL */
530 if (tblinfo[i].notnull[j] && !foundNotNull)
532 tblinfo[i].inhAttrs[j] = 0;
533 tblinfo[i].inhNotNull[j] = 0;
543 * finds the index (in tblinfo) of the table with the given relname
544 * returns -1 if not found
546 * NOTE: should hash this, but just do linear search for now
550 findTableByName(TableInfo *tblinfo, int numTables, const char *relname)
554 for (i = 0; i < numTables; i++)
556 if (strcmp(tblinfo[i].relname, relname) == 0)
564 * finds the index (in tblinfo) of the table with the given oid
565 * returns -1 if not found
567 * NOTE: should hash this, but just do linear search for now
571 findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
575 for (i = 0; i < numTables; i++)
577 if (strcmp(tblinfo[i].oid, oid) == 0)
586 * finds the index (in finfo) of the function with the given name
587 * returns -1 if not found
589 * NOTE: should hash this, but just do linear search for now
593 findFuncByName(FuncInfo *finfo, int numFuncs, const char *name)
597 for (i = 0; i < numFuncs; i++)
599 if (strcmp(finfo[i].proname, name) == 0)
608 * checks input string for non-lowercase characters
609 * returns pointer to input string or string surrounded by double quotes
611 * Note that the returned string should be used immediately since it
612 * uses a static buffer to hold the string. Non-reentrant but faster?
615 fmtId(const char *rawid, bool force_quotes)
617 static PQExpBuffer id_return = NULL;
622 /* do a quick check on the first character... */
623 if (!islower((unsigned char) *rawid))
625 /* otherwise check the entire string */
627 for (cp = rawid; *cp; cp++)
629 if (!(islower((unsigned char) *cp) ||
630 isdigit((unsigned char) *cp) ||
640 return rawid; /* no quoting needed */
643 resetPQExpBuffer(id_return);
645 id_return = createPQExpBuffer();
647 appendPQExpBufferChar(id_return, '\"');
648 for (cp = rawid; *cp; cp++)
652 * Did we find a double-quote in the string? Then make this a
653 * double double-quote per SQL99. Before, we put in a
654 * backslash/double-quote pair. - thomas 2000-08-05
658 appendPQExpBufferChar(id_return, '\"');
659 appendPQExpBufferChar(id_return, '\"');
661 appendPQExpBufferChar(id_return, *cp);
663 appendPQExpBufferChar(id_return, '\"');
665 return id_return->data;