]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/common.c
- Handle overridden attrs as per discussions 2-Apr-2001
[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-2001, PostgreSQL Global Development Group
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.55 2001/04/03 08:52:59 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  * Modifications 4-Apr-2001 - pjw@rhyme.com.au
25  *      -       Changed flagInhAttrs to check all parent tables for overridden settings
26  *              and set flags accordingly.
27  *
28  *              BEWARE: Since fmtId uses a static buffer, using 'useBaseTypeName' on more
29  *                              than one call in a line will cause problems.
30  *
31  *-------------------------------------------------------------------------
32  */
33
34 #include "pg_dump.h"
35
36 #include <ctype.h>
37
38 #include "libpq-fe.h"
39 #ifndef HAVE_STRDUP
40 #include "strdup.h"
41 #endif
42
43 static char **findParentsByOid(TableInfo *tbinfo, int numTables,
44                                  InhInfo *inhinfo, int numInherits,
45                                  const char *oid,
46                                  int *numParents,
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);
52
53 /*
54  * findTypeByOid
55  *        given an oid of a type, return its typename
56  *
57  * if oid is "0", return "opaque" -- this is a special case
58  *
59  * NOTE:  should hash this, but just do linear search for now
60  */
61
62 char *
63 findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid, OidOptions opts)
64 {
65         int                     i;
66
67         if (strcmp(oid, "0") == 0)
68         {
69
70                 if ((opts & zeroAsOpaque) != 0)
71                 {
72
73                         return g_opaque_type;
74
75                 }
76                 else if ((opts & zeroAsAny) != 0)
77                 {
78
79                         return "'any'";
80
81                 }
82         }
83
84         for (i = 0; i < numTypes; i++)
85         {
86                 if (strcmp(tinfo[i].oid, oid) == 0)
87                 {
88                         if ((opts & useBaseTypeName) != 0)
89                                 return (char *) fmtId(tinfo[i].typname, false);
90                         else
91                                 return tinfo[i].typedefn;
92                 }
93         }
94
95         /* no suitable type name was found */
96         return (NULL);
97 }
98
99 /*
100  * findOprByOid
101  *        given the oid of an operator, return the name of the operator
102  *
103  *
104  * NOTE:  should hash this, but just do linear search for now
105  *
106  */
107 char *
108 findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid)
109 {
110         int                     i;
111
112         for (i = 0; i < numOprs; i++)
113         {
114                 if (strcmp(oprinfo[i].oid, oid) == 0)
115                         return oprinfo[i].oprname;
116         }
117
118         /* should never get here */
119         fprintf(stderr, "failed sanity check, opr with oid %s was not found\n",
120                         oid);
121
122         /* no suitable operator name was found */
123         return (NULL);
124 }
125
126
127 /*
128  * findParentsByOid
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.
131  *
132  *
133  * returns NULL if none
134  */
135
136 static char **
137 findParentsByOid(TableInfo *tblinfo, int numTables,
138                                  InhInfo *inhinfo, int numInherits, const char *oid,
139                                  int *numParentsPtr, int (**parentIndices)[])
140 {
141         int                     i,
142                                 j;
143         int                     parentInd,
144                                 selfInd;
145         char      **result;
146         int                     numParents;
147
148         numParents = 0;
149         for (i = 0; i < numInherits; i++)
150         {
151                 if (strcmp(inhinfo[i].inhrelid, oid) == 0)
152                         numParents++;
153         }
154
155         *numParentsPtr = numParents;
156
157         if (numParents > 0)
158         {
159                 result = (char **) malloc(sizeof(char *) * numParents);
160                 (*parentIndices) = malloc(sizeof(int) * numParents);
161                 j = 0;
162                 for (i = 0; i < numInherits; i++)
163                 {
164                         if (strcmp(inhinfo[i].inhrelid, oid) == 0)
165                         {
166                                 parentInd = findTableByOid(tblinfo, numTables,
167                                                                                    inhinfo[i].inhparent);
168                                 if (parentInd < 0)
169                                 {
170                                         selfInd = findTableByOid(tblinfo, numTables, oid);
171                                         fprintf(stderr,
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 : "",
175                                                         oid);
176                                         exit(2);
177                                 }
178                                 (**parentIndices)[j] = parentInd;
179                                 result[j++] = tblinfo[parentInd].relname;
180                         }
181                 }
182                 return result;
183         }
184         else
185         {
186                 (*parentIndices) = NULL;
187                 return NULL;
188         }
189 }
190
191 /*
192  * parseNumericArray
193  *        parse a string of numbers delimited by spaces into a character array
194  */
195
196 void
197 parseNumericArray(const char *str, char **array, int arraysize)
198 {
199         int                     j,
200                                 argNum;
201         char            temp[100];
202         char            s;
203
204         argNum = 0;
205         j = 0;
206         for (;;)
207         {
208                 s = *str++;
209                 if (s == ' ' || s == '\0')
210                 {
211                         if (j > 0)
212                         {
213                                 if (argNum >= arraysize)
214                                 {
215                                         fprintf(stderr, "parseNumericArray: too many numbers\n");
216                                         exit(2);
217                                 }
218                                 temp[j] = '\0';
219                                 array[argNum++] = strdup(temp);
220                                 j = 0;
221                         }
222                         if (s == '\0')
223                                 break;
224                 }
225                 else
226                 {
227                         if (!(isdigit((unsigned char) s) || s == '-') ||
228                                 j >= sizeof(temp) - 1)
229                         {
230                                 fprintf(stderr, "parseNumericArray: bogus number\n");
231                                 exit(2);
232                         }
233                         temp[j++] = s;
234                 }
235         }
236         while (argNum < arraysize)
237                 array[argNum++] = strdup("0");
238 }
239
240
241 /*
242  * strInArray:
243  *        takes in a string and a string array and the number of elements in the
244  * string array.
245  *        returns the index if the string is somewhere in the array, -1 otherwise
246  *
247  */
248
249 static int
250 strInArray(const char *pattern, char **arr, int arr_size)
251 {
252         int                     i;
253
254         for (i = 0; i < arr_size; i++)
255         {
256                 if (strcmp(pattern, arr[i]) == 0)
257                         return i;
258         }
259         return -1;
260 }
261
262 /*
263  * dumpSchema:
264  *        we have a valid connection, we are now going to dump the schema
265  * into the file
266  *
267  */
268
269 TableInfo  *
270 dumpSchema(Archive *fout,
271                    int *numTablesPtr,
272                    const char *tablename,
273                    const bool aclsSkip,
274                    const bool oids,
275                    const bool schemaOnly,
276                    const bool dataOnly)
277 {
278         int                     numTypes;
279         int                     numFuncs;
280         int                     numTables;
281         int                     numInherits;
282         int                     numAggregates;
283         int                     numOperators;
284         int                     numIndices;
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;
292
293         if (g_verbose)
294                 fprintf(stderr, "%s reading user-defined types %s\n",
295                                 g_comment_start, g_comment_end);
296         tinfo = getTypes(&numTypes);
297
298         if (g_verbose)
299                 fprintf(stderr, "%s reading user-defined functions %s\n",
300                                 g_comment_start, g_comment_end);
301         finfo = getFuncs(&numFuncs);
302
303         if (g_verbose)
304                 fprintf(stderr, "%s reading user-defined aggregates %s\n",
305                                 g_comment_start, g_comment_end);
306         agginfo = getAggregates(&numAggregates);
307
308         if (g_verbose)
309                 fprintf(stderr, "%s reading user-defined operators %s\n",
310                                 g_comment_start, g_comment_end);
311         oprinfo = getOperators(&numOperators);
312
313         if (g_verbose)
314                 fprintf(stderr, "%s reading user-defined tables %s\n",
315                                 g_comment_start, g_comment_end);
316         tblinfo = getTables(&numTables, finfo, numFuncs);
317
318         if (g_verbose)
319                 fprintf(stderr, "%s reading indices information %s\n",
320                                 g_comment_start, g_comment_end);
321         indinfo = getIndices(&numIndices);
322
323         if (g_verbose)
324                 fprintf(stderr, "%s reading table inheritance information %s\n",
325                                 g_comment_start, g_comment_end);
326         inhinfo = getInherits(&numInherits);
327
328         if (g_verbose)
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);
332
333         if (g_verbose)
334                 fprintf(stderr, "%s flagging inherited attributes in subtables %s\n",
335                                 g_comment_start, g_comment_end);
336         flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
337
338         if (!tablename && !dataOnly)
339         {
340                 if (g_verbose)
341                         fprintf(stderr, "%s dumping out database comment %s\n",
342                                         g_comment_start, g_comment_end);
343                 dumpDBComment(fout);
344         }
345
346         if (!tablename && fout)
347         {
348                 if (g_verbose)
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);
352         }
353
354         if (g_verbose)
355                 fprintf(stderr, "%s dumping out tables %s\n",
356                                 g_comment_start, g_comment_end);
357
358         dumpTables(fout, tblinfo, numTables, indinfo, numIndices, inhinfo, numInherits,
359            tinfo, numTypes, tablename, aclsSkip, oids, schemaOnly, dataOnly);
360
361         if (fout && !dataOnly)
362         {
363                 if (g_verbose)
364                         fprintf(stderr, "%s dumping out indices %s\n",
365                                         g_comment_start, g_comment_end);
366                 dumpIndices(fout, indinfo, numIndices, tblinfo, numTables, tablename);
367         }
368
369         if (!tablename && !dataOnly)
370         {
371                 if (g_verbose)
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);
375         }
376
377         if (!tablename && !dataOnly)
378         {
379                 if (g_verbose)
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);
383         }
384
385         if (!tablename && !dataOnly)
386         {
387                 if (g_verbose)
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);
391         }
392
393         if (!tablename && !dataOnly)
394         {
395                 if (g_verbose)
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);
399         }
400
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);
408         return tblinfo;
409 }
410
411 /* flagInhAttrs -
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
414  *
415  * initializes the parentRels field of each table
416  *
417  * modifies tblinfo
418  *
419  */
420 static void
421 flagInhAttrs(TableInfo *tblinfo, int numTables,
422                          InhInfo *inhinfo, int numInherits)
423 {
424         int                     i,
425                                 j,
426                                 k;
427         int                     parentInd;
428         int                     inhAttrInd;
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 */
434         char            *attrDef;
435         char            *inhDef;
436
437         /*
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
441          */
442         for (i = numTables - 1; i >= 0; i--)
443         {
444
445                 /* Sequences can never have parents, and attr info is undefined */
446                 if (tblinfo[i].sequence)
447                         continue;
448
449                 /* Get all the parents and their indexes. */
450                 tblinfo[i].parentRels = findParentsByOid(tblinfo, numTables,
451                                                                                                  inhinfo, numInherits,
452                                                                                                  tblinfo[i].oid,
453                                                                                                  &tblinfo[i].numParents,
454                                                                                                  &parentIndices);
455
456                 /*
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:
460                  *
461                  *     - it is NOT NULL and zero parents are NOT NULL
462                  * OR  
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.
466                  *
467                  * See discussion on -hackers around 2-Apr-2001.
468                  */
469                 for (j = 0; j < tblinfo[i].numatts; j++)
470                 {
471                         foundAttr = false;
472                         foundNotNull = false;
473                         defaultsMatch = true;
474                         defaultsFound = false;
475
476                         attrDef = tblinfo[i].adef_expr[j];
477
478                         for (k = 0; k < tblinfo[i].numParents; k++)
479                         {
480                                 parentInd = (*parentIndices)[k];
481
482                                 if (parentInd < 0)
483                                 {
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]);
487                                         exit(2);
488                                 };
489
490                                 inhAttrInd = strInArray(tblinfo[i].attnames[j],
491                                                                                 tblinfo[parentInd].attnames,
492                                                                                 tblinfo[parentInd].numatts);
493
494                                 if (inhAttrInd != -1)
495                                 {
496                                         foundAttr = true;
497                                         foundNotNull |= tblinfo[parentInd].notnull[inhAttrInd];
498                                         if (attrDef != NULL) /* It we have a default, check parent */
499                                         {
500                                                 inhDef = tblinfo[parentInd].adef_expr[inhAttrInd];
501
502                                                 if (inhDef != NULL)
503                                                 {
504                                                         defaultsFound = true;
505                                                         defaultsMatch &= (strcmp(attrDef, inhDef) == 0);
506                                                 };
507                                         };
508                                 };
509                         };
510
511                         /* 
512                          * Based on the scan of the parents, decide if we
513                          * can rely on the inherited attr
514                          */
515                         if (foundAttr) /* Attr was inherited */
516                         {
517                                 /* Set inherited flag by default */
518                                 tblinfo[i].inhAttrs[j] = 1;
519                                 tblinfo[i].inhAttrDef[j] = 1;
520                                 tblinfo[i].inhNotNull[j] = 1;
521
522                                 /* Clear it if attr had a default, but parents did not, or mismatch */
523                                 if ( (attrDef != NULL) && (!defaultsFound || !defaultsMatch) )
524                                 {
525                                         tblinfo[i].inhAttrs[j] = 0;
526                                         tblinfo[i].inhAttrDef[j] = 0;
527                                 }
528
529                                 /* Clear it if NOT NULL and none of the parents were NOT NULL */
530                                 if (tblinfo[i].notnull[j] && !foundNotNull)
531                                 {
532                                         tblinfo[i].inhAttrs[j] = 0;
533                                         tblinfo[i].inhNotNull[j] = 0;
534                                 }
535                         }
536                 }
537         }
538 }
539
540
541 /*
542  * findTableByName
543  *        finds the index (in tblinfo) of the table with the given relname
544  *      returns -1 if not found
545  *
546  * NOTE:  should hash this, but just do linear search for now
547  */
548
549 int
550 findTableByName(TableInfo *tblinfo, int numTables, const char *relname)
551 {
552         int                     i;
553
554         for (i = 0; i < numTables; i++)
555         {
556                 if (strcmp(tblinfo[i].relname, relname) == 0)
557                         return i;
558         }
559         return -1;
560 }
561
562 /*
563  * findTableByOid
564  *        finds the index (in tblinfo) of the table with the given oid
565  *      returns -1 if not found
566  *
567  * NOTE:  should hash this, but just do linear search for now
568  */
569
570 static int
571 findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
572 {
573         int                     i;
574
575         for (i = 0; i < numTables; i++)
576         {
577                 if (strcmp(tblinfo[i].oid, oid) == 0)
578                         return i;
579         }
580         return -1;
581 }
582
583
584 /*
585  * findFuncByName
586  *        finds the index (in finfo) of the function with the given name
587  *      returns -1 if not found
588  *
589  * NOTE:  should hash this, but just do linear search for now
590  */
591
592 int
593 findFuncByName(FuncInfo *finfo, int numFuncs, const char *name)
594 {
595         int                     i;
596
597         for (i = 0; i < numFuncs; i++)
598         {
599                 if (strcmp(finfo[i].proname, name) == 0)
600                         return i;
601         }
602         return -1;
603 }
604
605 /*
606  * fmtId
607  *
608  *      checks input string for non-lowercase characters
609  *      returns pointer to input string or string surrounded by double quotes
610  *
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?
613  */
614 const char *
615 fmtId(const char *rawid, bool force_quotes)
616 {
617         static PQExpBuffer id_return = NULL;
618         const char *cp;
619
620         if (!force_quotes)
621         {
622                 /* do a quick check on the first character... */
623                 if (!islower((unsigned char) *rawid))
624                         force_quotes = true;
625                 /* otherwise check the entire string */
626                 else
627                         for (cp = rawid; *cp; cp++)
628                         {
629                                 if (!(islower((unsigned char) *cp) ||
630                                           isdigit((unsigned char) *cp) ||
631                                           (*cp == '_')))
632                                 {
633                                         force_quotes = true;
634                                         break;
635                                 }
636                         }
637         }
638
639         if (!force_quotes)
640                 return rawid;                   /* no quoting needed */
641
642         if (id_return)
643                 resetPQExpBuffer(id_return);
644         else
645                 id_return = createPQExpBuffer();
646
647         appendPQExpBufferChar(id_return, '\"');
648         for (cp = rawid; *cp; cp++)
649         {
650
651                 /*
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
655                  */
656                 if (*cp == '\"')
657                 {
658                         appendPQExpBufferChar(id_return, '\"');
659                         appendPQExpBufferChar(id_return, '\"');
660                 }
661                 appendPQExpBufferChar(id_return, *cp);
662         }
663         appendPQExpBufferChar(id_return, '\"');
664
665         return id_return->data;
666 }       /* fmtId() */