]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/common.c
a466dafc5da59b50a36a07d47cbbd36c3d3e2ec8
[postgresql] / src / bin / pg_dump / common.c
1 /*-------------------------------------------------------------------------
2  *
3  * common.c
4  *        common routines between pg_dump and pg4_dump
5  *
6  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.49 2001/01/12 15:41:29 pjw Exp $
12  *
13  * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
14  *
15  *       - Fixed dumpTable output to output lengths for char and varchar types!
16  *       - Added single. quote to twin single quote expansion for 'insert' string
17  *         mode.
18  *
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.
23  *
24  *              BEWARE: Since fmtId uses a static buffer, using 'useBaseTypeName' on more
25  *                              than one call in a line will cause problems.
26  *
27  *-------------------------------------------------------------------------
28  */
29
30
31 #include <ctype.h>
32
33 #include "postgres.h"
34
35 #include "libpq-fe.h"
36 #ifndef HAVE_STRDUP
37 #include "strdup.h"
38 #endif
39
40 #include "pg_dump.h"
41
42 static char **findParentsByOid(TableInfo *tbinfo, int numTables,
43                                  InhInfo *inhinfo, int numInherits,
44                                  const char *oid,
45                                  int *numParents);
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);
50
51 /*
52  * findTypeByOid
53  *        given an oid of a type, return its typename
54  *
55  * if oid is "0", return "opaque" -- this is a special case
56  *
57  * NOTE:  should hash this, but just do linear search for now
58  */
59
60 char *
61 findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid, OidOptions opts)
62 {
63         int                     i;
64
65         if (strcmp(oid, "0") == 0) {
66
67                 if ( (opts & zeroAsOpaque) != 0 ) {
68
69                         return g_opaque_type;
70
71                 } else if ( (opts & zeroAsAny) != 0 ) {
72
73                         return "'any'";
74
75                 }
76         }
77
78         for (i = 0; i < numTypes; i++)
79         {
80                 if (strcmp(tinfo[i].oid, oid) == 0) {
81                         if ( (opts & useBaseTypeName) != 0 ) {
82                                 return (char*) fmtId(tinfo[i].typname, false);
83                         } else {
84                                 return tinfo[i].typedefn;
85                         }
86                 }
87         }
88
89         /* should never get here */
90         fprintf(stderr, "failed sanity check, type with oid %s was not found\n",
91                         oid);
92         exit(2);
93 }
94
95 /*
96  * findOprByOid
97  *        given the oid of an operator, return the name of the operator
98  *
99  *
100  * NOTE:  should hash this, but just do linear search for now
101  *
102  */
103 char *
104 findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid)
105 {
106         int                     i;
107
108         for (i = 0; i < numOprs; i++)
109         {
110                 if (strcmp(oprinfo[i].oid, oid) == 0)
111                         return oprinfo[i].oprname;
112         }
113
114         /* should never get here */
115         fprintf(stderr, "failed sanity check, opr with oid %s was not found\n",
116                         oid);
117         exit(2);
118 }
119
120
121 /*
122  * findParentsByOid
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.
125  *
126  *
127  * returns NULL if none
128  */
129
130 static char **
131 findParentsByOid(TableInfo *tblinfo, int numTables,
132                                  InhInfo *inhinfo, int numInherits, const char *oid,
133                                  int *numParentsPtr)
134 {
135         int                     i,
136                                 j;
137         int                     parentInd,
138                                 selfInd;
139         char      **result;
140         int                     numParents;
141
142         numParents = 0;
143         for (i = 0; i < numInherits; i++)
144         {
145                 if (strcmp(inhinfo[i].inhrelid, oid) == 0)
146                         numParents++;
147         }
148
149         *numParentsPtr = numParents;
150
151         if (numParents > 0)
152         {
153                 result = (char **) malloc(sizeof(char *) * numParents);
154                 j = 0;
155                 for (i = 0; i < numInherits; i++)
156                 {
157                         if (strcmp(inhinfo[i].inhrelid, oid) == 0)
158                         {
159                                 parentInd = findTableByOid(tblinfo, numTables,
160                                                                                    inhinfo[i].inhparent);
161                                 if (parentInd < 0)
162                                 {
163                                         selfInd = findTableByOid(tblinfo, numTables, oid);
164                                         fprintf(stderr,
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 : "",
168                                                         oid);
169                                         exit(2);
170                                 }
171                                 result[j++] = tblinfo[parentInd].relname;
172                         }
173                 }
174                 return result;
175         }
176         else
177                 return NULL;
178 }
179
180 /*
181  * parseNumericArray
182  *        parse a string of numbers delimited by spaces into a character array
183  */
184
185 void
186 parseNumericArray(const char *str, char **array, int arraysize)
187 {
188         int                     j,
189                                 argNum;
190         char            temp[100];
191         char            s;
192
193         argNum = 0;
194         j = 0;
195         for (;;)
196         {
197                 s = *str++;
198                 if (s == ' ' || s == '\0')
199                 {
200                         if (j > 0)
201                         {
202                                 if (argNum >= arraysize)
203                                 {
204                                         fprintf(stderr, "parseNumericArray: too many numbers\n");
205                                         exit(2);
206                                 }
207                                 temp[j] = '\0';
208                                 array[argNum++] = strdup(temp);
209                                 j = 0;
210                         }
211                         if (s == '\0')
212                                 break;
213                 }
214                 else
215                 {
216                         if (!(isdigit((unsigned char) s) || s == '-') ||
217                                 j >= sizeof(temp) - 1)
218                         {
219                                 fprintf(stderr, "parseNumericArray: bogus number\n");
220                                 exit(2);
221                         }
222                         temp[j++] = s;
223                 }
224         }
225         while (argNum < arraysize)
226                 array[argNum++] = strdup("0");
227 }
228
229
230 /*
231  * strInArray:
232  *        takes in a string and a string array and the number of elements in the
233  * string array.
234  *        returns the index if the string is somewhere in the array, -1 otherwise
235  *
236  */
237
238 static int
239 strInArray(const char *pattern, char **arr, int arr_size)
240 {
241         int                     i;
242
243         for (i = 0; i < arr_size; i++)
244         {
245                 if (strcmp(pattern, arr[i]) == 0)
246                         return i;
247         }
248         return -1;
249 }
250
251 /*
252  * dumpSchema:
253  *        we have a valid connection, we are now going to dump the schema
254  * into the file
255  *
256  */
257
258 TableInfo  *
259 dumpSchema(Archive  *fout,
260                     int *numTablesPtr,
261                     const char *tablename,
262                     const bool aclsSkip,
263                     const bool oids,
264                     const bool schemaOnly,
265                     const bool dataOnly)
266 {
267         int                     numTypes;
268         int                     numFuncs;
269         int                     numTables;
270         int                     numInherits;
271         int                     numAggregates;
272         int                     numOperators;
273         int                     numIndices;
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;
281
282         if (g_verbose)
283                 fprintf(stderr, "%s reading user-defined types %s\n",
284                                 g_comment_start, g_comment_end);
285         tinfo = getTypes(&numTypes);
286
287         if (g_verbose)
288                 fprintf(stderr, "%s reading user-defined functions %s\n",
289                                 g_comment_start, g_comment_end);
290         finfo = getFuncs(&numFuncs);
291
292         if (g_verbose)
293                 fprintf(stderr, "%s reading user-defined aggregates %s\n",
294                                 g_comment_start, g_comment_end);
295         agginfo = getAggregates(&numAggregates);
296
297         if (g_verbose)
298                 fprintf(stderr, "%s reading user-defined operators %s\n",
299                                 g_comment_start, g_comment_end);
300         oprinfo = getOperators(&numOperators);
301
302         if (g_verbose)
303                 fprintf(stderr, "%s reading user-defined tables %s\n",
304                                 g_comment_start, g_comment_end);
305         tblinfo = getTables(&numTables, finfo, numFuncs);
306
307         if (g_verbose)
308                 fprintf(stderr, "%s reading indices information %s\n",
309                                 g_comment_start, g_comment_end);
310         indinfo = getIndices(&numIndices);
311
312         if (g_verbose)
313                 fprintf(stderr, "%s reading table inheritance information %s\n",
314                                 g_comment_start, g_comment_end);
315         inhinfo = getInherits(&numInherits);
316
317         if (g_verbose)
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);
321
322         if (g_verbose)
323                 fprintf(stderr, "%s flagging inherited attributes in subtables %s\n",
324                                 g_comment_start, g_comment_end);
325         flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
326
327         if (!tablename && !dataOnly)
328         {
329                 if (g_verbose)
330                         fprintf(stderr, "%s dumping out database comment %s\n",
331                                         g_comment_start, g_comment_end);
332                 dumpDBComment(fout);
333         }
334
335         if (!tablename && fout)
336         {
337                 if (g_verbose)
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);
341         }
342
343         if (g_verbose)
344                 fprintf(stderr, "%s dumping out tables %s\n",
345                                 g_comment_start, g_comment_end);
346
347         dumpTables(fout, tblinfo, numTables, indinfo, numIndices, inhinfo, numInherits,
348                            tinfo, numTypes, tablename, aclsSkip, oids, schemaOnly, dataOnly);
349
350         if (fout && !dataOnly)
351         {
352                 if (g_verbose)
353                         fprintf(stderr, "%s dumping out indices %s\n",
354                                         g_comment_start, g_comment_end);
355                 dumpIndices(fout, indinfo, numIndices, tblinfo, numTables, tablename);
356         }
357
358         if (!tablename && !dataOnly)
359         {
360                 if (g_verbose)
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);
364         }
365
366         if (!tablename && !dataOnly)
367         {
368                 if (g_verbose)
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);
372         }
373
374         if (!tablename && !dataOnly)
375         {
376                 if (g_verbose)
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);
380         }
381
382         if (!tablename && !dataOnly)
383         {
384                 if (g_verbose)
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);
388         }
389
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);
397         return tblinfo;
398 }
399
400 /* flagInhAttrs -
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
403  *
404  * initializes the parentRels field of each table
405  *
406  * modifies tblinfo
407  *
408  */
409 static void
410 flagInhAttrs(TableInfo *tblinfo, int numTables,
411                          InhInfo *inhinfo, int numInherits)
412 {
413         int                     i,
414                                 j,
415                                 k;
416         int                     parentInd;
417
418         /*
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
422          */
423         for (i = numTables - 1; i >= 0; i--)
424         {
425                 tblinfo[i].parentRels = findParentsByOid(tblinfo, numTables,
426                                                                                                  inhinfo, numInherits,
427                                                                                                  tblinfo[i].oid,
428                                                                                                  &tblinfo[i].numParents);
429                 for (k = 0; k < tblinfo[i].numParents; k++)
430                 {
431                         parentInd = findTableByName(tblinfo, numTables,
432                                                                                 tblinfo[i].parentRels[k]);
433                         if (parentInd < 0)
434                         {
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]);
438                                 exit(2);
439                         }
440                         for (j = 0; j < tblinfo[i].numatts; j++)
441                         {
442                                 if (strInArray(tblinfo[i].attnames[j],
443                                                            tblinfo[parentInd].attnames,
444                                                            tblinfo[parentInd].numatts) != -1)
445                                         tblinfo[i].inhAttrs[j] = 1;
446                         }
447                 }
448         }
449 }
450
451
452 /*
453  * findTableByName
454  *        finds the index (in tblinfo) of the table with the given relname
455  *      returns -1 if not found
456  *
457  * NOTE:  should hash this, but just do linear search for now
458  */
459
460 int
461 findTableByName(TableInfo *tblinfo, int numTables, const char *relname)
462 {
463         int                     i;
464
465         for (i = 0; i < numTables; i++)
466         {
467                 if (strcmp(tblinfo[i].relname, relname) == 0)
468                         return i;
469         }
470         return -1;
471 }
472
473 /*
474  * findTableByOid
475  *        finds the index (in tblinfo) of the table with the given oid
476  *      returns -1 if not found
477  *
478  * NOTE:  should hash this, but just do linear search for now
479  */
480
481 static int
482 findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
483 {
484         int                     i;
485
486         for (i = 0; i < numTables; i++)
487         {
488                 if (strcmp(tblinfo[i].oid, oid) == 0)
489                         return i;
490         }
491         return -1;
492 }
493
494
495 /*
496  * findFuncByName
497  *        finds the index (in finfo) of the function with the given name
498  *      returns -1 if not found
499  *
500  * NOTE:  should hash this, but just do linear search for now
501  */
502
503 int
504 findFuncByName(FuncInfo *finfo, int numFuncs, const char *name)
505 {
506         int                     i;
507
508         for (i = 0; i < numFuncs; i++)
509         {
510                 if (strcmp(finfo[i].proname, name) == 0)
511                         return i;
512         }
513         return -1;
514 }
515
516 /*
517  * fmtId
518  *
519  *      checks input string for non-lowercase characters
520  *      returns pointer to input string or string surrounded by double quotes
521  *
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?
524  */
525 const char *
526 fmtId(const char *rawid, bool force_quotes)
527 {
528         static PQExpBuffer id_return = NULL;
529         const char *cp;
530
531         if (!force_quotes)
532         {
533                 /* do a quick check on the first character... */
534                 if (!islower((unsigned char) *rawid))
535                         force_quotes = true;
536                 /* otherwise check the entire string */
537                 else
538                         for (cp = rawid; *cp; cp++)
539                         {
540                                 if (!(islower((unsigned char) *cp) ||
541                                           isdigit((unsigned char) *cp) ||
542                                           (*cp == '_')))
543                                 {
544                                         force_quotes = true;
545                                         break;
546                                 }
547                         }
548         }
549
550         if (!force_quotes)
551                 return rawid;                   /* no quoting needed */
552
553         if (id_return)
554                 resetPQExpBuffer(id_return);
555         else
556                 id_return = createPQExpBuffer();
557
558         appendPQExpBufferChar(id_return, '\"');
559         for (cp = rawid; *cp; cp++)
560         {
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 */
565                 if (*cp == '\"')
566                 {
567                         appendPQExpBufferChar(id_return, '\"');
568                         appendPQExpBufferChar(id_return, '\"');
569                 }
570                 appendPQExpBufferChar(id_return, *cp);
571         }
572         appendPQExpBufferChar(id_return, '\"');
573
574         return id_return->data;
575 }       /* fmtId() */