1 /*-------------------------------------------------------------------------
4 * common routines between pg_dump and pg4_dump
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.47 2000/09/15 04:57:09 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 * BEWARE: Since fmtId uses a static buffer, using 'useBaseTypeName' on more
25 * than one call in a line will cause problems.
27 *-------------------------------------------------------------------------
42 static char **findParentsByOid(TableInfo *tbinfo, int numTables,
43 InhInfo *inhinfo, int numInherits,
46 static int findTableByOid(TableInfo *tbinfo, int numTables, const char *oid);
47 static void flagInhAttrs(TableInfo *tbinfo, int numTables,
48 InhInfo *inhinfo, int numInherits);
49 static int strInArray(const char *pattern, char **arr, int arr_size);
53 * given an oid of a type, return its typename
55 * if oid is "0", return "opaque" -- this is a special case
57 * NOTE: should hash this, but just do linear search for now
61 findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid, OidOptions opts)
65 if (strcmp(oid, "0") == 0) {
67 if ( (opts & zeroAsOpaque) != 0 ) {
71 } else if ( (opts & zeroAsAny) != 0 ) {
78 for (i = 0; i < numTypes; i++)
80 if (strcmp(tinfo[i].oid, oid) == 0) {
81 if ( (opts & useBaseTypeName) != 0 ) {
82 return (char*) fmtId(tinfo[i].typname, false);
84 return tinfo[i].typedefn;
89 /* should never get here */
90 fprintf(stderr, "failed sanity check, type with oid %s was not found\n",
97 * given the oid of an operator, return the name of the operator
100 * NOTE: should hash this, but just do linear search for now
104 findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid)
108 for (i = 0; i < numOprs; i++)
110 if (strcmp(oprinfo[i].oid, oid) == 0)
111 return oprinfo[i].oprname;
114 /* should never get here */
115 fprintf(stderr, "failed sanity check, opr with oid %s was not found\n",
123 * given the oid of a class, return the names of its parent classes
124 * and assign the number of parents to the last argument.
127 * returns NULL if none
131 findParentsByOid(TableInfo *tblinfo, int numTables,
132 InhInfo *inhinfo, int numInherits, const char *oid,
143 for (i = 0; i < numInherits; i++)
145 if (strcmp(inhinfo[i].inhrelid, oid) == 0)
149 *numParentsPtr = numParents;
153 result = (char **) malloc(sizeof(char *) * numParents);
155 for (i = 0; i < numInherits; i++)
157 if (strcmp(inhinfo[i].inhrelid, oid) == 0)
159 parentInd = findTableByOid(tblinfo, numTables,
160 inhinfo[i].inhparent);
163 selfInd = findTableByOid(tblinfo, numTables, oid);
165 "failed sanity check, parent oid %s of table %s (oid %s) was not found\n",
166 inhinfo[i].inhparent,
167 (selfInd >= 0) ? tblinfo[selfInd].relname : "",
171 result[j++] = tblinfo[parentInd].relname;
182 * parse a string of numbers delimited by spaces into a character array
186 parseNumericArray(const char *str, char **array, int arraysize)
198 if (s == ' ' || s == '\0')
202 if (argNum >= arraysize)
204 fprintf(stderr, "parseNumericArray: too many numbers\n");
208 array[argNum++] = strdup(temp);
216 if (!(isdigit((int) s) || s == '-') || j >= sizeof(temp) - 1)
218 fprintf(stderr, "parseNumericArray: bogus number\n");
224 while (argNum < arraysize)
225 array[argNum++] = strdup("0");
231 * takes in a string and a string array and the number of elements in the
233 * returns the index if the string is somewhere in the array, -1 otherwise
238 strInArray(const char *pattern, char **arr, int arr_size)
242 for (i = 0; i < arr_size; i++)
244 if (strcmp(pattern, arr[i]) == 0)
252 * we have a valid connection, we are now going to dump the schema
258 dumpSchema(Archive *fout,
260 const char *tablename,
263 const bool schemaOnly,
272 TypeInfo *tinfo = NULL;
273 FuncInfo *finfo = NULL;
274 AggInfo *agginfo = NULL;
275 TableInfo *tblinfo = NULL;
276 InhInfo *inhinfo = NULL;
277 OprInfo *oprinfo = NULL;
280 fprintf(stderr, "%s reading user-defined types %s\n",
281 g_comment_start, g_comment_end);
282 tinfo = getTypes(&numTypes);
285 fprintf(stderr, "%s reading user-defined functions %s\n",
286 g_comment_start, g_comment_end);
287 finfo = getFuncs(&numFuncs);
290 fprintf(stderr, "%s reading user-defined aggregates %s\n",
291 g_comment_start, g_comment_end);
292 agginfo = getAggregates(&numAggregates);
295 fprintf(stderr, "%s reading user-defined operators %s\n",
296 g_comment_start, g_comment_end);
297 oprinfo = getOperators(&numOperators);
300 fprintf(stderr, "%s reading user-defined tables %s\n",
301 g_comment_start, g_comment_end);
302 tblinfo = getTables(&numTables, finfo, numFuncs);
305 fprintf(stderr, "%s reading table inheritance information %s\n",
306 g_comment_start, g_comment_end);
307 inhinfo = getInherits(&numInherits);
310 fprintf(stderr, "%s finding the attribute names and types for each table %s\n",
311 g_comment_start, g_comment_end);
312 getTableAttrs(tblinfo, numTables);
315 fprintf(stderr, "%s flagging inherited attributes in subtables %s\n",
316 g_comment_start, g_comment_end);
317 flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
319 if (!tablename && !dataOnly)
322 fprintf(stderr, "%s dumping out database comment %s\n",
323 g_comment_start, g_comment_end);
327 if (!tablename && fout)
330 fprintf(stderr, "%s dumping out user-defined types %s\n",
331 g_comment_start, g_comment_end);
332 dumpTypes(fout, finfo, numFuncs, tinfo, numTypes);
336 fprintf(stderr, "%s dumping out tables %s\n",
337 g_comment_start, g_comment_end);
338 dumpTables(fout, tblinfo, numTables, inhinfo, numInherits,
339 tinfo, numTypes, tablename, aclsSkip, oids, schemaOnly, dataOnly);
341 if (!tablename && !dataOnly)
344 fprintf(stderr, "%s dumping out user-defined procedural languages %s\n",
345 g_comment_start, g_comment_end);
346 dumpProcLangs(fout, finfo, numFuncs, tinfo, numTypes);
349 if (!tablename && !dataOnly)
352 fprintf(stderr, "%s dumping out user-defined functions %s\n",
353 g_comment_start, g_comment_end);
354 dumpFuncs(fout, finfo, numFuncs, tinfo, numTypes);
357 if (!tablename && !dataOnly)
360 fprintf(stderr, "%s dumping out user-defined aggregates %s\n",
361 g_comment_start, g_comment_end);
362 dumpAggs(fout, agginfo, numAggregates, tinfo, numTypes);
365 if (!tablename && !dataOnly)
368 fprintf(stderr, "%s dumping out user-defined operators %s\n",
369 g_comment_start, g_comment_end);
370 dumpOprs(fout, oprinfo, numOperators, tinfo, numTypes);
373 *numTablesPtr = numTables;
374 clearAggInfo(agginfo, numAggregates);
375 clearOprInfo(oprinfo, numOperators);
376 clearTypeInfo(tinfo, numTypes);
377 clearFuncInfo(finfo, numFuncs);
378 clearInhInfo(inhinfo, numInherits);
384 * dump indexes at the end for performance
389 dumpSchemaIdx(Archive *fout, const char *tablename,
390 TableInfo *tblinfo, int numTables)
396 fprintf(stderr, "%s reading indices information %s\n",
397 g_comment_start, g_comment_end);
398 indinfo = getIndices(&numIndices);
403 fprintf(stderr, "%s dumping out indices %s\n",
404 g_comment_start, g_comment_end);
405 dumpIndices(fout, indinfo, numIndices, tblinfo, numTables, tablename);
407 clearIndInfo(indinfo, numIndices);
411 * for each table in tblinfo, flag its inherited attributes
412 * so when we dump the table out, we don't dump out the inherited attributes
414 * initializes the parentRels field of each table
420 flagInhAttrs(TableInfo *tblinfo, int numTables,
421 InhInfo *inhinfo, int numInherits)
429 * we go backwards because the tables in tblinfo are in OID order,
430 * meaning the subtables are after the parent tables we flag inherited
431 * attributes from child tables first
433 for (i = numTables - 1; i >= 0; i--)
435 tblinfo[i].parentRels = findParentsByOid(tblinfo, numTables,
436 inhinfo, numInherits,
438 &tblinfo[i].numParents);
439 for (k = 0; k < tblinfo[i].numParents; k++)
441 parentInd = findTableByName(tblinfo, numTables,
442 tblinfo[i].parentRels[k]);
445 /* shouldn't happen unless findParentsByOid is broken */
446 fprintf(stderr, "failed sanity check, table %s not found by flagInhAttrs\n",
447 tblinfo[i].parentRels[k]);
450 for (j = 0; j < tblinfo[i].numatts; j++)
452 if (strInArray(tblinfo[i].attnames[j],
453 tblinfo[parentInd].attnames,
454 tblinfo[parentInd].numatts) != -1)
455 tblinfo[i].inhAttrs[j] = 1;
464 * finds the index (in tblinfo) of the table with the given relname
465 * returns -1 if not found
467 * NOTE: should hash this, but just do linear search for now
471 findTableByName(TableInfo *tblinfo, int numTables, const char *relname)
475 for (i = 0; i < numTables; i++)
477 if (strcmp(tblinfo[i].relname, relname) == 0)
485 * finds the index (in tblinfo) of the table with the given oid
486 * returns -1 if not found
488 * NOTE: should hash this, but just do linear search for now
492 findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
496 for (i = 0; i < numTables; i++)
498 if (strcmp(tblinfo[i].oid, oid) == 0)
507 * finds the index (in finfo) of the function with the given name
508 * returns -1 if not found
510 * NOTE: should hash this, but just do linear search for now
514 findFuncByName(FuncInfo *finfo, int numFuncs, const char *name)
518 for (i = 0; i < numFuncs; i++)
520 if (strcmp(finfo[i].proname, name) == 0)
529 * checks input string for non-lowercase characters
530 * returns pointer to input string or string surrounded by double quotes
532 * Note that the returned string should be used immediately since it
533 * uses a static buffer to hold the string. Non-reentrant but faster?
536 fmtId(const char *rawid, bool force_quotes)
538 static PQExpBuffer id_return = NULL;
543 /* do a quick check on the first character... */
544 if (!islower((int) *rawid))
546 /* otherwise check the entire string */
548 for (cp = rawid; *cp; cp++)
550 if (!(islower((int) *cp) || isdigit((int) *cp) || (*cp == '_')))
559 return rawid; /* no quoting needed */
562 resetPQExpBuffer(id_return);
564 id_return = createPQExpBuffer();
566 appendPQExpBufferChar(id_return, '\"');
567 for (cp = rawid; *cp; cp++)
569 /* Did we find a double-quote in the string?
570 * Then make this a double double-quote per SQL99.
571 * Before, we put in a backslash/double-quote pair.
572 * - thomas 2000-08-05 */
575 appendPQExpBufferChar(id_return, '\"');
576 appendPQExpBufferChar(id_return, '\"');
578 appendPQExpBufferChar(id_return, *cp);
580 appendPQExpBufferChar(id_return, '\"');
582 return id_return->data;