]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/common.c
7870a0d66d21d6a8d2e2c526b9e3bd15494195f3
[postgresql] / src / bin / pg_dump / common.c
1 /*-------------------------------------------------------------------------
2  *
3  * common.c
4  *        common routines between pg_dump and pg4_dump
5  *
6  * Since pg4_dump is long-dead code, there is no longer any useful distinction
7  * between this file and pg_dump.c.
8  *
9  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
10  * Portions Copyright (c) 1994, Regents of the University of California
11  *
12  *
13  * IDENTIFICATION
14  *        $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.71 2002/10/09 16:20:25 momjian Exp $
15  *
16  *-------------------------------------------------------------------------
17  */
18
19 #include "postgres_fe.h"
20 #include "pg_dump.h"
21 #include "pg_backup_archiver.h"
22 #include "postgres.h"
23 #include "catalog/pg_class.h"
24
25 #include <ctype.h>
26
27 #include "libpq-fe.h"
28 #ifndef HAVE_STRDUP
29 #include "strdup.h"
30 #endif
31
32 static void findParentsByOid(TableInfo *tblinfo, int numTables,
33                                  InhInfo *inhinfo, int numInherits,
34                                  const char *oid,
35                                  int *numParentsPtr, int **parentIndexes);
36 static void flagInhTables(TableInfo *tbinfo, int numTables,
37                           InhInfo *inhinfo, int numInherits);
38 static void flagInhAttrs(TableInfo *tbinfo, int numTables,
39                          InhInfo *inhinfo, int numInherits);
40 static int      strInArray(const char *pattern, char **arr, int arr_size);
41
42
43 /*
44  * dumpSchema:
45  *        we have a valid connection, we are now going to dump the schema
46  * into the file
47  */
48
49 TableInfo *
50 dumpSchema(Archive *fout,
51                    int *numTablesPtr,
52                    const bool aclsSkip,
53                    const bool schemaOnly,
54                    const bool dataOnly)
55 {
56         int                     numNamespaces;
57         int                     numTypes;
58         int                     numFuncs;
59         int                     numTables;
60         int                     numInherits;
61         int                     numAggregates;
62         int                     numOperators;
63         int                     numOpclasses;
64         NamespaceInfo *nsinfo;
65         TypeInfo   *tinfo;
66         FuncInfo   *finfo;
67         AggInfo    *agginfo;
68         TableInfo  *tblinfo;
69         InhInfo    *inhinfo;
70         OprInfo    *oprinfo;
71         OpclassInfo *opcinfo;
72
73         if (g_verbose)
74                 write_msg(NULL, "reading namespaces\n");
75         nsinfo = getNamespaces(&numNamespaces);
76
77         if (g_verbose)
78                 write_msg(NULL, "reading user-defined types\n");
79         tinfo = getTypes(&numTypes);
80
81         if (g_verbose)
82                 write_msg(NULL, "reading user-defined functions\n");
83         finfo = getFuncs(&numFuncs);
84
85         if (g_verbose)
86                 write_msg(NULL, "reading user-defined aggregate functions\n");
87         agginfo = getAggregates(&numAggregates);
88
89         if (g_verbose)
90                 write_msg(NULL, "reading user-defined operators\n");
91         oprinfo = getOperators(&numOperators);
92
93         if (g_verbose)
94                 write_msg(NULL, "reading user-defined operator classes\n");
95         opcinfo = getOpclasses(&numOpclasses);
96
97         if (g_verbose)
98                 write_msg(NULL, "reading user-defined tables\n");
99         tblinfo = getTables(&numTables);
100
101         if (g_verbose)
102                 write_msg(NULL, "reading table inheritance information\n");
103         inhinfo = getInherits(&numInherits);
104
105         /* Link tables to parents, mark parents of target tables interesting */
106         if (g_verbose)
107                 write_msg(NULL, "finding inheritance relationships\n");
108         flagInhTables(tblinfo, numTables, inhinfo, numInherits);
109
110         if (g_verbose)
111                 write_msg(NULL, "reading column info for interesting tables\n");
112         getTableAttrs(tblinfo, numTables);
113
114         if (g_verbose)
115                 write_msg(NULL, "flagging inherited columns in subtables\n");
116         flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
117
118         if (!dataOnly)
119         {
120                 if (g_verbose)
121                         write_msg(NULL, "dumping out database comment\n");
122                 dumpDBComment(fout);
123         }
124
125         if (!dataOnly)
126         {
127                 if (g_verbose)
128                         write_msg(NULL, "dumping out user-defined namespaces\n");
129                 dumpNamespaces(fout, nsinfo, numNamespaces);
130         }
131
132         if (!dataOnly)
133         {
134                 if (g_verbose)
135                         write_msg(NULL, "dumping out user-defined types\n");
136                 dumpTypes(fout, finfo, numFuncs, tinfo, numTypes);
137         }
138
139         if (g_verbose)
140                 write_msg(NULL, "dumping out tables\n");
141         dumpTables(fout, tblinfo, numTables,
142                            aclsSkip, schemaOnly, dataOnly);
143
144         if (!dataOnly)
145         {
146                 if (g_verbose)
147                         write_msg(NULL, "dumping out indexes\n");
148                 dumpIndexes(fout, tblinfo, numTables);
149         }
150
151         if (!dataOnly)
152         {
153                 if (g_verbose)
154                         write_msg(NULL, "dumping out user-defined procedural languages\n");
155                 dumpProcLangs(fout, finfo, numFuncs);
156         }
157
158         if (!dataOnly)
159         {
160                 if (g_verbose)
161                         write_msg(NULL, "dumping out user-defined functions\n");
162                 dumpFuncs(fout, finfo, numFuncs);
163         }
164
165         if (!dataOnly)
166         {
167                 if (g_verbose)
168                         write_msg(NULL, "dumping out user-defined aggregate functions\n");
169                 dumpAggs(fout, agginfo, numAggregates);
170         }
171
172         if (!dataOnly)
173         {
174                 if (g_verbose)
175                         write_msg(NULL, "dumping out user-defined operators\n");
176                 dumpOprs(fout, oprinfo, numOperators);
177         }
178
179         if (!dataOnly)
180         {
181                 if (g_verbose)
182                         write_msg(NULL, "dumping out user-defined operator classes\n");
183                 dumpOpclasses(fout, opcinfo, numOpclasses);
184         }
185
186         if (!dataOnly)
187         {
188                 if (g_verbose)
189                         write_msg(NULL, "dumping out user-defined casts\n");
190                 dumpCasts(fout, finfo, numFuncs, tinfo, numTypes);
191         }
192
193         *numTablesPtr = numTables;
194         return tblinfo;
195 }
196
197 /* flagInhTables -
198  *       Fill in parentIndexes fields of every target table, and mark
199  *       parents of target tables as interesting
200  *
201  * Note that only direct ancestors of targets are marked interesting.
202  * This is sufficient; we don't much care whether they inherited their
203  * attributes or not.
204  *
205  * modifies tblinfo
206  */
207 static void
208 flagInhTables(TableInfo *tblinfo, int numTables,
209                           InhInfo *inhinfo, int numInherits)
210 {
211         int                     i,
212                                 j;
213         int                     numParents;
214         int                *parentIndexes;
215
216         for (i = 0; i < numTables; i++)
217         {
218                 /* Sequences and views never have parents */
219                 if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
220                         tblinfo[i].relkind == RELKIND_VIEW)
221                         continue;
222
223                 /* Don't bother computing anything for non-target tables, either */
224                 if (!tblinfo[i].dump)
225                         continue;
226
227                 /* Find all the immediate parent tables */
228                 findParentsByOid(tblinfo, numTables,
229                                                  inhinfo, numInherits,
230                                                  tblinfo[i].oid,
231                                                  &tblinfo[i].numParents,
232                                                  &tblinfo[i].parentIndexes);
233                 numParents = tblinfo[i].numParents;
234                 parentIndexes = tblinfo[i].parentIndexes;
235
236                 /* Mark the parents as interesting for getTableAttrs */
237                 for (j = 0; j < numParents; j++)
238                 {
239                         int                     parentInd = parentIndexes[j];
240
241                         tblinfo[parentInd].interesting = true;
242                 }
243         }
244 }
245
246 /* flagInhAttrs -
247  *       for each dumpable table in tblinfo, flag its inherited attributes
248  * so when we dump the table out, we don't dump out the inherited attributes
249  *
250  * modifies tblinfo
251  */
252 static void
253 flagInhAttrs(TableInfo *tblinfo, int numTables,
254                          InhInfo *inhinfo, int numInherits)
255 {
256         int                     i,
257                                 j,
258                                 k;
259         int                     parentInd;
260         int                     inhAttrInd;
261         int                     numParents;
262         int                *parentIndexes;
263         bool            foundAttr;              /* Attr was found in a parent */
264         bool            foundNotNull;   /* Attr was NOT NULL in a parent */
265         bool            defaultsMatch;  /* All non-empty defaults match */
266         bool            defaultsFound;  /* Found a default in a parent */
267         char       *attrDef;
268         char       *inhDef;
269
270         for (i = 0; i < numTables; i++)
271         {
272                 /* Sequences and views never have parents */
273                 if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
274                         tblinfo[i].relkind == RELKIND_VIEW)
275                         continue;
276
277                 /* Don't bother computing anything for non-target tables, either */
278                 if (!tblinfo[i].dump)
279                         continue;
280
281                 numParents = tblinfo[i].numParents;
282                 parentIndexes = tblinfo[i].parentIndexes;
283
284                 if (numParents == 0)
285                         continue;                       /* nothing to see here, move along */
286
287                 /*----------------------------------------------------------------
288                  * For each attr, check the parent info: if no parent has an attr
289                  * with the same name, then it's not inherited. If there *is* an
290                  * attr with the same name, then only dump it if:
291                  *
292                  * - it is NOT NULL and zero parents are NOT NULL
293                  *   OR 
294                  * - it has a default value AND the default value does not match
295                  *   all parent default values, or no parents specify a default.
296                  *
297                  * See discussion on -hackers around 2-Apr-2001.
298                  *----------------------------------------------------------------
299                  */
300                 for (j = 0; j < tblinfo[i].numatts; j++)
301                 {
302                         foundAttr = false;
303                         foundNotNull = false;
304                         defaultsMatch = true;
305                         defaultsFound = false;
306
307                         attrDef = tblinfo[i].adef_expr[j];
308
309                         for (k = 0; k < numParents; k++)
310                         {
311                                 parentInd = parentIndexes[k];
312                                 inhAttrInd = strInArray(tblinfo[i].attnames[j],
313                                                                                 tblinfo[parentInd].attnames,
314                                                                                 tblinfo[parentInd].numatts);
315
316                                 if (inhAttrInd != -1)
317                                 {
318                                         foundAttr = true;
319                                         foundNotNull |= tblinfo[parentInd].notnull[inhAttrInd];
320                                         if (attrDef != NULL)            /* If we have a default,
321                                                                                                  * check parent */
322                                         {
323                                                 inhDef = tblinfo[parentInd].adef_expr[inhAttrInd];
324
325                                                 if (inhDef != NULL)
326                                                 {
327                                                         defaultsFound = true;
328                                                         defaultsMatch &= (strcmp(attrDef, inhDef) == 0);
329                                                 }
330                                         }
331                                 }
332                         }
333
334                         /*
335                          * Based on the scan of the parents, decide if we can rely on
336                          * the inherited attr
337                          */
338                         if (foundAttr)          /* Attr was inherited */
339                         {
340                                 /* Set inherited flag by default */
341                                 tblinfo[i].inhAttrs[j] = true;
342                                 tblinfo[i].inhAttrDef[j] = true;
343                                 tblinfo[i].inhNotNull[j] = true;
344
345                                 /*
346                                  * Clear it if attr had a default, but parents did not, or
347                                  * mismatch
348                                  */
349                                 if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch))
350                                 {
351                                         tblinfo[i].inhAttrs[j] = false;
352                                         tblinfo[i].inhAttrDef[j] = false;
353                                 }
354
355                                 /*
356                                  * Clear it if NOT NULL and none of the parents were NOT
357                                  * NULL
358                                  */
359                                 if (tblinfo[i].notnull[j] && !foundNotNull)
360                                 {
361                                         tblinfo[i].inhAttrs[j] = false;
362                                         tblinfo[i].inhNotNull[j] = false;
363                                 }
364
365                                 /* Clear it if attr has local definition */
366                                 if (g_fout->remoteVersion >= 70300 && tblinfo[i].attislocal[j])
367                                 {
368                                         tblinfo[i].inhAttrs[j] = false;
369                                 }
370                         }
371                 }
372         }
373 }
374
375
376 /*
377  * findTableByOid
378  *        finds the index (in tblinfo) of the table with the given oid
379  *      returns -1 if not found
380  *
381  * NOTE:  should hash this, but just do linear search for now
382  */
383 int
384 findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
385 {
386         int                     i;
387
388         for (i = 0; i < numTables; i++)
389         {
390                 if (strcmp(tblinfo[i].oid, oid) == 0)
391                         return i;
392         }
393         return -1;
394 }
395
396
397 /*
398  * findFuncByOid
399  *        finds the index (in finfo) of the function with the given OID
400  *      returns -1 if not found
401  *
402  * NOTE:  should hash this, but just do linear search for now
403  */
404 int
405 findFuncByOid(FuncInfo *finfo, int numFuncs, const char *oid)
406 {
407         int                     i;
408
409         for (i = 0; i < numFuncs; i++)
410         {
411                 if (strcmp(finfo[i].oid, oid) == 0)
412                         return i;
413         }
414         return -1;
415 }
416
417 /*
418  * Finds the index (in tinfo) of the type with the given OID.  Returns
419  * -1 if not found.
420  */
421 int
422 findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid)
423 {
424         int                     i;
425
426         for (i = 0; i < numTypes; i++)
427         {
428                 if (strcmp(tinfo[i].oid, oid) == 0)
429                         return i;
430         }
431         return -1;
432 }
433
434 /*
435  * findOprByOid
436  *        given the oid of an operator, return the name of the operator
437  *
438  * NOTE:  should hash this, but just do linear search for now
439  */
440 char *
441 findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid)
442 {
443         int                     i;
444
445         for (i = 0; i < numOprs; i++)
446         {
447                 if (strcmp(oprinfo[i].oid, oid) == 0)
448                         return oprinfo[i].oprname;
449         }
450
451         /* should never get here */
452         write_msg(NULL, "failed sanity check, operator with oid %s not found\n", oid);
453
454         /* no suitable operator name was found */
455         return (NULL);
456 }
457
458
459 /*
460  * findParentsByOid
461  *        given the oid of a class, find its parent classes in tblinfo[]
462  *
463  * Returns the number of parents and their array indexes into the
464  * last two arguments.
465  */
466
467 static void
468 findParentsByOid(TableInfo *tblinfo, int numTables,
469                                  InhInfo *inhinfo, int numInherits,
470                                  const char *oid,
471                                  int *numParentsPtr, int **parentIndexes)
472 {
473         int                     i,
474                                 j;
475         int                     parentInd,
476                                 selfInd;
477         int                     numParents;
478
479         numParents = 0;
480         for (i = 0; i < numInherits; i++)
481         {
482                 if (strcmp(inhinfo[i].inhrelid, oid) == 0)
483                         numParents++;
484         }
485
486         *numParentsPtr = numParents;
487
488         if (numParents > 0)
489         {
490                 *parentIndexes = (int *) malloc(sizeof(int) * numParents);
491                 j = 0;
492                 for (i = 0; i < numInherits; i++)
493                 {
494                         if (strcmp(inhinfo[i].inhrelid, oid) == 0)
495                         {
496                                 parentInd = findTableByOid(tblinfo, numTables,
497                                                                                    inhinfo[i].inhparent);
498                                 if (parentInd < 0)
499                                 {
500                                         selfInd = findTableByOid(tblinfo, numTables, oid);
501                                         if (selfInd >= 0)
502                                                 write_msg(NULL, "failed sanity check, parent oid %s of table %s (oid %s) not found\n",
503                                                                   inhinfo[i].inhparent,
504                                                                   tblinfo[selfInd].relname,
505                                                                   oid);
506                                         else
507                                                 write_msg(NULL, "failed sanity check, parent oid %s of table (oid %s) not found\n",
508                                                                   inhinfo[i].inhparent,
509                                                                   oid);
510
511                                         exit_nicely();
512                                 }
513                                 (*parentIndexes)[j++] = parentInd;
514                         }
515                 }
516         }
517         else
518                 *parentIndexes = NULL;
519 }
520
521 /*
522  * parseNumericArray
523  *        parse a string of numbers delimited by spaces into a character array
524  */
525
526 void
527 parseNumericArray(const char *str, char **array, int arraysize)
528 {
529         int                     j,
530                                 argNum;
531         char            temp[100];
532         char            s;
533
534         argNum = 0;
535         j = 0;
536         for (;;)
537         {
538                 s = *str++;
539                 if (s == ' ' || s == '\0')
540                 {
541                         if (j > 0)
542                         {
543                                 if (argNum >= arraysize)
544                                 {
545                                         write_msg(NULL, "parseNumericArray: too many numbers\n");
546                                         exit_nicely();
547                                 }
548                                 temp[j] = '\0';
549                                 array[argNum++] = strdup(temp);
550                                 j = 0;
551                         }
552                         if (s == '\0')
553                                 break;
554                 }
555                 else
556                 {
557                         if (!(isdigit((unsigned char) s) || s == '-') ||
558                                 j >= sizeof(temp) - 1)
559                         {
560                                 write_msg(NULL, "parseNumericArray: bogus number\n");
561                                 exit_nicely();
562                         }
563                         temp[j++] = s;
564                 }
565         }
566
567         while (argNum < arraysize)
568                 array[argNum++] = strdup("0");
569 }
570
571
572 /*
573  * strInArray:
574  *        takes in a string and a string array and the number of elements in the
575  * string array.
576  *        returns the index if the string is somewhere in the array, -1 otherwise
577  */
578
579 static int
580 strInArray(const char *pattern, char **arr, int arr_size)
581 {
582         int                     i;
583
584         for (i = 0; i < arr_size; i++)
585         {
586                 if (strcmp(pattern, arr[i]) == 0)
587                         return i;
588         }
589         return -1;
590 }