]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/common.c
Minor code cleanup (cast away const-ness)
[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.47 2000/09/15 04:57:09 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((int) s) || s == '-') || j >= sizeof(temp) - 1)
217                         {
218                                 fprintf(stderr, "parseNumericArray: bogus number\n");
219                                 exit(2);
220                         }
221                         temp[j++] = s;
222                 }
223         }
224         while (argNum < arraysize)
225                 array[argNum++] = strdup("0");
226 }
227
228
229 /*
230  * strInArray:
231  *        takes in a string and a string array and the number of elements in the
232  * string array.
233  *        returns the index if the string is somewhere in the array, -1 otherwise
234  *
235  */
236
237 static int
238 strInArray(const char *pattern, char **arr, int arr_size)
239 {
240         int                     i;
241
242         for (i = 0; i < arr_size; i++)
243         {
244                 if (strcmp(pattern, arr[i]) == 0)
245                         return i;
246         }
247         return -1;
248 }
249
250 /*
251  * dumpSchema:
252  *        we have a valid connection, we are now going to dump the schema
253  * into the file
254  *
255  */
256
257 TableInfo  *
258 dumpSchema(Archive  *fout,
259                     int *numTablesPtr,
260                     const char *tablename,
261                     const bool aclsSkip,
262                     const bool oids,
263                     const bool schemaOnly,
264                     const bool dataOnly)
265 {
266         int                     numTypes;
267         int                     numFuncs;
268         int                     numTables;
269         int                     numInherits;
270         int                     numAggregates;
271         int                     numOperators;
272         TypeInfo   *tinfo = NULL;
273         FuncInfo   *finfo = NULL;
274         AggInfo    *agginfo = NULL;
275         TableInfo  *tblinfo = NULL;
276         InhInfo    *inhinfo = NULL;
277         OprInfo    *oprinfo = NULL;
278
279         if (g_verbose)
280                 fprintf(stderr, "%s reading user-defined types %s\n",
281                                 g_comment_start, g_comment_end);
282         tinfo = getTypes(&numTypes);
283
284         if (g_verbose)
285                 fprintf(stderr, "%s reading user-defined functions %s\n",
286                                 g_comment_start, g_comment_end);
287         finfo = getFuncs(&numFuncs);
288
289         if (g_verbose)
290                 fprintf(stderr, "%s reading user-defined aggregates %s\n",
291                                 g_comment_start, g_comment_end);
292         agginfo = getAggregates(&numAggregates);
293
294         if (g_verbose)
295                 fprintf(stderr, "%s reading user-defined operators %s\n",
296                                 g_comment_start, g_comment_end);
297         oprinfo = getOperators(&numOperators);
298
299         if (g_verbose)
300                 fprintf(stderr, "%s reading user-defined tables %s\n",
301                                 g_comment_start, g_comment_end);
302         tblinfo = getTables(&numTables, finfo, numFuncs);
303
304         if (g_verbose)
305                 fprintf(stderr, "%s reading table inheritance information %s\n",
306                                 g_comment_start, g_comment_end);
307         inhinfo = getInherits(&numInherits);
308
309         if (g_verbose)
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);
313
314         if (g_verbose)
315                 fprintf(stderr, "%s flagging inherited attributes in subtables %s\n",
316                                 g_comment_start, g_comment_end);
317         flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
318
319         if (!tablename && !dataOnly)
320         {
321                 if (g_verbose)
322                         fprintf(stderr, "%s dumping out database comment %s\n",
323                                         g_comment_start, g_comment_end);
324                 dumpDBComment(fout);
325         }
326
327         if (!tablename && fout)
328         {
329                 if (g_verbose)
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);
333         }
334
335         if (g_verbose)
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);
340
341         if (!tablename && !dataOnly)
342         {
343                 if (g_verbose)
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);
347         }
348
349         if (!tablename && !dataOnly)
350         {
351                 if (g_verbose)
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);
355         }
356
357         if (!tablename && !dataOnly)
358         {
359                 if (g_verbose)
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);
363         }
364
365         if (!tablename && !dataOnly)
366         {
367                 if (g_verbose)
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);
371         }
372
373         *numTablesPtr = numTables;
374         clearAggInfo(agginfo, numAggregates);
375         clearOprInfo(oprinfo, numOperators);
376         clearTypeInfo(tinfo, numTypes);
377         clearFuncInfo(finfo, numFuncs);
378         clearInhInfo(inhinfo, numInherits);
379         return tblinfo;
380 }
381
382 /*
383  * dumpSchemaIdx:
384  *        dump indexes at the end for performance
385  *
386  */
387
388 extern void
389 dumpSchemaIdx(Archive *fout, const char *tablename,
390                           TableInfo *tblinfo, int numTables)
391 {
392         int                     numIndices;
393         IndInfo    *indinfo;
394
395         if (g_verbose)
396                 fprintf(stderr, "%s reading indices information %s\n",
397                                 g_comment_start, g_comment_end);
398         indinfo = getIndices(&numIndices);
399
400         if (fout)
401         {
402                 if (g_verbose)
403                         fprintf(stderr, "%s dumping out indices %s\n",
404                                         g_comment_start, g_comment_end);
405                 dumpIndices(fout, indinfo, numIndices, tblinfo, numTables, tablename);
406         }
407         clearIndInfo(indinfo, numIndices);
408 }
409
410 /* flagInhAttrs -
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
413  *
414  * initializes the parentRels field of each table
415  *
416  * modifies tblinfo
417  *
418  */
419 static void
420 flagInhAttrs(TableInfo *tblinfo, int numTables,
421                          InhInfo *inhinfo, int numInherits)
422 {
423         int                     i,
424                                 j,
425                                 k;
426         int                     parentInd;
427
428         /*
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
432          */
433         for (i = numTables - 1; i >= 0; i--)
434         {
435                 tblinfo[i].parentRels = findParentsByOid(tblinfo, numTables,
436                                                                                                  inhinfo, numInherits,
437                                                                                                  tblinfo[i].oid,
438                                                                                                  &tblinfo[i].numParents);
439                 for (k = 0; k < tblinfo[i].numParents; k++)
440                 {
441                         parentInd = findTableByName(tblinfo, numTables,
442                                                                                 tblinfo[i].parentRels[k]);
443                         if (parentInd < 0)
444                         {
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]);
448                                 exit(2);
449                         }
450                         for (j = 0; j < tblinfo[i].numatts; j++)
451                         {
452                                 if (strInArray(tblinfo[i].attnames[j],
453                                                            tblinfo[parentInd].attnames,
454                                                            tblinfo[parentInd].numatts) != -1)
455                                         tblinfo[i].inhAttrs[j] = 1;
456                         }
457                 }
458         }
459 }
460
461
462 /*
463  * findTableByName
464  *        finds the index (in tblinfo) of the table with the given relname
465  *      returns -1 if not found
466  *
467  * NOTE:  should hash this, but just do linear search for now
468  */
469
470 int
471 findTableByName(TableInfo *tblinfo, int numTables, const char *relname)
472 {
473         int                     i;
474
475         for (i = 0; i < numTables; i++)
476         {
477                 if (strcmp(tblinfo[i].relname, relname) == 0)
478                         return i;
479         }
480         return -1;
481 }
482
483 /*
484  * findTableByOid
485  *        finds the index (in tblinfo) of the table with the given oid
486  *      returns -1 if not found
487  *
488  * NOTE:  should hash this, but just do linear search for now
489  */
490
491 static int
492 findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
493 {
494         int                     i;
495
496         for (i = 0; i < numTables; i++)
497         {
498                 if (strcmp(tblinfo[i].oid, oid) == 0)
499                         return i;
500         }
501         return -1;
502 }
503
504
505 /*
506  * findFuncByName
507  *        finds the index (in finfo) of the function with the given name
508  *      returns -1 if not found
509  *
510  * NOTE:  should hash this, but just do linear search for now
511  */
512
513 int
514 findFuncByName(FuncInfo *finfo, int numFuncs, const char *name)
515 {
516         int                     i;
517
518         for (i = 0; i < numFuncs; i++)
519         {
520                 if (strcmp(finfo[i].proname, name) == 0)
521                         return i;
522         }
523         return -1;
524 }
525
526 /*
527  * fmtId
528  *
529  *      checks input string for non-lowercase characters
530  *      returns pointer to input string or string surrounded by double quotes
531  *
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?
534  */
535 const char *
536 fmtId(const char *rawid, bool force_quotes)
537 {
538         static PQExpBuffer id_return = NULL;
539         const char *cp;
540
541         if (!force_quotes)
542         {
543                 /* do a quick check on the first character... */
544                 if (!islower((int) *rawid))
545                         force_quotes = true;
546                 /* otherwise check the entire string */
547                 else
548                         for (cp = rawid; *cp; cp++)
549                         {
550                                 if (!(islower((int) *cp) || isdigit((int) *cp) || (*cp == '_')))
551                                 {
552                                         force_quotes = true;
553                                         break;
554                                 }
555                         }
556         }
557
558         if (!force_quotes)
559                 return rawid;                   /* no quoting needed */
560
561         if (id_return)
562                 resetPQExpBuffer(id_return);
563         else
564                 id_return = createPQExpBuffer();
565
566         appendPQExpBufferChar(id_return, '\"');
567         for (cp = rawid; *cp; cp++)
568         {
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 */
573                 if (*cp == '\"')
574                 {
575                         appendPQExpBufferChar(id_return, '\"');
576                         appendPQExpBufferChar(id_return, '\"');
577                 }
578                 appendPQExpBufferChar(id_return, *cp);
579         }
580         appendPQExpBufferChar(id_return, '\"');
581
582         return id_return->data;
583 }       /* fmtId() */