]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/common.c
Fix quoting bugs and incorrect trigger argument printout.
[postgresql] / src / bin / pg_dump / common.c
1 /*-------------------------------------------------------------------------
2  *
3  * common.c
4  *        common routines between pg_dump and pg4_dump
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.38 2000/01/18 07:29:58 tgl Exp $
11  *
12  * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
13  *
14  *       - Fixed dumpTable output to output lengths for char and varchar types!
15  *       - Added single. quote to twin single quote expansion for 'insert' string
16  *         mode.
17  *
18  *-------------------------------------------------------------------------
19  */
20
21
22 #include <ctype.h>
23
24 #include "postgres.h"
25
26 #include "libpq-fe.h"
27 #ifndef HAVE_STRDUP
28 #include "strdup.h"
29 #endif
30
31 #include "pg_dump.h"
32
33 static char **findParentsByOid(TableInfo *tbinfo, int numTables,
34                                  InhInfo *inhinfo, int numInherits,
35                                  const char *oid,
36                                  int *numParents);
37 static int      findTableByOid(TableInfo *tbinfo, int numTables, const char *oid);
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  * findTypeByOid
44  *        given an oid of a type, return its typename
45  *
46  * if oid is "0", return "opaque" -- this is a special case
47  *
48  * NOTE:  should hash this, but just do linear search for now
49  */
50
51 char *
52 findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid)
53 {
54         int                     i;
55
56         if (strcmp(oid, "0") == 0)
57                 return g_opaque_type;
58
59         for (i = 0; i < numTypes; i++)
60         {
61                 if (strcmp(tinfo[i].oid, oid) == 0)
62                         return tinfo[i].typname;
63         }
64
65         /* should never get here */
66         fprintf(stderr, "failed sanity check, type with oid %s was not found\n",
67                         oid);
68         exit(2);
69 }
70
71 /*
72  * findOprByOid
73  *        given the oid of an operator, return the name of the operator
74  *
75  *
76  * NOTE:  should hash this, but just do linear search for now
77  *
78  */
79 char *
80 findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid)
81 {
82         int                     i;
83
84         for (i = 0; i < numOprs; i++)
85         {
86                 if (strcmp(oprinfo[i].oid, oid) == 0)
87                         return oprinfo[i].oprname;
88         }
89
90         /* should never get here */
91         fprintf(stderr, "failed sanity check, opr with oid %s was not found\n",
92                         oid);
93         exit(2);
94 }
95
96
97 /*
98  * findParentsByOid
99  *        given the oid of a class, return the names of its parent classes
100  * and assign the number of parents to the last argument.
101  *
102  *
103  * returns NULL if none
104  */
105
106 static char **
107 findParentsByOid(TableInfo *tblinfo, int numTables,
108                                  InhInfo *inhinfo, int numInherits, const char *oid,
109                                  int *numParentsPtr)
110 {
111         int                     i,
112                                 j;
113         int                     parentInd,
114                                 selfInd;
115         char      **result;
116         int                     numParents;
117
118         numParents = 0;
119         for (i = 0; i < numInherits; i++)
120         {
121                 if (strcmp(inhinfo[i].inhrelid, oid) == 0)
122                         numParents++;
123         }
124
125         *numParentsPtr = numParents;
126
127         if (numParents > 0)
128         {
129                 result = (char **) malloc(sizeof(char *) * numParents);
130                 j = 0;
131                 for (i = 0; i < numInherits; i++)
132                 {
133                         if (strcmp(inhinfo[i].inhrelid, oid) == 0)
134                         {
135                                 parentInd = findTableByOid(tblinfo, numTables,
136                                                                                    inhinfo[i].inhparent);
137                                 if (parentInd < 0)
138                                 {
139                                         selfInd = findTableByOid(tblinfo, numTables, oid);
140                                         fprintf(stderr,
141                                                         "failed sanity check, parent oid %s of table %s (oid %s) was not found\n",
142                                                         inhinfo[i].inhparent,
143                                                   (selfInd >= 0) ? tblinfo[selfInd].relname : "",
144                                                         oid);
145                                         exit(2);
146                                 }
147                                 result[j++] = tblinfo[parentInd].relname;
148                         }
149                 }
150                 return result;
151         }
152         else
153                 return NULL;
154 }
155
156 /*
157  * parseNumericArray
158  *        parse a string of numbers delimited by spaces into a character array
159  */
160
161 void
162 parseNumericArray(const char *str, char **array, int arraysize)
163 {
164         int                     j,
165                                 argNum;
166         char            temp[100];
167         char            s;
168
169         argNum = 0;
170         j = 0;
171         for (;;)
172         {
173                 s = *str++;
174                 if (s == ' ' || s == '\0')
175                 {
176                         if (j > 0)
177                         {
178                                 if (argNum >= arraysize)
179                                 {
180                                         fprintf(stderr, "parseNumericArray: too many numbers\n");
181                                         exit(2);
182                                 }
183                                 temp[j] = '\0';
184                                 array[argNum++] = strdup(temp);
185                                 j = 0;
186                         }
187                         if (s == '\0')
188                                 break;
189                 }
190                 else
191                 {
192                         if (!isdigit(s) || j >= sizeof(temp)-1)
193                         {
194                                 fprintf(stderr, "parseNumericArray: bogus number\n");
195                                 exit(2);
196                         }
197                         temp[j++] = s;
198                 }
199         }
200         while (argNum < arraysize)
201                 array[argNum++] = strdup("0");
202 }
203
204
205 /*
206  * strInArray:
207  *        takes in a string and a string array and the number of elements in the
208  * string array.
209  *        returns the index if the string is somewhere in the array, -1 otherwise
210  *
211  */
212
213 static int
214 strInArray(const char *pattern, char **arr, int arr_size)
215 {
216         int                     i;
217
218         for (i = 0; i < arr_size; i++)
219         {
220                 if (strcmp(pattern, arr[i]) == 0)
221                         return i;
222         }
223         return -1;
224 }
225
226 /*
227  * dumpSchema:
228  *        we have a valid connection, we are now going to dump the schema
229  * into the file
230  *
231  */
232
233 TableInfo  *
234 dumpSchema(FILE *fout,
235                    int *numTablesPtr,
236                    const char *tablename,
237                    const bool aclsSkip)
238 {
239         int                     numTypes;
240         int                     numFuncs;
241         int                     numTables;
242         int                     numInherits;
243         int                     numAggregates;
244         int                     numOperators;
245         TypeInfo   *tinfo = NULL;
246         FuncInfo   *finfo = NULL;
247         AggInfo    *agginfo = NULL;
248         TableInfo  *tblinfo = NULL;
249         InhInfo    *inhinfo = NULL;
250         OprInfo    *oprinfo = NULL;
251
252         if (g_verbose)
253                 fprintf(stderr, "%s reading user-defined types %s\n",
254                                 g_comment_start, g_comment_end);
255         tinfo = getTypes(&numTypes);
256
257         if (g_verbose)
258                 fprintf(stderr, "%s reading user-defined functions %s\n",
259                                 g_comment_start, g_comment_end);
260         finfo = getFuncs(&numFuncs);
261
262         if (g_verbose)
263                 fprintf(stderr, "%s reading user-defined aggregates %s\n",
264                                 g_comment_start, g_comment_end);
265         agginfo = getAggregates(&numAggregates);
266
267         if (g_verbose)
268                 fprintf(stderr, "%s reading user-defined operators %s\n",
269                                 g_comment_start, g_comment_end);
270         oprinfo = getOperators(&numOperators);
271
272         if (g_verbose)
273                 fprintf(stderr, "%s reading user-defined tables %s\n",
274                                 g_comment_start, g_comment_end);
275         tblinfo = getTables(&numTables, finfo, numFuncs);
276
277         if (g_verbose)
278                 fprintf(stderr, "%s reading table inheritance information %s\n",
279                                 g_comment_start, g_comment_end);
280         inhinfo = getInherits(&numInherits);
281
282         if (g_verbose)
283                 fprintf(stderr, "%s finding the attribute names and types for each table %s\n",
284                                 g_comment_start, g_comment_end);
285         getTableAttrs(tblinfo, numTables);
286
287         if (g_verbose)
288                 fprintf(stderr, "%s flagging inherited attributes in subtables %s\n",
289                                 g_comment_start, g_comment_end);
290         flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
291
292         if (!tablename && fout)
293         {
294                 if (g_verbose)
295                         fprintf(stderr, "%s dumping out user-defined types %s\n",
296                                         g_comment_start, g_comment_end);
297                 dumpTypes(fout, finfo, numFuncs, tinfo, numTypes);
298         }
299
300         if (fout)
301         {
302                 if (g_verbose)
303                         fprintf(stderr, "%s dumping out tables %s\n",
304                                         g_comment_start, g_comment_end);
305                 dumpTables(fout, tblinfo, numTables, inhinfo, numInherits,
306                                    tinfo, numTypes, tablename, aclsSkip);
307         }
308
309         if (!tablename && fout)
310         {
311                 if (g_verbose)
312                         fprintf(stderr, "%s dumping out user-defined procedural languages %s\n",
313                                         g_comment_start, g_comment_end);
314                 dumpProcLangs(fout, finfo, numFuncs, tinfo, numTypes);
315         }
316
317         if (!tablename && fout)
318         {
319                 if (g_verbose)
320                         fprintf(stderr, "%s dumping out user-defined functions %s\n",
321                                         g_comment_start, g_comment_end);
322                 dumpFuncs(fout, finfo, numFuncs, tinfo, numTypes);
323         }
324
325         if (!tablename && fout)
326         {
327                 if (g_verbose)
328                         fprintf(stderr, "%s dumping out user-defined aggregates %s\n",
329                                         g_comment_start, g_comment_end);
330                 dumpAggs(fout, agginfo, numAggregates, tinfo, numTypes);
331         }
332
333         if (!tablename && fout)
334         {
335                 if (g_verbose)
336                         fprintf(stderr, "%s dumping out user-defined operators %s\n",
337                                         g_comment_start, g_comment_end);
338                 dumpOprs(fout, oprinfo, numOperators, tinfo, numTypes);
339         }
340
341         *numTablesPtr = numTables;
342         clearAggInfo(agginfo, numAggregates);
343         clearOprInfo(oprinfo, numOperators);
344         clearTypeInfo(tinfo, numTypes);
345         clearFuncInfo(finfo, numFuncs);
346         clearInhInfo(inhinfo, numInherits);
347         return tblinfo;
348 }
349
350 /*
351  * dumpSchemaIdx:
352  *        dump indexes at the end for performance
353  *
354  */
355
356 extern void
357 dumpSchemaIdx(FILE *fout, const char *tablename,
358                           TableInfo *tblinfo, int numTables)
359 {
360         int                     numIndices;
361         IndInfo    *indinfo;
362
363         if (g_verbose)
364                 fprintf(stderr, "%s reading indices information %s\n",
365                                 g_comment_start, g_comment_end);
366         indinfo = getIndices(&numIndices);
367
368         if (fout)
369         {
370                 if (g_verbose)
371                         fprintf(stderr, "%s dumping out indices %s\n",
372                                         g_comment_start, g_comment_end);
373                 dumpIndices(fout, indinfo, numIndices, tblinfo, numTables, tablename);
374         }
375         clearIndInfo(indinfo, numIndices);
376 }
377
378 /* flagInhAttrs -
379  *       for each table in tblinfo, flag its inherited attributes
380  * so when we dump the table out, we don't dump out the inherited attributes
381  *
382  * initializes the parentRels field of each table
383  *
384  * modifies tblinfo
385  *
386  */
387 static void
388 flagInhAttrs(TableInfo *tblinfo, int numTables,
389                          InhInfo *inhinfo, int numInherits)
390 {
391         int                     i,
392                                 j,
393                                 k;
394         int                     parentInd;
395
396         /*
397          * we go backwards because the tables in tblinfo are in OID order,
398          * meaning the subtables are after the parent tables we flag inherited
399          * attributes from child tables first
400          */
401         for (i = numTables - 1; i >= 0; i--)
402         {
403                 tblinfo[i].parentRels = findParentsByOid(tblinfo, numTables,
404                                                                                                  inhinfo, numInherits,
405                                                                                                  tblinfo[i].oid,
406                                                                                                  &tblinfo[i].numParents);
407                 for (k = 0; k < tblinfo[i].numParents; k++)
408                 {
409                         parentInd = findTableByName(tblinfo, numTables,
410                                                                                 tblinfo[i].parentRels[k]);
411                         if (parentInd < 0)
412                         {
413                                 /* shouldn't happen unless findParentsByOid is broken */
414                                 fprintf(stderr, "failed sanity check, table %s not found by flagInhAttrs\n",
415                                                 tblinfo[i].parentRels[k]);
416                                 exit(2);
417                         }
418                         for (j = 0; j < tblinfo[i].numatts; j++)
419                         {
420                                 if (strInArray(tblinfo[i].attnames[j],
421                                                            tblinfo[parentInd].attnames,
422                                                            tblinfo[parentInd].numatts) != -1)
423                                         tblinfo[i].inhAttrs[j] = 1;
424                         }
425                 }
426         }
427 }
428
429
430 /*
431  * findTableByName
432  *        finds the index (in tblinfo) of the table with the given relname
433  *      returns -1 if not found
434  *
435  * NOTE:  should hash this, but just do linear search for now
436  */
437
438 int
439 findTableByName(TableInfo *tblinfo, int numTables, const char *relname)
440 {
441         int                     i;
442
443         for (i = 0; i < numTables; i++)
444         {
445                 if (strcmp(tblinfo[i].relname, relname) == 0)
446                         return i;
447         }
448         return -1;
449 }
450
451 /*
452  * findTableByOid
453  *        finds the index (in tblinfo) of the table with the given oid
454  *      returns -1 if not found
455  *
456  * NOTE:  should hash this, but just do linear search for now
457  */
458
459 static int
460 findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
461 {
462         int                     i;
463
464         for (i = 0; i < numTables; i++)
465         {
466                 if (strcmp(tblinfo[i].oid, oid) == 0)
467                         return i;
468         }
469         return -1;
470 }
471
472
473 /*
474  * findFuncByName
475  *        finds the index (in finfo) of the function with the given name
476  *      returns -1 if not found
477  *
478  * NOTE:  should hash this, but just do linear search for now
479  */
480
481 int
482 findFuncByName(FuncInfo *finfo, int numFuncs, const char *name)
483 {
484         int                     i;
485
486         for (i = 0; i < numFuncs; i++)
487         {
488                 if (strcmp(finfo[i].proname, name) == 0)
489                         return i;
490         }
491         return -1;
492 }
493
494 /*
495  * fmtId
496  *
497  *      checks input string for non-lowercase characters
498  *      returns pointer to input string or string surrounded by double quotes
499  *
500  *      Note that the returned string should be used immediately since it
501  *      uses a static buffer to hold the string. Non-reentrant but faster?
502  */
503 const char *
504 fmtId(const char *rawid, bool force_quotes)
505 {
506         static PQExpBuffer id_return = NULL;
507         const char *cp;
508         
509         if (!force_quotes)
510         {
511                 if (! islower(*rawid))
512                         force_quotes = true;
513                 else
514                         for (cp = rawid; *cp; cp++)
515                         {
516                                 if (! (islower(*cp) || isdigit(*cp) || (*cp == '_')))
517                                 {
518                                         force_quotes = true;
519                                         break;
520                                 }
521                         }
522         }
523
524         if (!force_quotes)
525                 return rawid;                   /* no quoting needed */
526
527         if (id_return)
528                 resetPQExpBuffer(id_return);
529         else
530                 id_return = createPQExpBuffer();
531
532         appendPQExpBufferChar(id_return, '\"');
533         for (cp = rawid; *cp; cp++)
534         {
535                 if (*cp == '\"')
536                         appendPQExpBufferChar(id_return, '\\');
537                 appendPQExpBufferChar(id_return, *cp);
538         }
539         appendPQExpBufferChar(id_return, '\"');
540
541         return id_return->data;
542 }       /* fmtId() */