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.49 2001/01/12 15:41:29 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((unsigned char) s) || s == '-') ||
217 j >= sizeof(temp) - 1)
219 fprintf(stderr, "parseNumericArray: bogus number\n");
225 while (argNum < arraysize)
226 array[argNum++] = strdup("0");
232 * takes in a string and a string array and the number of elements in the
234 * returns the index if the string is somewhere in the array, -1 otherwise
239 strInArray(const char *pattern, char **arr, int arr_size)
243 for (i = 0; i < arr_size; i++)
245 if (strcmp(pattern, arr[i]) == 0)
253 * we have a valid connection, we are now going to dump the schema
259 dumpSchema(Archive *fout,
261 const char *tablename,
264 const bool schemaOnly,
274 TypeInfo *tinfo = NULL;
275 FuncInfo *finfo = NULL;
276 AggInfo *agginfo = NULL;
277 TableInfo *tblinfo = NULL;
278 InhInfo *inhinfo = NULL;
279 OprInfo *oprinfo = NULL;
280 IndInfo *indinfo = NULL;
283 fprintf(stderr, "%s reading user-defined types %s\n",
284 g_comment_start, g_comment_end);
285 tinfo = getTypes(&numTypes);
288 fprintf(stderr, "%s reading user-defined functions %s\n",
289 g_comment_start, g_comment_end);
290 finfo = getFuncs(&numFuncs);
293 fprintf(stderr, "%s reading user-defined aggregates %s\n",
294 g_comment_start, g_comment_end);
295 agginfo = getAggregates(&numAggregates);
298 fprintf(stderr, "%s reading user-defined operators %s\n",
299 g_comment_start, g_comment_end);
300 oprinfo = getOperators(&numOperators);
303 fprintf(stderr, "%s reading user-defined tables %s\n",
304 g_comment_start, g_comment_end);
305 tblinfo = getTables(&numTables, finfo, numFuncs);
308 fprintf(stderr, "%s reading indices information %s\n",
309 g_comment_start, g_comment_end);
310 indinfo = getIndices(&numIndices);
313 fprintf(stderr, "%s reading table inheritance information %s\n",
314 g_comment_start, g_comment_end);
315 inhinfo = getInherits(&numInherits);
318 fprintf(stderr, "%s finding the attribute names and types for each table %s\n",
319 g_comment_start, g_comment_end);
320 getTableAttrs(tblinfo, numTables);
323 fprintf(stderr, "%s flagging inherited attributes in subtables %s\n",
324 g_comment_start, g_comment_end);
325 flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
327 if (!tablename && !dataOnly)
330 fprintf(stderr, "%s dumping out database comment %s\n",
331 g_comment_start, g_comment_end);
335 if (!tablename && fout)
338 fprintf(stderr, "%s dumping out user-defined types %s\n",
339 g_comment_start, g_comment_end);
340 dumpTypes(fout, finfo, numFuncs, tinfo, numTypes);
344 fprintf(stderr, "%s dumping out tables %s\n",
345 g_comment_start, g_comment_end);
347 dumpTables(fout, tblinfo, numTables, indinfo, numIndices, inhinfo, numInherits,
348 tinfo, numTypes, tablename, aclsSkip, oids, schemaOnly, dataOnly);
350 if (fout && !dataOnly)
353 fprintf(stderr, "%s dumping out indices %s\n",
354 g_comment_start, g_comment_end);
355 dumpIndices(fout, indinfo, numIndices, tblinfo, numTables, tablename);
358 if (!tablename && !dataOnly)
361 fprintf(stderr, "%s dumping out user-defined procedural languages %s\n",
362 g_comment_start, g_comment_end);
363 dumpProcLangs(fout, finfo, numFuncs, tinfo, numTypes);
366 if (!tablename && !dataOnly)
369 fprintf(stderr, "%s dumping out user-defined functions %s\n",
370 g_comment_start, g_comment_end);
371 dumpFuncs(fout, finfo, numFuncs, tinfo, numTypes);
374 if (!tablename && !dataOnly)
377 fprintf(stderr, "%s dumping out user-defined aggregates %s\n",
378 g_comment_start, g_comment_end);
379 dumpAggs(fout, agginfo, numAggregates, tinfo, numTypes);
382 if (!tablename && !dataOnly)
385 fprintf(stderr, "%s dumping out user-defined operators %s\n",
386 g_comment_start, g_comment_end);
387 dumpOprs(fout, oprinfo, numOperators, tinfo, numTypes);
390 *numTablesPtr = numTables;
391 clearAggInfo(agginfo, numAggregates);
392 clearOprInfo(oprinfo, numOperators);
393 clearTypeInfo(tinfo, numTypes);
394 clearFuncInfo(finfo, numFuncs);
395 clearInhInfo(inhinfo, numInherits);
396 clearIndInfo(indinfo, numIndices);
401 * for each table in tblinfo, flag its inherited attributes
402 * so when we dump the table out, we don't dump out the inherited attributes
404 * initializes the parentRels field of each table
410 flagInhAttrs(TableInfo *tblinfo, int numTables,
411 InhInfo *inhinfo, int numInherits)
419 * we go backwards because the tables in tblinfo are in OID order,
420 * meaning the subtables are after the parent tables we flag inherited
421 * attributes from child tables first
423 for (i = numTables - 1; i >= 0; i--)
425 tblinfo[i].parentRels = findParentsByOid(tblinfo, numTables,
426 inhinfo, numInherits,
428 &tblinfo[i].numParents);
429 for (k = 0; k < tblinfo[i].numParents; k++)
431 parentInd = findTableByName(tblinfo, numTables,
432 tblinfo[i].parentRels[k]);
435 /* shouldn't happen unless findParentsByOid is broken */
436 fprintf(stderr, "failed sanity check, table %s not found by flagInhAttrs\n",
437 tblinfo[i].parentRels[k]);
440 for (j = 0; j < tblinfo[i].numatts; j++)
442 if (strInArray(tblinfo[i].attnames[j],
443 tblinfo[parentInd].attnames,
444 tblinfo[parentInd].numatts) != -1)
445 tblinfo[i].inhAttrs[j] = 1;
454 * finds the index (in tblinfo) of the table with the given relname
455 * returns -1 if not found
457 * NOTE: should hash this, but just do linear search for now
461 findTableByName(TableInfo *tblinfo, int numTables, const char *relname)
465 for (i = 0; i < numTables; i++)
467 if (strcmp(tblinfo[i].relname, relname) == 0)
475 * finds the index (in tblinfo) of the table with the given oid
476 * returns -1 if not found
478 * NOTE: should hash this, but just do linear search for now
482 findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
486 for (i = 0; i < numTables; i++)
488 if (strcmp(tblinfo[i].oid, oid) == 0)
497 * finds the index (in finfo) of the function with the given name
498 * returns -1 if not found
500 * NOTE: should hash this, but just do linear search for now
504 findFuncByName(FuncInfo *finfo, int numFuncs, const char *name)
508 for (i = 0; i < numFuncs; i++)
510 if (strcmp(finfo[i].proname, name) == 0)
519 * checks input string for non-lowercase characters
520 * returns pointer to input string or string surrounded by double quotes
522 * Note that the returned string should be used immediately since it
523 * uses a static buffer to hold the string. Non-reentrant but faster?
526 fmtId(const char *rawid, bool force_quotes)
528 static PQExpBuffer id_return = NULL;
533 /* do a quick check on the first character... */
534 if (!islower((unsigned char) *rawid))
536 /* otherwise check the entire string */
538 for (cp = rawid; *cp; cp++)
540 if (!(islower((unsigned char) *cp) ||
541 isdigit((unsigned char) *cp) ||
551 return rawid; /* no quoting needed */
554 resetPQExpBuffer(id_return);
556 id_return = createPQExpBuffer();
558 appendPQExpBufferChar(id_return, '\"');
559 for (cp = rawid; *cp; cp++)
561 /* Did we find a double-quote in the string?
562 * Then make this a double double-quote per SQL99.
563 * Before, we put in a backslash/double-quote pair.
564 * - thomas 2000-08-05 */
567 appendPQExpBufferChar(id_return, '\"');
568 appendPQExpBufferChar(id_return, '\"');
570 appendPQExpBufferChar(id_return, *cp);
572 appendPQExpBufferChar(id_return, '\"');
574 return id_return->data;